Files
Hydro/packages/hydrooj/src/entry/cli.ts
T
2022-10-06 13:29:07 +08:00

110 lines
4.0 KiB
TypeScript

/* eslint-disable import/no-dynamic-require */
/* eslint-disable no-await-in-loop */
import path from 'path';
import cac from 'cac';
import fs from 'fs-extra';
import { ObjectID } from 'mongodb';
import { Context } from '../context';
import db from '../service/db';
import {
addon, builtinModel, lib, script, service, setting,
} from './common';
const argv = cac().parse();
const COMMENTS = /((\/\/.*$)|(\/\*[\s\S]*?\*\/))/mg;
const ARR = /=>.*$/mg;
function parseParameters(fn: Function) {
const code = fn.toString()
.replace(COMMENTS, '')
.replace(ARR, '');
const result = code.slice(code.indexOf('(') + 1, code.indexOf(')'))
.match(/([^,]+)/g)?.map((i) => i.trim());
return result ?? [];
}
async function runScript(name: string, arg: any) {
const s = global.Hydro.script[name];
if (!s) return console.error('Script %s not found.', name);
if (typeof s.validate === 'function') arg = s.validate(arg);
return await s.run(arg, console.info);
}
async function cli() {
const [, modelName, func, ...args] = argv.args as [string, string, string, ...any[]];
if (modelName === 'script') {
let arg: any;
console.log(args.join(' '));
try {
arg = JSON.parse(args.join(' '));
} catch (e) {
return console.error('Invalid argument');
}
return await runScript(func, arg);
}
if (!global.Hydro.model[modelName]) {
return console.error(`Model ${modelName} doesn't exist.`);
}
if (!func) {
return console.log(Object.keys(global.Hydro.model[modelName]));
}
if (!global.Hydro.model[modelName][func]) {
return console.error(`Function ${func} doesn't exist in model ${modelName}.`);
}
if (typeof global.Hydro.model[modelName][func] !== 'function') {
return console.error(`${func} in model ${modelName} is not a function.`);
}
const parameterMin = global.Hydro.model[modelName][func].length;
const parameters = parseParameters(global.Hydro.model[modelName][func]);
const parameterMax = parameters.length;
if (args.length > parameterMax) {
console.error(`Too many arguments. Max ${parameterMax}`);
return console.error(parameters.join(', '));
}
if (args.length < parameterMin) {
console.error(`Too few arguments. Min ${parameterMin}`);
return console.error(parameters.join(', '));
}
for (let i = 0; i < args.length; i++) {
if ("'\"".includes(args[i][0]) && "'\"".includes(args[i][args[i].length - 1])) {
args[i] = args[i].substr(1, args[i].length - 2);
} else if (args[i].length === 24 && ObjectID.isValid(args[i])) {
args[i] = new ObjectID(args[i]);
} else if ((+args[i]).toString() === args[i]) {
args[i] = +args[i];
} else if (args[i].startsWith('~')) {
args[i] = argv.options[args[i].substr(1)];
}
}
let result = global.Hydro.model[modelName][func](...args);
if (result instanceof Promise) result = await result;
return console.log(result);
}
export async function load(ctx: Context) {
const pending = global.addons;
const fail = [];
require('../lib/i18n');
require('../utils');
require('../error');
await db.start();
await require('../settings').loadConfig();
await require('../model/system').runConfig();
await require('../service/storage').loadStorageService();
await ctx.root.start();
require('../lib/index');
await Promise.all([
lib(pending, fail, ctx),
service(pending, fail, ctx),
]);
await builtinModel(ctx);
await setting(pending, fail, require('../model/setting'));
ctx.plugin(require('../service/server'));
await addon(pending, fail, ctx);
const scriptDir = path.resolve(__dirname, '..', 'script');
for (const h of await fs.readdir(scriptDir)) {
ctx.loader.reloadPlugin(ctx, path.resolve(scriptDir, h), {}, `hydrooj/script/${h.split('.')[0]}`);
}
await script(pending, fail, ctx);
await cli();
}