UNPKG

diffusion

Version:

Diffusion JavaScript client

208 lines (173 loc) 7.09 kB
var COMMUNICATION_FAILURE = require('../../errors/error-reason').COMMUNICATION_FAILURE; var ErrorReason = require('client/error-reason'); var ConversationID = require('conversation/conversation-id'); var CommandHeader = require('services/command-header'); var Message = require('v4-stack/message'); var Codec = require('io/codec'); var log = require('util/logger').create('Service Adapter'); /** * Adaptor to bridge v4-stack components and command services. * * @param {InternalSession} internalSession - The internal session this adapter is bound to * @param {Serialisers} serialisers - The serialiser registry * @param {Function} sender - The function to enqueue messages * * @class */ function ServiceAdapter(internalSession, serialisers, sender) { var NULL_CALLBACK = { respond : function() { // no-op }, fail : function() { // no-op } }; var headerSerialiser = serialisers.get(CommandHeader); var listeners = {}; function sendRequest(header, command, serialiser) { var msg = Message.create({ type : Message.types.SERVICE_REQUEST }); headerSerialiser.write(msg, header); serialiser.write(msg, command); log.debug('Sending command request: ' + header, command); sender(msg); } function sendResponse(header, command, serialiser) { var msg = Message.create({ type : Message.types.SERVICE_RESPONSE }); headerSerialiser.write(msg, header); serialiser.write(msg, command); log.debug('Sending command response: ' + header, command); sender(msg); } function sendError(header, error, message) { var msg = Message.create({ type : Message.types.SERVICE_ERROR }); headerSerialiser.write(msg, header); Codec.writeString(msg, message); Codec.writeInt32(msg, error.id); log.debug('Sending command error: ' + error.id, message); sender(msg); } function handleRequest(header, input) { var listener = listeners[header.service]; if (listener) { log.debug('Received command request for service: ' + header); listener(header, input); } else { log.error('Received command request for unknown service: ' + header); sendError( header.createErrorHeader(), COMMUNICATION_FAILURE, "Unknown client service: " + header.service); } } function handleResponse(header, input) { log.debug('Received command response: ' + header); internalSession.getConversationSet().respondIfPresent(header.cid, input); } function handleError(header, input) { var description = Codec.readString(input); var code = Codec.readInt32(input); var error = new ErrorReason(code, description); log.warn("Received command error", error); internalSession.getConversationSet().discard(header.cid, error); } /** * Send a request command message to the server for a given service. * * @param {CommandHeader} header - The header encapsulating the message's context. * @param {Object} command - The command to send. * @param {Function} serialiser - The serialiser for the command object. */ this.sendRequest = sendRequest; /** * Send a response command message to the server for a given service. * * @param {CommandHeader} header - The header encapsulating the message's context. * @param {Object} command - The command to send. * @param {Function} serialiser - The serialiser for the command object. */ this.sendResponse = sendResponse; /** * Send an error command message to the server for a given service. * * @param {CommandHeader} header - The header encapsulating the message's context. * @param {Object} command - The command to send. * @param {Function} serialiser - The serialiser for the command object. */ this.sendError = sendError; /** * Add a service to the adapter, in order to receive requests from the server. * * @param {ServiceDefinition} definition - The service definition * @param {Service} service - The service implementation */ this.addService = function addService(definition, service) { if (listeners[definition.id] === undefined) { var requestSerialiser = serialisers.get(definition.request); var responseSerialiser = serialisers.get(definition.response); listeners[definition.id] = function(header, input) { var request = requestSerialiser.read(input); var callback = header.cid.equals(ConversationID.ONEWAY_CID) ? NULL_CALLBACK : { /** * Respond to the inbound request. * * @param {Object} response - The response to send */ respond : function(response) { var rHeader = header.createResponseHeader(); sendResponse(rHeader, response, responseSerialiser); }, /** * Return an error to the server. * * @param {String} error - The error reason to send. * @param {String} message - The error message */ fail : function(error, message) { var eHeader = header.createErrorHeader(); sendError(eHeader, error, message); } }; try { service.onRequest(internalSession, request, callback); } catch (e) { log.error(e); throw new Error("Unable to handle request for " + definition.name); } }; } else { throw new Error("Service already exists for " + definition); } }; /** * Callback function to handle inbound command messages to be routed to appropriate * handlers. * * @param {Number} modes - the service message mode. * @param {BufferInputStream} data - The input stream to read from. * @throws Error if parsed CommandHeader is invalid */ this.onMessage = function onMessage(modes, data) { var header = headerSerialiser.read(data); switch (modes) { case Message.types.SERVICE_REQUEST: handleRequest(header, data); break; case Message.types.SERVICE_RESPONSE: handleResponse(header, data); break; case Message.types.SERVICE_ERROR: handleError(header, data); break; default: throw new Error("Unknown Command Service message " + modes); } }; } module.exports = ServiceAdapter;