UNPKG

diffusion

Version:

Diffusion JavaScript client

337 lines (336 loc) 17.4 kB
"use strict"; var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) { function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); } return new (P || (P = Promise))(function (resolve, reject) { function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } } function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } } function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); } step((generator = generator.apply(thisArg, _arguments || [])).next()); }); }; var __generator = (this && this.__generator) || function (thisArg, body) { var _ = { label: 0, sent: function() { if (t[0] & 1) throw t[1]; return t[1]; }, trys: [], ops: [] }, f, y, t, g; return g = { next: verb(0), "throw": verb(1), "return": verb(2) }, typeof Symbol === "function" && (g[Symbol.iterator] = function() { return this; }), g; function verb(n) { return function (v) { return step([n, v]); }; } function step(op) { if (f) throw new TypeError("Generator is already executing."); while (_) try { if (f = 1, y && (t = op[0] & 2 ? y["return"] : op[0] ? y["throw"] || ((t = y["return"]) && t.call(y), 0) : y.next) && !(t = t.call(y, op[1])).done) return t; if (y = 0, t) op = [op[0] & 2, t.value]; switch (op[0]) { case 0: case 1: t = op; break; case 4: _.label++; return { value: op[1], done: false }; case 5: _.label++; y = op[1]; op = [0]; continue; case 7: op = _.ops.pop(); _.trys.pop(); continue; default: if (!(t = _.trys, t = t.length > 0 && t[t.length - 1]) && (op[0] === 6 || op[0] === 2)) { _ = 0; continue; } if (op[0] === 3 && (!t || (op[1] > t[0] && op[1] < t[3]))) { _.label = op[1]; break; } if (op[0] === 6 && _.label < t[1]) { _.label = t[1]; t = op; break; } if (t && _.label < t[2]) { _.label = t[2]; _.ops.push(op); break; } if (t[2]) _.ops.pop(); _.trys.pop(); continue; } op = body.call(thisArg, _); } catch (e) { op = [6, e]; y = 0; } finally { f = t = 0; } if (op[0] & 5) throw op[1]; return { value: op[0] ? op[1] : void 0, done: true }; } }; Object.defineProperty(exports, "__esModule", { value: true }); exports.WorkerSessionAdapter = void 0; var errors_1 = require("./../../errors/errors"); var buffer_input_stream_1 = require("./../io/buffer-input-stream"); var Codec = require("./../io/codec"); var buffer_serialiser_1 = require("./../serialisers/buffer-serialiser"); var command_header_1 = require("./../services/command-header"); var command_header_serialiser_1 = require("./../services/command-header-serialiser"); var session_lock_acquisition_1 = require("./../services/session-lock/session-lock-acquisition"); var logger = require("./../util/logger"); var uint8array_1 = require("./../util/uint8array"); var message_1 = require("./../v4-stack/message"); var worker_stream_registry_adapter_1 = require("./../webworker/topics/worker-stream-registry-adapter"); var worker_command_1 = require("./../webworker/worker-command"); var worker_service_callbacks_1 = require("./../webworker/worker-service-callbacks"); var worker_service_request_registry_1 = require("./../webworker/worker-service-request-registry"); var Long = require("long"); var error_reason_1 = require("../../errors/error-reason"); /* eslint-disable jsdoc/require-jsdoc */ var log = logger.create('WorkerSessionAdapter'); /** * An adapter that lives in the shared worker and passes messages received from * the client side InternalSessionWebworkerProxy to the internal session. */ var WorkerSessionAdapter = /** @class */ (function () { function WorkerSessionAdapter(internal) { this.internal = internal; this.headerSerialiser = command_header_serialiser_1.CommandHeaderSerialiser; this.responseHeaderSerialiser = command_header_serialiser_1.ResponseCommandHeaderSerialiser; this.streamRegistryAdapter = new worker_stream_registry_adapter_1.WorkerStreamRegistryAdapter(internal); this.serviceRequestRegistry = new worker_service_request_registry_1.WorkerServiceRequestRegistry(); this.workerServiceCallbacks = new worker_service_callbacks_1.WorkerServiceCallbacks(); } /** * Create a new WorkerSessionAdapter * * @param internalSessionFactory a factory function creating an internal session * @param options session options * @return a promise that resolves to a new WorkerSessionAdapter once the * session is connected */ WorkerSessionAdapter.create = function (internalSessionFactory, options) { return new Promise(function (resolve, reject) { var internalSession = internalSessionFactory(options); // tslint:disable-next-line:no-unused-variable function onConnect(sessionID) { internalSession.off('connect', onConnect); internalSession.off('close', onError); internalSession.off('error', onError); resolve(new WorkerSessionAdapter(internalSession)); } function onError(err) { internalSession.off('connect', onConnect); internalSession.off('close', onError); internalSession.off('error', onError); reject(err); } internalSession.on('connect', onConnect); internalSession.on('close', onError); internalSession.on('error', onError); internalSession.connect(); }); }; /** * Receive a command from the session proxy in the tab * * @param command the command * @param data data needed to execute the command * @param respond a response callback */ WorkerSessionAdapter.prototype.onCommand = function (command, data, respond) { switch (command) { case worker_command_1.WorkerCommand.MESSAGE: this.onMessage(JSON.parse(data), function (cid, error, response) { if (error !== undefined) { respond(['command_error', cid.toString(), error]); } else { respond(['command_response', cid.toString(), response]); } }); break; case worker_command_1.WorkerCommand.STREAM: this.onStreamAction(JSON.parse(data), function (adapterid, event, error, response) { respond(['stream_event', adapterid.toString(), event, error, response]); }); break; case worker_command_1.WorkerCommand.SERVICE: this.onServiceAction(JSON.parse(data), respond); break; case worker_command_1.WorkerCommand.LOCK: this.onLockAction(JSON.parse(data), function (lockName, action, response) { respond(['lock_event', lockName, action, response]); }); break; default: log.error("Unknown command " + command); } }; WorkerSessionAdapter.prototype.onMessage = function (msg, respond) { switch (msg.type) { case message_1.types.SERVICE_REQUEST: this.sendServiceRequest(msg, respond); break; case message_1.types.SERVICE_RESPONSE: this.sendServiceResponse(msg); break; case message_1.types.SERVICE_ERROR: this.sendServiceError(msg); break; } }; WorkerSessionAdapter.prototype.onStreamAction = function (action, respond) { switch (action.action) { case 'add': this.streamRegistryAdapter.add(action, respond); break; case 'add_fallback': this.streamRegistryAdapter.addFallback(action, respond); break; case 'remove': this.streamRegistryAdapter.remove(action); break; case 'close': this.streamRegistryAdapter.close(); break; default: throw new errors_1.InternalError("Unrecognised stream action: " + action.action); } }; WorkerSessionAdapter.prototype.onServiceAction = function (action, respond) { switch (action.action) { case 'add': this.addService(action.serviceId, respond); break; default: throw new errors_1.InternalError("Unrecognised service action: " + action.action); } }; WorkerSessionAdapter.prototype.onLockAction = function (action, respond) { switch (action.action) { case 'acquire': this.acquireLock(action.requestId, action.name, action.scope, respond); break; case 'release': this.releaseLock(action.requestId, action.sequence, action.name, action.scope, respond); break; default: throw new errors_1.InternalError("Unrecognised lock action: " + action.action); } }; WorkerSessionAdapter.prototype.sendServiceRequest = function (msg, respond) { return __awaiter(this, void 0, void 0, function () { var bis, header, data, handler, conversations; var _this = this; return __generator(this, function (_a) { switch (_a.label) { case 0: bis = new buffer_input_stream_1.BufferInputStream(uint8array_1.uint8FromBase64(msg.stream)); header = this.headerSerialiser.read(bis); data = buffer_serialiser_1.BufferSerialiser.read(bis); handler = { onOpen: function (cid) { var sendHeader = new command_header_1.CommandHeader(header.service, cid); try { _this.internal.getServiceAdapter().sendRequest(sendHeader, data, buffer_serialiser_1.BufferSerialiser); } catch (e) { respond(header.cid, e instanceof Error ? e.toString() : JSON.stringify(e)); throw e; } }, onResponse: function (cid, input) { var response; try { response = buffer_serialiser_1.BufferSerialiser.read(input); } catch (e) { log.debug("Failed to deserialise response from service " + header.service, e.stack); respond(header.cid, e.toString()); return true; } try { respond(header.cid, undefined, uint8array_1.uint8ToBase64(response)); } catch (e) { log.debug("Request callback for service '" + header.service + "' threw an error", e.stack); try { respond(header.cid, e instanceof Error ? e.toString() : JSON.stringify(e)); } catch (e) { log.debug("Failed to notify callback error for service '" + header.service + "'", e); } } return true; }, onDiscard: function (cid, err) { respond(header.cid, err instanceof Error ? err.toString() : JSON.stringify(err)); } }; conversations = this.internal.getConversationSet(); return [4 /*yield*/, conversations.newConversation(handler)]; case 1: _a.sent(); return [2 /*return*/]; } }); }); }; WorkerSessionAdapter.prototype.sendServiceResponse = function (msg) { var bis = new buffer_input_stream_1.BufferInputStream(uint8array_1.uint8FromBase64(msg.stream)); var header = this.responseHeaderSerialiser.read(bis); var data = buffer_serialiser_1.BufferSerialiser.read(bis); var callback = this.serviceRequestRegistry.getCallback(header.cid); callback.respond(data); }; WorkerSessionAdapter.prototype.sendServiceError = function (msg) { var bis = new buffer_input_stream_1.BufferInputStream(uint8array_1.uint8FromBase64(msg.stream)); var header = this.responseHeaderSerialiser.read(bis); var message = Codec.readString(bis); var errorId = Codec.readInt32(bis); var callback = this.serviceRequestRegistry.getCallback(header.cid); callback.fail(error_reason_1.ErrorReason[error_reason_1.ErrorReason[errorId]], message); }; WorkerSessionAdapter.prototype.addService = function (serviceId, respond) { var _this = this; if (!this.internal.getServiceAdapter().isServiceRegistered(serviceId)) { this.internal.getServiceAdapter().addService({ id: serviceId, request: buffer_serialiser_1.BufferSerialiser, response: buffer_serialiser_1.BufferSerialiser }, { onRequest: function (internal, request, callback) { var rid = _this.serviceRequestRegistry.addRequest(callback); _this.workerServiceCallbacks.onRequest(serviceId, request, rid); } }); } this.workerServiceCallbacks.addService(serviceId, respond); }; /** * acquire a session lock */ WorkerSessionAdapter.prototype.acquireLock = function (requestId, name, scope, respond) { return __awaiter(this, void 0, void 0, function () { var sessionLock, err_1; return __generator(this, function (_a) { switch (_a.label) { case 0: _a.trys.push([0, 2, , 3]); return [4 /*yield*/, this.internal.lock(name, scope, { onOwned: function (newOwned) { respond(name, worker_command_1.WorkerSessionLockCommand.OWNED, newOwned); }, onRemoveLock: function () { respond(name, worker_command_1.WorkerSessionLockCommand.REMOVED, undefined); } })]; case 1: sessionLock = _a.sent(); respond(name, worker_command_1.WorkerSessionLockCommand.ACQUIRED, [requestId, sessionLock.getSequence().toString(10), sessionLock.getScope()]); return [3 /*break*/, 3]; case 2: err_1 = _a.sent(); respond(name, worker_command_1.WorkerSessionLockCommand.ACQUIRE_ERROR, [requestId, err_1]); return [3 /*break*/, 3]; case 3: return [2 /*return*/]; } }); }); }; /** * release a session lock */ WorkerSessionAdapter.prototype.releaseLock = function (requestId, sequence, name, scope, respond) { return __awaiter(this, void 0, void 0, function () { var acquisition, success, err_2; return __generator(this, function (_a) { switch (_a.label) { case 0: _a.trys.push([0, 2, , 3]); acquisition = new session_lock_acquisition_1.SessionLockAcquisition(name, Long.fromString(sequence, 10), scope); return [4 /*yield*/, this.internal.unlock(acquisition)]; case 1: success = _a.sent(); respond(name, worker_command_1.WorkerSessionLockCommand.RELEASED, [requestId, success]); return [3 /*break*/, 3]; case 2: err_2 = _a.sent(); respond(name, worker_command_1.WorkerSessionLockCommand.RELEASE_ERROR, [requestId, err_2]); return [3 /*break*/, 3]; case 3: return [2 /*return*/]; } }); }); }; return WorkerSessionAdapter; }()); exports.WorkerSessionAdapter = WorkerSessionAdapter;