rpc

package module
v0.6.0 Latest Latest
Warning

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

Go to latest
Published: Jan 6, 2024 License: Apache-2.0, MIT Imports: 17 Imported by: 174

README

go-libp2p-gorpc

GoDoc Codecov Discourse posts

Simple Go RPC for libp2p.

go-libp2p-gorpc provides RPC support on top of libp2p in the same way that net/rpc does on HTTP with a few additional features like:

  • Streaming RPC calls using channels.
  • Contexts and async calls.

Table of Contents

Install

This module can be installed with go get:

> go get github.com/libp2p/go-libp2p-gorpc

This repo is gomod-compatible, and users of go 1.11 and later with modules enabled will automatically pull the latest tagged release by referencing this package. Upgrades to future releases can be managed using go get, or by editing your go.mod file as described by the gomod documentation.

Usage

Documentation for this module is maintained in pkg.go.dev.

There are also examples inside the examples directory

Contribute

PRs accepted.

Small note: If editing the README, please conform to the standard-readme specification.

License

MIT


The last gx published version of this module was: 1.1.4: QmcJCApoEsCJJap2iS1os9GFX5EuRrfuPeZdjCopz2SyPm

Documentation

Overview

Package rpc is heavily inspired by Go standard net/rpc package. It aims to do the same thing, except it uses libp2p for communication and provides context support for cancelling operations.

A server registers an object, making it visible as a service with the name of the type of the object. After registration, exported methods of the object will be accessible remotely. A server may register multiple objects (services) of different types but it is an error to register multiple objects of the same type.

Only methods that satisfy these criteria will be made available for remote access; other methods will be ignored:

  • the method's type is exported.
  • the method is exported.
  • the method has 3 arguments.
  • the method's first argument is a context.
  • For normal methods:
  • the method's second and third arguments are both exported (or builtin) types.
  • the method's second argument is a pointer.
  • For "streaming" methods:
  • the method's second argument is a receiving channel (<-chan) of exported (or builtin) type.
  • the method's third argument is a sending channel (chan<-) of exported (or builtin) type.
  • the method has return type error.

In effect, the method must look schematically like

	func (t *T) MethodName(ctx context.Context, argType T1, replyType *T2) error
     or
	func (t *T) MethodName(ctx context.Context, argChan <-chan T1, replyChan chan<- T2) error

where T1 and T2 can be marshaled by github.com/ugorji/go/codec.

In normal calls, the method's second argument represents the arguments provided by the caller; the third argument represents the result parameters to be returned to the caller. The function error response is passed to the client accordingly.

In streaming calls, the method's second and third arguments are argument and replies channels. The method is expected to read from the argument channel until it is closed. The method is expected to send responses on the replies channel and close it when done. Both channels are transparently and asynchronously streamed on the wire between remote hosts.

In order to use this package, a ready-to-go libp2p Host must be provided to clients and servers, along with a protocol.ID. rpc will add a stream handler for the given protocol.

Contexts are supported and honored when provided. On the server side, methods must take a context. A closure or reset of the libp2p stream will trigger a cancellation of the context received by the functions. On the client side, the user can optionally provide a context. Cancelling the client's context will cancel the operation both on the client and on the server side (by closing the associated stream).

Index

Constants

View Source
const (
	// ContextKeyRequestSender is default key for RPC service function context to retrieve peer ID of current request sender
	ContextKeyRequestSender = ContextKey("request_sender")
	// MaxServiceIDLength specifies a maximum length for the
	// "ServiceName.MethodName" so that an attacker cannot send an
	// arbitrarily large ServiceID.
	MaxServiceIDLength = 256
)

Variables

This section is empty.

Functions

func AuthorizeWithMap

func AuthorizeWithMap(p map[peer.ID]map[string]bool) func(pid peer.ID, svc string, method string) bool

AuthorizeWithMap returns an authrorization function that follows the strategy as described in the given map(maps "service.method" of a peer to boolean permission).

func GetRequestSender added in v0.1.3

func GetRequestSender(ctx context.Context) (peer.ID, error)

GetRequestSender gets current request sender from RPC service's function context

func IsAuthorizationError

func IsAuthorizationError(err error) bool

IsAuthorizationError returns whether an error is authorizationError.

func IsClientError

func IsClientError(err error) bool

IsClientError returns whether an error is clientError.

func IsRPCError

func IsRPCError(err error) bool

IsRPCError returns whether an error is either a serverError or clientError.

func IsServerError

func IsServerError(err error) bool

IsServerError returns whether an error is serverError.

Types

type Call

type Call struct {
	Dest          peer.ID
	SvcID         ServiceID     // The name of the service and method to call.
	Args          interface{}   // The argument to the function.
	Reply         interface{}   // The reply from the function.
	StreamArgs    reflect.Value // streaming objects (channel).
	StreamReplies reflect.Value // streaming replies (channel).
	Done          chan *Call    // Strobes when call is complete.

	Error error // After completion, the error status.
	// contains filtered or unexported fields
}

Call represents an active RPC. Calls are used to indicate completion of RPC requests and are returned within the provided channel in the Go() functions.

