nan0

package module
v2.5.3 Latest Latest
Warning

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

Go to latest
Published: Sep 12, 2020 License: MIT Imports: 32 Imported by: 0

README

Nan0

Protobuf Nanoservice Framework for Go
Purpose

This framework is designed to make it easier to pass messages between nanoservices, which are just a fancy name for lightweight microservices that compose some of my work. This framework supports developers in creating stream-based communications for protocol buffers over raw tcp connections. The key features of this framework include:

  • Security in-transit with minimal configuration

  • Service discovery capabilities to connect peers without configuring IP addresses

  • Quickly establish server and client communication objects using distinct pattern

  • Pass protobuf-based objects directly into a channel to both clients and servers

Usage

When I put together the framework, I needed a way to build the services without having to worry about the network transport protocols, message handshaking and so forth. Here are the primary uses and caveats:

  • There is a logging pattern in place for this plugin, to configure it, follow the steps in Logging section of this readme or simply call the NoLogging function to disable logging from this framework:
    package main
    import "github.com/yomiji/slog"
    
    func init() {
        slog.NoLogging()
    }
  • The Service type defines the actual nanoservices that you can create to serve as a client OR server. In order to quickly establish a Service, just instantiate a Service object and create a builder for it. You will still need to handle passing data to the connections that are established via the returned object like so:
        // TestRoute echoes received message
        type TestRoute struct{}
        
        func (TestRoute) Execute(msg proto.Message, sender chan<- interface{}) {
            sender <- msg
        }
        //...
        serviceConf := &nan0.Service{
            ServiceName: "TestService",
            Port:        8080,
            HostName:    "localhost",
            ServiceType: "Test",
            StartTime:   time.Now().Unix(),
        }
        server, err := serviceConf.NewNanoBuilder().
            BuildNanoServer(
                nan0.Route(new(protobufMessage), new(TestRoute)),
            )
        if err != nil {
            //..
        }
        // remember to ALWAYS shut your server down when finished
        defer server.Shutdown()
    
        client, err := clientConf.NewNanoBuilder().
            BuildNanoClient(
                nan0.AddMessageIdentity(new(protobufMessage)),
            )
        if err != nil {
            //...
        }
        // ALWAYS close your client
        defer client.Close()
        sender := client.GetSender()
        receiver := client.GetReceiver()
        
        sender <- message
        echoedProtobufMessage := <-receiver
    
    }
Logging

Slog is a logging package that originated in Nan0. Slog is used to inform the consumer of the details of operation. The logging mechanism is remotely similar to some packages in other languages such as Java's slf4j; or at least I'd like it to be similar to something most people have seen before. That being said there are some functions that must be discussed, as the default settings may be more verbose than you need.

  • There are four logging levels: Debug, Info, Warn, and Error
  • All of the logging levels are enabled by default, to disable them, you must set the corresponding logger.
      package main
    
      import "github.com/yomiji/slog"
    
      func main() {
      	// set logging levels enabled/disabled
      	// info: true, warn: true, fail: true, debug: false
        slog.ToggleLogging(true, true, true, false)
    
        slog.Info("this is a test") //works, prints
        slog.Debug("not going to print") // won't print
      }
    
Demo Project

There is a demo project created using the Nan0 API called Nan0Chat . This is a chat application that utilizes the features in Nan0 to communicate securely between a server and multiple clients.

Planned Features
  • Document nan0 settings in Wiki
  • Add godoc examples

Documentation

Index

Constants

View Source
const DefaultRoute = ""

Variables

View Source
var File_apiKey_proto protoreflect.FileDescriptor
View Source
var File_mdns_definition_proto protoreflect.FileDescriptor
View Source
var File_service_proto protoreflect.FileDescriptor
View Source
var ProtoPreamble = []byte{0x01, 0x02, 0x03, 0xFF, 0x03, 0x02, 0x01}

TCP Preamble, this pre-fixes a unique tcp transmission (protocol buffer message)

View Source
var SizeArrayWidth = defaultArrayWidth

The number of bytes that constitute the size of the proto.Message sent/received This variable is made visible so that developers can support larger data sizes

