truflux

2.0.11 • Public • Published

Truflux The fastest socket module on npm

To install

npm install --save truflux
var tru = require('truflux');

Truflux uses a separate protocol definition module. No internal messaging module is provided.Here are some official definition modules

truflux-msg A stateless messaging protocol.Very easy to use. https://www.npmjs.com/package/truflux-msg

truflux-state-msg A stateful messaging protocol.Recommended for intermediate use. https://www.npmjs.com/package/truflux-state-msg

TL:DR

Truflux is a lightweight high performance socket framework for protocol based messaging for websockets and netsockets supporting read/write streams to allow you to send files across a network, as well as crypto for symmetric and asymmetric secure connections.The browser client is about ~5kb minified and ~2kb gzipped.

For some recipes on common networking actions see the end of the readme. This includes file sending and binding to servers like express .Note that the browser client contains the same functionality as a net client, but has a few small differences which are outlined below

Current Performance stats

The current performance stats are based on the benchmarking test performed by ws, the current "fastest" socket library These number are performed on a lowend 32bit laptop with 1.3GHz CPU with 1GB RAM which is actually inferior to the m3.xlarge EC2 instance that ws uses for testing.

NOTE With a standard 3.2GHz CPU, you can expect a speed increase of about 8x

However as you can see, we soundly beat the current benchmark of 'ws' performance even with the overhead of crypto.

truflux

No crypto

  • Running 10000 roundtrips of 64 B binary data: 3.8s 185.96 kB/s
  • Running 5000 roundtrips of 16 kB binary data: 3.9s 23.85 MB/s
  • Running 1000 roundtrips of 128 kB binary data: 4.5s 36.62 MB/s
  • Running 100 roundtrips of 1 MB binary data: 5.2s 21.21 MB/s
  • Running 10 roundtrips of 10 MB binary data: 24.4s 4.71 MB/s

Crypto using aes-256-cbc

  • Running 10000 roundtrips of 64 B binary data: 4.9s 126.9 kB/s
  • Running 5000 roundtrips of 16 kB binary data: 9.1s 8.56 MB/s
  • Running 1000 roundtrips of 128 kB binary data: 13.2s 9.49 MB/s
  • Running 100 roundtrips of 1 MB binary data: 13.8s 7.27 MB/s
  • Running 10 roundtrips of 10 MB binary data: 31s 3.22 MB/s

ws

  • Running 10000 roundtrips of 64 B binary data: 22.1s 28.34 kB/s
  • Running 5000 roundtrips of 16 kB binary data: 33.9s 2.31 MB/s
  • Running 1000 roundtrips of 128 kB binary data: 50s 2.5 MB/s
  • Running 100 roundtrips of 1 MB binary data: 35.3s 2.83 MB/s
  • Running 10 roundtrips of 10 MB binary data: 35s 2.85 MB/s

We can improve this performance drastically for large files once Node / iojs increase the tcp window size to do more efficient chunking of the buffers NOTE also that truflux does not use unix sockets to circumvent the network interface to artificially inflate its speed.

Basic Echo server example

var tru=require('truflux');
var msg=require('truflux-msg');
 
var protocol=new msg();
protocol.add('echo',function(data,sock)
{sock.send('display',data);})
.add('display',function(data)
{console.log(data);});
 
var server=new tru.Server({msg:protocol});
server.open();
var client=new tru.Client({msg:protocol}))
client.open().on('open',function(sock)
{
    sock.send('echo','Atreyuuuu!');
});

Basic messenger example

See the following gist on how to create a minimal server/client messenger for truflux in 75 lines with extensible protocol,broadcasting and oldschool prompt interface https://gist.github.com/Auxolust/59d13b5f070b5717fa58

Upcoming improvements

  • An upcoming CDN will be provided to allow lightning fast downloads of the browserclient. This will be the recommended action to using truflux in the browser
  • UDP protocol for real time streaming (This will most likely be its own package to prevent bloat)
  • Message chunk limiter for production servers
  • Currently the server does not encrypt blob chunks when it sends data from the server to browserclient. This will be rectified via utf-8 encoding , however there will obviously be a large performance penalty on the client side to perform deciphering which I will address as soon as I can.
  • Automatic symmetric key randomisation every x amount of time to prevent cracking the socket security. This will create a pessimistic estimate of the time required by a malicious hacker to bruteforce their way past the symmetric key and automatically randomize the key

