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") |
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. |
24 | ErrNotHandled = errors.New("JSON RPC not handled") |
25 | |
26 | // ErrAsyncResponse is returned from a handler to indicate it will generate a |
27 | // response asynchronously. |
28 | // |
29 | // ErrAsyncResponse must not be returned for notifications, |
30 | // which do not receive responses. |
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 { |
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) |
48 | } |
49 | |
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 | |
59 | // Handler handles messages on a connection. |
60 | type Handler interface { |
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) |
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 | |
87 | // A HandlerFunc implements the Handler interface for a standalone Handle function. |
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 | |
94 | var _ Handler = HandlerFunc(nil) |
95 | |
96 | // async is a small helper for operations with an asynchronous result that you |
97 | // can wait for. |
98 | type async struct { |
99 | ready chan struct{} // closed when done |
100 | firstErr chan error // 1-buffered; contains either nil or the first non-nil error |
101 | } |
102 | |
103 | func newAsync() *async { |
104 | var a async |
105 | a.ready = make(chan struct{}) |
106 | a.firstErr = make(chan error, 1) |
107 | a.firstErr <- nil |
108 | return &a |
109 | } |
110 | |
111 | func (a *async) done() { |
112 | close(a.ready) |
113 | } |
114 | |
115 | func (a *async) isDone() bool { |
116 | select { |
117 | case <-a.ready: |
118 | return true |
119 | default: |
120 | return false |
121 | } |
122 | } |
123 | |
124 | func (a *async) wait() error { |
125 | <-a.ready |
126 | err := <-a.firstErr |
127 | a.firstErr <- err |
128 | return err |
129 | } |
130 | |
131 | func (a *async) setError(err error) { |
132 | storedErr := <-a.firstErr |
133 | if storedErr == nil { |
134 | storedErr = err |
135 | } |
136 | a.firstErr <- storedErr |
137 | } |
138 |
Members