View Source
var SizeReader = func(bytes []byte) int {
	return int(binary.BigEndian.Uint32(bytes))
}

Converts the size header from the byte slice that represents it to an integer type NOTE: If you change SizeArrayWidth, you should also change this function This function is made visible so that developers can support larger data sizes

View Source
var SizeWriter = func(size int) (bytes []byte) {
	bytes = make([]byte, SizeArrayWidth)
	binary.BigEndian.PutUint32(bytes, uint32(size))
	return bytes
}

Converts the integer representing the size of the following protobuf message to a byte slice NOTE: If you change SizeReader, you should also change this function This function is made visible so that developers can support variable data sizes

View Source
var TCPTimeout = 10 * time.Second

The timeout for TCP Writers and server connections

Functions

func AddMessageIdentities added in v2.3.0

func AddMessageIdentities(messageIdents ...proto.Message) baseBuilderOption

Adds multiple identity-type objects that will be cloned to either send or receive messages. All protocol buffers you intend to send or receive should be registered with this method or the transmissions will fail

func AddMessageIdentity added in v2.3.0

func AddMessageIdentity(messageIdent proto.Message) baseBuilderOption

AddMessageIdentity adds a single identity-type object that will be cloned to either send or receive messages. All protocol buffers you intend to send or receive should be registered with this method or the transmissions will fail

func AddOrigins added in v2.4.0

func AddOrigins(origin ...string) wsBuilderOption

Adds origin checks to websocket handler (no use for clients)

func AppendOrigins added in v2.4.0

func AppendOrigins(origin ...*url.URL) wsBuilderOption

Adds origin checks to websocket handler (no use for clients)

func AwaitNSignals added in v2.5.1

func AwaitNSignals(c chan struct{}, n int)

func CheckAndDo added in v2.5.1

func CheckAndDo(awaitedCondition func() bool, do func())

func CheckAndDoWithDuration added in v2.5.1

func CheckAndDoWithDuration(awaitedCondition func() bool, do func(), after time.Duration)

func CheckHMAC added in v2.3.0

func CheckHMAC(data, suppliedMAC []byte, key *[32]byte) bool

