domotz-remote-pawn
Version:
Domotz Agent
121 lines (112 loc) • 4.92 kB
JavaScript
/** This file is part of Domotz Agent.
* Copyright (C) 2016 Domotz Ltd
*
* Domotz Agent is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* Domotz Agent is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with Domotz Agent. If not, see <http://www.gnu.org/licenses/>.
*
* Created by Iacopo Papalini <iacopo@domotz.com> on 17/09/15.
*
* Process Messages incoming from the RabbitMQ command queue, instantiating the right class and calling the `execute`
* method.
*
* If the message contains the `reply-to` property, a reply message is sent back, containing the result of the `execute`
* call. By default it is JSON-encoded but other content types are supported
*
*/
var factory = function (resourceLocator) {
var myConsole = resourceLocator.log.decorateLogs();
function parse(message) {
var command = message.command;
var tokens = command.toLowerCase().split('_');
command = tokens.shift();
for (var i = 0; i < tokens.length; i++) {
command += tokens[i].charAt(0).toUpperCase() + tokens[i].slice(1);
}
myConsole.verbose('Parsed command: %s', command);
return command;
}
function createCommandFromMessage(message) {
var command = parse(message);
if (command.indexOf('ssh') !== -1) {
command = 'ssh/' + command;
}
if (!resourceLocator.settingsManager.isCommandHandlerEnabled(command)) {
myConsole.warn('(%s) command disabled from settings', command);
return null;
}
var commandModule = require('../commands/' + command + '.js');
return commandModule.command(message, resourceLocator);
}
function callback(payload, options) {
if (options === undefined) {
options = {};
}
if (payload === undefined || payload === null) {
myConsole.debug('Sending empty message as ack');
return new Buffer(JSON.stringify({}));
}
if (payload instanceof Object && !options.asBinary) {
return new Buffer(JSON.stringify(payload));
}
myConsole.debug('handling returned payload as binary - no transformation');
return new Buffer(payload, 'binary');
}
function processMessage(channel, exchange, amqpMessage) {
var message, cid, replyTo;
var command;
if (!amqpMessage) {
throw new Error('MESSAGE - Received an empty message');
}
message = JSON.parse(amqpMessage.content.toString());
cid = amqpMessage.properties.correlationId;
replyTo = amqpMessage.properties.replyTo;
myConsole.debug('MESSAGE - (%s): Received', cid);
message.correlationId = cid;
myConsole.debug('MESSAGE row ' + JSON.stringify(message));
command = createCommandFromMessage(message);
if (command === null) {
var buffer = callback({ error: 'COMMAND_DISABLED_BY_SETTINGS' }, {});
var properties = { correlationId: cid };
channel.publish(exchange, replyTo, buffer, properties);
return;
}
myConsole.info('MESSAGE - (%s): %s', cid, command.describe());
command.execute(buildExecutionResponseHandler(cid, replyTo, channel, exchange));
}
function buildExecutionResponseHandler(cid, replyTo, channel, exchange) {
return function (payload, error, options) {
if (replyTo === null || replyTo === undefined) {
myConsole.info('MESSAGE - (%s): without reply-to - not sending reply', cid);
return;
}
var buffer = callback(payload, options);
// TODO Handler error
myConsole.info('MESSAGE - (%s): Sending reply on queue %s - size in bytes: %d', cid, replyTo, buffer.length);
var properties = { correlationId: cid };
if (options && options.asBinary) {
myConsole.info('MESSAGE - (%s): content-type: %s', cid, options['content-type']);
properties.contentType = options['content-type'];
}
channel.publish(exchange, replyTo, buffer, properties);
};
}
return {
processMessage: processMessage,
// For testing
_createCommandFromMessage: createCommandFromMessage,
_callback: callback,
_parse: parse,
_buildExecutionResponseHandler: buildExecutionResponseHandler,
};
};
module.exports.factory = factory;