legion

package module
v0.0.5 Latest Latest
Warning

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

Go to latest
Published: Mar 4, 2019 License: MIT Imports: 3 Imported by: 0

README

Legion

Fast, modular, and flexible peer to peer library in Go


Legion is an easy to use, fast, and bare-bones peer to peer library designed to leave most of the network characteristics up to the user through a simple yet powerful framework system. It was written because here at Gladius we needed a peer to peer overlay for our applications, and existing solutions were not a perfect fit for our use case.

We would also like to link to the Perlin Network's Noise, as their initial API inspired a lot of our design philosophy and you should totally check it out.

Overview

  • User defined messages, allowing you to build your own cryptography and message validation system
  • Powerful framework system with easy to use event context
  • Single TCP connection opened to each peer, where messages are sent over multiplexed streams
  • User defined logging via a logging interface

Background

Basic Concepts

Messages are extremely customizable and simple with only enough information to allow Legion to discern the sender and message type. Legion has no cryptography by default and doesn't enforce any specific message body requirements. We also allow a user to set your own message validator through a framework to check an incoming message, which means you can add in your own cryptography, compression, or really any other criteria you want.

Usage

This should be considered a quick start guide, there are more examples in the examples folder and in the Gladius Network Gateway

Basic Usage

Here we create a legion object with a default config, wait until it's listening, and add a peer.

func main(){
    // Build a basic config
    conf := legion.SimpleConfig("localhost", 7947)
    
    // Build a new legion object from the config with no framework
    l := legion.New(conf, nil)

    // Listen in a new goroutine
    go l.Listen()
    // Wait until the network is listening
    l.Started()

    // Dial a peer and add it to the non-messagable peers
    err := l.AddPeer(utils.LegionAddressFromString("localhost:7946"))
    if err != nil {
        panic(err)
    }

    // Make that peer sendable by promoting it
     err := l.AddPeer(utils.LegionAddressFromString("localhost:7946"))
    if err != nil {
        panic(err)
    }

    // Block forever
    select {}
}

Messaging

There are several ways to send messages to peers in the network:

func main(){
    // ... build our legion object

    // Dial a peer and add it to the non-messagable peers
    err := l.AddPeer(utils.LegionAddressFromString("localhost:7946"))
    if err != nil {
        panic(err)
    }

    // Will send to all promoted peers
    l.Broadcast(l.NewMessage(config.BindAddress,"ping", []byte("ping"))

    // Send to a specific peer
    l.Broadcast(l.NewMessage(config.BindAddress,"ping", []byte("ping"), 
        utils.LegionAddressFromString("localhost:7946"))
    
    // Broadcast to a random 5 promoted peers
    l.BroadcastRandom(l.NewMessage(config.BindAddress,"ping", []byte("ping"), 5)

    // Block forever
    select {}
}

Custom Logger

The internal logger is a generic type that can be overridden by the user as long as your logger meets the requirements below:

// GenericLogger is the logger interface that legion uses, you can plug in
// your own logger as long as your logger implements this interface.
type GenericLogger interface {
	// Base log types
	Debug() GenericContext
	Info() GenericContext
	Warn() GenericContext
	Error() GenericContext

	// Add context like logger.With(NewContext().Field("test", "val"))
	With(ctx GenericContext) GenericLogger
}

// GenericContext provides a way to add fields to a log event
type GenericContext interface {
	Field(key string, val interface{}) GenericContext

	// Actually log the built up log line with the message
	Log(msg string)
}

You can register a new logger by calling

logger.SetLogger(YourLogger)

By default we use zerolog, you can see our implemented logger here. If you want to edit the underlying zerolog instance, you can call:

l := logger.GetLogger() // Get the wrapper
zerologger := l.(logger.ZeroLogger).Logger // Get the actual Zerolog instance (can change things like the formatting, output location, etc)

Frameworks

Writing your own

A framework is any struct that implements the framework interface:

type Framework interface {
    // Set anything up you want with Legion when the Listen method is called.
    // Should block until the framework is ready to accept messages.
    Configure(*Legion) error

    // Called before any message is passed to plugins
    ValidateMessage(*MessageContext) bool

    // Methods to interact with legion
    NewMessage(*MessageContext)
    PeerAdded(*PeerContext)
    PeerDisconnect(*PeerContext)
    Startup(*NetworkContext)
    Close(*NetworkContext)
}

If you don't need all of these methods, you can use our handy GenericFramework as an anonymous field in your struct, like this:

type MyFramework struct {
	network.GenericFramework
	specialData string
}

func (f *MyFramework) NewMessage(ctx *MessageContext) {
	fmt.Println(mspecialData)
}

by doing this, you only need to implement the methods you need and still conform to the interface.

Included frameworks

Legion includes a Kademlia like DHT framework built on top of Ethereum addresses, you can use this for discovery if you'd like:

// Create a new framework with a default address validator and a private key.
f := ethpool.New(func(common.Address) bool { return true }, privKey)

// Register it with legion
l := legion.New(conf, f)

// Connect to a peer
l.AddPeer(utils.LegionAddressFromString("localhost:6000"))

// Bootstrap with the remote peer
f.Bootstrap()

Documentation

Overview

Package legion is a simple top level package to allow a nice import syntax

Index

Constants

This section is empty.

Variables

This section is empty.

Functions

func DefaultConfig

func DefaultConfig(bindAddress string, port uint16) *config.LegionConfig

DefaultConfig returns a config with only the bind address and port specified, and all messages are considered valid

func New

New returns a new Legion object which contains most of the function needed to work with the network.

Types

This section is empty.

Directories

Path Synopsis
frameworks

Jump to

Keyboard shortcuts

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