discover-tcp-transport

Node discovery TCP transport

npm install discover-tcp-transport
24 downloads in the last month

discover-tcp-transport

Stability: 1 - Experimental

NPM version

TCP transport for Discover, a distributed master-less node discovery mechanism that enables locating any entity (server, worker, drone, actor) based on node id.

Contributors

@tristanls, @mikedeboer, @skeggse

Installation

npm install discover-tcp-transport

Tests

npm test

Overview

Discover TCP transport implements the Discover transport protocol consisting of a stripped down version of the Kademlia DHT protocol, PING and FIND-NODE. The TCP transport reports a node as unreachable if a connection cannot be established with it.

NOTE: Unreachability of nodes depends on the transport. For example, other transports (like TLS transport) could use other criteria (like invalid certificate) for reporting unreachable nodes.

WARNING: Using TCP transport is meant primarily for development in a development environment. TCP transport exists because it is a low hanging fruit. It is most likely that it should be replaced with DTLS transport in production (maybe TLS if DTLS is not viable). There may also be a use-case for using UDP transport if communicating nodes are on a VPN/VPC. Only if UDP on a VPN/VPC seems not viable, should TCP transport be considered.

Documentation

TcpTransport

Public API

TcpTransport.listen(options, callback)

  • options: See new TcpTransport(options) options.
  • callback: See tcpTransport.listen(callback) callback.
  • Return: Object An instance of TcpTransport with server running.

Creates new TCP transport and starts the server.

new TcpTransport(options)

  • options:
    • host: String (Default: 'localhost')
    • port: Integer (Default: 6742) A port value of zero will assign a random port.

Creates a new TCP transport.

tcpTransport.close(callback)

  • callback: Function (Default: undefined) Optional callback to call once the server is stopped.

Stops the server from listening to requests from other nodes.

tcpTransport.findNode(contact, nodeId, sender)

  • contact: Object The node to contact with request to find nodeId.
    • id: String (base64) Base64 encoded contact node id.
    • transport: Object TCP transport data.
      • host: String IP address to connect to.
      • port: Integer Port to connect to.
  • nodeId: String (base64) Base64 encoded string representation of the node id to find.
  • sender: Object The node making the request
    • id: String (base64) Base64 encoded sender node id.
    • data: Any Sender node data.
    • transport: Object TCP transport data.
      • host: String Host to connect to.
      • port: Integer Port to connect to.

Issues a FIND-NODE request to the contact. In other words, sends FIND-NODE request to the contact at contact.host and contact.port using TCP. The transport will emit node event when a response is processed (or times out).

tcpTransport.listen(callback)

  • callback: Function (Default: undefined) Optional callback to call once the server is up.

Starts the server to listen to requests from other nodes.

tcpTransport.ping(contact, sender)

  • contact: Object Contact to ping.
    • id: String (base64) Base64 encoded contact node id.
    • transport: Object TCP transport data.
      • host: String Host to connect to.
      • port: Integer Port to connect to.
  • sender: Object The contact making the request.
    • id: String (base64) Base64 encoded sender node id.
    • data: Any Sender node data.
    • transport: Object TCP transport data.
      • host: String Host of the sender.
      • port: Integer Port of the sender.

Issues a PING request to the contact. In other words, pings the contact at the contact.transport.host and contact.transport.port using TCP. The transport will emit unreachable event if the contact is deemed to be unreachable, or reached event otherwise.

tcpTransport.rpc(contact, payload, callback)

CAUTION: reserved for internal use

  • contact: Object Contact to ping.
    • id: String (base64) Base64 encoded contact node id.
    • transport: Object TCP transport data.
      • host: String Host to connect to.
      • port: Integer Port to connect to.
  • payload: String or Object Payload to send on the wire. If an Object is provided, it will be JSON.stringify()'ed.
  • callback: Function Callback to call with an error or response.

An internal common implementation for tcpTransport.findNode(...) and tcpTransport.ping(...).

tcpTransport.setTransportInfo(contact)

  • contact: Object A contact.
  • Return: Object contact with contact.transport populated.

Sets contact.transport to TCP transport configured values. For example:

var contact = {id: 'id', data: 'data'};
var tcpTransport = new TcpTransport({host: 'foo.com', port: 8888});
contact = tcpTransport.setTransportInfo(contact);
assert.ok(contact.transport.host === 'foo.com'); // true
assert.ok(contact.transport.port === 8888); // true

Event: findNode

  • nodeId: String (base64) Base64 encoded string representation of the node id to find.
  • sender: Object The contact making the request.
    • id: String (base64) Base64 encoded sender node id.
    • data: Any Sender node data.
    • transport: Object TCP transport data.
      • host: String Host of the sender.
      • port: Integer Port of the sender.
  • callback: Function The callback to call with the result of processing the FIND-NODE request.
    • error: Error An error, if any.
    • response: Object or Array The response to FIND-NODE request.