type Client

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

Client represents an RPC client which can perform calls to a remote (or local, see below) Server.

func NewClient

func NewClient(h host.Host, p protocol.ID, opts ...ClientOption) *Client

NewClient returns a new Client which uses the given libp2p host and protocol ID, which must match the one used by the server. The Host must be correctly configured to be able to open streams to the server (addresses and keys in Peerstore etc.).

The client returned will not be able to run any "local" requests (to its own peer ID) if a server is configured with the same Host becase libp2p hosts cannot open streams to themselves. For this, pass the server directly using NewClientWithServer.

func NewClientWithServer

func NewClientWithServer(h host.Host, p protocol.ID, s *Server, opts ...ClientOption) *Client

NewClientWithServer takes an additional RPC Server and returns a Client.

Unlike the normal client, this one will be able to perform any requests to itself by using the given directly (and way more efficiently). It is assumed that Client and Server share the same libp2p host in this case.

func (*Client) Call

func (c *Client) Call(
	dest peer.ID,
	svcName, svcMethod string,
	args, reply interface{},
) error

Call performs an RPC call to a registered Server service and blocks until completed, returning any errors.

The args parameter represents the service's method args and must be of exported or builtin type. The reply type will be used to provide a response and must be a pointer to an exported or builtin type. Otherwise a panic will occurr.

If dest is empty ("") or matches the Client's host ID, it will attempt to use the local configured Server when possible.

func (*Client) CallContext

func (c *Client) CallContext(
	ctx context.Context,
	dest peer.ID,
	svcName, svcMethod string,
	args, reply interface{},
) error

CallContext performs an RPC call to a registered Server service and blocks until completed, returning any errors. It takes a context which can be used to abort the call at any point.

The args parameter represents the service's method args and must be of exported or builtin type. The reply type will be used to provide a response and must be a pointer to an exported or builtin type. Otherwise a panic will occurr.

If dest is empty ("") or matches the Client's host ID, it will attempt to use the local configured Server when possible.

func (*Client) Go

func (c *Client) Go(
	dest peer.ID,
	svcName, svcMethod string,
	args, reply interface{},
	done chan *Call,
) error

Go performs an RPC call asynchronously. The associated Call will be placed in the provided channel upon completion, holding any Reply or Errors.

The args parameter represents the service's method args and must be of exported or builtin type. The reply type will be used to provide a response and must be a pointer to an exported or builtin type. Otherwise a panic will occurr.

The provided done channel must be nil, or have capacity for 1 element at least, or a panic will be triggered.

If dest is empty ("") or matches the Client's host ID, it will attempt to use the local configured Server when possible.

func (*Client) GoContext

func (c *Client) GoContext(
	ctx context.Context,
	dest peer.ID,
	svcName, svcMethod string,
	args, reply interface{},
	done chan *Call,
) error

GoContext performs an RPC call asynchronously. The provided context can be used to cancel the operation. The associated Call will be placed in the provided channel upon completion, holding any Reply or Errors.

The args parameter represents the service's method args and must be of exported or builtin type. The reply type will be used to provide a response and must be a pointer to an exported or builtin type. Otherwise a panic will occurr.

The provided done channel must be nil, or have capacity for 1 element at least, or a panic will be triggered.

If dest is empty ("") or matches the Client's host ID, it will attempt to use the local configured Server when possible.

func (*Client) ID

func (c *Client) ID() peer.ID

ID returns the peer.ID of the host associated with this client.

func (*Client) MultiCall

func (c *Client) MultiCall(
	ctxs []context.Context,
	dests []peer.ID,
	svcName, svcMethod string,
	args interface{},
	replies []interface{},
) []error

MultiCall performs a CallContext() to multiple destinations, using the same service name, method and arguments. It will not return until all calls have done so. The contexts, destinations and replies must match in length and will be used in order (ctxs[i] is used for dests[i] which obtains replies[i] and error[i]).

The calls will be triggered in parallel (with one goroutine for each).

func (*Client) MultiGo

func (c *Client) MultiGo(
	ctxs []context.Context,
	dests []peer.ID,
	svcName, svcMethod string,
	args interface{},
	replies []interface{},
	dones []chan *Call,
) error

MultiGo performs a GoContext() call to multiple destinations, using the same service name, method and arguments. MultiGo will return as right after performing all the calls. See the Go() documentation for more information.

The provided done channels must be nil, or have capacity for 1 element at least, or a panic will be triggered.

The contexts, destinations, replies and done channels must match in length and will be used in order (ctxs[i] is used for dests[i] which obtains replies[i] with dones[i] signalled upon completion).

func (*Client) MultiStream added in v0.2.0

func (c *Client) MultiStream(
	ctx context.Context,
	dests []peer.ID,
	svcName, svcMethod string,
	argsChan interface{},
	repliesChan interface{},
) []error

MultiStream performs parallel Stream() calls to multiple peers using a single arguments channel for arguments and a single replies channel that aggregates all replies. Errors from each destination are provided in the response. Channel types should be exported or builtin, otherwise a panic will be triggered.

