{"version":3,"file":"H3Transport.mjs","sources":["../../../src/transport/H3Transport.ts"],"sourcesContent":["import { ITransport, ITransportEventMap } from \"./ITransport\";\nimport { encode, decode, Iterator } from '@colyseus/schema';\n\nexport class H3TransportTransport implements ITransport {\n    wt: WebTransport;\n    isOpen: boolean = false;\n\n    reader: ReadableStreamDefaultReader;\n    writer: WritableStreamDefaultWriter;\n\n    unreliableReader: ReadableStreamDefaultReader<Uint8Array>;\n    unreliableWriter: WritableStreamDefaultWriter<Uint8Array>;\n\n    private lengthPrefixBuffer = new Uint8Array(9); // 9 bytes is the maximum length of a length prefix\n\n    constructor(public events: ITransportEventMap) { }\n\n    public connect(url: string, options: any = {}) {\n        const wtOpts: WebTransportOptions = options.fingerprint && ({\n            // requireUnreliable: true,\n            // congestionControl: \"default\", // \"low-latency\" || \"throughput\"\n\n            serverCertificateHashes: [{\n                algorithm: 'sha-256',\n                value: new Uint8Array(options.fingerprint).buffer\n            }]\n        }) || undefined;\n\n        this.wt = new WebTransport(url, wtOpts);\n\n        this.wt.ready.then((e) => {\n            console.log(\"WebTransport ready!\", e)\n            this.isOpen = true;\n\n            this.unreliableReader = this.wt.datagrams.readable.getReader();\n            this.unreliableWriter = this.wt.datagrams.writable.getWriter();\n\n            const incomingBidi = this.wt.incomingBidirectionalStreams.getReader();\n            incomingBidi.read().then((stream) => {\n                this.reader = stream.value.readable.getReader();\n                this.writer = stream.value.writable.getWriter();\n\n                // immediately write room/sessionId for establishing the room connection\n                this.sendSeatReservation(options.room.roomId, options.sessionId, options.reconnectionToken);\n\n                // start reading incoming data\n                this.readIncomingData();\n                this.readIncomingUnreliableData();\n\n            }).catch((e) => {\n                console.error(\"failed to read incoming stream\", e);\n                console.error(\"TODO: close the connection\");\n            });\n\n            // this.events.onopen(e);\n        }).catch((e: WebTransportCloseInfo) => {\n            // this.events.onerror(e);\n            // this.events.onclose({ code: e.closeCode, reason: e.reason });\n            console.log(\"WebTransport not ready!\", e)\n            this._close();\n        });\n\n        this.wt.closed.then((e: WebTransportCloseInfo) => {\n            console.log(\"WebTransport closed w/ success\", e)\n            this.events.onclose({ code: e.closeCode, reason: e.reason });\n\n        }).catch((e: WebTransportCloseInfo) => {\n            console.log(\"WebTransport closed w/ error\", e)\n            this.events.onerror(e);\n            this.events.onclose({ code: e.closeCode, reason: e.reason });\n        }).finally(() => {\n            this._close();\n        });\n    }\n\n    public send(data: Buffer | Uint8Array): void {\n        const prefixLength = encode.number(this.lengthPrefixBuffer as any, data.length, { offset: 0 });\n        const dataWithPrefixedLength = new Uint8Array(prefixLength + data.length);\n        dataWithPrefixedLength.set(this.lengthPrefixBuffer.subarray(0, prefixLength), 0);\n        dataWithPrefixedLength.set(data, prefixLength);\n        this.writer.write(dataWithPrefixedLength);\n    }\n\n    public sendUnreliable(data: Buffer | Uint8Array): void {\n        const prefixLength = encode.number(this.lengthPrefixBuffer as any, data.length, { offset: 0 });\n        const dataWithPrefixedLength = new Uint8Array(prefixLength + data.length);\n        dataWithPrefixedLength.set(this.lengthPrefixBuffer.subarray(0, prefixLength), 0);\n        dataWithPrefixedLength.set(data, prefixLength);\n        this.unreliableWriter.write(dataWithPrefixedLength);\n    }\n\n    public close(code?: number, reason?: string) {\n        try {\n            this.wt.close({ closeCode: code, reason: reason });\n        } catch (e) {\n            console.error(e);\n        }\n    }\n\n    protected async readIncomingData() {\n        let result: ReadableStreamReadResult<Uint8Array>;\n\n        while (this.isOpen) {\n            try {\n                result = await this.reader.read();\n\n                //\n                // a single read may contain multiple messages\n                // each message is prefixed with its length\n                //\n\n                const messages = result.value;\n                const it: Iterator = { offset: 0 };\n                do {\n                    //\n                    // QUESTION: should we buffer the message in case it's not fully read?\n                    //\n\n                    const length = decode.number(messages as any, it);\n                    this.events.onmessage({ data: messages.subarray(it.offset, it.offset + length) });\n                    it.offset += length;\n                } while (it.offset < messages.length);\n\n            } catch (e) {\n                if (e.message.indexOf(\"session is closed\") === -1) {\n                    console.error(\"H3Transport: failed to read incoming data\", e);\n                }\n                break;\n            }\n\n            if (result.done) {\n                break;\n            }\n        }\n    }\n\n    protected async readIncomingUnreliableData() {\n        let result: ReadableStreamReadResult<Uint8Array>;\n\n        while (this.isOpen) {\n            try {\n                result = await this.unreliableReader.read();\n\n                //\n                // a single read may contain multiple messages\n                // each message is prefixed with its length\n                //\n\n                const messages = result.value;\n                const it: Iterator = { offset: 0 };\n                do {\n                    //\n                    // QUESTION: should we buffer the message in case it's not fully read?\n                    //\n\n                    const length = decode.number(messages as any, it);\n                    this.events.onmessage({ data: messages.subarray(it.offset, it.offset + length) });\n                    it.offset += length;\n                } while (it.offset < messages.length);\n\n            } catch (e) {\n                if (e.message.indexOf(\"session is closed\") === -1) {\n                    console.error(\"H3Transport: failed to read incoming data\", e);\n                }\n                break;\n            }\n\n            if (result.done) {\n                break;\n            }\n        }\n    }\n\n    protected sendSeatReservation (roomId: string, sessionId: string, reconnectionToken?: string) {\n        const it: Iterator = { offset: 0 };\n        const bytes: number[] = [];\n\n        encode.string(bytes, roomId, it);\n        encode.string(bytes, sessionId, it);\n\n        if (reconnectionToken) {\n            encode.string(bytes, reconnectionToken, it);\n        }\n\n        this.writer.write(new Uint8Array(bytes).buffer);\n    }\n\n    protected _close() {\n        this.isOpen = false;\n    }\n\n}\n"],"names":[],"mappings":"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"}