"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
const types_1 = require("@deepstream/types");
class WSSocketWrapper {
    constructor(socket, handshakeData, services, config, connectionEndpoint, isBinary) {
        this.socket = socket;
        this.handshakeData = handshakeData;
        this.services = services;
        this.config = config;
        this.connectionEndpoint = connectionEndpoint;
        this.isBinary = isBinary;
        this.isRemote = false;
        this.isClosed = false;
        this.uuid = Math.random();
        this.authCallback = null;
        this.authAttempts = 0;
        this.bufferedWrites = [];
        this.closeCallbacks = new Set();
        this.userId = null;
        this.serverData = null;
        this.clientData = null;
        this.bufferedWritesTotalByteSize = 0;
    }
    get isOpen() {
        return this.isClosed !== true;
    }
    invalidTypeReceived() {
        this.services.logger.error(types_1.EVENT.ERROR, `Received an invalid message type on ${this.uuid}`);
        this.destroy();
    }
    /**
     * Called by the connection endpoint to flush all buffered writes.
     * A buffered write is a write that is not a high priority, such as an ack
     * and can wait to be bundled into another message if necessary
     */
    flush() {
        if (this.bufferedWritesTotalByteSize !== 0) {
            this.bufferedWrites.forEach((bw) => this.writeMessage(this.socket, bw));
            this.bufferedWritesTotalByteSize = 0;
            this.bufferedWrites = [];
        }
    }
    /**
     * Sends a message based on the provided action and topic
     */
    sendMessage(message, allowBuffering = true) {
        this.services.monitoring.onMessageSend(message);
        this.sendBuiltMessage(this.getMessage(message), allowBuffering);
    }
    /**
     * Sends a message based on the provided action and topic
     */
    sendAckMessage(message, allowBuffering = true) {
        this.services.monitoring.onMessageSend(message);
        this.sendBuiltMessage(this.getAckMessage(message));
    }
    onMessage(messages) {
    }
    /**
     * Destroys the socket. Removes all deepstream specific
     * logic and closes the connection
     */
    destroy() {
        try {
            this.socket.close();
        }
        catch (e) {
            this.socket.end();
        }
    }
    close() {
        this.isClosed = true;
        delete this.authCallback;
        this.closeCallbacks.forEach((cb) => cb(this));
        this.services.logger.info(types_1.EVENT.CLIENT_DISCONNECTED, this.userId);
    }
    /**
     * Returns a map of parameters that were collected
     * during the initial http request that established the
     * connection
     */
    getHandshakeData() {
        return this.handshakeData;
    }
    onClose(callback) {
        this.closeCallbacks.add(callback);
    }
    removeOnClose(callback) {
        this.closeCallbacks.delete(callback);
    }
    sendBuiltMessage(message, buffer) {
        if (this.isOpen) {
            if (this.config.outgoingBufferTimeout === 0) {
                this.writeMessage(this.socket, message);
            }
            else if (!buffer) {
                this.flush();
                this.writeMessage(this.socket, message);
            }
            else {
                this.bufferedWritesTotalByteSize += message.length;
                this.bufferedWrites.push(message);
                if (this.bufferedWritesTotalByteSize > this.config.maxBufferByteSize) {
                    this.flush();
                }
                else {
                    this.connectionEndpoint.scheduleFlush(this);
                }
            }
        }
    }
    writeMessage(socket, message) {
        this.services.httpService.sendWebsocketMessage(socket, message, this.isBinary);
    }
}
exports.WSSocketWrapper = WSSocketWrapper;
//# sourceMappingURL=socket-wrapper.js.map