cio
Conveniently create net/tls server/client sockets with helpful listeners providing common functionality.
This will do all the work for you to create client or server sockets setup for:
- secure connections using
tls
module and private/public/root certificates - authenticate both clients and servers and perform whitelist/blacklist of clients
- a server connection which automatically recalls
listen()
when the EADDRINUSE
error occurs
Additional features available in @cio
scope:
- @cio/duplex-emitter
- @cio/transformer
- @cio/oboe
See chain-builder for more on how each worker chain operates.
See ordering for more on how the workers are ordered in the chain.
Install
npm install cio --save
TODO: Create Table of Contents
Usage
Usage: Build module
The module accepts options to future proof it. This means the require call returns a builder function which makes the cio
instance you'll use.
var buildCio = require('cio')
var cio = buildCio(moduleOptions)
var server = cio.server(options)
var cio = require('cio')()
var cio = require('cio')(cioModuleOptions)
Usage: Default Client
var clientOptions = { }
, client = cio.client(clientOptions);
Usage: Simple Client
var clientOptions = {
port : 12345
, host: 'localhost'
}
, client = cio.client(clientOptions);
Usage: Simple Server
var serverOptions = { }
, server = cio.server(serverOptions);
Usage: Secured with TLS
All the above can be changed to perform secured communication by providing the necessary certificates as described in the Node TLS documentation (and createServer()).
Then cio
will use the tls
module, instead of net
, to create the sockets. The options object is passed on to the tls
functions as-is so all options supported by those modules may be specified.
Node uses the names: 'key', 'cert', and 'ca'. I prefer the names: 'private', 'public', and 'root'. So, either may be used.
You may specify the file path to the certificate and it will be read into a buffer for you.
Or, you may provide the buffer yourself.
These options are provided directly to the Node modules so options described by them are allowed.
This is a convenience so you don't have to write the file reading part.
var clientOrServerOptions = {
private: 'path/to/private/key/file'
, public: getPublicCertAsBuffer()
, root: [rootCertBuffer]
, rejectUnauthorized: true
, requestCert: true
, isClientAllowed: function allowSomeClients(clientName) {
return clientName.indexOf('noblah') > -1;
}
, rejectClient: function rejectWithMessage(connection, clientName) {
connection.end('Sorry, you are not allowed, '+clientName);
}
};
var client = cio.client(clientOrServerOptions);
var server = cio.server(clientOrServerOptions);
Both client and server also allow rejectUnauthorized
which makes it require certificates and secured communication. See the Node TLS documentation.
The server also supports the requestCert
for client whitelist/blacklist support. See the authenticate-client listener.
Usage: Addons
Provide additional functionality by adding listeners for new sockets. There are three types of listeners:
- client socket listeners made via
connect()
(net or tls) - server socket listeners made via
createServer()
(net or tls) - server client connection listeners emitted to
connection
or secureConnection
events.
Add listeners with corresponding functions:
cio.onClient(listener)
cio.onServer(listener)
cio.onServerClient(listener)
These functions also accept a string. They will attempt to require()
it to get the listener function. You may load addons like:
var cio = buildCio();
cio.onClient('@cio/transformer');
var transformer = require('@cio/transformer');
cio.onClient(transformer);
cio.onClient(function(control, context) {
});
cio.onServer(function(control, context) {
});
cio.onServerClient(function(control, context) {
});
See chain-builder for more on what the control
, context
, and this
are in your listeners.
By default new listeners are added at the end of the work chain. You may alter how the functions are ordered by setting order constraints onto the functions. See ordering for full documentation.
TODO: List the core listener ID's by work chain and show an example of using function options to alter ordering.
Usage: Client vs Server
There is little difference between client()
and server()
.
The server has:
requestCert
to deny clients.isClientAllowed
and rejectClient
for whitelist/blacklist of clientsnoRelisten
to disable the default behavior of retrying the listen()
when the error is EADDRINUSE
retryDelay
and maxRetries
to control the retry behavior
The client has:
reconnect
for automatically reconnecting (not yet implemented)
The rest are shared by both.
Options
All defaults are false or undefined.
Name | type | Client/Server | Description |
---|
noRelisten | bool | server | server socket gets an error listener for EADDRINUSE which will retry three times to listen() before exiting. Set this to true to turn that off |
retryDelay | int | server | Defaults to 3 second delay before retrying listen() |
maxRetries | int | server | Defaults to 3 tries before quitting |
requestCert | bool | server | will trigger using tls instead of net . Used for server only. Adds a listener which will get client name and check if they're allowed. Must specify isClientAllowed function. May specify rejectClient function. Default emits an error event with a message including the name of client rejected. |
rejectUnauthorized | bool | both | requires proper certificates |
key or private | file path or buffer | both | private key for TLS |
cert or public | file path or buffer | both | public key for TLS |
ca or root | file path or buffer | both | ca/root key |
isClientAllowed | Function | server | Receives the client name for the certificate. Returning false will cause the client connection to be rejected (closed). |
rejectClient | Function | server | When isClientAllowed returns false this function is called with client name and socket. When not specified and isClientAllowed returns false then an 'error' event is emitted ('Client Rejected: ' + clientName ). |
Not yet implemented (X), or, being moved to the @cio
scope (!):
? | Name | type | Client/Server | Description |
---|
X | reconnect | bool | client | use reconnect-net to handle reconnecting. not yet implemented |
! | multiplex | bool | both | use mux-demux for multiplexing connection |
! | eventor | bool | both | use duplex-emitter . if multiplex is true, create 'events' stream |
! | jsonify | bool | both | run connection thru json-duplex-stream for in+out |
! | transform | Transform | both | pipe connection thru Transform and back to connection. if jsonify is true then the Transform is in the middle: conn -> json.in -> transform -> json.out -> conn |
Events
Not yet, these are being moved to new modules in @cio
scope. They will emit these events once they are available.
- 'mux' - When
multiplex
is on, 'mux' is emitted on a new socket after the 'on connect' listeners have run. Use this to configure the mux instance. For example, adding more streams to it and associated handlers. - 'eventor' - When
eventor
is on, 'eventor' is emitted on a new socket after the 'on connect' listeners have run. Use this to setup event handlers on the socket specific eventor
. - 'jsonify' - When 'jsonify' is on, 'jsonify' is emitted when the
json-duplex-stream
has been setup with the socket piping to its input and its output piping to the socket. Use this to specify what should happen in the middle, after the jsonified input and how it gets back to the jsonify output.
MIT License