Documentation ¶
Overview ¶
Package frisbee is the core package for using the frisbee messaging framework. The frisbee framework is a messaging framework designed around the aspect of "bring your own protocol", and can be used by simply defining your packet types and their accompanying logic.
This package provides methods for defining packet types and logic, as well as functionality for implementing frisbee servers and clients. Useful features like automatic heartbeats and automatic reconnections are provided as well.
In depth documentation and examples can be found at https://loopholelabs.io/docs/frisbee
An Echo Example ¶
As a starting point, a very basic echo server:
package main import ( "github.com/loopholelabs/frisbee" "github.com/loopholelabs/frisbee/pkg/packet" "github.com/rs/zerolog/log" "os" "os/signal" ) const PING = uint16(10) const PONG = uint16(11) func handlePing(_ *frisbee.Async, incoming *packet.Packet) (outgoing *packet.Packet, action frisbee.Action) { if incoming.Metadata.ContentLength > 0 { log.Printf("Server Received Metadata: %s\n", incoming.Content) incoming.Metadata.Operation = PONG outgoing = incoming } return } func main() { handlerTable := make(frisbee.ServerRouter) handlerTable[PING] = handlePing exit := make(chan os.Signal) signal.Notify(exit, os.Interrupt) s := frisbee.NewServer(":8192", handlerTable, 0) err := s.Start() if err != nil { panic(err) } <-exit err = s.Shutdown() if err != nil { panic(err) } }
And an accompanying echo client:
package main import ( "fmt" "github.com/loopholelabs/frisbee" "github.com/loopholelabs/frisbee/pkg/packet" "github.com/rs/zerolog/log" "os" "os/signal" "time" ) const PING = uint16(10) const PONG = uint16(11) func handlePong(incoming *packet.Packet) (outgoing *packet.Packet, action frisbee.Action) { if incoming.Metadata.ContentLength > 0 { log.Printf("Client Received Metadata: %s\n", incoming.Content) } return } func main() { handlerTable := make(frisbee.ClientRouter) handlerTable[PONG] = handlePong exit := make(chan os.Signal) signal.Notify(exit, os.Interrupt) c, err := frisbee.NewClient("127.0.0.1:8192", handlerTable) if err != nil { panic(err) } err = c.ConnectAsync() if err != nil { panic(err) } go func() { i := 0 p := packet.Get() p.Metadata.Operation = PING for { p.Write([]byte(fmt.Sprintf("ECHO MESSAGE: %d", i))) p.Metadata.ContentLength = uint32(len(p.Content)) err := c.WritePacket(p) if err != nil { panic(err) } i++ time.Sleep(time.Second) } }() <-exit err = c.Close() if err != nil { panic(err) } }
(Examples taken from https://github.com/loopholelabs/frisbee-examples/)
This example is a simple echo client/server, where the client will repeatedly send packets to the server, and the server will echo them back. Its purpose is to describe the flow of packets from Frisbee Client to Server, as well as give an example of how a Frisbee application must be implemented.
Index ¶
- Constants
- Variables
- type Action
- type Async
- func (c *Async) Close() error
- func (c *Async) CloseChannel() <-chan struct{}
- func (c *Async) Closed() bool
- func (c *Async) ConnectionState() (tls.ConnectionState, error)
- func (c *Async) Context() (ctx context.Context)
- func (c *Async) Error() error
- func (c *Async) Flush() error
- func (c *Async) Handshake() error
- func (c *Async) HandshakeContext(ctx context.Context) error
- func (c *Async) LocalAddr() net.Addr
- func (c *Async) Logger() *zerolog.Logger
- func (c *Async) Raw() net.Conn
- func (c *Async) ReadPacket() (*packet.Packet, error)
- func (c *Async) RemoteAddr() net.Addr
- func (c *Async) SetContext(ctx context.Context)
- func (c *Async) SetDeadline(t time.Time) error
- func (c *Async) SetReadDeadline(t time.Time) error
- func (c *Async) SetWriteDeadline(t time.Time) error
- func (c *Async) WriteBufferSize() int
- func (c *Async) WritePacket(p *packet.Packet) error
- type Client
- func (c *Client) Close() error
- func (c *Client) CloseChannel() <-chan struct{}
- func (c *Client) Closed() bool
- func (c *Client) Connect(addr string) error
- func (c *Client) Error() error
- func (c *Client) Flush() error
- func (c *Client) FromConn(conn net.Conn) error
- func (c *Client) Logger() *zerolog.Logger
- func (c *Client) Raw() (net.Conn, error)
- func (c *Client) WritePacket(p *packet.Packet) error
- type Conn
- type Handler
- type HandlerTable
- type Option
- type Options
- type Server
- func (s *Server) Logger() *zerolog.Logger
- func (s *Server) ServeConn(newConn net.Conn)
- func (s *Server) SetBaseContext(f func() context.Context) error
- func (s *Server) SetOnClosed(f func(*Async, error)) error
- func (s *Server) SetPreWrite(f func()) error
- func (s *Server) Shutdown() error
- func (s *Server) Start(addr string) error
- type Sync
- func (c *Sync) Close() error
- func (c *Sync) ConnectionState() (tls.ConnectionState, error)
- func (c *Sync) Context() (ctx context.Context)
- func (c *Sync) Error() error
- func (c *Sync) Handshake() error
- func (c *Sync) HandshakeContext(ctx context.Context) error
- func (c *Sync) LocalAddr() net.Addr
- func (c *Sync) Logger() *zerolog.Logger
- func (c *Sync) Raw() net.Conn
- func (c *Sync) ReadPacket() (*packet.Packet, error)
- func (c *Sync) RemoteAddr() net.Addr
- func (c *Sync) SetContext(ctx context.Context)
- func (c *Sync) SetDeadline(t time.Time) error
- func (c *Sync) SetReadDeadline(t time.Time) error
- func (c *Sync) SetWriteDeadline(t time.Time) error
- func (c *Sync) WritePacket(p *packet.Packet) error
Examples ¶
Constants ¶
const ( // NONE is used to do nothing (default) NONE = Action(iota) // UPDATE is used to trigger an UpdateContext call on the Server or Client UPDATE // CLOSE is used to close the frisbee connection CLOSE )
These are various frisbee actions, used to modify the state of the client or server from a Handler function:
const ( // HEARTBEAT is used to send heartbeats from the client to the server (and measure round trip time) HEARTBEAT = uint16(iota) // PING is used to check if a client is still alive PING // PONG is used to respond to a PING packets PONG RESERVED3 RESERVED4 RESERVED5 RESERVED6 RESERVED7 RESERVED8 RESERVED9 )
These are internal reserved packet types, and are the reason you cannot use 0-9 in Handler functions:
const DefaultBufferSize = 1 << 16
DefaultBufferSize is the size of the default buffer
Variables ¶
var ( InvalidContentLength = errors.New("invalid content length") ConnectionClosed = errors.New("connection closed") ConnectionNotInitialized = errors.New("connection not initialized") InvalidBufferLength = errors.New("invalid buffer length") InvalidHandlerTable = errors.New("invalid handlePacket table configuration, a reserved value may have been used") )
These are various frisbee errors that can be returned by the client or server:
var ( // HEARTBEATPacket is a pre-allocated Frisbee Packet for HEARTBEAT Packets HEARTBEATPacket = &packet.Packet{ Metadata: &metadata.Metadata{ Operation: HEARTBEAT, }, Content: content.New(), } // PINGPacket is a pre-allocated Frisbee Packet for PING Packets PINGPacket = &packet.Packet{ Metadata: &metadata.Metadata{ Operation: PING, }, Content: content.New(), } // PONGPacket is a pre-allocated Frisbee Packet for PONG Packets PONGPacket = &packet.Packet{ Metadata: &metadata.Metadata{ Operation: PONG, }, Content: content.New(), } )
var ( BaseContextNil = errors.New("BaseContext cannot be nil") OnClosedNil = errors.New("OnClosed cannot be nil") PreWriteNil = errors.New("PreWrite cannot be nil") )
var DefaultLogger = zerolog.New(ioutil.Discard)
DefaultLogger is the default logger used within frisbee
var (
NotTLSConnectionError = errors.New("connection is not of type *tls.Conn")
)
Functions ¶
This section is empty.
Types ¶
type Action ¶
type Action int
Action is an ENUM used to modify the state of the client or server from a Handler function
NONE: used to do nothing (default) CLOSE: close the frisbee connection SHUTDOWN: shutdown the frisbee client or server
type Async ¶
Async is the underlying asynchronous frisbee connection which has extremely efficient read and write logic and can handle the specific frisbee requirements. This is not meant to be used on its own, and instead is meant to be used by frisbee client and server implementations
func ConnectAsync ¶
func ConnectAsync(addr string, keepAlive time.Duration, logger *zerolog.Logger, TLSConfig *tls.Config) (*Async, error)
ConnectAsync creates a new TCP connection (using net.Dial) and wraps it in a frisbee connection
func (*Async) CloseChannel ¶ added in v0.1.6
func (c *Async) CloseChannel() <-chan struct{}
CloseChannel returns a channel that can be listened to for a close event on a frisbee connection
func (*Async) Closed ¶ added in v0.1.6
Closed returns whether the frisbee.Async connection is closed
func (*Async) ConnectionState ¶
func (c *Async) ConnectionState() (tls.ConnectionState, error)
ConnectionState returns the tls.ConnectionState of a *tls.Conn if the connection is not *tls.Conn then the NotTLSConnectionError is returned
func (*Async) Flush ¶
Flush allows for synchronous messaging by flushing the write buffer and instantly sending packets
func (*Async) Handshake ¶ added in v0.2.1
Handshake performs the tls.Handshake() of a *tls.Conn if the connection is not *tls.Conn then the NotTLSConnectionError is returned
func (*Async) HandshakeContext ¶ added in v0.2.1
HandshakeContext performs the tls.HandshakeContext() of a *tls.Conn if the connection is not *tls.Conn then the NotTLSConnectionError is returned
func (*Async) Raw ¶
Raw shuts off all of frisbee's underlying functionality and converts the frisbee connection into a normal TCP connection (net.Conn)
func (*Async) ReadPacket ¶ added in v0.2.0
ReadPacket is a blocking function that will wait until a Frisbee packet is available and then return it (and its content). In the event that the connection is closed, ReadPacket will return an error.
func (*Async) RemoteAddr ¶
RemoteAddr returns the remote address of the underlying net.Conn
func (*Async) SetContext ¶ added in v0.2.4
SetContext allows users to save a context within a connection
func (*Async) SetDeadline ¶
SetDeadline sets the read and write deadline on the underlying net.Conn
func (*Async) SetReadDeadline ¶
SetReadDeadline sets the read deadline on the underlying net.Conn
func (*Async) SetWriteDeadline ¶
SetWriteDeadline sets the write deadline on the underlying net.Conn
func (*Async) WriteBufferSize ¶
WriteBufferSize returns the size of the underlying write buffer (used for internal packet handling and for heartbeat logic)
func (*Async) WritePacket ¶ added in v0.2.0
WritePacket takes a packet.Packet and queues it up to send asynchronously.
If packet.Metadata.ContentLength == 0, then the content array must be nil. Otherwise, it is required that packet.Metadata.ContentLength == len(content).
type Client ¶
type Client struct { // PacketContext is used to define packet-specific contexts based on the incoming packet // and is run whenever a new packet arrives PacketContext func(context.Context, *packet.Packet) context.Context // UpdateContext is used to update a handler-specific context whenever the returned // Action from a handler is UPDATE UpdateContext func(context.Context, *Async) context.Context // contains filtered or unexported fields }
Client connects to a frisbee Server and can send and receive frisbee packets
func NewClient ¶
NewClient returns an uninitialized frisbee Client with the registered ClientRouter. The ConnectAsync method must then be called to dial the server and initialize the connection.
Example ¶
package main import ( "context" "github.com/loopholelabs/frisbee" "github.com/loopholelabs/frisbee/pkg/packet" "github.com/rs/zerolog" "os" ) func main() { handlerTable := make(frisbee.HandlerTable) handlerTable[10] = func(ctx context.Context, incoming *packet.Packet) (outgoing *packet.Packet, action frisbee.Action) { return } logger := zerolog.New(os.Stdout) _, _ = frisbee.NewClient(handlerTable, context.Background(), frisbee.WithLogger(&logger)) }
Output:
func (*Client) CloseChannel ¶ added in v0.1.6
func (c *Client) CloseChannel() <-chan struct{}
CloseChannel returns a channel that can be listened to see if this client has been closed
func (*Client) Connect ¶
Connect actually connects to the given frisbee server, and starts the reactor goroutines to receive and handle incoming packets. If this function is called, FromConn should not be called.
func (*Client) Flush ¶ added in v0.1.6
Flush flushes any queued frisbee Packets from the client to the server
func (*Client) FromConn ¶ added in v0.4.0
FromConn takes a pre-existing connection to a Frisbee server and starts the reactor goroutines to receive and handle incoming packets. If this function is called, Connect should not be called.
type Conn ¶
type Conn interface { Close() error LocalAddr() net.Addr RemoteAddr() net.Addr ConnectionState() (tls.ConnectionState, error) Handshake() error HandshakeContext(context.Context) error SetDeadline(time.Time) error SetReadDeadline(time.Time) error SetWriteDeadline(time.Time) error WritePacket(*packet.Packet) error ReadPacket() (*packet.Packet, error) SetContext(context.Context) Context() context.Context Logger() *zerolog.Logger Error() error Raw() net.Conn }
type Handler ¶ added in v0.2.0
type Handler func(ctx context.Context, incoming *packet.Packet) (outgoing *packet.Packet, action Action)
Handler is the handler function called by frisbee for incoming packets of data, depending on the packet's Metadata.Operation field
type HandlerTable ¶ added in v0.2.0
HandlerTable is the lookup table for Frisbee handler functions - based on the Metadata.Operation field of a packet, Frisbee will look up the correct handler for that packet.
type Option ¶
type Option func(opts *Options)
Option is used to generate frisbee client and server options internally
func WithHeartbeat ¶
WithHeartbeat sets the minimum time between heartbeat packets. By default, packets are only sent if no packets have been sent since the last heartbeat packet - to change this behaviour you can disable heartbeats (by passing in -1), and implementing your own logic.
func WithKeepAlive ¶
WithKeepAlive allows users to define TCP keepalive options for the frisbee client or server (use -1 to disable)
func WithLogger ¶
WithLogger sets the logger for the frisbee client or server
func WithOptions ¶
WithOptions allows users to pass in an Options struct to configure a frisbee client or server
type Options ¶
type Options struct { KeepAlive time.Duration Heartbeat time.Duration Logger *zerolog.Logger TLSConfig *tls.Config }
Options is used to provide the frisbee client and server with configuration options.
Default Values:
options := Options { KeepAlive: time.Minute * 3, Logger: &DefaultLogger, Heartbeat: time.Second * 5, }
type Server ¶
type Server struct { // ConnContext is used to define a connection-specific context based on the incoming connection // and is run whenever a new connection is opened ConnContext func(context.Context, *Async) context.Context // PacketContext is used to define a handler-specific contexts based on the incoming packet // and is run whenever a new packet arrives PacketContext func(context.Context, *packet.Packet) context.Context // UpdateContext is used to update a handler-specific context whenever the returned // Action from a handler is UPDATE UpdateContext func(context.Context, *Async) context.Context // contains filtered or unexported fields }
Server accepts connections from frisbee Clients and can send and receive frisbee Packets
func NewServer ¶
func NewServer(handlerTable HandlerTable, opts ...Option) (*Server, error)
NewServer returns an uninitialized frisbee Server with the registered HandlerTable. The Start method must then be called to start the server and listen for connections.
Example ¶
package main import ( "context" "github.com/loopholelabs/frisbee" "github.com/loopholelabs/frisbee/pkg/packet" "github.com/rs/zerolog" "os" ) func main() { handlerTable := make(frisbee.HandlerTable) handlerTable[10] = func(ctx context.Context, incoming *packet.Packet) (outgoing *packet.Packet, action frisbee.Action) { return } logger := zerolog.New(os.Stdout) _, _ = frisbee.NewServer(handlerTable, frisbee.WithLogger(&logger)) }
Output:
func (*Server) ServeConn ¶ added in v0.4.0
ServeConn takes a TCP net.Conn and serves it using the Server
func (*Server) SetBaseContext ¶ added in v0.4.0
SetBaseContext sets the baseContext function for the server. If f is nil, it returns an error.
func (*Server) SetOnClosed ¶ added in v0.4.0
SetOnClosed sets the onClosed function for the server. If f is nil, it returns an error.
func (*Server) SetPreWrite ¶ added in v0.4.0
SetPreWrite sets the preWrite function for the server. If f is nil, it returns an error.
func (*Server) Shutdown ¶
Shutdown shuts down the frisbee server and kills all the goroutines and active connections
type Sync ¶
Sync is the underlying synchronous frisbee connection which has extremely efficient read and write logic and can handle the specific frisbee requirements. This is not meant to be used on its own, and instead is meant to be used by frisbee client and server implementations
func ConnectSync ¶
func ConnectSync(addr string, keepAlive time.Duration, logger *zerolog.Logger, TLSConfig *tls.Config) (*Sync, error)
ConnectSync creates a new TCP connection (using net.Dial) and wraps it in a frisbee connection
func (*Sync) ConnectionState ¶
func (c *Sync) ConnectionState() (tls.ConnectionState, error)
ConnectionState returns the tls.ConnectionState of a *tls.Conn if the connection is not *tls.Conn then the NotTLSConnectionError is returned
func (*Sync) Error ¶
Error returns the error that caused the frisbee.Sync to close or go into a paused state
func (*Sync) Handshake ¶ added in v0.2.1
Handshake performs the tls.Handshake() of a *tls.Conn if the connection is not *tls.Conn then the NotTLSConnectionError is returned
func (*Sync) HandshakeContext ¶ added in v0.2.1
HandshakeContext performs the tls.HandshakeContext() of a *tls.Conn if the connection is not *tls.Conn then the NotTLSConnectionError is returned
func (*Sync) Raw ¶
Raw shuts off all of frisbee's underlying functionality and converts the frisbee connection into a normal TCP connection (net.Conn)
func (*Sync) ReadPacket ¶ added in v0.2.0
ReadPacket is a blocking function that will wait until a frisbee packet is available and then return it (and its content). In the event that the connection is closed, ReadPacket will return an error.
func (*Sync) RemoteAddr ¶
RemoteAddr returns the remote address of the underlying net.Conn
func (*Sync) SetContext ¶ added in v0.2.4
SetContext allows users to save a context within a connection
func (*Sync) SetDeadline ¶
SetDeadline sets the read and write deadline on the underlying net.Conn
func (*Sync) SetReadDeadline ¶
SetReadDeadline sets the read deadline on the underlying net.Conn
func (*Sync) SetWriteDeadline ¶
SetWriteDeadline sets the write deadline on the underlying net.Conn
func (*Sync) WritePacket ¶ added in v0.2.0
WritePacket takes a packet.Packet and sends it synchronously.
If packet.Metadata.ContentLength == 0, then the content array must be nil. Otherwise, it is required that packet.Metadata.ContentLength == len(content).