"use strict";
var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
    function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
    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) : adopt(result.value).then(fulfilled, rejected); }
        step((generator = generator.apply(thisArg, _arguments || [])).next());
    });
};
Object.defineProperty(exports, "__esModule", { value: true });
exports.FactoryApiWorker = void 0;
/*
* Worker for the factory API
* not actually anything web or API related - besides the fact that it actively watches the database for new requests, then runs them.
* After it runs, it updates the database and this is used by 'query' to return data
*
*
* This worker is going to be running on different servers, and there will be tons of instances all looking at different installs of Factorio
* Each worker will be started independently, and will be responsible for a single 'factory' that can process trials
*
* It should start by querying the DB Request table, looking for a trial not allocated.
*
* try inserting to status table - if it fails, then another worker has already taken it
* if success, update the 'request' table to show that it's allocated
*
* now you can continue to run the trial
*
*
* */
const FactoryDatabase_1 = require("../FactoryDatabase");
const Trial_1 = require("../Trial");
const Source_1 = require("../Source");
const ModList_1 = require("../ModList");
const Dataset_1 = require("../Dataset");
const FactoryApiIngest_1 = require("./FactoryApiIngest");
const Factory_1 = require("../Factory");
const crypto_1 = require("crypto");
const Logging_1 = require("../Logging");
const typeorm_1 = require("typeorm");
class FactoryApiWorker {
    static initialize() {
        var _a;
        return __awaiter(this, void 0, void 0, function* () {
            // startup factory
            yield Factory_1.Factory.initialize({
                hideConsole: false,
                updateInstall: true
            });
            FactoryApiWorker.worker = (_a = process.env.NAME) !== null && _a !== void 0 ? _a : (0, crypto_1.randomUUID)();
            yield FactoryDatabase_1.FactoryDatabase.initialize([
                {
                    name: 'cache',
                    type: 'postgres',
                    host: process.env.PG_CACHE_HOST,
                    port: parseInt(process.env.PG_CACHE_PORT),
                    username: process.env.PG_CACHE_USER,
                    password: process.env.PG_CACHE_PASS,
                    poolSize: 4,
                    synchronize: true,
                    entities: [
                        Trial_1.Trial,
                        Source_1.Source,
                        ModList_1.ModList,
                        Dataset_1.GameFlowItemRecord,
                        Dataset_1.GameFlowElectricRecord,
                        Dataset_1.GameFlowCircuitRecord,
                        Dataset_1.GameFlowPollutionRecord,
                        Dataset_1.GameFlowSystemRecord,
                        FactoryApiIngest_1.FactoryApiExecutionRequest,
                        FactoryApiIngest_1.FactoryApiExecutionStatus
                    ]
                }, /*{
                    name: 'storage',
                    type: 'postgres',
                    host: process.env.PG_STORAGE_HOST,
                    port: parseInt(process.env.PG_STORAGE_PORT),
                    username: process.env.PG_STORAGE_USER,
                    password: process.env.PG_STORAGE_PASS,
                    poolSize: 4,
                    synchronize: true,
                    entities: [
                        Trial,
                        Source,
                        ModList,
                        GameFlowItemRecord,
                        GameFlowElectricRecord,
                        GameFlowCircuitRecord,
                        GameFlowPollutionRecord,
                        GameFlowSystemRecord,
                        FactoryApiExecutionRequest,
                        FactoryApiExecutionStatus
                    ]
                }*/
            ]);
            // now that we're connected and have a working factory, we can start processing requests!
            // this is a loop that will run forever, and will only stop when the process is killed
            // start a 'timeout' callback to run the main loop - once one is done, call process again, else start callback
            FactoryApiWorker.startTick();
        });
    }
    static startTick() {
        let tResp = FactoryApiWorker.tick();
        tResp.then(() => {
            setTimeout(() => {
                FactoryApiWorker.startTick();
            }, 500);
        }).catch((e) => {
            if (e)
                Logging_1.Logging.log('error', e);
            setTimeout(() => {
                FactoryApiWorker.startTick();
            }, 500);
        });
    }
    static tick() {
        return __awaiter(this, void 0, void 0, function* () {
            try {
                // grab request, then try reserving it.
                let nr = yield this.grabNewRequest();
                if (nr && !nr.allocatedAt) {
                    yield FactoryDatabase_1.FactoryDatabase.FactoryDB.getRepository(FactoryApiIngest_1.FactoryApiExecutionStatus).insert({
                        execution_id: nr.execution_id,
                        loggedAt: new Date(),
                        worker: FactoryApiWorker.worker
                    });
                    yield FactoryDatabase_1.FactoryDatabase.FactoryDB.getRepository(FactoryApiIngest_1.FactoryApiExecutionRequest).update({
                        execution_id: nr.execution_id
                    }, {
                        allocatedAt: new Date()
                    });
                    try {
                        // process this request
                        yield this.processExec(nr);
                        yield FactoryDatabase_1.FactoryDatabase.FactoryDB.getRepository(FactoryApiIngest_1.FactoryApiExecutionStatus).update({
                            execution_id: nr.execution_id
                        }, {
                            success: true
                        });
                    }
                    catch (e) {
                        // if the error occurred and is caught here, update factory status for this request to success: false
                        Logging_1.Logging.log('error', e);
                        yield FactoryDatabase_1.FactoryDatabase.FactoryDB.getRepository(FactoryApiIngest_1.FactoryApiExecutionStatus).update({
                            execution_id: nr.execution_id
                        }, {
                            success: false
                        });
                    }
                }
            }
            catch (e) {
                // if the error occurred and is caught here, ignore and move on
            }
        });
    }
    static grabNewRequest() {
        return __awaiter(this, void 0, void 0, function* () {
            return yield FactoryDatabase_1.FactoryDatabase.FactoryDB.getRepository(FactoryApiIngest_1.FactoryApiExecutionRequest).findOne({
                where: {
                    allocatedAt: (0, typeorm_1.IsNull)()
                },
                order: {
                    loggedAt: 'ASC'
                }
            });
        });
    }
    static processExec(exec) {
        return __awaiter(this, void 0, void 0, function* () {
            // load the request and the related trial and needed info to run it all
            let trial = yield FactoryDatabase_1.FactoryDatabase.loadTrial(exec.trialId);
            if (!trial)
                throw new Error('Trial not found');
            // analyze trial with save options on
            yield Factory_1.Factory.analyzeTrial(trial, true, true);
            // nothing more to do here - trial has been run and saved. return!
            return;
        });
    }
}
exports.FactoryApiWorker = FactoryApiWorker;
//# sourceMappingURL=FactoryApiWorker.js.map