@the3rdc/netshout

1.4.3 • Public • Published

NetShout

Broadcast and subscribe to simple messages over node's net sockets.

Getting Started

npm i @the3rdc/netshout
const NetShout = require('@the3rdc/netshout');

var strongPeer = new NetShout();

var weakPeer = new NetShout();

weakPeer.subscribe('sampleEvent',function(body){
  console.log("I Received:", body);
});

strongPeer.startHosting(1987,function(){
  weakPeer.connectTo('localhost',1987, function(){
    strongPeer.shout('sampleEvent',"Hello everyone!");
  });
});

Why This Exists

I needed a way to abstract the connection of arbitray nodes, and allow one way communication (out) from any node to it's neighbors.

It needed to function both on a linux server and in an "electron" or other native framework app on Mac, Windows, etc.

It needed to allow for some of the peers to be unable to receive incoming connections (ex: firewalls).

Documentation (especially good examples) on using Node JS "net" package were hard to find, and abstractions for inter-node communication were either too specific or included features that I did not need.

Documentation

Instantiation

const NetShout = require('@the3rdc/netshout');

var peer = new NetShout();

Hosting a Connection

var strongPeer = new NetShout();

var port = 1987;

strongPeer.startHosting(port, function(){
  console.log("I'm ready to accept connections on port " + port);
});

Connecting to a Host

var peer = new NetShout();
var address = '127.0.0.1';
var port = 1987;

peer.connectTo(address, port, function(){
  console.log("I'm connected to " + address + ':' + port);
});

Closing Connections

//closes the specified connection
peer.disconnectFrom(address, port);

//closes all connections
peer.disconnectAll();

//stops accepting incoming connections
peer.stopHosting();

//wrapper for diconnectAll() followed by stopHosting()
peer.shutDown();

Strong vs Weak Peers

A "Strong" peer in NetShout is simply a peer that can accept incoming connections. It can act as a host using the .startHosting() function. A "Weak" peer is one that can connect "out" to other nodes, but cannot let them connect "in" (ex: behind a network firewall). A node may be considered a "Strong Peer" within a local network, and a "weak" peer in relation to an external network. In order for two nodes to communicate, at least one of them must be "Strong".

However, once two nodes are connected, there is no difference in functionality. Both and can send messages via .shout() and subscribe to messages via .subscribe().

It's tempting to think of Strong and weak peers as a "Client/Server" framework, and this is accurate for a relationship between a single strong and weak peer. However, strong peers can connect to other strong peers, and a weak peer can connect to more than one strong peer.

It is likely that a given node's neighbors will be a mix of strong and weak peers.

Broadcast a Message

This will send a message to all neighbors. Type can be any string, and should be used to categorize the message.

(This will always send to all neighbors. NetShout does not currently provide a method for messaging a single peer.)

var type = 'example';
var message = 'hello there!';
peer.shout(type, message);

Subscribe to Message

The callback wil be fired when a message with the specified type is recieved from any neighbor.

(This will fire for all neighbors. NetShout does not currently provide a method for subscribing to a single peer.)

peer.subscribe('example',function(message){
  console.log("I received the message: ", message);
});

Multi Peer Example

In the below example, we create 2 "strong" and 2 "weak" peers. Both strong peers begin hosting connections, and both weak peers connect to both of them. The first strong peer also connects to the second.

You should see that when strongPeer1 sends out a message with .shout(), all three of the other peers receive it. It does not matter that strongPeer1 connected to strongPeer2 as opposed to the other way around. Once established, all connections can send from either side.

You should see that when weakPeer1 sendso ut a message with .shout(), only the two StrongPeers recieve it. This represents a scenario where some peers are not able to host - so weakPeer1 has a connection to both strong peers, but no connection to weakPeer2.

(Note, either strong peer could create a path from weakPeer1 to weakPeer2 but re-broadcasting their messages.)

const NetShout = require('@the3rdc/netshout');

var strongPeer1 = new NetShout();
var port1 = 1987;
var strongPeer2 = new NetShout();
var port2 = 1337;

var weakPeer1 = new NetShout();
var weakPeer2 = new NetShout();

function startHosing(){
  return new Promise(function(resolve, reject){
    var ready1 = false;
    var ready2 = false;
    strongPeer1.startHosting(port1, function(){
      //strong peer 1 is ready to receive connections
      ready1 = true;
      if(ready2){
        resolve();
      }
    });
    strongPeer2.startHosting(port2, function(){
      //strong peer 2 is ready to receive connections
      ready2 = true;
      if(ready1){
        resolve();
      }
    });
  });
}

function getConnected(){
  return new Promise(function(resolve, reject){
    var ready1 = false;
    var ready2 = false;
    var ready3 = false;
    var ready4 = false;
    var ready5 = false;

    weakPeer1.connectTo('localhost', port1,function(){
      ready1 = true;
      if(ready1 && ready2 && ready3 && ready4 && ready5){
        resolve();
      }
    }); //connected to strong 1
    weakPeer1.connectTo('localhost', port2,function(){
      ready2 = true;
      if(ready1 && ready2 && ready3 && ready4 && ready5){
        resolve();
      }
    }); //connected to strong 2

    weakPeer2.connectTo('localhost', port1,function(){
      ready3 = true;
      if(ready1 && ready2 && ready3 && ready4 && ready5){
        resolve();
      }
    }); //connected to strong 1
    weakPeer2.connectTo('localhost', port2,function(){
      ready4 = true;
      if(ready1 && ready2 && ready3 && ready4 && ready5){
        resolve();
      }
    }); //connected to strong 2

    strongPeer1.connectTo('localhost',port2,function(){
      ready5 = true;
      if(ready1 && ready2 && ready3 && ready4 && ready5){
        resolve();
      }
    }); //connected to strong 2
  });
}

startHosing().then(function(){
  getConnected().then(function(){
    weakPeer1.subscribe('ping',function(message){
      console.log('weak1 got: ', message);
    });
    weakPeer2.subscribe('ping',function(message){
      console.log('weak2 got: ', message);
    });
    strongPeer1.subscribe('ping',function(message){
      console.log('strong1 got: ', message);
    });
    strongPeer2.subscribe('ping',function(message){
      console.log('strong2 got: ', message);
    });

    strongPeer1.shout('ping','hello');
    weakPeer1.shout('ping','hi yourself');
  });
});

Version 1 Roadmap

  • Handle deduping of neighbors (currently if I connect to you, then you connect to me, we'll each list eachother twice...)

Roadmap for v2.0

(Seems a little soon for a v2, but these will be breaking changes, so...)

  1. Replace callBack pattern on .startHosting() and .connectTo() with a promise pattern.
  2. Add a context variable to subscription callbacks to identify which peer the message came from.
  3. Add the ability to message a specific neighbor instead of everyone.
  4. Add the ability to message everyone except the node you received a message from (within a subscription callback).

Package Sidebar

Install

npm i @the3rdc/netshout

Weekly Downloads

1

Version

1.4.3

License

ISC

Unpacked Size

24.6 kB

Total Files

4

Last publish

Collaborators

  • the3rdc