Move EventSource to SharedWorker (#12095)
Move EventSource to use a SharedWorker. This prevents issues with HTTP/1.1 open browser connections from preventing gitea from opening multiple tabs. Also allow setting EVENT_SOURCE_UPDATE_TIME to disable EventSource updating Fix #11978 Signed-off-by: Andrew Thornton <art27@cantab.net> Co-authored-by: silverwind <me@silverwind.io> Co-authored-by: techknowlogick <techknowlogick@gitea.io>tokarchuk/v1.17
parent
cd994f6354
commit
ae56411e9f
@ -0,0 +1,140 @@ |
||||
self.name = 'eventsource.sharedworker.js'; |
||||
|
||||
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('logout'); |
||||
this.listen('notification-count'); |
||||
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; |
||||
const self = this; |
||||
this.eventSource.addEventListener(eventType, (event) => { |
||||
self.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.onconnect = (e) => { |
||||
for (const port of e.ports) { |
||||
port.addEventListener('message', (event) => { |
||||
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; |
||||
return; |
||||
} else if (event.data.type === 'listen') { |
||||
const source = sourcesByPort[port]; |
||||
source.listen(event.data.eventType); |
||||
return; |
||||
} 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; |
||||
} |
||||
return; |
||||
} else if (event.data.type === 'status') { |
||||
const source = sourcesByPort[port]; |
||||
if (!source) { |
||||
port.postMessage({ |
||||
type: 'status', |
||||
message: 'not connected', |
||||
}); |
||||
return; |
||||
} |
||||
source.status(port); |
||||
return; |
||||
} else { |
||||
// just send it back
|
||||
port.postMessage({ |
||||
type: 'error', |
||||
message: `received but don't know how to handle: ${event.data}`, |
||||
}); |
||||
return; |
||||
} |
||||
}); |
||||
port.start(); |
||||
} |
||||
}; |
Loading…
Reference in new issue