summaryrefslogtreecommitdiffstats
path: root/web_src/js/features/eventsource.sharedworker.js
diff options
context:
space:
mode:
authorDaniel Baumann <daniel@debian.org>2024-10-18 20:33:49 +0200
committerDaniel Baumann <daniel@debian.org>2024-10-18 20:33:49 +0200
commitdd136858f1ea40ad3c94191d647487fa4f31926c (patch)
tree58fec94a7b2a12510c9664b21793f1ed560c6518 /web_src/js/features/eventsource.sharedworker.js
parentInitial commit. (diff)
downloadforgejo-dd136858f1ea40ad3c94191d647487fa4f31926c.tar.xz
forgejo-dd136858f1ea40ad3c94191d647487fa4f31926c.zip
Adding upstream version 9.0.0.upstream/9.0.0upstreamdebian
Signed-off-by: Daniel Baumann <daniel@debian.org>
Diffstat (limited to 'web_src/js/features/eventsource.sharedworker.js')
-rw-r--r--web_src/js/features/eventsource.sharedworker.js141
1 files changed, 141 insertions, 0 deletions
diff --git a/web_src/js/features/eventsource.sharedworker.js b/web_src/js/features/eventsource.sharedworker.js
new file mode 100644
index 0000000..62581cf
--- /dev/null
+++ b/web_src/js/features/eventsource.sharedworker.js
@@ -0,0 +1,141 @@
+const sourcesByUrl = {};
+const sourcesByPort = {};
+
+class Source {
+ constructor(url) {
+ this.url = url;
+ this.eventSource = new EventSource(url);
+ this.listening = {};
+ this.clients = [];
+ this.listen('open');
+ this.listen('close');
+ this.listen('logout');
+ this.listen('notification-count');
+ this.listen('stopwatches');
+ this.listen('error');
+ }
+
+ register(port) {
+ if (this.clients.includes(port)) return;
+
+ this.clients.push(port);
+
+ port.postMessage({
+ type: 'status',
+ message: `registered to ${this.url}`,
+ });
+ }
+
+ deregister(port) {
+ const portIdx = this.clients.indexOf(port);
+ if (portIdx < 0) {
+ return this.clients.length;
+ }
+ this.clients.splice(portIdx, 1);
+ return this.clients.length;
+ }
+
+ close() {
+ if (!this.eventSource) return;
+
+ this.eventSource.close();
+ this.eventSource = null;
+ }
+
+ listen(eventType) {
+ if (this.listening[eventType]) return;
+ this.listening[eventType] = true;
+ this.eventSource.addEventListener(eventType, (event) => {
+ this.notifyClients({
+ type: eventType,
+ data: event.data,
+ });
+ });
+ }
+
+ notifyClients(event) {
+ for (const client of this.clients) {
+ client.postMessage(event);
+ }
+ }
+
+ status(port) {
+ port.postMessage({
+ type: 'status',
+ message: `url: ${this.url} readyState: ${this.eventSource.readyState}`,
+ });
+ }
+}
+
+self.addEventListener('connect', (e) => {
+ for (const port of e.ports) {
+ port.addEventListener('message', (event) => {
+ if (!self.EventSource) {
+ // some browsers (like PaleMoon, Firefox<53) don't support EventSource in SharedWorkerGlobalScope.
+ // this event handler needs EventSource when doing "new Source(url)", so just post a message back to the caller,
+ // in case the caller would like to use a fallback method to do its work.
+ port.postMessage({type: 'no-event-source'});
+ return;
+ }
+ if (event.data.type === 'start') {
+ const url = event.data.url;
+ if (sourcesByUrl[url]) {
+ // we have a Source registered to this url
+ const source = sourcesByUrl[url];
+ source.register(port);
+ sourcesByPort[port] = source;
+ return;
+ }
+ let source = sourcesByPort[port];
+ if (source) {
+ if (source.eventSource && source.url === url) return;
+
+ // How this has happened I don't understand...
+ // deregister from that source
+ const count = source.deregister(port);
+ // Clean-up
+ if (count === 0) {
+ source.close();
+ sourcesByUrl[source.url] = null;
+ }
+ }
+ // Create a new Source
+ source = new Source(url);
+ source.register(port);
+ sourcesByUrl[url] = source;
+ sourcesByPort[port] = source;
+ } else if (event.data.type === 'listen') {
+ const source = sourcesByPort[port];
+ source.listen(event.data.eventType);
+ } else if (event.data.type === 'close') {
+ const source = sourcesByPort[port];
+
+ if (!source) return;
+
+ const count = source.deregister(port);
+ if (count === 0) {
+ source.close();
+ sourcesByUrl[source.url] = null;
+ sourcesByPort[port] = null;
+ }
+ } else if (event.data.type === 'status') {
+ const source = sourcesByPort[port];
+ if (!source) {
+ port.postMessage({
+ type: 'status',
+ message: 'not connected',
+ });
+ return;
+ }
+ source.status(port);
+ } else {
+ // just send it back
+ port.postMessage({
+ type: 'error',
+ message: `received but don't know how to handle: ${event.data}`,
+ });
+ }
+ });
+ port.start();
+ }
+});