diffusion
Version:
Diffusion JavaScript client
208 lines (173 loc) • 7.09 kB
JavaScript
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;