"use strict";
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
    if (k2 === undefined) k2 = k;
    var desc = Object.getOwnPropertyDescriptor(m, k);
    if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
      desc = { enumerable: true, get: function() { return m[k]; } };
    }
    Object.defineProperty(o, k2, desc);
}) : (function(o, m, k, k2) {
    if (k2 === undefined) k2 = k;
    o[k2] = m[k];
}));
var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
    Object.defineProperty(o, "default", { enumerable: true, value: v });
}) : function(o, v) {
    o["default"] = v;
});
var __importStar = (this && this.__importStar) || function (mod) {
    if (mod && mod.__esModule) return mod;
    var result = {};
    if (mod != null) for (var k in mod) if (k !== "default" && Object.prototype.hasOwnProperty.call(mod, k)) __createBinding(result, mod, k);
    __setModuleDefault(result, mod);
    return result;
};
var __importDefault = (this && this.__importDefault) || function (mod) {
    return (mod && mod.__esModule) ? mod : { "default": mod };
};
Object.defineProperty(exports, "__esModule", { value: true });
exports.NoiseServer = void 0;
const crypto = __importStar(require("@node-dlc/crypto"));
const assert_1 = __importDefault(require("assert"));
const events_1 = require("events");
const net_1 = require("net");
const noise_error_1 = require("./noise-error");
const noise_socket_1 = require("./noise-socket");
const noise_state_1 = require("./noise-state");
class NoiseServer extends events_1.EventEmitter {
    /**
     * NoiseServer is a TCP server that wraps socket instances
     * with the NoiseSocket class. This class is an event emitter
     * with the same interface as net.Server.
     *
     * The constructor take arguments that will be used by the
     * NoiseState.
     */
    constructor(opts, connListener) {
        super();
        // localSecret assertions
        assert_1.default.ok(Buffer.isBuffer(opts.ls), new noise_error_1.NoiseError('ls must be a buffer'));
        assert_1.default.ok(crypto.validPrivateKey(opts.ls), new noise_error_1.NoiseError('ls must be valid public key'));
        this.ls = opts.ls;
        // ephemeral secret factory
        assert_1.default.ok(!opts.esFactory || typeof opts.esFactory === 'function', new noise_error_1.NoiseError('esFactory must be a function'));
        this.esFactory = opts.esFactory || crypto.createPrivateKey;
        // construct and bind the server
        this._server = new net_1.Server();
        this._server.on('connection', this._onConnection.bind(this));
        this._server.on('error', (err) => this.emit('error', err));
        this._server.on('close', () => this.emit('close'));
        this._server.on('listening', () => this.emit('listening'));
        if (connListener)
            this.on('connection', connListener);
    }
    /**
     * Called when the socket receives a new socket connection.
     * Emits the `connection` event.
     */
    _onConnection(socket) {
        const ls = this.ls;
        const es = this.esFactory();
        const noiseState = new noise_state_1.NoiseState({ ls, es });
        const noiseSocket = new noise_socket_1.NoiseSocket({ socket, noiseState });
        this.emit('connection', noiseSocket);
    }
    /**
     * Returns the address the server is listeening on. If the server is
     * not listening, it will return undefined.
     */
    address() {
        return this._server.address();
    }
    /**
     * Stops the server from accepting new connections and keeps existing connections open.
     * This function is asynchronous, the server is fully closed when all connections are
     * ended and the server emits a `close` event. The optional `cb` event will be called
     * once the `close` event occurs.
     */
    close(cb) {
        this._server.close(cb);
    }
    /**
     * Asynchronously get the number of concurrent connections on the server. Works when sockets were sent to forks.
     */
    getConnections(cb) {
        this._server.getConnections(cb);
    }
    /**
     * Start a server listening for connections. This method is asyncrhonous,
     * once the server has started listening, the `listening` event will be
     * emitted.
     * @param callback Called when the server is listening. Automatically binds
     * the function to the `listening` event.
     */
    listen(opts, callback) {
        this._server.listen(opts, callback);
        return this;
    }
    /**
     * Indicates whether or not the server is listening for connections.
     */
    get listening() {
        return this._server.listening;
    }
    /**
     * Set this property to reject connections when the server's connection count gets high.
     */
    get maxConnections() {
        return this._server.maxConnections;
    }
    set maxConnections(val) {
        this._server.maxConnections = val;
    }
}
exports.NoiseServer = NoiseServer;
//# sourceMappingURL=noise-server.js.map