Async-Redis
view release on metacpan or search on metacpan
examples/pagi-chat/public/js/app.js view on Meta::CPAN
setConnectionStatus(state.reconnectAttempts > 0 ? 'reconnecting' : 'connecting');
state.ws = new WebSocket(wsUrl);
state.ws.onopen = () => {
setConnectionStatus('connected');
state.reconnectAttempts = 0;
state.lastPongTime = Date.now();
// Start keepalive ping interval
if (state.pingInterval) {
clearInterval(state.pingInterval);
}
state.pingInterval = setInterval(() => {
if (state.ws && state.ws.readyState === WebSocket.OPEN) {
sendMessage({ type: 'ping' });
}
}, state.pingIntervalMs);
// Start heartbeat timeout check
examples/pagi-chat/public/js/app.js view on Meta::CPAN
renderMessages(data.messages || []);
}
break;
case 'error':
showToast(data.message, 'error');
break;
case 'pong':
case 'server_ping':
// Keepalive messages - no action needed
break;
case 'stats':
updateStats(data);
break;
}
}
function sendMessage(data) {
if (state.ws && state.ws.readyState === WebSocket.OPEN) {
examples/pagi-chat/public/js/app.js view on Meta::CPAN
// ===== Event Handlers =====
function initEventHandlers() {
// Theme toggle
elements.themeToggle.addEventListener('click', toggleTheme);
// Visibility change - send ping when tab becomes visible
// This helps prevent disconnects from browser throttling background tabs
document.addEventListener('visibilitychange', () => {
if (document.visibilityState === 'visible') {
// Tab became visible - send immediate ping to keep connection alive
if (state.ws && state.ws.readyState === WebSocket.OPEN) {
sendMessage({ type: 'ping' });
}
}
});
// Login form
elements.loginForm.addEventListener('submit', (e) => {
e.preventDefault();
const username = elements.usernameInput.value.trim();
( run in 0.986 second using v1.01-cache-2.11-cpan-df04353d9ac )