diff --git a/package.json b/package.json index f8d06a1f..fde0d90c 100644 --- a/package.json +++ b/package.json @@ -39,6 +39,7 @@ "ip": "^1.0.2", "lodash.filter": "^4.2.1", "lodash.map": "^4.2.1", + "varint": "^4.0.0", "xtend": "^4.0.1" }, "devDependencies": { diff --git a/src/codec.js b/src/codec.js index 318d5d1c..cf87b9f2 100644 --- a/src/codec.js +++ b/src/codec.js @@ -1,8 +1,8 @@ var map = require('lodash.map') var filter = require('lodash.filter') -// var log = console.log var convert = require('./convert') var protocols = require('./protocols') +var varint = require('varint') // export codec module.exports = { @@ -40,7 +40,8 @@ function stringToStringTuples (str) { var part = parts[p] var proto = protocols(part) if (proto.size === 0) { - return [part] + tuples.push([part]) + return tuples } p++ // advance addr part @@ -63,12 +64,19 @@ function stringTuplesToString (tuples) { parts.push(tup[1]) } }) + if (parts[parts.length - 1] === '') { + parts.pop() + } + return '/' + parts.join('/') } // [[str name, str addr]... ] -> [[int code, Buffer]... ] function stringTuplesToTuples (tuples) { return map(tuples, function (tup) { + if (!Array.isArray(tup)) { + tup = [tup] + } var proto = protoFromTuple(tup) if (tup.length > 1) { return [proto.code, convert.toBuffer(proto.code, tup[1])] @@ -92,7 +100,7 @@ function tuplesToStringTuples (tuples) { function tuplesToBuffer (tuples) { return fromBuffer(Buffer.concat(map(tuples, function (tup) { var proto = protoFromTuple(tup) - var buf = new Buffer([proto.code]) + var buf = new Buffer(varint.encode(proto.code)) if (tup.length > 1) { buf = Buffer.concat([buf, tup[1]]) // add address buffer } @@ -104,14 +112,15 @@ function tuplesToBuffer (tuples) { function bufferToTuples (buf) { var tuples = [] for (var i = 0; i < buf.length;) { - var code = buf[i] + var code = varint.decode(buf, i) + var proto = protocols(code) if (!proto) { throw ParseError('Invalid protocol code: ' + code) } var size = (proto.size / 8) - code = 0 + buf[i] + code = Number(code) var addr = buf.slice(i + 1, i + 1 + size) i += 1 + size if (i > buf.length) { // did not end _exactly_ at buffer.length @@ -120,6 +129,7 @@ function bufferToTuples (buf) { // ok, tuple seems good. tuples.push([code, addr]) + i = i + varint.decode.bytes - 1 } return tuples } @@ -174,8 +184,5 @@ function ParseError (str) { function protoFromTuple (tup) { var proto = protocols(tup[0]) - if (tup.length > 1 && proto.size === 0) { - throw ParseError('tuple has address but protocol size is 0') - } return proto } diff --git a/src/protocols.js b/src/protocols.js index 91486a79..baf780b4 100644 --- a/src/protocols.js +++ b/src/protocols.js @@ -31,10 +31,12 @@ Protocols.table = [ [17, 16, 'udp'], [33, 16, 'dccp'], [41, 128, 'ip6'], - // these require varint: - [132, 16, 'sctp'] -// [480, 0, 'http'], -// [443, 0, 'https'], + [132, 16, 'sctp'], + // these require varint for the protocol code + [302, 0, 'utp'], + [480, 0, 'http'], + [443, 0, 'https'], + [477, 0, 'websockets'] ] Protocols.names = {} diff --git a/tests/test.js b/tests/test.js index 097874b1..71a250a4 100644 --- a/tests/test.js +++ b/tests/test.js @@ -42,6 +42,45 @@ describe('construction', (done) => { }) }) +describe('requiring varint', (done) => { + var uTPAddr + + it('create multiaddr', (done) => { + uTPAddr = multiaddr('/ip4/127.0.0.1/udp/1234/utp') + expect(uTPAddr instanceof multiaddr).to.equal(true) + done() + }) + + it('clone multiaddr', (done) => { + const uTPAddrClone = multiaddr(uTPAddr) + expect(uTPAddrClone !== uTPAddr).to.equal(true) + done() + }) + + it('reconstruct with buffer', (done) => { + expect(multiaddr(uTPAddr.buffer).buffer === uTPAddr.buffer).to.equal(false) + expect(multiaddr(uTPAddr.buffer).buffer).to.deep.equal(uTPAddr.buffer) + done() + }) + + it('reconstruct with string', (done) => { + expect(multiaddr(uTPAddr.toString()).buffer === uTPAddr.buffer).to.equal(false) + expect(multiaddr(uTPAddr.toString()).buffer).to.deep.equal(uTPAddr.buffer) + done() + }) + + it('reconstruct with object', (done) => { + expect(multiaddr(uTPAddr).buffer === uTPAddr.buffer).to.equal(false) + expect(multiaddr(uTPAddr).buffer).to.deep.equal(uTPAddr.buffer) + done() + }) + + it('empty construct still works', (done) => { + expect(multiaddr('').toString()).to.equal('/') + done() + }) +}) + describe('manipulation', () => { it('basic', (done) => { const udpAddrStr = '/ip4/127.0.0.1/udp/1234' @@ -67,3 +106,123 @@ describe('manipulation', () => { done() }) }) + +describe('variants', () => { + it('ip4', (done) => { + const str = '/ip4/127.0.0.1' + const addr = multiaddr(str) + expect(addr).to.have.property('buffer') + expect(addr.toString()).to.equal(str) + done() + }) + + it('ip6', (done) => { + const str = '/ip6/2001:8a0:7ac5:4201:3ac9:86ff:fe31:7095' + const addr = multiaddr(str) + expect(addr).to.have.property('buffer') + expect(addr.toString()).to.equal(str) + done() + }) + + it('ip4 + tcp', (done) => { + const str = '/ip4/127.0.0.1/tcp/5000' + const addr = multiaddr(str) + expect(addr).to.have.property('buffer') + expect(addr.toString()).to.equal(str) + done() + }) + + it('ip6 + tcp', (done) => { + const str = '/ip6/2001:8a0:7ac5:4201:3ac9:86ff:fe31:7095/tcp/5000' + const addr = multiaddr(str) + expect(addr).to.have.property('buffer') + expect(addr.toString()).to.equal(str) + done() + }) + + it('ip4 + udp', (done) => { + const str = '/ip4/127.0.0.1/udp/5000' + const addr = multiaddr(str) + expect(addr).to.have.property('buffer') + expect(addr.toString()).to.equal(str) + done() + }) + + it('ip6 + udp', (done) => { + const str = '/ip6/2001:8a0:7ac5:4201:3ac9:86ff:fe31:7095/udp/5000' + const addr = multiaddr(str) + expect(addr).to.have.property('buffer') + expect(addr.toString()).to.equal(str) + done() + }) + + it.skip('ip4 + dccp', (done) => {}) + it.skip('ip6 + dccp', (done) => {}) + + it.skip('ip4 + sctp', (done) => {}) + it.skip('ip6 + sctp', (done) => {}) + + it('ip4 + udp + utp', (done) => { + const str = '/ip4/127.0.0.1/udp/5000/utp' + const addr = multiaddr(str) + expect(addr).to.have.property('buffer') + expect(addr.toString()).to.equal(str) + done() + }) + + it('ip6 + udp + utp', (done) => { + const str = '/ip6/2001:8a0:7ac5:4201:3ac9:86ff:fe31:7095/udp/5000/utp' + const addr = multiaddr(str) + expect(addr).to.have.property('buffer') + expect(addr.toString()).to.equal(str) + done() + }) + + it('ip4 + tcp + http', (done) => { + const str = '/ip4/127.0.0.1/tcp/8000/http' + const addr = multiaddr(str) + expect(addr).to.have.property('buffer') + expect(addr.toString()).to.equal(str) + done() + }) + + it('ip6 + tcp + http', (done) => { + const str = '/ip6/2001:8a0:7ac5:4201:3ac9:86ff:fe31:7095/tcp/8000/http' + const addr = multiaddr(str) + expect(addr).to.have.property('buffer') + expect(addr.toString()).to.equal(str) + done() + }) + + it('ip4 + tcp + https', (done) => { + const str = '/ip4/127.0.0.1/tcp/8000/https' + const addr = multiaddr(str) + expect(addr).to.have.property('buffer') + expect(addr.toString()).to.equal(str) + done() + }) + + it('ip6 + tcp + https', (done) => { + const str = '/ip6/2001:8a0:7ac5:4201:3ac9:86ff:fe31:7095/tcp/8000/https' + const addr = multiaddr(str) + expect(addr).to.have.property('buffer') + expect(addr.toString()).to.equal(str) + done() + }) + + it('ip4 + tcp + websockets', (done) => { + const str = '/ip4/127.0.0.1/tcp/8000/websockets' + const addr = multiaddr(str) + expect(addr).to.have.property('buffer') + expect(addr.toString()).to.equal(str) + done() + }) + + it('ip6 + tcp + websockets', (done) => { + const str = '/ip6/2001:8a0:7ac5:4201:3ac9:86ff:fe31:7095/tcp/8000/websockets' + const addr = multiaddr(str) + expect(addr).to.have.property('buffer') + expect(addr.toString()).to.equal(str) + done() + }) +})