In order to replicate the argsChan values to several destinations and sed the replies into a single channel, intermediary channels for each call are created. These channels are buffered per the WithMultiStreamBufferSize() option. If the buffers is exausted for one of the sending or the receiving channels, the sending or receiving stalls. Therefore it is recommended to have enough buffering to allow that slower destinations do not delay everyone else.

func (*Client) Stream added in v0.2.0

func (c *Client) Stream(
	ctx context.Context,
	dest peer.ID,
	svcName, svcMethod string,
	argsChan interface{},
	repliesChan interface{},
) error

Stream performs a streaming RPC call. It receives two arguments which both must be channels of exported or builtin types. The first is a channel from which objects are read and sent on the wire. The second is a channel to receive the replies from. Calling with the wrong types will cause a panic.

The sending channel should be closed by the caller for successful completion of the call. The replies channel is closed by us when there is nothing else to receive (call finished or an error happened). The sending channel is drained in the background in case of error, so it is recommended that senders diligently close when an error happens to be able to free resources.

The function only returns when the operation is finished successful (both channels are closed) or when an error has occurred.

type ClientOption

type ClientOption func(*Client)

ClientOption allows for functional setting of options on a Client.

func WithClientStatsHandler

func WithClientStatsHandler(h stats.Handler) ClientOption

WithClientStatsHandler provides an implementation of stats.Handler to be used by the Client.

func WithMultiStreamBufferSize added in v0.2.0

func WithMultiStreamBufferSize(size int) ClientOption

WithMultiStreamBufferSize sets the channel sizes for multiStream calls. Reading from the argument channel will proceed as long as none of the destinations have filled their buffer. See MultiStream().

type ContextKey added in v0.1.3

type ContextKey string

ContextKey is special type for using as a key with context.Context

type ErrorType added in v0.2.0

type ErrorType int

ErrorType is an enum type for providing error type information over the wire between rpc server and client.

const (
	// NonRPCErr is an error that hasn't arisen from the gorpc package.
	NonRPCErr ErrorType = iota
	// ServerErr is an error that has arisen on the server side.
	ServerErr
	// ClientErr is an error that has arisen on the client side.
	ClientErr
	// AuthorizationErr is an error that has arisen because client doesn't
	// have permissions to make the given rpc request
	AuthorizationErr
)

type Response

type Response struct {
	Service ServiceID   `codec:",omitempty"`
	Error   string      `codec:",omitempty"` // error, if any.
	ErrType ErrorType   `codec:",omitempty"`
	Data    interface{} `codec:"-"` // Response data
}

Response wraps all elements necessary to reply to a call: Service ID, Error and data. Responses are written to the wire in two steps. First the response object (without the data), then the data object. In streaming calls, each reply object is prepended by a Response object, which should be fully empty unless there is an error.

type Server

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

Server is an LibP2P RPC server. It can register services which comply to the limitations outlined in the package description and it will call the relevant methods when receiving requests from a Client.

A server needs a LibP2P host and a protocol, which must match the one used by the client. The LibP2P host must be already correctly configured to be able to handle connections from clients.

func NewServer

func NewServer(h host.Host, p protocol.ID, opts ...ServerOption) *Server

NewServer creates a Server object with the given LibP2P host and protocol.

func (*Server) ID

func (server *Server) ID() peer.ID

ID returns the peer.ID of the host associated with this server.

func (*Server) Register

func (server *Server) Register(rcvr interface{}) error

Register publishes in the server the set of methods of the receiver value that satisfy the following conditions:

  • exported method of exported type
  • context as first argument
  • input as second argument: exported type or channel of exported type
  • output as third argument: a pointer to a exported type, or a channel of exported type
  • one return value, of type error.

It returns an error if the receiver is not an exported type or has no suitable methods. It also logs the error using package log. The client accesses each method using a string of the form "Type.Method", where Type is the receiver's concrete type.

func (*Server) RegisterName

func (server *Server) RegisterName(name string, rcvr interface{}) error

RegisterName is like Register but uses the provided name for the type instead of the receiver's concrete type.

type ServerOption

type ServerOption func(*Server)

ServerOption allows for functional setting of options on a Server.

func WithAuthorizeFunc

func WithAuthorizeFunc(a func(pid peer.ID, name string, method string) bool) ServerOption

WithAuthorizeFunc adds authorization strategy(A function defining whether the given peer id is allowed to access given method of the given service) to the server using given authorization function.

func WithServerStatsHandler

func WithServerStatsHandler(h stats.Handler) ServerOption

WithServerStatsHandler providers a implementation of stats.Handler to be used by the Server.

func WithStreamBufferSize added in v0.2.0

func WithStreamBufferSize(size int) ServerOption

WithStreamBufferSize sets the channel buffer size for streaming requests.

type ServiceID

type ServiceID struct {
	Name   string
	Method string
}

ServiceID is a header sent when performing an RPC request which identifies the service and method being called.

func (ServiceID) String added in v0.2.0

func (svcID ServiceID) String() string

String concatenates ServiceID name and method.

Directories

Path Synopsis
examples

Jump to

Keyboard shortcuts

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