// Copyright 2010 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.

// Package jsonrpc implements a JSON-RPC 1.0 ClientCodec and ServerCodec // for the rpc package. // For JSON-RPC 2.0 support, see https://godoc.org/?q=json-rpc+2.0
package jsonrpc import ( ) type clientCodec struct { dec *json.Decoder // for reading JSON values enc *json.Encoder // for writing JSON values c io.Closer // temporary work space req clientRequest resp clientResponse // JSON-RPC responses include the request id but not the request method. // Package rpc expects both. // We save the request method in pending when sending a request // and then look it up by request ID when filling out the rpc Response. mutex sync.Mutex // protects pending pending map[uint64]string // map request id to method name } // NewClientCodec returns a new [rpc.ClientCodec] using JSON-RPC on conn. func ( io.ReadWriteCloser) rpc.ClientCodec { return &clientCodec{ dec: json.NewDecoder(), enc: json.NewEncoder(), c: , pending: make(map[uint64]string), } } type clientRequest struct { Method string `json:"method"` Params [1]any `json:"params"` Id uint64 `json:"id"` } func ( *clientCodec) ( *rpc.Request, any) error { .mutex.Lock() .pending[.Seq] = .ServiceMethod .mutex.Unlock() .req.Method = .ServiceMethod .req.Params[0] = .req.Id = .Seq return .enc.Encode(&.req) } type clientResponse struct { Id uint64 `json:"id"` Result *json.RawMessage `json:"result"` Error any `json:"error"` } func ( *clientResponse) () { .Id = 0 .Result = nil .Error = nil } func ( *clientCodec) ( *rpc.Response) error { .resp.reset() if := .dec.Decode(&.resp); != nil { return } .mutex.Lock() .ServiceMethod = .pending[.resp.Id] delete(.pending, .resp.Id) .mutex.Unlock() .Error = "" .Seq = .resp.Id if .resp.Error != nil || .resp.Result == nil { , := .resp.Error.(string) if ! { return fmt.Errorf("invalid error %v", .resp.Error) } if == "" { = "unspecified error" } .Error = } return nil } func ( *clientCodec) ( any) error { if == nil { return nil } return json.Unmarshal(*.resp.Result, ) } func ( *clientCodec) () error { return .c.Close() } // NewClient returns a new [rpc.Client] to handle requests to the // set of services at the other end of the connection. func ( io.ReadWriteCloser) *rpc.Client { return rpc.NewClientWithCodec(NewClientCodec()) } // Dial connects to a JSON-RPC server at the specified network address. func (, string) (*rpc.Client, error) { , := net.Dial(, ) if != nil { return nil, } return NewClient(), }