UNPKG

diffusion

Version:

Diffusion JavaScript client

221 lines (220 loc) 9.36 kB
"use strict"; /** * @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;