jrpc2

package module
v0.0.4 Latest Latest
Warning

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

Go to latest
Published: Jun 5, 2018 License: BSD-3-Clause Imports: 16 Imported by: 0

README

jrpc2

Go Report Card

This repository provides Go package that implements a JSON-RPC 2.0 client and server.

View its documentation on GoDoc.

Documentation

Overview

Package jrpc2 implements a server and a client for the JSON-RPC 2.0 protocol defined by http://www.jsonrpc.org/specification.

Servers

The *Server type implements a JSON-RPC server. A server communicates with a client over a channel.Channel, and dispatches client requests to user-defined method handlers. These handlers satisfy the jrpc2.Method interface by exporting a Call method:

Call(ctx Context.Context, req *jrpc2.Request) (interface{}, error)

The server finds the Method for a request by looking up its name in a jrpc2.Assigner provided when the server is set up.

Let's work an example. Suppose we have defined the following Add function, and would like to export it via JSON-RPC:

// Add returns the sum of a slice of integers.
func Add(ctx context.Context, values []int) (int, error) {
   sum := 0
   for _, v := range values {
      sum += v
   }
   return sum, nil
}

To do this, we convert Add to a jrpc2.Method. The easiest way to do this is to call jrpc2.NewMethod, which uses reflection to lift the function into the jrpc2.Method interface exported by the server:

m := jrpc2.NewMethod(Add)  // m is a jrpc2.Method that invokes Add

Next, let's advertise this function under the name "Math.Add". For static assignments, we can use a jrpc2.MapAssigner, which finds methods by looking them up in a Go map:

import "bitbucket.org/creachadair/jrpc2"

assigner := jrpc2.MapAssigner{
   "Math.Add": jrpc2.NewMethod(Add),
}

Equipped with an Assigner we can now construct a Server:

srv := jrpc2.NewServer(assigner, nil)  // nil for default options

To serve requests, we will next need a connection. The channel package exports functions that can adapt various input and output streams to a channel.Channel, for example:

srv.Start(channel.Line(os.Stdin, os.Stdout))

The running server will handle incoming requests until the connection fails or until it is stopped explicitly by calling srv.Stop(). To wait for the server to finish, call:

err := srv.Wait()

This will report the error that led to the server exiting. A working implementation of this example can found in examples/adder/adder.go.

Clients

The *Client type implements a JSON-RPC client. A client communicates with a server over a channel.Channel, and is safe for concurrent use by multiple goroutines. It supports batched requests and may have arbitrarily many pending requests in flight simultaneously.

To establish a client we first need a channel.Channel:

import "net"

conn, err := net.Dial("tcp", "localhost:8080")
...
cli := jrpc2.NewClient(channel.JSON(conn, conn), nil)

There are two parts to sending an RPC: First, we construct a request given the method name and parameters, and issue it to the server. This returns a pending call:

p, err := cli.Call(ctx, "Math.Add", []int{1, 3, 5, 7})

Second, we wait for the pending call to complete to receive its results:

rsp := p.Wait()

You can check whether a response contains an error using its Error method:

if rsp.Error() != nil {
   log.Printf("Error from server: %v", rsp.Error())
   // N.B. This includes context errors such as cancellations and timeouts.
}

The separation of call and response allows requests to be issued serially and waited for in parallel. For convenience, the client has a CallWait method that combines these for a single synchronous call:

rsp, err := cli.CallWait(ctx, "Math.Add", []int{1, 3, 5, 7})

To issue a batch of requests all at once, use the Batch method:

batch, err := cli.Batch(ctx, []jrpc2.Spec{
   {"Math.Add", []int{1, 2, 3}},
   {"Math.Mul", []int{4, 5, 6}},
   {"Math.Max", []int{-1, 5, 3, 0, 1}},
})
...
rsps := batch.Wait()  // waits for all the pending responses

In this mode of operation, the caller must check each response for errors:

for i, rsp := range batch.Wait() {
   if err := rsp.Error(); err != nil {
     log.Printf("Request %d [%s] failed: %v", i, rsp.ID(), err)
   }
}

Alternatively, you may choose to wait for each request independently (though note that batch requests will usually not be returned until all results are complete anyway):

rsp0 := batch[0].Wait()
...

To decode the result from a successful response use its UnmarshalResult method:

var result int
if err := rsp.UnmarshalResult(&result); err != nil {
   log.Fatalln("UnmarshalResult:", err)
}

