github.com/powerman/golang-tools@v0.1.11-0.20220410185822-5ad214d8d803/internal/lsp/lsprpc/binder.go (about) 1 // Copyright 2021 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 5 package lsprpc 6 7 import ( 8 "context" 9 "encoding/json" 10 "fmt" 11 12 "github.com/powerman/golang-tools/internal/event" 13 jsonrpc2_v2 "github.com/powerman/golang-tools/internal/jsonrpc2_v2" 14 "github.com/powerman/golang-tools/internal/lsp/protocol" 15 "github.com/powerman/golang-tools/internal/xcontext" 16 errors "golang.org/x/xerrors" 17 ) 18 19 // The BinderFunc type adapts a bind function to implement the jsonrpc2.Binder 20 // interface. 21 type BinderFunc func(ctx context.Context, conn *jsonrpc2_v2.Connection) (jsonrpc2_v2.ConnectionOptions, error) 22 23 func (f BinderFunc) Bind(ctx context.Context, conn *jsonrpc2_v2.Connection) (jsonrpc2_v2.ConnectionOptions, error) { 24 return f(ctx, conn) 25 } 26 27 // Middleware defines a transformation of jsonrpc2 Binders, that may be 28 // composed to build jsonrpc2 servers. 29 type Middleware func(jsonrpc2_v2.Binder) jsonrpc2_v2.Binder 30 31 // A ServerFunc is used to construct an LSP server for a given client. 32 type ServerFunc func(context.Context, protocol.ClientCloser) protocol.Server 33 34 // ServerBinder binds incoming connections to a new server. 35 type ServerBinder struct { 36 newServer ServerFunc 37 } 38 39 func NewServerBinder(newServer ServerFunc) *ServerBinder { 40 return &ServerBinder{newServer: newServer} 41 } 42 43 func (b *ServerBinder) Bind(ctx context.Context, conn *jsonrpc2_v2.Connection) (jsonrpc2_v2.ConnectionOptions, error) { 44 client := protocol.ClientDispatcherV2(conn) 45 server := b.newServer(ctx, client) 46 serverHandler := protocol.ServerHandlerV2(server) 47 // Wrap the server handler to inject the client into each request context, so 48 // that log events are reflected back to the client. 49 wrapped := jsonrpc2_v2.HandlerFunc(func(ctx context.Context, req *jsonrpc2_v2.Request) (interface{}, error) { 50 ctx = protocol.WithClient(ctx, client) 51 return serverHandler.Handle(ctx, req) 52 }) 53 preempter := &canceler{ 54 conn: conn, 55 } 56 return jsonrpc2_v2.ConnectionOptions{ 57 Handler: wrapped, 58 Preempter: preempter, 59 }, nil 60 } 61 62 type canceler struct { 63 conn *jsonrpc2_v2.Connection 64 } 65 66 func (c *canceler) Preempt(ctx context.Context, req *jsonrpc2_v2.Request) (interface{}, error) { 67 if req.Method != "$/cancelRequest" { 68 return nil, jsonrpc2_v2.ErrNotHandled 69 } 70 var params protocol.CancelParams 71 if err := json.Unmarshal(req.Params, ¶ms); err != nil { 72 return nil, errors.Errorf("%w: %v", jsonrpc2_v2.ErrParse, err) 73 } 74 var id jsonrpc2_v2.ID 75 switch raw := params.ID.(type) { 76 case float64: 77 id = jsonrpc2_v2.Int64ID(int64(raw)) 78 case string: 79 id = jsonrpc2_v2.StringID(raw) 80 default: 81 return nil, errors.Errorf("%w: invalid ID type %T", jsonrpc2_v2.ErrParse, params.ID) 82 } 83 c.conn.Cancel(id) 84 return nil, nil 85 } 86 87 type ForwardBinder struct { 88 dialer jsonrpc2_v2.Dialer 89 onBind func(*jsonrpc2_v2.Connection) 90 } 91 92 func NewForwardBinder(dialer jsonrpc2_v2.Dialer) *ForwardBinder { 93 return &ForwardBinder{ 94 dialer: dialer, 95 } 96 } 97 98 func (b *ForwardBinder) Bind(ctx context.Context, conn *jsonrpc2_v2.Connection) (opts jsonrpc2_v2.ConnectionOptions, _ error) { 99 client := protocol.ClientDispatcherV2(conn) 100 clientBinder := NewClientBinder(func(context.Context, protocol.Server) protocol.Client { return client }) 101 serverConn, err := jsonrpc2_v2.Dial(context.Background(), b.dialer, clientBinder) 102 if err != nil { 103 return opts, err 104 } 105 if b.onBind != nil { 106 b.onBind(serverConn) 107 } 108 server := protocol.ServerDispatcherV2(serverConn) 109 preempter := &canceler{ 110 conn: conn, 111 } 112 detached := xcontext.Detach(ctx) 113 go func() { 114 conn.Wait() 115 if err := serverConn.Close(); err != nil { 116 event.Log(detached, fmt.Sprintf("closing remote connection: %v", err)) 117 } 118 }() 119 return jsonrpc2_v2.ConnectionOptions{ 120 Handler: protocol.ServerHandlerV2(server), 121 Preempter: preempter, 122 }, nil 123 } 124 125 // A ClientFunc is used to construct an LSP client for a given server. 126 type ClientFunc func(context.Context, protocol.Server) protocol.Client 127 128 // ClientBinder binds an LSP client to an incoming connection. 129 type ClientBinder struct { 130 newClient ClientFunc 131 } 132 133 func NewClientBinder(newClient ClientFunc) *ClientBinder { 134 return &ClientBinder{newClient} 135 } 136 137 func (b *ClientBinder) Bind(ctx context.Context, conn *jsonrpc2_v2.Connection) (jsonrpc2_v2.ConnectionOptions, error) { 138 server := protocol.ServerDispatcherV2(conn) 139 client := b.newClient(ctx, server) 140 return jsonrpc2_v2.ConnectionOptions{ 141 Handler: protocol.ClientHandlerV2(client), 142 }, nil 143 }