├── .gitignore ├── History.md ├── Makefile ├── Readme.md ├── benchmarks └── index.js ├── ci.yml ├── examples ├── net.js └── stress.js ├── index.js ├── lib ├── decode.js ├── encode.js └── stream.js ├── package-lock.json ├── package.json └── test ├── codec.js └── stream.js /.gitignore: -------------------------------------------------------------------------------- 1 | node_modules 2 | -------------------------------------------------------------------------------- /History.md: -------------------------------------------------------------------------------- 1 | 2 | 0.3.1 / 2013-11-13 3 | ================== 4 | 5 | * fix missing offset warning in 0.10.x buffer usage 6 | 7 | 0.3.0 / 2013-10-30 8 | ================== 9 | 10 | * change to use 32-bit ints for length 11 | 12 | 0.2.0 / 2013-10-30 13 | ================== 14 | 15 | * change to emit framed buffer instead of arguments 16 | 17 | 0.1.0 / 2013-10-28 18 | ================== 19 | 20 | * remove recursion (~100% perf increase) 21 | -------------------------------------------------------------------------------- /Makefile: -------------------------------------------------------------------------------- 1 | 2 | test: 3 | @./node_modules/.bin/mocha \ 4 | --require should \ 5 | --bail 6 | 7 | bench: 8 | @./node_modules/.bin/matcha \ 9 | benchmarks/index.js 10 | 11 | .PHONY: test bench 12 | -------------------------------------------------------------------------------- /Readme.md: -------------------------------------------------------------------------------- 1 | 2 | # amp 3 | 4 | Abstract Message Protocol codec and streaming parser for nodejs. 5 | 6 | ## Installation 7 | 8 | ``` 9 | $ npm install amp 10 | ``` 11 | 12 | ## Example 13 | 14 | ```js 15 | var bin = amp.encode([Buffer.from('hello'), Buffer.from('world')]); 16 | var msg = amp.decode(bin); 17 | console.log(msg); 18 | ``` 19 | 20 | ## Protocol 21 | 22 | AMP is a simple versioned protocol for framed messages containing 23 | zero or more "arguments". Each argument is opaque binary, thus you 24 | may use JSON, BSON, msgpack and others on top of AMP. Multiple argument 25 | support is used to allow a hybrid of binary/non-binary message args without 26 | requiring higher level serialization libraries like msgpack or BSON. 27 | 28 | All multi-byte integers are big endian. The `version` and `argc` integers 29 | are stored in the first byte, followed by a sequence of zero or more 30 | `` / `` pairs, where `length` is a 32-bit unsigned integer. 31 | 32 | ``` 33 | 0 1 2 3 4 ... 34 | +------------+----------+------------+ 35 | | | | | additional arguments 36 | +------------+----------+------------+ 37 | ``` 38 | 39 | # License 40 | 41 | MIT 42 | -------------------------------------------------------------------------------- /benchmarks/index.js: -------------------------------------------------------------------------------- 1 | 2 | var amp = require('..'); 3 | 4 | suite('amp', function(){ 5 | var args = ['foo', 'bar', 'baz'].map(function(s){ return Buffer.from(s); }); 6 | 7 | bench('amp.encode()', function(){ 8 | amp.encode(args); 9 | }) 10 | 11 | var stream = new amp.Stream; 12 | var msg = amp.encode(args); 13 | 14 | bench('amp.Stream#write()', function(){ 15 | stream.write(msg); 16 | }) 17 | }) 18 | -------------------------------------------------------------------------------- /ci.yml: -------------------------------------------------------------------------------- 1 | version: 0.2 2 | 3 | phases: 4 | install: 5 | commands: 6 | - npm install 7 | build: 8 | commands: 9 | - make test 10 | -------------------------------------------------------------------------------- /examples/net.js: -------------------------------------------------------------------------------- 1 | 2 | var net = require('net'); 3 | var amp = require('..'); 4 | 5 | var server = net.createServer(function(sock){ 6 | var parser = new amp.Stream; 7 | 8 | parser.on('data', function(chunk){ 9 | var args = chunk.map(function(c){ 10 | return c.toString(); 11 | }); 12 | 13 | var meth = args.shift(); 14 | console.log('.%s(%s)', meth, args.join(', ')); 15 | }); 16 | 17 | sock.pipe(parser); 18 | }); 19 | 20 | server.listen(3000); 21 | 22 | var client = net.connect(3000); 23 | 24 | setInterval(function(){ 25 | var msg = amp.encode([Buffer.from('thumb'), Buffer.from('image data here')]); 26 | client.write(msg); 27 | }, 100); 28 | -------------------------------------------------------------------------------- /examples/stress.js: -------------------------------------------------------------------------------- 1 | 2 | var assert = require('assert'); 3 | var net = require('net'); 4 | var amp = require('..'); 5 | 6 | var server = net.createServer(function(sock){ 7 | var parser = new amp.Stream; 8 | var n = 0; 9 | 10 | parser.on('data', function(msg){ 11 | assert('foo, bar baz' == msg.join(', ')); 12 | if (n++ % 1000 == 0) { 13 | process.stdout.write('.'); 14 | } 15 | }); 16 | 17 | sock.pipe(parser); 18 | }); 19 | 20 | server.listen(3000); 21 | 22 | var client = net.connect(3000); 23 | 24 | var msg = amp.encode([Buffer.from('foo'), Buffer.from('bar baz')]); 25 | 26 | function next() { 27 | var n = 200; 28 | while (n--) client.write(msg); 29 | setImmediate(next); 30 | } 31 | 32 | next(); 33 | -------------------------------------------------------------------------------- /index.js: -------------------------------------------------------------------------------- 1 | 2 | 3 | exports.Stream = require('./lib/stream'); 4 | exports.encode = require('./lib/encode'); 5 | exports.decode = require('./lib/decode'); 6 | -------------------------------------------------------------------------------- /lib/decode.js: -------------------------------------------------------------------------------- 1 | 2 | /** 3 | * Decode the given `buf`. 4 | * 5 | * @param {Buffer} buf 6 | * @return {Object} 7 | * @api public 8 | */ 9 | 10 | module.exports = function(buf){ 11 | var off = 0; 12 | 13 | // unpack meta 14 | var meta = buf[off++]; 15 | var version = meta >> 4; 16 | var argv = meta & 0xf; 17 | var args = new Array(argv); 18 | 19 | // unpack args 20 | for (var i = 0; i < argv; i++) { 21 | var len = buf.readUInt32BE(off); 22 | off += 4; 23 | 24 | var arg = buf.slice(off, off += len); 25 | args[i] = arg; 26 | } 27 | 28 | return args; 29 | }; -------------------------------------------------------------------------------- /lib/encode.js: -------------------------------------------------------------------------------- 1 | 2 | /** 3 | * Protocol version. 4 | */ 5 | 6 | var version = 1; 7 | 8 | /** 9 | * Encode `msg` and `args`. 10 | * 11 | * @param {Array} args 12 | * @return {Buffer} 13 | * @api public 14 | */ 15 | 16 | module.exports = function(args){ 17 | var argc = args.length; 18 | var len = 1; 19 | var off = 0; 20 | 21 | // data length 22 | for (var i = 0; i < argc; i++) { 23 | len += 4 + args[i].length; 24 | } 25 | 26 | // buffer 27 | var buf = Buffer.allocUnsafe(len); 28 | 29 | // pack meta 30 | buf[off++] = version << 4 | argc; 31 | 32 | // pack args 33 | for (var i = 0; i < argc; i++) { 34 | var arg = args[i]; 35 | 36 | buf.writeUInt32BE(arg.length, off); 37 | off += 4; 38 | 39 | arg.copy(buf, off); 40 | off += arg.length; 41 | } 42 | 43 | return buf; 44 | }; 45 | -------------------------------------------------------------------------------- /lib/stream.js: -------------------------------------------------------------------------------- 1 | 2 | /** 3 | * Module dependencies. 4 | */ 5 | 6 | var Stream = require('stream').Writable; 7 | var encode = require('./encode'); 8 | 9 | /** 10 | * Expose parser. 11 | */ 12 | 13 | module.exports = Parser; 14 | 15 | /** 16 | * Initialize parser. 17 | * 18 | * @param {Options} [opts] 19 | * @api public 20 | */ 21 | 22 | function Parser(opts) { 23 | Stream.call(this, opts); 24 | this.state = 'message'; 25 | this._lenbuf = Buffer.allocUnsafe(4); 26 | } 27 | 28 | /** 29 | * Inherit from `Stream.prototype`. 30 | */ 31 | 32 | Parser.prototype.__proto__ = Stream.prototype; 33 | 34 | /** 35 | * Write implementation. 36 | */ 37 | 38 | Parser.prototype._write = function(chunk, encoding, fn){ 39 | for (var i = 0; i < chunk.length; i++) { 40 | switch (this.state) { 41 | case 'message': 42 | var meta = chunk[i]; 43 | this.version = meta >> 4; 44 | this.argv = meta & 0xf; 45 | this.state = 'arglen'; 46 | this._bufs = [Buffer.from([meta])]; 47 | this._nargs = 0; 48 | this._leni = 0; 49 | break; 50 | 51 | case 'arglen': 52 | this._lenbuf[this._leni++] = chunk[i]; 53 | 54 | // done 55 | if (4 == this._leni) { 56 | this._arglen = this._lenbuf.readUInt32BE(0); 57 | var buf = Buffer.allocUnsafe(4); 58 | buf[0] = this._lenbuf[0]; 59 | buf[1] = this._lenbuf[1]; 60 | buf[2] = this._lenbuf[2]; 61 | buf[3] = this._lenbuf[3]; 62 | this._bufs.push(buf); 63 | this._argcur = 0; 64 | this.state = 'arg'; 65 | } 66 | break; 67 | 68 | case 'arg': 69 | // bytes remaining in the argument 70 | var rem = this._arglen - this._argcur; 71 | 72 | // consume the chunk we need to complete 73 | // the argument, or the remainder of the 74 | // chunk if it's not mixed-boundary 75 | var pos = Math.min(rem + i, chunk.length); 76 | 77 | // slice arg chunk 78 | var part = chunk.slice(i, pos); 79 | this._bufs.push(part); 80 | 81 | // check if we have the complete arg 82 | this._argcur += pos - i; 83 | var done = this._argcur == this._arglen; 84 | i = pos - 1; 85 | 86 | if (done) this._nargs++; 87 | 88 | // no more args 89 | if (this._nargs == this.argv) { 90 | this.state = 'message'; 91 | this.emit('data', Buffer.concat(this._bufs)); 92 | break; 93 | } 94 | 95 | if (done) { 96 | this.state = 'arglen'; 97 | this._leni = 0; 98 | } 99 | break; 100 | } 101 | } 102 | 103 | 104 | fn(); 105 | }; 106 | -------------------------------------------------------------------------------- /package-lock.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "amp", 3 | "version": "0.3.1", 4 | "lockfileVersion": 1, 5 | "requires": true, 6 | "dependencies": { 7 | "balanced-match": { 8 | "version": "1.0.0", 9 | "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.0.tgz", 10 | "integrity": "sha1-ibTRmasr7kneFk6gK4nORi1xt2c=", 11 | "dev": true 12 | }, 13 | "brace-expansion": { 14 | "version": "1.1.11", 15 | "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz", 16 | "integrity": "sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==", 17 | "dev": true, 18 | "requires": { 19 | "balanced-match": "1.0.0", 20 | "concat-map": "0.0.1" 21 | } 22 | }, 23 | "browser-stdout": { 24 | "version": "1.3.1", 25 | "resolved": "https://registry.npmjs.org/browser-stdout/-/browser-stdout-1.3.1.tgz", 26 | "integrity": "sha512-qhAVI1+Av2X7qelOfAIYwXONood6XlZE/fXaBSmW/T5SzLAmCgzi+eiWE7fUvbHaeNBQH13UftjpXxsfLkMpgw==", 27 | "dev": true 28 | }, 29 | "commander": { 30 | "version": "2.11.0", 31 | "resolved": "https://registry.npmjs.org/commander/-/commander-2.11.0.tgz", 32 | "integrity": "sha512-b0553uYA5YAEGgyYIGYROzKQ7X5RAqedkfjiZxwi0kL1g3bOaBNNZfYkzt/CL0umgD5wc9Jec2FbB98CjkMRvQ==", 33 | "dev": true 34 | }, 35 | "concat-map": { 36 | "version": "0.0.1", 37 | "resolved": "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz", 38 | "integrity": "sha1-2Klr13/Wjfd5OnMDajug1UBdR3s=", 39 | "dev": true 40 | }, 41 | "debug": { 42 | "version": "3.1.0", 43 | "resolved": "https://registry.npmjs.org/debug/-/debug-3.1.0.tgz", 44 | "integrity": "sha512-OX8XqP7/1a9cqkxYw2yXss15f26NKWBpDXQd0/uK/KPqdQhxbPa994hnzjcE2VqQpDslf55723cKPUOGSmMY3g==", 45 | "dev": true, 46 | "requires": { 47 | "ms": "2.0.0" 48 | } 49 | }, 50 | "diff": { 51 | "version": "3.5.0", 52 | "resolved": "https://registry.npmjs.org/diff/-/diff-3.5.0.tgz", 53 | "integrity": "sha512-A46qtFgd+g7pDZinpnwiRJtxbC1hpgf0uzP3iG89scHk0AUC7A1TGxf5OiiOUv/JMZR8GOt8hL900hV0bOy5xA==", 54 | "dev": true 55 | }, 56 | "drip": { 57 | "version": "1.1.0", 58 | "resolved": "https://registry.npmjs.org/drip/-/drip-1.1.0.tgz", 59 | "integrity": "sha1-zO+x5obYb8EVtwyewSb4+HG9/X4=", 60 | "dev": true, 61 | "requires": { 62 | "tea-concat": "0.1.0" 63 | } 64 | }, 65 | "electron": { 66 | "version": "0.4.1", 67 | "resolved": "https://registry.npmjs.org/electron/-/electron-0.4.1.tgz", 68 | "integrity": "sha1-p4oFGniC9OVC1uIH2KGnMHazAUQ=", 69 | "dev": true, 70 | "requires": { 71 | "drip": "1.1.0" 72 | } 73 | }, 74 | "escape-string-regexp": { 75 | "version": "1.0.5", 76 | "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz", 77 | "integrity": "sha1-G2HAViGQqN/2rjuyzwIAyhMLhtQ=", 78 | "dev": true 79 | }, 80 | "fs.realpath": { 81 | "version": "1.0.0", 82 | "resolved": "https://registry.npmjs.org/fs.realpath/-/fs.realpath-1.0.0.tgz", 83 | "integrity": "sha1-FQStJSMVjKpA20onh8sBQRmU6k8=", 84 | "dev": true 85 | }, 86 | "glob": { 87 | "version": "7.1.2", 88 | "resolved": "https://registry.npmjs.org/glob/-/glob-7.1.2.tgz", 89 | "integrity": "sha512-MJTUg1kjuLeQCJ+ccE4Vpa6kKVXkPYJ2mOCQyUuKLcLQsdrMCpBPUi8qVE6+YuaJkozeA9NusTAw3hLr8Xe5EQ==", 90 | "dev": true, 91 | "requires": { 92 | "fs.realpath": "1.0.0", 93 | "inflight": "1.0.6", 94 | "inherits": "2.0.3", 95 | "minimatch": "3.0.4", 96 | "once": "1.4.0", 97 | "path-is-absolute": "1.0.1" 98 | } 99 | }, 100 | "growl": { 101 | "version": "1.10.3", 102 | "resolved": "https://registry.npmjs.org/growl/-/growl-1.10.3.tgz", 103 | "integrity": "sha512-hKlsbA5Vu3xsh1Cg3J7jSmX/WaW6A5oBeqzM88oNbCRQFz+zUaXm6yxS4RVytp1scBoJzSYl4YAEOQIt6O8V1Q==", 104 | "dev": true 105 | }, 106 | "has-flag": { 107 | "version": "2.0.0", 108 | "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-2.0.0.tgz", 109 | "integrity": "sha1-6CB68cx7MNRGzHC3NLXovhj4jVE=", 110 | "dev": true 111 | }, 112 | "he": { 113 | "version": "1.1.1", 114 | "resolved": "https://registry.npmjs.org/he/-/he-1.1.1.tgz", 115 | "integrity": "sha1-k0EP0hsAlzUVH4howvJx80J+I/0=", 116 | "dev": true 117 | }, 118 | "inflight": { 119 | "version": "1.0.6", 120 | "resolved": "https://registry.npmjs.org/inflight/-/inflight-1.0.6.tgz", 121 | "integrity": "sha1-Sb1jMdfQLQwJvJEKEHW6gWW1bfk=", 122 | "dev": true, 123 | "requires": { 124 | "once": "1.4.0", 125 | "wrappy": "1.0.2" 126 | } 127 | }, 128 | "inherits": { 129 | "version": "2.0.3", 130 | "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.3.tgz", 131 | "integrity": "sha1-Yzwsg+PaQqUC9SRmAiSA9CCCYd4=", 132 | "dev": true 133 | }, 134 | "matcha": { 135 | "version": "0.4.1", 136 | "resolved": "https://registry.npmjs.org/matcha/-/matcha-0.4.1.tgz", 137 | "integrity": "sha1-8B3B+3z8OUhfTGeB+Z8HQIhVIXM=", 138 | "dev": true, 139 | "requires": { 140 | "electron": "0.4.1", 141 | "v8-argv": "0.1.0" 142 | } 143 | }, 144 | "minimatch": { 145 | "version": "3.0.4", 146 | "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.0.4.tgz", 147 | "integrity": "sha512-yJHVQEhyqPLUTgt9B83PXu6W3rx4MvvHvSUvToogpwoGDOUQ+yDrR0HRot+yOCdCO7u4hX3pWft6kWBBcqh0UA==", 148 | "dev": true, 149 | "requires": { 150 | "brace-expansion": "1.1.11" 151 | } 152 | }, 153 | "minimist": { 154 | "version": "0.0.8", 155 | "resolved": "https://registry.npmjs.org/minimist/-/minimist-0.0.8.tgz", 156 | "integrity": "sha1-hX/Kv8M5fSYluCKCYuhqp6ARsF0=", 157 | "dev": true 158 | }, 159 | "mkdirp": { 160 | "version": "0.5.1", 161 | "resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-0.5.1.tgz", 162 | "integrity": "sha1-MAV0OOrGz3+MR2fzhkjWaX11yQM=", 163 | "dev": true, 164 | "requires": { 165 | "minimist": "0.0.8" 166 | } 167 | }, 168 | "mocha": { 169 | "version": "5.1.1", 170 | "resolved": "https://registry.npmjs.org/mocha/-/mocha-5.1.1.tgz", 171 | "integrity": "sha512-kKKs/H1KrMMQIEsWNxGmb4/BGsmj0dkeyotEvbrAuQ01FcWRLssUNXCEUZk6SZtyJBi6EE7SL0zDDtItw1rGhw==", 172 | "dev": true, 173 | "requires": { 174 | "browser-stdout": "1.3.1", 175 | "commander": "2.11.0", 176 | "debug": "3.1.0", 177 | "diff": "3.5.0", 178 | "escape-string-regexp": "1.0.5", 179 | "glob": "7.1.2", 180 | "growl": "1.10.3", 181 | "he": "1.1.1", 182 | "minimatch": "3.0.4", 183 | "mkdirp": "0.5.1", 184 | "supports-color": "4.4.0" 185 | } 186 | }, 187 | "ms": { 188 | "version": "2.0.0", 189 | "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", 190 | "integrity": "sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g=", 191 | "dev": true 192 | }, 193 | "once": { 194 | "version": "1.4.0", 195 | "resolved": "https://registry.npmjs.org/once/-/once-1.4.0.tgz", 196 | "integrity": "sha1-WDsap3WWHUsROsF9nFC6753Xa9E=", 197 | "dev": true, 198 | "requires": { 199 | "wrappy": "1.0.2" 200 | } 201 | }, 202 | "path-is-absolute": { 203 | "version": "1.0.1", 204 | "resolved": "https://registry.npmjs.org/path-is-absolute/-/path-is-absolute-1.0.1.tgz", 205 | "integrity": "sha1-F0uSaHNVNP+8es5r9TpanhtcX18=", 206 | "dev": true 207 | }, 208 | "should": { 209 | "version": "13.2.1", 210 | "resolved": "https://registry.npmjs.org/should/-/should-13.2.1.tgz", 211 | "integrity": "sha512-l+/NwEMO+DcstsHEwPHRHzC9j4UOE3VQwJGcMWSsD/vqpqHbnQ+1iSHy64Ihmmjx1uiRPD9pFadTSc3MJtXAgw==", 212 | "dev": true, 213 | "requires": { 214 | "should-equal": "2.0.0", 215 | "should-format": "3.0.3", 216 | "should-type": "1.4.0", 217 | "should-type-adaptors": "1.1.0", 218 | "should-util": "1.0.0" 219 | } 220 | }, 221 | "should-equal": { 222 | "version": "2.0.0", 223 | "resolved": "https://registry.npmjs.org/should-equal/-/should-equal-2.0.0.tgz", 224 | "integrity": "sha512-ZP36TMrK9euEuWQYBig9W55WPC7uo37qzAEmbjHz4gfyuXrEUgF8cUvQVO+w+d3OMfPvSRQJ22lSm8MQJ43LTA==", 225 | "dev": true, 226 | "requires": { 227 | "should-type": "1.4.0" 228 | } 229 | }, 230 | "should-format": { 231 | "version": "3.0.3", 232 | "resolved": "https://registry.npmjs.org/should-format/-/should-format-3.0.3.tgz", 233 | "integrity": "sha1-m/yPdPo5IFxT04w01xcwPidxJPE=", 234 | "dev": true, 235 | "requires": { 236 | "should-type": "1.4.0", 237 | "should-type-adaptors": "1.1.0" 238 | } 239 | }, 240 | "should-type": { 241 | "version": "1.4.0", 242 | "resolved": "https://registry.npmjs.org/should-type/-/should-type-1.4.0.tgz", 243 | "integrity": "sha1-B1bYzoRt/QmEOmlHcZ36DUz/XPM=", 244 | "dev": true 245 | }, 246 | "should-type-adaptors": { 247 | "version": "1.1.0", 248 | "resolved": "https://registry.npmjs.org/should-type-adaptors/-/should-type-adaptors-1.1.0.tgz", 249 | "integrity": "sha512-JA4hdoLnN+kebEp2Vs8eBe9g7uy0zbRo+RMcU0EsNy+R+k049Ki+N5tT5Jagst2g7EAja+euFuoXFCa8vIklfA==", 250 | "dev": true, 251 | "requires": { 252 | "should-type": "1.4.0", 253 | "should-util": "1.0.0" 254 | } 255 | }, 256 | "should-util": { 257 | "version": "1.0.0", 258 | "resolved": "https://registry.npmjs.org/should-util/-/should-util-1.0.0.tgz", 259 | "integrity": "sha1-yYzaN0qmsZDfi6h8mInCtNtiAGM=", 260 | "dev": true 261 | }, 262 | "supports-color": { 263 | "version": "4.4.0", 264 | "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-4.4.0.tgz", 265 | "integrity": "sha512-rKC3+DyXWgK0ZLKwmRsrkyHVZAjNkfzeehuFWdGGcqGDTZFH73+RH6S/RDAAxl9GusSjZSUWYLmT9N5pzXFOXQ==", 266 | "dev": true, 267 | "requires": { 268 | "has-flag": "2.0.0" 269 | } 270 | }, 271 | "tea-concat": { 272 | "version": "0.1.0", 273 | "resolved": "https://registry.npmjs.org/tea-concat/-/tea-concat-0.1.0.tgz", 274 | "integrity": "sha1-6i6QdAD914pjNM4CD6PGlQLZnoQ=", 275 | "dev": true 276 | }, 277 | "v8-argv": { 278 | "version": "0.1.0", 279 | "resolved": "https://registry.npmjs.org/v8-argv/-/v8-argv-0.1.0.tgz", 280 | "integrity": "sha1-rfd3pS29w9qciclGXlntXzy22ak=", 281 | "dev": true 282 | }, 283 | "wrappy": { 284 | "version": "1.0.2", 285 | "resolved": "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz", 286 | "integrity": "sha1-tSQ9jz7BqjXxNkYFvA0QNuMKtp8=", 287 | "dev": true 288 | } 289 | } 290 | } 291 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "amp", 3 | "version": "0.3.1", 4 | "repository": "visionmedia/node-amp", 5 | "description": "Abstract messaging protocol", 6 | "keywords": [ 7 | "amp", 8 | "actor", 9 | "message", 10 | "messaging", 11 | "zmq", 12 | "zeromq" 13 | ], 14 | "dependencies": {}, 15 | "files": [ 16 | "index.js", 17 | "lib/*.js" 18 | ], 19 | "devDependencies": { 20 | "matcha": "~0.4.0", 21 | "mocha": "*", 22 | "should": "*" 23 | }, 24 | "license": "MIT" 25 | } 26 | -------------------------------------------------------------------------------- /test/codec.js: -------------------------------------------------------------------------------- 1 | 2 | var amp = require('..'); 3 | 4 | describe('amp.encode(args...)', function(){ 5 | it('should support no args', function(){ 6 | var bin = amp.encode([]); 7 | var msg = amp.decode(bin); 8 | 9 | msg.should.eql([]); 10 | }) 11 | 12 | it('should support multiple args', function(){ 13 | var bin = amp.encode([Buffer.from('hello'), Buffer.from('world')]); 14 | var msg = amp.decode(bin); 15 | 16 | msg.should.have.length(2); 17 | msg[0].toString().should.equal('hello'); 18 | msg[1].toString().should.equal('world'); 19 | }) 20 | }) 21 | -------------------------------------------------------------------------------- /test/stream.js: -------------------------------------------------------------------------------- 1 | 2 | var amp = require('..'); 3 | 4 | describe('amp.Stream', function(){ 5 | it('should emit "data" events', function(done){ 6 | var stream = new amp.Stream; 7 | 8 | var a = amp.encode([Buffer.from('tobi')]); 9 | var b = amp.encode([Buffer.from('loki'), Buffer.from('abby')]); 10 | var c = amp.encode([Buffer.from('manny'), Buffer.from('luna'), Buffer.from('ewald')]); 11 | 12 | var n = 0; 13 | 14 | stream.on('data', function(buf){ 15 | var msg = amp.decode(buf).map(function(b){ return b.toString(); }); 16 | 17 | switch (n++) { 18 | case 0: 19 | msg.should.have.length(1); 20 | msg[0].should.equal('tobi'); 21 | break; 22 | 23 | case 1: 24 | msg.should.have.length(2); 25 | msg[0].should.equal('loki'); 26 | msg[1].should.equal('abby'); 27 | break; 28 | 29 | case 2: 30 | msg.should.have.length(3); 31 | msg[0].should.equal('manny'); 32 | msg[1].should.equal('luna'); 33 | msg[2].should.equal('ewald'); 34 | done(); 35 | break; 36 | } 37 | }); 38 | 39 | write(a, stream); 40 | write(b, stream); 41 | stream.write(c.slice(0, 5)); 42 | stream.write(c.slice(5, c.length)); 43 | }) 44 | }) 45 | 46 | function write(from, to) { 47 | for (var i = 0; i < from.length; i++) { 48 | to.write(Buffer.from([from[i]])); 49 | } 50 | } 51 | --------------------------------------------------------------------------------