fallback for when reconnect_failed on socket, set max reconnects, goto polling. also make notifs and scroll to post independent and manual update button when live disabled or in polling mode"

merge-requests/208/head
fatchan 4 years ago
parent fd9b1c8cf9
commit 444a702fa9
  1. 3
      gulp/res/js/forms.js
  2. 219
      gulp/res/js/live.js
  3. 1
      socketio.js

@ -120,7 +120,8 @@ class formHandler {
return window.location = json.redirect;
}
setLocalStorage('myPostId', json.postId);
window.location.reload();
forceUpdate();
// window.location.reload();
}
}
this.form.reset();

@ -1,30 +1,30 @@
setDefaultLocalStorage('live', true);
setDefaultLocalStorage('notifications', false);
setDefaultLocalStorage('scroll', false);
var socket;
let liveEnabled = localStorage.getItem('live') == 'true';
let notificationsEnabled = localStorage.getItem('notifications') == 'true';
let scrollEnabled = localStorage.getItem('scroll') == 'true';
let socket;
let forceUpdate;
window.addEventListener('settingsReady', function(event) { //after domcontentloaded
let supportsWebSockets = 'WebSocket' in window || 'MozWebSocket' in window;
const livecolor = document.getElementById('livecolor');
const livetext = isThread ? document.getElementById('livetext').childNodes[1] : null;
const updateButton = livetext ? livetext.nextSibling : null;
const updateLive = (message, color) => {
const updateLive = (message, color, showRelativeTime) => {
livecolor.style.backgroundColor = color;
livetext.nodeValue = message;
livetext.nodeValue = `${message}`;
}
let lastPostId;
let liveTimeout;
const anchors = document.getElementsByClassName('anchor');
let liveEnabled = localStorage.getItem('live') == 'true';
let notificationsEnabled = localStorage.getItem('notifications') == 'true';
let scrollEnabled = localStorage.getItem('scroll') == 'true';
if (anchors.length > 0) {
lastPostId = anchors[anchors.length - 1].id;
}
const thread = document.querySelector('.thread');
const newPost = (data) => {
console.log('got new post');
lastPostId = data.postId;
@ -83,111 +83,132 @@ window.addEventListener('settingsReady', function(event) { //after domcontentloa
window.dispatchEvent(newPostEvent);
}
const jsonPath = window.location.pathname.replace(/\.html$/, '.json');
const jsonCatchup = async () => {
console.log('catching up after reconnect');
const fetchNewPosts = async () => {
console.log('fetching posts from api');
updateLive('Fetching posts...', 'yellow');
let json;
let newPosts = [];
try {
json = await fetch(jsonPath).then(res => res.json());
} catch (e) {
console.error(e);
}
if (json && json.replies && json.replies.length > 0) {
const newPosts = json.replies.filter(r => r.postId > lastPostId); //filter to only newer posts
newPosts = json.replies.filter(r => r.postId > lastPostId); //filter to only newer posts
if (newPosts.length > 0) {
for (let i = 0; i < newPosts.length; i++) {
newPost(newPosts[i]);
}
}
}
updateLive('Updated', 'green');
return newPosts.length;
}
const startLive = () => {
const roomParts = window.location.pathname.replace(/\.html$/, '').split('/');
const room = `${roomParts[1]}-${roomParts[3]}`;
socket = io({ transports: ['websocket'] });
socket.on('connect', () => {
updateButton.style.display = 'none';
console.log('joined room', room);
updateLive('Connected for live posts', '#0de600');
socket.emit('room', room);
});
socket.on('pong', (latency) => {
updateButton.style.display = 'none';
if (socket.connected) {
updateLive(`Connected for live posts (${latency}ms)`, '#0de600');
}
});
socket.on('reconnect_attempt', () => {
updateLive('Attempting to reconnect...', 'yellow');
});
socket.on('disconnect', () => {
updateButton.removeAttribute('style');
console.log('lost connection to room');
updateLive('Disconnected', 'red');
});
socket.on('reconnect', () => {
let interval = 5000;
forceUpdate = async () => {
updateButton.disabled = true;
clearTimeout(liveTimeout);
if ((await fetchNewPosts()) > 0) {
interval = 5000;
} else {
interval = Math.min(interval*2, 90000);
}
setTimeout(() => {
updateButton.disabled = false;
}, 10000);
if (liveEnabled) {
liveTimeout = setTimeout(forceUpdate, interval);
}
}
const enableLive = () => {
if (supportsWebSockets) {
updateButton.style.display = 'none';
console.log('reconnected to room');
jsonCatchup();
});
socket.on('error', (e) => {
updateButton.removeAttribute('style');
updateLive('Socket error', 'orange');
console.error(e);
});
socket.on('connect_error', (e) => {
updateButton.removeAttribute('style');
updateLive('Error connecting', 'orange');
console.error(e);
});
socket.on('reconnect_error', (e) => {
const roomParts = window.location.pathname.replace(/\.html$/, '').split('/');
const room = `${roomParts[1]}-${roomParts[3]}`;
socket = io({
transports: ['websocket'],
reconnectionAttempts: 5
});
socket.on('connect', async () => {
console.log('socket connected');
await fetchNewPosts();
socket.emit('room', room);
});
socket.on('message', (message) => {
console.log(message, room);
if (message === 'joined') {
updateLive('Connected for live posts', '#0de600');
}
});
socket.on('pong', (latency) => {
if (socket.connected) {
updateLive(`Connected for live posts (${latency}ms)`, '#0de600');
}
});
socket.on('reconnect_attempt', () => {
updateLive('Attempting to reconnect...', 'yellow');
});
socket.on('disconnect', () => {
console.log('lost connection to room');
updateLive('Disconnected', 'red');
});
socket.on('reconnect', () => {
console.log('reconnected to room');
fetchNewPosts();
});
socket.on('error', (e) => {
updateLive('Socket error', 'orange');
console.error(e);
});
socket.on('connect_error', (e) => {
updateLive('Error connecting', 'orange');
console.error(e);
});
socket.on('reconnect_error', (e) => {
updateLive('Error reconnecting', 'orange');
console.error(e);
});
socket.on('reconnect_failed', (e) => {
updateLive('Failed reconnecting', 'orange');
console.error(e);
console.log('failed to reconnnect, falling back to polling')
socket.close();
supportsWebSockets = false;
enableLive();
});
socket.on('newPost', newPost);
} else {
//websocket not supported, update with polling to api
updateButton.removeAttribute('style');
updateLive('Error reconnecting', 'orange');
console.error(e);
});
socket.on('newPost', newPost);
}
forceUpdate();
}
};
const liveSetting = document.getElementById('live-setting');
const notificationSetting = document.getElementById('notification-setting');
const scrollSetting = document.getElementById('scroll-setting');
const disableLive = () => {
updateButton.removeAttribute('style');
clearTimeout(liveTimeout);
if (socket && supportsWebSockets) {
socket.disconnect();
}
updateLive('Live posts off', 'darkgray');
};
const liveSetting = document.getElementById('live-setting');
const toggleLive = () => {
if (isThread) {
if (socket && liveEnabled) {
socket.disconnect();
updateLive('Live posts disabled', 'red');
} else {
if (!socket) {
startLive();
} else {
socket.connect();
}
jsonCatchup();
}
}
liveEnabled = !liveEnabled;
if (!liveEnabled) {
//disable notifications and scroll when live off because they wont work
if (notificationsEnabled) {
notificationSetting.checked = false;
toggleNotifications(null, true);
}
if (scrollEnabled) {
scrollSetting.checked = false;
toggleScroll(null, true);
}
}
liveEnabled ? enableLive() : disableLive();
console.log('toggling live posts', liveEnabled);
setLocalStorage('live', liveEnabled);
}
liveSetting.checked = liveEnabled;
liveSetting.addEventListener('change', toggleLive, false);
const toggleNotifications = async (change, changeFromConflict) => {
const notificationSetting = document.getElementById('notification-setting');
const toggleNotifications = async () => {
notificationsEnabled = !notificationsEnabled;
if (notificationsEnabled) {
const result = await Notification.requestPermission()
@ -200,42 +221,22 @@ window.addEventListener('settingsReady', function(event) { //after domcontentloa
}
console.log('toggling notifications', notificationsEnabled);
setLocalStorage('notifications', notificationsEnabled);
if (!liveEnabled && !changeFromConflict) {
liveSetting.checked = true;
toggleLive();
}
}
notificationSetting.checked = notificationsEnabled;
notificationSetting.addEventListener('change', toggleNotifications, false);
const toggleScroll = (change, changeFromConflict) => {
const scrollSetting = document.getElementById('scroll-setting');
const toggleScroll = () => {
scrollEnabled = !scrollEnabled;
console.log('toggling post scrolling', scrollEnabled);
setLocalStorage('scroll', scrollEnabled);
if (!liveEnabled && !changeFromConflict) {
liveSetting.checked = true;
toggleLive();
}
}
scrollSetting.checked = scrollEnabled;
scrollSetting.addEventListener('change', toggleScroll, false);
if (isThread) {
const forceUpdate = async () => {
updateButton.disabled = true;
await jsonCatchup();
updateLive('Updated', 'green');
setTimeout(() => {
updateButton.disabled = false;
}, 10000);
}
updateButton.addEventListener('click', forceUpdate);
if (liveEnabled) {
updateButton.style.display = 'none';
startLive();
} else {
updateLive('Live posts disabled', 'red');
}
liveEnabled ? enableLive() : disableLive();
}
});

@ -19,6 +19,7 @@ module.exports = {
socket.on('room', room => {
//TODO: add some validation here that rooms exist or AT LEAST a regex for valid thread rooms
socket.join(room);
socket.send('joined');
});
});
},

Loading…
Cancel
Save