To shut down a client and discard all its pending work, call cli.Close().

Notifications

The JSON-RPC protocol also supports a kind of request called a notification. Notifications differ from ordinary requests in that they are one-way: The client sends them to the server, but the server does not reply.

A Client supports sending notifications as follows:

err := cli.Notify(ctx, "Alert", struct{Msg string}{"a fire is burning"})

Unlike ordinary requests, there are no pending calls for notifications; the notification is complete once it has been sent.

On the server side, notifications are identical to ordinary requests, save that their return value is discarded once the handler returns. If a handler does not want to do anything for a notification, it can query the request:

if req.IsNotification() {
   return 0, nil  // ignore notifications
}

Cancellation

The *Client and *Server types support a nonstandard cancellation protocol, that consists of a notification method "rpc.cancel" taking an array of request IDs to be cancelled. Upon receiving this notification, the server will cancel the context of each method handler whose ID is named.

When the context associated with a client request is cancelled, the client will send an "rpc.cancel" notification to the server for that request's ID:

ctx, cancel := context.WithCancel(ctx)
p, err := cli.Call(ctx, "MethodName", params)
...
cancel()
rsp := p.Wait()

The "rpc.cancel" method is automatically handled by the *Server implementation from this package.

Services with Multiple Methods

The examples above show a server with only one method using NewMethod; you will often want to expose more than one. The NewService function supports this by applying NewMethod to all the exported methods of a concrete value to produce a MapAssigner for those methods:

type math struct{}

func (math) Add(ctx context.Context, vals ...int) (int, error) { ... }
func (math) Mul(ctx context.Context, vals []int) (int, error) { ... }

assigner := jrpc2.NewService(math{})

This assigner maps the name "Add" to the Add method, and the name "Mul" to the Mul method, of the math value.

This may be further combined with the ServiceMapper type to allow different services to work together:

type status struct{}

func (status) Get(context.Context) (string, error) {
   return "all is well", nil
}

assigner := jrpc2.ServiceMapper{
   "Math":   jrpc2.NewService(math{}),
   "Status": jrpc2.NewService(status{}),
}

This assigner dispatches "Math.Add" and "Math.Mul" to the math value's methods, and "Status.Get" to the status value's method. A ServiceMapper splits the method name on the first period ("."), and you may nest ServiceMappers more deeply if you require a more complex hierarchy.

See the "caller" package for a convenient way to generate client call wrappers.

Index

Examples

Constants

View Source
const Version = "2.0"

Version is the version string for the JSON-RPC protocol understood by this implementation, defined at http://www.jsonrpc.org/specification.

Variables

View Source
var ErrNoData = errors.New("no data to unmarshal")

ErrNoData indicates that there are no data to unmarshal.

Functions

func DataErrorf

func DataErrorf(code Code, v interface{}, msg string, args ...interface{}) error

DataErrorf returns an error value of concrete type *Error having the specified code, error data, and formatted message string. If v == nil this behaves identically to Errorf(code, msg, args...).

func Errorf

func Errorf(code Code, msg string, args ...interface{}) error

Errorf returns an error value of concrete type *Error having the specified code and formatted message string. It is shorthand for DataErrorf(code, nil, msg, args...)

func ServerNotify added in v0.0.4

func ServerNotify(ctx context.Context) func(context.Context, string, interface{}) error

ServerNotify returns the server notifier associated with the given context, or nil if ctx does not have a server notifier. The context passed to the handler by *jrpc2.Server will include this value if the server was constructed with the AllowNotify option set true.

Types

type Assigner

type Assigner interface {
	// Assign returns the handler for the named method, or nil.
	Assign(method string) Method

	// Names returns a slice of all known method names for the assigner.  The
	// resulting slice is ordered lexicographically and contains no duplicates.
	Names() []string
}

An Assigner assigns a Method to handle the specified method name, or nil if no method is available to handle the request.

type Batch

type Batch []*Pending

A Batch is a group of pending requests awaiting responses.

func (Batch) Wait

func (b Batch) Wait() []*Response

Wait blocks until all the requests in b have completed, and returns the corresponding responses. The caller is responsible for checking for errors in each of the responses.

type Client

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

A Client is a JSON-RPC 2.0 client. The client sends requests and receives responses on a channel.Channel provided by the caller.

func NewClient

func NewClient(ch channel.Channel, opts *ClientOptions) *Client

