diffusion
Version:
Diffusion JavaScript client
337 lines (336 loc) • 17.4 kB
JavaScript
"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;