"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.makeServer = void 0;
const http_1 = require("http");
const https_1 = require("https");
const ws_1 = require("ws");
const { name, version } = require('../../package.json');
const TOKEN_HEADER = 'x-eyes-universal-token';
const TOKEN = `${name}@${version}`;
async function makeServer(options = {}) {
    const { port = 21077, singleton = true, debug = false, portResolutionMode = 'next', cert, key } = options;
    const secure = Boolean(cert && key);
    const http = secure ? new https_1.Server({ cert, key }) : new http_1.Server();
    http.on('request', (request, response) => {
        if (request.url === '/handshake') {
            const token = debug ? request.headers[TOKEN_HEADER] : TOKEN;
            if (request.headers[TOKEN_HEADER] === token) {
                response.writeHead(200, { [TOKEN_HEADER]: token });
            }
            else {
                response.writeHead(400);
            }
            response.end();
        }
    });
    http.listen(port, 'localhost');
    return new Promise((resolve, reject) => {
        http.on('listening', () => {
            const ws = new ws_1.Server({ server: http, path: '/eyes', maxPayload: 256 * 1024 * 1024 });
            ws.on('close', () => http.close());
            resolve({ server: ws, port: http.address().port });
        });
        http.on('error', async (err) => {
            if (portResolutionMode !== 'lazy' && err.code === 'EADDRINUSE') {
                if (singleton && (await isHandshakable({ port, secure }))) {
                    return resolve({ port });
                }
                else {
                    return resolve(await makeServer({ ...options, port: portResolutionMode === 'next' ? port + 1 : 0 }));
                }
            }
            reject(err);
        });
    });
}
exports.makeServer = makeServer;
async function isHandshakable({ port, secure }) {
    const request = secure ? https_1.request : http_1.request;
    return new Promise(resolve => {
        const handshake = request(`${secure ? 'https' : 'http'}://localhost:${port}/handshake`, {
            headers: { [TOKEN_HEADER]: TOKEN },
        });
        handshake.on('response', ({ statusCode, headers }) => {
            resolve(statusCode === 200 && headers[TOKEN_HEADER] === TOKEN);
        });
        handshake.on('error', () => resolve(false));
        handshake.end();
    });
}
