serverline-sim/src/index.ts

157 lines
4.3 KiB
TypeScript
Raw Normal View History

2021-12-11 23:03:55 -05:00
/// <reference path="./externals.d.ts" />
2021-12-22 08:35:48 -05:00
import { Instance, ParsedSystemState, System } from '@kernel:base';
2021-12-12 17:09:52 -05:00
import '@kernel:log-hook';
import createExecutor from '@commands:executor';
2021-12-12 22:43:24 -05:00
import create from '@commands:create';
import ls from '@commands:ls';
import save from '@commands:save';
2021-12-22 04:54:25 -05:00
import help from '@commands:help';
2021-12-12 17:09:52 -05:00
import * as uuid from 'uuid';
2021-12-12 10:53:26 -05:00
import serverline from 'serverline';
2021-12-12 17:09:52 -05:00
import { existsSync, readFileSync, writeFileSync } from 'fs';
2021-12-12 10:53:26 -05:00
import { resolve } from 'path'
import chalk from 'chalk';
2021-12-12 22:43:24 -05:00
import md5 from 'md5';
2021-12-11 23:03:55 -05:00
2021-12-12 10:53:26 -05:00
const args = process.argv.slice(2);
const [ startupFile ] = args;
2021-12-22 08:35:48 -05:00
export const system: System = {
2021-12-12 10:53:26 -05:00
instances: new Map<string, Instance>(),
2021-12-12 22:43:24 -05:00
handoff: '',
2021-12-22 08:35:48 -05:00
aliases: new Map<string, string>(),
devMode: false
2021-12-12 22:43:24 -05:00
}
2021-12-13 00:14:09 -05:00
export function reverseAliasMap() {
const map = new Map<string, string>();
for(const [u, v] of system.aliases.entries()) {
map.set(v, u)
}
return map;
}
2021-12-12 22:43:24 -05:00
function checkpoint(string: string) {
console.log(chalk.black.bgAnsi256(204)(' ' + string + ' '));
}
export function autoColorString(string: string) {
let colorCode = 0;
for(const char of md5(string)) colorCode += char.charCodeAt(0);
colorCode %= 6 ** 3;
colorCode += 16;
return chalk.ansi256(colorCode)(string);
2021-12-12 10:53:26 -05:00
}
2021-12-12 11:23:03 -05:00
export const exec = async (s: string, echo = true) => {
2021-12-12 10:53:26 -05:00
if(echo) console.log(chalk.cyan('@ ') + chalk.ansi256(242)(s));
2021-12-22 08:35:48 -05:00
const args: (string | number | boolean)[] = [];
for(const arg of s.split(' ')) {
const asNum = parseFloat(arg);
const isTrue = arg.toLowerCase() === 'true';
const isBoolean = isTrue || arg.toLowerCase() === 'false';
if(isBoolean) {
args.push(isTrue);
} else if(!isNaN(asNum)) {
args.push(asNum)
} else {
args.push(arg);
}
}
2021-12-22 08:48:35 -05:00
return await executor(...args);
2021-12-12 10:53:26 -05:00
};
2021-12-11 23:03:55 -05:00
2021-12-12 22:43:24 -05:00
export const kernel = {
create: create,
2021-12-11 23:03:55 -05:00
quit() {
console.log('Shutting down');
2021-12-12 17:09:52 -05:00
setTimeout(() => process.exit(0), 0);
2021-12-12 10:53:26 -05:00
},
2021-12-12 22:43:24 -05:00
ls: ls,
save: save,
2021-12-12 10:53:26 -05:00
reset() {
2021-12-12 23:03:51 -05:00
// TODO add a user interaction requirement here... its kindof rm -rf...
2021-12-12 10:53:26 -05:00
system.handoff = '';
system.instances = new Map();
2021-12-12 22:43:24 -05:00
system.aliases = new Map();
2021-12-12 10:53:26 -05:00
console.log('System has been reset.');
},
exec: exec,
2021-12-12 23:03:51 -05:00
async invoke(location: string, fn: string, ...args: string[]) {
if(system.aliases.has(location)) {
location = system.aliases.get(location);
}
if(!system.instances.has(location)) {
2021-12-12 23:26:22 -05:00
throw new Error('INVOCATION_TARGET_DOES_NOT_EXIST: ' + location);
2021-12-12 23:03:51 -05:00
}
const instance = system.instances.get(location);
if(!(fn in instance.functions)) {
throw new Error('FUNCTION_DOES_NOT_EXIST_ON_INVOCATION_TARGET');
}
2021-12-22 04:25:12 -05:00
const bound = instance.functions[fn].bind(instance.privateScope);
2021-12-22 08:48:35 -05:00
const result = await bound(...args);
return result;
2021-12-12 17:09:52 -05:00
},
async script(path: string) {
const fullPath = resolve(path);
const lines = readFileSync(fullPath).toString().split('\n').map(v => v.trim());
for(const line of lines) {
await exec(line);
}
2021-12-12 23:03:51 -05:00
},
2021-12-22 08:35:48 -05:00
set(variable: string, ...rest: any) {
if(rest.length > 1) {
(system as any)[variable] = rest.join(' ');
} else {
(system as any)[variable] = rest[0];
}
2021-12-22 04:54:25 -05:00
},
help: help
2021-12-12 17:09:52 -05:00
};
const executor = createExecutor(kernel);
2021-12-11 23:03:55 -05:00
2021-12-12 11:23:03 -05:00
(async () => {
2021-12-12 17:09:52 -05:00
if(existsSync('.system')) {
2021-12-22 04:25:12 -05:00
const state: ParsedSystemState = JSON.parse(readFileSync('.system').toString());
2021-12-12 17:09:52 -05:00
system.handoff = state.handoff;
2021-12-22 04:25:12 -05:00
for(const [id, info] of Object.entries(state.instances)) {
const [alias] = Object.entries(state.aliases).find(([,tryId]) => tryId === id) ?? [undefined];
2021-12-12 22:43:24 -05:00
await kernel.create(info.module, alias, id);
2021-12-22 04:25:12 -05:00
system.instances.get(id).privateScope.config = info.config;
2021-12-12 11:23:03 -05:00
}
2021-12-12 22:43:24 -05:00
checkpoint('System State Restored');
2021-12-12 10:53:26 -05:00
}
2021-12-12 17:09:52 -05:00
if(startupFile) {
await exec('script ' + startupFile);
2021-12-12 22:43:24 -05:00
checkpoint('Script Finished');
2021-12-12 17:09:52 -05:00
await exec('quit');
2021-12-12 23:03:51 -05:00
return;
2021-12-12 17:09:52 -05:00
}
2021-12-12 23:03:51 -05:00
await exec(system.handoff);
checkpoint('Handoff Finished');
serverline.init({ prompt: chalk.cyan('λ ') });
2021-12-12 22:43:24 -05:00
serverline.setCompletion(Object.keys(kernel));
2021-12-22 08:48:35 -05:00
serverline.on('line', async (a: string) => {
2021-12-12 22:43:24 -05:00
if(a.trim() === "") return;
2021-12-22 08:48:35 -05:00
const res = await exec(a, false);
if(res !== undefined) {
console.log(chalk.ansi256(211)('< ' + res));
}
2021-12-12 22:43:24 -05:00
});
2021-12-12 23:03:51 -05:00
serverline.on('SIGINT', () => exec('quit'));
2021-12-22 04:54:25 -05:00
console.log('For help, type help');
2021-12-12 22:43:24 -05:00
})().catch((e: Error) => {
console.error(e);
});
2021-12-12 23:03:51 -05:00
2021-12-12 22:43:24 -05:00
checkpoint('Kernel Loaded');
2021-12-22 05:07:27 -05:00
import '@echo off';