Ian Cottrell | 877f9c4 | 2021-02-09 22:45:26 -0500 | [diff] [blame] | 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 is a minimal implementation of the JSON RPC 2 spec. |
| 6 | // https://www.jsonrpc.org/specification |
| 7 | // It is intended to be compatible with other implementations at the wire level. |
| 8 | package jsonrpc2 |
| 9 | |
| 10 | import ( |
| 11 | "context" |
| 12 | "errors" |
| 13 | ) |
| 14 | |
| 15 | var ( |
| 16 | // ErrIdleTimeout is returned when serving timed out waiting for new connections. |
| 17 | ErrIdleTimeout = errors.New("timed out waiting for new connections") |
Bryan C. Mills | 5d35a75 | 2022-02-28 10:55:20 -0500 | [diff] [blame] | 18 | |
| 19 | // ErrNotHandled is returned from a Handler or Preempter to indicate it did |
| 20 | // not handle the request. |
| 21 | // |
| 22 | // If a Handler returns ErrNotHandled, the server replies with |
| 23 | // ErrMethodNotFound. |
Ian Cottrell | 877f9c4 | 2021-02-09 22:45:26 -0500 | [diff] [blame] | 24 | ErrNotHandled = errors.New("JSON RPC not handled") |
Bryan C. Mills | 5d35a75 | 2022-02-28 10:55:20 -0500 | [diff] [blame] | 25 | |
Ian Cottrell | 877f9c4 | 2021-02-09 22:45:26 -0500 | [diff] [blame] | 26 | // ErrAsyncResponse is returned from a handler to indicate it will generate a |
| 27 | // response asynchronously. |
Bryan C. Mills | 5d35a75 | 2022-02-28 10:55:20 -0500 | [diff] [blame] | 28 | // |
| 29 | // ErrAsyncResponse must not be returned for notifications, |
| 30 | // which do not receive responses. |
Ian Cottrell | 877f9c4 | 2021-02-09 22:45:26 -0500 | [diff] [blame] | 31 | ErrAsyncResponse = errors.New("JSON RPC asynchronous response") |
| 32 | ) |
| 33 | |
| 34 | // Preempter handles messages on a connection before they are queued to the main |
| 35 | // handler. |
| 36 | // Primarily this is used for cancel handlers or notifications for which out of |
| 37 | // order processing is not an issue. |
| 38 | type Preempter interface { |
Bryan C. Mills | 5d35a75 | 2022-02-28 10:55:20 -0500 | [diff] [blame] | 39 | // Preempt is invoked for each incoming request before it is queued for handling. |
| 40 | // |
| 41 | // If Preempt returns ErrNotHandled, the request will be queued, |
| 42 | // and eventually passed to a Handle call. |
| 43 | // |
| 44 | // Otherwise, the result and error are processed as if returned by Handle. |
| 45 | // |
| 46 | // Preempt must not block. (The Context passed to it is for Values only.) |
| 47 | Preempt(ctx context.Context, req *Request) (result interface{}, err error) |
Ian Cottrell | 877f9c4 | 2021-02-09 22:45:26 -0500 | [diff] [blame] | 48 | } |
| 49 | |
Bryan C. Mills | bc2e3ae | 2022-02-28 11:24:36 -0500 | [diff] [blame] | 50 | // A PreempterFunc implements the Preempter interface for a standalone Preempt function. |
| 51 | type PreempterFunc func(ctx context.Context, req *Request) (interface{}, error) |
| 52 | |
| 53 | func (f PreempterFunc) Preempt(ctx context.Context, req *Request) (interface{}, error) { |
| 54 | return f(ctx, req) |
| 55 | } |
| 56 | |
| 57 | var _ Preempter = PreempterFunc(nil) |
| 58 | |
Ian Cottrell | 877f9c4 | 2021-02-09 22:45:26 -0500 | [diff] [blame] | 59 | // Handler handles messages on a connection. |
| 60 | type Handler interface { |
Bryan C. Mills | 5d35a75 | 2022-02-28 10:55:20 -0500 | [diff] [blame] | 61 | // Handle is invoked sequentially for each incoming request that has not |
| 62 | // already been handled by a Preempter. |
| 63 | // |
| 64 | // If the Request has a nil ID, Handle must return a nil result, |
| 65 | // and any error may be logged but will not be reported to the caller. |
| 66 | // |
| 67 | // If the Request has a non-nil ID, Handle must return either a |
| 68 | // non-nil, JSON-marshalable result, or a non-nil error. |
| 69 | // |
| 70 | // The Context passed to Handle will be canceled if the |
| 71 | // connection is broken or the request is canceled or completed. |
| 72 | // (If Handle returns ErrAsyncResponse, ctx will remain uncanceled |
| 73 | // until either Cancel or Respond is called for the request's ID.) |
| 74 | Handle(ctx context.Context, req *Request) (result interface{}, err error) |
Ian Cottrell | 877f9c4 | 2021-02-09 22:45:26 -0500 | [diff] [blame] | 75 | } |
| 76 | |
| 77 | type defaultHandler struct{} |
| 78 | |
| 79 | func (defaultHandler) Preempt(context.Context, *Request) (interface{}, error) { |
| 80 | return nil, ErrNotHandled |
| 81 | } |
| 82 | |
| 83 | func (defaultHandler) Handle(context.Context, *Request) (interface{}, error) { |
| 84 | return nil, ErrNotHandled |
| 85 | } |
| 86 | |
Bryan C. Mills | bc2e3ae | 2022-02-28 11:24:36 -0500 | [diff] [blame] | 87 | // A HandlerFunc implements the Handler interface for a standalone Handle function. |
Rob Findley | f451690 | 2021-05-18 13:33:26 -0400 | [diff] [blame] | 88 | type HandlerFunc func(ctx context.Context, req *Request) (interface{}, error) |
| 89 | |
| 90 | func (f HandlerFunc) Handle(ctx context.Context, req *Request) (interface{}, error) { |
| 91 | return f(ctx, req) |
| 92 | } |
| 93 | |
Bryan C. Mills | bc2e3ae | 2022-02-28 11:24:36 -0500 | [diff] [blame] | 94 | var _ Handler = HandlerFunc(nil) |
| 95 | |
Rob Findley | 00129ff | 2021-05-19 11:51:44 -0400 | [diff] [blame] | 96 | // async is a small helper for operations with an asynchronous result that you |
| 97 | // can wait for. |
Ian Cottrell | 877f9c4 | 2021-02-09 22:45:26 -0500 | [diff] [blame] | 98 | type async struct { |
Bryan C. Mills | 5d35a75 | 2022-02-28 10:55:20 -0500 | [diff] [blame] | 99 | ready chan struct{} // closed when done |
| 100 | firstErr chan error // 1-buffered; contains either nil or the first non-nil error |
Ian Cottrell | 877f9c4 | 2021-02-09 22:45:26 -0500 | [diff] [blame] | 101 | } |
| 102 | |
Rob Findley | fe2294a | 2021-06-25 11:49:46 -0400 | [diff] [blame] | 103 | func newAsync() *async { |
| 104 | var a async |
Ian Cottrell | 877f9c4 | 2021-02-09 22:45:26 -0500 | [diff] [blame] | 105 | a.ready = make(chan struct{}) |
Bryan C. Mills | 5d35a75 | 2022-02-28 10:55:20 -0500 | [diff] [blame] | 106 | a.firstErr = make(chan error, 1) |
| 107 | a.firstErr <- nil |
Rob Findley | fe2294a | 2021-06-25 11:49:46 -0400 | [diff] [blame] | 108 | return &a |
Ian Cottrell | 877f9c4 | 2021-02-09 22:45:26 -0500 | [diff] [blame] | 109 | } |
| 110 | |
| 111 | func (a *async) done() { |
| 112 | close(a.ready) |
| 113 | } |
| 114 | |
Ian Cottrell | b0e994d | 2021-03-25 22:16:30 -0400 | [diff] [blame] | 115 | func (a *async) isDone() bool { |
| 116 | select { |
| 117 | case <-a.ready: |
| 118 | return true |
| 119 | default: |
| 120 | return false |
| 121 | } |
| 122 | } |
| 123 | |
Ian Cottrell | 877f9c4 | 2021-02-09 22:45:26 -0500 | [diff] [blame] | 124 | func (a *async) wait() error { |
| 125 | <-a.ready |
Bryan C. Mills | 5d35a75 | 2022-02-28 10:55:20 -0500 | [diff] [blame] | 126 | err := <-a.firstErr |
| 127 | a.firstErr <- err |
Ian Cottrell | 877f9c4 | 2021-02-09 22:45:26 -0500 | [diff] [blame] | 128 | return err |
| 129 | } |
| 130 | |
| 131 | func (a *async) setError(err error) { |
Bryan C. Mills | 5d35a75 | 2022-02-28 10:55:20 -0500 | [diff] [blame] | 132 | storedErr := <-a.firstErr |
Ian Cottrell | 877f9c4 | 2021-02-09 22:45:26 -0500 | [diff] [blame] | 133 | if storedErr == nil { |
| 134 | storedErr = err |
| 135 | } |
Bryan C. Mills | 5d35a75 | 2022-02-28 10:55:20 -0500 | [diff] [blame] | 136 | a.firstErr <- storedErr |
Ian Cottrell | 877f9c4 | 2021-02-09 22:45:26 -0500 | [diff] [blame] | 137 | } |