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/pkg/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/pkg/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, but this is taken care of already in the implementation, so if you use one of the Call() methods, the size is checked before attempting to send everything to the remote peer.
Index ¶
- Variables
- type CallHook
- type Config
- type Context
- type Control
- func (c *Control) AddFunc(id string, f Func)
- func (c *Control) AddFuncs(funcs Funcs)
- func (c *Control) Call(id string, data interface{}) (*Context, error)
- func (c *Control) CallAsync(id string, data interface{}, callback func(ctx *Context, err error)) error
- func (c *Control) CallAsyncOpts(id string, data interface{}, timeout time.Duration, ...) error
- func (c *Control) CallOneWay(id string, data interface{}) error
- func (c *Control) CallOpts(id string, data interface{}, timeout time.Duration, cancelChan <-chan struct{}) (ctx *Context, err error)
- func (c *Control) Codec() codec.Codec
- func (c *Control) LocalAddr() net.Addr
- func (c *Control) Logger() *log.Logger
- func (c *Control) Ready()
- func (c *Control) RemoteAddr() net.Addr
- func (c *Control) SetCallHook(h CallHook)
- func (c *Control) SetErrorHook(h ErrorHook)
- type Error
- type ErrorCode
- type ErrorHook
- type Func
- type Funcs
Constants ¶
This section is empty.
Variables ¶
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") // ErrCallCanceled defines the error if the call has been canceled. ErrCallCanceled = errors.New("call canceled") // ErrWriteTimeout defines the error if a write operation's timeout is reached. ErrWriteTimeout = errors.New("write timeout") )
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 ¶
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 offers a convenience method to decode the encoded data into an interface and contains a closer that can be used to cancel the ongoing associated request.
func (*Context) CancelChan ¶
func (c *Context) CancelChan() <-chan struct{}
CancelChan returns the cancel channel of the context. It can be used to detect whether a context has been canceled. Attention: Since the caller of a remote call can decide, whether his call is cancelable or not, the cancel channel of the context may be nil! Users of this method should never read directly from this channel, but rather use a select clause.
type Control ¶
The Control type is the main struct of this package that is used to implement RPC.
func New ¶
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 ¶
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 ¶
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 ¶
Call is a convenience function that calls CallOpts(), but uses the default timeout from the config of the Control and does not provide a cancel channel.
This call can not be canceled, use CallOpts() for this instead.
Returns ErrClosed, if the control is closed. Returns ErrCallTimeout, if the timeout is exceeded.
This method is thread-safe.
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 CallAsyncOpts from the config of the Control.
The given callback will receive: ErrClosed error, should the control close. ErrCallTimeout error, should the timeout be exceeded.
This method is thread-safe.
func (*Control) CallAsyncOpts ¶
func (c *Control) CallAsyncOpts( id string, data interface{}, timeout time.Duration, callback func(ctx *Context, err error), cancelChan <-chan struct{}, ) error
CallAsyncOpts calls a remote function in an asynchronous fashion, as the response will be awaited in a new goroutine and passed to the given callback. Like with CallOpts(), the request is aborted after the timeout has been exceeded or the cancel channel has read a value.
The given callback will receive: ErrClosed error, should the control close. ErrCallTimeout error, should the timeout be exceeded. ErrCallCanceled error, should the call get canceled.
This method is thread-safe.
func (*Control) CallOneWay ¶
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 call can not be canceled, use CallAsyncOpts() for this instead.
This method is thread-safe.
func (*Control) CallOpts ¶
func (c *Control) CallOpts( id string, data interface{}, timeout time.Duration, cancelChan <-chan struct{}, ) (ctx *Context, err error)
CallOpts 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 given cancel channel can be used to abort the ongoing request. The channel is read from exactly once at 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 ErrClosed, if the control is closed. Returns ErrCallTimeout, if the timeout is exceeded. Returns ErrCallCanceled, if the caller cancels the call.
This method is thread-safe.
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 ¶
RemoteAddr returns the remote network address of the peer the Control is connected to.
func (*Control) SetCallHook ¶
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 ¶
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.
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.
type ErrorHook ¶
The ErrorHook type defines the error callback function that is executed for every Func calley by the remote peer, that produces an error.