diffusion
Version:
Diffusion JavaScript client
221 lines (220 loc) • 9.36 kB
JavaScript
;
/**
* @module Client
*/
Object.defineProperty(exports, "__esModule", { value: true });
exports.ServiceAdapter = void 0;
var errors_1 = require("./../../errors/errors");
var error_reason_1 = require("./../client/error-reason");
var conversation_id_1 = require("./../conversation/conversation-id");
var conversation_id_serialiser_1 = require("./../conversation/conversation-id-serialiser");
var Codec = require("./../io/codec");
var command_header_serialiser_1 = require("./../services/command-header-serialiser");
var logger = require("./../util/logger");
var message_1 = require("./../v4-stack/message");
var error_reason_2 = require("../../errors/error-reason");
var log = logger.create('ServiceAdapter');
/**
* A service callback that does nothing
*/
var NULL_CALLBACK = {
respond: function () {
// no-op
},
fail: function () {
// no-op
}
};
/**
* Adaptor to bridge v4-stack components and command services.
*/
var ServiceAdapter = /** @class */ (function () {
/**
* Create a new ServiceAdapter instance
*
* @param internalSession the internal session this adapter is bound to
* @param sender the function to enqueue messages
*/
function ServiceAdapter(internalSession, sender) {
/**
* Listeners that have bee registered for each command service
*/
this.listeners = {};
this.internalSession = internalSession;
this.sender = sender;
}
/**
* Send a request command message to the server for a given service.
*
* @param header the header encapsulating the message's context.
* @param command the command to send.
* @param serialiser the serialiser for the command object.
*/
ServiceAdapter.prototype.sendRequest = function (header, command, serialiser) {
var msg = message_1.create({
type: message_1.types.SERVICE_REQUEST
});
var bos = msg.getStream();
command_header_serialiser_1.CommandHeaderSerialiser.write(bos, header);
serialiser.write(bos, command);
log.debug('Sending command request: ' + header, command);
this.sender(msg);
};
/**
* Send a response command message to the server for a given service.
*
* @param header the header encapsulating the message's context.
* @param command the command to send.
* @param serialiser the serialiser for the command object.
*/
ServiceAdapter.prototype.sendResponse = function (header, command, serialiser) {
var msg = message_1.create({
type: message_1.types.SERVICE_RESPONSE
});
var bos = msg.getStream();
command_header_serialiser_1.ResponseCommandHeaderSerialiser.write(bos, header);
serialiser.write(bos, command);
log.debug('Sending command response: ' + header, command);
this.sender(msg);
};
/**
* Send an error command message to the server for a given service.
*
* @param header the header encapsulating the message's context.
* @param command the command to send.
* @param serialiser the serialiser for the command object.
*/
ServiceAdapter.prototype.sendError = function (header, error, message) {
var msg = message_1.create({
type: message_1.types.SERVICE_ERROR
});
var bos = msg.getStream();
command_header_serialiser_1.ResponseCommandHeaderSerialiser.write(bos, header);
Codec.writeString(bos, message);
// eslint-disable-next-line deprecation/deprecation
Codec.writeInt32(bos, error.id);
// eslint-disable-next-line deprecation/deprecation
log.debug('Sending command error: ' + error.id, message);
this.sender(msg);
};
/**
* Add a service to the adapter, in order to receive requests from the server.
*
* @param definition the service definition
* @param service the service implementation
*
* @throws a {@link RuntimeError} if the service is already registered
*/
ServiceAdapter.prototype.addService = function (definition, service) {
var _this = this;
// tslint:disable-next-line:strict-type-predicates
if (this.listeners[definition.id] === undefined) {
var requestSerialiser_1 = definition.request;
var responseSerialiser_1 = definition.response;
this.listeners[definition.id] = function (header, input) {
var request = requestSerialiser_1.read(input);
var callback = header.cid.equals(conversation_id_1.ONEWAY_CID) ? NULL_CALLBACK : {
// respond to the inbound request.
respond: function (response) {
var rHeader = header.createResponseHeader();
_this.sendResponse(rHeader, response, responseSerialiser_1);
},
// return an error to the server.
fail: function (error, message, rethrowError) {
if (rethrowError === void 0) { rethrowError = true; }
var eHeader = header.createErrorHeader();
_this.sendError(eHeader, error, message);
if (rethrowError) {
// rethrow the error so that the registration adapter can unregister the handler
throw new errors_1.RuntimeError('Callback received an error', error);
}
}
};
try {
service.onRequest(_this.internalSession, request, callback);
}
catch (e) {
log.error(e);
throw new errors_1.RuntimeError("Unable to handle request for service " + definition.id);
}
};
}
else {
throw new errors_1.RuntimeError("Service already exists for service " + definition.id);
}
};
/**
* Checks whether a service is already registered.
*/
ServiceAdapter.prototype.isServiceRegistered = function (serviceId) {
// tslint:disable-next-line:strict-type-predicates
return (this.listeners[serviceId] !== undefined);
};
/**
* Callback function to handle inbound command messages to be routed to appropriate
* handlers.
*
* @param modes the service message mode.
* @param data the input stream to read from.
* @throws an {@link AssertionError} if called with an unknown message type or
* a {@link RuntimeError} if the request could not be handled by the service.
*/
ServiceAdapter.prototype.onMessage = function (modes, data) {
switch (modes) {
case message_1.types.SERVICE_REQUEST:
this.handleRequest(command_header_serialiser_1.CommandHeaderSerialiser.read(data), data);
break;
case message_1.types.SERVICE_RESPONSE:
this.handleResponse(conversation_id_serialiser_1.CIDSerialiser.read(data), data);
break;
case message_1.types.SERVICE_ERROR:
this.handleError(conversation_id_serialiser_1.CIDSerialiser.read(data), data);
break;
default:
throw new errors_1.AssertionError("Unknown Command Service message " + modes);
}
};
/**
* Handle an incoming request
*
* @param header the command header of the request
* @param input the stream containing the data of the request
* @throws a {@link RuntimeError} if the request could not be handled by the service
*/
ServiceAdapter.prototype.handleRequest = function (header, input) {
var listener = this.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);
this.sendError(header.createErrorHeader(), error_reason_2.ErrorReason.COMMUNICATION_FAILURE, "Unknown client service: " + header.service);
}
};
/**
* Handle a response coming back from the server
*
* @param header the command header of the response
* @param input the stream containing the data of the response
*/
ServiceAdapter.prototype.handleResponse = function (cid, input) {
log.debug('Received command response: ' + cid);
this.internalSession.getConversationSet().respondIfPresent(cid, input);
};
/**
* Handle an error coming back from the server
*
* @param header the command header of the error
* @param input the stream containing the data of the error
*/
ServiceAdapter.prototype.handleError = function (cid, input) {
var description = Codec.readString(input);
var code = Codec.readInt32(input);
var error = new error_reason_1.ErrorReason(code, description);
log.warn('Received command error', error);
this.internalSession.getConversationSet().discard(cid, error);
};
return ServiceAdapter;
}());
exports.ServiceAdapter = ServiceAdapter;