incognitolm commited on
Commit
14e2e36
Β·
verified Β·
1 Parent(s): 8a7fbbb

Update public/js/ws.js

Browse files
Files changed (1) hide show
  1. public/js/ws.js +43 -19
public/js/ws.js CHANGED
@@ -50,13 +50,51 @@ function emit(type, data) {
50
  listeners.get('*')?.forEach(fn => fn({ type, ...data }));
51
  }
52
 
53
- function connect() {
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
54
  if (ws && (ws.readyState === WebSocket.CONNECTING || ws.readyState === WebSocket.OPEN)) return;
55
 
56
  ws = new WebSocket(WS_URL);
57
 
58
  ws.onopen = () => {
59
  reconnectDelay = RECONNECT_DELAY_MS;
 
60
  emit('ws:connected', {});
61
  };
62
 
@@ -64,8 +102,9 @@ function connect() {
64
  let msg;
65
  try { msg = JSON.parse(event.data); } catch { return; }
66
  if (!msg?.type) return;
 
 
67
 
68
- // Resolve pending request callbacks
69
  if (msg._reqId && pendingCallbacks.has(msg._reqId)) {
70
  const cb = pendingCallbacks.get(msg._reqId);
71
  pendingCallbacks.delete(msg._reqId);
@@ -79,6 +118,7 @@ function connect() {
79
  };
80
 
81
  ws.onclose = () => {
 
82
  emit('ws:disconnected', {});
83
  scheduleReconnect();
84
  };
@@ -88,22 +128,6 @@ function connect() {
88
  };
89
  }
90
 
91
- function scheduleReconnect() {
92
- clearTimeout(reconnectTimer);
93
- reconnectTimer = setTimeout(() => {
94
- reconnectDelay = Math.min(reconnectDelay * 1.5, MAX_RECONNECT_DELAY);
95
- connect();
96
- }, reconnectDelay);
97
- }
98
-
99
- export function getReadyState() {
100
- return ws?.readyState ?? WebSocket.CLOSED;
101
- }
102
-
103
- export function isConnected() {
104
- return ws?.readyState === WebSocket.OPEN;
105
- }
106
-
107
  // Boot
108
- connect();
109
  window.ws = { send, request, on, off, isConnected, getReadyState };
 
50
  listeners.get('*')?.forEach(fn => fn({ type, ...data }));
51
  }
52
 
53
+
54
+
55
+ function scheduleReconnect() {
56
+ clearTimeout(reconnectTimer);
57
+ reconnectTimer = setTimeout(() => {
58
+ reconnectDelay = Math.min(reconnectDelay * 1.5, MAX_RECONNECT_DELAY);
59
+ connectWithPing();
60
+ }, reconnectDelay);
61
+ }
62
+
63
+ export function getReadyState() {
64
+ return ws?.readyState ?? WebSocket.CLOSED;
65
+ }
66
+
67
+ export function isConnected() {
68
+ return ws?.readyState === WebSocket.OPEN;
69
+ }
70
+
71
+ // ── Ping keepalive ────────────────────────────────────────────────────────
72
+ // Prevents the WebSocket from being closed by proxies/servers during long
73
+ // operations like image/video generation (which can take 30-60+ seconds).
74
+ let pingInterval = null;
75
+
76
+ function startPing() {
77
+ stopPing();
78
+ pingInterval = setInterval(() => {
79
+ if (ws?.readyState === WebSocket.OPEN) {
80
+ try { ws.send(JSON.stringify({ type: 'ping' })); } catch {}
81
+ }
82
+ }, 20000); // every 20 seconds
83
+ }
84
+
85
+ function stopPing() {
86
+ if (pingInterval) { clearInterval(pingInterval); pingInterval = null; }
87
+ }
88
+
89
+ // Patch connect to start/stop ping
90
+ function connectWithPing() {
91
  if (ws && (ws.readyState === WebSocket.CONNECTING || ws.readyState === WebSocket.OPEN)) return;
92
 
93
  ws = new WebSocket(WS_URL);
94
 
95
  ws.onopen = () => {
96
  reconnectDelay = RECONNECT_DELAY_MS;
97
+ startPing();
98
  emit('ws:connected', {});
99
  };
100
 
 
102
  let msg;
103
  try { msg = JSON.parse(event.data); } catch { return; }
104
  if (!msg?.type) return;
105
+ // Silently swallow pong responses
106
+ if (msg.type === 'pong') return;
107
 
 
108
  if (msg._reqId && pendingCallbacks.has(msg._reqId)) {
109
  const cb = pendingCallbacks.get(msg._reqId);
110
  pendingCallbacks.delete(msg._reqId);
 
118
  };
119
 
120
  ws.onclose = () => {
121
+ stopPing();
122
  emit('ws:disconnected', {});
123
  scheduleReconnect();
124
  };
 
128
  };
129
  }
130
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
131
  // Boot
132
+ connectWithPing();
133
  window.ws = { send, request, on, off, isConnected, getReadyState };