1// Copyright 2018 The Go Authors. All rights reserved. 2// Use of this source code is governed by a BSD-style 3// license that can be found in the LICENSE file. 4 5package protocol 6 7import ( 8 "context" 9 "encoding/json" 10 "fmt" 11 12 "golang.org/x/tools/internal/jsonrpc2" 13 "golang.org/x/tools/internal/telemetry/log" 14 "golang.org/x/tools/internal/telemetry/trace" 15 "golang.org/x/tools/internal/xcontext" 16) 17 18const ( 19 // RequestCancelledError should be used when a request is cancelled early. 20 RequestCancelledError = -32800 21) 22 23type clientHandler struct { 24 jsonrpc2.EmptyHandler 25 client Client 26} 27 28// ClientHandler returns a jsonrpc2.Handler that handles the LSP client 29// protocol. 30func ClientHandler(client Client) jsonrpc2.Handler { 31 return &clientHandler{client: client} 32} 33 34type serverHandler struct { 35 jsonrpc2.EmptyHandler 36 server Server 37} 38 39// ServerHandler returns a jsonrpc2.Handler that handles the LSP server 40// protocol. 41func ServerHandler(server Server) jsonrpc2.Handler { 42 return &serverHandler{server: server} 43} 44 45// ClientDispatcher returns a Client that dispatches LSP requests across the 46// given jsonrpc2 connection. 47func ClientDispatcher(conn *jsonrpc2.Conn) Client { 48 return &clientDispatcher{Conn: conn} 49} 50 51// ServerDispatcher returns a Server that dispatches LSP requests across the 52// given jsonrpc2 connection. 53func ServerDispatcher(conn *jsonrpc2.Conn) Server { 54 return &serverDispatcher{Conn: conn} 55} 56 57// Canceller is a jsonrpc2.Handler that handles LSP request cancellation. 58type Canceller struct{ jsonrpc2.EmptyHandler } 59 60func (Canceller) Request(ctx context.Context, conn *jsonrpc2.Conn, direction jsonrpc2.Direction, r *jsonrpc2.WireRequest) context.Context { 61 if direction == jsonrpc2.Receive && r.Method == "$/cancelRequest" { 62 var params CancelParams 63 if err := json.Unmarshal(*r.Params, ¶ms); err != nil { 64 log.Error(ctx, "", err) 65 } else { 66 v := jsonrpc2.ID{} 67 if n, ok := params.ID.(float64); ok { 68 v.Number = int64(n) 69 } else if s, ok := params.ID.(string); ok { 70 v.Name = s 71 } else { 72 log.Error(ctx, fmt.Sprintf("Request ID %v malformed", params.ID), nil) 73 return ctx 74 } 75 conn.Cancel(v) 76 } 77 } 78 return ctx 79} 80 81func (Canceller) Cancel(ctx context.Context, conn *jsonrpc2.Conn, id jsonrpc2.ID, cancelled bool) bool { 82 if cancelled { 83 return false 84 } 85 ctx = xcontext.Detach(ctx) 86 ctx, done := trace.StartSpan(ctx, "protocol.canceller") 87 defer done() 88 // Note that only *jsonrpc2.ID implements json.Marshaler. 89 conn.Notify(ctx, "$/cancelRequest", &CancelParams{ID: &id}) 90 return true 91} 92 93func (Canceller) Deliver(ctx context.Context, r *jsonrpc2.Request, delivered bool) bool { 94 // Hide cancellations from downstream handlers. 95 return r.Method == "$/cancelRequest" 96} 97 98func sendParseError(ctx context.Context, req *jsonrpc2.Request, err error) { 99 if _, ok := err.(*jsonrpc2.Error); !ok { 100 err = jsonrpc2.NewErrorf(jsonrpc2.CodeParseError, "%v", err) 101 } 102 if err := req.Reply(ctx, nil, err); err != nil { 103 log.Error(ctx, "", err) 104 } 105} 106