"use strict";
var __values = (this && this.__values) || function(o) {
    var s = typeof Symbol === "function" && Symbol.iterator, m = s && o[s], i = 0;
    if (m) return m.call(o);
    if (o && typeof o.length === "number") return {
        next: function () {
            if (o && i >= o.length) o = void 0;
            return { value: o && o[i++], done: !o };
        }
    };
    throw new TypeError(s ? "Object is not iterable." : "Symbol.iterator is not defined.");
};
Object.defineProperty(exports, "__esModule", { value: true });
exports.WebSocketManager = void 0;
var crypto_1 = require("crypto");
var msgpackr_1 = require("msgpackr");
var util_1 = require("util");
var ws_1 = require("ws");
var WebSocketManager = /** @class */ (function () {
    function WebSocketManager() {
        this._messageBuffers = new Map();
        this._batchingTimers = new Map();
        this._webSockets = new Map();
        this._chunkMetaFlag = '__chunked';
        this._textDecoder = new util_1.TextDecoder();
        this._wsSendDebug = false;
        this._wsSendLogThresholdMs = 2000;
        this._wsSendLogBytes = 2 * 1024 * 1024;
        this._wsSendLogBufferedBytes = 4 * 1024 * 1024;
        this._packedChunkMinBytes = 64 * 1024;
        this._sendQueues = new Map();
        this._sendQueueTimers = new Map();
        this._sendThrottleMs = 0;
        this._sendBackpressureBytes = 0;
        this._sendMaxBatchesPerTick = 10;
        this._aiWorkerDebug = false;
        this._wsBackpressureLogAt = new Map();
        this._wsBackpressureLogCooldownMs = 2000;
    }
    WebSocketManager.create = function (mainServer, maxMessageSize, messageDelay, chunkThresholdBytes, chunkSizeBytes) {
        if (maxMessageSize === void 0) { maxMessageSize = 256 * 1024; }
        if (messageDelay === void 0) { messageDelay = 25; }
        if (chunkThresholdBytes === void 0) { chunkThresholdBytes = 512 * 1024; }
        if (chunkSizeBytes === void 0) { chunkSizeBytes = 1024 * 1024; }
        var websocketManager = new WebSocketManager();
        websocketManager.initialize(mainServer, maxMessageSize, messageDelay, chunkThresholdBytes, chunkSizeBytes);
        return websocketManager;
    };
    WebSocketManager.prototype.initialize = function (mainServer, maxMessageSize, messageDelay, chunkThresholdBytes, chunkSizeBytes) {
        if (maxMessageSize === void 0) { maxMessageSize = 20480; }
        if (messageDelay === void 0) { messageDelay = 25; }
        if (chunkThresholdBytes === void 0) { chunkThresholdBytes = 3 * 1024 * 1024; }
        if (chunkSizeBytes === void 0) { chunkSizeBytes = 4 * 1024 * 1024; }
        this._mainServer = mainServer;
        this._maxMessageSize = this.parsePositiveInt(process.env.WS_MAX_MESSAGE_SIZE_BYTES, maxMessageSize);
        this._messageDelay = messageDelay;
        this._chunkingEnabled = this.parseBoolean(process.env.WS_CHUNKING_ENABLED, true);
        this._chunkThresholdBytes = this.parsePositiveInt(process.env.WS_CHUNK_THRESHOLD_BYTES, chunkThresholdBytes);
        this._chunkSizeBytes = this.parsePositiveInt(process.env.WS_CHUNK_SIZE_BYTES, chunkSizeBytes);
        this._wsSendDebug = this.parseDebugFlag(process.env.WS_SEND_DEBUG);
        this._aiWorkerDebug = this.parseDebugFlag(process.env.AI_ASSISTANT_WORKER_DEBUG);
        this._wsSendLogThresholdMs = this.parsePositiveInt(process.env.WS_SEND_LOG_THRESHOLD_MS, this._wsSendLogThresholdMs);
        this._wsSendLogBytes = this.parsePositiveInt(process.env.WS_SEND_LOG_BYTES, this._wsSendLogBytes);
        this._wsSendLogBufferedBytes = this.parsePositiveInt(process.env.WS_SEND_LOG_BUFFERED_BYTES, this._wsSendLogBufferedBytes);
        var packedChunkFallback = Math.min(this._chunkThresholdBytes, this._packedChunkMinBytes);
        var packedChunkRaw = process.env.WS_PACKED_CHUNK_MIN_BYTES;
        this._packedChunkMinBytes = packedChunkRaw === '0'
            ? 0
            : this.parsePositiveInt(packedChunkRaw, packedChunkFallback);
        this._sendThrottleMs = this.parsePositiveInt(process.env.WS_SEND_THROTTLE_MS, this._sendThrottleMs);
        var backpressureRaw = process.env.WS_SEND_BACKPRESSURE_BYTES;
        if (backpressureRaw === '0') {
            this._sendBackpressureBytes = 0;
        }
        else if (backpressureRaw === undefined || backpressureRaw === null || backpressureRaw === '') {
            this._sendBackpressureBytes = this._wsSendLogBufferedBytes;
        }
        else {
            this._sendBackpressureBytes = this.parsePositiveInt(backpressureRaw, this._sendBackpressureBytes);
        }
        this._sendMaxBatchesPerTick = this.parsePositiveInt(process.env.WS_SEND_MAX_BATCHES_PER_TICK, this._sendMaxBatchesPerTick);
    };
    WebSocketManager.prototype.parseDebugFlag = function (value) {
        if (value === true) {
            return true;
        }
        if (value === false || value === null || value === undefined) {
            return false;
        }
        if (typeof value === 'number') {
            return value === 1;
        }
        if (typeof value === 'string') {
            var normalized = value.trim().toLowerCase();
            return ['1', 'true', 'yes', 'y', 'on'].includes(normalized);
        }
        return false;
    };
    WebSocketManager.prototype.parseBoolean = function (value, fallback) {
        if (value === null || value === undefined) {
            return fallback;
        }
        return this.parseDebugFlag(value);
    };
    WebSocketManager.prototype.parsePositiveInt = function (value, fallback) {
        var parsed = parseInt(value !== null && value !== void 0 ? value : '', 10);
        if (Number.isNaN(parsed) || parsed <= 0) {
            return fallback;
        }
        return parsed;
    };
    WebSocketManager.prototype.isBackpressured = function (ws) {
        if (this._sendBackpressureBytes <= 0) {
            return false;
        }
        var buffered = this.getBufferedAmount(ws);
        return buffered !== null && buffered >= this._sendBackpressureBytes;
    };
    WebSocketManager.prototype.shouldQueueSend = function (ws) {
        return this._sendThrottleMs > 0 || this.isBackpressured(ws);
    };
    WebSocketManager.prototype.maybeLogBackpressure = function (ws, batchSize) {
        var _a, _b;
        if (!this._aiWorkerDebug) {
            return;
        }
        var wsId = ws ? ws['id_socket'] : null;
        if (!wsId) {
            return;
        }
        var now = Date.now();
        var last = this._wsBackpressureLogAt.get(wsId) || 0;
        if (now - last < this._wsBackpressureLogCooldownMs) {
            return;
        }
        this._wsBackpressureLogAt.set(wsId, now);
        var bufferedAmount = this.getBufferedAmount(ws);
        var queueDepth = (_b = (_a = this._sendQueues.get(wsId)) === null || _a === void 0 ? void 0 : _a.length) !== null && _b !== void 0 ? _b : 0;
        var backpressured = this.isBackpressured(ws);
        var reason = backpressured ? 'backpressure' : (this._sendThrottleMs > 0 ? 'throttle' : 'queued');
        console.warn(new Date(), '[AI Worker Debug] wsSendQueued', {
            reason: reason,
            id_ws: wsId,
            user: ws ? ws['user'] : null,
            batchSize: batchSize,
            queueDepth: queueDepth,
            bufferedAmount: bufferedAmount,
            backpressureBytes: this._sendBackpressureBytes,
            sendThrottleMs: this._sendThrottleMs
        });
    };
    WebSocketManager.prototype.getQueueDelayMs = function (ws) {
        if (this._sendThrottleMs > 0) {
            return this._sendThrottleMs;
        }
        if (this.isBackpressured(ws)) {
            return 25;
        }
        return 0;
    };
    WebSocketManager.prototype.enqueueSend = function (ws, batch) {
        if (!batch || !batch.length) {
            return;
        }
        var wsId = ws['id_socket'];
        var queue = this._sendQueues.get(wsId);
        if (!queue) {
            queue = [];
            this._sendQueues.set(wsId, queue);
        }
        queue.push(batch);
        this.maybeLogBackpressure(ws, batch.length);
        this.scheduleSendDrain(ws);
    };
    WebSocketManager.prototype.scheduleSendDrain = function (ws) {
        var _this = this;
        var wsId = ws['id_socket'];
        if (this._sendQueueTimers.has(wsId)) {
            return;
        }
        var delay = this.getQueueDelayMs(ws);
        var timer = setTimeout(function () {
            _this._sendQueueTimers.delete(wsId);
            _this.drainSendQueue(ws);
        }, delay);
        this._sendQueueTimers.set(wsId, timer);
    };
    WebSocketManager.prototype.drainSendQueue = function (ws) {
        var wsId = ws['id_socket'];
        var queue = this._sendQueues.get(wsId);
        if (!queue || !queue.length) {
            this._sendQueues.delete(wsId);
            return;
        }
        var sent = 0;
        while (queue.length > 0 && sent < this._sendMaxBatchesPerTick && !this.isBackpressured(ws)) {
            var batch = queue.shift();
            if (batch && batch.length) {
                this.transmitBatchNow(ws, batch);
            }
            sent += 1;
        }
        if (queue.length > 0) {
            this.scheduleSendDrain(ws);
        }
        else {
            this._sendQueues.delete(wsId);
        }
    };
    WebSocketManager.prototype.scheduleNextChunk = function (ws, next) {
        var _a, _b;
        var wsId = ws['id_socket'];
        var queueSize = (_b = (_a = this._sendQueues.get(wsId)) === null || _a === void 0 ? void 0 : _a.length) !== null && _b !== void 0 ? _b : 0;
        var baseDelay = this.getQueueDelayMs(ws);
        var delay = queueSize >= this._sendMaxBatchesPerTick ? Math.max(baseDelay, 25) : baseDelay;
        if (delay > 0) {
            setTimeout(next, delay);
        }
        else {
            setImmediate(next);
        }
    };
    WebSocketManager.prototype.shouldLogSend = function (durationMs, totalBytes, bufferedAmount) {
        if (this._wsSendDebug) {
            return true;
        }
        if (durationMs !== null && durationMs >= this._wsSendLogThresholdMs) {
            return true;
        }
        if (totalBytes !== null && totalBytes >= this._wsSendLogBytes) {
            return true;
        }
        if (bufferedAmount !== null && bufferedAmount >= this._wsSendLogBufferedBytes) {
            return true;
        }
        return false;
    };
    WebSocketManager.prototype.getBufferedAmount = function (ws) {
        if (!ws) {
            return null;
        }
        var buffered = ws.bufferedAmount;
        return typeof buffered === 'number' ? buffered : null;
    };
    WebSocketManager.prototype.logWsSend = function (event, ws, details) {
        if (!this._wsSendDebug) {
            return;
        }
        var payload = Object.assign({
            ts: new Date().toISOString(),
            event: event,
            id_ws: ws ? ws['id_socket'] : null,
            user: ws ? ws['user'] : null
        }, details);
        console.log(JSON.stringify(payload));
    };
    WebSocketManager.prototype.addWebSocket = function (ws) {
        var wsId = ws['id_socket'];
        this._webSockets.set(wsId, ws);
    };
    WebSocketManager.prototype.isSocketActive = function (ws) {
        if (!ws) {
            return false;
        }
        return ws.readyState === ws_1.WebSocket.OPEN || ws.readyState === ws_1.WebSocket.CONNECTING;
    };
    WebSocketManager.prototype.removeWebSocket = function (ws) {
        var wsId = ws['id_socket'];
        this._webSockets.delete(wsId);
        this._wsBackpressureLogAt.delete(wsId);
        this.closeConnection(ws);
    };
    WebSocketManager.prototype.getWebSocket = function (id_socket) {
        return this._webSockets.get(id_socket);
    };
    WebSocketManager.prototype.getAllWebSockets = function () {
        return Array.from(this._webSockets.values());
    };
    WebSocketManager.prototype.getActiveWebSocketCount = function () {
        var _this = this;
        return this.getAllWebSockets().filter(function (ws) { return _this.isSocketActive(ws); }).length;
    };
    WebSocketManager.prototype.getUserWebSockets = function (id_user) {
        var _this = this;
        var targetUser = "".concat(id_user || '').trim();
        if (!targetUser) {
            return [];
        }
        return this.getAllWebSockets().filter(function (ws) { return _this.isSocketActive(ws) && "".concat((ws === null || ws === void 0 ? void 0 : ws['id_user']) || '').trim() === targetUser; });
    };
    WebSocketManager.prototype.send = function (ws, data) {
        var _this = this;
        var wsId = ws['id_socket'];
        if (!this._messageBuffers.has(wsId)) {
            this._messageBuffers.set(wsId, []);
        }
        if (typeof data === 'string') {
            if (ws && ws.readyState === ws_1.WebSocket.OPEN) {
                ws.send(data, function (error) {
                    if (error) {
                        _this.handleSendError(ws, error);
                    }
                });
            }
            return;
        }
        else {
            // Handle string messages like 'ping' or 'pong'
            var chunkContext = this.prepareChunkContext(data);
            if (chunkContext) {
                this.flushMessages(ws);
                this.sendChunkSequence(ws, data, chunkContext);
                return;
            }
            this._messageBuffers.get(wsId).push(data);
        }
        if (!this._batchingTimers.has(wsId)) {
            // Set a timer to send the batch after a short delay
            var timer = setTimeout(function () {
                _this.flushMessages(ws);
            }, this._messageDelay);
            this._batchingTimers.set(wsId, timer);
        }
    };
    WebSocketManager.prototype.sendPackedBuffer = function (ws, messageId, hasError, packedData, encoding, options) {
        var _a;
        var _this = this;
        if (encoding === void 0) { encoding = 'msgpack'; }
        if (options === void 0) { options = {}; }
        if (!ws || ws.readyState !== ws_1.WebSocket.OPEN || !packedData || !packedData.byteLength) {
            return;
        }
        var passThrough = !!options.passThrough;
        var preferPackedChunk = this._packedChunkMinBytes > 0 && packedData.byteLength >= this._packedChunkMinBytes;
        var canChunk = this._chunkingEnabled;
        var shouldChunk = passThrough
            ? canChunk
            : (canChunk && (packedData.byteLength > this._chunkThresholdBytes || preferPackedChunk));
        if (!shouldChunk) {
            var decoded = this.decodePackedPayload(packedData, encoding);
            if (decoded !== undefined) {
                this.send(ws, { messageId: messageId, hasError: hasError, data: decoded });
                return;
            }
            if (!this._chunkingEnabled) {
                return;
            }
        }
        if (!canChunk) {
            return;
        }
        var sendStartMs = Date.now();
        var bufferedStart = this.getBufferedAmount(ws);
        var chunkId = this.generateChunkId();
        var totalChunks = Math.max(1, Math.ceil(packedData.byteLength / this._chunkSizeBytes));
        var chunkSize = this._chunkSizeBytes;
        if (this.shouldLogSend(null, packedData.byteLength, bufferedStart)) {
            this.logWsSend('wsSendStart', ws, {
                messageId: messageId,
                totalBytes: packedData.byteLength,
                totalChunks: totalChunks,
                chunkSize: chunkSize,
                encoding: encoding,
                bufferedAmount: bufferedStart
            });
        }
        // Flush any buffered messages so the chunk stream starts immediately.
        this.flushMessages(ws);
        var startMessage = {
            messageId: messageId,
            hasError: hasError,
            data: (_a = {},
                _a[this._chunkMetaFlag] = true,
                _a.chunkId = chunkId,
                _a.chunkStatus = 'start',
                _a.totalChunks = totalChunks,
                _a.totalBytes = packedData.byteLength,
                _a.chunkSize = chunkSize,
                _a.encoding = encoding,
                _a)
        };
        this.transmitBatch(ws, [startMessage]);
        var sendChunk = function (index) {
            var _a, _b;
            if (!ws || ws.readyState !== ws_1.WebSocket.OPEN) {
                return;
            }
            if (index >= totalChunks) {
                var endMessage = {
                    messageId: messageId,
                    hasError: hasError,
                    data: (_a = {},
                        _a[_this._chunkMetaFlag] = true,
                        _a.chunkId = chunkId,
                        _a.chunkStatus = 'end',
                        _a)
                };
                _this.transmitBatch(ws, [endMessage]);
                var durationMs = Date.now() - sendStartMs;
                var bufferedEnd = _this.getBufferedAmount(ws);
                if (_this.shouldLogSend(durationMs, packedData.byteLength, bufferedEnd)) {
                    _this.logWsSend('wsSendEnd', ws, {
                        messageId: messageId,
                        totalBytes: packedData.byteLength,
                        totalChunks: totalChunks,
                        chunkSize: chunkSize,
                        encoding: encoding,
                        durationMs: durationMs,
                        bufferedAmount: bufferedEnd
                    });
                }
                return;
            }
            var start = index * chunkSize;
            var end = Math.min(packedData.byteLength, start + chunkSize);
            var slice = packedData.subarray(start, end);
            var payload = encoding === 'msgpack' ? slice : _this.toBase64(slice);
            var chunkMessage = {
                messageId: messageId,
                hasError: hasError,
                data: (_b = {},
                    _b[_this._chunkMetaFlag] = true,
                    _b.chunkId = chunkId,
                    _b.chunkStatus = 'chunk',
                    _b.chunkIndex = index,
                    _b.payload = payload,
                    _b.encoding = encoding,
                    _b)
            };
            _this.transmitBatch(ws, [chunkMessage]);
            _this.scheduleNextChunk(ws, function () { return sendChunk(index + 1); });
        };
        this.scheduleNextChunk(ws, function () { return sendChunk(0); });
    };
    WebSocketManager.prototype.flushMessages = function (ws) {
        var wsId = ws['id_socket'];
        var messages = this._messageBuffers.get(wsId);
        if (messages && messages.length > 0) {
            // Combine messages into one payload
            this.transmitBatch(ws, messages);
            this._messageBuffers.delete(wsId);
            clearTimeout(this._batchingTimers.get(wsId));
            this._batchingTimers.delete(wsId);
        }
    };
    WebSocketManager.prototype.sendMessagesInChunksBinary = function (ws, messages) {
        var e_1, _a;
        var _this = this;
        var chunk = [];
        var chunkSize = 0;
        try {
            for (var messages_1 = __values(messages), messages_1_1 = messages_1.next(); !messages_1_1.done; messages_1_1 = messages_1.next()) {
                var message = messages_1_1.value;
                var packedMessage = Buffer.from((0, msgpackr_1.pack)([message]));
                var messageSize = packedMessage.byteLength;
                if (chunkSize + messageSize > this._maxMessageSize) {
                    var packedChunk = Buffer.from((0, msgpackr_1.pack)(chunk));
                    ws.send(packedChunk, function (error) {
                        if (error) {
                            _this.handleSendError(ws, error);
                        }
                    });
                    chunk = [message];
                    chunkSize = messageSize;
                }
                else {
                    chunk.push(message);
                    chunkSize += messageSize;
                }
            }
        }
        catch (e_1_1) { e_1 = { error: e_1_1 }; }
        finally {
            try {
                if (messages_1_1 && !messages_1_1.done && (_a = messages_1.return)) _a.call(messages_1);
            }
            finally { if (e_1) throw e_1.error; }
        }
        if (chunk.length > 0) {
            var packedChunk = Buffer.from((0, msgpackr_1.pack)(chunk));
            ws.send(packedChunk, function (error) {
                if (error) {
                    _this.handleSendError(ws, error);
                }
            });
        }
    };
    WebSocketManager.prototype.handleSendError = function (ws, error) {
        if (this._mainServer.getSubscriptionManager()) {
            // Handle send error, e.g., unsubscribe, close connection
            if (this._mainServer.getSubscriptionManager().getEnableDebug()) {
                console.log(new Date(), 'WebSocketManager', 'Unsub WS', ws['user'], ws['id_socket'], error);
            }
            this._mainServer.getSubscriptionManager().unsubscribeAll(ws);
            this.removeWebSocket(ws);
        }
    };
    WebSocketManager.prototype.closeConnection = function (ws) {
        ws.close();
        var wsId = ws['id_socket'];
        // Clean up buffers and timers
        this._messageBuffers.delete(wsId);
        if (this._batchingTimers.has(wsId)) {
            clearTimeout(this._batchingTimers.get(wsId));
            this._batchingTimers.delete(wsId);
        }
        this._sendQueues.delete(wsId);
        if (this._sendQueueTimers.has(wsId)) {
            clearTimeout(this._sendQueueTimers.get(wsId));
            this._sendQueueTimers.delete(wsId);
        }
        this._wsBackpressureLogAt.delete(wsId);
        process.nextTick(function () {
            if ([ws_1.WebSocket.OPEN, ws_1.WebSocket.CLOSING].includes(ws.readyState)) {
                // Socket still hangs, hard close
                ws.terminate();
            }
        });
    };
    WebSocketManager.prototype.prepareChunkContext = function (message) {
        var _a;
        if (!this._chunkingEnabled) {
            return null;
        }
        if (!message || message.hasError) {
            return null;
        }
        var data = message.data;
        if (data === undefined || data === null) {
            return null;
        }
        try {
            var packed = Buffer.from((0, msgpackr_1.pack)(data));
            if (packed.byteLength > this._chunkThresholdBytes) {
                return { buffer: packed, encoding: 'msgpack' };
            }
        }
        catch (err) {
            if ((_a = this._mainServer.getSubscriptionManager()) === null || _a === void 0 ? void 0 : _a.getEnableDebug()) {
                console.log(new Date(), 'WebSocketManager', 'Chunking pack failed', (err === null || err === void 0 ? void 0 : err.message) || err);
            }
        }
        return null;
    };
    WebSocketManager.prototype.decodePackedPayload = function (packedData, encoding) {
        var _a;
        try {
            var source = packedData;
            if (encoding === 'msgpack') {
                return (0, msgpackr_1.unpack)(source);
            }
            var text = this._textDecoder.decode(source);
            return JSON.parse(text);
        }
        catch (err) {
            if ((_a = this._mainServer.getSubscriptionManager()) === null || _a === void 0 ? void 0 : _a.getEnableDebug()) {
                console.log(new Date(), 'WebSocketManager', 'Packed decode failed', (err === null || err === void 0 ? void 0 : err.message) || err);
            }
            return undefined;
        }
    };
    WebSocketManager.prototype.sendChunkSequence = function (ws, original, chunkContext) {
        var _a;
        var _this = this;
        var chunkId = this.generateChunkId();
        var totalChunks = Math.ceil(chunkContext.buffer.byteLength / this._chunkSizeBytes);
        var startMessage = {
            messageId: original.messageId,
            hasError: original.hasError,
            data: (_a = {},
                _a[this._chunkMetaFlag] = true,
                _a.chunkId = chunkId,
                _a.chunkStatus = 'start',
                _a.totalChunks = totalChunks,
                _a.totalBytes = chunkContext.buffer.byteLength,
                _a.chunkSize = this._chunkSizeBytes,
                _a.encoding = chunkContext.encoding,
                _a)
        };
        this.transmitBatch(ws, [startMessage]);
        var sendChunk = function (index) {
            var _a, _b;
            if (!ws || ws.readyState !== ws_1.WebSocket.OPEN) {
                return;
            }
            if (index >= totalChunks) {
                var endMessage = {
                    messageId: original.messageId,
                    hasError: original.hasError,
                    data: (_a = {},
                        _a[_this._chunkMetaFlag] = true,
                        _a.chunkId = chunkId,
                        _a.chunkStatus = 'end',
                        _a)
                };
                _this.transmitBatch(ws, [endMessage]);
                return;
            }
            var start = index * _this._chunkSizeBytes;
            var end = Math.min(chunkContext.buffer.byteLength, start + _this._chunkSizeBytes);
            var slice = chunkContext.buffer.subarray(start, end);
            var chunkPayload = slice;
            var chunkMessage = {
                messageId: original.messageId,
                hasError: original.hasError,
                data: (_b = {},
                    _b[_this._chunkMetaFlag] = true,
                    _b.chunkId = chunkId,
                    _b.chunkStatus = 'chunk',
                    _b.chunkIndex = index,
                    _b.payload = chunkPayload,
                    _b.encoding = chunkContext.encoding,
                    _b)
            };
            _this.transmitBatch(ws, [chunkMessage]);
            _this.scheduleNextChunk(ws, function () { return sendChunk(index + 1); });
        };
        this.scheduleNextChunk(ws, function () { return sendChunk(0); });
    };
    WebSocketManager.prototype.transmitBatch = function (ws, batch) {
        if (!batch || !batch.length) {
            return;
        }
        var wsId = ws['id_socket'];
        if (this.shouldQueueSend(ws) || this._sendQueues.has(wsId)) {
            this.enqueueSend(ws, batch);
            return;
        }
        this.transmitBatchNow(ws, batch);
    };
    WebSocketManager.prototype.transmitBatchNow = function (ws, batch) {
        var _this = this;
        var _a;
        if (!batch || !batch.length) {
            return;
        }
        var isChunkEnvelope = batch.length === 1 && ((_a = batch[0]) === null || _a === void 0 ? void 0 : _a.data) && typeof batch[0].data === 'object' && batch[0].data[this._chunkMetaFlag];
        var packedData = Buffer.from((0, msgpackr_1.pack)(batch));
        var dataSize = packedData.byteLength;
        var bufferedAmount = this.getBufferedAmount(ws);
        if (!isChunkEnvelope && dataSize > this._maxMessageSize) {
            this.sendMessagesInChunksBinary(ws, batch);
        }
        else {
            ws.send(packedData, function (error) {
                if (error) {
                    _this.handleSendError(ws, error);
                }
            });
        }
        if (this.shouldLogSend(null, dataSize, bufferedAmount)) {
            this.logWsSend('wsBatchSend', ws, {
                batchSize: batch.length,
                dataSize: dataSize,
                isChunkEnvelope: isChunkEnvelope,
                bufferedAmount: bufferedAmount
            });
        }
    };
    WebSocketManager.prototype.generateChunkId = function () {
        return (0, crypto_1.randomBytes)(8).toString('hex');
    };
    WebSocketManager.prototype.toBase64 = function (data) {
        if (Buffer.isBuffer(data)) {
            return data.toString('base64');
        }
        return Buffer.from(data).toString('base64');
    };
    return WebSocketManager;
}());
exports.WebSocketManager = WebSocketManager;

//# sourceMappingURL=websocket.manager.js.map
