github.com/jhump/golang-x-tools@v0.0.0-20220218190644-4958d6d39439/internal/jsonrpc2_v2/conn.go (about) 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 5 package jsonrpc2 6 7 import ( 8 "context" 9 "encoding/json" 10 "fmt" 11 "io" 12 "sync/atomic" 13 14 "github.com/jhump/golang-x-tools/internal/event" 15 "github.com/jhump/golang-x-tools/internal/event/label" 16 "github.com/jhump/golang-x-tools/internal/lsp/debug/tag" 17 errors "golang.org/x/xerrors" 18 ) 19 20 // Binder builds a connection configuration. 21 // This may be used in servers to generate a new configuration per connection. 22 // ConnectionOptions itself implements Binder returning itself unmodified, to 23 // allow for the simple cases where no per connection information is needed. 24 type Binder interface { 25 // Bind is invoked when creating a new connection. 26 // The connection is not ready to use when Bind is called. 27 Bind(context.Context, *Connection) (ConnectionOptions, error) 28 } 29 30 // ConnectionOptions holds the options for new connections. 31 type ConnectionOptions struct { 32 // Framer allows control over the message framing and encoding. 33 // If nil, HeaderFramer will be used. 34 Framer Framer 35 // Preempter allows registration of a pre-queue message handler. 36 // If nil, no messages will be preempted. 37 Preempter Preempter 38 // Handler is used as the queued message handler for inbound messages. 39 // If nil, all responses will be ErrNotHandled. 40 Handler Handler 41 } 42 43 // Connection manages the jsonrpc2 protocol, connecting responses back to their 44 // calls. 45 // Connection is bidirectional; it does not have a designated server or client 46 // end. 47 type Connection struct { 48 seq int64 // must only be accessed using atomic operations 49 closer io.Closer 50 writerBox chan Writer 51 outgoingBox chan map[ID]chan<- *Response 52 incomingBox chan map[ID]*incoming 53 async *async 54 } 55 56 type AsyncCall struct { 57 id ID 58 response chan *Response // the channel a response will be delivered on 59 resultBox chan asyncResult 60 endSpan func() // close the tracing span when all processing for the message is complete 61 } 62 63 type asyncResult struct { 64 result []byte 65 err error 66 } 67 68 // incoming is used to track an incoming request as it is being handled 69 type incoming struct { 70 request *Request // the request being processed 71 baseCtx context.Context // a base context for the message processing 72 done func() // a function called when all processing for the message is complete 73 handleCtx context.Context // the context for handling the message, child of baseCtx 74 cancel func() // a function that cancels the handling context 75 } 76 77 // Bind returns the options unmodified. 78 func (o ConnectionOptions) Bind(context.Context, *Connection) (ConnectionOptions, error) { 79 return o, nil 80 } 81 82 // newConnection creates a new connection and runs it. 83 // This is used by the Dial and Serve functions to build the actual connection. 84 func newConnection(ctx context.Context, rwc io.ReadWriteCloser, binder Binder) (*Connection, error) { 85 c := &Connection{ 86 closer: rwc, 87 writerBox: make(chan Writer, 1), 88 outgoingBox: make(chan map[ID]chan<- *Response, 1), 89 incomingBox: make(chan map[ID]*incoming, 1), 90 async: newAsync(), 91 } 92 93 options, err := binder.Bind(ctx, c) 94 if err != nil { 95 return nil, err 96 } 97 if options.Framer == nil { 98 options.Framer = HeaderFramer() 99 } 100 if options.Preempter == nil { 101 options.Preempter = defaultHandler{} 102 } 103 if options.Handler == nil { 104 options.Handler = defaultHandler{} 105 } 106 c.outgoingBox <- make(map[ID]chan<- *Response) 107 c.incomingBox <- make(map[ID]*incoming) 108 // the goroutines started here will continue until the underlying stream is closed 109 reader := options.Framer.Reader(rwc) 110 readToQueue := make(chan *incoming) 111 queueToDeliver := make(chan *incoming) 112 go c.readIncoming(ctx, reader, readToQueue) 113 go c.manageQueue(ctx, options.Preempter, readToQueue, queueToDeliver) 114 go c.deliverMessages(ctx, options.Handler, queueToDeliver) 115 116 // releaseing the writer must be the last thing we do in case any requests 117 // are blocked waiting for the connection to be ready 118 c.writerBox <- options.Framer.Writer(rwc) 119 return c, nil 120 } 121 122 // Notify invokes the target method but does not wait for a response. 123 // The params will be marshaled to JSON before sending over the wire, and will 124 // be handed to the method invoked. 125 func (c *Connection) Notify(ctx context.Context, method string, params interface{}) error { 126 notify, err := NewNotification(method, params) 127 if err != nil { 128 return errors.Errorf("marshaling notify parameters: %v", err) 129 } 130 ctx, done := event.Start(ctx, method, 131 tag.Method.Of(method), 132 tag.RPCDirection.Of(tag.Outbound), 133 ) 134 event.Metric(ctx, tag.Started.Of(1)) 135 err = c.write(ctx, notify) 136 switch { 137 case err != nil: 138 event.Label(ctx, tag.StatusCode.Of("ERROR")) 139 default: 140 event.Label(ctx, tag.StatusCode.Of("OK")) 141 } 142 done() 143 return err 144 } 145 146 // Call invokes the target method and returns an object that can be used to await the response. 147 // The params will be marshaled to JSON before sending over the wire, and will 148 // be handed to the method invoked. 149 // You do not have to wait for the response, it can just be ignored if not needed. 150 // If sending the call failed, the response will be ready and have the error in it. 151 func (c *Connection) Call(ctx context.Context, method string, params interface{}) *AsyncCall { 152 result := &AsyncCall{ 153 id: Int64ID(atomic.AddInt64(&c.seq, 1)), 154 resultBox: make(chan asyncResult, 1), 155 } 156 // generate a new request identifier 157 call, err := NewCall(result.id, method, params) 158 if err != nil { 159 //set the result to failed 160 result.resultBox <- asyncResult{err: errors.Errorf("marshaling call parameters: %w", err)} 161 return result 162 } 163 ctx, endSpan := event.Start(ctx, method, 164 tag.Method.Of(method), 165 tag.RPCDirection.Of(tag.Outbound), 166 tag.RPCID.Of(fmt.Sprintf("%q", result.id)), 167 ) 168 result.endSpan = endSpan 169 event.Metric(ctx, tag.Started.Of(1)) 170 // We have to add ourselves to the pending map before we send, otherwise we 171 // are racing the response. 172 // rchan is buffered in case the response arrives without a listener. 173 result.response = make(chan *Response, 1) 174 pending := <-c.outgoingBox 175 pending[result.id] = result.response 176 c.outgoingBox <- pending 177 // now we are ready to send 178 if err := c.write(ctx, call); err != nil { 179 // sending failed, we will never get a response, so deliver a fake one 180 r, _ := NewResponse(result.id, nil, err) 181 c.incomingResponse(r) 182 } 183 return result 184 } 185 186 // ID used for this call. 187 // This can be used to cancel the call if needed. 188 func (a *AsyncCall) ID() ID { return a.id } 189 190 // IsReady can be used to check if the result is already prepared. 191 // This is guaranteed to return true on a result for which Await has already 192 // returned, or a call that failed to send in the first place. 193 func (a *AsyncCall) IsReady() bool { 194 select { 195 case r := <-a.resultBox: 196 a.resultBox <- r 197 return true 198 default: 199 return false 200 } 201 } 202 203 // Await the results of a Call. 204 // The response will be unmarshaled from JSON into the result. 205 func (a *AsyncCall) Await(ctx context.Context, result interface{}) error { 206 defer a.endSpan() 207 var r asyncResult 208 select { 209 case response := <-a.response: 210 // response just arrived, prepare the result 211 switch { 212 case response.Error != nil: 213 r.err = response.Error 214 event.Label(ctx, tag.StatusCode.Of("ERROR")) 215 default: 216 r.result = response.Result 217 event.Label(ctx, tag.StatusCode.Of("OK")) 218 } 219 case r = <-a.resultBox: 220 // result already available 221 case <-ctx.Done(): 222 event.Label(ctx, tag.StatusCode.Of("CANCELLED")) 223 return ctx.Err() 224 } 225 // refill the box for the next caller 226 a.resultBox <- r 227 // and unpack the result 228 if r.err != nil { 229 return r.err 230 } 231 if result == nil || len(r.result) == 0 { 232 return nil 233 } 234 return json.Unmarshal(r.result, result) 235 } 236 237 // Respond deliverers a response to an incoming Call. 238 // It is an error to not call this exactly once for any message for which a 239 // handler has previously returned ErrAsyncResponse. It is also an error to 240 // call this for any other message. 241 func (c *Connection) Respond(id ID, result interface{}, rerr error) error { 242 pending := <-c.incomingBox 243 defer func() { c.incomingBox <- pending }() 244 entry, found := pending[id] 245 if !found { 246 return nil 247 } 248 delete(pending, id) 249 return c.respond(entry, result, rerr) 250 } 251 252 // Cancel is used to cancel an inbound message by ID, it does not cancel 253 // outgoing messages. 254 // This is only used inside a message handler that is layering a 255 // cancellation protocol on top of JSON RPC 2. 256 // It will not complain if the ID is not a currently active message, and it will 257 // not cause any messages that have not arrived yet with that ID to be 258 // cancelled. 259 func (c *Connection) Cancel(id ID) { 260 pending := <-c.incomingBox 261 defer func() { c.incomingBox <- pending }() 262 if entry, found := pending[id]; found && entry.cancel != nil { 263 entry.cancel() 264 entry.cancel = nil 265 } 266 } 267 268 // Wait blocks until the connection is fully closed, but does not close it. 269 func (c *Connection) Wait() error { 270 return c.async.wait() 271 } 272 273 // Close can be used to close the underlying stream, and then wait for the connection to 274 // fully shut down. 275 // This does not cancel in flight requests, but waits for them to gracefully complete. 276 func (c *Connection) Close() error { 277 // close the underlying stream 278 if err := c.closer.Close(); err != nil && !isClosingError(err) { 279 return err 280 } 281 // and then wait for it to cause the connection to close 282 if err := c.Wait(); err != nil && !isClosingError(err) { 283 return err 284 } 285 return nil 286 } 287 288 // readIncoming collects inbound messages from the reader and delivers them, either responding 289 // to outgoing calls or feeding requests to the queue. 290 func (c *Connection) readIncoming(ctx context.Context, reader Reader, toQueue chan<- *incoming) { 291 defer close(toQueue) 292 for { 293 // get the next message 294 // no lock is needed, this is the only reader 295 msg, n, err := reader.Read(ctx) 296 if err != nil { 297 // The stream failed, we cannot continue 298 c.async.setError(err) 299 return 300 } 301 switch msg := msg.(type) { 302 case *Request: 303 entry := &incoming{ 304 request: msg, 305 } 306 // add a span to the context for this request 307 labels := append(make([]label.Label, 0, 3), // make space for the id if present 308 tag.Method.Of(msg.Method), 309 tag.RPCDirection.Of(tag.Inbound), 310 ) 311 if msg.IsCall() { 312 labels = append(labels, tag.RPCID.Of(fmt.Sprintf("%q", msg.ID))) 313 } 314 entry.baseCtx, entry.done = event.Start(ctx, msg.Method, labels...) 315 event.Metric(entry.baseCtx, 316 tag.Started.Of(1), 317 tag.ReceivedBytes.Of(n)) 318 // in theory notifications cannot be cancelled, but we build them a cancel context anyway 319 entry.handleCtx, entry.cancel = context.WithCancel(entry.baseCtx) 320 // if the request is a call, add it to the incoming map so it can be 321 // cancelled by id 322 if msg.IsCall() { 323 pending := <-c.incomingBox 324 c.incomingBox <- pending 325 pending[msg.ID] = entry 326 } 327 // send the message to the incoming queue 328 toQueue <- entry 329 case *Response: 330 // If method is not set, this should be a response, in which case we must 331 // have an id to send the response back to the caller. 332 c.incomingResponse(msg) 333 } 334 } 335 } 336 337 func (c *Connection) incomingResponse(msg *Response) { 338 pending := <-c.outgoingBox 339 response, ok := pending[msg.ID] 340 if ok { 341 delete(pending, msg.ID) 342 } 343 c.outgoingBox <- pending 344 if response != nil { 345 response <- msg 346 } 347 } 348 349 // manageQueue reads incoming requests, attempts to proccess them with the preempter, or queue them 350 // up for normal handling. 351 func (c *Connection) manageQueue(ctx context.Context, preempter Preempter, fromRead <-chan *incoming, toDeliver chan<- *incoming) { 352 defer close(toDeliver) 353 q := []*incoming{} 354 ok := true 355 for { 356 var nextReq *incoming 357 if len(q) == 0 { 358 // no messages in the queue 359 // if we were closing, then we are done 360 if !ok { 361 return 362 } 363 // not closing, but nothing in the queue, so just block waiting for a read 364 nextReq, ok = <-fromRead 365 } else { 366 // we have a non empty queue, so pick whichever of reading or delivering 367 // that we can make progress on 368 select { 369 case nextReq, ok = <-fromRead: 370 case toDeliver <- q[0]: 371 //TODO: this causes a lot of shuffling, should we use a growing ring buffer? compaction? 372 q = q[1:] 373 } 374 } 375 if nextReq != nil { 376 // TODO: should we allow to limit the queue size? 377 var result interface{} 378 rerr := nextReq.handleCtx.Err() 379 if rerr == nil { 380 // only preempt if not already cancelled 381 result, rerr = preempter.Preempt(nextReq.handleCtx, nextReq.request) 382 } 383 switch { 384 case rerr == ErrNotHandled: 385 // message not handled, add it to the queue for the main handler 386 q = append(q, nextReq) 387 case rerr == ErrAsyncResponse: 388 // message handled but the response will come later 389 default: 390 // anything else means the message is fully handled 391 c.reply(nextReq, result, rerr) 392 } 393 } 394 } 395 } 396 397 func (c *Connection) deliverMessages(ctx context.Context, handler Handler, fromQueue <-chan *incoming) { 398 defer c.async.done() 399 for entry := range fromQueue { 400 // cancel any messages in the queue that we have a pending cancel for 401 var result interface{} 402 rerr := entry.handleCtx.Err() 403 if rerr == nil { 404 // only deliver if not already cancelled 405 result, rerr = handler.Handle(entry.handleCtx, entry.request) 406 } 407 switch { 408 case rerr == ErrNotHandled: 409 // message not handled, report it back to the caller as an error 410 c.reply(entry, nil, errors.Errorf("%w: %q", ErrMethodNotFound, entry.request.Method)) 411 case rerr == ErrAsyncResponse: 412 // message handled but the response will come later 413 default: 414 c.reply(entry, result, rerr) 415 } 416 } 417 } 418 419 // reply is used to reply to an incoming request that has just been handled 420 func (c *Connection) reply(entry *incoming, result interface{}, rerr error) { 421 if entry.request.IsCall() { 422 // we have a call finishing, remove it from the incoming map 423 pending := <-c.incomingBox 424 defer func() { c.incomingBox <- pending }() 425 delete(pending, entry.request.ID) 426 } 427 if err := c.respond(entry, result, rerr); err != nil { 428 // no way to propagate this error 429 //TODO: should we do more than just log it? 430 event.Error(entry.baseCtx, "jsonrpc2 message delivery failed", err) 431 } 432 } 433 434 // respond sends a response. 435 // This is the code shared between reply and SendResponse. 436 func (c *Connection) respond(entry *incoming, result interface{}, rerr error) error { 437 var err error 438 if entry.request.IsCall() { 439 // send the response 440 if result == nil && rerr == nil { 441 // call with no response, send an error anyway 442 rerr = errors.Errorf("%w: %q produced no response", ErrInternal, entry.request.Method) 443 } 444 var response *Response 445 response, err = NewResponse(entry.request.ID, result, rerr) 446 if err == nil { 447 // we write the response with the base context, in case the message was cancelled 448 err = c.write(entry.baseCtx, response) 449 } 450 } else { 451 switch { 452 case rerr != nil: 453 // notification failed 454 err = errors.Errorf("%w: %q notification failed: %v", ErrInternal, entry.request.Method, rerr) 455 rerr = nil 456 case result != nil: 457 //notification produced a response, which is an error 458 err = errors.Errorf("%w: %q produced unwanted response", ErrInternal, entry.request.Method) 459 default: 460 // normal notification finish 461 } 462 } 463 switch { 464 case rerr != nil || err != nil: 465 event.Label(entry.baseCtx, tag.StatusCode.Of("ERROR")) 466 default: 467 event.Label(entry.baseCtx, tag.StatusCode.Of("OK")) 468 } 469 // and just to be clean, invoke and clear the cancel if needed 470 if entry.cancel != nil { 471 entry.cancel() 472 entry.cancel = nil 473 } 474 // mark the entire request processing as done 475 entry.done() 476 return err 477 } 478 479 // write is used by all things that write outgoing messages, including replies. 480 // it makes sure that writes are atomic 481 func (c *Connection) write(ctx context.Context, msg Message) error { 482 writer := <-c.writerBox 483 defer func() { c.writerBox <- writer }() 484 n, err := writer.Write(ctx, msg) 485 event.Metric(ctx, tag.SentBytes.Of(n)) 486 return err 487 }