/* * Copyright (C) 2024 Puter Technologies Inc. * * This file is part of Puter. * * Puter is free software: you can redistribute it and/or modify * it under the terms of the GNU Affero General Public License as published * by the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU Affero General Public License for more details. * * You should have received a copy of the GNU Affero General Public License * along with this program. If not, see . */ const { AdvancedBase } = require("puter-js-common"); const { Context } = require('./util/context'); class Kernel extends AdvancedBase { constructor () { super(); this.modules = []; } add_module (module) { this.modules.push(module); } _runtime_init () { const kvjs = require('@heyputer/kv.js'); const kv = new kvjs(); global.kv = kv; global.cl = console.log; const { RuntimeEnvironment } = require('./boot/RuntimeEnvironment'); const { BootLogger } = require('./boot/BootLogger'); // Temporary logger for boot process; // LoggerService will be initialized in app.js const bootLogger = new BootLogger(); // Determine config and runtime locations const runtimeEnv = new RuntimeEnvironment({ logger: bootLogger, }); runtimeEnv.init(); // polyfills require('./polyfill/to-string-higher-radix'); } boot () { this._runtime_init(); // const express = require('express') // const app = express(); const config = require('./config'); globalThis.xtra_log = () => {}; if ( config.env === 'dev' ) { globalThis.xtra_log = (...args) => { // append to file in temp const fs = require('fs'); const path = require('path'); const log_path = path.join('/tmp/xtra_log.txt'); fs.appendFileSync(log_path, args.join(' ') + '\n'); } } const { consoleLogManager } = require('./util/consolelog'); consoleLogManager.initialize_proxy_methods(); // TODO: temporary dependency inversion; requires moving: // - rm, so we can move mv // - mv, so we can move mkdir // - generate_default_fsentries, so we can move mkdir // - mkdir, which needs an fs provider // === START: Initialize Service Registry === const { Container } = require('./services/Container'); const services = new Container(); this.services = services; // app.set('services', services); const root_context = Context.create({ services, config, }, 'app'); globalThis.root_context = root_context; root_context.arun(async () => { await this._install_modules(); await this._boot_services(); }); // Error.stackTraceLimit = Infinity; Error.stackTraceLimit = 200; } async _install_modules () { const { services } = this; for ( const module of this.modules ) { await module.install(Context.get()); } try { await services.init(); } catch (e) { // First we'll try to mark the system as invalid via // SystemValidationService. This might fail because this service // may not be initialized yet. const svc_systemValidation = (() => { try { return services.get('system-validation'); } catch (e) { return null; } })(); if ( ! svc_systemValidation ) { // If we can't mark the system as invalid, we'll just have to // throw the error and let the server crash. throw e; } await svc_systemValidation.mark_invalid( 'failed to initialize services', e, ); } for ( const module of this.modules ) { await module.install_legacy?.(Context.get()); } services.ready.resolve(); // provide services to helpers const { tmp_provide_services } = require('./helpers'); tmp_provide_services(services); } async _boot_services () { const { services } = this; await services.ready; { const app = services.get('web-server').app; app.use(async (req, res, next) => { req.services = services; next(); }); await services.emit('boot.services-initialized'); await services.emit('install.middlewares.context-aware', { app }); await services.emit('install.routes', { app }); await services.emit('install.routes-gui', { app }); } // === END: Initialize Service Registry === // self check (async () => { await services.ready; globalThis.services = services; const log = services.get('log-service').create('init'); log.info('services ready'); log.system('server ready', { deployment_type: globalThis.deployment_type, }); })(); await services.emit('start.webserver'); await services.emit('ready.webserver'); } } module.exports = { Kernel };