You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
113 lines
3.3 KiB
113 lines
3.3 KiB
// The river sweeps through |
|
// Silt and twigs, gravel and leaves |
|
// Driving the wheel on |
|
|
|
'use strict'; |
|
|
|
var defs = require('./defs'); |
|
var constants = defs.constants; |
|
var decode = defs.decode; |
|
|
|
var Bits = require('bitsyntax'); |
|
|
|
module.exports.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 |
|
module.exports.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; |
|
} |
|
|
|
module.exports.parseFrame = parseFrame; |
|
|
|
var headerPattern = Bits.matcher('class:16', |
|
'_weight:16', |
|
'size:64', |
|
'flagsAndfields/binary'); |
|
|
|
var methodPattern = Bits.matcher('id:32, args/binary'); |
|
|
|
var HEARTBEAT = {channel: 0}; |
|
|
|
module.exports.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 |
|
module.exports.HEARTBEAT_BUF = new Buffer([constants.FRAME_HEARTBEAT, |
|
0, 0, 0, 0, // size = 0 |
|
0, 0, // channel = 0 |
|
constants.FRAME_END]); |
|
|
|
module.exports.HEARTBEAT = HEARTBEAT;
|
|
|