Improve net/ documentation
This commit is contained in:
parent
084ddc8084
commit
2ae5d40463
|
@ -1,6 +1,9 @@
|
||||||
/**
|
/**
|
||||||
* Networking base module. You should import some transport instead in
|
* Networking base module. Defines base transport interface, useful for
|
||||||
* order to connect/accept connections to/from other nodes.
|
* implementing new transports. End-users should import some transport
|
||||||
|
* instead in order to connect/accept connections to/from other nodes.
|
||||||
|
* **NOTE**: `BaseTransport` is exported as a module.
|
||||||
|
* @example var BaseTransport = require("bitmessage/net/base");
|
||||||
* @module bitmessage/net/base
|
* @module bitmessage/net/base
|
||||||
*/
|
*/
|
||||||
// TODO(Kagami): Write some sort of tutorial.
|
// TODO(Kagami): Write some sort of tutorial.
|
||||||
|
@ -13,7 +16,9 @@ var PPromise = require("../platform").Promise;
|
||||||
var structs = require("../structs");
|
var structs = require("../structs");
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Network transport base class.
|
* Base transport class. Allows to use single class for both client and
|
||||||
|
* server modes (as separate instances).
|
||||||
|
* @param {?Object} opts - Transport options
|
||||||
* @constructor
|
* @constructor
|
||||||
* @static
|
* @static
|
||||||
*/
|
*/
|
||||||
|
@ -25,8 +30,10 @@ inherits(BaseTransport, EventEmitter);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Do the transport-specific bootstrap process and return promise that
|
* Do the transport-specific bootstrap process and return promise that
|
||||||
* contains discovered nodes when fulfilled.
|
* contains discovered nodes when fulfilled (both modes).
|
||||||
* @return {Promise.<Array.>}
|
* NOTE: Do not use nodes received by this method in `addr` messages!
|
||||||
|
* This is meaningless.
|
||||||
|
* @return {Promise.<Array>}
|
||||||
* @abstract
|
* @abstract
|
||||||
*/
|
*/
|
||||||
BaseTransport.prototype.bootstrap = function() {
|
BaseTransport.prototype.bootstrap = function() {
|
||||||
|
@ -34,9 +41,9 @@ BaseTransport.prototype.bootstrap = function() {
|
||||||
};
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Connect to the transport-specific address.
|
* Connect to the transport-specific address. Enters client mode. Should
|
||||||
* Should emit `open` event after successful connect and `established`
|
* emit `open` event after successful connect and `established` event
|
||||||
* event after `verack` messages exchange.
|
* after `verack` messages exchange.
|
||||||
* @abstract
|
* @abstract
|
||||||
*/
|
*/
|
||||||
BaseTransport.prototype.connect = function() {
|
BaseTransport.prototype.connect = function() {
|
||||||
|
@ -44,9 +51,9 @@ BaseTransport.prototype.connect = function() {
|
||||||
};
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Listen for the transport-specific incoming connections.
|
* Listen for the transport-specific incoming connections. Enters server
|
||||||
* Should emit `connection` event with a transport instance for each new
|
* mode. Should emit `connection` event with a transport instance for
|
||||||
* connection.
|
* each new connection.
|
||||||
* @abstract
|
* @abstract
|
||||||
*/
|
*/
|
||||||
BaseTransport.prototype.listen = function() {
|
BaseTransport.prototype.listen = function() {
|
||||||
|
@ -55,9 +62,9 @@ BaseTransport.prototype.listen = function() {
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Send [message]{@link module:bitmessage/structs.message} over the
|
* Send [message]{@link module:bitmessage/structs.message} over the
|
||||||
* wire (client mode).
|
* wire (client mode only).
|
||||||
* @param {(Buffer|string)} msg - Encoded message or command string
|
* @param {(Buffer|string)} msg - Encoded message or command string
|
||||||
* @param (?Buffer} payload - Message payload (used if the first
|
* @param {?Buffer} payload - Message payload (used if the first
|
||||||
* argument is a string)
|
* argument is a string)
|
||||||
* @abstract
|
* @abstract
|
||||||
*/
|
*/
|
||||||
|
@ -67,9 +74,9 @@ BaseTransport.prototype.send = function() {
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Send [message]{@link module:bitmessage/structs.message} to all
|
* Send [message]{@link module:bitmessage/structs.message} to all
|
||||||
* connected clients (server mode).
|
* connected clients (server mode only).
|
||||||
* @param {(Buffer|string)} msg - Encoded message or command string
|
* @param {(Buffer|string)} msg - Encoded message or command string
|
||||||
* @param (?Buffer} payload - Message payload (used if the first
|
* @param {?Buffer} payload - Message payload (used if the first
|
||||||
* argument is a string)
|
* argument is a string)
|
||||||
* @abstract
|
* @abstract
|
||||||
*/
|
*/
|
||||||
|
@ -78,14 +85,14 @@ BaseTransport.prototype.broadcast = function() {
|
||||||
};
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Close connection(s) and/or stop listening.
|
* Close connection(s) and/or stop listening (both modes).
|
||||||
* @abstract
|
* @abstract
|
||||||
*/
|
*/
|
||||||
BaseTransport.prototype.close = function() {
|
BaseTransport.prototype.close = function() {
|
||||||
throw new Error("Not implemented");
|
throw new Error("Not implemented");
|
||||||
};
|
};
|
||||||
|
|
||||||
// Static helpers.
|
// Static private helpers.
|
||||||
|
|
||||||
BaseTransport._getmsg = function(args) {
|
BaseTransport._getmsg = function(args) {
|
||||||
if (typeof args[0] === "string") {
|
if (typeof args[0] === "string") {
|
||||||
|
|
|
@ -1,6 +1,8 @@
|
||||||
/**
|
/**
|
||||||
* TCP transport. Should be compatible with PyBitmessage. Available only
|
* TCP transport compatible with PyBitmessage. Available only for Node
|
||||||
* for Node.js.
|
* platform.
|
||||||
|
* **NOTE**: `TcpTransport` is exported as a module.
|
||||||
|
* @example var TcpTransport = require("bitmessage/net/tcp");
|
||||||
* @module bitmessage/net/tcp
|
* @module bitmessage/net/tcp
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
@ -20,25 +22,26 @@ var getmsg = BaseTransport._getmsg;
|
||||||
var unmap = BaseTransport._unmap;
|
var unmap = BaseTransport._unmap;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* TCP transport constructor.
|
* TCP transport class. Implements
|
||||||
|
* [base transport interface]{@link module:bitmessage/net/base.BaseTransport}.
|
||||||
* @constructor
|
* @constructor
|
||||||
* @static
|
* @static
|
||||||
*/
|
*/
|
||||||
function Transport(opts) {
|
function TcpTransport(opts) {
|
||||||
Transport.super_.call(this);
|
TcpTransport.super_.call(this);
|
||||||
objectAssign(this, opts);
|
objectAssign(this, opts);
|
||||||
this.seeds = this.seeds || [];
|
this.seeds = this.seeds || [];
|
||||||
this.dnsSeeds = this.dnsSeeds || [];
|
this.dnsSeeds = this.dnsSeeds || [];
|
||||||
this._clients = {};
|
this._clients = {};
|
||||||
}
|
}
|
||||||
|
|
||||||
inherits(Transport, BaseTransport);
|
inherits(TcpTransport, BaseTransport);
|
||||||
|
|
||||||
function getfrom(client) {
|
function getfrom(client) {
|
||||||
return unmap(client.remoteAddress) + ":" + client.remotePort;
|
return unmap(client.remoteAddress) + ":" + client.remotePort;
|
||||||
}
|
}
|
||||||
|
|
||||||
Transport.prototype.sendVersion = function() {
|
TcpTransport.prototype._sendVersion = function() {
|
||||||
return this.send(messages.version.encode({
|
return this.send(messages.version.encode({
|
||||||
services: this.services,
|
services: this.services,
|
||||||
userAgent: this.userAgent,
|
userAgent: this.userAgent,
|
||||||
|
@ -49,7 +52,7 @@ Transport.prototype.sendVersion = function() {
|
||||||
}));
|
}));
|
||||||
};
|
};
|
||||||
|
|
||||||
Transport.prototype._setupClient = function(client, accepted) {
|
TcpTransport.prototype._setupClient = function(client, accepted) {
|
||||||
var self = this;
|
var self = this;
|
||||||
self._client = client;
|
self._client = client;
|
||||||
var cache = Buffer(0);
|
var cache = Buffer(0);
|
||||||
|
@ -68,7 +71,7 @@ Transport.prototype._setupClient = function(client, accepted) {
|
||||||
// accepted sockets but let's be sure.
|
// accepted sockets but let's be sure.
|
||||||
if (!accepted) {
|
if (!accepted) {
|
||||||
self.emit("open");
|
self.emit("open");
|
||||||
self.sendVersion();
|
self._sendVersion();
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
|
@ -113,7 +116,7 @@ Transport.prototype._setupClient = function(client, accepted) {
|
||||||
self.send("verack");
|
self.send("verack");
|
||||||
verackSent = true;
|
verackSent = true;
|
||||||
if (accepted) {
|
if (accepted) {
|
||||||
self.sendVersion();
|
self._sendVersion();
|
||||||
} else if (verackReceived) {
|
} else if (verackReceived) {
|
||||||
self.emit("established");
|
self.emit("established");
|
||||||
}
|
}
|
||||||
|
@ -176,7 +179,7 @@ function resolveDnsSeed(seed) {
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
Transport.prototype.bootstrap = function() {
|
TcpTransport.prototype.bootstrap = function() {
|
||||||
var promises = this.dnsSeeds.map(resolveDnsSeed);
|
var promises = this.dnsSeeds.map(resolveDnsSeed);
|
||||||
var hardcodedNodes = this.seeds;
|
var hardcodedNodes = this.seeds;
|
||||||
// FIXME(Kagami): Filter incorrect/private IP range nodes?
|
// FIXME(Kagami): Filter incorrect/private IP range nodes?
|
||||||
|
@ -190,13 +193,22 @@ Transport.prototype.bootstrap = function() {
|
||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
|
||||||
Transport.prototype.connect = function() {
|
/**
|
||||||
|
* Connect to a TCP node. Connection arguments are the same as for
|
||||||
|
* [net.connect](http://nodejs.org/api/net.html#net_net_connect_port_host_connectlistener).
|
||||||
|
*/
|
||||||
|
TcpTransport.prototype.connect = function() {
|
||||||
assert(!this._client, "Already connected");
|
assert(!this._client, "Already connected");
|
||||||
assert(!this._server, "Already listening");
|
assert(!this._server, "Already listening");
|
||||||
this._setupClient(net.connect.apply(null, arguments));
|
this._setupClient(net.connect.apply(null, arguments));
|
||||||
};
|
};
|
||||||
|
|
||||||
Transport.prototype.listen = function() {
|
/**
|
||||||
|
* Listen for incoming TCP connections. Listen arguments are the same as
|
||||||
|
* for
|
||||||
|
* [server.listen](http://nodejs.org/api/net.html#net_server_listen_port_host_backlog_callback).
|
||||||
|
*/
|
||||||
|
TcpTransport.prototype.listen = function() {
|
||||||
assert(!this._client, "Already connected");
|
assert(!this._client, "Already connected");
|
||||||
assert(!this._server, "Already listening");
|
assert(!this._server, "Already listening");
|
||||||
|
|
||||||
|
@ -241,7 +253,7 @@ Transport.prototype.listen = function() {
|
||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
|
||||||
Transport.prototype.send = function() {
|
TcpTransport.prototype.send = function() {
|
||||||
if (this._client) {
|
if (this._client) {
|
||||||
this._client.write(getmsg(arguments));
|
this._client.write(getmsg(arguments));
|
||||||
} else {
|
} else {
|
||||||
|
@ -249,7 +261,7 @@ Transport.prototype.send = function() {
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
Transport.prototype.broadcast = function() {
|
TcpTransport.prototype.broadcast = function() {
|
||||||
var data = getmsg(arguments);
|
var data = getmsg(arguments);
|
||||||
if (this._server) {
|
if (this._server) {
|
||||||
Object.keys(this._clients).forEach(function(ip) {
|
Object.keys(this._clients).forEach(function(ip) {
|
||||||
|
@ -260,7 +272,7 @@ Transport.prototype.broadcast = function() {
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
Transport.prototype.close = function() {
|
TcpTransport.prototype.close = function() {
|
||||||
if (this._client) {
|
if (this._client) {
|
||||||
this._client.end();
|
this._client.end();
|
||||||
} else if (this._server) {
|
} else if (this._server) {
|
||||||
|
@ -271,4 +283,4 @@ Transport.prototype.close = function() {
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
module.exports = Transport;
|
module.exports = TcpTransport;
|
||||||
|
|
|
@ -12,19 +12,19 @@ var structs = require("../structs");
|
||||||
var messages = require("../messages");
|
var messages = require("../messages");
|
||||||
var BaseTransport = require("./base");
|
var BaseTransport = require("./base");
|
||||||
|
|
||||||
function Transport(opts) {
|
function WsTransport(opts) {
|
||||||
Transport.super_.call(this);
|
WsTransport.super_.call(this);
|
||||||
objectAssign(this, opts);
|
objectAssign(this, opts);
|
||||||
this.seeds = this.seeds || [];
|
this.seeds = this.seeds || [];
|
||||||
}
|
}
|
||||||
|
|
||||||
inherits(Transport, BaseTransport);
|
inherits(WsTransport, BaseTransport);
|
||||||
|
|
||||||
Transport.prototype.bootstrap = function() {
|
WsTransport.prototype.bootstrap = function() {
|
||||||
return Promise.resolve([].concat(this.seeds));
|
return Promise.resolve([].concat(this.seeds));
|
||||||
};
|
};
|
||||||
|
|
||||||
Transport.prototype.connect = function(url, protocols) {
|
WsTransport.prototype.connect = function(url, protocols) {
|
||||||
var self = this;
|
var self = this;
|
||||||
assert(!self._client, "Already connected");
|
assert(!self._client, "Already connected");
|
||||||
|
|
||||||
|
@ -95,7 +95,7 @@ Transport.prototype.connect = function(url, protocols) {
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
|
||||||
Transport.prototype.send = function() {
|
WsTransport.prototype.send = function() {
|
||||||
if (this._client) {
|
if (this._client) {
|
||||||
this._client.send(BaseTransport._getmsg(arguments));
|
this._client.send(BaseTransport._getmsg(arguments));
|
||||||
} else {
|
} else {
|
||||||
|
@ -103,10 +103,10 @@ Transport.prototype.send = function() {
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
Transport.prototype.close = function() {
|
WsTransport.prototype.close = function() {
|
||||||
if (this._client) {
|
if (this._client) {
|
||||||
this._client.close();
|
this._client.close();
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
module.exports = Transport;
|
module.exports = WsTransport;
|
||||||
|
|
|
@ -1,7 +1,9 @@
|
||||||
/**
|
/**
|
||||||
* WebSocket transport. Needed because browsers can't handle TCP sockets
|
* WebSocket transport. Needed because browsers can't handle TCP sockets
|
||||||
* so we use separate WebSocket server to proxy messages into TCP data
|
* so we use separate WebSocket server to proxy messages into TCP data
|
||||||
* packets.
|
* packets. Available for both Node.js and Browser platforms.
|
||||||
|
* **NOTE**: `WsTransport` is exported as a module.
|
||||||
|
* @example var WsTransport = require("bitmessage/net/ws");
|
||||||
* @module bitmessage/net/ws
|
* @module bitmessage/net/ws
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
@ -21,23 +23,24 @@ var getmsg = BaseTransport._getmsg;
|
||||||
var unmap = BaseTransport._unmap;
|
var unmap = BaseTransport._unmap;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* WebSocket transport constructor.
|
* WebSocket transport class. Implements
|
||||||
|
* [base transport interface]{@link module:bitmessage/net/base.BaseTransport}.
|
||||||
* @constructor
|
* @constructor
|
||||||
* @static
|
* @static
|
||||||
*/
|
*/
|
||||||
function Transport(opts) {
|
function WsTransport(opts) {
|
||||||
Transport.super_.call(this);
|
WsTransport.super_.call(this);
|
||||||
objectAssign(this, opts);
|
objectAssign(this, opts);
|
||||||
this.seeds = this.seeds || [];
|
this.seeds = this.seeds || [];
|
||||||
}
|
}
|
||||||
|
|
||||||
inherits(Transport, BaseTransport);
|
inherits(WsTransport, BaseTransport);
|
||||||
|
|
||||||
function getfrom(client) {
|
function getfrom(client) {
|
||||||
return unmap(client._socket.remoteAddress) + ":" + client._socket.remotePort;
|
return unmap(client._socket.remoteAddress) + ":" + client._socket.remotePort;
|
||||||
}
|
}
|
||||||
|
|
||||||
Transport.prototype.sendVersion = function() {
|
WsTransport.prototype._sendVersion = function() {
|
||||||
return this.send(messages.version.encode({
|
return this.send(messages.version.encode({
|
||||||
services: this.services,
|
services: this.services,
|
||||||
userAgent: this.userAgent,
|
userAgent: this.userAgent,
|
||||||
|
@ -48,7 +51,7 @@ Transport.prototype.sendVersion = function() {
|
||||||
}));
|
}));
|
||||||
};
|
};
|
||||||
|
|
||||||
Transport.prototype._handleTimeout = function() {
|
WsTransport.prototype._handleTimeout = function() {
|
||||||
var client = this._client;
|
var client = this._client;
|
||||||
// TODO(Kagami): We may also want to close connection if it wasn't
|
// TODO(Kagami): We may also want to close connection if it wasn't
|
||||||
// established within minute.
|
// established within minute.
|
||||||
|
@ -63,7 +66,7 @@ Transport.prototype._handleTimeout = function() {
|
||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
|
||||||
Transport.prototype._setupClient = function(client, accepted) {
|
WsTransport.prototype._setupClient = function(client, accepted) {
|
||||||
var self = this;
|
var self = this;
|
||||||
self._client = client;
|
self._client = client;
|
||||||
var verackSent = false;
|
var verackSent = false;
|
||||||
|
@ -79,7 +82,7 @@ Transport.prototype._setupClient = function(client, accepted) {
|
||||||
// `_setupClient` is called.
|
// `_setupClient` is called.
|
||||||
self._handleTimeout();
|
self._handleTimeout();
|
||||||
self.emit("open");
|
self.emit("open");
|
||||||
self.sendVersion();
|
self._sendVersion();
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
|
@ -113,7 +116,7 @@ Transport.prototype._setupClient = function(client, accepted) {
|
||||||
self.send("verack");
|
self.send("verack");
|
||||||
verackSent = true;
|
verackSent = true;
|
||||||
if (accepted) {
|
if (accepted) {
|
||||||
self.sendVersion();
|
self._sendVersion();
|
||||||
} else if (verackReceived) {
|
} else if (verackReceived) {
|
||||||
established = true;
|
established = true;
|
||||||
self.emit("established");
|
self.emit("established");
|
||||||
|
@ -138,11 +141,15 @@ Transport.prototype._setupClient = function(client, accepted) {
|
||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
|
||||||
Transport.prototype.bootstrap = function() {
|
WsTransport.prototype.bootstrap = function() {
|
||||||
return PPromise.resolve([].concat(this.seeds));
|
return PPromise.resolve([].concat(this.seeds));
|
||||||
};
|
};
|
||||||
|
|
||||||
Transport.prototype.connect = function(address, protocols, options) {
|
/**
|
||||||
|
* Connect to a WebSocket node. Connection arguments are the same as for
|
||||||
|
* [WebSocket](https://developer.mozilla.org/en-US/docs/Web/API/WebSocket).
|
||||||
|
*/
|
||||||
|
WsTransport.prototype.connect = function(address, protocols, options) {
|
||||||
assert(!this._client, "Already connected");
|
assert(!this._client, "Already connected");
|
||||||
assert(!this._server, "Already listening");
|
assert(!this._server, "Already listening");
|
||||||
// `new` doesn't work with `apply`, so passing all possible arguments
|
// `new` doesn't work with `apply`, so passing all possible arguments
|
||||||
|
@ -150,7 +157,13 @@ Transport.prototype.connect = function(address, protocols, options) {
|
||||||
this._setupClient(new WebSocket(address, protocols, options));
|
this._setupClient(new WebSocket(address, protocols, options));
|
||||||
};
|
};
|
||||||
|
|
||||||
Transport.prototype.listen = function(options, callback) {
|
/**
|
||||||
|
* Listen for incoming WebSocket connections. Listen arguments are the
|
||||||
|
* same as for
|
||||||
|
* [WebSocketServer](https://github.com/websockets/ws#server-example).
|
||||||
|
* Available only for Node platform.
|
||||||
|
*/
|
||||||
|
WsTransport.prototype.listen = function(options, callback) {
|
||||||
assert(!this._client, "Already connected");
|
assert(!this._client, "Already connected");
|
||||||
assert(!this._server, "Already listening");
|
assert(!this._server, "Already listening");
|
||||||
|
|
||||||
|
@ -195,7 +208,7 @@ Transport.prototype.listen = function(options, callback) {
|
||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
|
||||||
Transport.prototype.send = function() {
|
WsTransport.prototype.send = function() {
|
||||||
if (this._client) {
|
if (this._client) {
|
||||||
// TODO(Kagami): `mask: true` doesn't work with Chromium 40. File a
|
// TODO(Kagami): `mask: true` doesn't work with Chromium 40. File a
|
||||||
// bug to ws bugtracker.
|
// bug to ws bugtracker.
|
||||||
|
@ -205,7 +218,7 @@ Transport.prototype.send = function() {
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
Transport.prototype.broadcast = function() {
|
WsTransport.prototype.broadcast = function() {
|
||||||
var data = getmsg(arguments);
|
var data = getmsg(arguments);
|
||||||
if (this._server) {
|
if (this._server) {
|
||||||
this._server.clients.forEach(function(client) {
|
this._server.clients.forEach(function(client) {
|
||||||
|
@ -216,7 +229,7 @@ Transport.prototype.broadcast = function() {
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
Transport.prototype.close = function() {
|
WsTransport.prototype.close = function() {
|
||||||
if (this._client) {
|
if (this._client) {
|
||||||
this._client.close();
|
this._client.close();
|
||||||
} else if (this._server) {
|
} else if (this._server) {
|
||||||
|
@ -227,4 +240,4 @@ Transport.prototype.close = function() {
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
module.exports = Transport;
|
module.exports = WsTransport;
|
||||||
|
|
Loading…
Reference in New Issue
Block a user