1 var ProtoBuf = require("protobufjs"),
\r
2 ByteBuffer = ProtoBuf.ByteBuffer, // ProtoBuf.js uses and also exposes ByteBuffer.js
\r
3 Long = ProtoBuf.Long; // as well as Long.js (not used in this example)
\r
5 // Option 1: Loading the .proto file directly
\r
6 var builder = ProtoBuf.loadProtoFile("./json.proto"), // Creates the Builder
\r
7 JS = builder.build("js"); // Returns just the 'js' namespace if that's all we need
\r
9 // Option 2: Loading the .json file generated through 'proto2js json.proto > json.json'
\r
10 var root = ProtoBuf.loadJsonFile("./json.json").build(), // Here we make the Builder return the root namespace
\r
11 JS = root.js; // then we reference 'js' inside. Both is possible.
\r
13 // Option 3: Loading the module generated through 'proto2js json.proto -commonjs=js > json.js'
\r
14 var JS = require("./json.js"); // Returns what is specified with -commonjs[=XX] (omitted=root)
\r
16 // `JS` now contains the js namespace from json.proto: Value, Array and Object
\r
18 // This is how we use these classes:
\r
21 * Converts a JSON-like structure to JS-Namespace values.
\r
22 * @param {*} val JSON
\r
23 * @returns {!JS.Value} JS-Namespace value
\r
26 function _protoify(val) {
\r
27 switch (typeof val) {
\r
29 if (val%1 === 0 && val >= (0x80000000|0) && val <= (0x7fffffff|0))
\r
30 return new JS.Value(val); // sets the first field declared in .js.Value
\r
32 return new JS.Value(null, val); // sets the second field
\r
34 return new JS.Value({ 'string': val }); // uses object notation instead
\r
36 return new JS.Value({ 'boolean': val });
\r
39 return new JS.Value({ 'null': true });
\r
40 if (Object.prototype.toString.call(val) === "[object Array]") {
\r
41 var arr = new JS.Array();
\r
42 for (var i=0; i<val.length; ++i)
\r
43 arr['values'][i] = _protoify(val[i]);
\r
44 return new JS.Value({ 'array': arr });
\r
46 var obj = new JS.Object();
\r
47 for (var key in val)
\r
48 if (val.hasOwnProperty(key))
\r
49 obj['keys'].push(_protoify(key)),
\r
50 obj['values'].push(_protoify(val[key]));
\r
51 return new JS.Value({ 'object': obj });
\r
53 return new JS.Value(); // undefined
\r
55 throw Error("Unsupported type: "+(typeof val)); // symbol, function
\r
60 * Converts JS-Namespace values to JSON.
\r
61 * @param {!JS.Value} value JS value
\r
65 function _jsonify(value) {
\r
66 if (value.type === null)
\r
68 switch (value.type) {
\r
72 return (function() {
\r
73 var values = value['array']['values'],
\r
78 arr[i] = _jsonify(values[i]);
\r
82 return (function() {
\r
83 var keys = value['object']['keys'],
\r
84 values = value['object']['values'],
\r
89 obj[keys[i]['string'] /* is a JS.Value, here always a string */] = _jsonify(values[i]);
\r
93 return value[value.type];
\r
97 // And this is how we actually encode and decode them:
\r
100 * A temporary Buffer to speed up encoding.
\r
101 * @type {!ByteBuffer}
\r
104 var tempBuffer = ByteBuffer.allocate(1024);
\r
107 * Converts a JSON structure to a Buffer.
\r
108 * @param {*} json JSON
\r
109 * @returns {!Buffer|!ArrayBuffer}
\r
112 module.exports = function(json) {
\r
113 return _protoify(json) // Returns the root JS.Value
\r
114 .encode(tempBuffer).flip() // Encodes it to a ByteBuffer, here: reusing tempBuffer forever
\r
115 // The non-tempBuffer alternative is just doing .encode()
\r
116 .toBuffer(); // Converts it to a Buffer. In the browser, this returns an ArrayBuffer. To return an
\r
117 // ArrayBuffer explicitly both under node.js and in the browser, use .toArrayBuffer().
\r
118 // Performance note: This just returns a slice on the ByteBuffer's backing .buffer
\r
122 * Converts a Buffer to a JSON structure.
\r
123 * @param {!Buffer|!ArrayBuffer} proto Buffer
\r
124 * @returns {*} JSON
\r
127 module.exports.parse = function(proto) {
\r
128 return _jsonify( // Processes JS-namespace objects
\r
129 JS.Value.decode(proto) // Decodes the JS.Value from a ByteBuffer, a Buffer, an ArrayBuffer, an Uint8Array, ...
\r
134 * Performs maintenance.
\r
137 module.exports.performMaintenance = function() {
\r
138 if (tempBuffer.capacity() > 2048)
\r
139 tempBuffer = ByteBuffer.allocate(1024);
\r
140 // In case this module is running inside of a daemon, we'd just call this
\r
141 // method every now and then to discard the tempBuffer if it becomes too
\r
142 // large. This is just an example on how to reuse ByteBuffers effectively.
\r
143 // You may consider something like this for the performance benefit, which
\r
144 // is decreasing the memory allocation footprint of your app.
\r
147 // Have a nice day!
\r