Changelog

V2.0.0

Major overhaul. Everything was rewritten with the exception of the security and standard files. Needless to say this mandated a major update. New changes include more concise language, as well as the adoption of traits internally to prevent the performance overhead of function stacks.

The most prevalent of these changes is the abstraction between websockets and netsockets and the new support for http servers

V1.0.0

Modified the ID to use the Pseudo-Hadamard transform as an isomorphic map for the ID when in secure mode. This is the first step to allowing one to plug their own cipher into the endpoints. As a result of this the fixed header size is down to 72 bits in both secure and unsecure mode, reducing header size in secure mode by 57%.This replaces the old aes-256-cbc ciphering of the message ID which was slow and inefficient.The new PHT function results in an average 1.132 microsecond decryption and encryption

Modified file sending to send as binary type, this has reduced file sending size by ~69% on average Also added in asymmetric security and expose the cipher type to allow custom encryption on the channels if needed

The change in the underlying architecture to changing the security has mandated a v1.0.0 increase to avoid breaking changes with old non asymmetric channels

V0.3.0

Added support to pausing and resuming network streams. We now default to sending buffer based encoding when sending files to avoid mangling binary files so you can now send .exes etc through the network. Also modified server broadcast to allow passing in an array of excluded sockets we don't want to receive the broadcasted message

V 0.2.0

Now using fixed header sizes and preferring binary type buffer data

Old Dynamic messages

256 bits Minimal message size in unsecure mode 592 bits Minimal message size in secure mode

New fixed headers

9 Octet header size per message in unsecure mode = 72 bits 21 Octet header size per message in secure mode = 168 bits Average message size is now down 77%

We now support 2147483647 unique message types as well as a theoretical single message maximal size of 31.2 Gb. However we highly suggest streaming for large volume data exchange. Added support to pipe to/from streams when sending files across the network.Encryption has been upgraded from aes-192-cbc to aes-256-cbc.

Performance for pushing out messages has degraded by 0.9% based on sending 1000 messages of varying types, this is in response to buffer packing, as the performance of buffers only truly shines with larger message types.To see the current stats of pushing out messages, see the bottom of the page

We've now changed from recursive descent parsing of the the message parsing to an iterative approach, so you cannot blow the call stack by pushing too many messages too fast

API

There are 4 objects exposed when you require truflux

Server   //The object to create a new server with
Client   //The object to create a new client with
std      //A collection of standards, such as default system messages as well as an enumeration of errors.These will not be changed with the exception of major version updates, so feel free to use
httpBind //A function to bind a truflux server to an http server

httpBind(trufluxServer,httpServer,options)

Used to bind an http server to allow websockets to interact with the truflux server

   options:
    {
        path: String Relative path on the http server for the binding. An error WILL be thrown if you attempt to bind two truflux servers to the same path. DEFAULT='/'
    }
truflux.httpBind(trufluxServer,someHttpServer,{path:'/myChatServer'});
someHttpServer.listen(80,function()
{
    console.log('Server up');
});

Server

Constructor([options])

    options:
    {
        port: Integer
        msg: Truflux-msg Object
        ciphers: String or Array of Strings. A list in priority order of the cipher type you wish to you to connect to a client. DEFAULT aes-256-cbc
        noDelay: Whether to turn off message buffering according to Nagles algorithm. Default is false to reduce network congestion
    }

open(cb)

Opens the server and starts listening. CHAINABLE

    cb : callback function

onNewSocket(socket,options)

Manually adds a socket object to the server. This socket must adhere to the standard tcp socket interface. You will probably never have to call this yourself

    options:
    {
        port: Integer
        msg: Truflux-msg Object
        ciphers: String or Array of Strings. A list in priority order of the cipher type you wish to you to connect to a client. DEFAULT aes-256-cbc
        noDelay: Whether to turn off message buffering according to Nagles algorithm. Default is false to reduce network congestion
    }

close([cb],[force])

Closes the server .CHAINABLE

    cb : callback function
    force : Whether to force closing or end gracefully

broadcast(id,[data],[exclude])

Broadcasts a message to currently connected server-clients , see Common client's send function for more info on id and data.CHAINABLE

    id: String | Integer
    data: Any
    exclude: Client| Array of Clients

getNumSockets()

Returns the number of currently connected clients

Events

  • client Emitted on new connection from a client
