execrpc

package module
v0.7.0 Latest Latest
Warning

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

Go to latest
Published: Aug 20, 2022 License: MIT Imports: 16 Imported by: 11

README

Tests on Linux, MacOS and Windows Go Report Card GoDoc

This library implements a simple, custom RPC protocol via os/exex and stdin and stdout. Both server and client comes in a raw ([]byte) and strongly typed variant (using Go generics).

A strongly typed client may look like this:

client, err := execrpc.StartClient(
		execrpc.ClientOptions[model.ExampleRequest, model.ExampleResponse]{
			ClientRawOptions: execrpc.ClientRawOptions{
				Version: 1,
				Cmd:     "go",
				Dir:  "./examples/servers/typed"
				Args:    []string{"run", "."},
			},
			Codec: codecs.JSONCodec[model.ExampleRequest, model.ExampleResponse]{},
		},
	)

result, _ := client.Execute(model.ExampleRequest{Text: "world"})

fmt.Println(result.Hello)

//...

client.Close()

To get the best performance you should keep the client open as long as its needed – and store it as a shared object; it's safe and encouraged to call Execute from multiple goroutines.

And the server side of the above:

func main() {
	server, _ := execrpc.NewServer(
		execrpc.ServerOptions[model.ExampleRequest, model.ExampleResponse]{
			Call: func(d execrpc.Dispatcher, req model.ExampleRequest) model.ExampleResponse {
				return model.ExampleResponse{
					Hello: "Hello " + req.Text + "!",
				}
			},
		},
	)
	if err := server.Start(); err != nil {
		// ... handle error
	}
	_ = server.Wait()
}

Of the included codecs, JSON seems to win by a small margin (but only tested with small requests/responses):

name            time/op
Client/JSON-10  4.89µs ± 0%
Client/TOML-10  5.51µs ± 0%
Client/Gob-10   17.0µs ± 0%

name            alloc/op
Client/JSON-10    922B ± 0%
Client/TOML-10  1.67kB ± 0%
Client/Gob-10   9.22kB ± 0%

name            allocs/op
Client/JSON-10    19.0 ± 0%
Client/TOML-10    28.0 ± 0%
Client/Gob-10      227 ± 0%

Status Codes

The status codes in the header between 1 and 99 are reserved for the system. This will typically be used to catch decoding/encoding errors on the server.

Documentation

Index

Constants

View Source
const (
	// MessageStatusOK is the status code for a successful message.
	MessageStatusOK = iota
	// MessageStatusErrDecodeFailed is the status code for a message that failed to decode.
	MessageStatusErrDecodeFailed
	// MessageStatusErrEncodeFailed is the status code for a message that failed to encode.
	MessageStatusErrEncodeFailed

	// MessageStatusSystemReservedMax is the maximum value for a system reserved status code.
	MessageStatusSystemReservedMax = 99
)

Variables

View Source
var ErrShutdown = errors.New("connection is shut down")

ErrShutdown will be returned from Execute and Close if the client is or is about to be shut down.

View Source
var ErrTimeoutWaitingForServer = errors.New("timed out waiting for server to start")

ErrTimeoutWaitingForServer is returned on timeouts starting the server.

Functions

This section is empty.

Types

type Client

type Client[Q, R any] struct {
	// contains filtered or unexported fields
}

Client is a strongly typed RPC client.

func StartClient

func StartClient[Q, R any](opts ClientOptions[Q, R]) (*Client[Q, R], error)

StartClient starts a client for the given options.

func (*Client[Q, R]) Close

func (c *Client[Q, R]) Close() error

Close closes the client.

func (*Client[Q, R]) Execute

func (c *Client[Q, R]) Execute(r Q) (R, error)

Execute encodes and sends r the server and returns the response object. It's safe to call Execute from multiple goroutines.

type ClientOptions

type ClientOptions[Q, R any] struct {
	ClientRawOptions
	Codec codecs.Codec[Q, R]
}

ClientOptions are options for the client.

type ClientRaw

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

