import { BinaryPacketTransport } from "./BinaryPackageTransport.js"; import { GatewayProxy } from "../GatewayProxy.js"; import { decodeMessage } from "./EncodeDecodeMessage.js"; export let encoder = new TextEncoder(); export let decoder = new TextDecoder(); export class WebsocketTransportClient extends BinaryPacketTransport { outgoingBuffer: ArrayBuffer[] = []; socket: any; connectCount = 0; //connected = false; constructor(public seed: string, ssl: boolean, employer: GatewayProxy) { super(employer); this.enableOutgoingHeartbeats = true; this.supressDatagrams = 2; this.connect(ssl); } get driver() { return this.employer.gateway.state.whole.transient.driver } get isClosed(): boolean { return this.driver.socketStatus(this.socket) != "open" } getUrl(ssl: boolean) { let ht = this.employer.hostTemplate; let url = `${ssl ? "wss" : "ws"}://${ht.networkHost}${location.port == "80" ? "" : `:${location.port}`}/children/${ht.nameTemplate}?reqno=${this.employer.gateway.nextReqno}&seed=${this.seed}&secret=${this.employer.secret}&tempAlias=${this.employer.gateway.alias.name}&roaming=${this.connectCount > 0}`; return url; } connect(ssl: boolean) { //let ht = this.employer.hostTemplate; let onMessage = (buffer: ArrayBuffer) => { return this.onIncommingPackage(buffer); } if (this.connectCount > 0) { console.warn("Reconnecting"); } let url = this.getUrl(ssl); // `${ssl ? "wss" : "ws"}://${ht.networkHost}${location.port == "80" ? "" : `:${location.port}`}/children/${ht.nameTemplate}?reqno=${this.employer.gateway.nextReqno}&seed=${this.seed}&secret=${this.employer.secret}&tempAlias=${this.employer.gateway.alias.name}&roaming=${this.connectCount > 0}`; //console.log("ABOUT TO CONNECT WEBSOCKET", url) this.employer.gateway.state.log("Connecting", url); this.socket = this.driver.createSocket(url, onMessage, (socket: any) => { // console.log("websocket connected.") this.employer.gateway.state.log("Connected", url); this.connected = true; this.connectCount++; }, () => { this.employer.gateway.state.log("Failed", url); }) this.restartHeartbeat(true, false, true); } async sendOutgoingPackage(message1: ArrayBuffer): Promise { let attempts = 0; let success: boolean; if (this.closing) { return; } // console.log(`want to send ${message1} for ${this.employer.gateway.alias}`); this.outgoingBuffer.push(message1); if (this.sending) { return; } this.sending = true; while (this.outgoingBuffer.length > 0) { let message = this.outgoingBuffer[0]; this.restartHeartbeat(false, false, false); do { attempts++; success = this.driver.socketSend(this.socket, message); if (!success) { if (this.connected) { this.employer.gateway.state.log("Socket fail", this.getUrl(false)); } console.warn("SOCKET SEND IS NOT WORKING"); console.log("ROAMING", attempts); this.clearHeartbeat(false); if (this.driver.socketStatus(this.socket) != "connecting") { console.log("connection attempt") this.connect(false); } let sl = Math.min((1 + attempts / 10) * (1 + attempts / 10), 5000); await sleep(Math.max(200, sl)); if (this.driver.socketStatus(this.socket) == "open") { success = this.driver.socketSend(this.socket, message); } else { //console.log(TheDriver.socketStatus(this.socket), "TRYING"); } } else { //console.log("SENT MESSAGE", decodeMessage(message)); } } while (!success && !this.closing); this.outgoingBuffer.shift(); this.sending = false; //console.log(`have sent ${JSON.stringify(decodeMessage(message))}`); } return; } } function sleep(ms: number) { console.log("SLEEP", ms); return new Promise(resolve => setTimeout(resolve, ms)); }