diff --git a/doc/contributors/extensions/README.md b/doc/contributors/extensions/README.md
index 661d943ce..0af053c18 100644
--- a/doc/contributors/extensions/README.md
+++ b/doc/contributors/extensions/README.md
@@ -87,7 +87,3 @@ See [events.md](./events.md)
## Definitions
See [definitions.md](./definitions.md)
-
-## Bundled extensions
-
-- [dev-console](./dev-console.md) – Dev socket for running backend commands locally (opt-in via `DEVCONSOLE=1`).
diff --git a/doc/contributors/extensions/dev-console.md b/doc/contributors/extensions/dev-console.md
deleted file mode 100644
index 1a9d73687..000000000
--- a/doc/contributors/extensions/dev-console.md
+++ /dev/null
@@ -1,21 +0,0 @@
-# dev-console extension
-
-The **dev-console** extension provides a **dev socket** so you can run backend commands on a local Puter instance (e.g. commands registered in [CommandService](../../../src/backend/src/services/CommandService.js)).
-
-## Enabling
-
-The extension is **opt-in**. Set the environment variable `DEVCONSOLE=1` when starting Puter. The `npm run dev` script already does this:
-
-```bash
-npm run dev
-```
-
-With `DEVCONSOLE=1`, the extension registers a `dev-socket` service that creates a UNIX socket and runs command lines through CommandService.
-
-## Usage
-
-See [Backend – dev socket](../../../src/backend/doc/dev_socket.md) for how to connect (e.g. `rlwrap nc -U ./dev.sock`) and run commands like `help`, `logs:indent`, etc.
-
-## Location
-
-The extension lives in `extensions/dev-console/`. It only registers the dev-socket service when `DEVCONSOLE=1`; otherwise the extension loads but does nothing, so it does not affect default runs.
diff --git a/extensions/README.md b/extensions/README.md
index d8c0f876f..6186a41dd 100644
--- a/extensions/README.md
+++ b/extensions/README.md
@@ -5,10 +5,6 @@
### Here
Documentation for extensions is [here](src/backend/doc/extensions/README.md).
-### Bundled extensions
-
-- **dev-console** (`extensions/dev-console/`) – Dev socket for running backend commands locally. Opt-in via `DEVCONSOLE=1` (e.g. `npm run dev`). See [Backend – dev socket](src/backend/doc/dev_socket.md).
-
### Not Here
Outdated documentation for extensions is [here](../doc/contributors/extensions/README.md).
diff --git a/mods/mods_available/dev-socket/main.js b/mods/mods_available/dev-socket/main.js
deleted file mode 100644
index f0082eb0f..000000000
--- a/mods/mods_available/dev-socket/main.js
+++ /dev/null
@@ -1,104 +0,0 @@
-/*
- * Copyright (C) 2024-present 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 .
- */
-
-import fs from 'node:fs';
-import net from 'node:net';
-import path from 'node:path';
-
-const SOCKET_NAME = 'dev.sock';
-const WELCOME = [
- 'Puter dev socket – enter a command (e.g. help) and press Enter.',
- 'Close the connection with Ctrl+C or by typing exit.',
- '',
-].join('\n');
-
-function getSocketDir () {
- if ( process.env.PUTER_DEV_SOCKET_DIR ) {
- return process.env.PUTER_DEV_SOCKET_DIR;
- }
- const volatileRuntime = path.join(process.cwd(), 'volatile', 'runtime');
- if ( fs.existsSync(volatileRuntime) ) {
- return volatileRuntime;
- }
- return process.cwd();
-}
-
-extension.on('init', async () => {
- if ( process.env.DEVCONSOLE !== '1' ) {
- return;
- }
-
- const commands = extension.import('service:commands');
- const socketDir = getSocketDir();
- const socketPath = path.join(socketDir, SOCKET_NAME);
-
- try {
- if ( fs.existsSync(socketPath) ) {
- fs.unlinkSync(socketPath);
- }
- fs.mkdirSync(socketDir, { recursive: true });
- } catch ( err ) {
- console.warn('dev-socket: could not prepare socket path', socketPath, err.message);
- return;
- }
-
- const server = net.createServer((socket) => {
- socket.setEncoding('utf8');
- socket.write(`${WELCOME }\n> `);
- let buffer = '';
- socket.on('data', (chunk) => {
- buffer += chunk;
- const lines = buffer.split(/\r?\n/);
- buffer = lines.pop() ?? '';
- for ( const line of lines ) {
- const trimmed = line.trim();
- if ( trimmed === '' ) continue;
- if ( trimmed.toLowerCase() === 'exit' ) {
- socket.end();
- return;
- }
- const log = {
- log: (msg) => {
- socket.write(`${String(msg) }\n`);
- },
- error: (msg) => {
- socket.write(`${String(msg) }\n`);
- },
- };
- commands.executeRawCommand(trimmed, log).then(() => {
- socket.write('> ');
- }).catch((err) => {
- log.error(err?.message ?? err);
- socket.write('> ');
- });
- }
- });
- socket.on('end', () => {
- });
- socket.on('error', () => {
- });
- });
-
- server.listen(socketPath, () => {
- console.log('dev-socket: socket listening at', socketPath);
- });
- server.on('error', (err) => {
- console.warn('dev-socket: socket error', err.message);
- });
-});
diff --git a/mods/mods_available/dev-socket/package.json b/mods/mods_available/dev-socket/package.json
deleted file mode 100644
index 16a796309..000000000
--- a/mods/mods_available/dev-socket/package.json
+++ /dev/null
@@ -1,8 +0,0 @@
-{
- "name": "@heyputer/extension-dev-console",
- "version": "1.0.0",
- "description": "Dev socket for running backend commands locally (opt-in via DEVCONSOLE=1)",
- "main": "main.js",
- "type": "module",
- "private": true
-}
\ No newline at end of file
diff --git a/mods/mods_available/kdmod/CustomPuterService.js b/mods/mods_available/kdmod/CustomPuterService.js
index ec5b730d8..51f5685f1 100644
--- a/mods/mods_available/kdmod/CustomPuterService.js
+++ b/mods/mods_available/kdmod/CustomPuterService.js
@@ -26,52 +26,27 @@ class CustomPuterService extends use.Service {
const svc_puterHomepage = this.services.get('puter-homepage');
svc_puterHomepage.register_script('/custom-gui/main.js');
}
- ['__on_install.routes'] (_, { app }) {
+ '__on_install.routes' (_, { app }) {
const require = this.require;
const express = require('express');
const path_ = require('path');
- app.use('/custom-gui',
- express.static(path.join(__dirname, 'gui')));
+ app.use(
+ '/custom-gui',
+ express.static(path.join(__dirname, 'gui')),
+ );
}
- async ['__on_boot.consolidation'] () {
- const then = Date.now();
- this.tod_widget = () => {
- const s = 5 - Math.floor((Date.now() - then) / 1000);
- const lines = [
- '\x1B[36;1mKDMOD ENABLED\x1B[0m' +
- ` (👁️ ${s}s)`,
- ];
- // It would be super cool to be able to use this here
- // surrounding_box('33;1', lines);
- return lines;
- };
-
- const svc_devConsole = this.services.get('dev-console', { optional: true });
- if ( ! svc_devConsole ) return;
- svc_devConsole.add_widget(this.tod_widget);
-
- setTimeout(() => {
- svc_devConsole.remove_widget(this.tod_widget);
- }, 5000);
- }
-
_register_commands (commands) {
commands.registerCommands('o', [
{
id: 'k',
description: '',
handler: async (_, log) => {
- const svc_devConsole = this.services.get('dev-console', { optional: true });
- if ( ! svc_devConsole ) return;
- svc_devConsole.remove_widget(this.tod_widget);
- const lines = this.tod_widget();
- for ( const line of lines ) log.log(line);
- this.tod_widget = null;
+ log.log('kdmod is enabled');
},
},
]);
}
}
-module.exports = { CustomPuterService };
\ No newline at end of file
+module.exports = { CustomPuterService };
diff --git a/package.json b/package.json
index 868551dc8..495d0b488 100644
--- a/package.json
+++ b/package.json
@@ -50,7 +50,7 @@
"start=gui": "nodemon --exec \"node dev-server.js\" ",
"start": "node ./tools/run-selfhosted.js",
"prestart": "npm run build:ts",
- "dev": "npm run build:ts && DEVCONSOLE=1 node ./tools/run-selfhosted.js",
+ "dev": "npm run build:ts && node ./tools/run-selfhosted.js",
"build": "npx eslint --quiet -c eslint/mandatory.eslint.config.js src/backend/src extensions && npm run build:ts && cd src/gui && node ./build.js",
"check-translations": "node tools/check-translations.js",
"prepare": "husky",
diff --git a/src/backend/doc/dev_socket.md b/src/backend/doc/dev_socket.md
deleted file mode 100644
index 73df862d2..000000000
--- a/src/backend/doc/dev_socket.md
+++ /dev/null
@@ -1,32 +0,0 @@
-## Backend - dev socket
-
-The "dev socket" allows you to interact with Puter's backend by running commands.
-It's a UNIX socket that lets you run commands registered with
-[CommandService](../../src/services/CommandService.js) (e.g. `help`, `logs:indent`, `params:get`, etc.).
-
-### Enabling the dev socket
-
-The dev socket is provided by the **dev-console extension** and is **opt-in**. To enable it:
-
-1. Set the environment variable `DEVCONSOLE=1` when starting Puter (e.g. `npm run dev` already does this).
-2. The extension lives in `extensions/dev-console/` and registers a `dev-socket` service when `DEVCONSOLE=1`.
-
-### Socket location
-
-The socket is created in a directory chosen as follows (in order):
-
-- `PUTER_DEV_SOCKET_DIR` if set
-- `./volatile/runtime` if it exists (typical local dev)
-- otherwise the process current working directory
-
-The socket file is named `dev.sock`.
-
-### Connecting
-
-When in that directory, connect with your tool of choice. For example, using `nc` and `rlwrap` for readline history:
-
-```
-rlwrap nc -U ./dev.sock
-```
-
-If it is successful you will see a message with instructions. Enter a command (e.g. `help`) and press Enter.
diff --git a/src/backend/doc/extensions/README.md b/src/backend/doc/extensions/README.md
index fe3201bfb..2ac7ca49e 100644
--- a/src/backend/doc/extensions/README.md
+++ b/src/backend/doc/extensions/README.md
@@ -72,10 +72,6 @@ key-value store, and in-memory cache.
### Adding Features to Puter
- [Implementing Drivers](./pages/drivers.md)
-### Bundled extensions
-
-- **dev-console** – When `DEVCONSOLE=1` is set (e.g. `npm run dev`), the dev-console extension registers a UNIX socket (`dev.sock`) so you can run backend commands (see [CommandService](../../src/services/CommandService.js)) from a terminal. See [Backend – dev socket](../dev_socket.md).
-
## Extensions - Planned Features
Extensions are under refactor currently. This is the checklist:
diff --git a/src/backend/src/CoreModule.js b/src/backend/src/CoreModule.js
index 82417a553..2b61b3b66 100644
--- a/src/backend/src/CoreModule.js
+++ b/src/backend/src/CoreModule.js
@@ -33,6 +33,7 @@ const { redisClient } = require('./clients/redis/redisSingleton');
const { kv } = require('./util/kvSingleton');
const { s3ClientProvider } = require('./clients/s3/s3ClientProvider');
const { PuterS3Service } = require('./deprecated/filesystem/PuterS3Service');
+const BaseService = require('./services/BaseService');
/**
* @footgun - real install method is defined above
@@ -121,7 +122,6 @@ const install = async ({ context, services, app, useapi, modapi }) => {
// TODO: move these to top level imports or await imports and esm this file
- const { CommandService } = require('./services/CommandService');
const { RateLimitService } = require('./services/sla/RateLimitService');
const { AuthService } = require('./services/auth/AuthService');
const { SLAService } = require('./services/sla/SLAService');
@@ -164,7 +164,6 @@ const install = async ({ context, services, app, useapi, modapi }) => {
services.registerService('dynamo', DDBClientWrapper);
services.registerService('system-validation', SystemValidationService);
- services.registerService('commands', CommandService);
services.registerService('__api-filesystem', FilesystemAPIService);
services.registerService('__api', PuterAPIService);
services.registerService('__gui', ServeGUIService);
@@ -395,14 +394,11 @@ const install = async ({ context, services, app, useapi, modapi }) => {
const install_legacy = async ({ services }) => {
const { OperationTraceService } = require('./services/OperationTraceService');
const { ClientOperationService } = require('./services/ClientOperationService');
- const { EngPortalService } = require('./services/EngPortalService');
// === Services which do not yet extend BaseService ===
// services.registerService('filesystem', FilesystemService);
services.registerService('operationTrace', OperationTraceService);
services.registerService('client-operation', ClientOperationService);
- services.registerService('engineering-portal', EngPortalService);
-
};
/**
diff --git a/src/backend/src/DatabaseModule.js b/src/backend/src/DatabaseModule.js
index a20187462..ee785d935 100644
--- a/src/backend/src/DatabaseModule.js
+++ b/src/backend/src/DatabaseModule.js
@@ -16,14 +16,17 @@
* You should have received a copy of the GNU Affero General Public License
* along with this program. If not, see .
*/
-const { AdvancedBase } = require('@heyputer/putility');
+
+import { AdvancedBase } from '@heyputer/putility';
+import { StrategizedService } from './services/StrategizedService.js';
+import { SqliteDatabaseAccessService } from './services/database/SqliteDatabaseAccessService.js';
+
+// import {BaseService} from './services/BaseService.js';
class DatabaseModule extends AdvancedBase {
async install (context) {
const services = context.get('services');
- const { StrategizedService } = require('./services/StrategizedService');
- const { SqliteDatabaseAccessService } = require('./services/database/SqliteDatabaseAccessService');
services.registerService('database', StrategizedService, {
strategy_key: 'engine',
strategies: {
@@ -33,4 +36,4 @@ class DatabaseModule extends AdvancedBase {
}
}
-module.exports = DatabaseModule;
+export default DatabaseModule;
diff --git a/src/backend/src/Kernel.js b/src/backend/src/Kernel.js
index be0f45f90..dd712e3b1 100644
--- a/src/backend/src/Kernel.js
+++ b/src/backend/src/Kernel.js
@@ -213,7 +213,6 @@ class Kernel extends AdvancedBase {
deployment_type: globalThis.deployment_type,
});
})();
-
await services.emit('boot.activation');
await services.emit('boot.ready');
diff --git a/src/backend/src/modules/core/AlarmService.js b/src/backend/src/modules/core/AlarmService.js
index 013e41897..dce7f5b31 100644
--- a/src/backend/src/modules/core/AlarmService.js
+++ b/src/backend/src/modules/core/AlarmService.js
@@ -64,7 +64,6 @@ class AlarmService extends BaseService {
* the '_init' method of CommandService may not have been called yet.
*/
'__on_boot.consolidation' () {
- this._register_commands(this.services.get('commands'));
}
adapt_id_ (id) {
@@ -361,137 +360,6 @@ class AlarmService extends BaseService {
get_alarm (id) {
return this.alarms[id] ?? this.alarm_aliases[id];
}
-
- _register_commands (commands) {
- // Function to handle a specific alarm event.
- // This comment can be added above line 320.
- // This function is responsible for processing specific events related to alarms.
- // It can be used for tasks such as updating alarm status, sending notifications, or triggering actions.
- // This function is called internally by the AlarmService class.
-
- // /*
- // * handleAlarmEvent - Handles a specific alarm event.
- // *
- // * @param {Object} alarm - The alarm object containing relevant information.
- // * @param {Function} callback - Optional callback function to be called when the event is handled.
- // */
- // function handleAlarmEvent(alarm, callback) {
- // // Implementation goes here.
- // }
- const completeAlarmID = (args) => {
- // The alarm ID is the first argument, so return no results if we're on the second or later.
- if ( args.length > 1 )
- {
- return;
- }
- const lastArg = args[args.length - 1];
-
- const results = [];
- for ( const alarm of Object.values(this.alarms) ) {
- if ( alarm.id.startsWith(lastArg) ) {
- results.push(alarm.id);
- }
- if ( alarm.short_id?.startsWith(lastArg) ) {
- results.push(alarm.short_id);
- }
- }
- return results;
- };
-
- commands.registerCommands('alarm', [
- {
- id: 'list',
- description: 'list alarms',
- handler: async (args, log) => {
- for ( const alarm of Object.values(this.alarms) ) {
- log.log(`${alarm.id_string}: ${alarm.message} (${alarm.count})`);
- }
- },
- },
- {
- id: 'info',
- description: 'show info about an alarm',
- handler: async (args, log) => {
- const [id] = args;
- const alarm = this.get_alarm(id);
- if ( ! alarm ) {
- log.log(`no alarm with id ${id}`);
- return;
- }
- log.log(`\x1B[33;1m${alarm.id_string}\x1B[0m :: ${alarm.message} (${alarm.count})`);
- log.log(`started: ${new Date(alarm.started).toISOString()}`);
- log.log(`short id: ${alarm.short_id}`);
- log.log(`original id: ${alarm.id}`);
-
- // print stack trace of alarm error
- if ( alarm.error ) {
- log.log(alarm.error.stack);
- }
- // print other fields
- for ( const [key, value] of Object.entries(alarm.fields) ) {
- log.log(`- ${key}: ${util.inspect(value)}`);
- }
- },
- completer: completeAlarmID,
- },
- {
- id: 'clear',
- description: 'clear an alarm',
- handler: async (args, log) => {
- const [id] = args;
- const alarm = this.get_alarm(id);
- if ( ! alarm ) {
- log.log(`no alarm with id ${id}; ` +
- `but calling clear(${JSON.stringify(id)}) anyway.`);
- }
- this.clear(id);
- },
- completer: completeAlarmID,
- },
- {
- id: 'clear-all',
- description: 'clear all alarms',
- handler: async (_args, _log) => {
- const alarms = Object.values(this.alarms);
- this.alarms = {};
- for ( const alarm of alarms ) {
- this.handle_alarm_off_(alarm);
- }
- },
- },
- {
- id: 'sound',
- description: 'sound an alarm',
- handler: async (args, _log) => {
- const [id, message] = args;
- this.create(id ?? 'test', message, {});
- },
- },
- {
- id: 'inspect',
- description: 'show logs that happened an alarm',
- handler: async (args, log) => {
- const [id, occurance_idx] = args;
- const alarm = this.get_alarm(id);
- if ( ! alarm ) {
- log.log(`no alarm with id ${id}`);
- return;
- }
- const occurance = alarm.occurrences[occurance_idx];
- if ( ! occurance ) {
- log.log(`no occurance with index ${occurance_idx}`);
- return;
- }
- log.log(`┏━━ Logs before: ${alarm.id_string} ━━━━`);
- for ( const lg of occurance.logs ) {
- log.log(`┃ ${ this.logutil.stringify_log_entry(lg)}`);
- }
- log.log(`┗━━ Logs before: ${alarm.id_string} ━━━━`);
- },
- completer: completeAlarmID,
- },
- ]);
- }
}
module.exports = {
diff --git a/src/backend/src/modules/core/LogService.js b/src/backend/src/modules/core/LogService.js
index 70462ebf3..e09cfd412 100644
--- a/src/backend/src/modules/core/LogService.js
+++ b/src/backend/src/modules/core/LogService.js
@@ -410,61 +410,6 @@ class LogService extends BaseService {
* Registers logging commands with the command service.
*/
'__on_boot.consolidation' () {
- const commands = this.services.get('commands');
- commands.registerCommands('logs', [
- {
- id: 'show',
- description: 'toggle log output',
- handler: async () => {
- this.devlogger && (this.devlogger.off = !this.devlogger.off);
- },
- },
- {
- id: 'rec',
- description: 'start recording to a file via dev logger',
- handler: async (args, ctx) => {
- const [name] = args;
- const { log } = ctx;
- if ( ! this.devlogger ) {
- log('no dev logger; what are you doing?');
- }
- this.devlogger.recto = name;
- },
- },
- {
- id: 'stop',
- description: 'stop recording to a file via dev logger',
- handler: async ([_name], log) => {
- if ( ! this.devlogger ) {
- log('no dev logger; what are you doing?');
- }
- this.devlogger.recto = null;
- },
- },
- {
- id: 'indent',
- description: 'toggle log indentation',
- handler: async () => {
- globalThis.dev_console_indent_on =
- !globalThis.dev_console_indent_on;
- },
- },
- {
- id: 'get-level',
- description: 'get the current log level for displayed logs',
- handler: async (args, log) => {
- log.log(`${display_log_level} (${display_log_level_label[display_log_level] ?? '?'})`);
- },
- },
- {
- id: 'set-level',
- description: 'set the new log level for displayed logs',
- handler: async (args, log) => {
- display_log_level = Number(args[0]);
- log.log(`${display_log_level} (${display_log_level_label[display_log_level] ?? '?'})`);
- },
- },
- ]);
}
/**
* Registers logging commands with the command service.
diff --git a/src/backend/src/modules/core/PagerService.js b/src/backend/src/modules/core/PagerService.js
index 648fba2ca..e40be7308 100644
--- a/src/backend/src/modules/core/PagerService.js
+++ b/src/backend/src/modules/core/PagerService.js
@@ -45,7 +45,6 @@ class PagerService extends BaseService {
* the '_init' method of CommandService may not have been called yet.
*/
'__on_boot.consolidation' () {
- this._register_commands(this.services.get('commands'));
}
/**
@@ -139,24 +138,6 @@ class PagerService extends BaseService {
}
}
- _register_commands (commands) {
- commands.registerCommands('pager', [
- {
- id: 'test-alert',
- description: 'create a test alert',
- handler: async (args, log) => {
- const [severity] = args;
- await this.alert({
- id: 'test-alert',
- message: 'test alert',
- source: 'test',
- severity,
- });
- },
- },
- ]);
- }
-
}
module.exports = {
diff --git a/src/backend/src/modules/core/ParameterService.js b/src/backend/src/modules/core/ParameterService.js
index ccd4206d8..d26599dce 100644
--- a/src/backend/src/modules/core/ParameterService.js
+++ b/src/backend/src/modules/core/ParameterService.js
@@ -98,7 +98,6 @@ class ParameterService extends BaseService {
* @private
*/
'__on_boot.consolidation' () {
- this._registerCommands(this.services.get('commands'));
}
createParameters (serviceName, parameters, opt_instance) {
@@ -109,9 +108,11 @@ class ParameterService extends BaseService {
id: `${serviceName}:${parameter.id}`,
}));
if ( opt_instance ) {
- this.bindToInstance(`${serviceName}:${parameter.id}`,
- opt_instance,
- parameter.id);
+ this.bindToInstance(
+ `${serviceName}:${parameter.id}`,
+ opt_instance,
+ parameter.id,
+ );
}
}
}
@@ -144,71 +145,6 @@ class ParameterService extends BaseService {
}
return parameter;
}
-
- /**
- * Registers parameter-related commands with the command service
- * @param {Object} commands - The command service instance to register with
- */
- _registerCommands (commands) {
- const completeParameterName = (args) => {
- // The parameter name is the first argument, so return no results if we're on the second or later.
- if ( args.length > 1 )
- {
- return;
- }
- const lastArg = args[args.length - 1];
-
- return this.parameters_
- .map(parameter => parameter.spec_.id)
- .filter(parameterName => parameterName.startsWith(lastArg));
- };
-
- commands.registerCommands('params', [
- {
- id: 'get',
- description: 'get a parameter',
- handler: async (args, log) => {
- const [name] = args;
- const value = await this.get(name);
- log.log(value);
- },
- completer: completeParameterName,
- },
- {
- id: 'set',
- description: 'set a parameter',
- handler: async (args, log) => {
- const [name, value] = args;
- const parameter = this._get_param(name);
- parameter.set(value);
- log.log(value);
- },
- completer: completeParameterName,
- },
- {
- id: 'list',
- description: 'list parameters',
- handler: async (args, log) => {
- const [prefix] = args;
- let parameters = this.parameters_;
- if ( prefix ) {
- parameters = parameters
- .filter(p => p.spec_.id.startsWith(prefix));
- }
- log.log(`available parameters${
- prefix ? ` (starting with: ${prefix})` : ''
- }:`);
- for ( const parameter of parameters ) {
- // log.log(`- ${parameter.spec_.id}: ${parameter.spec_.description}`);
- // Log parameter description and value
- const value = await parameter.get();
- log.log(`- ${parameter.spec_.id} = ${value}`);
- log.log(` ${parameter.spec_.description}`);
- }
- },
- },
- ]);
- }
}
module.exports = {
diff --git a/src/backend/src/modules/domain/DomainVerificationService.js b/src/backend/src/modules/domain/DomainVerificationService.js
index f8c76ad96..01b032bec 100644
--- a/src/backend/src/modules/domain/DomainVerificationService.js
+++ b/src/backend/src/modules/domain/DomainVerificationService.js
@@ -23,19 +23,6 @@ class DomainVerificationService extends BaseService {
return await get_user({ username: 'admin' });
}
- _register_commands (commands) {
- const svc_commands = this.services.get('commands');
- svc_commands.registerCommands('domain', [
- {
- id: 'user',
- description: '',
- handler: async (args, log) => {
- const res = await this.get_controlling_user({ domain: args[0] });
- log.log(res);
- },
- },
- ]);
- }
}
module.exports = {
diff --git a/src/backend/src/modules/puterfs/SizeService.js b/src/backend/src/modules/puterfs/SizeService.js
index 270b5e1ef..67a5afa59 100644
--- a/src/backend/src/modules/puterfs/SizeService.js
+++ b/src/backend/src/modules/puterfs/SizeService.js
@@ -42,35 +42,6 @@ class SizeService extends BaseService {
}
'__on_boot.consolidate' () {
- const svc_commands = this.services.get('commands');
- svc_commands.registerCommands('size', [
- {
- id: 'get-usage',
- description: 'get usage for a user',
- handler: async (args, log) => {
- const user = await UserParameter.adapt(args[0]);
- const usage = await this.get_usage(user.id);
- log.log(`usage: ${usage} bytes`);
- },
- },
- {
- id: 'get-capacity',
- description: 'get storage capacity for a user',
- handler: async (args, log) => {
- const user = await UserParameter.adapt(args[0]);
- const capacity = await this.get_storage_capacity(user);
- log.log(`capacity: ${capacity} bytes`);
- },
- },
- {
- id: 'get-cache-size',
- description: 'get the number of cached users',
- handler: async (args, log) => {
- const size = Object.keys(this.usages).length;
- log.log(`cache size: ${size}`);
- },
- },
- ]);
}
async get_usage (user_id) {
diff --git a/src/backend/src/modules/selfhosted/DefaultUserService.js b/src/backend/src/modules/selfhosted/DefaultUserService.js
index 7ed64ac9e..daa79d620 100644
--- a/src/backend/src/modules/selfhosted/DefaultUserService.js
+++ b/src/backend/src/modules/selfhosted/DefaultUserService.js
@@ -36,7 +36,6 @@ const DEFAULT_FILES = {};
class DefaultUserService extends BaseService {
async _init () {
- this._register_commands(this.services.get('commands'));
}
async '__on_ready.webserver' () {
// check if a user named `admin` exists
@@ -221,19 +220,6 @@ class DefaultUserService extends BaseService {
return tmp_password;
});
}
- _register_commands (commands) {
- commands.registerCommands('default-user', [
- {
- id: 'reset-password',
- handler: async (args, ctx) => {
- const [username] = args;
- const user = await get_user({ username });
- const tmp_pwd = await this.force_tmp_password_(user);
- ctx.log(`New password for ${quot(username)} is: ${tmp_pwd}`);
- },
- },
- ]);
- }
}
module.exports = DefaultUserService;
diff --git a/src/backend/src/modules/selfhosted/SelfhostedService.js b/src/backend/src/modules/selfhosted/SelfhostedService.js
index d0cf95d8f..fbdde8752 100644
--- a/src/backend/src/modules/selfhosted/SelfhostedService.js
+++ b/src/backend/src/modules/selfhosted/SelfhostedService.js
@@ -25,57 +25,6 @@ class SelfhostedService extends BaseService {
`;
async _init () {
- this._register_commands(this.services.get('commands'));
- }
-
- _register_commands (commands) {
- const db = this.services.get('database').get(DB_WRITE, 'selfhosted');
- commands.registerCommands('app', [
- {
- id: 'godmode-on',
- description: 'Toggle godmode for an app',
- handler: async (args, _log) => {
- const svc_su = this.services.get('su');
- await await svc_su.sudo(async () => {
- const [app_uid] = args;
- const es_app = await this.services.get('es:app');
- const app = await es_app.read(app_uid);
- if ( ! app ) {
- throw new Error(`App ${app_uid} not found`);
- }
- await db.write('UPDATE apps SET godmode = 1 WHERE uid = ?', [app_uid]);
- const svc_event = this.services.get('event');
- await svc_event.emit('app.changed', {
- app_uid,
- action: 'updated',
- });
- });
- },
- },
- ]);
- commands.registerCommands('app', [
- {
- id: 'godmode-off',
- description: 'Toggle godmode for an app',
- handler: async (args, _log) => {
- const svc_su = this.services.get('su');
- await await svc_su.sudo(async () => {
- const [app_uid] = args;
- const es_app = await this.services.get('es:app');
- const app = await es_app.read(app_uid);
- if ( ! app ) {
- throw new Error(`App ${app_uid} not found`);
- }
- await db.write('UPDATE apps SET godmode = 0 WHERE uid = ?', [app_uid]);
- const svc_event = this.services.get('event');
- await svc_event.emit('app.changed', {
- app_uid,
- action: 'updated',
- });
- });
- },
- },
- ]);
}
}
diff --git a/src/backend/src/modules/test-core/TestCoreModule.js b/src/backend/src/modules/test-core/TestCoreModule.js
index aa28a81ec..5711fced3 100644
--- a/src/backend/src/modules/test-core/TestCoreModule.js
+++ b/src/backend/src/modules/test-core/TestCoreModule.js
@@ -33,7 +33,6 @@ export class TestCoreModule {
services.registerService('su', SUService);
services.registerService('alarm', AlarmService);
services.registerService('event', EventService);
- services.registerService('commands', CommandService);
services.registerService('meteringService', MeteringServiceWrapper);
services.registerService('puter-kvstore', DynamoKVStoreWrapper);
services.registerService('permission', PermissionService);
diff --git a/src/backend/src/modules/web/WebServerService.js b/src/backend/src/modules/web/WebServerService.js
index caf3639b8..be74ef6f7 100644
--- a/src/backend/src/modules/web/WebServerService.js
+++ b/src/backend/src/modules/web/WebServerService.js
@@ -136,6 +136,7 @@ class WebServerService extends BaseService {
* @returns {Promise} A promise that resolves once the server is started.
*/
async '__on_boot.activation' () {
+ console.log('starting webser');
const services = this.services;
await services.emit('start.webserver');
await services.emit('ready.webserver');
diff --git a/src/backend/src/services/CommandService.js b/src/backend/src/services/CommandService.js
index ee7155809..e69de29bb 100644
--- a/src/backend/src/services/CommandService.js
+++ b/src/backend/src/services/CommandService.js
@@ -1,204 +0,0 @@
-/*
- * Copyright (C) 2024-present 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 { Context } = require('../util/context');
-const BaseService = require('./BaseService');
-
-/**
-* Represents a Command class that encapsulates command execution functionality.
-* Each Command instance contains a specification (spec) that defines its ID,
-* name, description, handler function, and optional argument completer.
-* The class provides methods for executing commands and handling command
-* argument completion.
-*/
-class Command {
- constructor (spec) {
- this.spec_ = spec;
- }
-
- /**
- * Gets the unique identifier for this command
- * @returns {string} The command's ID as specified in the constructor
- */
- get id () {
- return this.spec_.id;
- }
-
- /**
- * Executes the command with given arguments and logging
- * @param {Array} args - Command arguments to pass to the handler
- * @param {Object} [log=console] - Logger object for output, defaults to console
- * @returns {Promise}
- * @throws {Error} Logs any errors that occur during command execution
- */
- async execute (args, log) {
- log = log ?? console;
- const { id, name, description, handler } = this.spec_;
- try {
- await handler(args, log);
- } catch ( err ) {
- log.error(`command ${name ?? id} failed: ${err.message}`);
- log.error(err.stack);
- }
- }
-
- completeArgument (args) {
- const completer = this.spec_.completer;
- if ( completer )
- {
- return completer(args);
- }
- return [];
- }
-}
-
-/**
-* CommandService class manages the registration, execution, and handling of commands in the Puter system.
-* Extends BaseService to provide command-line interface functionality. Maintains a collection of Command
-* objects, supports command registration with namespaces, command execution with arguments, and provides
-* command lookup capabilities. Includes built-in help command functionality.
-* @extends BaseService
-*/
-class CommandService extends BaseService {
- /**
- * Initializes the command service's internal state
- * Called during service construction to set up the empty commands array
- */
- async _construct () {
- this.commands_ = [];
- }
-
- /**
- * Add the help command to the list of commands on init
- */
- async _init () {
- this.commands_.push(new Command({
- id: 'help',
- description: 'show this help',
- handler: (args, log) => {
- log.log('available commands:');
- for ( const command of this.commands_ ) {
- log.log(`- ${command.spec_.id}: ${command.spec_.description}`);
- }
- },
- }));
- }
-
- async '__on_boot.consolidation' () {
- const svc_event = this.services.get('event');
- const svc_command = this;
- const event = {
- createCommand (name, command) {
- const serviceName = Context.get('extension_name') ?? '%missing%';
- const commandSpec = typeof command === 'function'
- ? { handler: command }
- : command;
- if ( typeof commandSpec !== 'object' ) {
- throw new Error('command must be either a function or an object');
- }
- if ( ! (typeof command.handler === 'function') ) {
- throw new Error('command should have a handler function');
- }
- svc_command.registerCommands(serviceName, [{
- id: name,
- ...commandSpec,
- }]);
- },
- };
- svc_event.emit('create.commands', event);
- }
-
- registerCommands (serviceName, commands) {
- if ( ! this.log ) {
- /* eslint-disable */
- console.error(
- 'CommandService.registerCommands was called before a logger ' +
- 'was initialied. This happens when calling registerCommands ' +
- 'in the "construct" phase instead of the "init" phase. If ' +
- 'you are migrating a legacy service that does not extend ' +
- 'BaseService, maybe the _construct hook is calling init()'
- );
- /* eslint-enable */
- process.exit(1);
- }
- for ( const command of commands ) {
- this.log.debug(`registering command ${serviceName}:${command.id}`);
- this.commands_.push(new Command({
- ...command,
- id: `${serviceName}:${command.id}`,
- }));
- }
- }
-
- /**
- * Executes a command with the given arguments and logging context
- * @param {string[]} args - Array of command arguments where first element is command name
- * @param {Object} log - Logger object for output (defaults to console if not provided)
- * @returns {Promise}
- * @throws {Error} If command execution fails
- */
- async executeCommand (args, log) {
- const [commandName, ...commandArgs] = args;
- const command = this.commands_.find(c => c.spec_.id === commandName);
- if ( ! command ) {
- log.error(`unknown command: ${commandName}`);
- return;
- }
- /**
- * Executes a command with the given arguments in a global context
- * @param {string[]} args - Array of command arguments where first element is command name
- * @param {Object} log - Logger object for output
- * @returns {Promise}
- * @throws {Error} If command execution fails
- */
- await globalThis.root_context.sub({
- injected_logger: log,
- }).arun(async () => {
- await command.execute(commandArgs, log);
- });
- }
-
- /**
- * Executes a raw command string by splitting it into arguments and executing the command
- * @param {string} text - Raw command string to execute
- * @param {object} log - Logger object for output (defaults to console if not provided)
- * @returns {Promise}
- * @todo Replace basic whitespace splitting with proper tokenizer (obvious-json)
- */
- async executeRawCommand (text, log) {
- // TODO: add obvious-json as a tokenizer
- const args = text.split(/\s+/);
- await this.executeCommand(args, log);
- }
-
- /**
- * Gets a list of all registered command names/IDs
- * @returns {string[]} Array of command identifier strings
- */
- get commandNames () {
- return this.commands_.map(command => command.id);
- }
-
- getCommand (id) {
- return this.commands_.find(command => command.id === id);
- }
-}
-
-module.exports = {
- CommandService,
-};
diff --git a/src/backend/src/services/CommandService.test.ts b/src/backend/src/services/CommandService.test.ts
index 3d4c02a39..e69de29bb 100644
--- a/src/backend/src/services/CommandService.test.ts
+++ b/src/backend/src/services/CommandService.test.ts
@@ -1,120 +0,0 @@
-import { describe, expect, it, vi } from 'vitest';
-import { createTestKernel } from '../../tools/test.mjs';
-import { CommandService } from './CommandService';
-
-describe('CommandService', async () => {
- const testKernel = await createTestKernel({
- serviceMap: {
- commands: CommandService,
- },
- initLevelString: 'init',
- });
-
- const commandService = testKernel.services!.get('commands') as CommandService;
-
- it('should be instantiated', () => {
- expect(commandService).toBeInstanceOf(CommandService);
- });
-
- it('should have help command registered by default', () => {
- expect(commandService.commandNames).toContain('help');
- });
-
- it('should register commands', () => {
- commandService.registerCommands('test-service', [
- {
- id: 'test-cmd',
- description: 'A test command',
- handler: async () => {},
- },
- ]);
- expect(commandService.commandNames).toContain('test-service:test-cmd');
- });
-
- it('should execute registered commands', async () => {
- let executed = false;
- commandService.registerCommands('exec-test', [
- {
- id: 'exec-cmd',
- description: 'Execute test',
- handler: async () => { executed = true; },
- },
- ]);
-
- const mockLog = { error: vi.fn(), log: vi.fn() };
- await commandService.executeCommand(['exec-test:exec-cmd'], mockLog);
- expect(executed).toBe(true);
- });
-
- it('should pass arguments to command handler', async () => {
- let receivedArgs: string[] = [];
- commandService.registerCommands('args-test', [
- {
- id: 'args-cmd',
- description: 'Args test',
- handler: async (args) => { receivedArgs = args; },
- },
- ]);
-
- const mockLog = { error: vi.fn(), log: vi.fn() };
- await commandService.executeCommand(['args-test:args-cmd', 'arg1', 'arg2'], mockLog);
- expect(receivedArgs).toEqual(['arg1', 'arg2']);
- });
-
- it('should handle unknown commands', async () => {
- const mockLog = { error: vi.fn(), log: vi.fn() };
- await commandService.executeCommand(['unknown-command'], mockLog);
- expect(mockLog.error).toHaveBeenCalledWith('unknown command: unknown-command');
- });
-
- it('should execute raw commands', async () => {
- let executed = false;
- commandService.registerCommands('raw-test', [
- {
- id: 'raw-cmd',
- description: 'Raw test',
- handler: async () => { executed = true; },
- },
- ]);
-
- const mockLog = { error: vi.fn(), log: vi.fn() };
- await commandService.executeRawCommand('raw-test:raw-cmd', mockLog);
- expect(executed).toBe(true);
- });
-
- it('should get command by id', () => {
- commandService.registerCommands('get-test', [
- {
- id: 'get-cmd',
- description: 'Get test',
- handler: async () => {},
- },
- ]);
-
- const cmd = commandService.getCommand('get-test:get-cmd');
- expect(cmd).toBeDefined();
- expect(cmd?.id).toBe('get-test:get-cmd');
- });
-
- it('should execute help command', async () => {
- const mockLog = { error: vi.fn(), log: vi.fn() };
- await commandService.executeCommand(['help'], mockLog);
- expect(mockLog.log).toHaveBeenCalledWith('available commands:');
- });
-
- it('should support command completers', () => {
- commandService.registerCommands('complete-test', [
- {
- id: 'complete-cmd',
- description: 'Complete test',
- handler: async () => {},
- completer: (args) => ['option1', 'option2'],
- },
- ]);
-
- const cmd = commandService.getCommand('complete-test:complete-cmd');
- const completions = cmd?.completeArgument([]);
- expect(completions).toEqual(['option1', 'option2']);
- });
-});
-
diff --git a/src/backend/src/services/Container.js b/src/backend/src/services/Container.js
index 07b25821b..117803b20 100644
--- a/src/backend/src/services/Container.js
+++ b/src/backend/src/services/Container.js
@@ -211,7 +211,17 @@ class Container {
for ( const k in this.instances_ ) {
try {
if ( PARALLEL ) promises.push(this.instances_[k].init());
- else await this.instances_[k].init();
+ else {
+ // Logic to get name of a service, unused but
+ // if you ever need to log the name
+ // this will be accurate
+ let name = this.instances_[k].constructor.name;
+ if ( name === 'ExtensionService' ) {
+ name = this.instances_[k].args.state.extension.runtime.name;
+ }
+
+ await this.instances_[k].init();
+ }
} catch (e) {
init_failures.push({ k, e });
}
diff --git a/src/backend/src/services/EngPortalService.js b/src/backend/src/services/EngPortalService.js
deleted file mode 100644
index 06e6c9d20..000000000
--- a/src/backend/src/services/EngPortalService.js
+++ /dev/null
@@ -1,162 +0,0 @@
-/*
- * Copyright (C) 2024-present 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('@heyputer/putility');
-
-/**
-* @class EngPortalService
-* @extends {AdvancedBase}
-*
-* EngPortalService is a class that provides services for managing and accessing various operations, alarms, and statistics
-* within a system. It inherits from the AdvancedBase class and utilizes multiple dependencies such as socket.io for communication
-* and uuidv4 for generating unique identifiers. The class includes methods for listing operations, serializing frames, listing alarms,
-* fetching server statistics, and registering command handlers. This class is integral to maintaining and monitoring system health
-* and operations efficiently.
-*/
-class EngPortalService extends AdvancedBase {
- static MODULES = {
- uuidv4: require('uuid').v4,
- };
-
- constructor ({ services }) {
- super();
- this.services = services;
- this.commands = services.get('commands');
- this._registerCommands(this.commands);
- }
-
- /**
- * Lists all ongoing operations.
- * This method retrieves all ongoing operations from the 'operationTrace' service,
- * serializes them, and returns the serialized list.
- *
- * @async
- * @returns {Promise} A list of serialized operation frames.
- */
- async list_operations () {
- const svc_operationTrace = this.services.get('operationTrace');
- const ls = [];
- for ( const id in svc_operationTrace.ongoing ) {
- const op = svc_operationTrace.ongoing[id];
- ls.push(this._serialize_frame(op));
- }
-
- return ls;
- }
-
- _serialize_frame (frame) {
- const out = {
- id: frame.id,
- label: frame.label,
- status: frame.status,
- async: frame.async,
- checkpoint: frame.checkpoint,
- // tags: frame.tags,
- // attributes: frame.attributes,
- // messages: frame.messages,
- // error: frame.error_ ? frame.error_.message || true : null,
- children: [],
- attributes: {},
- };
-
- for ( const k in frame.attributes ) {
- out.attributes[k] = frame.attributes[k];
- }
-
- for ( const child of frame.children ) {
- out.children.push(this._serialize_frame(child));
- }
-
- return out;
- }
-
- /**
- * Retrieves a list of alarms.
- *
- * This method fetches all active alarms from the 'alarm' service and returns a serialized array of alarm objects.
- *
- * @returns {Promise} A promise that resolves to an array of serialized alarm objects.
- */
- async list_alarms () {
- const svc_alarm = this.services.get('alarm');
- const ls = [];
- for ( const id in svc_alarm.alarms ) {
- const alarm = svc_alarm.alarms[id];
- ls.push(this._serialize_alarm(alarm));
- }
-
- return ls;
- }
-
- /**
- * Gets the system statistics.
- *
- * This method retrieves the system statistics from the server-health service and returns them.
- *
- * @async
- * @returns {Promise