Skip to content

Commit 3acf09e

Browse files
committed
types,jsonrpc2: change ID and JSONRPC field to new architecture
1 parent aa9e0be commit 3acf09e

File tree

3 files changed

+102
-50
lines changed

3 files changed

+102
-50
lines changed

jsonrpc2.go

Lines changed: 11 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -113,9 +113,8 @@ func (c *Conn) Notify(ctx context.Context, method string, params interface{}) er
113113
return fmt.Errorf("failed to marshaling notify parameters: %v", err)
114114
}
115115
req := &WireRequest{
116-
JSONRPC: Version,
117-
Method: method,
118-
Params: p,
116+
Method: method,
117+
Params: p,
119118
}
120119
data, err := json.Marshal(req)
121120
if err != nil {
@@ -142,16 +141,15 @@ func (c *Conn) Notify(ctx context.Context, method string, params interface{}) er
142141
// Call sends a request over the connection and then waits for a response.
143142
func (c *Conn) Call(ctx context.Context, method string, params, result interface{}) error {
144143
// generate a new request identifier
145-
id := ID{Number: atomic.AddInt64(&c.seq, 1)}
144+
id := NewIntID(atomic.AddInt64(&c.seq, 1))
146145
p, err := marshalInterface(params)
147146
if err != nil {
148147
return fmt.Errorf("failed to marshaling call parameters: %v", err)
149148
}
150149
req := &WireRequest{
151-
JSONRPC: Version,
152-
ID: &id,
153-
Method: method,
154-
Params: p,
150+
ID: &id,
151+
Method: method,
152+
Params: p,
155153
}
156154

157155
// marshal the request now it is complete
@@ -275,10 +273,9 @@ func (c *Conn) Run(ctx context.Context) error {
275273
cancel: cancelReq,
276274
nextReqCh: nextReqCh,
277275
WireRequest: WireRequest{
278-
JSONRPC: Version,
279-
Method: msg.Method,
280-
Params: msg.Params,
281-
ID: msg.ID,
276+
Method: msg.Method,
277+
Params: msg.Params,
278+
ID: msg.ID,
282279
},
283280
}
284281
for _, h := range c.handlers {
@@ -398,9 +395,8 @@ func (r *Request) Reply(ctx context.Context, result interface{}, reqErr error) e
398395
return err
399396
}
400397
resp := &WireResponse{
401-
JSONRPC: Version,
402-
Result: raw,
403-
ID: r.ID,
398+
Result: raw,
399+
ID: r.ID,
404400
}
405401
if reqErr != nil {
406402
var callErr *Error

types.go

Lines changed: 56 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -6,63 +6,96 @@ package jsonrpc2
66

77
import (
88
"encoding/json"
9-
"strconv"
9+
"fmt"
10+
"math"
1011
)
1112

1213
// Version represents a JSON-RPC version.
1314
const Version = "2.0"
1415

16+
var versionStr = string(Version)
17+
18+
// version is a special 0 sized struct that encodes as the JSON-RPC version
19+
// tag.
20+
// It will fail during decode if it is not the correct version tag in the
21+
// stream.
22+
type version struct{}
23+
24+
func (version) MarshalJSON() ([]byte, error) {
25+
return json.Marshal(Version)
26+
}
27+
28+
func (version) UnmarshalJSON(data []byte) error {
29+
version := ""
30+
if err := json.Unmarshal(data, &version); err != nil {
31+
return err
32+
}
33+
if version != Version {
34+
return fmt.Errorf("invalid JSON-RPC version %v", version)
35+
}
36+
return nil
37+
}
38+
1539
// ID is a Request identifier.
1640
// Only one of either the Name or Number members will be set, using the
1741
// number form if the Name is the empty string.
1842
type ID struct {
19-
Name string
20-
Number int64
43+
name string
44+
number int64
2145
}
2246

2347
// compile time check whether the ID implements a json.Marshaler and json.Unmarshaler interfaces.
2448
var (
49+
_ fmt.Formatter = (*ID)(nil)
2550
_ json.Marshaler = (*ID)(nil)
2651
_ json.Unmarshaler = (*ID)(nil)
2752
)
2853

29-
// String returns a string representation of the ID.
30-
// The representation is non ambiguous, string forms are quoted, number forms
31-
// are preceded by a #.
32-
func (id *ID) String() string {
33-
if id == nil {
34-
return ""
54+
// Format writes the ID to the formatter.
55+
// If the rune is q the representation is non ambiguous,
56+
// string forms are quoted, number forms are preceded by a #
57+
func (id ID) Format(f fmt.State, r rune) {
58+
numF, strF := `%d`, `%s`
59+
if r == 'q' {
60+
numF, strF = `#%d`, `%q`
3561
}
36-
if id.Name != "" {
37-
return strconv.Quote(id.Name)
62+
switch {
63+
case id.name != "":
64+
fmt.Fprintf(f, strF, id.name)
65+
default:
66+
fmt.Fprintf(f, numF, id.number)
3867
}
39-
40-
return "#" + strconv.FormatInt(id.Number, 10)
4168
}
4269

4370
// MarshalJSON implements json.Marshaler.
4471
func (id *ID) MarshalJSON() ([]byte, error) {
45-
if id.Name != "" {
46-
return json.Marshal(id.Name)
72+
if id.name != "" {
73+
return json.Marshal(id.name)
4774
}
48-
49-
return json.Marshal(id.Number)
75+
return json.Marshal(id.number)
5076
}
5177

5278
// UnmarshalJSON implements json.Unmarshaler.
5379
func (id *ID) UnmarshalJSON(data []byte) error {
5480
*id = ID{}
55-
if err := json.Unmarshal(data, &id.Number); err == nil {
81+
if err := json.Unmarshal(data, &id.number); err == nil {
5682
return nil
5783
}
58-
59-
return json.Unmarshal(data, &id.Name)
84+
return json.Unmarshal(data, &id.name)
6085
}
6186

87+
// NewIntID returns a new numerical request ID.
88+
func NewIntID(v int64) ID { return ID{number: v} }
89+
90+
// NewStringID returns a new string request ID.
91+
func NewStringID(v string) ID { return ID{name: v} }
92+
93+
const invalidID int64 = math.MaxInt64
94+
6295
// WireRequest is sent to a server to represent a Call or Notify operaton.
6396
type WireRequest struct {
6497
// JSONRPC is always encoded as the string "2.0"
65-
JSONRPC string `json:"jsonrpc"`
98+
JSONRPC version `json:"jsonrpc"`
6699

67100
// Method is a string containing the method name to invoke.
68101
//
@@ -86,7 +119,7 @@ type WireRequest struct {
86119
// success or failure response.
87120
type WireResponse struct {
88121
// JSONRPC is always encoded as the string "2.0"
89-
JSONRPC string `json:"jsonrpc"`
122+
JSONRPC version `json:"jsonrpc"`
90123

91124
// Result is the response value, and is required on success.
92125
// This member MUST NOT exist if there was an error invoking the method.
@@ -112,7 +145,7 @@ type WireResponse struct {
112145
// Combined represents a all the fields of both Request and Response.
113146
// We can decode this and then work out which it is.
114147
type Combined struct {
115-
JSONRPC string `json:"jsonrpc"`
148+
JSONRPC version `json:"jsonrpc"`
116149
ID *ID `json:"id,omitempty"`
117150
Method string `json:"method"`
118151
Params *json.RawMessage `json:"params,omitempty"`

types_gojay.go

Lines changed: 35 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@ package jsonrpc2
99
import (
1010
"encoding/json"
1111
"errors"
12+
"fmt"
1213

1314
"github.com/francoispqt/gojay"
1415
)
@@ -58,10 +59,32 @@ func (m *RawMessage) UnmarshalJSON(data []byte) error {
5859
return nil
5960
}
6061

62+
// MarshalJSONObject implements gojay.MarshalerJSONObject.
63+
func (r *version) MarshalJSONObject(enc *gojay.Encoder) {
64+
enc.String(Version)
65+
}
66+
67+
// IsNil implements gojay.MarshalerJSONObject.
68+
func (r *version) IsNil() bool { return r == nil }
69+
70+
// UnmarshalJSONObject implements gojay.UnmarshalerJSONObject.
71+
func (r *version) UnmarshalJSONObject(dec *gojay.Decoder, _ string) error {
72+
return dec.String(&versionStr)
73+
}
74+
75+
// NKeys implements gojay.UnmarshalerJSONObject.
76+
func (r *version) NKeys() int { return 0 }
77+
78+
// compile time check whether the WireRequest implements a gojay.MarshalerJSONObject and gojay.UnmarshalerJSONObject interfaces.
79+
var (
80+
_ gojay.MarshalerJSONObject = (*version)(nil)
81+
_ gojay.UnmarshalerJSONObject = (*version)(nil)
82+
)
83+
6184
// MarshalJSONObject implements gojay.MarshalerJSONObject.
6285
func (r *WireRequest) MarshalJSONObject(enc *gojay.Encoder) {
63-
enc.StringKey(keyJSONRPC, r.JSONRPC)
64-
enc.StringKeyOmitEmpty(keyID, r.ID.String())
86+
enc.StringKey(keyJSONRPC, Version)
87+
enc.StringKeyOmitEmpty(keyID, fmt.Sprint(r.ID))
6588
enc.StringKey(keyMethod, r.Method)
6689
enc.AddEmbeddedJSONKeyOmitEmpty(keyParams, (*gojay.EmbeddedJSON)(r.Params))
6790
}
@@ -73,12 +96,12 @@ func (r *WireRequest) IsNil() bool { return r == nil }
7396
func (r *WireRequest) UnmarshalJSONObject(dec *gojay.Decoder, k string) error {
7497
switch k {
7598
case keyJSONRPC:
76-
return dec.String(&r.JSONRPC)
99+
return dec.String(&versionStr)
77100
case keyID:
78101
if r.ID == nil {
79102
r.ID = &ID{}
80103
}
81-
s := r.ID.String()
104+
s := fmt.Sprint(r.ID)
82105
return dec.String(&s)
83106
case keyMethod:
84107
return dec.String(&r.Method)
@@ -102,8 +125,8 @@ var (
102125

103126
// MarshalJSONObject implements gojay's MarshalerJSONObject
104127
func (r *WireResponse) MarshalJSONObject(enc *gojay.Encoder) {
105-
enc.StringKey(keyJSONRPC, r.JSONRPC)
106-
enc.StringKeyOmitEmpty(keyID, r.ID.String())
128+
enc.StringKey(keyJSONRPC, Version)
129+
enc.StringKeyOmitEmpty(keyID, fmt.Sprint(r.ID))
107130
enc.ObjectKeyOmitEmpty(keyError, r.Error)
108131
enc.AddEmbeddedJSONKeyOmitEmpty(keyResult, (*gojay.EmbeddedJSON)(r.Result))
109132
}
@@ -115,12 +138,12 @@ func (r *WireResponse) IsNil() bool { return r == nil }
115138
func (r *WireResponse) UnmarshalJSONObject(dec *gojay.Decoder, k string) error {
116139
switch k {
117140
case keyJSONRPC:
118-
return dec.String(&r.JSONRPC)
141+
return dec.String(&versionStr)
119142
case keyID:
120143
if r.ID == nil {
121144
r.ID = &ID{}
122145
}
123-
s := r.ID.String()
146+
s := fmt.Sprint(r.ID)
124147
return dec.String(&s)
125148
case keyError:
126149
if r.Error == nil {
@@ -147,8 +170,8 @@ var (
147170

148171
// MarshalJSONObject implements gojay's MarshalerJSONObject
149172
func (r *Combined) MarshalJSONObject(enc *gojay.Encoder) {
150-
enc.StringKey(keyJSONRPC, r.JSONRPC)
151-
enc.StringKeyOmitEmpty(keyID, r.ID.String())
173+
enc.StringKey(keyJSONRPC, Version)
174+
enc.StringKeyOmitEmpty(keyID, fmt.Sprint(r.ID))
152175
enc.StringKey(keyMethod, r.Method)
153176
enc.AddEmbeddedJSONKeyOmitEmpty(keyParams, (*gojay.EmbeddedJSON)(r.Params))
154177
enc.ObjectKeyOmitEmpty(keyError, r.Error)
@@ -162,12 +185,12 @@ func (r *Combined) IsNil() bool { return r == nil }
162185
func (r *Combined) UnmarshalJSONObject(dec *gojay.Decoder, k string) error {
163186
switch k {
164187
case keyJSONRPC:
165-
return dec.String(&r.JSONRPC)
188+
return dec.String(&versionStr)
166189
case keyID:
167190
if r.ID == nil {
168191
r.ID = &ID{}
169192
}
170-
s := r.ID.String()
193+
s := fmt.Sprint(r.ID)
171194
return dec.String(&s)
172195
case keyMethod:
173196
return dec.String(&r.Method)

0 commit comments

Comments
 (0)