function(client)
  • error Emitted on server error. One such possible error would be if the client does not support the required cipher type
function(stdError,clientIfApplicable)

The stdError Object is as follows

{
    e:The error code.Error codes are available from sec.std.errors
    add:An OPTIONAL value that is passed in from some error codes
}

Common Client

These methods are common to any client, server-client,websocket client or the net client.

Accessible properties

    session: An object that can be used to store session variables if needed

Events

These events are common to both server-client and standard client

  • error Emitted when an error occurs on a client
function(stdErrorObject,client)
  • file Emitted when a file is offered for download
function(NetworkFileWriter,client)
  • close emitted the client closing
function(stdErrorObject,client)

send(id,[data])

Sends a message to across the network to the peer.Internally a call to a checkStructure function will be called by the client to check if the message adheres to the schema set out in the message definition .CHAINABLE

id : String/Integer
data : Any. Any data you send will return on the other side with the correct type intact. Objects will be objects, buffers will be buffers, etc
client.send(trufluxMsgObject.id.echo,"Do you want messages? Because that's how you get messages");
// OR
client.send("echo","Um phrasing? Are we still doing that?");

sendFile(Reader,[options])

Returns a NetworkFileReader object and starts sending a file to the peer.See NetworkFileReader for more details

    Reader: String for a filepath ||Readable stream that will have its input piped in and sent
    options :
        {
           name :String If string filepath is provided for reader this is not required , defaults to "[Stream]" for streams
           type:String, Stream transport type ,hex,base64 etc USELESS IN BROWSER
           size:number If string filepath is provided for reader this is not required to be set ,-1 for streams is the default
        }

close([force])

Closes the connection and sends a message to the peer to know the connection was closed cleanly, if no force was applied.CHAINABLE

    force: Boolean , whether to force close the socket connection or to send a message saying it was closed cleanly

getInfo()

Retrieves the socket info.Returns the following.

    address:String, the local address
    port:Integer, the local port
    remoteAddress:String,
    remotePort:Integer

Server-client

There are 3 readOnly properties.The first 2 are used to see the current security status. Truflux allows asymmetric encryption

secure     //Boolean Whether we are encrypting our data
peerSecure //Boolean Whether our peer is encrypting their data
ws         //Boolean Whether or not the connections is a websocket

setClientSecurity(enabled)

Turns the security of the stream from client->serverClient on/off.Turning security off has performance gains as we don't have to encrypt messages.CHAINABLE

    enabled: Boolean

setOwnSecurity(enabled)

Turns the security of the stream from serverClient->client on/off.Turning security off has performance gains as we don't have to encrypt messages.CHAINABLE

    enabled: Boolean

Client

Constructor([options])

options Object

{
    port: Number USELESS FOR BROWSER CLIENTS
    host: String
    msg:  Truflux-msg Object,
    noDelay: Whether to turn off message buffering according to Nagles algorithm  USELESS FOR BROWSER CLIENTS
    crypto: Crypto module for BROWSER CLIENTS. Allows modular security
}

open()

Connects to the server specified on host : port . CHAINABLE

Events

Events in Browser

NOTE the browser implementation does not utilize eventEmitters. It instead exposes functions as properties

onClose=function()
onOpen=function()
onErr=function(err)

EventEmitter events for non-browser

  • open Emitted when the client has connected to the server and communication can occur.The client is now ready to use
function(client)

NetworkFileReader

An object this is provided when calling client.sendFile()

Events

Events in Browser

NOTE the browser implementation does not utilize eventEmitters. It instead exposes functions as properties

onEnd=function()
onAccept=function()
onCancel=function()
onPause=function()
onResume=function()
onDecline=function()

EventEmitter events for non-browser

  • accept Emitted when the peer has accepted the offered file for download.
function(NetworkFileReader,client)
  • error
function(NetworkFileReader,client)
  • decline Emitted when the peer has declined the proffered file
function(NetworkFileReader,client)
  • pause Emitted when the peer has paused the proffered file
function(NetworkFileReader,client)
  • resume Emitted when the peer has resumed download of the proffered file
function(NetworkFileReader,client)
  • finish Emitted when the peer has finished downloading the entire file
function(NetworkFileReader,client)
  • cancel Emitted when the peer has cancelled the download of the file
function(NetworkFileReader,client)

NetworkFileWriter

An object that is provided on the file event of the CommonClient

There are a few publicly accessible properties you might find helpful

