1
0
mirror of https://github.com/golang/go synced 2024-09-30 22:48:32 -06:00
go/internal/lsp/protocol/protocol.go
Ian Cottrell 17cc17e0bb internal/jsonrpc2: remove the legacy interface
We can do cancelling at the top level handler now, it can drop the cancel
messages themselves before they enter the queue stage, and also track
all the events as they flow through it.
The ugly part is the OnCancelled interface, which is a bit clunky.

Change-Id: I3fa972198625fb3517fdecc740d1a3fdb19a188a
Reviewed-on: https://go-review.googlesource.com/c/tools/+/226959
Run-TryBot: Ian Cottrell <iancottrell@google.com>
Reviewed-by: Robert Findley <rfindley@google.com>
2020-04-06 14:43:58 +00:00

73 lines
2.1 KiB
Go

// Copyright 2018 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
package protocol
import (
"context"
"encoding/json"
"fmt"
"golang.org/x/tools/internal/jsonrpc2"
"golang.org/x/tools/internal/telemetry/event"
"golang.org/x/tools/internal/xcontext"
)
const (
// RequestCancelledError should be used when a request is cancelled early.
RequestCancelledError = -32800
)
// ClientDispatcher returns a Client that dispatches LSP requests across the
// given jsonrpc2 connection.
func ClientDispatcher(conn *jsonrpc2.Conn) Client {
conn.OnCancelled(cancelCall)
return &clientDispatcher{Conn: conn}
}
// ServerDispatcher returns a Server that dispatches LSP requests across the
// given jsonrpc2 connection.
func ServerDispatcher(conn *jsonrpc2.Conn) Server {
conn.OnCancelled(cancelCall)
return &serverDispatcher{Conn: conn}
}
func CancelHandler(handler jsonrpc2.Handler) jsonrpc2.Handler {
handler, canceller := jsonrpc2.CancelHandler(handler)
return func(ctx context.Context, req *jsonrpc2.Request) error {
if req.Method != "$/cancelRequest" {
return handler(ctx, req)
}
var params CancelParams
if err := json.Unmarshal(*req.Params, &params); err != nil {
return sendParseError(ctx, req, err)
}
v := jsonrpc2.ID{}
if n, ok := params.ID.(float64); ok {
v.Number = int64(n)
} else if s, ok := params.ID.(string); ok {
v.Name = s
} else {
return sendParseError(ctx, req, fmt.Errorf("Request ID %v malformed", params.ID))
}
canceller(v)
return req.Reply(ctx, nil, nil)
}
}
func cancelCall(ctx context.Context, conn *jsonrpc2.Conn, id jsonrpc2.ID) {
ctx = xcontext.Detach(ctx)
ctx, done := event.StartSpan(ctx, "protocol.canceller")
defer done()
// Note that only *jsonrpc2.ID implements json.Marshaler.
conn.Notify(ctx, "$/cancelRequest", &CancelParams{ID: &id})
}
func sendParseError(ctx context.Context, req *jsonrpc2.Request, err error) error {
if _, ok := err.(*jsonrpc2.Error); !ok {
err = jsonrpc2.NewErrorf(jsonrpc2.CodeParseError, "%v", err)
}
return req.Reply(ctx, nil, err)
}