#!/usr/bin/env node
"use strict";
// This file is part of HFS - Copyright 2021-2023, Massimo Melina <a@rejetto.com> - License https://www.gnu.org/licenses/gpl-3.0.txt
var __importDefault = (this && this.__importDefault) || function (mod) {
    return (mod && mod.__esModule) ? mod : { "default": mod };
};
Object.defineProperty(exports, "__esModule", { value: true });
exports.app = void 0;
const koa_1 = __importDefault(require("koa"));
const koa_mount_1 = __importDefault(require("koa-mount"));
require("./consoleLog");
const apiMiddleware_1 = require("./apiMiddleware");
const const_1 = require("./const");
const frontEndApis_1 = require("./frontEndApis");
const log_1 = require("./log");
const plugins_1 = require("./plugins");
const throttler_1 = require("./throttler");
const middlewares_1 = require("./middlewares");
const serveGuiAndSharedFiles_1 = require("./serveGuiAndSharedFiles");
const webdav_1 = require("./webdav");
require("./listen");
require("./commands");
const adminApis_1 = require("./adminApis");
const config_1 = require("./config");
const assert_1 = require("assert");
const lodash_1 = __importDefault(require("lodash"));
const misc_1 = require("./misc");
const selfCheck_1 = require("./selfCheck");
const acme_1 = require("./acme");
require("./geo");
const geo_1 = require("./geo");
const roots_1 = require("./roots");
const events_1 = __importDefault(require("./events"));
const ips_1 = require("./ips");
require("./outboundProxy");
(0, assert_1.ok)(lodash_1.default.intersection(Object.keys(frontEndApis_1.frontEndApis), Object.keys(adminApis_1.adminApis)).length === 0); // they share same endpoints, don't clash
if (new config_1.Version(process.versions.node).olderThan('18.15.0')) {
    console.error("Node.js 18.15+ is required, please update");
    process.exit(2);
}
process.title = 'HFS ' + const_1.VERSION;
misc_1.httpStream.defaultUA = 'HFS';
const keys = process.env.COOKIE_SIGN_KEYS?.split(',')
    || [(0, misc_1.randomId)(30)]; // randomness at start gives some extra security, btu also invalidates existing sessions
exports.app = new koa_1.default({ keys });
exports.app.use(middlewares_1.sessionMiddleware)
    .use(selfCheck_1.selfCheckMiddleware)
    .use(acme_1.acmeMiddleware)
    .use(middlewares_1.prepareState)
    .use(geo_1.geoFilter)
    .use(ips_1.trackIpsMw)
    .use(middlewares_1.gzipper)
    .use(middlewares_1.paramsDecoder) // must be done before plugins, so they can manipulate params
    .use(middlewares_1.headRequests)
    .use(roots_1.rootsMiddleware)
    .use(log_1.logMw)
    .use(middlewares_1.someSecurity)
    .use(throttler_1.throttler)
    .use(plugins_1.pluginsMiddleware)
    .use((0, koa_mount_1.default)(const_1.API_URI, (0, apiMiddleware_1.apiMiddleware)({ ...frontEndApis_1.frontEndApis, ...adminApis_1.adminApis })))
    .use(serveGuiAndSharedFiles_1.guiFilesMiddleware)
    .use(webdav_1.webdav)
    .use(serveGuiAndSharedFiles_1.serveSharedFiles)
    .on('error', errorHandler);
events_1.default.emit('app', exports.app);
function errorHandler(err) {
    const { code } = err;
    if (const_1.DEV && code === 'ENOENT' && err.path?.endsWith('sockjs-node'))
        return; // spam out dev stuff
    if (code === 'ECANCELED' || code === 'ECONNRESET' || code === 'ECONNABORTED' || code === 'EPIPE'
        || code === 'ERR_STREAM_WRITE_AFTER_END' // happens disconnecting uploads, don't care
        || code === 'ERR_STREAM_PREMATURE_CLOSE' // happens when many files are sent (not locally), but I checked that the files are written completely. Introduced after node18.5.0 and is thrown by pipeline() used by PUT method handler.
        || code?.startsWith('HPE'))
        return; // malformed client/probe HTTP parser errors, not internal failures
    console.error('Server error', err);
}
process.on('uncaughtException', (err) => {
    if (err.syscall !== 'watch' && err.code !== 'ECONNRESET' && err.code !== 'EIO') // EIO seems to happen when the terminal is closed
        try {
            console.error("Uncaught:", err);
        }
        catch { } // in case we are writing to a closed terminal, we may throw with "write eio at afterwritedispatched", causing an infinite loop
});
// this warning is scaring users, and has been removed in node 20.12.0 https://github.com/nodejs/node/pull/51204
const original = process.emitWarning;
process.emitWarning = warn => String(warn).startsWith('An error event has already been emitted') || original.call(process, warn);
(0, config_1.defineConfig)('proxies', 0).sub(n => {
    exports.app.proxy = n > 0;
    exports.app.maxIpsCount = n;
});
