mirror of
https://github.com/HeyPuter/puter.git
synced 2026-08-15 02:27:35 +00:00
A command can optionally define a `completer(args)` function. It takes an array of strings for the current arguments, and returns an array of completion results for the last argument. Includes a few completers: - alarm:info/clear/inspect completes the first argument as an alarm id or short_id - script:run completes the first argument as a script name - params:get/set completes the first argument as a parameter name
106 lines
3.0 KiB
JavaScript
106 lines
3.0 KiB
JavaScript
/*
|
|
* 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 <https://www.gnu.org/licenses/>.
|
|
*/
|
|
const BaseService = require("./BaseService");
|
|
|
|
class Command {
|
|
constructor(spec) {
|
|
this.spec_ = spec;
|
|
}
|
|
|
|
get id() {
|
|
return this.spec_.id;
|
|
}
|
|
|
|
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 [];
|
|
}
|
|
}
|
|
|
|
class CommandService extends BaseService {
|
|
async _construct () {
|
|
this.commands_ = [];
|
|
}
|
|
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}`);
|
|
}
|
|
}
|
|
}));
|
|
}
|
|
|
|
registerCommands(serviceName, commands) {
|
|
for (const command of commands) {
|
|
this.log.info(`registering command ${serviceName}:${command.id}`);
|
|
this.commands_.push(new Command({
|
|
...command,
|
|
id: `${serviceName}:${command.id}`,
|
|
}));
|
|
}
|
|
}
|
|
|
|
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;
|
|
}
|
|
await globalThis.root_context.arun(async () => {
|
|
await command.execute(commandArgs, log);
|
|
});
|
|
}
|
|
|
|
async executeRawCommand(text, log) {
|
|
// TODO: add obvious-json as a tokenizer
|
|
const args = text.split(/\s+/);
|
|
await this.executeCommand(args, log);
|
|
}
|
|
|
|
get commandNames() {
|
|
return this.commands_.map(command => command.id);
|
|
}
|
|
|
|
getCommand(id) {
|
|
return this.commands_.find(command => command.id === id);
|
|
}
|
|
}
|
|
|
|
module.exports = {
|
|
CommandService
|
|
};
|