name //String Name of the sent file 
size //Integer Size in bytes of the file 
isStream//Boolean whether or not its a stream
paused //whether or not the filewriter is paused. Check for truthyness on the BROWSER CLIENT

accept(acceptor)

Accepts an offered file over the network and starts stream writing it to the specified Writer

    acceptor:String for filepath | writable stream that will have the input piped to it
    NOTE The browser client does not have an acceptor argument

decline()

Declines an offered network file

cancel()

Cancels the file download if previously accepted

pause()

Pauses the file download

resume()

Resumes the file download

Events

Events in Browser

NOTE the browser implementation does not utilize eventEmitters. It instead exposes functions as properties

 onEnd=function(blobDataURI)
 onErr=function(err)

EventEmitter events for non-browser

  • error
function(stdErrObject,NetworkFileWriter,client);
  • end Emitted when the stream has finished writing the object to file
function(NetworkFileWriter,client)

Browser caveats

  • The browserClient for truflux does not contain the server,httpbind or std objects

  • Compatibility is always a problem with browsers. By default truflux exports all its properties into the window namespaced as an object called truflux .This has the following properties

window.truflux=
{
    Client:Function,//The client constructor to create a new client
    fileDown:Boolean,//Whether file downloads are possible
    fileUp:Boolean //Whether file uploads are possible
};
  • When sending files between net sockets, they are automatically encrypted. The current performance penalty in the browser means I have yet to implement it, so be awares that on a non wss:// socket files might be sniffed

  • Since its wrapped in a function for the import, no errors should be throw if websockets are not supported, however I urge you to use !!window.WebSocket to check if websockets are supported

  • The browser does not contain crypto within it. Therefore having a server that uses a secure channel will cause a failSecure event to be emitted on the server client In order to enable crypto in the browser, the crypto module must provide the following functionality in compliance with standard node/iojs crypto functionality

crypto.getCiphers()
DiffieHellman=crypto .createDiffieHellman(prime,'base64');
DiffieHellman.generateKeys();
DiffieHellman.getPublicKey('base64;);
DiffieHellman.computeSecret(publicKey,'base64','base64');
 
decipher=crypto.createDecipher(cipherType,symmetricKey);
data=decipher.update(MessageData,'utf8');
data+=decipher.final('utf8');
 
cipher=crypto.createCipher(cipherType,symmetricKey);
data=cipher.update(messageData,'utf8');
data+=cipher.final('utf8');

Recipes

Binding to an http server

var truflux=require('truflux');
var server= new truflux.Server(/*...*/);
server.open();
 
truflux.httpBind(server,someHttpServer,{path:'/myChatServer'});
someHttpServer.listen(80,function()
{
    console.log('Server up');
});
 

Sending a file as a browser client

 
 var sender=browserClient.sendFile(someFileObject);
 sender.onAccept=function()
 {
  console.log('Our file upload offer was accepted');
 }
 sender.onEnd=function()
 {
   console.log('The server has our file');
 }

Receiving a file as a browser client

browserClient.onFile=function(wstream)
{
 wstream.accept();
 wstream.onEnd=function(uri)
 {
    var a = document.createElement("a");
    document.body.appendChild(a);
    a.style = "display: none";
 
    a.href = uri;
    a.download = wstream.name;
    a.click();
    
    //Remove URL if you're not using it anymore
    window.URL.revokeObjectURL(uri);
 }
}

Upgrading to a symmetric secure connection

//Assuming this is the first time we've called it
serverClient.setOwnSecurity(true)
.setClientSecurity(true)
.once('handshaked',function()
{
   console.log(socket.secure);//true
   console.log(socket.peerSecure);/*Not necessarily true until truflux gets the client acknowledgement, 
   however the client will receive the setSecurity message before this so synchronicity is conserved*/
 
   //Once the initial handshake happens, there is no need to listen anymore ie 
   //No need to listen to the handshake anymore, we just flip the security on and off from here
  serverClient.setOwnSecurity(false)
       .setOwnSecurity(true)
             .setClientSecurity(false)
             .setClientSecurity(true)
             .send('someMessage',someData);
 
}).once('failSecure',function()
{
    //Client probably does not have the supported ciphers.Lets  kick him off
    serverClient.close();
};

Package Sidebar

Install

npm i truflux

Weekly Downloads

25

Version

2.0.11

License

none

Last publish

Collaborators

  • titon