Add encodePayload/decodePayload to messages module

This commit is contained in:
Kagami Hiiragi 2015-01-26 20:03:43 +03:00
parent 874acfac45
commit 514265b7cd
2 changed files with 149 additions and 20 deletions

View File

@ -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
View File

@ -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("");