{"version":3,"sources":["src/common.speech/WebsocketMessageFormatter.ts"],"names":[],"mappings":"AAGA,OAAO,EACH,iBAAiB,EAGjB,0BAA0B,EAE1B,OAAO,EACP,mBAAmB,EACtB,MAAM,mBAAmB,CAAC;AAI3B,qBAAa,yBAA0B,YAAW,0BAA0B;IAEjE,mBAAmB,+DAsDzB;IAEM,qBAAqB,+DAsC3B;IAED,OAAO,CAAC,WAAW,CAYlB;IAED,OAAO,CAAC,YAAY,CAsBnB;IAED,OAAO,CAAC,mBAAmB,CAO1B;CACJ","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    Promise,\n    RawWebsocketMessage,\n} from \"../common/Exports\";\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}`);\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 headerInt8Array = new Int8Array(this.stringToArrayBuffer(headersString));\n\n                const payload = new ArrayBuffer(2 + headerInt8Array.byteLength + (content ? content.byteLength : 0));\n                const dataView = new DataView(payload);\n\n                dataView.setInt16(0, headerInt8Array.length);\n\n                for (let i = 0; i < headerInt8Array.byteLength; i++) {\n                    dataView.setInt8(2 + i, headerInt8Array[i]);\n                }\n\n                if (content) {\n                    const bodyInt8Array = new Int8Array(content);\n                    for (let i = 0; i < bodyInt8Array.byteLength; i++) {\n                        dataView.setInt8(2 + headerInt8Array.byteLength + i, bodyInt8Array[i]);\n                    }\n                }\n\n                deferral.resolve(new RawWebsocketMessage(MessageType.Binary, payload, message.id));\n            }\n        } catch (e) {\n            deferral.reject(`Error formatting the message. ${e}`);\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"]}