Emitted when another node issues a FIND-NODE request to this node.

var TcpTransport = require('discover-tcp-transport');
var tcpTransport = new TcpTransport();
tcpTransport.on('findNode', function (nodeId, sender, callback) {
    // ... find closestNodes to the desired nodeId
    return callback(null, closestNodes);
});

In the above example closestNodes is an Array of contacts that are closest known to the desired nodeId.

If the node handling the request itself contains the nodeId, then it sends only itself back.

var TcpTransport = require('discover-tcp-transport');
var tcpTransport = new TcpTransport();
tcpTransport.on('findNode', function (nodeId, sender, callback) {
    // ... this node knows the node with nodeId or is itself node with nodeId
    return callback(null, nodeWithNodeId);
});

In the above example, nodeWithNodeId is not an array, but an individual contact representing the answer to findNode query.

Event: node

  • error: Error An error, if one occurred.
  • contact: Object The node that FIND-NODE request was sent to.
  • nodeId: String (base64) The original base64 encoded node id requested to be found.
  • response: Object or Array The response from the queried contact.

If error occurs, the transport encountered an error when issuing the findNode request to the contact. contact and nodeId will also be provided in case of an error. response is undefined if an error occurs.

response will be an Array if the contact does not contain the nodeId requested. In this case response will be a contact list of nodes closer to the nodeId that the queried node is aware of. The usual step is to next query the returned contacts with the FIND-NODE request.

response will be an Object if the contact contains the nodeId. In other words, the node has been found.

Event: ping

  • nodeId: String (base64) Base64 encoded string representation of the node id being pinged.
  • sender: Object The contact making the request.
    • id: String (base64) Base64 encoded sender node id.
    • data: Any Sender node data.
    • transport: Object TCP transport data.
      • host: String Host of the sender.
      • port: Integer Port of the sender.
  • callback: Function The callback to call with the result of processing the PING request.
    • error: Error An error, if any.
    • response: Object The response to PING request, if any.

Emitted when another node issues a PING request to this node.

var TcpTransport = require('discover-tcp-transport');
var tcpTransport = new TcpTransport();
tcpTransport.on('ping', function (nodeId, sender, callback) {
    // ... verify that we have the exact node specified by nodeId
    return callback(null, contact);
});

In the above example contact is an Object representing the answer to ping query.

If the exact node specified by nodeId does not exist, an error shall be returned as shown below:

var TcpTransport = require('discover-tcp-transport');
var tcpTransport = new TcpTransport();
tcpTransport.on('ping', function (nodeId, sender, callback) {
    // ...we don't have the nodeId specified
    return callback(true);
});

Event: reached

  • contact: Object The contact that was reached when pinged.
    • id: String (base64) Base64 encoded contact node id.
    • data: Any Data included with the contact.
    • transport: Object TCP transport data.
      • host: String Host of reached contact.
      • port: Integer port of reached contact.

Emitted when a previously pinged contact is deemed reachable by the transport.

Event: unreachable

  • contact: Object The contact that was unreachable when pinged.
    • id: String (base64) Base64 encoded contact node id.
    • transport: Object TCP transport data.
      • host: String Host of unreachable contact.
      • port: Integer port of unreachable contact.

Emitted when a previously pinged contact is deemed unreachable by the transport.

Wire Protocol

Wire protocol for TCP transport is simple one-line \r\n terminated ASCII.

FIND-NODE

{"request":{"findNode":"Zm9v"},"sender":{"id":"YmF6","data":"some data","transport":{"host":"127.0.0.1","port":6742}}}\r\n

FIND-NODE request consists of a JSON object with base64 encoded node id and a sender followed by \r\n as shown above.

Object Response

{"id":"Zm9v","data":"some data","transport":{"host":"127.0.0.1","port":6742}}\r\n

An Object response is JSON representation of the contact followed by \r\n.

Array Response

[{"id":"YmFy","data":"some data","transport":{"host":"192.168.0.1","port":6742}},{"id":"YmF6","data":"some data","transport":{"host":"192.168.0.2","port":6742}}]\r\n

An Array response is JSON representation of an array of closest contacts followed by \r\n.

PING

{"request":{"ping":"Zm9v"},"sender":{"id":"YmF6","data":"some data","transport":{"host":"127.0.0.1","port":6742}}}\r\n

PING request consists of a JSON object with base64 encoded node id and a sender followed by \r\n as shown above.

Object Response

{"id":"Zm9v","data":"some data","transport":{"host":"127.0.0.1","port":6742}}\r\n

An Object response is JSON representation of the pinged contact followed by \r\n.

Failure Responses

Closing the connection without an object response or inability to connect in the first place indicates a PING failure.

npm loves you