Add encodePayload/decodePayload to messages module
This commit is contained in:
parent
874acfac45
commit
514265b7cd
124
lib/messages.js
124
lib/messages.js
|
@ -9,29 +9,44 @@
|
|||
|
||||
"use strict";
|
||||
|
||||
var objectAssign = Object.assign || require("object-assign");
|
||||
var assert = require("./_util").assert;
|
||||
var structs = require("./structs");
|
||||
var UserAgent = require("./user-agent");
|
||||
var util = require("./_util");
|
||||
|
||||
var message = structs.message;
|
||||
var ServicesBitfield = structs.ServicesBitfield;
|
||||
|
||||
/**
|
||||
* `version` message.
|
||||
* @see {@link https://bitmessage.org/wiki/Protocol_specification#version}
|
||||
* @namespace
|
||||
* @static
|
||||
*/
|
||||
exports.version = {
|
||||
var version = exports.version = {
|
||||
/** Random nonce used to detect connections to self. */
|
||||
NONCE: new Buffer("20bde0a3355dad78", "hex"),
|
||||
|
||||
/**
|
||||
* Decode `version` message.
|
||||
* NOTE: `nonce` is copied.
|
||||
* @param {Buffer} buf - Message
|
||||
* @return {Object} Decoded `version` structure.
|
||||
*/
|
||||
decode: function(buf) {
|
||||
var decoded = message.decode(buf);
|
||||
assert(decoded.command === "version", "Bad command");
|
||||
return version.decodePayload(decoded.payload);
|
||||
},
|
||||
|
||||
/**
|
||||
* Decode `version` message payload.
|
||||
* NOTE: `nonce` is copied.
|
||||
* @param {Buffer} buf - Message payload
|
||||
* @return {Object} Decoded `version` structure.
|
||||
*/
|
||||
decode: function(buf) {
|
||||
decodePayload: function(buf) {
|
||||
// 4 + 8 + 8 + 26 + 26 + 8 + (1+) + (1+)
|
||||
assert(buf.length >= 82, "Buffer is too small");
|
||||
var protoVersion = buf.readUInt32BE(0, true);
|
||||
|
@ -62,17 +77,27 @@ exports.version = {
|
|||
};
|
||||
},
|
||||
|
||||
/**
|
||||
* Encode `version` message.
|
||||
* @param {Object} opts - Version options
|
||||
* @return {Buffer} Encoded message.
|
||||
*/
|
||||
encode: function(opts) {
|
||||
var payload = version.encodePayload(opts);
|
||||
return message.encode("version", payload);
|
||||
},
|
||||
|
||||
/**
|
||||
* Encode `version` message payload.
|
||||
* @param {Object} opts - Version options
|
||||
* @return {Buffer} Encoded payload.
|
||||
*/
|
||||
encode: function(opts) {
|
||||
encodePayload: function(opts) {
|
||||
// Deal with default options.
|
||||
var services = opts.services ||
|
||||
ServicesBitfield().set(ServicesBitfield.NODE_NETWORK);
|
||||
var time = opts.time || new Date();
|
||||
var nonce = opts.nonce || exports.version.NONCE;
|
||||
var nonce = opts.nonce || version.NONCE;
|
||||
assert(nonce.length === 8, "Bad nonce");
|
||||
var userAgent = opts.userAgent || UserAgent.SELF;
|
||||
var streamNumbers = opts.streamNumbers || [1];
|
||||
|
@ -108,14 +133,26 @@ exports.version = {
|
|||
* `addr` message. Provide information on known nodes of the network.
|
||||
* @see {@link https://bitmessage.org/wiki/Protocol_specification#addr}
|
||||
* @namespace
|
||||
* @static
|
||||
*/
|
||||
exports.addr = {
|
||||
var addr = exports.addr = {
|
||||
/**
|
||||
* Decode `addr` message.
|
||||
* @param {Buffer} buf - Message
|
||||
* @return {Object} Decoded `addr` structure.
|
||||
*/
|
||||
decode: function(buf) {
|
||||
var decoded = message.decode(buf);
|
||||
assert(decoded.command === "addr", "Bad command");
|
||||
return addr.decodePayload(decoded.payload);
|
||||
},
|
||||
|
||||
/**
|
||||
* Decode `addr` message payload.
|
||||
* @param {Buffer} buf - Message payload
|
||||
* @return {Object} Decoded `addr` structure.
|
||||
*/
|
||||
decode: function(buf) {
|
||||
decodePayload: function(buf) {
|
||||
var decoded = structs.var_int.decode(buf);
|
||||
var listLength = decoded.value;
|
||||
assert(listLength <= 1000, "Too many address entires");
|
||||
|
@ -133,12 +170,22 @@ exports.addr = {
|
|||
};
|
||||
},
|
||||
|
||||
/**
|
||||
* Encode `addr` message.
|
||||
* @param {Object[]} addrs - Network addresses
|
||||
* @return {Buffer} Encoded message.
|
||||
*/
|
||||
encode: function(addrs) {
|
||||
var payload = addr.encodePayload(addrs);
|
||||
return message.encode("addr", payload);
|
||||
},
|
||||
|
||||
/**
|
||||
* Encode `addr` message payload.
|
||||
* @param {Object[]} addrs - Network addresses
|
||||
* @return {Buffer} Encoded payload.
|
||||
*/
|
||||
encode: function(addrs) {
|
||||
encodePayload: function(addrs) {
|
||||
assert(addrs.length <= 1000, "Too many address entires");
|
||||
var addrsBuf = Buffer.concat(addrs.map(structs.net_addr.encode));
|
||||
return Buffer.concat([structs.var_int.encode(addrs.length), addrsBuf]);
|
||||
|
@ -153,12 +200,23 @@ exports.addr = {
|
|||
* @static
|
||||
*/
|
||||
var inv = exports.inv = {
|
||||
/**
|
||||
* Decode `inv` message.
|
||||
* @param {Buffer} buf - Message
|
||||
* @return {Object} Decoded `inv` structure.
|
||||
*/
|
||||
decode: function(buf) {
|
||||
var decoded = message.decode(buf);
|
||||
assert(decoded.command === "inv", "Bad command");
|
||||
return inv.decodePayload(decoded.payload);
|
||||
},
|
||||
|
||||
/**
|
||||
* Decode `inv` message payload.
|
||||
* @param {Buffer} buf - Message payload
|
||||
* @return {Object} Decoded `inv` structure.
|
||||
*/
|
||||
decode: function(buf) {
|
||||
decodePayload: function(buf) {
|
||||
var decoded = structs.var_int.decode(buf);
|
||||
var listLength = decoded.value;
|
||||
assert(listLength <= 50000, "Too many inventory entires");
|
||||
|
@ -176,12 +234,22 @@ var inv = exports.inv = {
|
|||
};
|
||||
},
|
||||
|
||||
/**
|
||||
* Encode `inv` message.
|
||||
* @param {Buffer[]} inventory - Inventory vector list (encoded)
|
||||
* @return {Buffer} Encoded message.
|
||||
*/
|
||||
encode: function(inventory) {
|
||||
var payload = inv.encodePayload(inventory);
|
||||
return message.encode("inv", payload);
|
||||
},
|
||||
|
||||
/**
|
||||
* Encode `inv` message payload.
|
||||
* @param {Buffer[]} inventory - Inventory vector list (encoded)
|
||||
* @return {Buffer} Encoded payload.
|
||||
*/
|
||||
encode: function(inventory) {
|
||||
encodePayload: function(inventory) {
|
||||
assert(inventory.length <= 50000, "Too many inventory entires");
|
||||
var invBuf = Buffer.concat(inventory);
|
||||
return Buffer.concat([structs.var_int.encode(inventory.length), invBuf]);
|
||||
|
@ -195,12 +263,23 @@ var inv = exports.inv = {
|
|||
* @see {@link https://bitmessage.org/wiki/Protocol_specification#getdata}
|
||||
* @namespace
|
||||
*/
|
||||
exports.getdata = inv;
|
||||
exports.getdata = objectAssign({}, inv, {
|
||||
decode: function(buf) {
|
||||
var decoded = message.decode(buf);
|
||||
assert(decoded.command === "getdata", "Bad command");
|
||||
return inv.decodePayload(decoded.payload);
|
||||
},
|
||||
encode: function(inventory) {
|
||||
var payload = inv.encodePayload(inventory);
|
||||
return message.encode("getdata", payload);
|
||||
},
|
||||
});
|
||||
|
||||
/**
|
||||
* `error` message.
|
||||
* @see {@link https://bitmessage.org/wiki/Protocol_specification_v3#error}
|
||||
* @namespace
|
||||
* @static
|
||||
*/
|
||||
var error = exports.error = {
|
||||
/**
|
||||
|
@ -219,12 +298,23 @@ var error = exports.error = {
|
|||
*/
|
||||
FATAL: 2,
|
||||
|
||||
/**
|
||||
* Decode `error` message.
|
||||
* @param {Buffer} buf - Message
|
||||
* @return {Object} Decoded `error` structure.
|
||||
*/
|
||||
decode: function(buf) {
|
||||
var decoded = message.decode(buf);
|
||||
assert(decoded.command === "error", "Bad command");
|
||||
return error.decodePayload(decoded.payload);
|
||||
},
|
||||
|
||||
/**
|
||||
* Decode `error` message payload.
|
||||
* @param {Buffer} buf - Message payload
|
||||
* @return {Object} Decoded `error` structure.
|
||||
*/
|
||||
decode: function(buf) {
|
||||
decodePayload: function(buf) {
|
||||
assert(buf.length >= 4, "Buffer is too small");
|
||||
var decodedFatal = structs.var_int.decode(buf);
|
||||
var decodedBanTime = structs.var_int.decode(decodedFatal.rest);
|
||||
|
@ -246,12 +336,22 @@ var error = exports.error = {
|
|||
};
|
||||
},
|
||||
|
||||
/**
|
||||
* Encode `error` message.
|
||||
* @param {Object} opts - Error options
|
||||
* @return {Buffer} Encoded message.
|
||||
*/
|
||||
encode: function(opts) {
|
||||
var payload = error.encodePayload(opts);
|
||||
return message.encode("error", payload);
|
||||
},
|
||||
|
||||
/**
|
||||
* Encode `error` message payload.
|
||||
* @param {Object} opts - Error options
|
||||
* @return {Buffer} Encoded payload.
|
||||
*/
|
||||
encode: function(opts) {
|
||||
encodePayload: function(opts) {
|
||||
var fatal = opts.fatal || error.WARNING;
|
||||
var banTime = opts.banTime || 0;
|
||||
var vector = opts.vector || "";
|
||||
|
|
45
test.js
45
test.js
|
@ -21,6 +21,7 @@ var messages = bitmessage.messages;
|
|||
var version = messages.version;
|
||||
var addr = messages.addr;
|
||||
var inv = messages.inv;
|
||||
var getdata = messages.getdata;
|
||||
var error = messages.error;
|
||||
var objects = bitmessage.objects;
|
||||
var getpubkey = objects.getpubkey;
|
||||
|
@ -362,11 +363,13 @@ describe("Common structures", function() {
|
|||
describe("Message types", function() {
|
||||
describe("version", function() {
|
||||
it("should encode and decode", function() {
|
||||
var res = version.decode(version.encode({
|
||||
var encoded = version.encode({
|
||||
remoteHost: "1.2.3.4",
|
||||
remotePort: 48444,
|
||||
port: 8444,
|
||||
}));
|
||||
});
|
||||
expect(message.decode(encoded).command).to.equal("version");
|
||||
var res = version.decode(encoded);
|
||||
expect(res.version).to.equal(3);
|
||||
expect(res.services.get(ServicesBitfield.NODE_NETWORK)).to.be.true;
|
||||
expect(res.time).to.be.instanceof(Date);
|
||||
|
@ -396,10 +399,12 @@ describe("Message types", function() {
|
|||
expect(res.length).to.equal(1);
|
||||
expect(res.addrs).to.deep.equal([]);
|
||||
|
||||
res = addr.decode(addr.encode([
|
||||
var encoded = addr.encode([
|
||||
{host: "1.2.3.4", port: 8444},
|
||||
{host: "ff::1", port: 18444},
|
||||
]));
|
||||
]);
|
||||
expect(message.decode(encoded).command).to.equal("addr");
|
||||
res = addr.decode(encoded);
|
||||
expect(res.length).to.equal(77);
|
||||
expect(res.addrs.length).to.equal(2);
|
||||
expect(res.addrs[0].host).to.equal("1.2.3.4");
|
||||
|
@ -410,7 +415,7 @@ describe("Message types", function() {
|
|||
|
||||
it("shouldn't encode/decode more than 1000 entires", function() {
|
||||
expect(addr.encode.bind(null, Array(2000))).to.throw(/too many/i);
|
||||
expect(addr.decode.bind(null, var_int.encode(2000))).to.throw(/too many/i);
|
||||
expect(addr.decodePayload.bind(null, var_int.encode(2000))).to.throw(/too many/i);
|
||||
});
|
||||
});
|
||||
|
||||
|
@ -419,7 +424,9 @@ describe("Message types", function() {
|
|||
var vect1 = inv_vect.encode(Buffer("test"));
|
||||
var vect2 = inv_vect.encode(Buffer("test2"));
|
||||
var inventory = [vect1, vect2];
|
||||
var res = inv.decode(inv.encode(inventory));
|
||||
var encoded = inv.encode(inventory);
|
||||
expect(message.decode(encoded).command).to.equal("inv");
|
||||
var res = inv.decode(encoded);
|
||||
expect(res.inventory.length).to.equal(2);
|
||||
expect(bufferEqual(res.inventory[0], vect1)).to.be.true;
|
||||
expect(bufferEqual(res.inventory[1], vect2)).to.be.true;
|
||||
|
@ -428,13 +435,35 @@ describe("Message types", function() {
|
|||
|
||||
it("shouldn't encode/decode more than 50000 entires", function() {
|
||||
expect(inv.encode.bind(null, Array(60000))).to.throw(/too many/i);
|
||||
expect(inv.decode.bind(null, var_int.encode(60000))).to.throw(/too many/i);
|
||||
expect(inv.decodePayload.bind(null, var_int.encode(60000))).to.throw(/too many/i);
|
||||
});
|
||||
});
|
||||
|
||||
describe("getdata", function() {
|
||||
it("should encode and decode", function() {
|
||||
var vect1 = inv_vect.encode(Buffer("test"));
|
||||
var vect2 = inv_vect.encode(Buffer("test2"));
|
||||
var inventory = [vect1, vect2];
|
||||
var encoded = getdata.encode(inventory);
|
||||
expect(message.decode(encoded).command).to.equal("getdata");
|
||||
var res = getdata.decode(encoded);
|
||||
expect(res.inventory.length).to.equal(2);
|
||||
expect(bufferEqual(res.inventory[0], vect1)).to.be.true;
|
||||
expect(bufferEqual(res.inventory[1], vect2)).to.be.true;
|
||||
expect(res.length).to.equal(65);
|
||||
});
|
||||
|
||||
it("shouldn't encode/decode more than 50000 entires", function() {
|
||||
expect(getdata.encode.bind(null, Array(60000))).to.throw(/too many/i);
|
||||
expect(getdata.decodePayload.bind(null, var_int.encode(60000))).to.throw(/too many/i);
|
||||
});
|
||||
});
|
||||
|
||||
describe("error", function() {
|
||||
it("should encode and decode", function() {
|
||||
var res = error.decode(error.encode({errorText: "test"}));
|
||||
var encoded = error.encode({errorText: "test"});
|
||||
expect(message.decode(encoded).command).to.equal("error");
|
||||
var res = error.decode(encoded);
|
||||
expect(res.fatal).to.equal(0);
|
||||
expect(res.banTime).to.equal(0);
|
||||
expect(res.vector).to.equal("");
|
||||
|
|
Loading…
Reference in New Issue
Block a user