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