mirror of
https://github.com/sourcegraph/jsonrpc2.git
synced 2026-06-17 20:50:03 +02:00
The JSON-RPC 2.0 specification allows the params member of a request to be omitted [1]. Before this commit, this library did not allow the params member to be omitted. When the params argument of the Conn.Call or Conn.Notify method was set to nil, then Request.Params was set to the JSON encoding of nil which is null. This commit adds a ConnOption named OmitNilParams. If OmitNilParams is applied on Conn and Conn.Call or Conn.Notify are invoked with their params argument set to nil, then the params member in the JSON encoding of Request is omitted. If the OmitNilParams option is not applied on Conn then the previous behavior is maintained. In other words, the changes in this commit are backwards compatible. References [1]: https://www.jsonrpc.org/specification#request_object
119 lines
3.2 KiB
Go
119 lines
3.2 KiB
Go
package jsonrpc2
|
|
|
|
import (
|
|
"encoding/json"
|
|
"sync"
|
|
)
|
|
|
|
// Logger interface implements one method - Printf.
|
|
// You can use the stdlib logger *log.Logger
|
|
type Logger interface {
|
|
Printf(format string, v ...interface{})
|
|
}
|
|
|
|
// ConnOpt is the type of function that can be passed to NewConn to
|
|
// customize the Conn before it is created.
|
|
type ConnOpt func(*Conn)
|
|
|
|
// OnRecv causes all requests received on conn to invoke f(req, nil)
|
|
// and all responses to invoke f(req, resp),
|
|
func OnRecv(f func(*Request, *Response)) ConnOpt {
|
|
return func(c *Conn) { c.onRecv = append(c.onRecv, f) }
|
|
}
|
|
|
|
// OnSend causes all requests sent on conn to invoke f(req, nil) and
|
|
// all responses to invoke f(nil, resp),
|
|
func OnSend(f func(*Request, *Response)) ConnOpt {
|
|
return func(c *Conn) { c.onSend = append(c.onSend, f) }
|
|
}
|
|
|
|
// LogMessages causes all messages sent and received on conn to be
|
|
// logged using the provided logger.
|
|
func LogMessages(logger Logger) ConnOpt {
|
|
return func(c *Conn) {
|
|
// Remember reqs we have received so we can helpfully show the
|
|
// request method in OnSend for responses.
|
|
var (
|
|
mu sync.Mutex
|
|
reqMethods = map[ID]string{}
|
|
)
|
|
|
|
// Set custom logger from provided input
|
|
c.logger = logger
|
|
|
|
OnRecv(func(req *Request, resp *Response) {
|
|
switch {
|
|
case req != nil:
|
|
mu.Lock()
|
|
reqMethods[req.ID] = req.Method
|
|
mu.Unlock()
|
|
|
|
params, _ := json.Marshal(req.Params)
|
|
if req.Notif {
|
|
logger.Printf("jsonrpc2: --> notif: %s: %s\n", req.Method, params)
|
|
} else {
|
|
logger.Printf("jsonrpc2: --> request #%s: %s: %s\n", req.ID, req.Method, params)
|
|
}
|
|
|
|
case resp != nil:
|
|
var method string
|
|
if req != nil {
|
|
method = req.Method
|
|
} else {
|
|
method = "(no matching request)"
|
|
}
|
|
switch {
|
|
case resp.Result != nil:
|
|
result, _ := json.Marshal(resp.Result)
|
|
logger.Printf("jsonrpc2: --> result #%s: %s: %s\n", resp.ID, method, result)
|
|
case resp.Error != nil:
|
|
err, _ := json.Marshal(resp.Error)
|
|
logger.Printf("jsonrpc2: --> error #%s: %s: %s\n", resp.ID, method, err)
|
|
}
|
|
}
|
|
})(c)
|
|
OnSend(func(req *Request, resp *Response) {
|
|
switch {
|
|
case req != nil:
|
|
params, _ := json.Marshal(req.Params)
|
|
if req.Notif {
|
|
logger.Printf("jsonrpc2: <-- notif: %s: %s\n", req.Method, params)
|
|
} else {
|
|
logger.Printf("jsonrpc2: <-- request #%s: %s: %s\n", req.ID, req.Method, params)
|
|
}
|
|
|
|
case resp != nil:
|
|
mu.Lock()
|
|
method := reqMethods[resp.ID]
|
|
delete(reqMethods, resp.ID)
|
|
mu.Unlock()
|
|
if method == "" {
|
|
method = "(no previous request)"
|
|
}
|
|
|
|
if resp.Result != nil {
|
|
result, _ := json.Marshal(resp.Result)
|
|
logger.Printf("jsonrpc2: <-- result #%s: %s: %s\n", resp.ID, method, result)
|
|
} else {
|
|
err, _ := json.Marshal(resp.Error)
|
|
logger.Printf("jsonrpc2: <-- error #%s: %s: %s\n", resp.ID, method, err)
|
|
}
|
|
}
|
|
})(c)
|
|
}
|
|
}
|
|
|
|
// SetLogger sets the logger for the connection.
|
|
func SetLogger(logger Logger) ConnOpt {
|
|
return func(c *Conn) {
|
|
c.logger = logger
|
|
}
|
|
}
|
|
|
|
// OmitNilParams instructs Conn.Call and Conn.Notify to omit the params member
|
|
// from the JSON-RPC request if invoked with their params argument set to nil.
|
|
func OmitNilParams() ConnOpt {
|
|
return func(c *Conn) {
|
|
c.omitNilParams = true
|
|
}
|
|
}
|