message_handler.js 16 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521
  1. /**
  2. * @licstart The following is the entire license notice for the
  3. * Javascript code in this page
  4. *
  5. * Copyright 2019 Mozilla Foundation
  6. *
  7. * Licensed under the Apache License, Version 2.0 (the "License");
  8. * you may not use this file except in compliance with the License.
  9. * You may obtain a copy of the License at
  10. *
  11. * http://www.apache.org/licenses/LICENSE-2.0
  12. *
  13. * Unless required by applicable law or agreed to in writing, software
  14. * distributed under the License is distributed on an "AS IS" BASIS,
  15. * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  16. * See the License for the specific language governing permissions and
  17. * limitations under the License.
  18. *
  19. * @licend The above is the entire license notice for the
  20. * Javascript code in this page
  21. */
  22. "use strict";
  23. Object.defineProperty(exports, "__esModule", {
  24. value: true
  25. });
  26. exports.MessageHandler = MessageHandler;
  27. var _regenerator = _interopRequireDefault(require("@babel/runtime/regenerator"));
  28. var _util = require("./util");
  29. function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { "default": obj }; }
  30. 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); }
  31. 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); } }
  32. 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); }); }; }
  33. function resolveCall(_x, _x2) {
  34. return _resolveCall.apply(this, arguments);
  35. }
  36. function _resolveCall() {
  37. _resolveCall = _asyncToGenerator(
  38. /*#__PURE__*/
  39. _regenerator["default"].mark(function _callee(fn, args) {
  40. var thisArg,
  41. _args = arguments;
  42. return _regenerator["default"].wrap(function _callee$(_context) {
  43. while (1) {
  44. switch (_context.prev = _context.next) {
  45. case 0:
  46. thisArg = _args.length > 2 && _args[2] !== undefined ? _args[2] : null;
  47. if (fn) {
  48. _context.next = 3;
  49. break;
  50. }
  51. return _context.abrupt("return", undefined);
  52. case 3:
  53. return _context.abrupt("return", fn.apply(thisArg, args));
  54. case 4:
  55. case "end":
  56. return _context.stop();
  57. }
  58. }
  59. }, _callee);
  60. }));
  61. return _resolveCall.apply(this, arguments);
  62. }
  63. function wrapReason(reason) {
  64. if (_typeof(reason) !== 'object') {
  65. return reason;
  66. }
  67. switch (reason.name) {
  68. case 'AbortException':
  69. return new _util.AbortException(reason.message);
  70. case 'MissingPDFException':
  71. return new _util.MissingPDFException(reason.message);
  72. case 'UnexpectedResponseException':
  73. return new _util.UnexpectedResponseException(reason.message, reason.status);
  74. default:
  75. return new _util.UnknownErrorException(reason.message, reason.details);
  76. }
  77. }
  78. function makeReasonSerializable(reason) {
  79. if (!(reason instanceof Error) || reason instanceof _util.AbortException || reason instanceof _util.MissingPDFException || reason instanceof _util.UnexpectedResponseException || reason instanceof _util.UnknownErrorException) {
  80. return reason;
  81. }
  82. return new _util.UnknownErrorException(reason.message, reason.toString());
  83. }
  84. function resolveOrReject(capability, success, reason) {
  85. if (success) {
  86. capability.resolve();
  87. } else {
  88. capability.reject(reason);
  89. }
  90. }
  91. function finalize(promise) {
  92. return Promise.resolve(promise)["catch"](function () {});
  93. }
  94. function MessageHandler(sourceName, targetName, comObj) {
  95. var _this = this;
  96. this.sourceName = sourceName;
  97. this.targetName = targetName;
  98. this.comObj = comObj;
  99. this.callbackId = 1;
  100. this.streamId = 1;
  101. this.postMessageTransfers = true;
  102. this.streamSinks = Object.create(null);
  103. this.streamControllers = Object.create(null);
  104. var callbacksCapabilities = this.callbacksCapabilities = Object.create(null);
  105. var ah = this.actionHandler = Object.create(null);
  106. this._onComObjOnMessage = function (event) {
  107. var data = event.data;
  108. if (data.targetName !== _this.sourceName) {
  109. return;
  110. }
  111. if (data.stream) {
  112. _this._processStreamMessage(data);
  113. } else if (data.isReply) {
  114. var callbackId = data.callbackId;
  115. if (data.callbackId in callbacksCapabilities) {
  116. var callback = callbacksCapabilities[callbackId];
  117. delete callbacksCapabilities[callbackId];
  118. if ('error' in data) {
  119. callback.reject(wrapReason(data.error));
  120. } else {
  121. callback.resolve(data.data);
  122. }
  123. } else {
  124. throw new Error("Cannot resolve callback ".concat(callbackId));
  125. }
  126. } else if (data.action in ah) {
  127. var action = ah[data.action];
  128. if (data.callbackId) {
  129. var _sourceName = _this.sourceName;
  130. var _targetName = data.sourceName;
  131. Promise.resolve().then(function () {
  132. return action[0].call(action[1], data.data);
  133. }).then(function (result) {
  134. comObj.postMessage({
  135. sourceName: _sourceName,
  136. targetName: _targetName,
  137. isReply: true,
  138. callbackId: data.callbackId,
  139. data: result
  140. });
  141. }, function (reason) {
  142. comObj.postMessage({
  143. sourceName: _sourceName,
  144. targetName: _targetName,
  145. isReply: true,
  146. callbackId: data.callbackId,
  147. error: makeReasonSerializable(reason)
  148. });
  149. });
  150. } else if (data.streamId) {
  151. _this._createStreamSink(data);
  152. } else {
  153. action[0].call(action[1], data.data);
  154. }
  155. } else {
  156. throw new Error("Unknown action from worker: ".concat(data.action));
  157. }
  158. };
  159. comObj.addEventListener('message', this._onComObjOnMessage);
  160. }
  161. MessageHandler.prototype = {
  162. on: function on(actionName, handler, scope) {
  163. var ah = this.actionHandler;
  164. if (ah[actionName]) {
  165. throw new Error("There is already an actionName called \"".concat(actionName, "\""));
  166. }
  167. ah[actionName] = [handler, scope];
  168. },
  169. send: function send(actionName, data, transfers) {
  170. var message = {
  171. sourceName: this.sourceName,
  172. targetName: this.targetName,
  173. action: actionName,
  174. data: data
  175. };
  176. this.postMessage(message, transfers);
  177. },
  178. sendWithPromise: function sendWithPromise(actionName, data, transfers) {
  179. var callbackId = this.callbackId++;
  180. var message = {
  181. sourceName: this.sourceName,
  182. targetName: this.targetName,
  183. action: actionName,
  184. data: data,
  185. callbackId: callbackId
  186. };
  187. var capability = (0, _util.createPromiseCapability)();
  188. this.callbacksCapabilities[callbackId] = capability;
  189. try {
  190. this.postMessage(message, transfers);
  191. } catch (e) {
  192. capability.reject(e);
  193. }
  194. return capability.promise;
  195. },
  196. sendWithStream: function sendWithStream(actionName, data, queueingStrategy, transfers) {
  197. var _this2 = this;
  198. var streamId = this.streamId++;
  199. var sourceName = this.sourceName;
  200. var targetName = this.targetName;
  201. return new _util.ReadableStream({
  202. start: function start(controller) {
  203. var startCapability = (0, _util.createPromiseCapability)();
  204. _this2.streamControllers[streamId] = {
  205. controller: controller,
  206. startCall: startCapability,
  207. isClosed: false
  208. };
  209. _this2.postMessage({
  210. sourceName: sourceName,
  211. targetName: targetName,
  212. action: actionName,
  213. streamId: streamId,
  214. data: data,
  215. desiredSize: controller.desiredSize
  216. });
  217. return startCapability.promise;
  218. },
  219. pull: function pull(controller) {
  220. var pullCapability = (0, _util.createPromiseCapability)();
  221. _this2.streamControllers[streamId].pullCall = pullCapability;
  222. _this2.postMessage({
  223. sourceName: sourceName,
  224. targetName: targetName,
  225. stream: 'pull',
  226. streamId: streamId,
  227. desiredSize: controller.desiredSize
  228. });
  229. return pullCapability.promise;
  230. },
  231. cancel: function cancel(reason) {
  232. var cancelCapability = (0, _util.createPromiseCapability)();
  233. _this2.streamControllers[streamId].cancelCall = cancelCapability;
  234. _this2.streamControllers[streamId].isClosed = true;
  235. _this2.postMessage({
  236. sourceName: sourceName,
  237. targetName: targetName,
  238. stream: 'cancel',
  239. reason: reason,
  240. streamId: streamId
  241. });
  242. return cancelCapability.promise;
  243. }
  244. }, queueingStrategy);
  245. },
  246. _createStreamSink: function _createStreamSink(data) {
  247. var _this3 = this;
  248. var self = this;
  249. var action = this.actionHandler[data.action];
  250. var streamId = data.streamId;
  251. var desiredSize = data.desiredSize;
  252. var sourceName = this.sourceName;
  253. var targetName = data.sourceName;
  254. var capability = (0, _util.createPromiseCapability)();
  255. var sendStreamRequest = function sendStreamRequest(_ref) {
  256. var stream = _ref.stream,
  257. chunk = _ref.chunk,
  258. transfers = _ref.transfers,
  259. success = _ref.success,
  260. reason = _ref.reason;
  261. _this3.postMessage({
  262. sourceName: sourceName,
  263. targetName: targetName,
  264. stream: stream,
  265. streamId: streamId,
  266. chunk: chunk,
  267. success: success,
  268. reason: reason
  269. }, transfers);
  270. };
  271. var streamSink = {
  272. enqueue: function enqueue(chunk) {
  273. var size = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : 1;
  274. var transfers = arguments.length > 2 ? arguments[2] : undefined;
  275. if (this.isCancelled) {
  276. return;
  277. }
  278. var lastDesiredSize = this.desiredSize;
  279. this.desiredSize -= size;
  280. if (lastDesiredSize > 0 && this.desiredSize <= 0) {
  281. this.sinkCapability = (0, _util.createPromiseCapability)();
  282. this.ready = this.sinkCapability.promise;
  283. }
  284. sendStreamRequest({
  285. stream: 'enqueue',
  286. chunk: chunk,
  287. transfers: transfers
  288. });
  289. },
  290. close: function close() {
  291. if (this.isCancelled) {
  292. return;
  293. }
  294. this.isCancelled = true;
  295. sendStreamRequest({
  296. stream: 'close'
  297. });
  298. delete self.streamSinks[streamId];
  299. },
  300. error: function error(reason) {
  301. if (this.isCancelled) {
  302. return;
  303. }
  304. this.isCancelled = true;
  305. sendStreamRequest({
  306. stream: 'error',
  307. reason: reason
  308. });
  309. },
  310. sinkCapability: capability,
  311. onPull: null,
  312. onCancel: null,
  313. isCancelled: false,
  314. desiredSize: desiredSize,
  315. ready: null
  316. };
  317. streamSink.sinkCapability.resolve();
  318. streamSink.ready = streamSink.sinkCapability.promise;
  319. this.streamSinks[streamId] = streamSink;
  320. resolveCall(action[0], [data.data, streamSink], action[1]).then(function () {
  321. sendStreamRequest({
  322. stream: 'start_complete',
  323. success: true
  324. });
  325. }, function (reason) {
  326. sendStreamRequest({
  327. stream: 'start_complete',
  328. success: false,
  329. reason: reason
  330. });
  331. });
  332. },
  333. _processStreamMessage: function _processStreamMessage(data) {
  334. var _this4 = this;
  335. var sourceName = this.sourceName;
  336. var targetName = data.sourceName;
  337. var streamId = data.streamId;
  338. var sendStreamResponse = function sendStreamResponse(_ref2) {
  339. var stream = _ref2.stream,
  340. success = _ref2.success,
  341. reason = _ref2.reason;
  342. _this4.comObj.postMessage({
  343. sourceName: sourceName,
  344. targetName: targetName,
  345. stream: stream,
  346. success: success,
  347. streamId: streamId,
  348. reason: reason
  349. });
  350. };
  351. var deleteStreamController = function deleteStreamController() {
  352. Promise.all([_this4.streamControllers[data.streamId].startCall, _this4.streamControllers[data.streamId].pullCall, _this4.streamControllers[data.streamId].cancelCall].map(function (capability) {
  353. return capability && finalize(capability.promise);
  354. })).then(function () {
  355. delete _this4.streamControllers[data.streamId];
  356. });
  357. };
  358. switch (data.stream) {
  359. case 'start_complete':
  360. resolveOrReject(this.streamControllers[data.streamId].startCall, data.success, wrapReason(data.reason));
  361. break;
  362. case 'pull_complete':
  363. resolveOrReject(this.streamControllers[data.streamId].pullCall, data.success, wrapReason(data.reason));
  364. break;
  365. case 'pull':
  366. if (!this.streamSinks[data.streamId]) {
  367. sendStreamResponse({
  368. stream: 'pull_complete',
  369. success: true
  370. });
  371. break;
  372. }
  373. if (this.streamSinks[data.streamId].desiredSize <= 0 && data.desiredSize > 0) {
  374. this.streamSinks[data.streamId].sinkCapability.resolve();
  375. }
  376. this.streamSinks[data.streamId].desiredSize = data.desiredSize;
  377. resolveCall(this.streamSinks[data.streamId].onPull).then(function () {
  378. sendStreamResponse({
  379. stream: 'pull_complete',
  380. success: true
  381. });
  382. }, function (reason) {
  383. sendStreamResponse({
  384. stream: 'pull_complete',
  385. success: false,
  386. reason: reason
  387. });
  388. });
  389. break;
  390. case 'enqueue':
  391. (0, _util.assert)(this.streamControllers[data.streamId], 'enqueue should have stream controller');
  392. if (!this.streamControllers[data.streamId].isClosed) {
  393. this.streamControllers[data.streamId].controller.enqueue(data.chunk);
  394. }
  395. break;
  396. case 'close':
  397. (0, _util.assert)(this.streamControllers[data.streamId], 'close should have stream controller');
  398. if (this.streamControllers[data.streamId].isClosed) {
  399. break;
  400. }
  401. this.streamControllers[data.streamId].isClosed = true;
  402. this.streamControllers[data.streamId].controller.close();
  403. deleteStreamController();
  404. break;
  405. case 'error':
  406. (0, _util.assert)(this.streamControllers[data.streamId], 'error should have stream controller');
  407. this.streamControllers[data.streamId].controller.error(wrapReason(data.reason));
  408. deleteStreamController();
  409. break;
  410. case 'cancel_complete':
  411. resolveOrReject(this.streamControllers[data.streamId].cancelCall, data.success, wrapReason(data.reason));
  412. deleteStreamController();
  413. break;
  414. case 'cancel':
  415. if (!this.streamSinks[data.streamId]) {
  416. break;
  417. }
  418. resolveCall(this.streamSinks[data.streamId].onCancel, [wrapReason(data.reason)]).then(function () {
  419. sendStreamResponse({
  420. stream: 'cancel_complete',
  421. success: true
  422. });
  423. }, function (reason) {
  424. sendStreamResponse({
  425. stream: 'cancel_complete',
  426. success: false,
  427. reason: reason
  428. });
  429. });
  430. this.streamSinks[data.streamId].sinkCapability.reject(wrapReason(data.reason));
  431. this.streamSinks[data.streamId].isCancelled = true;
  432. delete this.streamSinks[data.streamId];
  433. break;
  434. default:
  435. throw new Error('Unexpected stream case');
  436. }
  437. },
  438. postMessage: function postMessage(message, transfers) {
  439. if (transfers && this.postMessageTransfers) {
  440. this.comObj.postMessage(message, transfers);
  441. } else {
  442. this.comObj.postMessage(message);
  443. }
  444. },
  445. destroy: function destroy() {
  446. this.comObj.removeEventListener('message', this._onComObjOnMessage);
  447. }
  448. };