You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
521 lines
16 KiB
521 lines
16 KiB
6 years ago
|
/**
|
||
|
* @licstart The following is the entire license notice for the
|
||
|
* Javascript code in this page
|
||
|
*
|
||
|
* Copyright 2018 Mozilla Foundation
|
||
|
*
|
||
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||
|
* you may not use this file except in compliance with the License.
|
||
|
* You may obtain a copy of the License at
|
||
|
*
|
||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||
|
*
|
||
|
* Unless required by applicable law or agreed to in writing, software
|
||
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
||
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||
|
* See the License for the specific language governing permissions and
|
||
|
* limitations under the License.
|
||
|
*
|
||
|
* @licend The above is the entire license notice for the
|
||
|
* Javascript code in this page
|
||
|
*/
|
||
|
"use strict";
|
||
|
|
||
|
Object.defineProperty(exports, "__esModule", {
|
||
|
value: true
|
||
|
});
|
||
|
exports.MessageHandler = MessageHandler;
|
||
|
|
||
|
var _regenerator = _interopRequireDefault(require("@babel/runtime/regenerator"));
|
||
|
|
||
|
var _util = require("./util");
|
||
|
|
||
|
function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
|
||
|
|
||
|
function _typeof(obj) { if (typeof Symbol === "function" && typeof Symbol.iterator === "symbol") { _typeof = function _typeof(obj) { return typeof obj; }; } else { _typeof = function _typeof(obj) { return obj && typeof Symbol === "function" && obj.constructor === Symbol && obj !== Symbol.prototype ? "symbol" : typeof obj; }; } return _typeof(obj); }
|
||
|
|
||
|
function asyncGeneratorStep(gen, resolve, reject, _next, _throw, key, arg) { try { var info = gen[key](arg); var value = info.value; } catch (error) { reject(error); return; } if (info.done) { resolve(value); } else { Promise.resolve(value).then(_next, _throw); } }
|
||
|
|
||
|
function _asyncToGenerator(fn) { return function () { var self = this, args = arguments; return new Promise(function (resolve, reject) { var gen = fn.apply(self, args); function _next(value) { asyncGeneratorStep(gen, resolve, reject, _next, _throw, "next", value); } function _throw(err) { asyncGeneratorStep(gen, resolve, reject, _next, _throw, "throw", err); } _next(undefined); }); }; }
|
||
|
|
||
|
function resolveCall(_x, _x2) {
|
||
|
return _resolveCall.apply(this, arguments);
|
||
|
}
|
||
|
|
||
|
function _resolveCall() {
|
||
|
_resolveCall = _asyncToGenerator(
|
||
|
/*#__PURE__*/
|
||
|
_regenerator.default.mark(function _callee(fn, args) {
|
||
|
var thisArg,
|
||
|
_args = arguments;
|
||
|
return _regenerator.default.wrap(function _callee$(_context) {
|
||
|
while (1) {
|
||
|
switch (_context.prev = _context.next) {
|
||
|
case 0:
|
||
|
thisArg = _args.length > 2 && _args[2] !== undefined ? _args[2] : null;
|
||
|
|
||
|
if (fn) {
|
||
|
_context.next = 3;
|
||
|
break;
|
||
|
}
|
||
|
|
||
|
return _context.abrupt("return");
|
||
|
|
||
|
case 3:
|
||
|
return _context.abrupt("return", fn.apply(thisArg, args));
|
||
|
|
||
|
case 4:
|
||
|
case "end":
|
||
|
return _context.stop();
|
||
|
}
|
||
|
}
|
||
|
}, _callee, this);
|
||
|
}));
|
||
|
return _resolveCall.apply(this, arguments);
|
||
|
}
|
||
|
|
||
|
function wrapReason(reason) {
|
||
|
if (_typeof(reason) !== 'object') {
|
||
|
return reason;
|
||
|
}
|
||
|
|
||
|
switch (reason.name) {
|
||
|
case 'AbortException':
|
||
|
return new _util.AbortException(reason.message);
|
||
|
|
||
|
case 'MissingPDFException':
|
||
|
return new _util.MissingPDFException(reason.message);
|
||
|
|
||
|
case 'UnexpectedResponseException':
|
||
|
return new _util.UnexpectedResponseException(reason.message, reason.status);
|
||
|
|
||
|
default:
|
||
|
return new _util.UnknownErrorException(reason.message, reason.details);
|
||
|
}
|
||
|
}
|
||
|
|
||
|
function makeReasonSerializable(reason) {
|
||
|
if (!(reason instanceof Error) || reason instanceof _util.AbortException || reason instanceof _util.MissingPDFException || reason instanceof _util.UnexpectedResponseException || reason instanceof _util.UnknownErrorException) {
|
||
|
return reason;
|
||
|
}
|
||
|
|
||
|
return new _util.UnknownErrorException(reason.message, reason.toString());
|
||
|
}
|
||
|
|
||
|
function resolveOrReject(capability, success, reason) {
|
||
|
if (success) {
|
||
|
capability.resolve();
|
||
|
} else {
|
||
|
capability.reject(reason);
|
||
|
}
|
||
|
}
|
||
|
|
||
|
function finalize(promise) {
|
||
|
return Promise.resolve(promise).catch(function () {});
|
||
|
}
|
||
|
|
||
|
function MessageHandler(sourceName, targetName, comObj) {
|
||
|
var _this = this;
|
||
|
|
||
|
this.sourceName = sourceName;
|
||
|
this.targetName = targetName;
|
||
|
this.comObj = comObj;
|
||
|
this.callbackId = 1;
|
||
|
this.streamId = 1;
|
||
|
this.postMessageTransfers = true;
|
||
|
this.streamSinks = Object.create(null);
|
||
|
this.streamControllers = Object.create(null);
|
||
|
var callbacksCapabilities = this.callbacksCapabilities = Object.create(null);
|
||
|
var ah = this.actionHandler = Object.create(null);
|
||
|
|
||
|
this._onComObjOnMessage = function (event) {
|
||
|
var data = event.data;
|
||
|
|
||
|
if (data.targetName !== _this.sourceName) {
|
||
|
return;
|
||
|
}
|
||
|
|
||
|
if (data.stream) {
|
||
|
_this._processStreamMessage(data);
|
||
|
} else if (data.isReply) {
|
||
|
var callbackId = data.callbackId;
|
||
|
|
||
|
if (data.callbackId in callbacksCapabilities) {
|
||
|
var callback = callbacksCapabilities[callbackId];
|
||
|
delete callbacksCapabilities[callbackId];
|
||
|
|
||
|
if ('error' in data) {
|
||
|
callback.reject(wrapReason(data.error));
|
||
|
} else {
|
||
|
callback.resolve(data.data);
|
||
|
}
|
||
|
} else {
|
||
|
throw new Error("Cannot resolve callback ".concat(callbackId));
|
||
|
}
|
||
|
} else if (data.action in ah) {
|
||
|
var action = ah[data.action];
|
||
|
|
||
|
if (data.callbackId) {
|
||
|
var _sourceName = _this.sourceName;
|
||
|
var _targetName = data.sourceName;
|
||
|
Promise.resolve().then(function () {
|
||
|
return action[0].call(action[1], data.data);
|
||
|
}).then(function (result) {
|
||
|
comObj.postMessage({
|
||
|
sourceName: _sourceName,
|
||
|
targetName: _targetName,
|
||
|
isReply: true,
|
||
|
callbackId: data.callbackId,
|
||
|
data: result
|
||
|
});
|
||
|
}, function (reason) {
|
||
|
comObj.postMessage({
|
||
|
sourceName: _sourceName,
|
||
|
targetName: _targetName,
|
||
|
isReply: true,
|
||
|
callbackId: data.callbackId,
|
||
|
error: makeReasonSerializable(reason)
|
||
|
});
|
||
|
});
|
||
|
} else if (data.streamId) {
|
||
|
_this._createStreamSink(data);
|
||
|
} else {
|
||
|
action[0].call(action[1], data.data);
|
||
|
}
|
||
|
} else {
|
||
|
throw new Error("Unknown action from worker: ".concat(data.action));
|
||
|
}
|
||
|
};
|
||
|
|
||
|
comObj.addEventListener('message', this._onComObjOnMessage);
|
||
|
}
|
||
|
|
||
|
MessageHandler.prototype = {
|
||
|
on: function on(actionName, handler, scope) {
|
||
|
var ah = this.actionHandler;
|
||
|
|
||
|
if (ah[actionName]) {
|
||
|
throw new Error("There is already an actionName called \"".concat(actionName, "\""));
|
||
|
}
|
||
|
|
||
|
ah[actionName] = [handler, scope];
|
||
|
},
|
||
|
send: function send(actionName, data, transfers) {
|
||
|
var message = {
|
||
|
sourceName: this.sourceName,
|
||
|
targetName: this.targetName,
|
||
|
action: actionName,
|
||
|
data: data
|
||
|
};
|
||
|
this.postMessage(message, transfers);
|
||
|
},
|
||
|
sendWithPromise: function sendWithPromise(actionName, data, transfers) {
|
||
|
var callbackId = this.callbackId++;
|
||
|
var message = {
|
||
|
sourceName: this.sourceName,
|
||
|
targetName: this.targetName,
|
||
|
action: actionName,
|
||
|
data: data,
|
||
|
callbackId: callbackId
|
||
|
};
|
||
|
var capability = (0, _util.createPromiseCapability)();
|
||
|
this.callbacksCapabilities[callbackId] = capability;
|
||
|
|
||
|
try {
|
||
|
this.postMessage(message, transfers);
|
||
|
} catch (e) {
|
||
|
capability.reject(e);
|
||
|
}
|
||
|
|
||
|
return capability.promise;
|
||
|
},
|
||
|
sendWithStream: function sendWithStream(actionName, data, queueingStrategy, transfers) {
|
||
|
var _this2 = this;
|
||
|
|
||
|
var streamId = this.streamId++;
|
||
|
var sourceName = this.sourceName;
|
||
|
var targetName = this.targetName;
|
||
|
return new _util.ReadableStream({
|
||
|
start: function start(controller) {
|
||
|
var startCapability = (0, _util.createPromiseCapability)();
|
||
|
_this2.streamControllers[streamId] = {
|
||
|
controller: controller,
|
||
|
startCall: startCapability,
|
||
|
isClosed: false
|
||
|
};
|
||
|
|
||
|
_this2.postMessage({
|
||
|
sourceName: sourceName,
|
||
|
targetName: targetName,
|
||
|
action: actionName,
|
||
|
streamId: streamId,
|
||
|
data: data,
|
||
|
desiredSize: controller.desiredSize
|
||
|
});
|
||
|
|
||
|
return startCapability.promise;
|
||
|
},
|
||
|
pull: function pull(controller) {
|
||
|
var pullCapability = (0, _util.createPromiseCapability)();
|
||
|
_this2.streamControllers[streamId].pullCall = pullCapability;
|
||
|
|
||
|
_this2.postMessage({
|
||
|
sourceName: sourceName,
|
||
|
targetName: targetName,
|
||
|
stream: 'pull',
|
||
|
streamId: streamId,
|
||
|
desiredSize: controller.desiredSize
|
||
|
});
|
||
|
|
||
|
return pullCapability.promise;
|
||
|
},
|
||
|
cancel: function cancel(reason) {
|
||
|
var cancelCapability = (0, _util.createPromiseCapability)();
|
||
|
_this2.streamControllers[streamId].cancelCall = cancelCapability;
|
||
|
_this2.streamControllers[streamId].isClosed = true;
|
||
|
|
||
|
_this2.postMessage({
|
||
|
sourceName: sourceName,
|
||
|
targetName: targetName,
|
||
|
stream: 'cancel',
|
||
|
reason: reason,
|
||
|
streamId: streamId
|
||
|
});
|
||
|
|
||
|
return cancelCapability.promise;
|
||
|
}
|
||
|
}, queueingStrategy);
|
||
|
},
|
||
|
_createStreamSink: function _createStreamSink(data) {
|
||
|
var _this3 = this;
|
||
|
|
||
|
var self = this;
|
||
|
var action = this.actionHandler[data.action];
|
||
|
var streamId = data.streamId;
|
||
|
var desiredSize = data.desiredSize;
|
||
|
var sourceName = this.sourceName;
|
||
|
var targetName = data.sourceName;
|
||
|
var capability = (0, _util.createPromiseCapability)();
|
||
|
|
||
|
var sendStreamRequest = function sendStreamRequest(_ref) {
|
||
|
var stream = _ref.stream,
|
||
|
chunk = _ref.chunk,
|
||
|
transfers = _ref.transfers,
|
||
|
success = _ref.success,
|
||
|
reason = _ref.reason;
|
||
|
|
||
|
_this3.postMessage({
|
||
|
sourceName: sourceName,
|
||
|
targetName: targetName,
|
||
|
stream: stream,
|
||
|
streamId: streamId,
|
||
|
chunk: chunk,
|
||
|
success: success,
|
||
|
reason: reason
|
||
|
}, transfers);
|
||
|
};
|
||
|
|
||
|
var streamSink = {
|
||
|
enqueue: function enqueue(chunk) {
|
||
|
var size = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : 1;
|
||
|
var transfers = arguments.length > 2 ? arguments[2] : undefined;
|
||
|
|
||
|
if (this.isCancelled) {
|
||
|
return;
|
||
|
}
|
||
|
|
||
|
var lastDesiredSize = this.desiredSize;
|
||
|
this.desiredSize -= size;
|
||
|
|
||
|
if (lastDesiredSize > 0 && this.desiredSize <= 0) {
|
||
|
this.sinkCapability = (0, _util.createPromiseCapability)();
|
||
|
this.ready = this.sinkCapability.promise;
|
||
|
}
|
||
|
|
||
|
sendStreamRequest({
|
||
|
stream: 'enqueue',
|
||
|
chunk: chunk,
|
||
|
transfers: transfers
|
||
|
});
|
||
|
},
|
||
|
close: function close() {
|
||
|
if (this.isCancelled) {
|
||
|
return;
|
||
|
}
|
||
|
|
||
|
this.isCancelled = true;
|
||
|
sendStreamRequest({
|
||
|
stream: 'close'
|
||
|
});
|
||
|
delete self.streamSinks[streamId];
|
||
|
},
|
||
|
error: function error(reason) {
|
||
|
if (this.isCancelled) {
|
||
|
return;
|
||
|
}
|
||
|
|
||
|
this.isCancelled = true;
|
||
|
sendStreamRequest({
|
||
|
stream: 'error',
|
||
|
reason: reason
|
||
|
});
|
||
|
},
|
||
|
sinkCapability: capability,
|
||
|
onPull: null,
|
||
|
onCancel: null,
|
||
|
isCancelled: false,
|
||
|
desiredSize: desiredSize,
|
||
|
ready: null
|
||
|
};
|
||
|
streamSink.sinkCapability.resolve();
|
||
|
streamSink.ready = streamSink.sinkCapability.promise;
|
||
|
this.streamSinks[streamId] = streamSink;
|
||
|
resolveCall(action[0], [data.data, streamSink], action[1]).then(function () {
|
||
|
sendStreamRequest({
|
||
|
stream: 'start_complete',
|
||
|
success: true
|
||
|
});
|
||
|
}, function (reason) {
|
||
|
sendStreamRequest({
|
||
|
stream: 'start_complete',
|
||
|
success: false,
|
||
|
reason: reason
|
||
|
});
|
||
|
});
|
||
|
},
|
||
|
_processStreamMessage: function _processStreamMessage(data) {
|
||
|
var _this4 = this;
|
||
|
|
||
|
var sourceName = this.sourceName;
|
||
|
var targetName = data.sourceName;
|
||
|
var streamId = data.streamId;
|
||
|
|
||
|
var sendStreamResponse = function sendStreamResponse(_ref2) {
|
||
|
var stream = _ref2.stream,
|
||
|
success = _ref2.success,
|
||
|
reason = _ref2.reason;
|
||
|
|
||
|
_this4.comObj.postMessage({
|
||
|
sourceName: sourceName,
|
||
|
targetName: targetName,
|
||
|
stream: stream,
|
||
|
success: success,
|
||
|
streamId: streamId,
|
||
|
reason: reason
|
||
|
});
|
||
|
};
|
||
|
|
||
|
var deleteStreamController = function deleteStreamController() {
|
||
|
Promise.all([_this4.streamControllers[data.streamId].startCall, _this4.streamControllers[data.streamId].pullCall, _this4.streamControllers[data.streamId].cancelCall].map(function (capability) {
|
||
|
return capability && finalize(capability.promise);
|
||
|
})).then(function () {
|
||
|
delete _this4.streamControllers[data.streamId];
|
||
|
});
|
||
|
};
|
||
|
|
||
|
switch (data.stream) {
|
||
|
case 'start_complete':
|
||
|
resolveOrReject(this.streamControllers[data.streamId].startCall, data.success, wrapReason(data.reason));
|
||
|
break;
|
||
|
|
||
|
case 'pull_complete':
|
||
|
resolveOrReject(this.streamControllers[data.streamId].pullCall, data.success, wrapReason(data.reason));
|
||
|
break;
|
||
|
|
||
|
case 'pull':
|
||
|
if (!this.streamSinks[data.streamId]) {
|
||
|
sendStreamResponse({
|
||
|
stream: 'pull_complete',
|
||
|
success: true
|
||
|
});
|
||
|
break;
|
||
|
}
|
||
|
|
||
|
if (this.streamSinks[data.streamId].desiredSize <= 0 && data.desiredSize > 0) {
|
||
|
this.streamSinks[data.streamId].sinkCapability.resolve();
|
||
|
}
|
||
|
|
||
|
this.streamSinks[data.streamId].desiredSize = data.desiredSize;
|
||
|
resolveCall(this.streamSinks[data.streamId].onPull).then(function () {
|
||
|
sendStreamResponse({
|
||
|
stream: 'pull_complete',
|
||
|
success: true
|
||
|
});
|
||
|
}, function (reason) {
|
||
|
sendStreamResponse({
|
||
|
stream: 'pull_complete',
|
||
|
success: false,
|
||
|
reason: reason
|
||
|
});
|
||
|
});
|
||
|
break;
|
||
|
|
||
|
case 'enqueue':
|
||
|
(0, _util.assert)(this.streamControllers[data.streamId], 'enqueue should have stream controller');
|
||
|
|
||
|
if (!this.streamControllers[data.streamId].isClosed) {
|
||
|
this.streamControllers[data.streamId].controller.enqueue(data.chunk);
|
||
|
}
|
||
|
|
||
|
break;
|
||
|
|
||
|
case 'close':
|
||
|
(0, _util.assert)(this.streamControllers[data.streamId], 'close should have stream controller');
|
||
|
|
||
|
if (this.streamControllers[data.streamId].isClosed) {
|
||
|
break;
|
||
|
}
|
||
|
|
||
|
this.streamControllers[data.streamId].isClosed = true;
|
||
|
this.streamControllers[data.streamId].controller.close();
|
||
|
deleteStreamController();
|
||
|
break;
|
||
|
|
||
|
case 'error':
|
||
|
(0, _util.assert)(this.streamControllers[data.streamId], 'error should have stream controller');
|
||
|
this.streamControllers[data.streamId].controller.error(wrapReason(data.reason));
|
||
|
deleteStreamController();
|
||
|
break;
|
||
|
|
||
|
case 'cancel_complete':
|
||
|
resolveOrReject(this.streamControllers[data.streamId].cancelCall, data.success, wrapReason(data.reason));
|
||
|
deleteStreamController();
|
||
|
break;
|
||
|
|
||
|
case 'cancel':
|
||
|
if (!this.streamSinks[data.streamId]) {
|
||
|
break;
|
||
|
}
|
||
|
|
||
|
resolveCall(this.streamSinks[data.streamId].onCancel, [wrapReason(data.reason)]).then(function () {
|
||
|
sendStreamResponse({
|
||
|
stream: 'cancel_complete',
|
||
|
success: true
|
||
|
});
|
||
|
}, function (reason) {
|
||
|
sendStreamResponse({
|
||
|
stream: 'cancel_complete',
|
||
|
success: false,
|
||
|
reason: reason
|
||
|
});
|
||
|
});
|
||
|
this.streamSinks[data.streamId].sinkCapability.reject(wrapReason(data.reason));
|
||
|
this.streamSinks[data.streamId].isCancelled = true;
|
||
|
delete this.streamSinks[data.streamId];
|
||
|
break;
|
||
|
|
||
|
default:
|
||
|
throw new Error('Unexpected stream case');
|
||
|
}
|
||
|
},
|
||
|
postMessage: function postMessage(message, transfers) {
|
||
|
if (transfers && this.postMessageTransfers) {
|
||
|
this.comObj.postMessage(message, transfers);
|
||
|
} else {
|
||
|
this.comObj.postMessage(message);
|
||
|
}
|
||
|
},
|
||
|
destroy: function destroy() {
|
||
|
this.comObj.removeEventListener('message', this._onComObjOnMessage);
|
||
|
}
|
||
|
};
|