Files
Atay-Makhzan/web_src/js/eventsource.sharedworker.ts
T

146 lines
4.1 KiB
TypeScript
Raw Normal View History

2020-07-03 10:55:36 +01:00
class Source {
url: string;
2025-12-03 03:13:16 +01:00
eventSource: EventSource | null;
listening: Record<string, boolean>;
clients: Array<MessagePort>;
constructor(url: string) {
2020-07-03 10:55:36 +01:00
this.url = url;
this.eventSource = new EventSource(url);
this.listening = {};
this.clients = [];
this.listen('open');
this.listen('close');
2020-07-03 10:55:36 +01:00
this.listen('logout');
this.listen('notification-count');
this.listen('stopwatches');
2020-07-03 10:55:36 +01:00
this.listen('error');
}
register(port: MessagePort) {
2020-07-04 23:04:00 +01:00
if (this.clients.includes(port)) return;
2020-07-03 10:55:36 +01:00
this.clients.push(port);
port.postMessage({
type: 'status',
message: `registered to ${this.url}`,
});
}
deregister(port: MessagePort) {
2020-07-03 10:55:36 +01:00
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: string) {
2020-07-03 10:55:36 +01:00
if (this.listening[eventType]) return;
this.listening[eventType] = true;
2025-12-03 03:13:16 +01:00
this.eventSource?.addEventListener(eventType, (event) => {
2021-03-22 05:04:19 +01:00
this.notifyClients({
2020-07-03 10:55:36 +01:00
type: eventType,
data: event.data,
2020-07-03 10:55:36 +01:00
});
});
}
notifyClients(event: {type: string, data: any}) {
2020-07-03 10:55:36 +01:00
for (const client of this.clients) {
client.postMessage(event);
}
}
status(port: MessagePort) {
2020-07-03 10:55:36 +01:00
port.postMessage({
type: 'status',
2025-12-03 03:13:16 +01:00
message: `url: ${this.url} readyState: ${this.eventSource?.readyState}`,
2020-07-03 10:55:36 +01:00
});
}
}
2025-11-28 00:58:10 +01:00
const sourcesByUrl = new Map<string, Source | null>();
const sourcesByPort = new Map<MessagePort, Source | null>();
2026-02-02 01:00:34 +08:00
(self as unknown as SharedWorkerGlobalScope).addEventListener('connect', (e: MessageEvent) => {
2020-07-03 10:55:36 +01:00
for (const port of e.ports) {
2026-02-02 01:00:34 +08:00
port.addEventListener('message', (event: MessageEvent) => {
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;
}
2020-07-03 10:55:36 +01:00
if (event.data.type === 'start') {
const url = event.data.url;
2025-12-03 03:13:16 +01:00
let source = sourcesByUrl.get(url);
if (source) {
2020-07-03 10:55:36 +01:00
// we have a Source registered to this url
source.register(port);
sourcesByPort.set(port, source);
2020-07-03 10:55:36 +01:00
return;
}
2025-12-03 03:13:16 +01:00
source = sourcesByPort.get(port);
2020-07-03 10:55:36 +01:00
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);
2020-07-04 15:01:25 +01:00
// Clean-up
2020-07-03 10:55:36 +01:00
if (count === 0) {
source.close();
sourcesByUrl.set(source.url, null);
2020-07-03 10:55:36 +01:00
}
}
// Create a new Source
source = new Source(url);
source.register(port);
sourcesByUrl.set(url, source);
sourcesByPort.set(port, source);
2020-07-03 10:55:36 +01:00
} else if (event.data.type === 'listen') {
2025-12-03 03:13:16 +01:00
const source = sourcesByPort.get(port)!;
2020-07-03 10:55:36 +01:00
source.listen(event.data.eventType);
} else if (event.data.type === 'close') {
const source = sourcesByPort.get(port);
2020-07-03 10:55:36 +01:00
if (!source) return;
const count = source.deregister(port);
if (count === 0) {
source.close();
sourcesByUrl.set(source.url, null);
sourcesByPort.set(port, null);
2020-07-03 10:55:36 +01:00
}
} else if (event.data.type === 'status') {
const source = sourcesByPort.get(port);
2020-07-03 10:55:36 +01:00
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();
}
2021-08-17 07:32:48 +02:00
});