NewClient returns a new client that communicates with the server via ch.

func (*Client) Batch

func (c *Client) Batch(ctx context.Context, specs []Spec) (Batch, error)

Batch initiates a batch of concurrent requests. It blocks until the entire batch is sent.

func (*Client) Call

func (c *Client) Call(ctx context.Context, method string, params interface{}) (*Pending, error)

Call initiates a single request. It blocks until the request is sent.

Example
package main

import (
	"context"
	"fmt"
	"log"

	"bitbucket.org/creachadair/jrpc2"
	"bitbucket.org/creachadair/jrpc2/channel"
)

var (
	ctx      = context.Background()
	srv, cli = channel.Pipe(channel.Line)
	c        = jrpc2.NewClient(cli, nil)
)

func main() {
	// var c = jrpc2.NewClient(cli, nil)
	p, err := c.Call(ctx, "Hello", nil)
	if err != nil {
		log.Fatalf("Call: %v", err)
	}
	rsp := p.Wait()
	if err := rsp.Error(); err != nil {
		log.Fatalf("Response: %v", err)
	}
	var msg string
	if err := rsp.UnmarshalResult(&msg); err != nil {
		log.Fatalf("Decoding result: %v", err)
	}
	fmt.Println(msg)
}
Output:

Hello, world!

func (*Client) CallWait

func (c *Client) CallWait(ctx context.Context, method string, params interface{}) (*Response, error)

CallWait initiates a single request and blocks until the response returns. It is shorthand for Call + Wait. If err != nil then rsp == nil. Errors from the server have concrete type *jrpc2.Error.

rsp, err := c.CallWait(ctx, method, params)
if err != nil {
   if e, ok := err.(*jrpc2.Error); ok {
      log.Fatalf("Error from server: %v", err)
   } else {
      log.Fatalf("Call failed: %v", err)
   }
}
handleValidResponse(rsp)
Example
package main

import (
	"context"
	"fmt"
	"log"

	"bitbucket.org/creachadair/jrpc2"
	"bitbucket.org/creachadair/jrpc2/channel"
)

var (
	ctx      = context.Background()
	srv, cli = channel.Pipe(channel.Line)
	c        = jrpc2.NewClient(cli, nil)
)

func main() {
	// var c = jrpc2.NewClient(cli, nil)
	rsp, err := c.CallWait(ctx, "Hello", nil)
	if err != nil {
		log.Fatalf("CallWait: %v", err)
	}
	var msg string
	if err := rsp.UnmarshalResult(&msg); err != nil {
		log.Fatalf("Decoding result: %v", err)
	}
	fmt.Println(msg)
}
Output:

Hello, world!

func (*Client) Close

func (c *Client) Close() error

Close shuts down the client, abandoning any pending in-flight requests.

func (*Client) Notify

func (c *Client) Notify(ctx context.Context, method string, params interface{}) error

Notify transmits a notification to the specified method and parameters. It blocks until the notification has been sent.

type ClientOptions

type ClientOptions struct {
	// If not nil, send debug logs here.
	Logger *log.Logger

	// Instructs the client to tolerate responses that do not include the
	// required "jsonrpc" version marker.
	AllowV1 bool

	// If set, this function is called with the context and encoded request
	// parameters before the request is sent to the server. Its return value
	// replaces the request parameters. This allows the client to send context
	// metadata along with the request. If unset, the parameters are unchanged.
	EncodeContext func(context.Context, json.RawMessage) (json.RawMessage, error)

	// If set, this function is called if a notification is received from the
	// server. If unset, server notifications are logged and discarded.  At
	// most one invocation of the callback will be active at a time.
	// Server notifications are a non-standard extension of JSON-RPC.
	OnNotify func(*Request)
}

ClientOptions control the behaviour of a client created by NewClient. A nil *ClientOptions provides sensible defaults.

type Code

type Code int32

A Code is an error response code, that satisfies the Error interface. Codes can be used directly as error values, but a more useful value can be obtained by passing a Code to the Errorf function along with a descriptive message.

const (
	E_ParseError     Code = -32700 // Invalid JSON received by the server
	E_InvalidRequest Code = -32600 // The JSON sent is not a valid request object
	E_MethodNotFound Code = -32601 // The method does not exist or is unavailable
	E_InvalidParams  Code = -32602 // Invalid method parameters
	E_InternalError  Code = -32603 // Internal JSON-RPC error

	E_NoError          Code = -32099 // Denotes a nil error
	E_SystemError      Code = -32098 // Errors from the operating environment
	E_Cancelled        Code = -32097 // Request cancelled
	E_DeadlineExceeded Code = -32096 // Request deadline exceeded
)

