1
2
3
4
5 package jsonrpc2
6
7 import (
8 "encoding/json"
9 "errors"
10 "fmt"
11 )
12
13
14 type ID struct {
15 value interface{}
16 }
17
18
19
20
21
22 type Message interface {
23
24
25 marshal(to *wireCombined)
26 }
27
28
29
30 type Request struct {
31
32
33 ID ID
34
35 Method string
36
37 Params json.RawMessage
38 }
39
40
41
42 type Response struct {
43
44 Result json.RawMessage
45
46 Error error
47
48 ID ID
49 }
50
51
52 func StringID(s string) ID { return ID{value: s} }
53
54
55 func Int64ID(i int64) ID { return ID{value: i} }
56
57
58
59 func (id ID) IsValid() bool { return id.value != nil }
60
61
62 func (id ID) Raw() interface{} { return id.value }
63
64
65
66 func NewNotification(method string, params interface{}) (*Request, error) {
67 p, merr := marshalToRaw(params)
68 return &Request{Method: method, Params: p}, merr
69 }
70
71
72
73 func NewCall(id ID, method string, params interface{}) (*Request, error) {
74 p, merr := marshalToRaw(params)
75 return &Request{ID: id, Method: method, Params: p}, merr
76 }
77
78 func (msg *Request) IsCall() bool { return msg.ID.IsValid() }
79
80 func (msg *Request) marshal(to *wireCombined) {
81 to.ID = msg.ID.value
82 to.Method = msg.Method
83 to.Params = msg.Params
84 }
85
86
87
88 func NewResponse(id ID, result interface{}, rerr error) (*Response, error) {
89 r, merr := marshalToRaw(result)
90 return &Response{ID: id, Result: r, Error: rerr}, merr
91 }
92
93 func (msg *Response) marshal(to *wireCombined) {
94 to.ID = msg.ID.value
95 to.Error = toWireError(msg.Error)
96 to.Result = msg.Result
97 }
98
99 func toWireError(err error) *WireError {
100 if err == nil {
101
102 return nil
103 }
104 if err, ok := err.(*WireError); ok {
105
106 return err
107 }
108 result := &WireError{Message: err.Error()}
109 var wrapped *WireError
110 if errors.As(err, &wrapped) {
111
112
113 result.Code = wrapped.Code
114 }
115 return result
116 }
117
118 func EncodeMessage(msg Message) ([]byte, error) {
119 wire := wireCombined{VersionTag: wireVersion}
120 msg.marshal(&wire)
121 data, err := json.Marshal(&wire)
122 if err != nil {
123 return data, fmt.Errorf("marshaling jsonrpc message: %w", err)
124 }
125 return data, nil
126 }
127
128 func DecodeMessage(data []byte) (Message, error) {
129 msg := wireCombined{}
130 if err := json.Unmarshal(data, &msg); err != nil {
131 return nil, fmt.Errorf("unmarshaling jsonrpc message: %w", err)
132 }
133 if msg.VersionTag != wireVersion {
134 return nil, fmt.Errorf("invalid message version tag %s expected %s", msg.VersionTag, wireVersion)
135 }
136 id := ID{}
137 switch v := msg.ID.(type) {
138 case nil:
139 case float64:
140
141 id = Int64ID(int64(v))
142 case int64:
143 id = Int64ID(v)
144 case string:
145 id = StringID(v)
146 default:
147 return nil, fmt.Errorf("invalid message id type <%T>%v", v, v)
148 }
149 if msg.Method != "" {
150
151 return &Request{
152 Method: msg.Method,
153 ID: id,
154 Params: msg.Params,
155 }, nil
156 }
157
158 if !id.IsValid() {
159 return nil, ErrInvalidRequest
160 }
161 resp := &Response{
162 ID: id,
163 Result: msg.Result,
164 }
165
166 if msg.Error != nil {
167 resp.Error = msg.Error
168 }
169 return resp, nil
170 }
171
172 func marshalToRaw(obj interface{}) (json.RawMessage, error) {
173 if obj == nil {
174 return nil, nil
175 }
176 data, err := json.Marshal(obj)
177 if err != nil {
178 return nil, err
179 }
180 return json.RawMessage(data), nil
181 }
182
View as plain text