From b875eb8b21c56239f36efed3ac5f2f50e5206cbb Mon Sep 17 00:00:00 2001 From: Andrew Thornton Date: Mon, 29 Jun 2020 22:26:09 +0100 Subject: [PATCH 01/18] Move EventSource to SharedWorker Move EventSource to use a SharedWorker. This prevents issues with HTTP/1.1 open browser connections from preventing gitea from opening multiple tabs. Also adds several options to control this. Fix #11978 Signed-off-by: Andrew Thornton --- custom/conf/app.example.ini | 3 + .../doc/advanced/config-cheat-sheet.en-us.md | 4 +- modules/setting/setting.go | 9 ++ modules/templates/helper.go | 7 +- templates/base/head.tmpl | 3 + .../js/features/eventsource.sharedworker.js | 151 ++++++++++++++++++ web_src/js/features/eventsource.worker.js | 29 ++++ web_src/js/features/notification.js | 149 +++++++++++++---- web_src/js/index.js | 2 +- webpack.config.js | 3 + 10 files changed, 327 insertions(+), 33 deletions(-) create mode 100644 web_src/js/features/eventsource.sharedworker.js create mode 100644 web_src/js/features/eventsource.worker.js diff --git a/custom/conf/app.example.ini b/custom/conf/app.example.ini index 648cf59fec83e..7492156dff565 100644 --- a/custom/conf/app.example.ini +++ b/custom/conf/app.example.ini @@ -220,6 +220,9 @@ TIMEOUT_STEP = 10s ; This setting determines how often the db is queried to get the latest notification counts. ; If the browser client supports EventSource, it will be used in preference to polling notification. EVENT_SOURCE_UPDATE_TIME = 10s +USE_SHARED_WORKER=true ; use a eventsource in shared worker +USE_WORKER=false ; use eventsource in worker +USE_PLAIN_EVENT_SOURCE=false ; allow direct use of event source outside of worker [markdown] ; Render soft line breaks as hard line breaks, which means a single newline character between diff --git a/docs/content/doc/advanced/config-cheat-sheet.en-us.md b/docs/content/doc/advanced/config-cheat-sheet.en-us.md index 2cbe4c59ea906..1a43fef46650d 100644 --- a/docs/content/doc/advanced/config-cheat-sheet.en-us.md +++ b/docs/content/doc/advanced/config-cheat-sheet.en-us.md @@ -151,7 +151,9 @@ Values containing `#` or `;` must be quoted using `` ` `` or `"""`. - `MAX_TIMEOUT`: **60s**. - `TIMEOUT_STEP`: **10s**. - `EVENT_SOURCE_UPDATE_TIME`: **10s**: This setting determines how often the database is queried to update notification counts. If the browser client supports `EventSource`, it will be used in preference to polling notification endpoint. - +- `USE_SHARED_WORKER`: **true**: If the client supports `SharedWorker` and the `EVENT_SOURCE_UPDATE_TIME` is greater than `0`. Use a `SharedWorker` `EventSource` in preference to polling. +- `USE_WORKER`: **false**: If the client supports `Worker` and the `EVENT_SOURCE_UPDATE_TIME` is greater than `0`. Use a `Worker` `EventSource` in preference to polling. (Disabled by default due to limited browser connections under HTTP/1.1.) +- `USE_PLAIN_EVENT_SOURCE`: **false**: If the client supports `EventSource` and the `EVENT_SOURCE_UPDATE_TIME` is greater than `0`. Use a `EventSource` in preference to polling. (Disabled by default due to limited browser connections under HTTP/1.1.) ## Markdown (`markdown`) diff --git a/modules/setting/setting.go b/modules/setting/setting.go index 8efc832f9dc30..777e3f3f2dc7d 100644 --- a/modules/setting/setting.go +++ b/modules/setting/setting.go @@ -185,6 +185,9 @@ var ( TimeoutStep time.Duration MaxTimeout time.Duration EventSourceUpdateTime time.Duration + UseSharedWorker bool + UseWorker bool + UsePlainEventSource bool } `ini:"ui.notification"` Admin struct { @@ -220,11 +223,17 @@ var ( TimeoutStep time.Duration MaxTimeout time.Duration EventSourceUpdateTime time.Duration + UseSharedWorker bool + UseWorker bool + UsePlainEventSource bool }{ MinTimeout: 10 * time.Second, TimeoutStep: 10 * time.Second, MaxTimeout: 60 * time.Second, EventSourceUpdateTime: 10 * time.Second, + UseSharedWorker: true, + UseWorker: false, + UsePlainEventSource: false, }, Admin: struct { UserPagingNum int diff --git a/modules/templates/helper.go b/modules/templates/helper.go index ff974aba9f651..28dc0b8c66d5a 100644 --- a/modules/templates/helper.go +++ b/modules/templates/helper.go @@ -282,12 +282,15 @@ func NewFuncMap() []template.FuncMap { return "" } }, - "NotificationSettings": func() map[string]int { - return map[string]int{ + "NotificationSettings": func() map[string]interface{} { + return map[string]interface{}{ "MinTimeout": int(setting.UI.Notification.MinTimeout / time.Millisecond), "TimeoutStep": int(setting.UI.Notification.TimeoutStep / time.Millisecond), "MaxTimeout": int(setting.UI.Notification.MaxTimeout / time.Millisecond), "EventSourceUpdateTime": int(setting.UI.Notification.EventSourceUpdateTime / time.Millisecond), + "UseSharedWorker": setting.UI.Notification.UseSharedWorker, + "UseWorker": setting.UI.Notification.UseWorker, + "UsePlainEventSource": setting.UI.Notification.UsePlainEventSource, } }, "contain": func(s []int64, id int64) bool { diff --git a/templates/base/head.tmpl b/templates/base/head.tmpl index 7999eebb11216..72325e18a2c2e 100644 --- a/templates/base/head.tmpl +++ b/templates/base/head.tmpl @@ -77,6 +77,9 @@ TimeoutStep: {{NotificationSettings.TimeoutStep}}, MaxTimeout: {{NotificationSettings.MaxTimeout}}, EventSourceUpdateTime: {{NotificationSettings.EventSourceUpdateTime}}, + UseSharedWorker: {{NotificationSettings.UseSharedWorker}}, + UseWorker: {{NotificationSettings.UseWorker}}, + UsePlainEventSource: {{NotificationSettings.UsePlainEventSource}}, }, {{if .RequireTribute}} tributeValues: [ diff --git a/web_src/js/features/eventsource.sharedworker.js b/web_src/js/features/eventsource.sharedworker.js new file mode 100644 index 0000000000000..44a494b0a5599 --- /dev/null +++ b/web_src/js/features/eventsource.sharedworker.js @@ -0,0 +1,151 @@ +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) { + const portIdx = this.clients.indexOf(port); + if (portIdx > -1) { + 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 + }, false); + }); + } + + notifyClients(event) { + const len = this.clients.length; + for (let i = 0; i < len; i++) { + const port = this.clients[i]; + port.postMessage(event); + } + } + + status(port) { + port.postMessage({ + type: 'status', + message: `url: ${this.url} readyState: ${this.eventSource.readyState}`, + }); + } +} + +self.onconnect = (e) => { + e.ports.forEach((port) => { + port.addEventListener('message', (event) => { + switch (event.data.type) { + case '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) { + // We have a valid source for this port... + 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; + } + case 'listen': { + const source = sourcesByPort[port]; + source.listen(event.data.eventType); + } + return; + case '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; + } + case 'status': { + const source = sourcesByPort[port]; + if (!source) { + port.postMessage({ + type: 'status', + message: 'not connected', + }); + return; + } + source.status(port); + return; + } + default: + // just send it back + port.postMessage({ + type: 'error', + message: `received but don't know how to handle: ${event.data}`, + }); + return; + } + }); + port.start(); + }); +}; diff --git a/web_src/js/features/eventsource.worker.js b/web_src/js/features/eventsource.worker.js new file mode 100644 index 0000000000000..a03f989137fbe --- /dev/null +++ b/web_src/js/features/eventsource.worker.js @@ -0,0 +1,29 @@ +let eventSource; + +const listening = {}; + +self.addEventListener('message', (event) => { + if (event.data.type === 'start') { + eventSource = new EventSource(event.data.url); + listen('open'); + listen('error'); + listen('notification-count'); + this.listen('logout'); + } else if (event.data.type === 'listen') { + listen(event.data.eventType); + } else if (event.data.type === 'close' && eventSource) { + eventSource.close(); + eventSource = null; + } +}, false); + +function listen (eventType) { + if (listening[eventType]) return; + listening[eventType] = true; + eventSource.addEventListener(eventType, (event) => { + self.postMessage({ + type: eventType, + data: event.data + }, false); + }); +} diff --git a/web_src/js/features/notification.js b/web_src/js/features/notification.js index 0ea7f93c8d6e0..5c3ddf551cc41 100644 --- a/web_src/js/features/notification.js +++ b/web_src/js/features/notification.js @@ -18,7 +18,25 @@ export function initNotificationsTable() { }); } -export function initNotificationCount() { +async function receiveUpdateCount(event) { + try { + const data = JSON.parse(event.data); + + const notificationCount = $('.notification_count'); + if (data.Count === 0) { + notificationCount.addClass('hidden'); + } else { + notificationCount.removeClass('hidden'); + } + + notificationCount.text(`${data.Count}`); + await updateNotificationTable(); + } catch (error) { + console.error(error, event); + } +} + +export async function initNotificationCount() { const notificationCount = $('.notification_count'); if (!notificationCount.length) { @@ -27,35 +45,108 @@ export function initNotificationCount() { if (NotificationSettings.EventSourceUpdateTime > 0 && !!window.EventSource) { // Try to connect to the event source first - const source = new EventSource(`${AppSubUrl}/user/events`); - source.addEventListener('notification-count', async (e) => { - try { - const data = JSON.parse(e.data); - - const notificationCount = $('.notification_count'); - if (data.Count === 0) { - notificationCount.addClass('hidden'); - } else { - notificationCount.removeClass('hidden'); - } - notificationCount.text(`${data.Count}`); - await updateNotificationTable(); - } catch (error) { - console.error(error); - } - }); - source.addEventListener('logout', async (e) => { - if (e.data !== 'here') { - return; - } - source.close(); - window.location.href = AppSubUrl; - }); - window.addEventListener('beforeunload', () => { - source.close(); - }); - return; + if (window.SharedWorker && NotificationSettings.UseSharedWorker) { + // const {default: Worker} = await import(/* webpackChunkName: "eventsource" */'./eventsource.sharedworker.js'); + // const worker = Worker('notification'); + const worker = new SharedWorker('js/eventsource.sharedworker.js', 'notification-worker'); + // worker.port.addEventListener('message', (event) => { + // console.log(event.data); + // }, false); + // worker.port.start(); + worker.addEventListener('error', (event) => { + console.error(event); + }, false); + worker.port.onmessageeerror = (event) => { + console.error(event); + }; + worker.port.postMessage({ + type: 'start', + url: `${window.location.protocol}//${window.location.host}${AppSubUrl}/user/events`, + }); + worker.port.addEventListener('message', (e) => { + if (!e.data || !e.data.type) { + console.error(e); + return; + } + switch (event.data.type) { + case 'notification-count': + receiveUpdateCount(e.data); + return; + case 'error': + console.error(e.data); + return; + case 'logout': { + if (e.data !== 'here') { + return; + } + worker.port.postMessage({ + type: 'close', + }); + worker.port.close(); + window.location.href = AppSubUrl; + return; + } + default: + return; + } + }, false); + worker.port.addEventListener('error', (e) => { + console.error(e); + }, false); + worker.port.start(); + window.addEventListener('beforeunload', () => { + worker.port.postMessage({ + type: 'close', + }); + worker.port.close(); + }, false); + + return; + } + + if (window.Worker && NotificationSettings.UseWorker) { + const {default: Worker} = await import(/* webpackChunkName: "eventsource" */'./eventsource.worker.js'); + const worker = new Worker(); + worker.postMessage({ + type: 'start', + url: `${window.location.protocol}//${window.location.host}${AppSubUrl}/user/events`, + }); + worker.addEventListener('nofication-count', receiveUpdateCount, false); + worker.addEventListener('logout', (e) => { + if (e.data !== 'here') { + return; + } + worker.postMessage({ + type: 'close', + }); + worker.terminate(); + window.location.href = AppSubUrl; + }, false); + window.addEventListener('beforeunload', () => { + worker.postMessage({ + type: 'close', + }); + worker.terminate(); + }, false); + return; + } + + if (window.EventSource && NotificationSettings.UsePlainEventSource) { + const eventSource = new EventSource(`${AppSubUrl}/user/events`); + eventSource.addEventListener('notification-count', receiveUpdateCount, false); + eventSource.addEventListener('logout', (e) => { + if (e.data !== 'here') { + return; + } + eventSource.close(); + window.location.href = AppSubUrl; + }, false); + window.addEventListener('beforeunload', () => { + eventSource.close(); + }, false); + return; + } } if (NotificationSettings.MinTimeout <= 0) { diff --git a/web_src/js/index.js b/web_src/js/index.js index 544c2457c4e97..31b65f6e8ddc6 100644 --- a/web_src/js/index.js +++ b/web_src/js/index.js @@ -2445,7 +2445,6 @@ $(document).ready(async () => { initContextPopups(); initTableSort(); initNotificationsTable(); - initNotificationCount(); // Repo clone url. if ($('#repo-clone-url').length > 0) { @@ -2491,6 +2490,7 @@ $(document).ready(async () => { initClipboard(), initUserHeatmap(), initServiceWorker(), + initNotificationCount(), ]); }); diff --git a/webpack.config.js b/webpack.config.js index 7b917cbdc108d..286302e2db918 100644 --- a/webpack.config.js +++ b/webpack.config.js @@ -50,6 +50,9 @@ module.exports = { serviceworker: [ resolve(__dirname, 'web_src/js/serviceworker.js'), ], + 'eventsource.sharedworker': [ + resolve(__dirname, 'web_src/js/features/eventsource.sharedworker.js'), + ], icons: [ ...glob('node_modules/@primer/octicons/build/svg/**/*.svg'), ...glob('assets/svg/*.svg'), From 4c27b3feab10d0514766fbeeddfbace35ef8d382 Mon Sep 17 00:00:00 2001 From: Andrew Thornton Date: Tue, 30 Jun 2020 17:32:59 +0100 Subject: [PATCH 02/18] Also allow setting EVENT_SOURCE_UPDATE_TIME to disable EventSource updating Signed-off-by: Andrew Thornton --- docs/content/doc/advanced/config-cheat-sheet.en-us.md | 2 +- modules/eventsource/manager_run.go | 3 +++ 2 files changed, 4 insertions(+), 1 deletion(-) diff --git a/docs/content/doc/advanced/config-cheat-sheet.en-us.md b/docs/content/doc/advanced/config-cheat-sheet.en-us.md index 1a43fef46650d..9f32260b643fd 100644 --- a/docs/content/doc/advanced/config-cheat-sheet.en-us.md +++ b/docs/content/doc/advanced/config-cheat-sheet.en-us.md @@ -150,7 +150,7 @@ Values containing `#` or `;` must be quoted using `` ` `` or `"""`. - `MIN_TIMEOUT`: **10s**: These options control how often notification endpoint is polled to update the notification count. On page load the notification count will be checked after `MIN_TIMEOUT`. The timeout will increase to `MAX_TIMEOUT` by `TIMEOUT_STEP` if the notification count is unchanged. Set MIN_TIMEOUT to 0 to turn off. - `MAX_TIMEOUT`: **60s**. - `TIMEOUT_STEP`: **10s**. -- `EVENT_SOURCE_UPDATE_TIME`: **10s**: This setting determines how often the database is queried to update notification counts. If the browser client supports `EventSource`, it will be used in preference to polling notification endpoint. +- `EVENT_SOURCE_UPDATE_TIME`: **10s**: This setting determines how often the database is queried to update notification counts. If the browser client supports `EventSource`, it will be used in preference to polling notification endpoint. Set to **-1** to disable the `EventSource`. - `USE_SHARED_WORKER`: **true**: If the client supports `SharedWorker` and the `EVENT_SOURCE_UPDATE_TIME` is greater than `0`. Use a `SharedWorker` `EventSource` in preference to polling. - `USE_WORKER`: **false**: If the client supports `Worker` and the `EVENT_SOURCE_UPDATE_TIME` is greater than `0`. Use a `Worker` `EventSource` in preference to polling. (Disabled by default due to limited browser connections under HTTP/1.1.) - `USE_PLAIN_EVENT_SOURCE`: **false**: If the client supports `EventSource` and the `EVENT_SOURCE_UPDATE_TIME` is greater than `0`. Use a `EventSource` in preference to polling. (Disabled by default due to limited browser connections under HTTP/1.1.) diff --git a/modules/eventsource/manager_run.go b/modules/eventsource/manager_run.go index 75d3ee5b013c4..ccfe2e07097a0 100644 --- a/modules/eventsource/manager_run.go +++ b/modules/eventsource/manager_run.go @@ -17,6 +17,9 @@ import ( // Init starts this eventsource func (m *Manager) Init() { + if setting.UI.Notification.EventSourceUpdateTime <= 0 { + return + } go graceful.GetManager().RunWithShutdownContext(m.Run) } From 261e4011b97ae526d0c620943634f58513badfe2 Mon Sep 17 00:00:00 2001 From: zeripath Date: Tue, 30 Jun 2020 18:28:32 +0100 Subject: [PATCH 03/18] as per @silverwind Co-authored-by: silverwind --- web_src/js/features/notification.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/web_src/js/features/notification.js b/web_src/js/features/notification.js index 5c3ddf551cc41..0f3992aa7876b 100644 --- a/web_src/js/features/notification.js +++ b/web_src/js/features/notification.js @@ -49,7 +49,7 @@ export async function initNotificationCount() { if (window.SharedWorker && NotificationSettings.UseSharedWorker) { // const {default: Worker} = await import(/* webpackChunkName: "eventsource" */'./eventsource.sharedworker.js'); // const worker = Worker('notification'); - const worker = new SharedWorker('js/eventsource.sharedworker.js', 'notification-worker'); + const worker = new SharedWorker(`${__webpack_public_path__}js/eventsource.sharedworker.js`, 'notification-worker'); // worker.port.addEventListener('message', (event) => { // console.log(event.data); // }, false); From eca09dfd54981e066aa6943a9d34998138d44634 Mon Sep 17 00:00:00 2001 From: zeripath Date: Tue, 30 Jun 2020 18:28:48 +0100 Subject: [PATCH 04/18] as per @silverwind Co-authored-by: silverwind --- web_src/js/features/notification.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/web_src/js/features/notification.js b/web_src/js/features/notification.js index 0f3992aa7876b..355e4bd5a0165 100644 --- a/web_src/js/features/notification.js +++ b/web_src/js/features/notification.js @@ -112,7 +112,7 @@ export async function initNotificationCount() { type: 'start', url: `${window.location.protocol}//${window.location.host}${AppSubUrl}/user/events`, }); - worker.addEventListener('nofication-count', receiveUpdateCount, false); + worker.addEventListener('notification-count', receiveUpdateCount, false); worker.addEventListener('logout', (e) => { if (e.data !== 'here') { return; From 40338887651458c8e375e8a445d55ea38a630894 Mon Sep 17 00:00:00 2001 From: Andrew Thornton Date: Tue, 30 Jun 2020 19:38:48 +0100 Subject: [PATCH 05/18] Remove the plain Worker and EventSource fallbacks Signed-off-by: Andrew Thornton --- custom/conf/app.example.ini | 5 +- .../doc/advanced/config-cheat-sheet.en-us.md | 5 +- modules/setting/setting.go | 9 ---- modules/templates/helper.go | 3 -- templates/base/head.tmpl | 3 -- web_src/js/features/notification.js | 51 +------------------ 6 files changed, 3 insertions(+), 73 deletions(-) diff --git a/custom/conf/app.example.ini b/custom/conf/app.example.ini index 7492156dff565..dff1b3d0ee3e9 100644 --- a/custom/conf/app.example.ini +++ b/custom/conf/app.example.ini @@ -218,11 +218,8 @@ MIN_TIMEOUT = 10s MAX_TIMEOUT = 60s TIMEOUT_STEP = 10s ; This setting determines how often the db is queried to get the latest notification counts. -; If the browser client supports EventSource, it will be used in preference to polling notification. +; If the browser client supports EventSource and SharedWorker, a SharedWorker will be used in preference to polling notification. EVENT_SOURCE_UPDATE_TIME = 10s -USE_SHARED_WORKER=true ; use a eventsource in shared worker -USE_WORKER=false ; use eventsource in worker -USE_PLAIN_EVENT_SOURCE=false ; allow direct use of event source outside of worker [markdown] ; Render soft line breaks as hard line breaks, which means a single newline character between diff --git a/docs/content/doc/advanced/config-cheat-sheet.en-us.md b/docs/content/doc/advanced/config-cheat-sheet.en-us.md index 9f32260b643fd..ad89876c82679 100644 --- a/docs/content/doc/advanced/config-cheat-sheet.en-us.md +++ b/docs/content/doc/advanced/config-cheat-sheet.en-us.md @@ -150,10 +150,7 @@ Values containing `#` or `;` must be quoted using `` ` `` or `"""`. - `MIN_TIMEOUT`: **10s**: These options control how often notification endpoint is polled to update the notification count. On page load the notification count will be checked after `MIN_TIMEOUT`. The timeout will increase to `MAX_TIMEOUT` by `TIMEOUT_STEP` if the notification count is unchanged. Set MIN_TIMEOUT to 0 to turn off. - `MAX_TIMEOUT`: **60s**. - `TIMEOUT_STEP`: **10s**. -- `EVENT_SOURCE_UPDATE_TIME`: **10s**: This setting determines how often the database is queried to update notification counts. If the browser client supports `EventSource`, it will be used in preference to polling notification endpoint. Set to **-1** to disable the `EventSource`. -- `USE_SHARED_WORKER`: **true**: If the client supports `SharedWorker` and the `EVENT_SOURCE_UPDATE_TIME` is greater than `0`. Use a `SharedWorker` `EventSource` in preference to polling. -- `USE_WORKER`: **false**: If the client supports `Worker` and the `EVENT_SOURCE_UPDATE_TIME` is greater than `0`. Use a `Worker` `EventSource` in preference to polling. (Disabled by default due to limited browser connections under HTTP/1.1.) -- `USE_PLAIN_EVENT_SOURCE`: **false**: If the client supports `EventSource` and the `EVENT_SOURCE_UPDATE_TIME` is greater than `0`. Use a `EventSource` in preference to polling. (Disabled by default due to limited browser connections under HTTP/1.1.) +- `EVENT_SOURCE_UPDATE_TIME`: **10s**: This setting determines how often the database is queried to update notification counts. If the browser client supports `EventSource` and `SharedWorker`, A `SharedWorker` will be used in preference to polling notification endpoint. Set to **-1** to disable the `EventSource` `SharedWorker`. ## Markdown (`markdown`) diff --git a/modules/setting/setting.go b/modules/setting/setting.go index 777e3f3f2dc7d..8efc832f9dc30 100644 --- a/modules/setting/setting.go +++ b/modules/setting/setting.go @@ -185,9 +185,6 @@ var ( TimeoutStep time.Duration MaxTimeout time.Duration EventSourceUpdateTime time.Duration - UseSharedWorker bool - UseWorker bool - UsePlainEventSource bool } `ini:"ui.notification"` Admin struct { @@ -223,17 +220,11 @@ var ( TimeoutStep time.Duration MaxTimeout time.Duration EventSourceUpdateTime time.Duration - UseSharedWorker bool - UseWorker bool - UsePlainEventSource bool }{ MinTimeout: 10 * time.Second, TimeoutStep: 10 * time.Second, MaxTimeout: 60 * time.Second, EventSourceUpdateTime: 10 * time.Second, - UseSharedWorker: true, - UseWorker: false, - UsePlainEventSource: false, }, Admin: struct { UserPagingNum int diff --git a/modules/templates/helper.go b/modules/templates/helper.go index 28dc0b8c66d5a..0be7bcfa70faa 100644 --- a/modules/templates/helper.go +++ b/modules/templates/helper.go @@ -288,9 +288,6 @@ func NewFuncMap() []template.FuncMap { "TimeoutStep": int(setting.UI.Notification.TimeoutStep / time.Millisecond), "MaxTimeout": int(setting.UI.Notification.MaxTimeout / time.Millisecond), "EventSourceUpdateTime": int(setting.UI.Notification.EventSourceUpdateTime / time.Millisecond), - "UseSharedWorker": setting.UI.Notification.UseSharedWorker, - "UseWorker": setting.UI.Notification.UseWorker, - "UsePlainEventSource": setting.UI.Notification.UsePlainEventSource, } }, "contain": func(s []int64, id int64) bool { diff --git a/templates/base/head.tmpl b/templates/base/head.tmpl index 72325e18a2c2e..7999eebb11216 100644 --- a/templates/base/head.tmpl +++ b/templates/base/head.tmpl @@ -77,9 +77,6 @@ TimeoutStep: {{NotificationSettings.TimeoutStep}}, MaxTimeout: {{NotificationSettings.MaxTimeout}}, EventSourceUpdateTime: {{NotificationSettings.EventSourceUpdateTime}}, - UseSharedWorker: {{NotificationSettings.UseSharedWorker}}, - UseWorker: {{NotificationSettings.UseWorker}}, - UsePlainEventSource: {{NotificationSettings.UsePlainEventSource}}, }, {{if .RequireTribute}} tributeValues: [ diff --git a/web_src/js/features/notification.js b/web_src/js/features/notification.js index 355e4bd5a0165..6d47f643c0157 100644 --- a/web_src/js/features/notification.js +++ b/web_src/js/features/notification.js @@ -46,14 +46,8 @@ export async function initNotificationCount() { if (NotificationSettings.EventSourceUpdateTime > 0 && !!window.EventSource) { // Try to connect to the event source first - if (window.SharedWorker && NotificationSettings.UseSharedWorker) { - // const {default: Worker} = await import(/* webpackChunkName: "eventsource" */'./eventsource.sharedworker.js'); - // const worker = Worker('notification'); + if (window.SharedWorker) { const worker = new SharedWorker(`${__webpack_public_path__}js/eventsource.sharedworker.js`, 'notification-worker'); - // worker.port.addEventListener('message', (event) => { - // console.log(event.data); - // }, false); - // worker.port.start(); worker.addEventListener('error', (event) => { console.error(event); }, false); @@ -104,49 +98,6 @@ export async function initNotificationCount() { return; } - - if (window.Worker && NotificationSettings.UseWorker) { - const {default: Worker} = await import(/* webpackChunkName: "eventsource" */'./eventsource.worker.js'); - const worker = new Worker(); - worker.postMessage({ - type: 'start', - url: `${window.location.protocol}//${window.location.host}${AppSubUrl}/user/events`, - }); - worker.addEventListener('notification-count', receiveUpdateCount, false); - worker.addEventListener('logout', (e) => { - if (e.data !== 'here') { - return; - } - worker.postMessage({ - type: 'close', - }); - worker.terminate(); - window.location.href = AppSubUrl; - }, false); - window.addEventListener('beforeunload', () => { - worker.postMessage({ - type: 'close', - }); - worker.terminate(); - }, false); - return; - } - - if (window.EventSource && NotificationSettings.UsePlainEventSource) { - const eventSource = new EventSource(`${AppSubUrl}/user/events`); - eventSource.addEventListener('notification-count', receiveUpdateCount, false); - eventSource.addEventListener('logout', (e) => { - if (e.data !== 'here') { - return; - } - eventSource.close(); - window.location.href = AppSubUrl; - }, false); - window.addEventListener('beforeunload', () => { - eventSource.close(); - }, false); - return; - } } if (NotificationSettings.MinTimeout <= 0) { From 1681afcf62cb9a08d31a43c16cb59ccbab7569f9 Mon Sep 17 00:00:00 2001 From: zeripath Date: Tue, 30 Jun 2020 20:01:12 +0100 Subject: [PATCH 06/18] Update custom/conf/app.example.ini --- custom/conf/app.example.ini | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/custom/conf/app.example.ini b/custom/conf/app.example.ini index dff1b3d0ee3e9..d6c73fbe57c31 100644 --- a/custom/conf/app.example.ini +++ b/custom/conf/app.example.ini @@ -218,7 +218,7 @@ MIN_TIMEOUT = 10s MAX_TIMEOUT = 60s TIMEOUT_STEP = 10s ; This setting determines how often the db is queried to get the latest notification counts. -; If the browser client supports EventSource and SharedWorker, a SharedWorker will be used in preference to polling notification. +; If the browser client supports EventSource and SharedWorker, a SharedWorker will be used in preference to polling notification. Set to -1 to disable the EventSource EVENT_SOURCE_UPDATE_TIME = 10s [markdown] From 7c83c210045be5fe6069dff7ca7143fd6abacffa Mon Sep 17 00:00:00 2001 From: Andrew Thornton Date: Tue, 30 Jun 2020 20:36:45 +0100 Subject: [PATCH 07/18] as per @silverwind Signed-off-by: Andrew Thornton --- .../js/features/eventsource.sharedworker.js | 4 +-- web_src/js/features/eventsource.worker.js | 29 ------------------- web_src/js/features/notification.js | 4 +-- 3 files changed, 4 insertions(+), 33 deletions(-) delete mode 100644 web_src/js/features/eventsource.worker.js diff --git a/web_src/js/features/eventsource.sharedworker.js b/web_src/js/features/eventsource.sharedworker.js index 44a494b0a5599..aebb77cc3ab20 100644 --- a/web_src/js/features/eventsource.sharedworker.js +++ b/web_src/js/features/eventsource.sharedworker.js @@ -73,7 +73,7 @@ class Source { } self.onconnect = (e) => { - e.ports.forEach((port) => { + for (const port of e.ports) { port.addEventListener('message', (event) => { switch (event.data.type) { case 'start': { @@ -147,5 +147,5 @@ self.onconnect = (e) => { } }); port.start(); - }); + } }; diff --git a/web_src/js/features/eventsource.worker.js b/web_src/js/features/eventsource.worker.js deleted file mode 100644 index a03f989137fbe..0000000000000 --- a/web_src/js/features/eventsource.worker.js +++ /dev/null @@ -1,29 +0,0 @@ -let eventSource; - -const listening = {}; - -self.addEventListener('message', (event) => { - if (event.data.type === 'start') { - eventSource = new EventSource(event.data.url); - listen('open'); - listen('error'); - listen('notification-count'); - this.listen('logout'); - } else if (event.data.type === 'listen') { - listen(event.data.eventType); - } else if (event.data.type === 'close' && eventSource) { - eventSource.close(); - eventSource = null; - } -}, false); - -function listen (eventType) { - if (listening[eventType]) return; - listening[eventType] = true; - eventSource.addEventListener(eventType, (event) => { - self.postMessage({ - type: eventType, - data: event.data - }, false); - }); -} diff --git a/web_src/js/features/notification.js b/web_src/js/features/notification.js index 6d47f643c0157..f45c5f4d1d0d3 100644 --- a/web_src/js/features/notification.js +++ b/web_src/js/features/notification.js @@ -51,8 +51,8 @@ export async function initNotificationCount() { worker.addEventListener('error', (event) => { console.error(event); }, false); - worker.port.onmessageeerror = (event) => { - console.error(event); + worker.port.onmessageeerror = () => { + console.error('Unable to deserialize message'); }; worker.port.postMessage({ type: 'start', From 11e16383b66c9a299a5708790c9033b9cc91f896 Mon Sep 17 00:00:00 2001 From: Andrew Thornton Date: Tue, 30 Jun 2020 20:38:51 +0100 Subject: [PATCH 08/18] as per @silverwind Signed-off-by: Andrew Thornton --- web_src/js/features/notification.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/web_src/js/features/notification.js b/web_src/js/features/notification.js index f45c5f4d1d0d3..b767fae0f1111 100644 --- a/web_src/js/features/notification.js +++ b/web_src/js/features/notification.js @@ -51,7 +51,7 @@ export async function initNotificationCount() { worker.addEventListener('error', (event) => { console.error(event); }, false); - worker.port.onmessageeerror = () => { + worker.port.onmessageerror = () => { console.error('Unable to deserialize message'); }; worker.port.postMessage({ From e4bab0812fcbcaa4e960aa7a667bae31c2bb57f8 Mon Sep 17 00:00:00 2001 From: zeripath Date: Tue, 30 Jun 2020 20:40:59 +0100 Subject: [PATCH 09/18] as per @silverwind Co-authored-by: silverwind --- web_src/js/features/eventsource.sharedworker.js | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/web_src/js/features/eventsource.sharedworker.js b/web_src/js/features/eventsource.sharedworker.js index aebb77cc3ab20..43979fb7fdb97 100644 --- a/web_src/js/features/eventsource.sharedworker.js +++ b/web_src/js/features/eventsource.sharedworker.js @@ -57,10 +57,8 @@ class Source { } notifyClients(event) { - const len = this.clients.length; - for (let i = 0; i < len; i++) { - const port = this.clients[i]; - port.postMessage(event); + for (const client of this.clients) { + client.postMessage(event); } } From da873f4f2b31f07c2eed7ec468532f10dfbbf68e Mon Sep 17 00:00:00 2001 From: zeripath Date: Tue, 30 Jun 2020 21:01:27 +0100 Subject: [PATCH 10/18] Update web_src/js/features/eventsource.sharedworker.js Co-authored-by: silverwind --- web_src/js/features/eventsource.sharedworker.js | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/web_src/js/features/eventsource.sharedworker.js b/web_src/js/features/eventsource.sharedworker.js index 43979fb7fdb97..addf8a308c090 100644 --- a/web_src/js/features/eventsource.sharedworker.js +++ b/web_src/js/features/eventsource.sharedworker.js @@ -16,10 +16,7 @@ class Source { } register(port) { - const portIdx = this.clients.indexOf(port); - if (portIdx > -1) { - return; - } + if (!this.clients.includes(port)) return; this.clients.push(port); port.postMessage({ type: 'status', From 372ab504136ddc4def9caf84a70d75b67236a456 Mon Sep 17 00:00:00 2001 From: Andrew Thornton Date: Tue, 30 Jun 2020 21:17:42 +0100 Subject: [PATCH 11/18] as per @silverwind Signed-off-by: Andrew Thornton --- web_src/js/features/eventsource.sharedworker.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/web_src/js/features/eventsource.sharedworker.js b/web_src/js/features/eventsource.sharedworker.js index addf8a308c090..10f90d71572d9 100644 --- a/web_src/js/features/eventsource.sharedworker.js +++ b/web_src/js/features/eventsource.sharedworker.js @@ -105,8 +105,8 @@ self.onconnect = (e) => { case 'listen': { const source = sourcesByPort[port]; source.listen(event.data.eventType); - } return; + } case 'close': { const source = sourcesByPort[port]; if (!source) { From 49f2c75e894dd2c4ee124abf3643db788b77233c Mon Sep 17 00:00:00 2001 From: zeripath Date: Tue, 30 Jun 2020 21:24:51 +0100 Subject: [PATCH 12/18] Update web_src/js/features/eventsource.sharedworker.js Co-authored-by: silverwind --- web_src/js/features/eventsource.sharedworker.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/web_src/js/features/eventsource.sharedworker.js b/web_src/js/features/eventsource.sharedworker.js index 10f90d71572d9..de34d1860410f 100644 --- a/web_src/js/features/eventsource.sharedworker.js +++ b/web_src/js/features/eventsource.sharedworker.js @@ -49,7 +49,7 @@ class Source { self.notifyClients({ type: eventType, data: event.data - }, false); + }); }); } From 13d4d01c7824dc75af70fe278a7a62a3b989a4ce Mon Sep 17 00:00:00 2001 From: zeripath Date: Tue, 30 Jun 2020 21:25:01 +0100 Subject: [PATCH 13/18] Update web_src/js/features/notification.js Co-authored-by: silverwind --- web_src/js/features/notification.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/web_src/js/features/notification.js b/web_src/js/features/notification.js index b767fae0f1111..3680edbb5056c 100644 --- a/web_src/js/features/notification.js +++ b/web_src/js/features/notification.js @@ -56,7 +56,7 @@ export async function initNotificationCount() { }; worker.port.postMessage({ type: 'start', - url: `${window.location.protocol}//${window.location.host}${AppSubUrl}/user/events`, + url: `${window.location.origin}${AppSubUrl}/user/events`, }); worker.port.addEventListener('message', (e) => { if (!e.data || !e.data.type) { From e1f50b506c6650284c4f49532116626b6e8a6c69 Mon Sep 17 00:00:00 2001 From: Andrew Thornton Date: Tue, 30 Jun 2020 21:37:12 +0100 Subject: [PATCH 14/18] multiple stylistic changes as per @silverwind Signed-off-by: Andrew Thornton --- .../js/features/eventsource.sharedworker.js | 107 ++++++++---------- web_src/js/features/notification.js | 34 +++--- 2 files changed, 66 insertions(+), 75 deletions(-) diff --git a/web_src/js/features/eventsource.sharedworker.js b/web_src/js/features/eventsource.sharedworker.js index de34d1860410f..d3fd28f7d8489 100644 --- a/web_src/js/features/eventsource.sharedworker.js +++ b/web_src/js/features/eventsource.sharedworker.js @@ -17,7 +17,9 @@ class Source { register(port) { if (!this.clients.includes(port)) return; + this.clients.push(port); + port.postMessage({ type: 'status', message: `registered to ${this.url}`, @@ -34,9 +36,8 @@ class Source { } close() { - if (!this.eventSource) { - return; - } + if (!this.eventSource) return; + this.eventSource.close(); this.eventSource = null; } @@ -70,75 +71,67 @@ class Source { self.onconnect = (e) => { for (const port of e.ports) { port.addEventListener('message', (event) => { - switch (event.data.type) { - case 'start': { - const url = event.data.url; - if (sourcesByUrl[url]) { + 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) { - // We have a valid source for this port... - 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); + const source = sourcesByUrl[url]; source.register(port); - sourcesByUrl[url] = source; sourcesByPort[port] = source; return; } - case 'listen': { - const source = sourcesByPort[port]; - source.listen(event.data.eventType); - return; - } - case 'close': { - const source = sourcesByPort[port]; - if (!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; - sourcesByPort[port] = null; } - return; } - case 'status': { - const source = sourcesByPort[port]; - if (!source) { - port.postMessage({ - type: 'status', - message: 'not connected', - }); - return; - } - source.status(port); - return; + // 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; } - default: - // just send it back + return; + } else if (event.data.type === 'status') { + const source = sourcesByPort[port]; + if (!source) { port.postMessage({ - type: 'error', - message: `received but don't know how to handle: ${event.data}`, + 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(); diff --git a/web_src/js/features/notification.js b/web_src/js/features/notification.js index 3680edbb5056c..8f44dbe422d82 100644 --- a/web_src/js/features/notification.js +++ b/web_src/js/features/notification.js @@ -63,26 +63,24 @@ export async function initNotificationCount() { console.error(e); return; } - switch (event.data.type) { - case 'notification-count': - receiveUpdateCount(e.data); - return; - case 'error': - console.error(e.data); - return; - case 'logout': { - if (e.data !== 'here') { - return; - } - worker.port.postMessage({ - type: 'close', - }); - worker.port.close(); - window.location.href = AppSubUrl; + if (event.data.type === 'notification-count') { + receiveUpdateCount(e.data); + return; + } else if (event.data.type === 'error') { + console.error(e.data); + return; + } else if (event.data.type === 'logout') { + if (e.data !== 'here') { return; } - default: - return; + worker.port.postMessage({ + type: 'close', + }); + worker.port.close(); + window.location.href = AppSubUrl; + return; + } else { + return; } }, false); worker.port.addEventListener('error', (e) => { From bc1b11c6f1bf6bcb50bd4212f1c14d8f5f2fb601 Mon Sep 17 00:00:00 2001 From: zeripath Date: Tue, 30 Jun 2020 21:42:59 +0100 Subject: [PATCH 15/18] as per @silverwind Co-authored-by: silverwind --- web_src/js/features/notification.js | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/web_src/js/features/notification.js b/web_src/js/features/notification.js index 8f44dbe422d82..0e38ed093c62e 100644 --- a/web_src/js/features/notification.js +++ b/web_src/js/features/notification.js @@ -50,7 +50,7 @@ export async function initNotificationCount() { const worker = new SharedWorker(`${__webpack_public_path__}js/eventsource.sharedworker.js`, 'notification-worker'); worker.addEventListener('error', (event) => { console.error(event); - }, false); + }); worker.port.onmessageerror = () => { console.error('Unable to deserialize message'); }; @@ -82,17 +82,17 @@ export async function initNotificationCount() { } else { return; } - }, false); + }); worker.port.addEventListener('error', (e) => { console.error(e); - }, false); + }); worker.port.start(); window.addEventListener('beforeunload', () => { worker.port.postMessage({ type: 'close', }); worker.port.close(); - }, false); + }); return; } From aaccdfc6e2466f5dc6f55ebe7494fd4bc3cf486c Mon Sep 17 00:00:00 2001 From: Andrew Thornton Date: Tue, 30 Jun 2020 21:45:56 +0100 Subject: [PATCH 16/18] as per @silverwind Signed-off-by: Andrew Thornton --- web_src/js/features/eventsource.sharedworker.js | 5 +++-- web_src/js/features/notification.js | 3 +-- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/web_src/js/features/eventsource.sharedworker.js b/web_src/js/features/eventsource.sharedworker.js index d3fd28f7d8489..fd166f68ee81b 100644 --- a/web_src/js/features/eventsource.sharedworker.js +++ b/web_src/js/features/eventsource.sharedworker.js @@ -74,7 +74,7 @@ self.onconnect = (e) => { if (event.data.type === 'start') { const url = event.data.url; if (sourcesByUrl[url]) { - // we have a Source registered to this url + // we have a Source registered to this url const source = sourcesByUrl[url]; source.register(port); sourcesByPort[port] = source; @@ -83,6 +83,7 @@ self.onconnect = (e) => { 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); @@ -126,7 +127,7 @@ self.onconnect = (e) => { source.status(port); return; } else { - // just send it back + // just send it back port.postMessage({ type: 'error', message: `received but don't know how to handle: ${event.data}`, diff --git a/web_src/js/features/notification.js b/web_src/js/features/notification.js index 0e38ed093c62e..3be02d6ca0602 100644 --- a/web_src/js/features/notification.js +++ b/web_src/js/features/notification.js @@ -44,8 +44,7 @@ export async function initNotificationCount() { } if (NotificationSettings.EventSourceUpdateTime > 0 && !!window.EventSource) { - // Try to connect to the event source first - + // Try to connect to the event source via the shared worker first if (window.SharedWorker) { const worker = new SharedWorker(`${__webpack_public_path__}js/eventsource.sharedworker.js`, 'notification-worker'); worker.addEventListener('error', (event) => { From 7052eba94fb233d46795200c35fdcbc58c5f9386 Mon Sep 17 00:00:00 2001 From: Andrew Thornton Date: Wed, 1 Jul 2020 09:54:20 +0100 Subject: [PATCH 17/18] more indentation Signed-off-by: Andrew Thornton --- web_src/js/features/eventsource.sharedworker.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/web_src/js/features/eventsource.sharedworker.js b/web_src/js/features/eventsource.sharedworker.js index fd166f68ee81b..7dccd8994e1f9 100644 --- a/web_src/js/features/eventsource.sharedworker.js +++ b/web_src/js/features/eventsource.sharedworker.js @@ -93,7 +93,7 @@ self.onconnect = (e) => { sourcesByUrl[source.url] = null; } } - // Create a new Source + // Create a new Source source = new Source(url); source.register(port); sourcesByUrl[url] = source; From e362de13f32145d4c516e0cd5cd9d27512064120 Mon Sep 17 00:00:00 2001 From: Andrew Thornton Date: Fri, 3 Jul 2020 09:58:32 +0100 Subject: [PATCH 18/18] As per @silverwind, @lafriks and @techknowlogick Signed-off-by: Andrew Thornton --- .eslintrc | 2 +- docs/content/doc/advanced/config-cheat-sheet.en-us.md | 2 +- web_src/js/features/notification.js | 8 ++++---- 3 files changed, 6 insertions(+), 6 deletions(-) diff --git a/.eslintrc b/.eslintrc index 1a7551aee7480..8e478f4a5a3f2 100644 --- a/.eslintrc +++ b/.eslintrc @@ -28,7 +28,7 @@ globals: Tribute: false overrides: - - files: ["web_src/**/*.worker.js", "web_src/js/serviceworker.js"] + - files: ["web_src/**/*worker.js"] env: worker: true diff --git a/docs/content/doc/advanced/config-cheat-sheet.en-us.md b/docs/content/doc/advanced/config-cheat-sheet.en-us.md index ad89876c82679..4fa0910b1f487 100644 --- a/docs/content/doc/advanced/config-cheat-sheet.en-us.md +++ b/docs/content/doc/advanced/config-cheat-sheet.en-us.md @@ -150,7 +150,7 @@ Values containing `#` or `;` must be quoted using `` ` `` or `"""`. - `MIN_TIMEOUT`: **10s**: These options control how often notification endpoint is polled to update the notification count. On page load the notification count will be checked after `MIN_TIMEOUT`. The timeout will increase to `MAX_TIMEOUT` by `TIMEOUT_STEP` if the notification count is unchanged. Set MIN_TIMEOUT to 0 to turn off. - `MAX_TIMEOUT`: **60s**. - `TIMEOUT_STEP`: **10s**. -- `EVENT_SOURCE_UPDATE_TIME`: **10s**: This setting determines how often the database is queried to update notification counts. If the browser client supports `EventSource` and `SharedWorker`, A `SharedWorker` will be used in preference to polling notification endpoint. Set to **-1** to disable the `EventSource` `SharedWorker`. +- `EVENT_SOURCE_UPDATE_TIME`: **10s**: This setting determines how often the database is queried to update notification counts. If the browser client supports `EventSource` and `SharedWorker`, a `SharedWorker` will be used in preference to polling notification endpoint. Set to **-1** to disable the `EventSource`. ## Markdown (`markdown`) diff --git a/web_src/js/features/notification.js b/web_src/js/features/notification.js index 3be02d6ca0602..2b7fc452374d9 100644 --- a/web_src/js/features/notification.js +++ b/web_src/js/features/notification.js @@ -22,11 +22,11 @@ async function receiveUpdateCount(event) { try { const data = JSON.parse(event.data); - const notificationCount = $('.notification_count'); - if (data.Count === 0) { - notificationCount.addClass('hidden'); + const notificationCount = document.querySelector('.notification_count'); + if (data.Count > 0) { + notificationCount.classList.remove('hidden'); } else { - notificationCount.removeClass('hidden'); + notificationCount.classList.add('hidden'); } notificationCount.text(`${data.Count}`);