Pre-defined error codes, including the standard ones from the JSON-RPC specification and some specific to this implementation.

func ErrorCode

func ErrorCode(err error) Code

ErrorCode reports the error code associated with err. If err == nil, E_NoError is returned. If err is a Code, that code is returned. If err has type *Error, its code is returned. Otherwise E_SystemError is returned.

func RegisterCode

func RegisterCode(value int32, message string) Code

RegisterCode adds a new Code value with the specified message string. This function will panic if the proposed value is already registered.

func (Code) Error

func (c Code) Error() string

func (Code) ToError

func (c Code) ToError() *Error

ToError converts a Code to an *Error using its default message.

type Error

type Error struct {
	Code    Code
	Message string
	// contains filtered or unexported fields
}

Error is the concrete type of errors returned from RPC calls.

func (Error) Error

func (e Error) Error() string

Error renders e to a human-readable string for the error interface.

func (Error) HasData

func (e Error) HasData() bool

HasData reports whether e has error data to unmarshal.

func (Error) UnmarshalData

func (e Error) UnmarshalData(v interface{}) error

UnmarshalData decodes the error data associated with e into v. It returns ErrNoData without modifying v if there was no data message attached to e.

type MapAssigner

type MapAssigner map[string]Method

A MapAssigner is a trivial implementation of the Assigner interface that looks up literal method names in a map of static Methods.

func NewService

func NewService(obj interface{}) MapAssigner

NewService adapts the methods of a value to a map from method names to Method implementations as constructed by NewMethod. It will panic if obj has no exported methods with a suitable signature.

func (MapAssigner) Assign

func (m MapAssigner) Assign(method string) Method

Assign implements part of the Assigner interface.

func (MapAssigner) Names

func (m MapAssigner) Names() []string

Names implements part of the Assigner interface.

type Method

type Method interface {
	// Call invokes the method with the specified request. The response value,
	// if non-nil, must be JSON-marshalable. In case of error, the handler can
	// return a value of type *jrpc2.Error to control the response code sent
	// back to the caller; otherwise the server will wrap the resulting value.
	//
	// The context passed to the handler by a *jrpc2.Server includes two extra
	// values that the handler may extract.
	//
	// To obtain a server metrics value, write:
	//
	//    sm := jrpc2.ServerMetrics(ctx)
	//
	// To obtain the inbound request message, write:
	//
	//    req := jrpc2.InboundRequest(ctx)
	//
	// The inbound request is the same value passed to the Call method -- the
	// latter is primarily useful in handlers generated by jrpc2.NewMethod,
	// which do not receive this value directly.
	Call(context.Context, *Request) (interface{}, error)
}

A Method handles a single request.

func NewMethod

func NewMethod(fn interface{}) Method

NewMethod adapts a function to a Method. The concrete value of fn must be a function with one of the following type signatures:

func(context.Context) (Y, error)
func(context.Context, X) (Y, error)
func(context.Context, ...X) (Y, error)
func(context.Context, *jrpc2.Request) (Y, error)

for JSON-marshalable types X and Y. NewMethod will panic if the type of its argument does not have one of these forms. The resulting method will handle encoding and decoding of JSON and report appropriate errors.

type Metrics

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

A Metrics value collects counters and maximum value trackers. A nil *Metrics is valid, and discards all metrics. A *Metrics value is safe for concurrent use by multiple goroutines.

func NewMetrics

func NewMetrics() *Metrics

NewMetrics creates a new, empty metrics collector.

func ServerMetrics

func ServerMetrics(ctx context.Context) *Metrics

ServerMetrics returns the server metrics collector associated with the given context, or nil if ctx doees not have a collector attached. The context passed to a handler by *jrpc2.Server will include this value.

func (*Metrics) Count

func (m *Metrics) Count(name string, n int64)

Count adds n to the current value of the counter named, defining the counter if it does not already exist.

func (*Metrics) CountAndSetMax

func (m *Metrics) CountAndSetMax(name string, n int64)

CountAndSetMax adds n to the current value of the counter named, and also updates a max value tracker with the same name in a single step.

func (*Metrics) SetMaxValue

