named_message_port_connector.js 2.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103
  1. // Copyright 2019 The Chromium Authors. All rights reserved.
  2. // Use of this source code is governed by a BSD-style license that can be
  3. // found in the LICENSE file.
  4. 'use strict';
  5. if (!window['cast']) {
  6. /**
  7. * @const
  8. */
  9. // eslint-disable-next-line no-var
  10. var cast = new Object();
  11. }
  12. if (!cast['__platform__']) {
  13. /**
  14. * @const
  15. */
  16. cast.__platform__ = {};
  17. }
  18. // Creates named HTML5 MessagePorts that are connected to native code.
  19. cast.__platform__.PortConnector = new class {
  20. constructor() {
  21. /** @private {MessagePort} */
  22. this.controlPort_ = null;
  23. // A map of ports waiting to be published to the controlPort_, keyed by
  24. // string IDs.
  25. /** @private {Object<string, MessagePort>} */
  26. this.pendingPorts_ = {};
  27. /** @private */
  28. this.listener = this.onMessageEvent.bind(this);
  29. window.addEventListener(
  30. 'message',
  31. this.listener,
  32. true, // Let the listener handle events before they hit the DOM tree.
  33. );
  34. }
  35. /**
  36. * Returns a MessagePort whose channel will be passed to the native code.
  37. * The channel can be used immediately after construction. Outgoing messages
  38. * will be automatically buffered until the connection is established.
  39. * @param {string} id The ID of the port being registered.
  40. * @return {MessagePort}
  41. */
  42. bind(id) {
  43. const channel = new MessageChannel();
  44. if (this.controlPort_) {
  45. this.sendPort(id, channel.port2);
  46. } else {
  47. this.pendingPorts_[id] = channel.port2;
  48. }
  49. return channel.port1;
  50. }
  51. /**
  52. * Sends a MessagePort to the remote NamedMessagePortConnector.
  53. * @param {string} portId The name of the port to send over the control port.
  54. * @param {MessagePort} port The port being sent.
  55. */
  56. sendPort(portId, port) {
  57. this.controlPort_.postMessage(portId, [port]);
  58. }
  59. /**
  60. * Handles frame message events to receive a connection "control port" from
  61. * native code.
  62. * @param {Event} messageEvent
  63. */
  64. onMessageEvent(messageEvent) {
  65. // Only process window.onmessage events which are intended for this class.
  66. if (messageEvent.data != 'cast.master.connect') {
  67. return;
  68. }
  69. if (messageEvent.ports.length != 1) {
  70. console.error(
  71. 'Expected only one MessagePort, got ' + messageEvent.ports.length +
  72. ' instead.');
  73. for (const port of messageEvent.ports) {
  74. port.close();
  75. }
  76. return;
  77. }
  78. this.controlPort_ = messageEvent.ports[0];
  79. for (const portId in this.pendingPorts_) {
  80. this.sendPort(portId, this.pendingPorts_[portId]);
  81. }
  82. this.pendingPorts_ = null;
  83. messageEvent.stopPropagation();
  84. // No need to receive more onmessage events.
  85. window.removeEventListener('message', this.listener);
  86. }
  87. }
  88. ();