{"version":3,"sources":["src/common.speech/WebsocketMessageFormatter.ts"],"names":[],"mappings":"AAGA,OAAO,EACH,iBAAiB,EAGjB,0BAA0B,EAE1B,mBAAmB,EACtB,MAAM,sBAAsB,CAAC;AAI9B,qBAAa,yBAA0B,YAAW,0BAA0B;IAEjE,mBAAmB,CAAC,OAAO,EAAE,mBAAmB,GAAG,OAAO,CAAC,iBAAiB,CAAC;IAwD7E,qBAAqB,CAAC,OAAO,EAAE,iBAAiB,GAAG,OAAO,CAAC,mBAAmB,CAAC;IAsCtF,OAAO,CAAC,WAAW;IAcnB,OAAO,CAAC,YAAY;IAwBpB,OAAO,CAAC,mBAAmB;CAQ9B","file":"WebsocketMessageFormatter.d.ts","sourcesContent":["// Copyright (c) Microsoft Corporation. All rights reserved.\n// Licensed under the MIT license.\n\nimport {\n    ConnectionMessage,\n    Deferred,\n    IStringDictionary,\n    IWebsocketMessageFormatter,\n    MessageType,\n    RawWebsocketMessage,\n} from \"../common/Exports.js\";\n\nconst CRLF: string = \"\\r\\n\";\n\nexport class WebsocketMessageFormatter implements IWebsocketMessageFormatter {\n\n    public toConnectionMessage(message: RawWebsocketMessage): Promise<ConnectionMessage> {\n        const deferral = new Deferred<ConnectionMessage>();\n\n        try {\n            if (message.messageType === MessageType.Text) {\n                const textMessage: string = message.textContent;\n                let headers: IStringDictionary<string> = {};\n                let body: string = null;\n\n                if (textMessage) {\n                    const headerBodySplit = textMessage.split(\"\\r\\n\\r\\n\");\n                    if (headerBodySplit && headerBodySplit.length > 0) {\n                        headers = this.parseHeaders(headerBodySplit[0]);\n                        if (headerBodySplit.length > 1) {\n                            body = headerBodySplit[1];\n                        }\n                    }\n                }\n\n                deferral.resolve(new ConnectionMessage(message.messageType, body, headers, message.id));\n            } else if (message.messageType === MessageType.Binary) {\n                const binaryMessage: ArrayBuffer = message.binaryContent;\n                let headers: IStringDictionary<string> = {};\n                let body: ArrayBuffer = null;\n\n                if (!binaryMessage || binaryMessage.byteLength < 2) {\n                    throw new Error(\"Invalid binary message format. Header length missing.\");\n                }\n\n                const dataView = new DataView(binaryMessage);\n                const headerLength = dataView.getInt16(0);\n\n                if (binaryMessage.byteLength < headerLength + 2) {\n                    throw new Error(\"Invalid binary message format. Header content missing.\");\n                }\n\n                let headersString = \"\";\n                for (let i = 0; i < headerLength; i++) {\n                    headersString += String.fromCharCode((dataView).getInt8(i + 2));\n                }\n\n                headers = this.parseHeaders(headersString);\n\n                if (binaryMessage.byteLength > headerLength + 2) {\n                    body = binaryMessage.slice(2 + headerLength);\n                }\n\n                deferral.resolve(new ConnectionMessage(message.messageType, body, headers, message.id));\n            }\n        } catch (e) {\n            deferral.reject(`Error formatting the message. Error: ${e as string}`);\n        }\n\n        return deferral.promise;\n    }\n\n    public fromConnectionMessage(message: ConnectionMessage): Promise<RawWebsocketMessage> {\n        const deferral = new Deferred<RawWebsocketMessage>();\n\n        try {\n            if (message.messageType === MessageType.Text) {\n                const payload = `${this.makeHeaders(message)}${CRLF}${message.textBody ? message.textBody : \"\"}`;\n\n                deferral.resolve(new RawWebsocketMessage(MessageType.Text, payload, message.id));\n\n            } else if (message.messageType === MessageType.Binary) {\n                const headersString = this.makeHeaders(message);\n                const content = message.binaryBody;\n\n                const headerBuffer = this.stringToArrayBuffer(headersString);\n                const headerInt8Array = new Int8Array(headerBuffer);\n                const headerLength = headerInt8Array.byteLength;\n\n                const payloadInt8Array = new Int8Array(2 + headerLength + (content ? content.byteLength : 0));\n                payloadInt8Array[0] = ((headerLength >> 8) & 0xff);\n                payloadInt8Array[1] = headerLength & 0xff;\n                payloadInt8Array.set(headerInt8Array, 2);\n\n                if (content) {\n                    const bodyInt8Array = new Int8Array(content);\n                    payloadInt8Array.set(bodyInt8Array, 2 + headerLength);\n                }\n\n                const payload: ArrayBuffer = payloadInt8Array.buffer;\n\n                deferral.resolve(new RawWebsocketMessage(MessageType.Binary, payload, message.id));\n            }\n        } catch (e) {\n            deferral.reject(`Error formatting the message. ${e as string}`);\n        }\n\n        return deferral.promise;\n    }\n\n    private makeHeaders(message: ConnectionMessage): string {\n        let headersString: string = \"\";\n\n        if (message.headers) {\n            for (const header in message.headers) {\n                if (header) {\n                    headersString += `${header}: ${message.headers[header]}${CRLF}`;\n                }\n            }\n        }\n\n        return headersString;\n    }\n\n    private parseHeaders(headersString: string): IStringDictionary<string> {\n        const headers: IStringDictionary<string> = {};\n\n        if (headersString) {\n            const headerMatches = headersString.match(/[^\\r\\n]+/g);\n            if (headers) {\n                for (const header of headerMatches) {\n                    if (header) {\n                        const separatorIndex = header.indexOf(\":\");\n                        const headerName = separatorIndex > 0 ? header.substr(0, separatorIndex).trim().toLowerCase() : header;\n                        const headerValue =\n                            separatorIndex > 0 && header.length > (separatorIndex + 1) ?\n                                header.substr(separatorIndex + 1).trim() :\n                                \"\";\n\n                        headers[headerName] = headerValue;\n                    }\n                }\n            }\n        }\n\n        return headers;\n    }\n\n    private stringToArrayBuffer(str: string): ArrayBuffer {\n        const buffer = new ArrayBuffer(str.length);\n        const view = new DataView(buffer);\n        for (let i = 0; i < str.length; i++) {\n            view.setUint8(i, str.charCodeAt(i));\n        }\n        return buffer;\n    }\n}\n"]}