func (m *Metrics) SetMaxValue(name string, n int64)

SetMaxValue sets the maximum value metric named to the greater of n and its current value, defining the value if it does not already exist.

func (*Metrics) Snapshot

func (m *Metrics) Snapshot(counters, maxValues map[string]int64)

Snapshot copies an atomic snapshot of the counters and max value trackers into the provided non-nil maps.

type Pending

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

A Pending tracks a single pending request whose response is awaited. Calling Wait blocks until the response is received. It is safe to call Wait multiple times from concurrent goroutines.

func (*Pending) ID

func (p *Pending) ID() string

ID reports the request identifier of the request p is waiting for. It is safe to call ID even if the request has not yet completed.

func (*Pending) Wait

func (p *Pending) Wait() *Response

Wait blocks until p is complete, then returns the response. The caller must check the response for an error from the server.

type Request

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

A Request is a request message from a client to a server.

func InboundRequest

func InboundRequest(ctx context.Context) *Request

InboundRequest returns the inbound request associated with the given context, or nil if ctx does not have an inbound request. The context passed to the handler by *jrpc2.Server will include this value.

This is mainly useful to wrapped server methods that do not have the request as an explicit parameter; for direct implementations of Method.Call the request value returned by InboundRequest will be the same value as was passed explicitly.

func (*Request) ID

func (r *Request) ID() string

ID returns the request identifier for r, or "" if r is a notification.

func (*Request) IsNotification

func (r *Request) IsNotification() bool

IsNotification reports whether the request is a notification, and thus does not require a value response.

func (*Request) Method

func (r *Request) Method() string

Method reports the method name for the request.

func (*Request) UnmarshalParams

func (r *Request) UnmarshalParams(v interface{}) error

UnmarshalParams decodes the parameters into v.

type Response

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

A Response is a response message from a server to a client.

func (*Response) Error

func (r *Response) Error() *Error

Error returns a non-nil *Error if the response contains an error.

func (*Response) ID

func (r *Response) ID() string

ID returns the request identifier for r.

func (*Response) UnmarshalResult

func (r *Response) UnmarshalResult(v interface{}) error

UnmarshalResult decodes the result message into v. If the request failed, UnmarshalResult returns the *Error value that would also be returned by r.Error(), and v is unmodified.

type Server

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

A Server is a JSON-RPC 2.0 server. The server receives requests and sends responses on a channel.Channel provided by the caller, and dispatches requests to user-defined Method handlers.

func NewServer

func NewServer(mux Assigner, opts *ServerOptions) *Server

NewServer returns a new unstarted server that will dispatch incoming JSON-RPC requests according to mux. To start serving, call Start.

N.B. It is only safe to modify mux after the server has been started if mux itself is safe for concurrent use by multiple goroutines.

This function will panic if mux == nil.

Example
package main

import (
	"context"
	"fmt"
	"strings"

	"bitbucket.org/creachadair/jrpc2"
	"bitbucket.org/creachadair/jrpc2/channel"
)

var (
	s *jrpc2.Server

	srv, cli = channel.Pipe(channel.Line)
)

func main() {
	// Construct a new server with a single method "Hello".
	s = jrpc2.NewServer(jrpc2.MapAssigner{
		"Hello": jrpc2.NewMethod(func(ctx context.Context) (string, error) {
			return "Hello, world!", nil
		}),
	}, nil).Start(srv)

	// We can query the server for its current status information, including a
	// list of its methods.
	si := s.ServerInfo()

	fmt.Println(strings.Join(si.Methods, "\n"))
}
Output:

Hello

func (*Server) Notify added in v0.0.4

func (s *Server) Notify(ctx context.Context, method string, params interface{}) error

Notify posts a server-side notification to the client. This is a non-standard extension of JSON-RPC, and may not be supported by all clients.

func (*Server) ServerInfo

func (s *Server) ServerInfo() *ServerInfo

ServerInfo returns an atomic snapshot of the current server info for s.

func (*Server) Start

func (s *Server) Start(c channel.Channel) *Server

Start enables processing of requests from c. This function will panic if the server is already running.

func (*Server) Stop

func (s *Server) Stop()

Stop shuts down the server. It is safe to call this method multiple times or from concurrent goroutines; it will only take effect once.

func (*Server) Wait

func (s *Server) Wait() error

Wait blocks until the connection terminates and returns the resulting error.

type ServerInfo

