nan0

package module
v1.6.1 Latest Latest
Warning

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

Go to latest
Published: Jul 23, 2019 License: MIT Imports: 17 Imported by: 2

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:

  • Quickly establish server and client communication objects using distinct builder pattern

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

Usage

In a Dep project, use the 'ensure' command to add the nan0 package as a dependency:

    dep ensure -add "github.com/Yomiji/nan0"

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/nan0"
    
      func init() {
          nan0.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:
      package main
    
      import (
            "github.com/Yomiji/nan0"
            "time"
            "fmt"
            "github.com/golang/protobuf/proto"
        )
    
        //NOTE: Error checking omitted for demonstration purposes only, PLEASE be more vigilant in production systems.
      func main() {
      	// Create a nan0 service
      	service := &nan0.Service{
      		ServiceName: "TestService",
      		Port:        4546,
      		HostName:    "127.0.0.1",
      		ServiceType: "Test",
      		StartTime:   time.Now().Unix(),
      	}
    
      	// Create a service / client builder instance
      	builder := service.NewNanoBuilder().
      		AddMessageIdentity(proto.Clone(service)).
      		ReceiveBuffer(0).
      		SendBuffer(0)
      	// Build an echo server, nil for default implementation
      	server, _ := builder.BuildServer(nil)
      	defer server.Shutdown()
      	// The function for echo service, for the first connection, pass all messages received to the sender
      	go func() {
      		conn := <-server.GetConnections()
      		for ; ; {
      			select {
      			case msg := <-conn.GetReceiver():
      				conn.GetSender() <- msg
      			default:
      			}
      		}
      	}()
    
      	// Establish a client connection
      	comm, _ := builder.Build()
    
      	// Shutdown when finished
      	defer comm.Close()
    
      	// The nan0.Nan0 allows for sending and receiving protobufs on channels for communication
      	sender := comm.GetSender()
      	receiver := comm.GetReceiver()
    
      	// Send a protocol buffer, yes nan0.Service is a protobuf type
      	sender <- service
      	// Wait to receive a response, which should be the Service back again in this case due to the echo code above
      	result := <-receiver
    
      	// Test the results, should be the same
      	if service.String() == result.(*nan0.Service).String() {
      		fmt.Println("Service was echoed back")
      	}
      }
    
    
Logging

This framework has a logging package that 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 to nil.
      package main
    
      import "github.com/yomiji/nan0"
    
      func main() {
        nan0.Debug = nil
      }
    
  • You can reassign the logger from console to another writer using the SetLogWriter function.
      package main
    
      import (
        "github.com/Yomiji/nan0"
        "net"
      )
    
      func main() {
        logserv,_ := net.Dial("tcp", "localhost:1234")
        nan0.SetLogWriter(logserv)
      }
    
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
  • Create a separate configuration for writer timeouts
  • Document nan0 settings
  • Add godoc examples

Documentation

Index

Constants

This section is empty.

Variables

View Source
var (
	Info              = log.New(os.Stdout, "Nan0 [INFO]: ", log.Ldate|log.Ltime)
	Warn              = log.New(os.Stderr, "Nan0 [WARN]: ", log.Ldate|log.Ltime)
	Error             = log.New(os.Stderr, "Nan0 [ERROR]: ", log.Ldate|log.Ltime)
	Debug *log.Logger = nil
)

Loggers provided:

 Level | Output | Format
	Info: Standard Output - 'Nan0 [INFO] %date% %time%'
	Warn: Standard Error - 'Nan0 [DEBUG] %date% %time%'
	Error: Standard Error - 'Nan0 [ERROR] %date% %time%'
	Debug: Disabled by default
View Source
var MaxNanoCache = 50

The max queued connections for NanoServer handling, used with ListenTCP()

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 NoLogging

func NoLogging()

Conveniently disable all logging for this api

func SetLogWriter

func SetLogWriter(w io.Writer)

func ToggleLineNumberPrinting

func ToggleLineNumberPrinting(info, warn, fail, debug bool)

Types

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

type NanoBuilder

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

func (*NanoBuilder) AddMessageIdentities

func (sec *NanoBuilder) AddMessageIdentities(messageIdents ...proto.Message) *NanoBuilder

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 (*NanoBuilder) AddMessageIdentity

func (sec *NanoBuilder) AddMessageIdentity(messageIdent proto.Message) *NanoBuilder

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 (NanoBuilder) Build

func (sec NanoBuilder) Build() (nan0 NanoServiceWrapper, err error)

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

func (*NanoBuilder) BuildServer

func (sec *NanoBuilder) BuildServer(handler func(net.Listener, *NanoBuilder)) (*NanoServer, error)

Build a wrapped server instance

func (*NanoBuilder) ReceiveBuffer

func (sec *NanoBuilder) ReceiveBuffer(receiveBuffer int) *NanoBuilder

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

func (*NanoBuilder) SendBuffer

func (sec *NanoBuilder) SendBuffer(sendBuffer int) *NanoBuilder

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

func (*NanoBuilder) ToggleWriteDeadline

func (sec *NanoBuilder) ToggleWriteDeadline(writeDeadline bool) *NanoBuilder

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

func (*NanoBuilder) Websocket

func (sec *NanoBuilder) Websocket() *NanoBuilder

Enables websocket handling for this connection

func (NanoBuilder) WrapConnection

func (sec NanoBuilder) WrapConnection(connection interface{}) (nan0 NanoServiceWrapper, err error)

Wrap a raw connection which will communicate with the server

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) 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

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) IsAlive

