From 67a9a9715d691367c1d6a66c0d32f6f80fd6099a Mon Sep 17 00:00:00 2001 From: Valerie Date: Sun, 12 Dec 2021 22:43:24 -0500 Subject: [PATCH] better error handling & messaging --- .system | 16 ++---- loader.mjs | 20 +++++-- package.json | 4 +- src/commands/create.ts | 36 ++++++++++-- src/commands/ls.ts | 15 +++++ src/commands/save.ts | 26 +++++++++ src/externals.d.ts | 3 + src/index.ts | 127 ++++++++++++++++------------------------- tsconfig.json | 3 +- vsh/install.vsh | 1 + yarn.lock | 33 ++++++++++- 11 files changed, 182 insertions(+), 102 deletions(-) create mode 100644 src/commands/ls.ts create mode 100644 src/commands/save.ts diff --git a/.system b/.system index c86bac2..76bd100 100644 --- a/.system +++ b/.system @@ -1,21 +1,17 @@ { "handoff": "", "instances": { - "72C17CDFC5F943E0A41155D892419843": { + "50C60F4EF04D41B38A2EB573788829DA": { "config": {}, "module": "systemd" }, - "D2A1E19739BB4CC08DD7192164CD4D67": { - "config": {}, - "module": "sshd" - }, - "768C13637962402D803215C97D8F04CD": { - "config": {}, - "module": "systemd" - }, - "0CEB261DB70A4A51BC80E15D782D8D98": { + "C34D0DE00AB3454195E9249BF3596610": { "config": {}, "module": "sshd" } + }, + "aliases": { + "systemd": "50C60F4EF04D41B38A2EB573788829DA", + "sshd": "C34D0DE00AB3454195E9249BF3596610" } } \ No newline at end of file diff --git a/loader.mjs b/loader.mjs index 1604afa..2e5a2b9 100644 --- a/loader.mjs +++ b/loader.mjs @@ -16,6 +16,7 @@ let echo = true; export async function resolve(specifier, context, defaultResolver) { if(echo === false) { } else if(imports === 0) { + console.log(chalk.black.bgAnsi256(204)(' Welcome to Vogue System Runtime ')); console.log(chalk.green('#'), chalk.ansi256(242)('@kernel')) } else { console.log(chalk.green('#'), chalk.ansi256(242)(specifier)); @@ -26,13 +27,20 @@ export async function resolve(specifier, context, defaultResolver) { } const maps = { - 'file:///boot': pathResolve(__dirname, 'src', 'index.ts'), - '@kernel:base': pathResolve(__dirname, 'src', 'index.ts'), - '@kernel:log-hook': pathResolve(__dirname, 'src', 'logHook.ts'), + 'file:///boot': pathResolve(__dirname, 'src', 'index.ts'), + + '@kernel:base': pathResolve(__dirname, 'src', 'index.ts'), + '@kernel:log-hook': pathResolve(__dirname, 'src', 'logHook.ts'), + '@commands:executor': pathResolve(__dirname, 'src', 'commands', 'executor.ts'), - '@builtin:systemd': pathResolve(__dirname, 'src', 'modules', 'systemd.ts'), - '@builtin:sshd': pathResolve(__dirname, 'src', 'modules', 'sshd.ts'), - '@echo off': pathResolve(__dirname, 'src', 'noop.ts') + '@commands:create': pathResolve(__dirname, 'src', 'commands', 'create.ts'), + '@commands:ls': pathResolve(__dirname, 'src', 'commands', 'ls.ts'), + '@commands:save': pathResolve(__dirname, 'src', 'commands', 'save.ts'), + + '@builtin:systemd': pathResolve(__dirname, 'src', 'modules', 'systemd.ts'), + '@builtin:sshd': pathResolve(__dirname, 'src', 'modules', 'sshd.ts'), + + '@echo off': pathResolve(__dirname, 'src', 'noop.ts') }; const matches = Object.keys(maps).filter(map => specifier.startsWith(map)); diff --git a/package.json b/package.json index a7cd3b3..b6d4bc5 100644 --- a/package.json +++ b/package.json @@ -5,13 +5,15 @@ "license": "MIT", "type": "module", "scripts": { - "start": "(clear || cls) && node --no-warnings --loader ./loader.mjs /boot", + "start": "(clear || cls) && node --no-warnings --unhandled-rejections=strict --loader ./loader.mjs /boot", "tsc": "tsc" }, "dependencies": { + "@types/md5": "^2.3.1", "@types/node": "^16.11.12", "@types/uuid": "^8.3.3", "chalk": "^5.0.0", + "md5": "^2.3.0", "serverline": "^1.5.0", "ssh2": "^1.5.0", "telnet": "^0.0.1", diff --git a/src/commands/create.ts b/src/commands/create.ts index e757de7..ac91ab3 100644 --- a/src/commands/create.ts +++ b/src/commands/create.ts @@ -1,7 +1,33 @@ -import createExecutor from "./executor.js"; +import { system, autoColorString } from '@kernel:base'; +import * as uuid from 'uuid'; -export const create = createExecutor({ - pawn() { - +export default async function create(module: string, name: string, id: string) { + if(!module || typeof module !== 'string' || module.trim() === '') { + throw new Error('INVALID_MODULE_NAME'); } -}) \ No newline at end of file + if(name && (typeof name !== 'string' || name.trim() === '')) { + throw new Error('IVALID_MODULE_ALIAS'); + } + name ??= module; + if(system.aliases.has(name)) { + if(name === module) { + throw new Error('DEFAULT_MODULE_ALREADY_EXISTS'); + } else { + throw new Error('MODULE_ALIAS_TAKEN'); + } + } + const imported = (await import('@builtin:' + module)); + const functions = 'default' in imported ? imported.default : imported; + id ??= uuid.v4().replace(/-/g, '').toUpperCase(); + system.instances.set(id, { + config: {}, + ram: {}, + module: module, + functions + }); + if(name) { + system.aliases.set(name, id); + } + console.log('Created instance of', autoColorString(module)) + return id; +} \ No newline at end of file diff --git a/src/commands/ls.ts b/src/commands/ls.ts new file mode 100644 index 0000000..f3229f3 --- /dev/null +++ b/src/commands/ls.ts @@ -0,0 +1,15 @@ +import { system, autoColorString } from '@kernel:base'; +import chalk from 'chalk'; + +export default function ls(flags: any) { + // if(flags) console.log(flags) + + console.log('Instances', chalk.ansi256(242)('(' + system.instances.size + ')')); + for(const [k, v] of system.instances) { + console.log( + ' ' + + autoColorString(k.substring(0, 4)) + + ':', JSON.stringify(v.config, null, 2).replace('\n', ' ').trim() + ); + } +} \ No newline at end of file diff --git a/src/commands/save.ts b/src/commands/save.ts new file mode 100644 index 0000000..5e97c1f --- /dev/null +++ b/src/commands/save.ts @@ -0,0 +1,26 @@ +import { system } from '@kernel:base'; +import { resolve } from 'path'; +import { writeFileSync } from 'fs'; + +export default function save() { + const timeStart = new Date().getTime(); + const obj: any = { + handoff: system.handoff, + instances: {}, + aliases: {} + }; + for(const [id, info] of system.instances.entries()) { + obj.instances[id] = { + config: info.config, + module: info.module + } + } + for(const [alias, id] of system.aliases.entries()) { + obj.aliases[alias] = id; + } + const systemString = JSON.stringify(obj, null, 2); + const fullPath = resolve('.system'); + writeFileSync(fullPath, systemString); + const elapsed = new Date().getTime() - timeStart; + console.log('System saved to ' + fullPath + ' in ' + elapsed + ' ms') +} \ No newline at end of file diff --git a/src/externals.d.ts b/src/externals.d.ts index a8ebaa8..847853f 100644 --- a/src/externals.d.ts +++ b/src/externals.d.ts @@ -2,6 +2,9 @@ declare module "serverline"; declare module "telnet"; declare module "@kernel:base"; declare module "@commands:executor"; +declare module "@commands:create"; +declare module "@commands:ls"; +declare module "@commands:save"; declare module "@builtin:systemd"; declare module "@builtin:sshd"; declare module "@echo off"; \ No newline at end of file diff --git a/src/index.ts b/src/index.ts index c291a99..75de3d7 100644 --- a/src/index.ts +++ b/src/index.ts @@ -1,14 +1,16 @@ /// -// console.clear(); - import '@kernel:log-hook'; import createExecutor from '@commands:executor'; +import create from '@commands:create'; +import ls from '@commands:ls'; +import save from '@commands:save'; import * as uuid from 'uuid'; import serverline from 'serverline'; import { existsSync, readFileSync, writeFileSync } from 'fs'; import { resolve } from 'path' import chalk from 'chalk'; +import md5 from 'md5'; const args = process.argv.slice(2); const [ startupFile ] = args; @@ -20,9 +22,22 @@ type Instance = { functions: any; }; -const system = { +export const system = { instances: new Map(), - handoff: '' + handoff: '', + aliases: new Map() +} + +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); } export const exec = async (s: string, echo = true) => { @@ -30,71 +45,18 @@ export const exec = async (s: string, echo = true) => { await executor(...(s.split(' '))); }; -serverline.init({ - prompt: chalk.cyan('λ ') -}); - -const kernel = { - async create(module: string, name: string) { - // TODO assert module. - try { - const imported = (await import('@builtin:' + module)); - const functions = 'default' in imported ? imported.default : imported; - const id = name ?? uuid.v4().replace(/-/g, '').toUpperCase(); - system.instances.set(id, { - config: {}, - ram: {}, - module: module, - functions - }); - return id; - } catch(e) { - console.log(e); - e.trace(); - } - }, +export const kernel = { + create: create, quit() { console.log('Shutting down'); - serverline.close(); setTimeout(() => process.exit(0), 0); }, - ls(flags: any) { - if(flags) console.log(flags) - - console.log('Instances', chalk.ansi256(242)('(' + system.instances.size + ')')); - for(const [k, v] of system.instances) { - let colorCode = 0; - for(const char of k) colorCode += char.charCodeAt(0); - colorCode %= 6 ** 3; - colorCode += 16; - console.log( - ' ' - + chalk.ansi256(colorCode)(k.substring(0, 8)) - + ':', JSON.stringify(v.config, null, 2).replace('\n', ' ').trim() - ); - } - }, - save() { - const timeStart = new Date().getTime(); - const obj: any = { - handoff: system.handoff, - instances: {} - }; - for(const [id, info] of system.instances.entries()) { - obj.instances[id] = { - config: info.config, - module: info.module - } - } - const systemString = JSON.stringify(obj, null, 2); - const fullPath = resolve('.system'); - writeFileSync(fullPath, systemString); - const elapsed = new Date().getTime() - timeStart; - console.log('System saved to ' + fullPath + ' in ' + elapsed + ' ms') - }, + ls: ls, + save: save, reset() { system.handoff = ''; system.instances = new Map(); + system.aliases = new Map(); console.log('System has been reset.'); }, exec: exec, @@ -112,35 +74,44 @@ const kernel = { const executor = createExecutor(kernel); -serverline.on('line', (a: string) => { - if(a.trim() === "") return; - exec(a, false); -}) - -serverline.on('SIGINT', () => { - exec('quit'); -}); - - - (async () => { if(existsSync('.system')) { const state: any = JSON.parse(readFileSync('.system').toString()); system.handoff = state.handoff; for(const [id, info] of Object.entries(state.instances)) { - await kernel.create(info.module, id); + const [alias] = + Object.entries(state.aliases) + .find(([,tryId]) => tryId === id) + ?? [undefined]; + await kernel.create(info.module, alias, id); system.instances.get(id).config = info.config; } + checkpoint('System State Restored'); } if(startupFile) { await exec('script ' + startupFile); - console.log(chalk.green('Script finished, exitting...')); + checkpoint('Script Finished'); await exec('quit'); + } else { } -})() + serverline.init({ + prompt: chalk.cyan('λ ') + }); + serverline.setCompletion(Object.keys(kernel)); + serverline.on('line', (a: string) => { + if(a.trim() === "") return; + exec(a, false); + }); + + serverline.on('SIGINT', () => { + exec('quit'); + }); + +})().catch((e: Error) => { + console.error(e); +}); +checkpoint('Kernel Loaded'); import '@echo off'; - -serverline.setCompletion(Object.keys(kernel)) \ No newline at end of file diff --git a/tsconfig.json b/tsconfig.json index bef4e22..bfc7fb6 100644 --- a/tsconfig.json +++ b/tsconfig.json @@ -6,7 +6,8 @@ "moduleResolution": "Node", "baseUrl": "./src", "outDir": "./dist", - "declaration": true + "declaration": true, + "allowSyntheticDefaultImports": true }, "paths": { "@commands:executor": [""] diff --git a/vsh/install.vsh b/vsh/install.vsh index dca1810..5d7683f 100644 --- a/vsh/install.vsh +++ b/vsh/install.vsh @@ -1,3 +1,4 @@ +reset create systemd create sshd invoke systemd add sshd invoke sshd start diff --git a/yarn.lock b/yarn.lock index 62719cd..4bb3718 100644 --- a/yarn.lock +++ b/yarn.lock @@ -39,7 +39,14 @@ resolved "https://registry.yarnpkg.com/@types/json5/-/json5-0.0.29.tgz#ee28707ae94e11d2b827bcbe5270bcea7f3e71ee" integrity sha1-7ihweulOEdK4J7y+UnC86n8+ce4= -"@types/node@^16.11.12": +"@types/md5@^2.3.1": + version "2.3.1" + resolved "https://registry.yarnpkg.com/@types/md5/-/md5-2.3.1.tgz#010bcf3bb50a2cff3a574cb1c0b4051a9c67d6bc" + integrity sha512-OK3oe+ALIoPSo262lnhAYwpqFNXbiwH2a+0+Z5YBnkQEwWD8fk5+PIeRhYA48PzvX9I4SGNpWy+9bLj8qz92RQ== + dependencies: + "@types/node" "*" + +"@types/node@*", "@types/node@^16.11.12": version "16.11.12" resolved "https://registry.yarnpkg.com/@types/node/-/node-16.11.12.tgz#ac7fb693ac587ee182c3780c26eb65546a1a3c10" integrity sha512-+2Iggwg7PxoO5Kyhvsq9VarmPbIelXP070HMImEpbtGCoyWNINQj4wzjbQCXzdHTRXnqufutJb5KAURZANNBAw== @@ -103,6 +110,11 @@ chalk@^5.0.0: resolved "https://registry.yarnpkg.com/chalk/-/chalk-5.0.0.tgz#bd96c6bb8e02b96e08c0c3ee2a9d90e050c7b832" integrity sha512-/duVOqst+luxCQRKEo4bNxinsOQtMP80ZYm7mMqzuh5PociNL0PvmHFvREJ9ueYL2TxlHjBcmLCdmocx9Vg+IQ== +charenc@0.0.2: + version "0.0.2" + resolved "https://registry.yarnpkg.com/charenc/-/charenc-0.0.2.tgz#c0a1d2f3a7092e03774bfa83f14c0fc5790a8667" + integrity sha1-wKHS86cJLgN3S/qD8UwPxXkKhmc= + cpu-features@0.0.2: version "0.0.2" resolved "https://registry.yarnpkg.com/cpu-features/-/cpu-features-0.0.2.tgz#9f636156f1155fd04bdbaa028bb3c2fbef3cea7a" @@ -115,6 +127,11 @@ create-require@^1.1.0: resolved "https://registry.yarnpkg.com/create-require/-/create-require-1.1.1.tgz#c1d7e8f1e5f6cfc9ff65f9cd352d37348756c333" integrity sha512-dcKFX3jn0MpIaXjisoRvexIJVEKzaq7z2rZKxf+MSr9TkdmHmsU4m2lcLojrj/FHl8mk5VxMmYA+ftRkP/3oKQ== +crypt@0.0.2: + version "0.0.2" + resolved "https://registry.yarnpkg.com/crypt/-/crypt-0.0.2.tgz#88d7ff7ec0dfb86f713dc87bbb42d044d3e6c41b" + integrity sha1-iNf/fsDfuG9xPch7u0LQRNPmxBs= + debug@*: version "4.3.3" resolved "https://registry.yarnpkg.com/debug/-/debug-4.3.3.tgz#04266e0b70a98d4462e6e288e38259213332b664" @@ -127,6 +144,11 @@ diff@^4.0.1: resolved "https://registry.yarnpkg.com/diff/-/diff-4.0.2.tgz#60f3aecb89d5fae520c11aa19efc2bb982aade7d" integrity sha512-58lmxKSA4BNyLz+HHMUzlOEpg09FV+ev6ZMe3vJihgdxzgcwZ8VoEEPmALCZG9LmqfVoNMMKpttIYTVG6uDY7A== +is-buffer@~1.1.6: + version "1.1.6" + resolved "https://registry.yarnpkg.com/is-buffer/-/is-buffer-1.1.6.tgz#efaa2ea9daa0d7ab2ea13a97b2b8ad51fefbe8be" + integrity sha512-NcdALwpXkTm5Zvvbk7owOUSvVvBKDgKP5/ewfXEznmQFfs4ZRmanOeKBTjRVjka3QFoN6XJ+9F3USqfHqTaU5w== + json5@^1.0.1: version "1.0.1" resolved "https://registry.yarnpkg.com/json5/-/json5-1.0.1.tgz#779fb0018604fa854eacbf6252180d83543e3dbe" @@ -139,6 +161,15 @@ make-error@^1.1.1: resolved "https://registry.yarnpkg.com/make-error/-/make-error-1.3.6.tgz#2eb2e37ea9b67c4891f684a1394799af484cf7a2" integrity sha512-s8UhlNe7vPKomQhC1qFelMokr/Sc3AgNbso3n74mVPA5LTZwkB9NlXf4XPamLxJE8h0gh73rM94xvwRT2CVInw== +md5@^2.3.0: + version "2.3.0" + resolved "https://registry.yarnpkg.com/md5/-/md5-2.3.0.tgz#c3da9a6aae3a30b46b7b0c349b87b110dc3bda4f" + integrity sha512-T1GITYmFaKuO91vxyoQMFETst+O71VUPEU3ze5GNzDm0OWdP8v1ziTaAEPUr/3kLsY3Sftgz242A1SetQiDL7g== + dependencies: + charenc "0.0.2" + crypt "0.0.2" + is-buffer "~1.1.6" + minimist@^1.2.0: version "1.2.5" resolved "https://registry.yarnpkg.com/minimist/-/minimist-1.2.5.tgz#67d66014b66a6a8aaa0c083c5fd58df4e4e97602"