From cryptopasta (https://github.com/gtank/cryptopasta)

CheckHMAC securely checks the supplied MAC against a message using the shared secret key.

func Decrypt added in v2.3.0

func Decrypt(ciphertext []byte, key *[32]byte) (plaintext []byte, err error)

From cryptopasta (https://github.com/gtank/cryptopasta)

Decrypt decrypts data using 256-bit AES-GCM. This both hides the content of the data and provides a check that it hasn't been altered. Expects input form nonce|ciphertext|tag where '|' indicates concatenation.

func DecryptProtobuf added in v2.3.0

func DecryptProtobuf(rawData []byte, msg proto.Message, hmacSize int, decryptKey *[32]byte, hmacKey *[32]byte) (err error)

Decrypts, authenticates and unmarshals a protobuf message using the given encrypt/decrypt key and hmac key

func Default added in v2.3.0

func Default(strict bool, bb *baseBuilder, definitionChannel <-chan *MDefinition)

func DoAfterFirstSignal added in v2.5.1

func DoAfterFirstSignal(c chan struct{}, action func())

func DoAfterNSignals added in v2.5.1

func DoAfterNSignals(c chan struct{}, n int, action func())

func Encrypt added in v2.3.0

func Encrypt(plaintext []byte, key *[32]byte) (ciphertext []byte, err error)

From cryptopasta (https://github.com/gtank/cryptopasta)

Encrypt encrypts data using 256-bit AES-GCM. This both hides the content of the data and provides a check that it hasn't been altered. Output takes the form nonce|ciphertext|tag where '|' indicates concatenation.

func EncryptProtobuf added in v2.3.0

func EncryptProtobuf(pb proto.Message, typeVal int, encryptKey *[32]byte, hmacKey *[32]byte) []byte

Signs and encrypts a marshalled protobuf message using the given encrypt/decrypt key and hmac key

func GenerateHMAC added in v2.3.0

func GenerateHMAC(data []byte, key *[32]byte) []byte

From cryptopasta (https://github.com/gtank/cryptopasta)

GenerateHMAC produces a symmetric signature using a shared secret key.

func Insecure added in v2.3.0

func Insecure(bb *baseBuilder)

Flag indicating this builder is insecure

func MaxConnections added in v2.5.1

func MaxConnections(max int) baseBuilderOption

func MaxIdleDuration added in v2.5.1

func MaxIdleDuration(duration time.Duration) baseBuilderOption

func NewEncryptionKey added in v2.3.0

func NewEncryptionKey() *[32]byte

From cryptopasta (https://github.com/gtank/cryptopasta)

NewEncryptionKey generates a random 256-bit key for Encrypt() and Decrypt(). It panics if the source of randomness fails.

func NewHMACKey added in v2.3.0

func NewHMACKey() *[32]byte

From cryptopasta (https://github.com/gtank/cryptopasta)

NewHMACKey generates a random 256-bit secret key for HMAC use. Because key generation is critical, it panics if the source of randomness fails.

func PurgeConnectionsAfter added in v2.5.1

func PurgeConnectionsAfter(duration time.Duration) baseBuilderOption

func ReceiveBuffer added in v2.3.0

func ReceiveBuffer(receiveBuffer int) baseBuilderOption

Part of the NanoBuilder chain, sets the number of messages that can be simultaneously placed on the receive buffer

func Route added in v2.5.0

func Route(messageIdent proto.Message, route ExecutableRoute) baseBuilderOption

Route enables service or client to respond to receipt of a message with the given ExecutableRoute

NOTE: route must not be nil

func Secure added in v2.3.0

func Secure(bb *baseBuilder)

Flag indicating this builder is secure this will set up a secure handshake process on connection (tcp)

func SecureWs added in v2.4.0

func SecureWs(config TLSConfig) wsBuilderOption

Enables secure websocket handling for this connection

func SendBuffer added in v2.3.0

func SendBuffer(sendBuffer int) baseBuilderOption

Part of the NanoBuilder chain, sets the number of messages that can be simultaneously placed on the send buffer

func ServiceDiscovery added in v2.3.0

func ServiceDiscovery(bb *baseBuilder)

Flag indicating if service discovery is enabled (client/server)

func ToggleWriteDeadline added in v2.3.0

func ToggleWriteDeadline(writeDeadline bool) baseBuilderOption

Part of the builder chain, sets write deadline to the TCPTimeout global value

func WithTimeout added in v2.3.0

func WithTimeout(duration time.Duration) clientDNSStrategy

Types

type ApiKey added in v2.3.0

type ApiKey struct {
	EncKey  []byte `protobuf:"bytes,1,opt,name=encKey,proto3" json:"encKey,omitempty"`
	HmacKey []byte `protobuf:"bytes,2,opt,name=hmacKey,proto3" json:"hmacKey,omitempty"`
	// contains filtered or unexported fields
}

func (*ApiKey) Descriptor deprecated added in v2.3.0

func (*ApiKey) Descriptor() ([]byte, []int)

Deprecated: Use ApiKey.ProtoReflect.Descriptor instead.

func (*ApiKey) GetEncKey added in v2.3.0

func (x *ApiKey) GetEncKey() []byte

func (*ApiKey) GetHmacKey added in v2.3.0

func (x *ApiKey) GetHmacKey() []byte

func (*ApiKey) ProtoMessage added in v2.3.0

func (*ApiKey) ProtoMessage()

func (*ApiKey) ProtoReflect added in v2.3.0

func (x *ApiKey) ProtoReflect() protoreflect.Message

func (*ApiKey) Reset added in v2.3.0

func (x *ApiKey) Reset()

func (*ApiKey) String added in v2.3.0

func (x *ApiKey) String() string

type ClientDNSFactory added in v2.3.0

type ClientDNSFactory func(strictProtocols bool) (nan0 NanoServiceWrapper, err error)

type Closer added in v2.3.0

type Closer interface {
	Close()
	IsClosed() bool
}

Close the wrapper goroutines and the underlying connections IsClosed Check if the wrapper is closed

type ConnectionHandler added in v2.3.0

type ConnectionHandler interface {
	GetConnections() <-chan NanoServiceWrapper
	AddConnection(NanoServiceWrapper)
	ActiveConnectionsCount() int
}

Handles connections established

type ConnectionInfo

type ConnectionInfo struct {
	Websocket bool   `protobuf:"varint,1,opt,name=websocket,proto3" json:"websocket,omitempty"`
	Port      int32  `protobuf:"varint,3,opt,name=port,proto3" json:"port,omitempty"`
	HostName  string `protobuf:"bytes,5,opt,name=hostName,proto3" json:"hostName,omitempty"`
	Uri       string `protobuf:"bytes,7,opt,name=uri,proto3" json:"uri,omitempty"`
	// contains filtered or unexported fields
}

func (*ConnectionInfo) Descriptor deprecated

func (*ConnectionInfo) Descriptor() ([]byte, []int)

Deprecated: Use ConnectionInfo.ProtoReflect.Descriptor instead.

func (*ConnectionInfo) GetHostName

func (x *ConnectionInfo) GetHostName() string

func (*ConnectionInfo) GetPort

func (x *ConnectionInfo) GetPort() int32

func (*ConnectionInfo) GetUri

func (x *ConnectionInfo) GetUri() string

func (*ConnectionInfo) GetWebsocket

func (x *ConnectionInfo) GetWebsocket() bool

func (*ConnectionInfo) ProtoMessage

func (*ConnectionInfo) ProtoMessage()

func (*ConnectionInfo) ProtoReflect added in v2.3.0

func (x *ConnectionInfo) ProtoReflect() protoreflect.Message

func (*ConnectionInfo) Reset

func (x *ConnectionInfo) Reset()

func (*ConnectionInfo) String

func (x *ConnectionInfo) String() string

type DiscoverableService added in v2.3.0

type DiscoverableService interface {
	MdnsTag() string
}

Generates discovery tags

type Equality added in v2.3.0

type Equality interface {
	Equals(NanoServiceWrapper) bool
}

Determine if two instances are equal

type ExecutableRoute added in v2.5.0

type ExecutableRoute interface {
	Execute(msg proto.Message, sender chan<- interface{})
}

type Identity added in v2.3.0

type Identity interface {
	GetServiceName() string
}

Get the name of a service or client

type MDefinition

type MDefinition struct {
	ConnectionInfo        *ConnectionInfo `protobuf:"bytes,1,opt,name=connectionInfo,proto3" json:"connectionInfo,omitempty"`
	SupportedMessageTypes []string        `protobuf:"bytes,3,rep,name=supportedMessageTypes,proto3" json:"supportedMessageTypes,omitempty"`
	// contains filtered or unexported fields
}

func (*MDefinition) Descriptor deprecated

func (*MDefinition) Descriptor() ([]byte, []int)

Deprecated: Use MDefinition.ProtoReflect.Descriptor instead.

func (*MDefinition) GetConnectionInfo

func (x *MDefinition) GetConnectionInfo() *ConnectionInfo

func (*MDefinition) GetSupportedMessageTypes

func (x *MDefinition) GetSupportedMessageTypes() []string

func (*MDefinition) ProtoMessage

func (*MDefinition) ProtoMessage()

func (*MDefinition) ProtoReflect added in v2.3.0

func (x *MDefinition) ProtoReflect() protoreflect.Message

func (*MDefinition) Reset

func (x *MDefinition) Reset()

func (*MDefinition) String

func (x *MDefinition) String() string

type Nan0

type Nan0 struct {
	// The name of the service
	ServiceName string
	// contains filtered or unexported fields
}

The Nan0 structure is a wrapper around a net/TCP connection which sends and receives protocol buffers across it. The protocol buffers are not descriptive and one must send or receive using the methods provided. If one needs more control over the conduit, one should create a connection to the server using the Server.DialTCP method.

func (*Nan0) Close

func (n *Nan0) Close()

Closes the open connection and terminates the goroutines associated with reading them

func (Nan0) Equals

func (n Nan0) Equals(other NanoServiceWrapper) bool

Determine if two instances are equal

func (*Nan0) GetReceiver

func (n *Nan0) GetReceiver() <-chan interface{}

Returns a read-only channel that is used to receive a protocol buffer message returned through this connection

func (*Nan0) GetSender

func (n *Nan0) GetSender() chan<- interface{}

Return a write-only channel that is used to send a protocol buffer message through this connection

func (Nan0) GetServiceName

func (n Nan0) GetServiceName() string

Get the service name identifier

func (*Nan0) IsClosed

func (n *Nan0) IsClosed() bool

Determine if this connection is closed

func (Nan0) LastComm added in v2.5.1

func (n Nan0) LastComm() time.Time

type NanoBuilder

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

func (*NanoBuilder) BuildNanoClient added in v2.3.0

func (nsb *NanoBuilder) BuildNanoClient(opts ...interface{}) (nan0 NanoServiceWrapper, err error)

Establish a connection creating a first-class Nan0 connection which will communicate with the server

func (*NanoBuilder) BuildNanoDNS added in v2.3.0

func (nsb *NanoBuilder) BuildNanoDNS(ctx context.Context, strategy clientDNSStrategy, opts ...interface{}) ClientDNSFactory

func (*NanoBuilder) BuildNanoServer added in v2.3.0

func (nsb *NanoBuilder) BuildNanoServer(opts ...interface{}) (*NanoServer, error)

Build a wrapped server instance

type NanoServer

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

The NanoServer structure is a wrapper around a service which allows for the acceptance of connections which are wrapped automatically in Nan0 objects. This allows for the communication of protocol buffers along channels for each connection.

func (NanoServer) ActiveConnectionsCount added in v2.5.1

func (server NanoServer) ActiveConnectionsCount() int

func (*NanoServer) AddConnection

func (server *NanoServer) AddConnection(conn NanoServiceWrapper)

Puts a connection in the server

func (*NanoServer) GetAllConnections

func (server *NanoServer) GetAllConnections() []NanoServiceWrapper

Get all connections that this service has ever opened

func (*NanoServer) GetConnections

func (server *NanoServer) GetConnections() <-chan NanoServiceWrapper

GetConnections +-- Deprecated --+ Get the channel which is fed new connections to the server

func (NanoServer) GetHost

func (server NanoServer) GetHost() string

Exposes the service delegate's hostName property

func (NanoServer) GetPort

func (server NanoServer) GetPort() int32

Exposes the service delegate's port property

func (NanoServer) GetServiceName

func (server NanoServer) GetServiceName() string

Exposes the service delegate's serviceName property

func (NanoServer) GetServiceType

func (server NanoServer) GetServiceType() string

Exposes the service delegate's serviceType property

func (NanoServer) GetStartTime

func (server NanoServer) GetStartTime() int64

Exposes the service delegate's startTime property

func (*NanoServer) IsShutdown

func (server *NanoServer) IsShutdown() bool

func (NanoServer) MdnsTag added in v2.3.0

func (server NanoServer) MdnsTag() string

func (*NanoServer) Shutdown

func (server *NanoServer) Shutdown()

type NanoServiceWrapper

type NanoServiceWrapper interface {
	Closer
	TxRx
	Identity
	Equality
	// contains filtered or unexported methods
}

Any object which wraps a connection to send and receive different protocol buffers

type Receiver added in v2.3.0

type Receiver interface {
	GetReceiver() <-chan interface{}
}

Return the receiver channel for this nanoservice wrapper, messages are received from this

type RouteMap added in v2.5.0

type RouteMap map[string]ExecutableRoute

type Sender added in v2.3.0

type Sender interface {
	GetSender() chan<- interface{}
}

Return the sender channel for this nanoservice wrapper, messages are sent along this route

type Server

Represents a server object with live-ness and registry to a discovery mechanism

type Service

type Service struct {
	Expired     bool   `protobuf:"varint,1,opt,name=expired,proto3" json:"expired,omitempty"`
	Port        int32  `protobuf:"varint,2,opt,name=port,proto3" json:"port,omitempty"`
	StartTime   int64  `protobuf:"varint,3,opt,name=startTime,proto3" json:"startTime,omitempty"`
	HostName    string `protobuf:"bytes,5,opt,name=hostName,proto3" json:"hostName,omitempty"` // an externally facing host name which clients connect to
	Uri         string `protobuf:"bytes,7,opt,name=uri,proto3" json:"uri,omitempty"`
	ServiceName string `protobuf:"bytes,8,opt,name=serviceName,proto3" json:"serviceName,omitempty"`
	ServiceType string `protobuf:"bytes,9,opt,name=serviceType,proto3" json:"serviceType,omitempty"`
	// contains filtered or unexported fields
}

func (*Service) Descriptor deprecated

func (*Service) Descriptor() ([]byte, []int)

Deprecated: Use Service.ProtoReflect.Descriptor instead.

func (Service) Equals

func (ns Service) Equals(other Service) bool

Compare two service instances for equality

func (*Service) GetExpired

func (x *Service) GetExpired() bool

func (*Service) GetHostName

func (x *Service) GetHostName() string

func (*Service) GetPort

func (x *Service) GetPort() int32

func (*Service) GetServiceName

func (x *Service) GetServiceName() string

func (*Service) GetServiceType

func (x *Service) GetServiceType() string

func (*Service) GetStartTime

func (x *Service) GetStartTime() int64

func (*Service) GetUri

func (x *Service) GetUri() string

func (Service) MdnsTag

func (ns Service) MdnsTag() string

func (*Service) NewNanoBuilder

func (ns *Service) NewNanoBuilder() *NanoBuilder

func (*Service) NewWebsocketBuilder added in v2.3.0

func (ns *Service) NewWebsocketBuilder() *WebsocketBuilder

func (*Service) ProtoMessage

func (*Service) ProtoMessage()

func (*Service) ProtoReflect added in v2.3.0

func (x *Service) ProtoReflect() protoreflect.Message

func (*Service) Reset

func (x *Service) Reset()

func (*Service) String

func (x *Service) String() string

type ServiceLifecycle added in v2.3.0

type ServiceLifecycle interface {
	IsShutdown() bool
	Shutdown()
}

Handles shutdown procedure

type TLSConfig

type TLSConfig struct {
	CertFile string
	KeyFile  string
	tls.Config
}

type TxRx added in v2.3.0

type TxRx interface {
	Sender
	Receiver
	// LastComm returns the time of last Tx or Rx
	LastComm() time.Time
}

Transmit and Receive

type WebsocketBuilder added in v2.3.0

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

func (*WebsocketBuilder) BuildWebsocketClient added in v2.3.0

func (wsb *WebsocketBuilder) BuildWebsocketClient(opts ...interface{}) (nan0 NanoServiceWrapper, err error)

func (*WebsocketBuilder) BuildWebsocketDNS added in v2.3.0

func (wsb *WebsocketBuilder) BuildWebsocketDNS(ctx context.Context, strategy clientDNSStrategy, opts ...interface{}) ClientDNSFactory

func (*WebsocketBuilder) BuildWebsocketServer added in v2.3.0

func (wsb *WebsocketBuilder) BuildWebsocketServer(opts ...interface{}) (*NanoServer, error)

type WsNan0

type WsNan0 struct {
	// The name of the service
	ServiceName string
	// contains filtered or unexported fields
}

The WsNan0 structure is a wrapper around a websocket connection which sends and receives protocol buffers across it. Use the provided Builder object to correctly initialize this structure.

func (*WsNan0) Close

func (n *WsNan0) Close()

Closes the open connection and terminates the goroutines associated with reading them

func (WsNan0) Equals

func (n WsNan0) Equals(other NanoServiceWrapper) bool

Determine if two instances are equal

func (WsNan0) GetReceiver

func (n WsNan0) GetReceiver() <-chan interface{}

Returns a read-only channel that is used to receive a protocol buffer message returned through this connection

func (WsNan0) GetSender

func (n WsNan0) GetSender() chan<- interface{}

Return a write-only channel that is used to send a protocol buffer message through this connection

func (WsNan0) GetServiceName

func (n WsNan0) GetServiceName() string

Get the service name identifier

func (*WsNan0) IsClosed

func (n *WsNan0) IsClosed() bool

Determine if this connection is closed

func (WsNan0) LastComm added in v2.5.1

func (n WsNan0) LastComm() time.Time

Jump to

Keyboard shortcuts

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