jrpc2

package
v0.8.2 Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: May 2, 2020 License: MIT Imports: 15 Imported by: 0

README

jrpc2: a thin framework for making jsonrpc2 clients and servers

jrpc2 is an almost standards compliant implementation of JSON-RPC 2.0.

A few modifications have been made to better fit the needs of the c-lightning RPC, most notably that the server offers a "Notify" method.

Some notes on architecture

A marriage of JSON and a strongly typed language such as Go is never a truly happy affair. In order to provide the best hiding of this fact, glightning offers a boutique jsonrpc2 implementation, jrpc2.

glightning takes advantage of reflection to marshal and unmarshal method parameters.

Offering a method from the Server

To have your server respond to methods, you'll need to create a new type struct that implements the ServerMethod interface.

type ServerMethod interface {
	Method
	New() interface{}
	Call() (Result, error)
}

Here's an example:

// Declare a new Subtract method, as a struct

// The public members of this struct will be the expected parameters
// when the method is called.
type Subtract struct {
	Minuend    int	`json:"minuend"`
	Subtrahend int	`json:"subtrahend"`
}

func (s *Subtract) New() interface{} {
	return &Subtract{}
}

func (s *Subtract) Call() (jrpc2.Result, error) {
	return s.Minuend - s.Subtrahend, nil
}

// This is the name of the method!
func (s *Subtract) Name() string {
	return "subtract"
}

After your server method has been created, you just need to register the method with the server, so it knows who to call when it receives a request.

server := jrpc2.NewServer()
server.Register(&Subtract{})

All that's left to do now is to start up the server on the socket or pipeset of your choice.

Calling a method from a Client

Calling a method from the Client is much easier. You only need to pass a Method and a result object to client, as a request.

type ClientSubtract struct {
	Minuend int
	Subtrahend int
}

func (s *ClientSubtract) Name() string {
	return "subtract"
}

// You can wrap the client call in a function for convenience
func subtract(c *jrpc2.Client, min, sub int) int {
	var result int	
	err := c.Request(&ClientSubtract{min,sub}, &result)
	if err != nil {
		panic(err)
	}
	return result
}

You can also send notifications from the client. These are JSON-RPC notifications, which means they do not include an ID and will not get a response from the server.

client.Notify(&ClientSubtract{min,sub})

Missing Features

jrpc2 currently does not support request batching

jrpc2 currently does not provide an elegant mechanism for parsing extra data that is passed back in error responses.

Documentation

Index

Constants

View Source
const InternalErr = -32603
View Source
const InvalidParams = -32603
View Source
const InvalidRequest = -32600
View Source
const (
	MaxIntakeBuffer = 500 * 1024 * 1023
)
View Source
const MethodNotFound = -32601
View Source
const ParseError = -32700

Variables

This section is empty.

Functions

func GetNamedParams

func GetNamedParams(target Method) map[string]interface{}

func GetParams

func GetParams(target Method) []interface{}

func ParseNamedParams

func ParseNamedParams(target Method, params map[string]interface{}) error

func ParseParamArray

func ParseParamArray(target Method, params []interface{}) error

Map passed in params to the fields on the method, in listed order

Types

type Client

type Client struct {
	// contains filtered or unexported fields
}

func NewClient

func NewClient() *Client

func (*Client) IsUp

func (c *Client) IsUp() bool

func (*Client) NextId

func (c *Client) NextId() *Id

for now, use a counter as the id for requests

func (*Client) Notify

func (c *Client) Notify(m Method) error

Sends a notification to the server. No response is expected, and no ID is assigned to the request.

func (*Client) Request

func (c *Client) Request(m Method, resp interface{}) error

Isses an RPC call. Is blocking. Times out after {timeout} seconds (set on client).

func (*Client) RequestNoTimeout

func (c *Client) RequestNoTimeout(m Method, resp interface{}) error

Hangs until a response comes. Be aware that this may never terminate.

func (*Client) SetTimeout

func (c *Client) SetTimeout(secs uint)

func (*Client) Shutdown

func (c *Client) Shutdown()

func (*Client) SocketStart

func (c *Client) SocketStart(socket string, up chan bool) error

Start up on a socket, instead of using pipes This method blocks. The up channel is an optional channel to receive notification when the connection is set up

