Octobit
Small and fast tructured binary message codec for Nodejs.
Size and performance
// from /example/index.jsvar octobit= var struct= // examplevar getQuery= requestId: 35 requestType: get: true ack: true noProxy: true timestamp: Date notInStruct: 'xyz' // ignored as not in structure key: '108827d4-e7f0-7d0a-6775-c93236ca00a3' value: 'some value'var buffer= structconsole // 64console // {requestId: 35, requestDat ... } // smaller examplevar pingQuery= requestId: 12345678 requestType: ping: 1 ack: 1 noProxy: 1 noCache: 1var buf= structconsole // 6console // {requestId: 12345678, requestType: { ping: tru ... }
2012 Mac Air's single core can encode 300,000 {getQuery} objects per second, and decode the resulted buffers in 0.06 second.
Structures and data types
There are 3 basic data types: number
, buffer
and octet
. Number is the usual (U)int32 and a double; buffer (byte arrays) is Nodejs Buffer that can be up to 65536 long; and octet is one byte (8 bits), and can hold up to 8 unique flags. Example structure [ key, type[, list] ]:
// from /example/example.octo.json "requestId" "uint" "requestType" "octet" "get" "set" "ping" "noCache" "proxy" "noProxy" "faf" "ack" "responseType" "octet" "get" "set" "error" "proxied" "cached" "timestamp" "double" "key" "buffer" "value" "buffer"
A single structure
can contain up to 8 elements
. A structure must be defined once and never modified. Only the octet type can endure changes -- new flags can be appended (up to 8).
when 8 elements is not enough, pack another structure into the first one as a buffer
encode/decode
- .encode(obj) is a one step process, it directly returns a Buffer that you can flush down a socket.
- .decode(buffer) on the other hand
only reads
the buffer and creates anindex
; it returns an octo-object that allows to get/set specific keys without converting the buffer into an object. This allows to proxy data between servers without decoding/re-encoding the whole thing.
if proxying data is not a concern, use .decode().toObject() to get the complete object at once
Data types
- 1:
uint
4 bytes, 32-bit unsigned integer, max value: 4,294,967,295 - 2:
int
4 bytes, 32-bit signed integer, max value: -/+2,147,483,647 - 3:
double
8 bytes, 64-bit double-precision floating-point, max value: -/+9,007,199,254,740,991 - 4:
buffer
2 bytes, byte-array (Buffer), max buffer byte length: 65,535 - 5:
octet
1 byte, 8 bits, max values (flags): 8
there's is no plain text or
String
support; usebuffer type
instead: .encode( { myKey: new Buffer('some text') } )
octet
type
The The octet type uses 1 byte (8 bits) to store 8 Boolean flags. Octet's elements order must not change. If order is changed octet's flags will get scrumbled. You do however can append elements or set existing elements to undefined. Encoding/decoding example:
var octetOnly= structconsole // <Buffer 02 29>// <29> is the octet (byte) with 3 bits set to 1var octObj= structconsole // { get: true, noCache: true, noProxy: true }console // trueconsole // { noCache: true, noProxy: true }console // trueconsole // { set: true, noCache: true, noProxy: true }
The format
The format is very simple and can be split into 3 main parts, bits, header and buffers:
+-----+--------+----------------...
[bits]|[header]|[buffers ...]
+-----+--------+----------------...
- bits is an 8 bit index that indicates which of the 8 elements are set
- header contains all the integers, octets, and length of buffers, there are no empty spaces and no offsets, the elements order in the structure is used instead
- buffers contains all the buffers clamped up together at the end of the message
In the above
octet
example, in < Buffer 02 29 > that's 1 byte for message's index to indicate which elements are present ('requestType'), and 1 byte for octet data type to indicate which flags are set ('get', 'noCache' and 'noProxy')
API
new Octobit(structureArray)
var struct= structureArray
octobit.encode(object)
var buffer= struct // returns buffer
octobit.decode(buffer)
var octObject= struct // returns octobject
new Octobject
octo-object is created by the octobit.decode() method:
var octObject= struct // returns octobject
octobject.get(key)
octObject // returns array containing all set keysoctObject // value
octobject.isSet(key[, value])
octObject // true// See TODO
octobject.set(key, value)
octObject // trueoctObject // trueoctObject // true// See TODO
octobject.unset(key[, value])
// unset 'noProxy' flag from 'requestType' octetoctObject // true// See TODO
octobject.getBuffer()
octoObject // <Buffer ... >
octobject.toObject()
octoObject // returns complete object currently held in the buffer
Installation
npm install octobit
TODO
- Octobject.unset(key) // remove a key
- Octobject.set(key, buffer) // set buffer type
- Octobject.set(newKey, value) // set previously not set key
- Octobject.isSet(key, value) // check if a specific flag is set