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