{"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.\r\n// Licensed under the MIT license.\r\n\r\nimport {\r\n    ConnectionMessage,\r\n    Deferred,\r\n    IStringDictionary,\r\n    IWebsocketMessageFormatter,\r\n    MessageType,\r\n    RawWebsocketMessage,\r\n} from \"../common/Exports.js\";\r\n\r\nconst CRLF: string = \"\\r\\n\";\r\n\r\nexport class WebsocketMessageFormatter implements IWebsocketMessageFormatter {\r\n\r\n    public toConnectionMessage(message: RawWebsocketMessage): Promise<ConnectionMessage> {\r\n        const deferral = new Deferred<ConnectionMessage>();\r\n\r\n        try {\r\n            if (message.messageType === MessageType.Text) {\r\n                const textMessage: string = message.textContent;\r\n                let headers: IStringDictionary<string> = {};\r\n                let body: string = null;\r\n\r\n                if (textMessage) {\r\n                    const headerBodySplit = textMessage.split(\"\\r\\n\\r\\n\");\r\n                    if (headerBodySplit && headerBodySplit.length > 0) {\r\n                        headers = this.parseHeaders(headerBodySplit[0]);\r\n                        if (headerBodySplit.length > 1) {\r\n                            body = headerBodySplit[1];\r\n                        }\r\n                    }\r\n                }\r\n\r\n                deferral.resolve(new ConnectionMessage(message.messageType, body, headers, message.id));\r\n            } else if (message.messageType === MessageType.Binary) {\r\n                const binaryMessage: ArrayBuffer = message.binaryContent;\r\n                let headers: IStringDictionary<string> = {};\r\n                let body: ArrayBuffer = null;\r\n\r\n                if (!binaryMessage || binaryMessage.byteLength < 2) {\r\n                    throw new Error(\"Invalid binary message format. Header length missing.\");\r\n                }\r\n\r\n                const dataView = new DataView(binaryMessage);\r\n                const headerLength = dataView.getInt16(0);\r\n\r\n                if (binaryMessage.byteLength < headerLength + 2) {\r\n                    throw new Error(\"Invalid binary message format. Header content missing.\");\r\n                }\r\n\r\n                let headersString = \"\";\r\n                for (let i = 0; i < headerLength; i++) {\r\n                    headersString += String.fromCharCode((dataView).getInt8(i + 2));\r\n                }\r\n\r\n                headers = this.parseHeaders(headersString);\r\n\r\n                if (binaryMessage.byteLength > headerLength + 2) {\r\n                    body = binaryMessage.slice(2 + headerLength);\r\n                }\r\n\r\n                deferral.resolve(new ConnectionMessage(message.messageType, body, headers, message.id));\r\n            }\r\n        } catch (e) {\r\n            deferral.reject(`Error formatting the message. Error: ${e as string}`);\r\n        }\r\n\r\n        return deferral.promise;\r\n    }\r\n\r\n    public fromConnectionMessage(message: ConnectionMessage): Promise<RawWebsocketMessage> {\r\n        const deferral = new Deferred<RawWebsocketMessage>();\r\n\r\n        try {\r\n            if (message.messageType === MessageType.Text) {\r\n                const payload = `${this.makeHeaders(message)}${CRLF}${message.textBody ? message.textBody : \"\"}`;\r\n\r\n                deferral.resolve(new RawWebsocketMessage(MessageType.Text, payload, message.id));\r\n\r\n            } else if (message.messageType === MessageType.Binary) {\r\n                const headersString = this.makeHeaders(message);\r\n                const content = message.binaryBody;\r\n\r\n                const headerBuffer = this.stringToArrayBuffer(headersString);\r\n                const headerInt8Array = new Int8Array(headerBuffer);\r\n                const headerLength = headerInt8Array.byteLength;\r\n\r\n                const payloadInt8Array = new Int8Array(2 + headerLength + (content ? content.byteLength : 0));\r\n                payloadInt8Array[0] = ((headerLength >> 8) & 0xff);\r\n                payloadInt8Array[1] = headerLength & 0xff;\r\n                payloadInt8Array.set(headerInt8Array, 2);\r\n\r\n                if (content) {\r\n                    const bodyInt8Array = new Int8Array(content);\r\n                    payloadInt8Array.set(bodyInt8Array, 2 + headerLength);\r\n                }\r\n\r\n                const payload: ArrayBuffer = payloadInt8Array.buffer;\r\n\r\n                deferral.resolve(new RawWebsocketMessage(MessageType.Binary, payload, message.id));\r\n            }\r\n        } catch (e) {\r\n            deferral.reject(`Error formatting the message. ${e as string}`);\r\n        }\r\n\r\n        return deferral.promise;\r\n    }\r\n\r\n    private makeHeaders(message: ConnectionMessage): string {\r\n        let headersString: string = \"\";\r\n\r\n        if (message.headers) {\r\n            for (const header in message.headers) {\r\n                if (header) {\r\n                    headersString += `${header}: ${message.headers[header]}${CRLF}`;\r\n                }\r\n            }\r\n        }\r\n\r\n        return headersString;\r\n    }\r\n\r\n    private parseHeaders(headersString: string): IStringDictionary<string> {\r\n        const headers: IStringDictionary<string> = {};\r\n\r\n        if (headersString) {\r\n            const headerMatches = headersString.match(/[^\\r\\n]+/g);\r\n            if (headers) {\r\n                for (const header of headerMatches) {\r\n                    if (header) {\r\n                        const separatorIndex = header.indexOf(\":\");\r\n                        const headerName = separatorIndex > 0 ? header.substr(0, separatorIndex).trim().toLowerCase() : header;\r\n                        const headerValue =\r\n                            separatorIndex > 0 && header.length > (separatorIndex + 1) ?\r\n                                header.substr(separatorIndex + 1).trim() :\r\n                                \"\";\r\n\r\n                        headers[headerName] = headerValue;\r\n                    }\r\n                }\r\n            }\r\n        }\r\n\r\n        return headers;\r\n    }\r\n\r\n    private stringToArrayBuffer(str: string): ArrayBuffer {\r\n        const buffer = new ArrayBuffer(str.length);\r\n        const view = new DataView(buffer);\r\n        for (let i = 0; i < str.length; i++) {\r\n            view.setUint8(i, str.charCodeAt(i));\r\n        }\r\n        return buffer;\r\n    }\r\n}\r\n"]}