()
| 100 | } |
| 101 | |
| 102 | async function connect(): Promise<void> { |
| 103 | if (closed) return; |
| 104 | if (socket) return; // already connected/connecting |
| 105 | |
| 106 | const client = getRpcClient(); |
| 107 | if (!client) { |
| 108 | scheduleReconnect(); |
| 109 | return; |
| 110 | } |
| 111 | const endpoint = await client.resolveEndpoint(); |
| 112 | // The generation may have bumped (dispose/reinit) while resolving — abandon. |
| 113 | if (closed || getRpcGeneration() !== connectGeneration) return; |
| 114 | if (!endpoint) { |
| 115 | scheduleReconnect(); |
| 116 | return; |
| 117 | } |
| 118 | |
| 119 | let ws: WebSocket; |
| 120 | try { |
| 121 | ws = new WebSocket(`ws://127.0.0.1:${endpoint.port}/ws`); |
| 122 | } catch { |
| 123 | scheduleReconnect(); |
| 124 | return; |
| 125 | } |
| 126 | socket = ws; |
| 127 | |
| 128 | ws.addEventListener("open", () => { |
| 129 | if (socket !== ws) return; |
| 130 | reconnectAttempt = 0; |
| 131 | sendHello(ws, endpoint.token); |
| 132 | }); |
| 133 | |
| 134 | ws.addEventListener("message", (event) => { |
| 135 | if (socket !== ws) return; |
| 136 | void handleSocketMessage(ws, String((event as MessageEvent).data)); |
| 137 | }); |
| 138 | |
| 139 | const onDown = () => { |
| 140 | if (socket === ws) { |
| 141 | socket = null; |
| 142 | helloedSession = null; |
| 143 | } |
| 144 | scheduleReconnect(); |
| 145 | }; |
| 146 | ws.addEventListener("close", onDown); |
| 147 | ws.addEventListener("error", onDown); |
| 148 | } |
| 149 | |
| 150 | function sendHello(ws: WebSocket, token: string | null): void { |
| 151 | const sessionId = opts?.getSessionId() ?? undefined; |
no test coverage detected