Mesh Socket

Basic Usage

To connect to a mesh network, you will use the MeshSocket() object. You can instantiate this as follows:

> const mesh = require('js2p').mesh;
> sock = new mesh.MeshSocket('', 4444);

Using '' will automatically grab your LAN address. If you want to use an outward-facing internet connection, there is a little more work. First you need to make sure that you have a port forward setup (NAT busting is not in the scope of this project). Then you will specify this outward address as follows:

> const mesh = require('js2p').mesh;
> sock = new mesh.MeshSocket('', 4444, null, ['', 44565]);

If nodejs-websocket is installed, then you can use websockets as a transport layer (for instance, to allow communication with a browser). If node-forge is installed, then you can use SSL/TLS as a transport layer. You can do this by providing a Protocol() object, like so:

> const mesh = require('js2p').mesh;
> const base = require('js2p').base;
> var app_description = 'A string which describes your application';
> var SSL = new mesh.MeshSocket('', 4444, new base.Protocol(app_description, 'SSL'));
> var WS = new mesh.MeshSocket('', 5555, new base.Protocol(app_description, 'ws'));

Specifying a different protocol object will ensure that you only can connect to people who share your object structure. So if someone has the description 'mesh2' instead of 'mesh', you will fail to connect.

Unfortunately, this failure is currently silent. Because this is asynchronous in nature, raising an error is not possible. Because of this, it’s good to perform the following check the truthiness of MeshSocket.routing_table. If it is truthy, then you are connected to the network.

To send a message, you should use the send() method. Each argument you supply will correspond to a packet that your peer receives. In addition, there are two keyed arguments you can use. flag will specify how other nodes relay this. These flags are defined in js2p.base.flags . broadcast will indicate that other nodes are supposed to relay it. whisper will indicate that your peers are not supposed to relay it. There are other technically valid options, but they are not recommended. type will specify what actions other nodes are supposed to take on it. It defaults to broadcast, which indicates no change from the norm. There are other valid options, but they should normally be left alone, unless you’ve written a handler (see below) to act on this.

> sock.send(['this is', 'a test']);

Receiving is a bit simpler. When you call the recv() method, you receive a Message() object. This has a number of methods outlined which you can find by clicking its name. Most notably, you can get the packets in a message with packets, and reply directly with reply().

> sock.send(['Did you get this?']);
> // a peer replies
> var msg = sock.recv();
> console.log(msg);
Message {
 type: 2
 packets: [ 'Yes', 'I did' ]
 sender: '8vu4oLsvVBsnnH6N83z6y6RZqrMKRrVHr44xRwXCFaU9qcyYsjJDzVfKwmdGp51K4d' }
> msg.packets.forEach((packet) => {
... var str = packet.toString()
... console.log(util.inspect(str));
... });
'I did'
> console.log(msg.packets);
[ 2, 'yes', 'I did' ]
> sock.recv(10).forEach((msg) => {
... msg.reply(["Replying to a list", {'here': 10, 'have some': 'data'}]);
... });


In addition to the above, the MeshSocket() object has two Event() s.

First there’s MeshSocket Event 'connect'(). This is called whenever you finalize a connection to your distributed service. It is also called if you reconnect to the service after some failure.

> sock.once('connect', (conn)=>{
... // conn is a reference to the socket, in case you're in a new scope
... // the .once() indicates that this event should only be called once
... });
> sock.on('connect', (conn)=>{
... // conn is still a reference to the socket
... // the .on() indicates that this event should be called *every* time
... });

This class has one other event: MeshSocket Event 'message'(). This one is a little bit trickier to use, and it’s recommended that you only have one callback in place at any given time. The event is called any time you receive a message that is not handled by one of the “privileged” callbacks. Such callbacks include the ones for dealing with new peers on the network.

> sock.on('message', (conn)=>{
... // note that you are not passed a reference to the message.
... // This means that you must explicitly recv().
... let msg = conn.recv();
... if (msg !== undefined)  {
..... // note the guard clause for if someone else registered a callback
..... msg.reply(['this is an example'])
..... }
... });

Advanced Usage

In addition to this, you can register a custom handler for incoming messages. This is appended to the end of the included ones. When writing your handler, you must keep in mind that you are only passed a Message() object and a MeshConnection(). Fortunately you can get access to everything you need from these objects.

> function example(msg, handler)   {
... const packets = msg.packets;
... if (packets[0] === some_flag)   {
..... some_action(msg, handler);
..... return true; // This tells the socket that the message has been processed
..... }
... };
> const js2p = require('js2p');
> let sock = js2p.mesh.MeshSocket('', 4444);
> sock.register_handler(example);

Use In A Browser

There are a few differences if you want to use this in a browser. First, you can only use websockets as a transport layer. That means that any servers which want to listen must have nodejs-websocket installed. The code run in the browser uses the natively supplied WebSocket() implementation.

Browser nodes also cannot receive connections. That means they must connect to a “server” at some point.

Lastly, you do not need to require() this module, it is provided for you in a file. This can be loaded either from the latest release (starting in 0.5), or by cloning the repository and calling make browser.