diff --git a/client/src/AdriftClient.ts b/client/src/AdriftClient.ts index 16d0dde..c969895 100644 --- a/client/src/AdriftClient.ts +++ b/client/src/AdriftClient.ts @@ -71,11 +71,21 @@ export class AdriftBareClient extends Client { let initalCloseHappened = false; ws.addEventListener("close", (e) => { if (!initalCloseHappened) { + // we can freely mess with the fake readyState here because there is no + // readyStateChange listener for WebSockets onReadyState(WebSocket.CONNECTING); e.stopImmediatePropagation(); initalCloseHappened = true; } }); + let initialErrorHappened = false; + ws.addEventListener("error", (e) => { + if (!initialErrorHappened) { + onReadyState(WebSocket.CONNECTING); + e.stopImmediatePropagation(); + initialErrorHappened = true; + } + }); let { send, close } = this.connection.wsconnect( remote, @@ -95,6 +105,7 @@ export class AdriftBareClient extends Client { ); }, (message: string) => { + console.log({ message }); ws.dispatchEvent(new ErrorEvent("error", { message })); } ); diff --git a/client/src/Connection.ts b/client/src/Connection.ts index 1219528..39ed606 100644 --- a/client/src/Connection.ts +++ b/client/src/Connection.ts @@ -12,6 +12,7 @@ import { } from "protocol"; type OpenWSMeta = { + onopen: () => void; onclose: (code: number, reason: string, wasClean: boolean) => void; onmessage: (data: any) => void; onerror: (message: string) => void; @@ -20,7 +21,7 @@ type OpenWSMeta = { export class Connection { requestCallbacks: Record = {}; openRequestStreams: Record> = {}; - openingSockets: Record void; rest: OpenWSMeta }> = {}; + openingSockets: Record = {}; openSockets: Record = {}; counter: number = 0; @@ -47,6 +48,7 @@ export class Connection { const msgText = () => new TextDecoder().decode(data.slice(cursor)); const msgJSON = () => JSON.parse(msgText()); + console.log({ requestType }); switch (requestType) { case S2CRequestTypes.HTTPResponseStart: const payload = msgJSON(); @@ -77,10 +79,10 @@ export class Connection { break; case S2CRequestTypes.WSOpen: - const { onopen, rest } = this.openingSockets[requestID]; + const socketMeta = this.openingSockets[requestID]; delete this.openingSockets[requestID]; - this.openSockets[requestID] = rest; - onopen(); + this.openSockets[requestID] = socketMeta; + setTimeout(() => socketMeta.onopen()); break; case S2CRequestTypes.WSDataText: { @@ -98,7 +100,8 @@ export class Connection { } case S2CRequestTypes.WSClose: { - const socketMeta = this.openSockets[requestID]; + const socketMeta = + this.openingSockets[requestID] || this.openSockets[requestID]; if (!socketMeta) return; const payload: WSClosePayload = msgJSON(); setTimeout(() => @@ -108,16 +111,18 @@ export class Connection { "wasClean" in payload ? Boolean(payload.wasClean) : false ) ); + delete this.openingSockets[requestID]; delete this.openSockets[requestID]; break; } case S2CRequestTypes.WSError: { - const socketMeta = this.openSockets[requestID]; + const socketMeta = + this.openingSockets[requestID] || this.openSockets[requestID]; if (!socketMeta) return; const payload: WSErrorPayload = msgJSON(); setTimeout(() => socketMeta.onerror(payload.message)); - setTimeout(() => socketMeta.onclose(1006, "", false)); + // don't delete socket entries because server will send close after this break; } @@ -187,7 +192,9 @@ export class Connection { // this can't be async, just call onopen when opened this.openingSockets[seq] = { onopen, - rest: { onmessage, onclose, onerror }, + onmessage, + onclose, + onerror, }; return { diff --git a/server/src/server.ts b/server/src/server.ts index 39b74e4..6bea84c 100644 --- a/server/src/server.ts +++ b/server/src/server.ts @@ -246,8 +246,8 @@ export class AdriftServer { const ws = (this.sockets[seq] = new WebSocket(payload.url)); ws.binaryType = "arraybuffer"; ws.onerror = (e) => { - // WSError implies close with code 1006, reason "" and wasClean false this.sendWSError(seq, { message: e.message }); + // onclose will be called after this with code 1006, reason "" and wasClean false }; ws.onopen = () => { this.sendWSOpen(seq);