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.

eventsource.sharedworker.js 3.3KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135
  1. self.name = 'eventsource.sharedworker.js';
  2. const sourcesByUrl = {};
  3. const sourcesByPort = {};
  4. class Source {
  5. constructor(url) {
  6. this.url = url;
  7. this.eventSource = new EventSource(url);
  8. this.listening = {};
  9. this.clients = [];
  10. this.listen('open');
  11. this.listen('logout');
  12. this.listen('notification-count');
  13. this.listen('error');
  14. }
  15. register(port) {
  16. if (!this.clients.includes(port)) return;
  17. this.clients.push(port);
  18. port.postMessage({
  19. type: 'status',
  20. message: `registered to ${this.url}`,
  21. });
  22. }
  23. deregister(port) {
  24. const portIdx = this.clients.indexOf(port);
  25. if (portIdx < 0) {
  26. return this.clients.length;
  27. }
  28. this.clients.splice(portIdx, 1);
  29. return this.clients.length;
  30. }
  31. close() {
  32. if (!this.eventSource) return;
  33. this.eventSource.close();
  34. this.eventSource = null;
  35. }
  36. listen(eventType) {
  37. if (this.listening[eventType]) return;
  38. this.listening[eventType] = true;
  39. const self = this;
  40. this.eventSource.addEventListener(eventType, (event) => {
  41. self.notifyClients({
  42. type: eventType,
  43. data: event.data
  44. });
  45. });
  46. }
  47. notifyClients(event) {
  48. for (const client of this.clients) {
  49. client.postMessage(event);
  50. }
  51. }
  52. status(port) {
  53. port.postMessage({
  54. type: 'status',
  55. message: `url: ${this.url} readyState: ${this.eventSource.readyState}`,
  56. });
  57. }
  58. }
  59. self.onconnect = (e) => {
  60. for (const port of e.ports) {
  61. port.addEventListener('message', (event) => {
  62. if (event.data.type === 'start') {
  63. const url = event.data.url;
  64. if (sourcesByUrl[url]) {
  65. // we have a Source registered to this url
  66. const source = sourcesByUrl[url];
  67. source.register(port);
  68. sourcesByPort[port] = source;
  69. return;
  70. }
  71. let source = sourcesByPort[port];
  72. if (source) {
  73. if (source.eventSource && source.url === url) return;
  74. // How this has happened I don't understand...
  75. // deregister from that source
  76. const count = source.deregister(port);
  77. // Clean-up
  78. if (count === 0) {
  79. source.close();
  80. sourcesByUrl[source.url] = null;
  81. }
  82. }
  83. // Create a new Source
  84. source = new Source(url);
  85. source.register(port);
  86. sourcesByUrl[url] = source;
  87. sourcesByPort[port] = source;
  88. } else if (event.data.type === 'listen') {
  89. const source = sourcesByPort[port];
  90. source.listen(event.data.eventType);
  91. } else if (event.data.type === 'close') {
  92. const source = sourcesByPort[port];
  93. if (!source) return;
  94. const count = source.deregister(port);
  95. if (count === 0) {
  96. source.close();
  97. sourcesByUrl[source.url] = null;
  98. sourcesByPort[port] = null;
  99. }
  100. } else if (event.data.type === 'status') {
  101. const source = sourcesByPort[port];
  102. if (!source) {
  103. port.postMessage({
  104. type: 'status',
  105. message: 'not connected',
  106. });
  107. return;
  108. }
  109. source.status(port);
  110. } else {
  111. // just send it back
  112. port.postMessage({
  113. type: 'error',
  114. message: `received but don't know how to handle: ${event.data}`,
  115. });
  116. }
  117. });
  118. port.start();
  119. }
  120. };