amqp-node
Version:
An AMQP 0-9-1 (e.g., RabbitMQ) library and client.
142 lines (120 loc) • 3.31 kB
JavaScript
;
// The river sweeps through
// Silt and twigs, gravel and leaves
// Driving the wheel on
/*!
* Module dependencies.
*/
var defs = require('./defs');
var constants = defs.constants;
var decode = defs.decode;
var Bits = require('bitsyntax');
var PROTOCOL_HEADER = "AMQP" + String.fromCharCode(0, 0, 9, 1);
/*
Frame format:
0 1 3 7 size+7 size+8
+------+---------+-------------+ +------------+ +-----------+
| type | channel | size | | payload | | frame-end |
+------+---------+-------------+ +------------+ +-----------+
octet short long size octets octet
In general I want to know those first three things straight away, so I
can discard frames early.
*/
// framing constants
var FRAME_METHOD = constants.FRAME_METHOD,
FRAME_HEARTBEAT = constants.FRAME_HEARTBEAT,
FRAME_HEADER = constants.FRAME_HEADER,
FRAME_BODY = constants.FRAME_BODY,
FRAME_END = constants.FRAME_END;
var bodyCons =
Bits.builder(FRAME_BODY,
'channel:16, size:32, payload:size/binary',
FRAME_END);
// %%% TESTME possibly better to cons the first bit and write the
// second directly, in the absence of IO lists
var makeBodyFrame = function (channel, payload) {
return bodyCons({
channel: channel,
size: payload.length,
payload: payload
});
};
var frameHeaderPattern = Bits.matcher('type:8', 'channel:16',
'size:32', 'rest/binary');
function parseFrame(bin, max) {
var fh = frameHeaderPattern(bin);
if (fh) {
var size = fh.size,
rest = fh.rest;
if (size > max) {
throw new Error('Frame size exceeds frame max');
} else if (rest.length > size) {
if (rest[size] !== FRAME_END) {
throw new Error('Invalid frame');
}
return {
type: fh.type,
channel: fh.channel,
size: size,
payload: rest.slice(0, size),
rest: rest.slice(size + 1)
};
}
}
return false;
}
var headerPattern = Bits.matcher('class:16',
'_weight:16',
'size:64',
'flagsAndfields/binary');
var methodPattern = Bits.matcher('id:32, args/binary');
var HEARTBEAT = {
channel: 0
};
var decodeFrame = function (frame) {
var payload = frame.payload;
switch (frame.type) {
case FRAME_METHOD:
var idAndArgs = methodPattern(payload);
var id = idAndArgs.id;
var fields = decode(id, idAndArgs.args);
return {
id: id,
channel: frame.channel,
fields: fields
};
case FRAME_HEADER:
var parts = headerPattern(payload);
var id = parts['class'];
var fields = decode(id, parts.flagsAndfields);
return {
id: id,
channel: frame.channel,
size: parts.size,
fields: fields
};
case FRAME_BODY:
return {
channel: frame.channel,
content: frame.payload
};
case FRAME_HEARTBEAT:
return HEARTBEAT;
default:
throw new Error('Unknown frame type ' + frame.type);
}
};
// encoded heartbeat
var HEARTBEAT_BUF = new Buffer([constants.FRAME_HEARTBEAT,
0, 0, 0, 0, // size = 0
0, 0, // channel = 0
constants.FRAME_END
]);
module.exports = {
PROTOCOL_HEADER: PROTOCOL_HEADER,
makeBodyFrame: makeBodyFrame,
parseFrame: parseFrame,
decodeFrame: decodeFrame,
HEARTBEAT_BUF: HEARTBEAT_BUF,
HEARTBEAT: HEARTBEAT
};