UNPKG

amqp-node

Version:

An AMQP 0-9-1 (e.g., RabbitMQ) library and client.

142 lines (120 loc) 3.31 kB
'use strict'; // 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 };