diff --git a/go.mod b/go.mod index 91f00e61ba..fc8849ecdf 100644 --- a/go.mod +++ b/go.mod @@ -10,6 +10,6 @@ require ( github.com/neelance/parallel v0.0.0-20160708114440-4de9ce63d14c github.com/pkg/errors v0.8.0 github.com/sourcegraph/go-langserver v0.0.0-20180410094615-6d56335e3448 - github.com/sourcegraph/jsonrpc2 v0.0.0-20180501180217-a3d86c792f0f + github.com/sourcegraph/jsonrpc2 v0.1.0 golang.org/x/net v0.0.0-20180420171651-5f9ae10d9af5 ) diff --git a/go.sum b/go.sum index 1225a325d7..3c8fcb8ce6 100644 --- a/go.sum +++ b/go.sum @@ -14,5 +14,7 @@ github.com/sourcegraph/go-langserver v0.0.0-20180410094615-6d56335e3448 h1:1qFoN github.com/sourcegraph/go-langserver v0.0.0-20180410094615-6d56335e3448/go.mod h1:bBMjfpzEHd6ijPRoQ7f+knFfw+e8R+W158/MsqAy77c= github.com/sourcegraph/jsonrpc2 v0.0.0-20180501180217-a3d86c792f0f h1:mHcjtPCPBj4hKeRIwIU/R+Tn6TEBvDZPQnhOquzzAgA= github.com/sourcegraph/jsonrpc2 v0.0.0-20180501180217-a3d86c792f0f/go.mod h1:eESpbCslcLDs8j2D7IEdGVgul7xuk9odqDTaor30IUU= +github.com/sourcegraph/jsonrpc2 v0.1.0 h1:ohJHjZ+PcaLxDUjqk2NC3tIGsVa5bXThe1ZheSXOjuk= +github.com/sourcegraph/jsonrpc2 v0.1.0/go.mod h1:ZafdZgk/axhT1cvZAPOhw+95nz2I/Ra5qMlU4gTRwIo= golang.org/x/net v0.0.0-20180420171651-5f9ae10d9af5 h1:ylIG3jIeS45kB0W95N19kS62fwermjMYLIyybf8xh9M= golang.org/x/net v0.0.0-20180420171651-5f9ae10d9af5/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= diff --git a/vendor/github.com/sourcegraph/jsonrpc2/.travis.yml b/vendor/github.com/sourcegraph/jsonrpc2/.travis.yml index 75e6db9944..7b2f9de0fc 100644 --- a/vendor/github.com/sourcegraph/jsonrpc2/.travis.yml +++ b/vendor/github.com/sourcegraph/jsonrpc2/.travis.yml @@ -1,6 +1,6 @@ language: go go: - - 1.8 + - 1.x script: - go test -race -v ./... diff --git a/vendor/github.com/sourcegraph/jsonrpc2/README.md b/vendor/github.com/sourcegraph/jsonrpc2/README.md index afad9a4080..d2406ab078 100644 --- a/vendor/github.com/sourcegraph/jsonrpc2/README.md +++ b/vendor/github.com/sourcegraph/jsonrpc2/README.md @@ -1,4 +1,4 @@ -# jsonrpc2: JSON-RPC 2.0 implementation for Go [![Build Status](https://travis-ci.org/sourcegraph/jsonrpc2.svg)](https://travis-ci.org/sourcegraph/jsonrpc2) [![Sourcegraph](https://sourcegraph.com/github.com/sourcegraph/jsonrpc2/-/badge.svg)](https://sourcegraph.com/github.com/sourcegraph/jsonrpc2?badge) +# jsonrpc2: JSON-RPC 2.0 implementation for Go [![Build Status](https://travis-ci.org/sourcegraph/jsonrpc2.svg)](https://travis-ci.org/sourcegraph/jsonrpc2) [![Sourcegraph](https://sourcegraph.com/github.com/sourcegraph/jsonrpc2/-/badge.svg)](https://sourcegraph.com/github.com/sourcegraph/jsonrpc2?badge) [![GoDoc](https://godoc.org/github.com/sourcegraph/jsonrpc2?status.svg)](https://godoc.org/github.com/sourcegraph/jsonrpc2) Package jsonrpc2 provides a [Go](https://golang.org) implementation of [JSON-RPC 2.0](http://www.jsonrpc.org/specification). diff --git a/vendor/github.com/sourcegraph/jsonrpc2/call_opt.go b/vendor/github.com/sourcegraph/jsonrpc2/call_opt.go index b554baca87..73fe9c213b 100644 --- a/vendor/github.com/sourcegraph/jsonrpc2/call_opt.go +++ b/vendor/github.com/sourcegraph/jsonrpc2/call_opt.go @@ -28,3 +28,12 @@ func PickID(id ID) CallOption { return nil }) } + +// StringID returns a call option that instructs the request ID to be set as a +// string. +func StringID() CallOption { + return callOptionFunc(func(r *Request) error { + r.ID.IsString = true + return nil + }) +} diff --git a/vendor/github.com/sourcegraph/jsonrpc2/conn_opt.go b/vendor/github.com/sourcegraph/jsonrpc2/conn_opt.go index 0a4290437f..3779d7f0fb 100644 --- a/vendor/github.com/sourcegraph/jsonrpc2/conn_opt.go +++ b/vendor/github.com/sourcegraph/jsonrpc2/conn_opt.go @@ -2,10 +2,15 @@ package jsonrpc2 import ( "encoding/json" - "log" "sync" ) +// Logger interface implements one method - Printf. +// You can use the stdlib logger *log.Logger +type Logger interface { + Printf(format string, v ...interface{}) +} + // ConnOpt is the type of function that can be passed to NewConn to // customize the Conn before it is created. type ConnOpt func(*Conn) @@ -24,7 +29,7 @@ func OnSend(f func(*Request, *Response)) ConnOpt { // LogMessages causes all messages sent and received on conn to be // logged using the provided logger. -func LogMessages(log *log.Logger) ConnOpt { +func LogMessages(logger Logger) ConnOpt { return func(c *Conn) { // Remember reqs we have received so we can helpfully show the // request method in OnSend for responses. @@ -33,18 +38,21 @@ func LogMessages(log *log.Logger) ConnOpt { reqMethods = map[ID]string{} ) + // Set custom logger from provided input + c.logger = logger + OnRecv(func(req *Request, resp *Response) { switch { - case req != nil && resp == nil: + case req != nil: mu.Lock() reqMethods[req.ID] = req.Method mu.Unlock() params, _ := json.Marshal(req.Params) if req.Notif { - log.Printf("--> notif: %s: %s", req.Method, params) + logger.Printf("jsonrpc2: --> notif: %s: %s\n", req.Method, params) } else { - log.Printf("--> request #%s: %s: %s", req.ID, req.Method, params) + logger.Printf("jsonrpc2: --> request #%s: %s: %s\n", req.ID, req.Method, params) } case resp != nil: @@ -57,10 +65,10 @@ func LogMessages(log *log.Logger) ConnOpt { switch { case resp.Result != nil: result, _ := json.Marshal(resp.Result) - log.Printf("--> result #%s: %s: %s", resp.ID, method, result) + logger.Printf("jsonrpc2: --> result #%s: %s: %s\n", resp.ID, method, result) case resp.Error != nil: err, _ := json.Marshal(resp.Error) - log.Printf("--> error #%s: %s: %s", resp.ID, method, err) + logger.Printf("jsonrpc2: --> error #%s: %s: %s\n", resp.ID, method, err) } } })(c) @@ -69,9 +77,9 @@ func LogMessages(log *log.Logger) ConnOpt { case req != nil: params, _ := json.Marshal(req.Params) if req.Notif { - log.Printf("<-- notif: %s: %s", req.Method, params) + logger.Printf("jsonrpc2: <-- notif: %s: %s\n", req.Method, params) } else { - log.Printf("<-- request #%s: %s: %s", req.ID, req.Method, params) + logger.Printf("jsonrpc2: <-- request #%s: %s: %s\n", req.ID, req.Method, params) } case resp != nil: @@ -85,10 +93,10 @@ func LogMessages(log *log.Logger) ConnOpt { if resp.Result != nil { result, _ := json.Marshal(resp.Result) - log.Printf("<-- result #%s: %s: %s", resp.ID, method, result) + logger.Printf("jsonrpc2: <-- result #%s: %s: %s\n", resp.ID, method, result) } else { err, _ := json.Marshal(resp.Error) - log.Printf("<-- error #%s: %s: %s", resp.ID, method, err) + logger.Printf("jsonrpc2: <-- error #%s: %s: %s\n", resp.ID, method, err) } } })(c) diff --git a/vendor/github.com/sourcegraph/jsonrpc2/go.mod b/vendor/github.com/sourcegraph/jsonrpc2/go.mod new file mode 100644 index 0000000000..95cca53caa --- /dev/null +++ b/vendor/github.com/sourcegraph/jsonrpc2/go.mod @@ -0,0 +1,5 @@ +module github.com/sourcegraph/jsonrpc2 + +go 1.12 + +require github.com/gorilla/websocket v1.4.1 diff --git a/vendor/github.com/sourcegraph/jsonrpc2/go.sum b/vendor/github.com/sourcegraph/jsonrpc2/go.sum new file mode 100644 index 0000000000..1f9b923e90 --- /dev/null +++ b/vendor/github.com/sourcegraph/jsonrpc2/go.sum @@ -0,0 +1,2 @@ +github.com/gorilla/websocket v1.4.1 h1:q7AeDBpnBk8AogcD4DSag/Ukw/KV+YhzLj2bP5HvKCM= +github.com/gorilla/websocket v1.4.1/go.mod h1:YR8l580nyteQvAITg2hZ9XVh4b55+EU/adAjf1fMHhE= diff --git a/vendor/github.com/sourcegraph/jsonrpc2/handler_with_error.go b/vendor/github.com/sourcegraph/jsonrpc2/handler_with_error.go index 6f056ccadc..2bd5c1d900 100644 --- a/vendor/github.com/sourcegraph/jsonrpc2/handler_with_error.go +++ b/vendor/github.com/sourcegraph/jsonrpc2/handler_with_error.go @@ -2,7 +2,6 @@ package jsonrpc2 import ( "context" - "log" ) // HandlerWithError implements Handler by calling the func for each @@ -11,6 +10,7 @@ func HandlerWithError(handleFunc func(context.Context, *Conn, *Request) (result return &HandlerWithErrorConfigurer{handleFunc: handleFunc} } +// HandlerWithErrorConfigurer is a handler created by HandlerWithError. type HandlerWithErrorConfigurer struct { handleFunc func(context.Context, *Conn, *Request) (result interface{}, err error) suppressErrClosed bool @@ -21,7 +21,7 @@ func (h *HandlerWithErrorConfigurer) Handle(ctx context.Context, conn *Conn, req result, err := h.handleFunc(ctx, conn, req) if req.Notif { if err != nil { - log.Printf("jsonrpc2 handler: notification %q handling error: %s", req.Method, err) + conn.logger.Printf("jsonrpc2 handler: notification %q handling error: %v\n", req.Method, err) } return } @@ -41,7 +41,7 @@ func (h *HandlerWithErrorConfigurer) Handle(ctx context.Context, conn *Conn, req if !req.Notif { if err := conn.SendResponse(ctx, resp); err != nil { if err != ErrClosed || !h.suppressErrClosed { - log.Printf("jsonrpc2 handler: sending response %s: %s", resp.ID, err) + conn.logger.Printf("jsonrpc2 handler: sending response %s: %v\n", resp.ID, err) } } } diff --git a/vendor/github.com/sourcegraph/jsonrpc2/jsonrpc2.go b/vendor/github.com/sourcegraph/jsonrpc2/jsonrpc2.go index 3e0763d73f..005b65c07f 100644 --- a/vendor/github.com/sourcegraph/jsonrpc2/jsonrpc2.go +++ b/vendor/github.com/sourcegraph/jsonrpc2/jsonrpc2.go @@ -10,6 +10,7 @@ import ( "fmt" "io" "log" + "os" "strconv" "sync" ) @@ -84,11 +85,12 @@ func (r *Request) UnmarshalJSON(data []byte) error { return err } r.Method = r2.Method - if r2.Params == nil { + switch { + case r2.Params == nil: r.Params = &jsonNull - } else if len(*r2.Params) == 0 { + case len(*r2.Params) == 0: r.Params = nil - } else { + default: r.Params = r2.Params } r.Meta = r2.Meta @@ -212,22 +214,20 @@ func (e *Error) Error() string { return fmt.Sprintf("jsonrpc2: code %v message: %s", e.Code, e.Message) } +// Errors defined in the JSON-RPC spec. See +// http://www.jsonrpc.org/specification#error_object. const ( - // Errors defined in the JSON-RPC spec. See - // http://www.jsonrpc.org/specification#error_object. - CodeParseError = -32700 - CodeInvalidRequest = -32600 - CodeMethodNotFound = -32601 - CodeInvalidParams = -32602 - CodeInternalError = -32603 - codeServerErrorStart = -32099 - codeServerErrorEnd = -32000 + CodeParseError = -32700 + CodeInvalidRequest = -32600 + CodeMethodNotFound = -32601 + CodeInvalidParams = -32602 + CodeInternalError = -32603 ) // Handler handles JSON-RPC requests and notifications. type Handler interface { // Handle is called to handle a request. No other requests are handled - // until it returns. If you do not require strict ordering behaviour + // until it returns. If you do not require strict ordering behavior // of received RPCs, it is suggested to wrap your handler in // AsyncHandler. Handle(context.Context, *Conn, *Request) @@ -297,6 +297,8 @@ type Conn struct { disconnect chan struct{} + logger Logger + // Set by ConnOpt funcs. onRecv []func(*Request, *Response) onSend []func(*Request, *Response) @@ -315,14 +317,18 @@ var ErrClosed = errors.New("jsonrpc2: connection is closed") // // NewClient consumes conn, so you should call Close on the returned // client not on the given conn. -func NewConn(ctx context.Context, stream ObjectStream, h Handler, opt ...ConnOpt) *Conn { +func NewConn(ctx context.Context, stream ObjectStream, h Handler, opts ...ConnOpt) *Conn { c := &Conn{ stream: stream, h: h, pending: map[ID]*call{}, disconnect: make(chan struct{}), + logger: log.New(os.Stderr, "", log.LstdFlags), } - for _, opt := range opt { + for _, opt := range opts { + if opt == nil { + continue + } opt(c) } go c.readMessages(ctx) @@ -342,7 +348,7 @@ func (c *Conn) Close() error { return c.stream.Close() } -func (c *Conn) send(ctx context.Context, m *anyMessage, wait bool) (cc *call, err error) { +func (c *Conn) send(_ context.Context, m *anyMessage, wait bool) (cc *call, err error) { c.sending.Lock() defer c.sending.Unlock() @@ -360,9 +366,14 @@ func (c *Conn) send(ctx context.Context, m *anyMessage, wait bool) (cc *call, er // responses. if m.request != nil && wait { cc = &call{request: m.request, seq: c.seq, done: make(chan error, 1)} - if !m.request.ID.IsString && m.request.ID.Num == 0 { - // unset, use next seq as call ID - m.request.ID.Num = c.seq + + isIDUnset := len(m.request.ID.Str) == 0 && m.request.ID.Num == 0 + if isIDUnset { + if m.request.ID.IsString { + m.request.ID.Str = strconv.FormatUint(c.seq, 10) + } else { + m.request.ID.Num = c.seq + } } id = m.request.ID c.pending[id] = cc @@ -410,21 +421,50 @@ func (c *Conn) send(ctx context.Context, m *anyMessage, wait bool) (cc *call, er // its result is stored in result (a pointer to a value that can be // JSON-unmarshaled into); otherwise, a non-nil error is returned. func (c *Conn) Call(ctx context.Context, method string, params, result interface{}, opts ...CallOption) error { + call, err := c.DispatchCall(ctx, method, params, opts...) + if err != nil { + return err + } + return call.Wait(ctx, result) +} + +// DispatchCall dispatches a JSON-RPC call using the specified method +// and params, and returns a call proxy or an error. Call Wait() +// on the returned proxy to receive the response. Only use this +// function if you need to do work after dispatching the request, +// otherwise use Call. +func (c *Conn) DispatchCall(ctx context.Context, method string, params interface{}, opts ...CallOption) (Waiter, error) { req := &Request{Method: method} if err := req.SetParams(params); err != nil { - return err + return Waiter{}, err } for _, opt := range opts { + if opt == nil { + continue + } if err := opt.apply(req); err != nil { - return err + return Waiter{}, err } } call, err := c.send(ctx, &anyMessage{request: req}, true) if err != nil { - return err + return Waiter{}, err } + return Waiter{call: call}, nil +} + +// Waiter proxies an ongoing JSON-RPC call. +type Waiter struct { + *call +} + +// Wait for the result of an ongoing JSON-RPC call. If the response +// is successful, its result is stored in result (a pointer to a +// value that can be JSON-unmarshaled into); otherwise, a non-nil +// error is returned. +func (w Waiter) Wait(ctx context.Context, result interface{}) error { select { - case err, ok := <-call.done: + case err, ok := <-w.call.done: if !ok { err = ErrClosed } @@ -432,11 +472,10 @@ func (c *Conn) Call(ctx context.Context, method string, params, result interface return err } if result != nil { - if call.response.Result == nil { - call.response.Result = &jsonNull + if w.call.response.Result == nil { + w.call.response.Result = &jsonNull } - // TODO(sqs): error handling - if err := json.Unmarshal(*call.response.Result, result); err != nil { + if err := json.Unmarshal(*w.call.response.Result, result); err != nil { return err } } @@ -458,6 +497,9 @@ func (c *Conn) Notify(ctx context.Context, method string, params interface{}, op return err } for _, opt := range opts { + if opt == nil { + continue + } if err := opt.apply(req); err != nil { return err } @@ -535,7 +577,7 @@ func (c *Conn) readMessages(ctx context.Context) { switch { case call == nil: - log.Printf("jsonrpc2: ignoring response #%s with no corresponding request", id) + c.logger.Printf("jsonrpc2: ignoring response #%s with no corresponding request\n", id) case resp.Error != nil: call.done <- resp.Error @@ -567,7 +609,7 @@ func (c *Conn) readMessages(ctx context.Context) { c.mu.Unlock() c.sending.Unlock() if err != io.ErrUnexpectedEOF && !closing { - log.Println("jsonrpc2: protocol error:", err) + c.logger.Printf("jsonrpc2: protocol error: %v\n", err) } close(c.disconnect) } @@ -633,17 +675,22 @@ func (m *anyMessage) UnmarshalJSON(data []byte) error { if len(msgs) == 0 { return errors.New("jsonrpc2: invalid empty batch") } - for _, msg := range msgs { - if err := checkType(&msg); err != nil { + for i := range msgs { + if err := checkType(&msg{ + ID: msgs[i].ID, + Method: msgs[i].Method, + Result: msgs[i].Result, + Error: msgs[i].Error, + }); err != nil { return err } } } else { - var msg msg - if err := json.Unmarshal(data, &msg); err != nil { + var m msg + if err := json.Unmarshal(data, &m); err != nil { return err } - if err := checkType(&msg); err != nil { + if err := checkType(&m); err != nil { return err } } @@ -684,8 +731,3 @@ func (v *anyValueWithExplicitNull) UnmarshalJSON(data []byte) error { *v = anyValueWithExplicitNull{} return json.Unmarshal(data, &v.value) } - -var ( - errInvalidRequestJSON = errors.New("jsonrpc2: request must be either a JSON object or JSON array") - errInvalidResponseJSON = errors.New("jsonrpc2: response must be either a JSON object or JSON array") -) diff --git a/vendor/github.com/sourcegraph/jsonrpc2/stream.go b/vendor/github.com/sourcegraph/jsonrpc2/stream.go index f38c026ac1..e7a90253c7 100644 --- a/vendor/github.com/sourcegraph/jsonrpc2/stream.go +++ b/vendor/github.com/sourcegraph/jsonrpc2/stream.go @@ -162,3 +162,16 @@ func (VSCodeObjectCodec) ReadObject(stream *bufio.Reader, v interface{}) error { } return json.NewDecoder(io.LimitReader(stream, int64(contentLength))).Decode(v) } + +// PlainObjectCodec reads/writes plain JSON-RPC 2.0 objects without a header. +type PlainObjectCodec struct{} + +// WriteObject implements ObjectCodec. +func (PlainObjectCodec) WriteObject(stream io.Writer, v interface{}) error { + return json.NewEncoder(stream).Encode(v) +} + +// ReadObject implements ObjectCodec. +func (PlainObjectCodec) ReadObject(stream *bufio.Reader, v interface{}) error { + return json.NewDecoder(stream).Decode(v) +} diff --git a/vendor/modules.txt b/vendor/modules.txt index da14cd6e9b..7617898fc5 100644 --- a/vendor/modules.txt +++ b/vendor/modules.txt @@ -1,19 +1,29 @@ # github.com/google/uuid v0.0.0-20161128191214-064e2069ce9c +## explicit github.com/google/uuid +# github.com/gorilla/websocket v1.4.1 +## explicit # github.com/hashicorp/errwrap v0.0.0-20141028054710-7554cd9344ce +## explicit github.com/hashicorp/errwrap # github.com/hashicorp/go-multierror v0.0.0-20171204182908-b7773ae21874 +## explicit github.com/hashicorp/go-multierror # github.com/neelance/parallel v0.0.0-20160708114440-4de9ce63d14c +## explicit github.com/neelance/parallel # github.com/pkg/errors v0.8.0 +## explicit github.com/pkg/errors # github.com/sourcegraph/go-langserver v0.0.0-20180410094615-6d56335e3448 +## explicit github.com/sourcegraph/go-langserver/pkg/lsp github.com/sourcegraph/go-langserver/pkg/lspext -# github.com/sourcegraph/jsonrpc2 v0.0.0-20180501180217-a3d86c792f0f +# github.com/sourcegraph/jsonrpc2 v0.1.0 +## explicit github.com/sourcegraph/jsonrpc2 # golang.org/x/net v0.0.0-20180420171651-5f9ae10d9af5 -golang.org/x/net/trace +## explicit golang.org/x/net/context golang.org/x/net/internal/timeseries +golang.org/x/net/trace