ClientRaw is a raw RPC client. Raw means that the client doesn't do any type conversion, a byte slice is what you get.

func StartClientRaw

func StartClientRaw(opts ClientRawOptions) (*ClientRaw, error)

StartClientRaw starts a untyped client client for the given options.

func (*ClientRaw) Close

func (c *ClientRaw) Close() error

Close closes the server connection and waits for the server process to quit.

func (*ClientRaw) Execute

func (c *ClientRaw) Execute(body []byte) (Message, error)

Execute sends body to the server and returns the Message it receives. It's safe to call Execute from multiple goroutines.

type ClientRawOptions

type ClientRawOptions struct {
	// Version number passed to the server.
	Version uint16

	// The server to start.
	Cmd string

	// The arguments to pass to the command.
	Args []string

	// Environment variables to pass to the command.
	// These will be merged with the environment variables of the current process,
	// vallues in this slice have precedence.
	// A slice of strings of the form "key=value"
	Env []string

	// Dir specifies the working directory of the command.
	// If Dir is the empty string, the command runs in the
	// calling process's current directory.
	Dir string

	// Callback for messages received from server without an ID (e.g. log message).
	OnMessage func(Message)

	// The timeout for the client.
	Timeout time.Duration
}

ClientRawOptions are options for the raw part of the client.

type Dispatcher

type Dispatcher interface {
	// Send sends one or more message back to the client.
	// This is normally used for log messages and similar,
	// and these messages should have a zero (0) ID.
	Send(...Message) error
}

Dispatcher is the interface for dispatching standalone messages to the client, e.g. log messages.

type Header struct {
	ID      uint32
	Version uint16
	Status  uint16
	Size    uint32
}

Header is the header of a message. ID and Size are set by the system.

func (*Header) Read

func (h *Header) Read(r io.Reader) error

Read reads the header from the reader.

func (Header) Write

func (h Header) Write(w io.Writer) error

Write writes the header to the writer.

type Message

type Message struct {
	Header Header
	Body   []byte
}

Message is what gets sent to and from the server.

func (*Message) Read

func (m *Message) Read(r io.Reader) error

func (*Message) Write

func (m *Message) Write(w io.Writer) error

type Server

type Server[Q, R any] struct {
	*ServerRaw
}

Server is a stringly typed server for requests of type Q and responses of tye R.

func NewServer

func NewServer[Q, R any](opts ServerOptions[Q, R]) (*Server[Q, R], error)

NewServer creates a new Server. using the given options.

type ServerOptions

type ServerOptions[Q, R any] struct {
	// Call is the function that will be called when a request is received.
	Call func(Dispatcher, Q) R

	// Codec is the codec that will be used to encode and decode requests and responses.
	// The client will tell the server what codec is in use, so in most cases you should just leave this unset.
	Codec codecs.Codec[R, Q]
}

ServerOptions is the options for a server.

type ServerRaw

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

ServerRaw is a RPC server handling raw messages with a header and []byte body. See Server for a generic, typed version.

func NewServerRaw

func NewServerRaw(opts ServerRawOptions) (*ServerRaw, error)

NewServerRaw creates a new Server using the given options.

func (*ServerRaw) Start

func (s *ServerRaw) Start() error

Start sets upt the server communication and starts the server loop. It's safe to call Start multiple times, but only the first call will start the server.

func (*ServerRaw) Wait

func (s *ServerRaw) Wait() error

Wait waits for the server to stop. This happens when it gets disconnected from the client.

type ServerRawOptions

type ServerRawOptions struct {
	// Call is the message exhcange between the client and server.
	// Note that any error returned by this function will be treated as a fatal error and the server is stopped.
	// Validation errors etc. should be returned in the response message.
	// The Dispatcher can be used to send messages to the client outside of the request/response loop, e.g. log messages.
	// Note that these messages must have ID 0.
	Call func(Dispatcher, Message) (Message, error)
}

ServerRawOptions is the options for a raw portion of the server.

Directories

Path Synopsis
examples
servers/raw module
servers/typed module

Jump to

Keyboard shortcuts

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