Fallback to polling if streaming fails

This commit is contained in:
Lim Chee Aun 2023-11-01 21:31:43 +08:00
parent 33f807de73
commit 7119a78711

View file

@ -13,55 +13,80 @@ export default memo(function BackgroundService({ isLoggedIn }) {
// - WebSocket to receive notifications when page is visible // - WebSocket to receive notifications when page is visible
const [visible, setVisible] = useState(true); const [visible, setVisible] = useState(true);
usePageVisibility(setVisible); usePageVisibility(setVisible);
const checkLatestNotification = async (masto, instance, skipCheckMarkers) => {
if (states.notificationsLast) {
const notificationsIterator = masto.v1.notifications.list({
limit: 1,
sinceId: states.notificationsLast.id,
});
const { value: notifications } = await notificationsIterator.next();
if (notifications?.length) {
if (skipCheckMarkers) {
states.notificationsShowNew = true;
} else {
let lastReadId;
try {
const markers = await masto.v1.markers.fetch({
timeline: 'notifications',
});
lastReadId = markers?.notifications?.lastReadId;
} catch (e) {}
if (lastReadId) {
states.notificationsShowNew = notifications[0].id !== lastReadId;
} else {
states.notificationsShowNew = true;
}
}
}
}
};
useEffect(() => { useEffect(() => {
let sub; let sub;
let pollNotifications;
if (isLoggedIn && visible) { if (isLoggedIn && visible) {
const { masto, streaming, instance } = api(); const { masto, streaming, instance } = api();
(async () => { (async () => {
// 1. Get the latest notification // 1. Get the latest notification
if (states.notificationsLast) { await checkLatestNotification(masto, instance);
const notificationsIterator = masto.v1.notifications.list({
limit: 1, let hasStreaming = false;
since_id: states.notificationsLast.id, // 2. Start streaming
}); if (streaming) {
const { value: notifications } = await notificationsIterator.next(); try {
if (notifications?.length) { hasStreaming = true;
let lastReadId; sub = streaming.user.notification.subscribe();
try { console.log('🎏 Streaming notification', sub);
const markers = await masto.v1.markers.fetch({ for await (const entry of sub) {
timeline: 'notifications', if (!sub) break;
}); console.log('🔔🔔 Notification entry', entry);
lastReadId = markers?.notifications?.lastReadId; if (entry.event === 'notification') {
} catch (e) {} console.log('🔔🔔 Notification', entry);
if (lastReadId) { saveStatus(entry.payload, instance, {
states.notificationsShowNew = notifications[0].id !== lastReadId; skipThreading: true,
} else { });
}
states.notificationsShowNew = true; states.notificationsShowNew = true;
} }
} catch (e) {
hasStreaming = false;
console.error(e);
} }
} }
// 2. Start streaming if (!hasStreaming) {
if (streaming) { console.log('🎏 Streaming failed, fallback to polling');
sub = streaming.user.notification.subscribe(); // Fallback to polling every minute
console.log('🎏 Streaming notification', sub); pollNotifications = setInterval(() => {
for await (const entry of sub) { checkLatestNotification(masto, instance, true);
if (!sub) break; }, 1000 * 60);
console.log('🔔🔔 Notification entry', entry);
if (entry.event === 'notification') {
console.log('🔔🔔 Notification', entry);
saveStatus(entry.payload, instance, {
skipThreading: true,
});
}
states.notificationsShowNew = true;
}
} }
})(); })();
} }
return () => { return () => {
sub?.unsubscribe?.(); sub?.unsubscribe?.();
sub = null; sub = null;
clearInterval(pollNotifications);
}; };
}, [visible, isLoggedIn]); }, [visible, isLoggedIn]);