type ServerInfo struct {
	// The list of method names exported by this server.
	Methods []string `json:"methods,omitempty"`

	// Metric values defined by the evaluation of methods.
	Counter  map[string]int64 `json:"counters,omitempty"`
	MaxValue map[string]int64 `json:"maxValue,omitempty"`
}

ServerInfo is the concrete type of responses from the rpc.serverInfo method.

type ServerOptions

type ServerOptions struct {
	// If not nil, send debug logs here.
	Logger *log.Logger

	// Instructs the server to tolerate requests that do not include the
	// required "jsonrpc" version marker.
	AllowV1 bool

	// Instructs the server to allow server notifications, a non-standard
	// extension to the JSON-RPC protocol.
	AllowNotify bool

	// Allows up to the specified number of concurrent goroutines to execute
	// when processing requests. A value less than 1 uses runtime.NumCPU().
	Concurrency int

	// If set, this function is called with the encoded request parameters
	// received from the client, before they are delivered to the handler.  Its
	// return value replaces the context and argument values. This allows the
	// server to decode context metadata sent by the client. If unset, ctx and
	// params are used as given.
	DecodeContext func(context.Context, json.RawMessage) (context.Context, json.RawMessage, error)

	// If set, use this value to record server metrics. All servers created
	// from the same options will share the same metrics collector.  If none is
	// set, an empty collector will be created for each new server.
	Metrics *Metrics
}

ServerOptions control the behaviour of a server created by NewServer. A nil *ServerOptions provides sensible defaults.

type ServiceMapper

type ServiceMapper map[string]Assigner

A ServiceMapper combines multiple assigners into one, permitting a server to export multiple services under different names.

Example:

m := jrpc2.ServiceMapper{
  "Foo": jrpc2.NewService(fooService),  // methods Foo.A, Foo.B, etc.
  "Bar": jrpc2.NewService(barService),  // methods Bar.A, Bar.B, etc.
}

func (ServiceMapper) Assign

func (m ServiceMapper) Assign(method string) Method

Assign splits the inbound method name as Service.Method, and passes the Method portion to the corresponding Service assigner. If method does not have the form Service.Method, or if Service is not set in m, the lookup fails and returns nil.

func (ServiceMapper) Names

func (m ServiceMapper) Names() []string

Names reports the composed names of all the methods in the service, each having the form Service.Method.

type Spec

type Spec struct {
	Method string
	Params interface{}
}

A Spec combines a method name and parameter value.

Directories

Path Synopsis
Package caller provides a function to construct JRPC2 client call wrappers.
Package caller provides a function to construct JRPC2 client call wrappers.
Package channel defines a communications channel that can encode/transmit and decode/receive data records with a configurable framing discipline, and provides some simple framing implementations.
Package channel defines a communications channel that can encode/transmit and decode/receive data records with a configurable framing discipline, and provides some simple framing implementations.
examples
adder
Program adder demonstrates a trivial JSON-RPC server that communicates over the process's stdin and stdout.
Program adder demonstrates a trivial JSON-RPC server that communicates over the process's stdin and stdout.
client
Program client demonstrates how to set up a JSON-RPC 2.0 client using the bitbucket.org/creachadair/jrpc2 package.
Program client demonstrates how to set up a JSON-RPC 2.0 client using the bitbucket.org/creachadair/jrpc2 package.
jcl
Program jcl is a client program for the demonstration shell-server defined in jsh.go.
Program jcl is a client program for the demonstration shell-server defined in jsh.go.
jsh
Program jsh exposes a trivial command-shell functionality via JSON-RPC for demonstration purposes.
Program jsh exposes a trivial command-shell functionality via JSON-RPC for demonstration purposes.
server
Program server demonstrates how to set up a JSON-RPC 2.0 server using the bitbucket.org/creachadair/jrpc2 package.
Program server demonstrates how to set up a JSON-RPC 2.0 server using the bitbucket.org/creachadair/jrpc2 package.
Program jcall issues RPC calls to a JSON-RPC server.
Program jcall issues RPC calls to a JSON-RPC server.
Package jcontext implements an encoder and decoder for request context values, allowing context metadata to be propagated through JSON-RPC.
Package jcontext implements an encoder and decoder for request context values, allowing context metadata to be propagated through JSON-RPC.
Package server provides support routines for running jrpc2 servers.
Package server provides support routines for running jrpc2 servers.

Jump to

Keyboard shortcuts

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