Skip to content

Commit 760bab5

Browse files
committed
fall back to periodic poller
1 parent f1ab3c4 commit 760bab5

File tree

2 files changed

+70
-65
lines changed

2 files changed

+70
-65
lines changed

web_src/js/features/notification.js

Lines changed: 24 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -28,14 +28,11 @@ async function receiveUpdateCount(event) {
2828
try {
2929
const data = JSON.parse(event.data);
3030

31-
const notificationCount = document.querySelector('.notification_count');
32-
if (data.Count > 0) {
33-
notificationCount.classList.remove('hidden');
34-
} else {
35-
notificationCount.classList.add('hidden');
31+
const notificationCounts = document.querySelectorAll('.notification_count');
32+
for (const count of notificationCounts) {
33+
count.classList.toggle('hidden', data.Count === 0);
34+
count.textContent = `${data.Count}`;
3635
}
37-
38-
notificationCount.textContent = `${data.Count}`;
3936
await updateNotificationTable();
4037
} catch (error) {
4138
console.error(error, event);
@@ -49,28 +46,41 @@ export function initNotificationCount() {
4946
return;
5047
}
5148

52-
if (notificationSettings.EventSourceUpdateTime > 0 && !!window.EventSource && window.SharedWorker) {
49+
let usingPeriodicPoller = false;
50+
const startPeriodicPoller = (timeout, lastCount) => {
51+
if (timeout <= 0 || !Number.isFinite(timeout)) return;
52+
usingPeriodicPoller = true;
53+
lastCount = lastCount ?? notificationCount.text();
54+
setTimeout(async () => {
55+
await updateNotificationCountWithCallback(startPeriodicPoller, timeout, lastCount);
56+
}, timeout);
57+
};
58+
59+
if (notificationSettings.EventSourceUpdateTime > 0 && window.EventSource && window.SharedWorker) {
5360
// Try to connect to the event source via the shared worker first
5461
const worker = new SharedWorker(`${__webpack_public_path__}js/eventsource.sharedworker.js`, 'notification-worker');
5562
worker.addEventListener('error', (event) => {
56-
console.error(event);
63+
console.error('worker error', event);
5764
});
5865
worker.port.addEventListener('messageerror', () => {
59-
console.error('Unable to deserialize message');
66+
console.error('unable to deserialize message');
6067
});
6168
worker.port.postMessage({
6269
type: 'start',
6370
url: `${window.location.origin}${appSubUrl}/user/events`,
6471
});
6572
worker.port.addEventListener('message', (event) => {
6673
if (!event.data || !event.data.type) {
67-
console.error(event);
74+
console.error('unknown worker message event', event);
6875
return;
6976
}
7077
if (event.data.type === 'notification-count') {
7178
const _promise = receiveUpdateCount(event.data);
79+
} else if (event.data.type === 'no-event-source') {
80+
console.error(`browser doesn't support EventSource, falling back to periodic poller`);
81+
if (!usingPeriodicPoller) startPeriodicPoller(notificationSettings.MinTimeout);
7282
} else if (event.data.type === 'error') {
73-
console.error(event.data);
83+
console.error('worker port event error', event.data);
7484
} else if (event.data.type === 'logout') {
7585
if (event.data.data !== 'here') {
7686
return;
@@ -88,7 +98,7 @@ export function initNotificationCount() {
8898
}
8999
});
90100
worker.port.addEventListener('error', (e) => {
91-
console.error(e);
101+
console.error('worker port error', e);
92102
});
93103
worker.port.start();
94104
window.addEventListener('beforeunload', () => {
@@ -101,17 +111,7 @@ export function initNotificationCount() {
101111
return;
102112
}
103113

104-
if (notificationSettings.MinTimeout <= 0) {
105-
return;
106-
}
107-
108-
const fn = (timeout, lastCount) => {
109-
setTimeout(() => {
110-
const _promise = updateNotificationCountWithCallback(fn, timeout, lastCount);
111-
}, timeout);
112-
};
113-
114-
fn(notificationSettings.MinTimeout, notificationCount.text());
114+
startPeriodicPoller(notificationSettings.MinTimeout);
115115
}
116116

117117
async function updateNotificationCountWithCallback(callback, timeout, lastCount) {

web_src/js/features/stopwatch.js

Lines changed: 46 additions & 41 deletions
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,6 @@ import $ from 'jquery';
22
import prettyMilliseconds from 'pretty-ms';
33

44
const {appSubUrl, csrfToken, notificationSettings, enableTimeTracking} = window.config;
5-
let updateTimeInterval = null; // holds setInterval id when active
65

76
export function initStopwatch() {
87
if (!enableTimeTracking) {
@@ -26,28 +25,48 @@ export function initStopwatch() {
2625
$(this).parent().trigger('submit');
2726
});
2827

29-
if (notificationSettings.EventSourceUpdateTime > 0 && !!window.EventSource && window.SharedWorker) {
28+
// global stop watch (in the head_navbar), it should always work in any case either the EventSource or the TimerPoller is used.
29+
const currSeconds = $('.stopwatch-time').attr('data-seconds');
30+
if (currSeconds) {
31+
updateStopwatchTime(currSeconds);
32+
}
33+
34+
let usingPeriodicPoller = false;
35+
// poll the stopwatch status periodically
36+
const startPeriodicPoller = (timeout) => {
37+
if (timeout <= 0 || !Number.isFinite(timeout)) return;
38+
usingPeriodicPoller = true;
39+
setTimeout(async () => {
40+
await updateStopwatchWithCallback(startPeriodicPoller, timeout);
41+
}, timeout);
42+
};
43+
44+
// if the browser supports EventSource and SharedWorker, use it instead of the periodic poller
45+
if (notificationSettings.EventSourceUpdateTime > 0 && window.EventSource && window.SharedWorker) {
3046
// Try to connect to the event source via the shared worker first
3147
const worker = new SharedWorker(`${__webpack_public_path__}js/eventsource.sharedworker.js`, 'notification-worker');
3248
worker.addEventListener('error', (event) => {
33-
console.error(event);
49+
console.error('worker error', event);
3450
});
3551
worker.port.addEventListener('messageerror', () => {
36-
console.error('Unable to deserialize message');
52+
console.error('unable to deserialize message');
3753
});
3854
worker.port.postMessage({
3955
type: 'start',
4056
url: `${window.location.origin}${appSubUrl}/user/events`,
4157
});
4258
worker.port.addEventListener('message', (event) => {
4359
if (!event.data || !event.data.type) {
44-
console.error(event);
60+
console.error('unknown worker message event', event);
4561
return;
4662
}
4763
if (event.data.type === 'stopwatches') {
4864
updateStopwatchData(JSON.parse(event.data.data));
65+
} else if (event.data.type === 'no-event-source') {
66+
console.error(`browser doesn't support EventSource, falling back to periodic poller`);
67+
if (!usingPeriodicPoller) startPeriodicPoller(notificationSettings.MinTimeout);
4968
} else if (event.data.type === 'error') {
50-
console.error(event.data);
69+
console.error('worker port event error', event.data);
5170
} else if (event.data.type === 'logout') {
5271
if (event.data.data !== 'here') {
5372
return;
@@ -65,7 +84,7 @@ export function initStopwatch() {
6584
}
6685
});
6786
worker.port.addEventListener('error', (e) => {
68-
console.error(e);
87+
console.error('worker port error', e);
6988
});
7089
worker.port.start();
7190
window.addEventListener('beforeunload', () => {
@@ -78,22 +97,7 @@ export function initStopwatch() {
7897
return;
7998
}
8099

81-
if (notificationSettings.MinTimeout <= 0) {
82-
return;
83-
}
84-
85-
const fn = (timeout) => {
86-
setTimeout(() => {
87-
const _promise = updateStopwatchWithCallback(fn, timeout);
88-
}, timeout);
89-
};
90-
91-
fn(notificationSettings.MinTimeout);
92-
93-
const currSeconds = $('.stopwatch-time').data('seconds');
94-
if (currSeconds) {
95-
updateTimeInterval = updateStopwatchTime(currSeconds);
96-
}
100+
startPeriodicPoller(notificationSettings.MinTimeout);
97101
}
98102

99103
async function updateStopwatchWithCallback(callback, timeout) {
@@ -114,23 +118,14 @@ async function updateStopwatch() {
114118
url: `${appSubUrl}/user/stopwatches`,
115119
headers: {'X-Csrf-Token': csrfToken},
116120
});
117-
118-
if (updateTimeInterval) {
119-
clearInterval(updateTimeInterval);
120-
updateTimeInterval = null;
121-
}
122-
123121
return updateStopwatchData(data);
124122
}
125123

126124
function updateStopwatchData(data) {
127125
const watch = data[0];
128126
const btnEl = $('.active-stopwatch-trigger');
129127
if (!watch) {
130-
if (updateTimeInterval) {
131-
clearInterval(updateTimeInterval);
132-
updateTimeInterval = null;
133-
}
128+
clearStopwatchTimer();
134129
btnEl.addClass('hidden');
135130
} else {
136131
const {repo_owner_name, repo_name, issue_index, seconds} = watch;
@@ -139,22 +134,32 @@ function updateStopwatchData(data) {
139134
$('.stopwatch-commit').attr('action', `${issueUrl}/times/stopwatch/toggle`);
140135
$('.stopwatch-cancel').attr('action', `${issueUrl}/times/stopwatch/cancel`);
141136
$('.stopwatch-issue').text(`${repo_owner_name}/${repo_name}#${issue_index}`);
142-
$('.stopwatch-time').text(prettyMilliseconds(seconds * 1000));
143-
updateTimeInterval = updateStopwatchTime(seconds);
137+
updateStopwatchTime(seconds);
144138
btnEl.removeClass('hidden');
145139
}
146-
147140
return !!data.length;
148141
}
149142

143+
let updateTimeIntervalId = null; // holds setInterval id when active
144+
function clearStopwatchTimer() {
145+
if (updateTimeIntervalId !== null) {
146+
clearInterval(updateTimeIntervalId);
147+
updateTimeIntervalId = null;
148+
}
149+
}
150150
function updateStopwatchTime(seconds) {
151151
const secs = parseInt(seconds);
152-
if (!Number.isFinite(secs)) return null;
153-
152+
if (!Number.isFinite(secs)) {
153+
return;
154+
}
155+
clearStopwatchTimer();
156+
const $stopwatch = $('.stopwatch-time');
154157
const start = Date.now();
155-
return setInterval(() => {
158+
const updateUi = () => {
156159
const delta = Date.now() - start;
157160
const dur = prettyMilliseconds(secs * 1000 + delta, {compact: true});
158-
$('.stopwatch-time').text(dur);
159-
}, 1000);
161+
$stopwatch.text(dur);
162+
};
163+
updateUi();
164+
updateTimeIntervalId = setInterval(updateUi, 1000);
160165
}

0 commit comments

Comments
 (0)