control

package
v1.0.0 Latest Latest
Warning

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

Go to latest
Published: Apr 15, 2019 License: MIT Imports: 13 Imported by: 0

Documentation

Overview

Package control provides an implementation of a simple network protocol that offers a RPC-like request/response mechanism between two peers.

Each peer can register functions on his control that the remote peer can then call, either synchronously with a response, or asynchronously. Making calls is possible by using the Call- methods defined in this package.

A Control must be created once. Then it is advised to register all possible requests on it. If the configuration is done, the Ready() method must be called on it to start the routine that accepts incoming requests.

Network Data Format

Control uses the packet package (https://github.com/desertbit/orbit/packet) to send and receive data over the connection.

Encoding

Each packet's header is automatically encoded with the msgpack.Codec (https://github.com/desertbit/orbit/codec/msgpack). The payloads are encoded with the codec.Codec defined in its configuration file. In case the payload is already a slice of bytes, the encoding is skipped.

Hooks

The Control offers a call- and an errorHook. These are useful for logging purposes and similar tasks. Check out their documentation for further information on when exactly they are called.

Error Handling

On the 'server' side, each handler function registered to handle a certain request may return an error that satisfies the control.Error interface, to specifically determine, what the client receives as message and to specify error codes the client can react to.

On the 'client' side, the Call- functions return (beside the usual errors that can happen) the ErrorCode struct that satisfies the standard error interface, but contains in addition the error code the server can set to indicate certain errors. Clients should therefore always check, whether the returned error is of type ErrorCode, to handle certain errors appropriately.

Note: The MaxMessageSize that can be configured in the Config is a hard limit for the read routine of the respective peer that receives a message. Every request that exceeds this configured limit and sends the request anyways causes the connection to be closed and dropped. This is done on purpose, as allowing peers to send huge payloads can result in a DoS. Therefore, the peer that wants to make a call is required to check beforehand how big its request may be.

Index

Constants

This section is empty.

Variables

View Source
var (
	// ErrClosed defines the error if the socket connection is closed.
	ErrClosed = errors.New("socket closed")

	// ErrCallTimeout defines the error if the call timeout is reached.
	ErrCallTimeout = errors.New("call timeout")

	// ErrWriteTimeout defines the error if a write operation's timeout is reached.
	ErrWriteTimeout = errors.New("write timeout")
)
View Source
var (
	// ErrNoContextData defines the error if no context data is available.
	ErrNoContextData = errors.New("no context data available to decode")
)

Functions

This section is empty.

Types

type CallHook

type CallHook func(c *Control, funcID string, ctx *Context)

The CallHook type defines the callback function that is executed for every Func called by the remote peer.

type Config

type Config struct {
	// The codec.Codec that should be used to encode the payload of messages.
	Codec codec.Codec

	// The log.logger to be used for writing log messages to.
	Logger *log.Logger

	// The max size in bytes a message may have that is sent over the stream.
	MaxMessageSize int

	// The maximum time a call may take to finish.
	CallTimeout time.Duration
	// The maximum time it may take to read a packet from the stream.
	ReadTimeout time.Duration
	// The maximum time it may take to write a packet to the stream.
	WriteTimeout time.Duration

	// A flag that controls whether we sent errors that occur during the
	// handling of calls back to the caller.
	// Be cautious, in case you set this to true, as errors may contain
	// critical information about your app, most often useful for attackers.
	SendErrToCaller bool
}

The Config type contains the possible configuration parameter of a Control.

type Context

type Context struct {
	// Data is the raw byte representation of the encoded context data.
	Data []byte
	// contains filtered or unexported fields
}

The Context type is a wrapper around the raw payload data of calls. It offer a convenience method to decode the encoded data into an interface.

func (*Context) Control

func (c *Context) Control() *Control

Control returns the control of the context.

func (*Context) Decode

func (c *Context) Decode(v interface{}) error

Decode the context data to a custom value. The value has to be passed as pointer. Returns ErrNoContextData, if there is no context data available to decode.

type Control

type Control struct {
	closer.Closer
	// contains filtered or unexported fields
}

The Control type is the main struct of this package that is used to implement RPC.

func New

func New(conn net.Conn, config *Config) *Control

New creates a new Control using the passed connection.

A config can be passed to manage the behaviour of the Control. Any value of the config that has not been set, a default value is provided. If a nil config is passed, a config with default values is created.

Ready() must be called on the Control to start its read routine, so it can accept incoming requests.

func (*Control) AddFunc

func (c *Control) AddFunc(id string, f Func)

AddFunc registers a local function that can be called by the remote peer. This method is thread-safe and may be called at any time.

func (*Control) AddFuncs

func (c *Control) AddFuncs(funcs Funcs)

AddFuncs registers a map of local functions that can be called by the remote peer. This method is thread-safe and may be called at any time.

func (*Control) Call

func (c *Control) Call(id string, data interface{}) (*Context, error)

Call is a convenience function that calls CallTimeout(), but uses the default CallTimeout from the config of the Control.

func (*Control) CallAsync

func (c *Control) CallAsync(
	id string,
	data interface{},
	callback func(ctx *Context, err error),
) error

CallAsync calls a remote function in an asynchronous fashion, as the response will be awaited in a new goroutine and passed to the given callback. It uses the default CallTimeout from the config of the Control.

This method is thread-safe.

func (*Control) CallAsyncTimeout added in v1.0.0

func (c *Control) CallAsyncTimeout(
	id string,
	data interface{},
	timeout time.Duration,
	callback func(ctx *Context, err error),
) error

CallAsync calls a remote function in an asynchronous fashion, as the response will be awaited in a new goroutine and passed to the given callback.

The response will be awaited in a new goroutine. The given callback will receive an ErrCallTimeout error, should the timeout be exceeded.

This method is thread-safe.

func (*Control) CallOneWay

func (c *Control) CallOneWay(id string, data interface{}) error

CallOneWay calls a remote function, but the remote peer will not send back a response and this func will immediately return, as soon as the data has been written to the connection.

This method is thread-safe.

func (*Control) CallTimeout added in v1.0.0

func (c *Control) CallTimeout(
	id string,
	data interface{},
	timeout time.Duration,
) (ctx *Context, err error)

CallTimeout calls a remote function and waits for its result. The given id determines, which function should be called on the remote. The given timeout determines how long the request/response process may take at a maximum.

The passed data are sent as payload of the request and get automatically encoded with the codec.Codec of the Control. If data is nil, no payload is sent. If data is a byte slice, the encoding is skipped.

This method blocks until the remote function sent back a response and returns the Context of this response. It is therefore considered 'synchronous'.

Returns ErrCallTimeout on a timeout. Returns ErrClosed if the connection is closed.

This method is thread-safe.

func (*Control) Codec

func (c *Control) Codec() codec.Codec

Codec returns the codec.Codec of the control's config.

func (*Control) LocalAddr

func (c *Control) LocalAddr() net.Addr

LocalAddr returns the local network address of the Control.

func (*Control) Logger

func (c *Control) Logger() *log.Logger

Logger returns the log.Logger of the control's config.

func (*Control) Ready

func (c *Control) Ready()

Ready signalizes the Control that the initialization is done. The socket starts reading from the underlying connection. This should be called only once per Control.

func (*Control) RemoteAddr

func (c *Control) RemoteAddr() net.Addr

RemoteAddr returns the remote network address of the peer the Control is connected to.

func (*Control) SetCallHook

func (c *Control) SetCallHook(h CallHook)

SetCallHook sets the call hook function which is triggered, if a local remote callable function will be called. This hook can be used for logging purpose. Only set this hook during initialization (before Ready() has been called).

func (*Control) SetErrorHook

func (c *Control) SetErrorHook(h ErrorHook)

SetErrorHook sets the error hook function which is triggered, if a local remote callable function returns an error. This hook can be used for logging purpose. Only set this hook during initialization (before Ready() has been called).

type Error

type Error interface {
	// Embeds the standard go error interface.
	error

	// Msg returns a textual explanation of the error and should
	// NOT contain sensitive information about the application.
	Msg() string

	// Code returns an integer that can give a hint about the
	// type of error that occurred.
	Code() int
}

An Error offers a way for handler functions of control calls to determine the information passed to the client, in case an error occurs. That way, sensitive information that may be contained in a standard error, can be hidden from the client. Instead, a Msg and a code can be sent back to give a non-sensitive explanation of the error and a code that is easy to check, to allow handling common errors.

func Err

func Err(err error, msg string, code int) Error

Err constructs and returns a type that satisfies the control.Error interface from the given parameters.

type ErrorCode

type ErrorCode struct {
	// The code is used to identify common errors.
	Code int
	// contains filtered or unexported fields
}

The ErrorCode type extends the standard go error by a simple integer code. It is returned in the Call- functions of this package and allows callers that use them to check for common errors via the code.

func (ErrorCode) Error

func (e ErrorCode) Error() string

Implements the error interface.

type ErrorHook

type ErrorHook func(c *Control, funcID string, err error)

The ErrorHook type defines the error callback function that is executed for every Func calley by the remote peer, that produces an error.

type Func

type Func func(ctx *Context) (data interface{}, err error)

The Func type defines a callable Control function. If the returned error is not nil and implements the Error interface of this package, the clients can react to predefined error codes and act accordingly.

type Funcs

type Funcs map[string]Func

The Funcs type defines a set of callable Control functions.

Jump to

Keyboard shortcuts

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