func (server NanoServer) IsAlive() bool

Exposes the IsAlive method of the service delegate

func (NanoServer) IsExpired

func (server NanoServer) IsExpired() bool

Exposes the IsExpired method of the service delegate

func (*NanoServer) IsShutdown

func (server *NanoServer) IsShutdown() bool

func (*NanoServer) Shutdown

func (server *NanoServer) Shutdown()

type NanoServiceWrapper

type NanoServiceWrapper interface {

	// Close the wrapper goroutines and the underlying connections
	Close()
	// Check if the wrapper is closed
	IsClosed() bool
	// Return the sender channel for this nanoservice wrapper, messages are sent along this route
	GetSender() chan<- interface{}
	// Return the receiver channel for this nanoservice wrapper, messages are received from this
	GetReceiver() <-chan interface{}
	// Get the service name identifier
	GetServiceName() string
	// Determine if two instances are equal
	Equals(NanoServiceWrapper) bool
	// contains filtered or unexported methods
}

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

type Server

type Server interface {
	IsAlive() bool
	IsExpired() bool
	IsShutdown() bool
	Shutdown()
	GetServiceName() string
	GetConnections() <-chan NanoServiceWrapper
	AddConnection(NanoServiceWrapper)
}

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,4,opt,name=hostName,proto3" json:"hostName,omitempty"`
	Uri                  string   `protobuf:"bytes,5,opt,name=uri,proto3" json:"uri,omitempty"`
	ServiceName          string   `protobuf:"bytes,6,opt,name=serviceName,proto3" json:"serviceName,omitempty"`
	ServiceType          string   `protobuf:"bytes,7,opt,name=serviceType,proto3" json:"serviceType,omitempty"`
	XXX_NoUnkeyedLiteral struct{} `json:"-"`
	XXX_unrecognized     []byte   `json:"-"`
	XXX_sizecache        int32    `json:"-"`
}

func (*Service) Descriptor

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

func (Service) Equals

func (ns Service) Equals(other Service) bool

Compare two service instances for equality

func (*Service) GetExpired

func (m *Service) GetExpired() bool

func (*Service) GetHostName

func (m *Service) GetHostName() string

func (*Service) GetPort

func (m *Service) GetPort() int32

func (*Service) GetServiceName

func (m *Service) GetServiceName() string

func (*Service) GetServiceType

func (m *Service) GetServiceType() string

func (*Service) GetStartTime

func (m *Service) GetStartTime() int64

func (*Service) GetUri

func (m *Service) GetUri() string

func (Service) IsAlive

func (ns Service) IsAlive() bool

Checks if this nanoservice is responding to tcp on its port

func (Service) IsExpired

func (ns Service) IsExpired() bool

Checks if a particular nanoservice is expired based on its start time and time to live

func (*Service) NewNanoBuilder

func (ns *Service) NewNanoBuilder() *NanoBuilder

func (*Service) ProtoMessage

func (*Service) ProtoMessage()

func (*Service) Refresh

func (ns *Service) Refresh()

Refreshes the start time so that this service does not expire

func (*Service) Reset

func (m *Service) Reset()

func (*Service) Start

func (ns *Service) Start() (net.Listener, error)

Starts a tcp listener for this service

func (*Service) String

func (m *Service) String() string

func (*Service) XXX_DiscardUnknown

func (m *Service) XXX_DiscardUnknown()

func (*Service) XXX_Marshal

func (m *Service) XXX_Marshal(b []byte, deterministic bool) ([]byte, error)

func (*Service) XXX_Merge

func (dst *Service) XXX_Merge(src proto.Message)

func (*Service) XXX_Size

func (m *Service) XXX_Size() int

func (*Service) XXX_Unmarshal

func (m *Service) XXX_Unmarshal(b []byte) 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

Jump to

Keyboard shortcuts

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