From c2286084c6ab2464fb980fe00495aefffb3e1575 Mon Sep 17 00:00:00 2001 From: Matthieu Monsch Date: Fri, 29 Jan 2016 12:42:35 -0800 Subject: [PATCH] Add assemble option. The new `oneWayVoid` option makes the `void` IDL keyword useful (rather than just being a crufty alias for `null`). Also expose protocol emitter classes (to be consistent with only documenting exposed classes in the API). --- README.md | 20 +++++++++++--------- doc | 2 +- etc/browser/avsc-protocols.js | 1 + etc/browser/avsc.js | 1 + lib/index.js | 7 ++++--- lib/protocols.js | 4 ++++ lib/schemas.js | 20 +++++++++++++++++--- package.json | 2 +- test/test_schemas.js | 23 +++++++++++++++++++++++ 9 files changed, 63 insertions(+), 17 deletions(-) diff --git a/README.md b/README.md index 1f0322c1..ec61ae21 100644 --- a/README.md +++ b/README.md @@ -6,8 +6,8 @@ specification](https://avro.apache.org/docs/current/spec.html). ## Features -+ [Blazingly fast and compact serialization!][benchmarks] Typically twice as - fast as JSON with much smaller encodings. ++ Blazingly [fast and compact][benchmarks] serialization! Typically faster than + JSON with much smaller encodings. + All the Avro goodness, including [schema evolution][schema-evolution] and [remote procedure calls][rpc]. + Support for [serializing arbitrary JavaScript objects][logical-types]. @@ -67,15 +67,16 @@ var avro = require('avsc'); .on('data', function (val) { /* Do something with the decoded value. */ }); ``` -+ Respond to remote procedure calls over TCP: ++ Implement a TCP server for an [IDL-defined][idl] protocol: ```javascript - var protocol = avro.parse('./Ping.avpr') - .on('ping', function (req, ee, cb) { cb(null, 'pong'); }); - - require('net').createServer() - .on('connection', function (con) { protocol.createListener(con); }) - .listen(8000); + avro.assemble('./Ping.avdl', function (err, attrs) { + var protocol = avro.parse(attrs); + protocol.on('ping', function (req, ee, cb) { cb(null, 'pong'); }); + require('net').createServer() + .on('connection', function (con) { protocol.createListener(con); }) + .listen(8000); + }); ``` @@ -90,3 +91,4 @@ var avro = require('avsc'); [home]: https://github.com/mtth/avsc/wiki [rpc]: https://github.com/mtth/avsc/wiki/Advanced-usage#remote-procedure-calls [releases]: https://github.com/mtth/avsc/releases +[idl]: https://avro.apache.org/docs/current/idl.html diff --git a/doc b/doc index 160cef4b..70c6ba27 160000 --- a/doc +++ b/doc @@ -1 +1 @@ -Subproject commit 160cef4b680e00349796009b4955c14180284f77 +Subproject commit 70c6ba27b8355ae05d04b8fdd88b47f8906720cd diff --git a/etc/browser/avsc-protocols.js b/etc/browser/avsc-protocols.js index a0272d4b..ead53e1e 100644 --- a/etc/browser/avsc-protocols.js +++ b/etc/browser/avsc-protocols.js @@ -27,6 +27,7 @@ module.exports = { Protocol: protocols.Protocol, Type: types.Type, assemble: schemas.assemble, + messages: protocols.messages, parse: parse, types: types.builtins }; diff --git a/etc/browser/avsc.js b/etc/browser/avsc.js index ec7c922f..67fde3c5 100644 --- a/etc/browser/avsc.js +++ b/etc/browser/avsc.js @@ -26,6 +26,7 @@ module.exports = { Protocol: protocols.Protocol, Type: types.Type, assemble: schemas.assemble, + messages: protocols.messages, parse: parse, streams: containers.streams, types: types.builtins diff --git a/lib/index.js b/lib/index.js index d2bf88cf..e8d1ac68 100644 --- a/lib/index.js +++ b/lib/index.js @@ -5,8 +5,8 @@ /** * Node.js entry point (see `etc/browser/` for browserify's entry points). * - * It adds Node.js specific functionality (for example filesystem - * conveniences). + * It also adds Node.js specific functionality (for example a few convenience + * functions to read Avro files from the local filesystem). * */ @@ -20,7 +20,7 @@ var containers = require('./containers'), /** - * Parse a schema and return the corresponding type. + * Parse a schema and return the corresponding type or protocol. * */ function parse(schema, opts) { @@ -104,6 +104,7 @@ module.exports = { createFileDecoder: createFileDecoder, createFileEncoder: createFileEncoder, extractFileHeader: extractFileHeader, + messages: protocols.messages, parse: parse, streams: containers.streams, types: types.builtins diff --git a/lib/protocols.js b/lib/protocols.js index 9e34c24d..1d06c027 100644 --- a/lib/protocols.js +++ b/lib/protocols.js @@ -1253,6 +1253,10 @@ module.exports = { StatefulListener: StatefulListener, StatelessListener: StatelessListener }, + messages: { + MessageEmitter: MessageEmitter, + MessageListener: MessageListener, + }, streams: { MessageDecoder: MessageDecoder, MessageEncoder: MessageEncoder diff --git a/lib/schemas.js b/lib/schemas.js index ceadbb4e..dc5d5380 100644 --- a/lib/schemas.js +++ b/lib/schemas.js @@ -159,7 +159,18 @@ function assemble(fpath, opts, cb) { // message otherwise. attrs.types.push(typeAttrs); } else { - readMessage(attrs, typeAttrs); + var oneWay = false; + if (typeAttrs === 'void' || typeAttrs.type === 'void') { + if (opts.oneWayVoid) { + oneWay = true; + } + if (typeAttrs === 'void') { + typeAttrs = 'null'; + } else { + typeAttrs.type = 'null'; + } + } + readMessage(attrs, typeAttrs, oneWay); } } } @@ -188,8 +199,11 @@ function assemble(fpath, opts, cb) { tk.next(); } - function readMessage(protocolAttrs, responseAttrs) { + function readMessage(protocolAttrs, responseAttrs, oneWay) { var messageAttrs = {response: responseAttrs}; + if (oneWay) { + messageAttrs['one-way'] = true; + } while (tk.get().val === '@') { readAnnotation(messageAttrs); } @@ -272,7 +286,7 @@ function assemble(fpath, opts, cb) { } return readUnion(); default: - var type = tk.get().val === 'void' ? 'null' : tk.get().val; + var type = tk.get().val; tk.next(); if (Object.keys(attrs).length) { attrs.type = type; diff --git a/package.json b/package.json index 15706f04..b4dca8e2 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "avsc", - "version": "3.3.4", + "version": "3.3.5", "description": "Avro for JavaScript", "homepage": "https://github.com/mtth/avsc", "keywords": [ diff --git a/test/test_schemas.js b/test/test_schemas.js index 44ebd8df..9d8abc15 100644 --- a/test/test_schemas.js +++ b/test/test_schemas.js @@ -345,6 +345,29 @@ suite('schemas', function () { }); }); + test('one way void', function (done) { + var hook = createImportHook({ + '1': 'protocol A { void ping(); @foo(true) void pong(); }', + }); + var opts = {importHook: hook, oneWayVoid: true}; + assemble('1', opts, function (err, attrs) { + assert.strictEqual(err, null); + assert.deepEqual(attrs, { + protocol: 'A', + types: [], + messages: { + ping: {response: 'null', request: [], 'one-way': true}, + pong: { + response: {foo: true, type: 'null'}, + request: [], + 'one-way': true + } + } + }); + done(); + }); + }); + test('reset namespace', function (done) { var hook = createImportHook({ '1': 'protocol A { import idl "2"; }',