"use strict";
var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
    return new (P || (P = Promise))(function (resolve, reject) {
        function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
        function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
        function step(result) { result.done ? resolve(result.value) : new P(function (resolve) { resolve(result.value); }).then(fulfilled, rejected); }
        step((generator = generator.apply(thisArg, _arguments || [])).next());
    });
};
var __importDefault = (this && this.__importDefault) || function (mod) {
    return (mod && mod.__esModule) ? mod : { "default": mod };
};
Object.defineProperty(exports, "__esModule", { value: true });
const get_port_1 = __importDefault(require("get-port"));
const koa_compose_1 = __importDefault(require("koa-compose"));
const lru_cache_1 = __importDefault(require("lru-cache"));
const os_1 = __importDefault(require("os"));
const path_1 = __importDefault(require("path"));
const impl_1 = require("./impl");
const servers_1 = require("./servers");
class ProxyServer {
    constructor() {
        this.middleware = [];
    }
    static create() {
        return __awaiter(this, void 0, void 0, function* () {
            const proxyServer = new ProxyServer();
            yield proxyServer.init();
            return proxyServer;
        });
    }
    listen(port = 8001) {
        return __awaiter(this, void 0, void 0, function* () {
            const handlerMiddleware = koa_compose_1.default(this.middleware.concat([
                (ctx) => __awaiter(this, void 0, void 0, function* () {
                    yield this.forwarder.forward(ctx);
                }),
            ]));
            this.handlers.connect.httpPort = port;
            this.handlers.http.setMiddleware(handlerMiddleware);
            this.handlers.upgrade.setMiddleware(koa_compose_1.default(this.middleware));
            this.httpProxyServer.listen(port);
            this.httpsProxyServer.listen(this.httpsPort);
        });
    }
    use(fn) {
        if (typeof fn !== 'function') {
            throw new TypeError('middleware must be a function!');
        }
        this.middleware.push(fn);
        return this;
    }
    init() {
        return __awaiter(this, void 0, void 0, function* () {
            this.forwarder = new impl_1.Forwarder();
            this.cache = lru_cache_1.default({
                max: 500,
                maxAge: 1000 * 60 * 60,
            });
            const certStorage = new impl_1.CertificateStorage(path_1.default.join(os_1.default.homedir(), '.front-end-proxy/certificate'));
            const certService = new impl_1.CertificateService(certStorage, this.cache);
            this.cert = {
                service: certService,
                storage: certStorage,
            };
            this.httpsPort = yield get_port_1.default({ port: 8989 });
            this.handlers = {
                connect: new impl_1.ConnectHandler(this.httpsPort, this.cache),
                http: new impl_1.HttpHandler(),
                upgrade: new impl_1.UpgradeHandler(),
            };
            this.httpProxyServer = new servers_1.HttpServer();
            this.httpsProxyServer = yield servers_1.HttpsServer.create(this.cert.service);
            this.httpProxyServer.setHttpHandler(this.handlers.http);
            this.httpProxyServer.setConnectHandler(this.handlers.connect);
            this.httpProxyServer.setUpgradeHandler(this.handlers.upgrade);
            this.httpsProxyServer.setHttpHandler(this.handlers.http);
            this.httpsProxyServer.setUpgradeHandler(this.handlers.upgrade);
        });
    }
}
exports.ProxyServer = ProxyServer;
//# sourceMappingURL=index.js.map