docker_socket.svelte.ts
1 // place files you want to import through the `$lib` alias in this folder. 2 import { ws_url } from './utils'; 3 import { wsStatus, type DockerInfo } from './types'; 4 5 export const ddata = $state({ 6 data: {} as DockerInfo, 7 status: wsStatus.INIT as wsStatus 8 }); 9 10 11 let d_ws: WebSocket | null = null; 12 let reconnectAttempt = 0; 13 let reconnectTimeout: number | null = null; 14 let isReconnecting = false; 15 16 function getReconnectDelay(): number { 17 // Backoff with a maximum of 10 seconds 18 return Math.min(2000 * (reconnectAttempt + 1), 10000); 19 } 20 21 function scheduleReconnect() { 22 if (isReconnecting) return; 23 24 if (ddata.data === null) return; // Don't flood the log with errors if docker is inaccessible 25 26 isReconnecting = true; 27 const delay = getReconnectDelay(); 28 29 //console.log(`Scheduling reconnect attempt in ${delay}ms`); 30 31 if (reconnectTimeout !== null) { 32 clearTimeout(reconnectTimeout); 33 } 34 35 reconnectTimeout = setTimeout(() => { 36 reconnectAttempt++;; 37 isReconnecting = false; 38 open_ws(); 39 }, delay) as unknown as number; 40 } 41 42 export function close_ws() { 43 if (d_ws !== null) { 44 d_ws.close(); 45 } 46 } 47 48 export function open_ws() { 49 // Clean up existing connection if any 50 if (d_ws !== null) { 51 try { 52 d_ws.onopen = null; 53 d_ws.onclose = null; 54 d_ws.onerror = null; 55 d_ws.onmessage = null; 56 d_ws.close(); 57 } catch (e) { 58 console.error("Error while closing existing WebSocket:", e); 59 } 60 d_ws = null; 61 } 62 63 try { 64 d_ws = new WebSocket(import.meta.env.PROD 65 ? ws_url('ws/d') 66 : "ws://localhost:30000/ws/d"); 67 } 68 catch (e) { 69 console.error("WebSocket connection failed: ", e); 70 ddata.status = wsStatus.ERROR; 71 scheduleReconnect(); 72 return; 73 } 74 75 d_ws.onopen = function (event) { 76 ddata.status = wsStatus.WAITING; 77 //console.log("WebSocket opened:", event); 78 reconnectAttempt = 0; 79 } 80 81 d_ws.onerror = function (event) { 82 ddata.status = wsStatus.ERROR; 83 console.error("WebSocket error observed:", event); 84 // We'll let onclose handle the reconnection 85 } 86 87 d_ws.onclose = function (event) { 88 ddata.status = wsStatus.DISCONNECTED; 89 //console.log("WebSocket closed:", event); 90 scheduleReconnect(); 91 } 92 93 d_ws.onmessage = async function (event) { 94 ddata.status = wsStatus.CONNECTED; 95 const compressedData = await event.data.arrayBuffer(); 96 const decompressStream = new DecompressionStream('gzip'); 97 const decompressedStream = new ReadableStream({ 98 start(controller) { 99 controller.enqueue(compressedData); 100 controller.close(); 101 } 102 }).pipeThrough(decompressStream); 103 104 const responseData = await new Response(decompressedStream).text(); 105 106 ddata.data = JSON.parse(responseData) as DockerInfo; 107 } 108 }