mirror of
https://github.com/golang/go
synced 2024-09-30 22:48:32 -06:00
17cc17e0bb
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>
73 lines
2.1 KiB
Go
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, ¶ms); 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)
|
|
}
|