func (*Client) StartUp

func (c *Client) StartUp(in, out *os.File)

type CodedError

type CodedError struct {
	Id   *Id
	Code int
	Msg  string
}

func NewError

func NewError(id *Id, code int, msg string) *CodedError

func (CodedError) Error

func (e CodedError) Error() string

type Id

type Id struct {
	// contains filtered or unexported fields
}

ids for JSON-RPC v2 can be a string, an integer or null. We use the pointer type in Request to simulate a null value for JSON mapping; this struct manages the rest. for giggles, we map all Ids to strings, but in the case of this being something that's populated from an incoming request, we need to maintain the 'actual' type of it so when we send it back over the wire, we don't confuse the other side.

func NewId

func NewId(val string) *Id

func NewIdAsInt

func NewIdAsInt(val int64) *Id

func (Id) MarshalJSON

func (id Id) MarshalJSON() ([]byte, error)

func (Id) String added in v0.8.0

func (id Id) String() string

func (*Id) UnmarshalJSON

func (id *Id) UnmarshalJSON(data []byte) error

func (*Id) Val

func (id *Id) Val() string

type Method

type Method interface {
	Name() string
}

type RawResponse

type RawResponse struct {
	Id    *Id             `json:"id"`
	Raw   json.RawMessage `json:"-"`
	Error *RpcError       `json:"error,omitempty"`
}

RawResponses are what the client gets back from an RPC call. Leaving raw json around is kind of hacky, until you realize how clean it is from a parsing perspective

func (*RawResponse) MarshalJSON

func (r *RawResponse) MarshalJSON() ([]byte, error)

func (*RawResponse) UnmarshalJSON

func (r *RawResponse) UnmarshalJSON(data []byte) error

type Request

type Request struct {
	Id     *Id    `json:"id,omitempty"`
	Method Method `json:"-"`
}

Models for the model gods

func (*Request) MarshalJSON

func (r *Request) MarshalJSON() ([]byte, error)

What we really want is the parameter values off of the Method object called on the client side

func (*Request) UnmarshalJSON

func (r *Request) UnmarshalJSON(data []byte) error

type Response

type Response struct {
	Result Result    `json:"result,omitempty"`
	Error  *RpcError `json:"error,omitempty"`
	Id     *Id       `json:"id"`
}

Responses are sent by the Server

func Execute

func Execute(id *Id, method ServerMethod) *Response

func (*Response) MarshalJSON

func (r *Response) MarshalJSON() ([]byte, error)

func (*Response) UnmarshalJSON

func (r *Response) UnmarshalJSON(data []byte) error

type Result

type Result interface{}

type RpcError

type RpcError struct {
	Code    int             `json:"code"`
	Message string          `json:"message"`
	Data    json.RawMessage `json:"data,omitempty"`
}

func (*RpcError) Error

func (e *RpcError) Error() string

func (*RpcError) ParseData

func (e *RpcError) ParseData(into interface{}) error

provide your own object to parse this with! ehehe

type Server

type Server struct {
	// contains filtered or unexported fields
}

a server needs to be able to - send back a response (with the right id) bonus round:

  • respond to batched requests

func NewServer

func NewServer() *Server

func (*Server) GetMethodMap

func (s *Server) GetMethodMap() []ServerMethod

func (*Server) Notify

func (s *Server) Notify(m Method) error

Technically, this is a client side method but we're monkey patching it on here because c-lightning acts both as a server and a client.

func (*Server) Register

func (s *Server) Register(method ServerMethod) error

func (*Server) Shutdown

func (s *Server) Shutdown()

func (*Server) StartUp

func (s *Server) StartUp(in, out *os.File) error

func (*Server) StartUpSingle

func (s *Server) StartUpSingle(in string)

Listen through a file socket

func (*Server) Unmarshal

func (s *Server) Unmarshal(data []byte, r *Request) *CodedError

func (*Server) Unregister

func (s *Server) Unregister(method ServerMethod) error

func (*Server) UnregisterByName

func (s *Server) UnregisterByName(name string) error

type ServerMethod

type ServerMethod interface {
	Method
	New() interface{}
	Call() (Result, error)
}

method type to register on the server side

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL