/*
  Сервис интеграции ПП Парус 8 с WEB API
  Точка входа в сервер приложений
*/

//----------------------
// Подключение библиотек
//----------------------

const cfg = require("./config"); //Настройки сервера приложений
const app = require("./core/app"); //Сервер приложений
const { makeErrorText } = require("./core/utils"); //Вспомогательные функции

//--------------------------
// Глобальные идентификаторы
//--------------------------

let appSrv = new app.ParusAppServer(); //Экземпляр сервера приложений

//----------------------------------------
// Управление процессом сервера приложений
//----------------------------------------

//Разрешение на TLS (Transport Layer Security) без авторизации
process.env.NODE_TLS_REJECT_UNAUTHORIZED = cfg?.outGoing?.bValidateSSL === false ? "0" : "1";

//Включение "Токого режима" для Oracle
process.env.NODE_ORACLE_DB_THIN_MODE = cfg?.dbConnect?.bOraUseThinMode === true ? "1" : "0";

//Путь к клиентским библиотекам для Oracle
process.env.ORACLE_CLIENT_LIB_DIR = cfg?.dbConnect?.sOraClient || "";

//Аварийное освобождение файла лога
const releaseLogFileEmergency = () => {
    try {
        appSrv.logger.closeLogFileSync();
    } catch {}
};

//Аварийный выход с протоколированием и освобождением файла лога
const emergencyExit = sErrMsg => {
    if (sErrMsg) appSrv.logger.errorSync(sErrMsg);
    if (!appSrv.logger.wasStopLogged()) {
        appSrv.logger.notifyServerStoppedSync(1);
    }
    releaseLogFileEmergency();
    process.exit(1);
};

//Обработка события "выход" жизненного цикла процесса
process.on("exit", code => {
    //Если сообщение об останове уже было выдано ранее - не дублируем
    if (appSrv.logger.wasStopLogged()) return;
    //Допишем в console и в файл (если ещё открыт), затем освободим дескриптор
    appSrv.logger.notifyServerStoppedSync(code);
    releaseLogFileEmergency();
});

//Обработка событий мягкого останова процесса
["SIGINT", "SIGQUIT", "SIGTERM"].forEach(sSig => {
    process.once(sSig, async () => {
        await appSrv.logger.warn(`Получен сигнал на останов сервера приложений: ${sSig}`);
        const terminateTimeout = setTimeout(() => {
            emergencyExit("Истекло время ожидания останова сервера приложений. Инициирован аварийный выход из процесса.");
        }, cfg.common.nTerminateTimeout);
        try {
            await appSrv.stop(terminateTimeout);
        } catch (e) {
            clearTimeout(terminateTimeout);
            //Только sync: дальше закрываем файл и выходим
            appSrv.logger.errorSync(`При останове сервера приложений: ${makeErrorText(e)}`);
            emergencyExit();
        }
    });
});

//Перехват всех неохваченных ошибок
process.on("uncaughtException", e => {
    emergencyExit(`НЕПРЕДВИДЕННАЯ ОШИБКА: ${makeErrorText(e)}`);
});

//Запуск сервера приложений
const start = async () => {
    try {
        //Инициализируем сервер приложений
        await appSrv.init({ config: cfg });
        //Включаем его
        await appSrv.run();
    } catch (e) {
        //Если есть ошибки с которыми сервер не справился - ловим их, показываем...
        await appSrv.logger.error(makeErrorText(e));
        //...и пытаемся остановить сервер нормально (с таймаутом и кодом 1)
        const terminateTimeout = setTimeout(() => {
            emergencyExit("Истекло время ожидания останова сервера приложений. Инициирован аварийный выход из процесса.");
        }, cfg.common.nTerminateTimeout);
        try {
            await appSrv.stop(terminateTimeout, 1);
        } catch (eStop) {
            clearTimeout(terminateTimeout);
            //Только sync: дальше закрываем файл и выходим
            appSrv.logger.errorSync(makeErrorText(eStop));
            emergencyExit();
        }
    }
};

//------------
// Точка входа
//------------

//Старутем
start();
