mirror of
https://github.com/golang/go
synced 2024-11-18 14:14:46 -07:00
internal/jsonrpc2: change to a more synchronous dispatch model
Delivering each message in a go routine turned out to be problematic, there are some messages that must be fully processed before later messages are started, and there was no way to guarantee that. We now push concurrence handling up to the higher level, this has the disadvantage of not being able to guarantee we respond to call messages correctly, but its a small price to pay. The LSP currently processes each message fully in order blocking the handler, while we still work on basic functionality. Change-Id: If0648c77713ddbe4fed69da97a57696f433b8002 Reviewed-on: https://go-review.googlesource.com/c/149497 Run-TryBot: Ian Cottrell <iancottrell@google.com> TryBot-Result: Gobot Gobot <gobot@golang.org> Reviewed-by: Rebecca Stambler <rstambler@golang.org>
This commit is contained in:
parent
7d6b83ca4d
commit
94339b8328
@ -29,15 +29,15 @@ type Conn struct {
|
||||
pendingMu sync.Mutex // protects the pending map
|
||||
pending map[ID]chan *Response
|
||||
handlingMu sync.Mutex // protects the handling map
|
||||
handling map[ID]context.CancelFunc
|
||||
handling map[ID]handling
|
||||
}
|
||||
|
||||
// Handler is an option you can pass to NewConn to handle incoming requests.
|
||||
// If the request returns true from IsNotify then the Handler should not return a
|
||||
// result or error, otherwise it should handle the Request and return either
|
||||
// an encoded result, or an error.
|
||||
// Handlers must be concurrency-safe.
|
||||
type Handler = func(context.Context, *Conn, *Request) (interface{}, *Error)
|
||||
// If the request returns false from IsNotify then the Handler must eventually
|
||||
// call Reply on the Conn with the supplied request.
|
||||
// Handlers are called synchronously, they should pass the work off to a go
|
||||
// routine if they are going to take a long time.
|
||||
type Handler func(context.Context, *Conn, *Request)
|
||||
|
||||
// Canceler is an option you can pass to NewConn which is invoked for
|
||||
// cancelled outgoing requests.
|
||||
@ -46,7 +46,7 @@ type Handler = func(context.Context, *Conn, *Request) (interface{}, *Error)
|
||||
// It is okay to use the connection to send notifications, but the context will
|
||||
// be in the cancelled state, so you must do it with the background context
|
||||
// instead.
|
||||
type Canceler = func(context.Context, *Conn, *Request)
|
||||
type Canceler func(context.Context, *Conn, *Request)
|
||||
|
||||
// NewErrorf builds a Error struct for the suppied message and code.
|
||||
// If args is not empty, message and args will be passed to Sprintf.
|
||||
@ -64,7 +64,7 @@ func NewConn(ctx context.Context, s Stream, options ...interface{}) *Conn {
|
||||
stream: s,
|
||||
done: make(chan struct{}),
|
||||
pending: make(map[ID]chan *Response),
|
||||
handling: make(map[ID]context.CancelFunc),
|
||||
handling: make(map[ID]handling),
|
||||
}
|
||||
for _, opt := range options {
|
||||
switch opt := opt.(type) {
|
||||
@ -89,8 +89,10 @@ func NewConn(ctx context.Context, s Stream, options ...interface{}) *Conn {
|
||||
}
|
||||
if conn.handle == nil {
|
||||
// the default handler reports a method error
|
||||
conn.handle = func(ctx context.Context, c *Conn, r *Request) (interface{}, *Error) {
|
||||
return nil, NewErrorf(CodeMethodNotFound, "method %q not found", r.Method)
|
||||
conn.handle = func(ctx context.Context, c *Conn, r *Request) {
|
||||
if r.IsNotify() {
|
||||
c.Reply(ctx, r, nil, NewErrorf(CodeMethodNotFound, "method %q not found", r.Method))
|
||||
}
|
||||
}
|
||||
}
|
||||
if conn.cancel == nil {
|
||||
@ -126,10 +128,10 @@ func (c *Conn) Wait(ctx context.Context) error {
|
||||
// to propagate the cancel.
|
||||
func (c *Conn) Cancel(id ID) {
|
||||
c.handlingMu.Lock()
|
||||
cancel := c.handling[id]
|
||||
handling, found := c.handling[id]
|
||||
c.handlingMu.Unlock()
|
||||
if cancel != nil {
|
||||
cancel()
|
||||
if found {
|
||||
handling.cancel()
|
||||
}
|
||||
}
|
||||
|
||||
@ -215,6 +217,59 @@ func (c *Conn) Call(ctx context.Context, method string, params, result interface
|
||||
}
|
||||
}
|
||||
|
||||
// Reply sends a reply to the given request.
|
||||
// It is an error to call this if request was not a call.
|
||||
// You must call this exactly once for any given request.
|
||||
// If err is set then result will be ignored.
|
||||
func (c *Conn) Reply(ctx context.Context, req *Request, result interface{}, err error) error {
|
||||
if req.IsNotify() {
|
||||
return fmt.Errorf("reply not invoked with a valid call")
|
||||
}
|
||||
c.handlingMu.Lock()
|
||||
handling, found := c.handling[*req.ID]
|
||||
if found {
|
||||
delete(c.handling, *req.ID)
|
||||
}
|
||||
c.handlingMu.Unlock()
|
||||
if !found {
|
||||
return fmt.Errorf("not a call in progress: %v", req.ID)
|
||||
}
|
||||
|
||||
elapsed := time.Since(handling.start)
|
||||
var raw *json.RawMessage
|
||||
if err == nil {
|
||||
raw, err = marshalToRaw(result)
|
||||
}
|
||||
response := &Response{
|
||||
Result: raw,
|
||||
ID: req.ID,
|
||||
}
|
||||
if err != nil {
|
||||
if callErr, ok := err.(*Error); ok {
|
||||
response.Error = callErr
|
||||
} else {
|
||||
response.Error = NewErrorf(0, "%s", err)
|
||||
}
|
||||
}
|
||||
data, err := json.Marshal(response)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
c.log(Send, response.ID, elapsed, req.Method, response.Result, response.Error)
|
||||
if err = c.stream.Write(ctx, data); err != nil {
|
||||
// TODO(iancottrell): if a stream write fails, we really need to shut down
|
||||
// the whole stream
|
||||
return err
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
type handling struct {
|
||||
request *Request
|
||||
cancel context.CancelFunc
|
||||
start time.Time
|
||||
}
|
||||
|
||||
// combined has all the fields of both Request and Response.
|
||||
// We can decode this and then work out which it is.
|
||||
type combined struct {
|
||||
@ -230,7 +285,6 @@ type combined struct {
|
||||
// It must be called exactly once for each Conn.
|
||||
// It returns only when the reader is closed or there is an error in the stream.
|
||||
func (c *Conn) run(ctx context.Context) error {
|
||||
ctx, cancelRun := context.WithCancel(ctx)
|
||||
for {
|
||||
// get the data for a message
|
||||
data, err := c.stream.Read(ctx)
|
||||
@ -258,57 +312,19 @@ func (c *Conn) run(ctx context.Context) error {
|
||||
if request.IsNotify() {
|
||||
c.log(Receive, request.ID, -1, request.Method, request.Params, nil)
|
||||
// we have a Notify, forward to the handler in a go routine
|
||||
go func() {
|
||||
if _, err := c.handle(ctx, c, request); err != nil {
|
||||
// notify produced an error, we can't forward it to the other side
|
||||
// because there is no id, so we just log it
|
||||
c.log(Receive, nil, -1, request.Method, nil, err)
|
||||
}
|
||||
}()
|
||||
c.handle(ctx, c, request)
|
||||
} else {
|
||||
// we have a Call, forward to the handler in another go routine
|
||||
reqCtx, cancelReq := context.WithCancel(ctx)
|
||||
c.handlingMu.Lock()
|
||||
c.handling[*request.ID] = cancelReq
|
||||
c.handling[*request.ID] = handling{
|
||||
request: request,
|
||||
cancel: cancelReq,
|
||||
start: time.Now(),
|
||||
}
|
||||
c.handlingMu.Unlock()
|
||||
go func() {
|
||||
defer func() {
|
||||
// clean up the cancel handler on the way out
|
||||
c.handlingMu.Lock()
|
||||
delete(c.handling, *request.ID)
|
||||
c.handlingMu.Unlock()
|
||||
cancelReq()
|
||||
}()
|
||||
c.log(Receive, request.ID, -1, request.Method, request.Params, nil)
|
||||
before := time.Now()
|
||||
resp, callErr := c.handle(reqCtx, c, request)
|
||||
elapsed := time.Since(before)
|
||||
var result *json.RawMessage
|
||||
if result, err = marshalToRaw(resp); err != nil {
|
||||
callErr = &Error{Message: err.Error()}
|
||||
}
|
||||
response := &Response{
|
||||
Result: result,
|
||||
Error: callErr,
|
||||
ID: request.ID,
|
||||
}
|
||||
data, err := json.Marshal(response)
|
||||
if err != nil {
|
||||
// failure to marshal leaves the call without a response
|
||||
// possibly we could attempt to respond with a different message
|
||||
// but we can probably rely on timeouts instead
|
||||
c.log(Send, request.ID, elapsed, request.Method, nil, NewErrorf(0, "%s", err))
|
||||
return
|
||||
}
|
||||
c.log(Send, response.ID, elapsed, request.Method, response.Result, response.Error)
|
||||
if err = c.stream.Write(ctx, data); err != nil {
|
||||
// if a stream write fails, we really need to shut down the whole
|
||||
// stream and return from the run
|
||||
c.log(Send, request.ID, elapsed, request.Method, nil, NewErrorf(0, "%s", err))
|
||||
cancelRun()
|
||||
return
|
||||
}
|
||||
}()
|
||||
c.log(Receive, request.ID, -1, request.Method, request.Params, nil)
|
||||
c.handle(reqCtx, c, request)
|
||||
}
|
||||
case msg.ID != nil:
|
||||
// we have a response, get the pending entry from the map
|
||||
|
@ -102,7 +102,7 @@ func prepare(ctx context.Context, t *testing.T, withHeaders bool) (*testHandler,
|
||||
} else {
|
||||
h.stream = jsonrpc2.NewStream(h.reader, h.writer)
|
||||
}
|
||||
args := []interface{}{handle}
|
||||
args := []interface{}{jsonrpc2.Handler(handle)}
|
||||
if *logRPC {
|
||||
args = append(args, jsonrpc2.Log)
|
||||
}
|
||||
@ -128,32 +128,36 @@ type testHandler struct {
|
||||
*jsonrpc2.Conn
|
||||
}
|
||||
|
||||
func handle(ctx context.Context, c *jsonrpc2.Conn, r *jsonrpc2.Request) (interface{}, *jsonrpc2.Error) {
|
||||
func handle(ctx context.Context, c *jsonrpc2.Conn, r *jsonrpc2.Request) {
|
||||
switch r.Method {
|
||||
case "no_args":
|
||||
if r.Params != nil {
|
||||
return nil, jsonrpc2.NewErrorf(jsonrpc2.CodeInvalidParams, "Expected no params")
|
||||
c.Reply(ctx, r, nil, jsonrpc2.NewErrorf(jsonrpc2.CodeInvalidParams, "Expected no params"))
|
||||
return
|
||||
}
|
||||
return true, nil
|
||||
c.Reply(ctx, r, true, nil)
|
||||
case "one_string":
|
||||
var v string
|
||||
if err := json.Unmarshal(*r.Params, &v); err != nil {
|
||||
return nil, jsonrpc2.NewErrorf(jsonrpc2.CodeParseError, "%v", err.Error())
|
||||
c.Reply(ctx, r, nil, jsonrpc2.NewErrorf(jsonrpc2.CodeParseError, "%v", err.Error()))
|
||||
return
|
||||
}
|
||||
return "got:" + v, nil
|
||||
c.Reply(ctx, r, "got:"+v, nil)
|
||||
case "one_number":
|
||||
var v int
|
||||
if err := json.Unmarshal(*r.Params, &v); err != nil {
|
||||
return nil, jsonrpc2.NewErrorf(jsonrpc2.CodeParseError, "%v", err.Error())
|
||||
c.Reply(ctx, r, nil, jsonrpc2.NewErrorf(jsonrpc2.CodeParseError, "%v", err.Error()))
|
||||
return
|
||||
}
|
||||
return fmt.Sprintf("got:%d", v), nil
|
||||
c.Reply(ctx, r, fmt.Sprintf("got:%d", v), nil)
|
||||
case "join":
|
||||
var v []string
|
||||
if err := json.Unmarshal(*r.Params, &v); err != nil {
|
||||
return nil, jsonrpc2.NewErrorf(jsonrpc2.CodeParseError, "%v", err.Error())
|
||||
c.Reply(ctx, r, nil, jsonrpc2.NewErrorf(jsonrpc2.CodeParseError, "%v", err.Error()))
|
||||
return
|
||||
}
|
||||
return path.Join(v...), nil
|
||||
c.Reply(ctx, r, path.Join(v...), nil)
|
||||
default:
|
||||
return nil, jsonrpc2.NewErrorf(jsonrpc2.CodeMethodNotFound, "method %q not found", r.Method)
|
||||
c.Reply(ctx, r, nil, jsonrpc2.NewErrorf(jsonrpc2.CodeMethodNotFound, "method %q not found", r.Method))
|
||||
}
|
||||
}
|
||||
|
@ -25,121 +25,103 @@ type Client interface {
|
||||
}
|
||||
|
||||
func clientHandler(client Client) jsonrpc2.Handler {
|
||||
return func(ctx context.Context, conn *jsonrpc2.Conn, r *jsonrpc2.Request) (interface{}, *jsonrpc2.Error) {
|
||||
return func(ctx context.Context, conn *jsonrpc2.Conn, r *jsonrpc2.Request) {
|
||||
switch r.Method {
|
||||
case "$/cancelRequest":
|
||||
var params CancelParams
|
||||
if err := json.Unmarshal(*r.Params, ¶ms); err != nil {
|
||||
return nil, jsonrpc2.NewErrorf(jsonrpc2.CodeParseError, "%v", err)
|
||||
sendParseError(ctx, conn, r, err)
|
||||
return
|
||||
}
|
||||
conn.Cancel(params.ID)
|
||||
return nil, nil
|
||||
|
||||
case "window/showMessage":
|
||||
var params ShowMessageParams
|
||||
if err := json.Unmarshal(*r.Params, ¶ms); err != nil {
|
||||
return nil, jsonrpc2.NewErrorf(jsonrpc2.CodeParseError, "%v", err)
|
||||
sendParseError(ctx, conn, r, err)
|
||||
return
|
||||
}
|
||||
if err := client.ShowMessage(ctx, ¶ms); err != nil {
|
||||
return nil, toJSONError(err)
|
||||
}
|
||||
return nil, nil
|
||||
unhandledError(client.ShowMessage(ctx, ¶ms))
|
||||
|
||||
case "window/showMessageRequest":
|
||||
var params ShowMessageRequestParams
|
||||
if err := json.Unmarshal(*r.Params, ¶ms); err != nil {
|
||||
return nil, jsonrpc2.NewErrorf(jsonrpc2.CodeParseError, "%v", err)
|
||||
sendParseError(ctx, conn, r, err)
|
||||
return
|
||||
}
|
||||
resp, err := client.ShowMessageRequest(ctx, ¶ms)
|
||||
if err != nil {
|
||||
return nil, toJSONError(err)
|
||||
}
|
||||
return resp, nil
|
||||
unhandledError(conn.Reply(ctx, r, resp, err))
|
||||
|
||||
case "window/logMessage":
|
||||
var params LogMessageParams
|
||||
if err := json.Unmarshal(*r.Params, ¶ms); err != nil {
|
||||
return nil, jsonrpc2.NewErrorf(jsonrpc2.CodeParseError, "%v", err)
|
||||
sendParseError(ctx, conn, r, err)
|
||||
return
|
||||
}
|
||||
if err := client.LogMessage(ctx, ¶ms); err != nil {
|
||||
return nil, toJSONError(err)
|
||||
}
|
||||
return nil, nil
|
||||
unhandledError(client.LogMessage(ctx, ¶ms))
|
||||
|
||||
case "telemetry/event":
|
||||
var params interface{}
|
||||
if err := json.Unmarshal(*r.Params, ¶ms); err != nil {
|
||||
return nil, jsonrpc2.NewErrorf(jsonrpc2.CodeParseError, "%v", err)
|
||||
sendParseError(ctx, conn, r, err)
|
||||
return
|
||||
}
|
||||
if err := client.Telemetry(ctx, ¶ms); err != nil {
|
||||
return nil, toJSONError(err)
|
||||
}
|
||||
return nil, nil
|
||||
unhandledError(client.Telemetry(ctx, ¶ms))
|
||||
|
||||
case "client/registerCapability":
|
||||
var params RegistrationParams
|
||||
if err := json.Unmarshal(*r.Params, ¶ms); err != nil {
|
||||
return nil, jsonrpc2.NewErrorf(jsonrpc2.CodeParseError, "%v", err)
|
||||
sendParseError(ctx, conn, r, err)
|
||||
return
|
||||
}
|
||||
if err := client.RegisterCapability(ctx, ¶ms); err != nil {
|
||||
return nil, toJSONError(err)
|
||||
}
|
||||
return nil, nil
|
||||
unhandledError(client.RegisterCapability(ctx, ¶ms))
|
||||
|
||||
case "client/unregisterCapability":
|
||||
var params UnregistrationParams
|
||||
if err := json.Unmarshal(*r.Params, ¶ms); err != nil {
|
||||
return nil, jsonrpc2.NewErrorf(jsonrpc2.CodeParseError, "%v", err)
|
||||
sendParseError(ctx, conn, r, err)
|
||||
return
|
||||
}
|
||||
if err := client.UnregisterCapability(ctx, ¶ms); err != nil {
|
||||
return nil, toJSONError(err)
|
||||
}
|
||||
return nil, nil
|
||||
unhandledError(client.UnregisterCapability(ctx, ¶ms))
|
||||
|
||||
case "workspace/workspaceFolders":
|
||||
if r.Params != nil {
|
||||
return nil, jsonrpc2.NewErrorf(jsonrpc2.CodeInvalidParams, "Expected no params")
|
||||
conn.Reply(ctx, r, nil, jsonrpc2.NewErrorf(jsonrpc2.CodeInvalidParams, "Expected no params"))
|
||||
return
|
||||
}
|
||||
resp, err := client.WorkspaceFolders(ctx)
|
||||
if err != nil {
|
||||
return nil, toJSONError(err)
|
||||
}
|
||||
return resp, nil
|
||||
unhandledError(conn.Reply(ctx, r, resp, err))
|
||||
|
||||
case "workspace/configuration":
|
||||
var params ConfigurationParams
|
||||
if err := json.Unmarshal(*r.Params, ¶ms); err != nil {
|
||||
return nil, jsonrpc2.NewErrorf(jsonrpc2.CodeParseError, "%v", err)
|
||||
sendParseError(ctx, conn, r, err)
|
||||
return
|
||||
}
|
||||
resp, err := client.Configuration(ctx, ¶ms)
|
||||
if err != nil {
|
||||
return nil, toJSONError(err)
|
||||
}
|
||||
return resp, nil
|
||||
unhandledError(conn.Reply(ctx, r, resp, err))
|
||||
|
||||
case "workspace/applyEdit":
|
||||
var params ApplyWorkspaceEditParams
|
||||
if err := json.Unmarshal(*r.Params, ¶ms); err != nil {
|
||||
return nil, jsonrpc2.NewErrorf(jsonrpc2.CodeParseError, "%v", err)
|
||||
sendParseError(ctx, conn, r, err)
|
||||
return
|
||||
}
|
||||
resp, err := client.ApplyEdit(ctx, ¶ms)
|
||||
if err != nil {
|
||||
return nil, toJSONError(err)
|
||||
}
|
||||
return resp, nil
|
||||
unhandledError(conn.Reply(ctx, r, resp, err))
|
||||
|
||||
case "textDocument/publishDiagnostics":
|
||||
var params PublishDiagnosticsParams
|
||||
if err := json.Unmarshal(*r.Params, ¶ms); err != nil {
|
||||
return nil, jsonrpc2.NewErrorf(jsonrpc2.CodeParseError, "%v", err)
|
||||
sendParseError(ctx, conn, r, err)
|
||||
return
|
||||
}
|
||||
if err := client.PublishDiagnostics(ctx, ¶ms); err != nil {
|
||||
return nil, toJSONError(err)
|
||||
}
|
||||
return nil, nil
|
||||
unhandledError(client.PublishDiagnostics(ctx, ¶ms))
|
||||
|
||||
default:
|
||||
return nil, jsonrpc2.NewErrorf(jsonrpc2.CodeMethodNotFound, "method %q not found", r.Method)
|
||||
if r.IsNotify() {
|
||||
conn.Reply(ctx, r, nil, jsonrpc2.NewErrorf(jsonrpc2.CodeMethodNotFound, "method %q not found", r.Method))
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -6,6 +6,7 @@ package protocol
|
||||
|
||||
import (
|
||||
"context"
|
||||
"log"
|
||||
|
||||
"golang.org/x/tools/internal/jsonrpc2"
|
||||
)
|
||||
@ -15,20 +16,34 @@ func canceller(ctx context.Context, conn *jsonrpc2.Conn, req *jsonrpc2.Request)
|
||||
}
|
||||
|
||||
func RunClient(ctx context.Context, stream jsonrpc2.Stream, client Client, opts ...interface{}) (*jsonrpc2.Conn, Server) {
|
||||
opts = append([]interface{}{clientHandler(client), canceller}, opts...)
|
||||
opts = append([]interface{}{clientHandler(client), jsonrpc2.Canceler(canceller)}, opts...)
|
||||
conn := jsonrpc2.NewConn(ctx, stream, opts...)
|
||||
return conn, &serverDispatcher{Conn: conn}
|
||||
}
|
||||
|
||||
func RunServer(ctx context.Context, stream jsonrpc2.Stream, server Server, opts ...interface{}) (*jsonrpc2.Conn, Client) {
|
||||
opts = append([]interface{}{serverHandler(server), canceller}, opts...)
|
||||
opts = append([]interface{}{serverHandler(server), jsonrpc2.Canceler(canceller)}, opts...)
|
||||
conn := jsonrpc2.NewConn(ctx, stream, opts...)
|
||||
return conn, &clientDispatcher{Conn: conn}
|
||||
}
|
||||
|
||||
func toJSONError(err error) *jsonrpc2.Error {
|
||||
if jsonError, ok := err.(*jsonrpc2.Error); ok {
|
||||
return jsonError
|
||||
func sendParseError(ctx context.Context, conn *jsonrpc2.Conn, req *jsonrpc2.Request, err error) {
|
||||
if _, ok := err.(*jsonrpc2.Error); !ok {
|
||||
err = jsonrpc2.NewErrorf(jsonrpc2.CodeParseError, "%v", err)
|
||||
}
|
||||
return jsonrpc2.NewErrorf(jsonrpc2.CodeParseError, "%v", err)
|
||||
unhandledError(conn.Reply(ctx, req, nil, err))
|
||||
}
|
||||
|
||||
// unhandledError is used in places where an error may occur that cannot be handled.
|
||||
// This occurs in things like rpc handlers that are a notify, where we cannot
|
||||
// reply to the caller, or in a call when we are actually attempting to reply.
|
||||
// In these cases, there is nothing we can do with the error except log it, so
|
||||
// we do that in this function, and the presence of this function acts as a
|
||||
// useful reminder of why we are effectively dropping the error and also a
|
||||
// good place to hook in when debugging those kinds of errors.
|
||||
func unhandledError(err error) {
|
||||
if err == nil {
|
||||
return
|
||||
}
|
||||
log.Printf("%v", err)
|
||||
}
|
||||
|
@ -52,411 +52,339 @@ type Server interface {
|
||||
}
|
||||
|
||||
func serverHandler(server Server) jsonrpc2.Handler {
|
||||
return func(ctx context.Context, conn *jsonrpc2.Conn, r *jsonrpc2.Request) (interface{}, *jsonrpc2.Error) {
|
||||
return func(ctx context.Context, conn *jsonrpc2.Conn, r *jsonrpc2.Request) {
|
||||
switch r.Method {
|
||||
case "initialize":
|
||||
var params InitializeParams
|
||||
if err := json.Unmarshal(*r.Params, ¶ms); err != nil {
|
||||
return nil, jsonrpc2.NewErrorf(jsonrpc2.CodeParseError, "%v", err)
|
||||
sendParseError(ctx, conn, r, err)
|
||||
return
|
||||
}
|
||||
resp, err := server.Initialize(ctx, ¶ms)
|
||||
if err != nil {
|
||||
return nil, toJSONError(err)
|
||||
}
|
||||
return resp, nil
|
||||
unhandledError(conn.Reply(ctx, r, resp, err))
|
||||
|
||||
case "initialized":
|
||||
var params InitializedParams
|
||||
if err := json.Unmarshal(*r.Params, ¶ms); err != nil {
|
||||
return nil, jsonrpc2.NewErrorf(jsonrpc2.CodeParseError, "%v", err)
|
||||
sendParseError(ctx, conn, r, err)
|
||||
return
|
||||
}
|
||||
if err := server.Initialized(ctx, ¶ms); err != nil {
|
||||
return nil, toJSONError(err)
|
||||
}
|
||||
return nil, nil
|
||||
unhandledError(server.Initialized(ctx, ¶ms))
|
||||
|
||||
case "shutdown":
|
||||
if r.Params != nil {
|
||||
return nil, jsonrpc2.NewErrorf(jsonrpc2.CodeInvalidParams, "Expected no params")
|
||||
conn.Reply(ctx, r, nil, jsonrpc2.NewErrorf(jsonrpc2.CodeInvalidParams, "Expected no params"))
|
||||
return
|
||||
}
|
||||
if err := server.Shutdown(ctx); err != nil {
|
||||
return nil, toJSONError(err)
|
||||
}
|
||||
return nil, nil
|
||||
unhandledError(server.Shutdown(ctx))
|
||||
|
||||
case "exit":
|
||||
if r.Params != nil {
|
||||
return nil, jsonrpc2.NewErrorf(jsonrpc2.CodeInvalidParams, "Expected no params")
|
||||
conn.Reply(ctx, r, nil, jsonrpc2.NewErrorf(jsonrpc2.CodeInvalidParams, "Expected no params"))
|
||||
return
|
||||
}
|
||||
if err := server.Exit(ctx); err != nil {
|
||||
return nil, toJSONError(err)
|
||||
}
|
||||
return nil, nil
|
||||
unhandledError(server.Exit(ctx))
|
||||
|
||||
case "$/cancelRequest":
|
||||
var params CancelParams
|
||||
if err := json.Unmarshal(*r.Params, ¶ms); err != nil {
|
||||
return nil, jsonrpc2.NewErrorf(jsonrpc2.CodeParseError, "%v", err)
|
||||
sendParseError(ctx, conn, r, err)
|
||||
return
|
||||
}
|
||||
conn.Cancel(params.ID)
|
||||
return nil, nil
|
||||
|
||||
case "workspace/didChangeWorkspaceFolders":
|
||||
var params DidChangeWorkspaceFoldersParams
|
||||
if err := json.Unmarshal(*r.Params, ¶ms); err != nil {
|
||||
return nil, jsonrpc2.NewErrorf(jsonrpc2.CodeParseError, "%v", err)
|
||||
sendParseError(ctx, conn, r, err)
|
||||
return
|
||||
}
|
||||
if err := server.DidChangeWorkspaceFolders(ctx, ¶ms); err != nil {
|
||||
return nil, toJSONError(err)
|
||||
}
|
||||
return nil, nil
|
||||
unhandledError(server.DidChangeWorkspaceFolders(ctx, ¶ms))
|
||||
|
||||
case "workspace/didChangeConfiguration":
|
||||
var params DidChangeConfigurationParams
|
||||
if err := json.Unmarshal(*r.Params, ¶ms); err != nil {
|
||||
return nil, jsonrpc2.NewErrorf(jsonrpc2.CodeParseError, "%v", err)
|
||||
sendParseError(ctx, conn, r, err)
|
||||
return
|
||||
}
|
||||
if err := server.DidChangeConfiguration(ctx, ¶ms); err != nil {
|
||||
return nil, toJSONError(err)
|
||||
}
|
||||
return nil, nil
|
||||
unhandledError(server.DidChangeConfiguration(ctx, ¶ms))
|
||||
|
||||
case "workspace/didChangeWatchedFiles":
|
||||
var params DidChangeWatchedFilesParams
|
||||
if err := json.Unmarshal(*r.Params, ¶ms); err != nil {
|
||||
return nil, jsonrpc2.NewErrorf(jsonrpc2.CodeParseError, "%v", err)
|
||||
sendParseError(ctx, conn, r, err)
|
||||
return
|
||||
}
|
||||
if err := server.DidChangeWatchedFiles(ctx, ¶ms); err != nil {
|
||||
return nil, toJSONError(err)
|
||||
}
|
||||
return nil, nil
|
||||
unhandledError(server.DidChangeWatchedFiles(ctx, ¶ms))
|
||||
|
||||
case "workspace/symbol":
|
||||
var params WorkspaceSymbolParams
|
||||
if err := json.Unmarshal(*r.Params, ¶ms); err != nil {
|
||||
return nil, jsonrpc2.NewErrorf(jsonrpc2.CodeParseError, "%v", err)
|
||||
sendParseError(ctx, conn, r, err)
|
||||
return
|
||||
}
|
||||
resp, err := server.Symbols(ctx, ¶ms)
|
||||
if err != nil {
|
||||
return nil, toJSONError(err)
|
||||
}
|
||||
return resp, nil
|
||||
unhandledError(conn.Reply(ctx, r, resp, err))
|
||||
|
||||
case "workspace/executeCommand":
|
||||
var params ExecuteCommandParams
|
||||
if err := json.Unmarshal(*r.Params, ¶ms); err != nil {
|
||||
return nil, jsonrpc2.NewErrorf(jsonrpc2.CodeParseError, "%v", err)
|
||||
sendParseError(ctx, conn, r, err)
|
||||
return
|
||||
}
|
||||
resp, err := server.ExecuteCommand(ctx, ¶ms)
|
||||
if err != nil {
|
||||
return nil, toJSONError(err)
|
||||
}
|
||||
return resp, nil
|
||||
unhandledError(conn.Reply(ctx, r, resp, err))
|
||||
|
||||
case "textDocument/didOpen":
|
||||
var params DidOpenTextDocumentParams
|
||||
if err := json.Unmarshal(*r.Params, ¶ms); err != nil {
|
||||
return nil, jsonrpc2.NewErrorf(jsonrpc2.CodeParseError, "%v", err)
|
||||
sendParseError(ctx, conn, r, err)
|
||||
return
|
||||
}
|
||||
if err := server.DidOpen(ctx, ¶ms); err != nil {
|
||||
return nil, toJSONError(err)
|
||||
}
|
||||
return nil, nil
|
||||
unhandledError(server.DidOpen(ctx, ¶ms))
|
||||
|
||||
case "textDocument/didChange":
|
||||
var params DidChangeTextDocumentParams
|
||||
if err := json.Unmarshal(*r.Params, ¶ms); err != nil {
|
||||
return nil, jsonrpc2.NewErrorf(jsonrpc2.CodeParseError, "%v", err)
|
||||
sendParseError(ctx, conn, r, err)
|
||||
return
|
||||
}
|
||||
if err := server.DidChange(ctx, ¶ms); err != nil {
|
||||
return nil, toJSONError(err)
|
||||
}
|
||||
return nil, nil
|
||||
unhandledError(server.DidChange(ctx, ¶ms))
|
||||
|
||||
case "textDocument/willSave":
|
||||
var params WillSaveTextDocumentParams
|
||||
if err := json.Unmarshal(*r.Params, ¶ms); err != nil {
|
||||
return nil, jsonrpc2.NewErrorf(jsonrpc2.CodeParseError, "%v", err)
|
||||
sendParseError(ctx, conn, r, err)
|
||||
return
|
||||
}
|
||||
if err := server.WillSave(ctx, ¶ms); err != nil {
|
||||
return nil, toJSONError(err)
|
||||
}
|
||||
return nil, nil
|
||||
unhandledError(server.WillSave(ctx, ¶ms))
|
||||
|
||||
case "textDocument/willSaveWaitUntil":
|
||||
var params WillSaveTextDocumentParams
|
||||
if err := json.Unmarshal(*r.Params, ¶ms); err != nil {
|
||||
return nil, jsonrpc2.NewErrorf(jsonrpc2.CodeParseError, "%v", err)
|
||||
sendParseError(ctx, conn, r, err)
|
||||
return
|
||||
}
|
||||
resp, err := server.WillSaveWaitUntil(ctx, ¶ms)
|
||||
if err != nil {
|
||||
return nil, toJSONError(err)
|
||||
}
|
||||
return resp, nil
|
||||
unhandledError(conn.Reply(ctx, r, resp, err))
|
||||
|
||||
case "textDocument/didSave":
|
||||
var params DidSaveTextDocumentParams
|
||||
if err := json.Unmarshal(*r.Params, ¶ms); err != nil {
|
||||
return nil, jsonrpc2.NewErrorf(jsonrpc2.CodeParseError, "%v", err)
|
||||
sendParseError(ctx, conn, r, err)
|
||||
return
|
||||
}
|
||||
if err := server.DidSave(ctx, ¶ms); err != nil {
|
||||
return nil, toJSONError(err)
|
||||
}
|
||||
return nil, nil
|
||||
unhandledError(server.DidSave(ctx, ¶ms))
|
||||
|
||||
case "textDocument/didClose":
|
||||
var params DidCloseTextDocumentParams
|
||||
if err := json.Unmarshal(*r.Params, ¶ms); err != nil {
|
||||
return nil, jsonrpc2.NewErrorf(jsonrpc2.CodeParseError, "%v", err)
|
||||
sendParseError(ctx, conn, r, err)
|
||||
return
|
||||
}
|
||||
if err := server.DidClose(ctx, ¶ms); err != nil {
|
||||
return nil, toJSONError(err)
|
||||
}
|
||||
return nil, nil
|
||||
unhandledError(server.DidClose(ctx, ¶ms))
|
||||
|
||||
case "textDocument/completion":
|
||||
var params CompletionParams
|
||||
if err := json.Unmarshal(*r.Params, ¶ms); err != nil {
|
||||
return nil, jsonrpc2.NewErrorf(jsonrpc2.CodeParseError, "%v", err)
|
||||
sendParseError(ctx, conn, r, err)
|
||||
return
|
||||
}
|
||||
resp, err := server.Completion(ctx, ¶ms)
|
||||
if err != nil {
|
||||
return nil, toJSONError(err)
|
||||
}
|
||||
return resp, nil
|
||||
unhandledError(conn.Reply(ctx, r, resp, err))
|
||||
|
||||
case "completionItem/resolve":
|
||||
var params CompletionItem
|
||||
if err := json.Unmarshal(*r.Params, ¶ms); err != nil {
|
||||
return nil, jsonrpc2.NewErrorf(jsonrpc2.CodeParseError, "%v", err)
|
||||
sendParseError(ctx, conn, r, err)
|
||||
return
|
||||
}
|
||||
resp, err := server.CompletionResolve(ctx, ¶ms)
|
||||
if err != nil {
|
||||
return nil, toJSONError(err)
|
||||
}
|
||||
return resp, nil
|
||||
unhandledError(conn.Reply(ctx, r, resp, err))
|
||||
|
||||
case "textDocument/hover":
|
||||
var params TextDocumentPositionParams
|
||||
if err := json.Unmarshal(*r.Params, ¶ms); err != nil {
|
||||
return nil, jsonrpc2.NewErrorf(jsonrpc2.CodeParseError, "%v", err)
|
||||
sendParseError(ctx, conn, r, err)
|
||||
return
|
||||
}
|
||||
resp, err := server.Hover(ctx, ¶ms)
|
||||
if err != nil {
|
||||
return nil, toJSONError(err)
|
||||
}
|
||||
return resp, nil
|
||||
unhandledError(conn.Reply(ctx, r, resp, err))
|
||||
|
||||
case "textDocument/signatureHelp":
|
||||
var params TextDocumentPositionParams
|
||||
if err := json.Unmarshal(*r.Params, ¶ms); err != nil {
|
||||
return nil, jsonrpc2.NewErrorf(jsonrpc2.CodeParseError, "%v", err)
|
||||
sendParseError(ctx, conn, r, err)
|
||||
return
|
||||
}
|
||||
resp, err := server.SignatureHelp(ctx, ¶ms)
|
||||
if err != nil {
|
||||
return nil, toJSONError(err)
|
||||
}
|
||||
return resp, nil
|
||||
unhandledError(conn.Reply(ctx, r, resp, err))
|
||||
|
||||
case "textDocument/definition":
|
||||
var params TextDocumentPositionParams
|
||||
if err := json.Unmarshal(*r.Params, ¶ms); err != nil {
|
||||
return nil, jsonrpc2.NewErrorf(jsonrpc2.CodeParseError, "%v", err)
|
||||
sendParseError(ctx, conn, r, err)
|
||||
return
|
||||
}
|
||||
resp, err := server.Definition(ctx, ¶ms)
|
||||
if err != nil {
|
||||
return nil, toJSONError(err)
|
||||
}
|
||||
return resp, nil
|
||||
unhandledError(conn.Reply(ctx, r, resp, err))
|
||||
|
||||
case "textDocument/typeDefinition":
|
||||
var params TextDocumentPositionParams
|
||||
if err := json.Unmarshal(*r.Params, ¶ms); err != nil {
|
||||
return nil, jsonrpc2.NewErrorf(jsonrpc2.CodeParseError, "%v", err)
|
||||
sendParseError(ctx, conn, r, err)
|
||||
return
|
||||
}
|
||||
resp, err := server.TypeDefinition(ctx, ¶ms)
|
||||
if err != nil {
|
||||
return nil, toJSONError(err)
|
||||
}
|
||||
return resp, nil
|
||||
unhandledError(conn.Reply(ctx, r, resp, err))
|
||||
|
||||
case "textDocument/implementation":
|
||||
var params TextDocumentPositionParams
|
||||
if err := json.Unmarshal(*r.Params, ¶ms); err != nil {
|
||||
return nil, jsonrpc2.NewErrorf(jsonrpc2.CodeParseError, "%v", err)
|
||||
sendParseError(ctx, conn, r, err)
|
||||
return
|
||||
}
|
||||
resp, err := server.Implementation(ctx, ¶ms)
|
||||
if err != nil {
|
||||
return nil, toJSONError(err)
|
||||
}
|
||||
return resp, nil
|
||||
unhandledError(conn.Reply(ctx, r, resp, err))
|
||||
|
||||
case "textDocument/references":
|
||||
var params ReferenceParams
|
||||
if err := json.Unmarshal(*r.Params, ¶ms); err != nil {
|
||||
return nil, jsonrpc2.NewErrorf(jsonrpc2.CodeParseError, "%v", err)
|
||||
sendParseError(ctx, conn, r, err)
|
||||
return
|
||||
}
|
||||
resp, err := server.References(ctx, ¶ms)
|
||||
if err != nil {
|
||||
return nil, toJSONError(err)
|
||||
}
|
||||
return resp, nil
|
||||
unhandledError(conn.Reply(ctx, r, resp, err))
|
||||
|
||||
case "textDocument/documentHighlight":
|
||||
var params TextDocumentPositionParams
|
||||
if err := json.Unmarshal(*r.Params, ¶ms); err != nil {
|
||||
return nil, jsonrpc2.NewErrorf(jsonrpc2.CodeParseError, "%v", err)
|
||||
sendParseError(ctx, conn, r, err)
|
||||
return
|
||||
}
|
||||
resp, err := server.DocumentHighlight(ctx, ¶ms)
|
||||
if err != nil {
|
||||
return nil, toJSONError(err)
|
||||
}
|
||||
return resp, nil
|
||||
unhandledError(conn.Reply(ctx, r, resp, err))
|
||||
|
||||
case "textDocument/documentSymbol":
|
||||
var params DocumentSymbolParams
|
||||
if err := json.Unmarshal(*r.Params, ¶ms); err != nil {
|
||||
return nil, jsonrpc2.NewErrorf(jsonrpc2.CodeParseError, "%v", err)
|
||||
sendParseError(ctx, conn, r, err)
|
||||
return
|
||||
}
|
||||
resp, err := server.DocumentSymbol(ctx, ¶ms)
|
||||
if err != nil {
|
||||
return nil, toJSONError(err)
|
||||
}
|
||||
return resp, nil
|
||||
unhandledError(conn.Reply(ctx, r, resp, err))
|
||||
|
||||
case "textDocument/codeAction":
|
||||
var params CodeActionParams
|
||||
if err := json.Unmarshal(*r.Params, ¶ms); err != nil {
|
||||
return nil, jsonrpc2.NewErrorf(jsonrpc2.CodeParseError, "%v", err)
|
||||
sendParseError(ctx, conn, r, err)
|
||||
return
|
||||
}
|
||||
resp, err := server.CodeAction(ctx, ¶ms)
|
||||
if err != nil {
|
||||
return nil, toJSONError(err)
|
||||
}
|
||||
return resp, nil
|
||||
unhandledError(conn.Reply(ctx, r, resp, err))
|
||||
|
||||
case "textDocument/codeLens":
|
||||
var params CodeLensParams
|
||||
if err := json.Unmarshal(*r.Params, ¶ms); err != nil {
|
||||
return nil, jsonrpc2.NewErrorf(jsonrpc2.CodeParseError, "%v", err)
|
||||
sendParseError(ctx, conn, r, err)
|
||||
return
|
||||
}
|
||||
resp, err := server.CodeLens(ctx, ¶ms)
|
||||
if err != nil {
|
||||
return nil, toJSONError(err)
|
||||
}
|
||||
return resp, nil
|
||||
unhandledError(conn.Reply(ctx, r, resp, err))
|
||||
|
||||
case "codeLens/resolve":
|
||||
var params CodeLens
|
||||
if err := json.Unmarshal(*r.Params, ¶ms); err != nil {
|
||||
return nil, jsonrpc2.NewErrorf(jsonrpc2.CodeParseError, "%v", err)
|
||||
sendParseError(ctx, conn, r, err)
|
||||
return
|
||||
}
|
||||
resp, err := server.CodeLensResolve(ctx, ¶ms)
|
||||
if err != nil {
|
||||
return nil, toJSONError(err)
|
||||
}
|
||||
return resp, nil
|
||||
unhandledError(conn.Reply(ctx, r, resp, err))
|
||||
|
||||
case "textDocument/documentLink":
|
||||
var params DocumentLinkParams
|
||||
if err := json.Unmarshal(*r.Params, ¶ms); err != nil {
|
||||
return nil, jsonrpc2.NewErrorf(jsonrpc2.CodeParseError, "%v", err)
|
||||
sendParseError(ctx, conn, r, err)
|
||||
return
|
||||
}
|
||||
resp, err := server.DocumentLink(ctx, ¶ms)
|
||||
if err != nil {
|
||||
return nil, toJSONError(err)
|
||||
}
|
||||
return resp, nil
|
||||
unhandledError(conn.Reply(ctx, r, resp, err))
|
||||
|
||||
case "documentLink/resolve":
|
||||
var params DocumentLink
|
||||
if err := json.Unmarshal(*r.Params, ¶ms); err != nil {
|
||||
return nil, jsonrpc2.NewErrorf(jsonrpc2.CodeParseError, "%v", err)
|
||||
sendParseError(ctx, conn, r, err)
|
||||
return
|
||||
}
|
||||
resp, err := server.DocumentLinkResolve(ctx, ¶ms)
|
||||
if err != nil {
|
||||
return nil, toJSONError(err)
|
||||
}
|
||||
return resp, nil
|
||||
unhandledError(conn.Reply(ctx, r, resp, err))
|
||||
|
||||
case "textDocument/documentColor":
|
||||
var params DocumentColorParams
|
||||
if err := json.Unmarshal(*r.Params, ¶ms); err != nil {
|
||||
return nil, jsonrpc2.NewErrorf(jsonrpc2.CodeParseError, "%v", err)
|
||||
sendParseError(ctx, conn, r, err)
|
||||
return
|
||||
}
|
||||
resp, err := server.DocumentColor(ctx, ¶ms)
|
||||
if err != nil {
|
||||
return nil, toJSONError(err)
|
||||
}
|
||||
return resp, nil
|
||||
unhandledError(conn.Reply(ctx, r, resp, err))
|
||||
|
||||
case "textDocument/colorPresentation":
|
||||
var params ColorPresentationParams
|
||||
if err := json.Unmarshal(*r.Params, ¶ms); err != nil {
|
||||
return nil, jsonrpc2.NewErrorf(jsonrpc2.CodeParseError, "%v", err)
|
||||
sendParseError(ctx, conn, r, err)
|
||||
return
|
||||
}
|
||||
resp, err := server.ColorPresentation(ctx, ¶ms)
|
||||
if err != nil {
|
||||
return nil, toJSONError(err)
|
||||
}
|
||||
return resp, nil
|
||||
unhandledError(conn.Reply(ctx, r, resp, err))
|
||||
|
||||
case "textDocument/formatting":
|
||||
var params DocumentFormattingParams
|
||||
if err := json.Unmarshal(*r.Params, ¶ms); err != nil {
|
||||
return nil, jsonrpc2.NewErrorf(jsonrpc2.CodeParseError, "%v", err)
|
||||
sendParseError(ctx, conn, r, err)
|
||||
return
|
||||
}
|
||||
resp, err := server.Formatting(ctx, ¶ms)
|
||||
if err != nil {
|
||||
return nil, toJSONError(err)
|
||||
}
|
||||
return resp, nil
|
||||
unhandledError(conn.Reply(ctx, r, resp, err))
|
||||
|
||||
case "textDocument/rangeFormatting":
|
||||
var params DocumentRangeFormattingParams
|
||||
if err := json.Unmarshal(*r.Params, ¶ms); err != nil {
|
||||
return nil, jsonrpc2.NewErrorf(jsonrpc2.CodeParseError, "%v", err)
|
||||
sendParseError(ctx, conn, r, err)
|
||||
return
|
||||
}
|
||||
resp, err := server.RangeFormatting(ctx, ¶ms)
|
||||
if err != nil {
|
||||
return nil, toJSONError(err)
|
||||
}
|
||||
return resp, nil
|
||||
unhandledError(conn.Reply(ctx, r, resp, err))
|
||||
|
||||
case "textDocument/onTypeFormatting":
|
||||
var params DocumentOnTypeFormattingParams
|
||||
if err := json.Unmarshal(*r.Params, ¶ms); err != nil {
|
||||
return nil, jsonrpc2.NewErrorf(jsonrpc2.CodeParseError, "%v", err)
|
||||
sendParseError(ctx, conn, r, err)
|
||||
return
|
||||
}
|
||||
resp, err := server.OnTypeFormatting(ctx, ¶ms)
|
||||
if err != nil {
|
||||
return nil, toJSONError(err)
|
||||
}
|
||||
return resp, nil
|
||||
unhandledError(conn.Reply(ctx, r, resp, err))
|
||||
|
||||
case "textDocument/rename":
|
||||
var params RenameParams
|
||||
if err := json.Unmarshal(*r.Params, ¶ms); err != nil {
|
||||
return nil, jsonrpc2.NewErrorf(jsonrpc2.CodeParseError, "%v", err)
|
||||
sendParseError(ctx, conn, r, err)
|
||||
return
|
||||
}
|
||||
resp, err := server.Rename(ctx, ¶ms)
|
||||
if err != nil {
|
||||
return nil, toJSONError(err)
|
||||
}
|
||||
return resp, nil
|
||||
unhandledError(conn.Reply(ctx, r, resp, err))
|
||||
|
||||
case "textDocument/foldingRanges":
|
||||
var params FoldingRangeRequestParam
|
||||
if err := json.Unmarshal(*r.Params, ¶ms); err != nil {
|
||||
return nil, jsonrpc2.NewErrorf(jsonrpc2.CodeParseError, "%v", err)
|
||||
sendParseError(ctx, conn, r, err)
|
||||
return
|
||||
}
|
||||
resp, err := server.FoldingRanges(ctx, ¶ms)
|
||||
if err != nil {
|
||||
return nil, toJSONError(err)
|
||||
}
|
||||
return resp, nil
|
||||
unhandledError(conn.Reply(ctx, r, resp, err))
|
||||
default:
|
||||
return nil, jsonrpc2.NewErrorf(jsonrpc2.CodeMethodNotFound, "method %q not found", r.Method)
|
||||
if r.IsNotify() {
|
||||
conn.Reply(ctx, r, nil, jsonrpc2.NewErrorf(jsonrpc2.CodeMethodNotFound, "method %q not found", r.Method))
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user