diff --git a/packages/plugin-eval/src/index.ts b/packages/plugin-eval/src/index.ts index ed7b614bf7..52cf64db45 100644 --- a/packages/plugin-eval/src/index.ts +++ b/packages/plugin-eval/src/index.ts @@ -69,7 +69,7 @@ export function apply(ctx: Context, config: Config = {}) { const { app } = ctx // addons are registered in another plugin - if (config.addonRoot) { + if (config.root) { ctx.plugin(addon, config) } @@ -182,8 +182,8 @@ export function apply(ctx: Context, config: Config = {}) { function addon(ctx: Context, config: EvalConfig) { const logger = ctx.logger('eval:addons') - const root = config.addonRoot = resolve(process.cwd(), config.addonRoot) - config.dataKeys.push('addonNames', 'addonRoot') + const root = config.root = resolve(process.cwd(), config.root) + config.dataKeys.push('addonNames', 'root') const git = Git(root) diff --git a/packages/plugin-eval/src/loader.ts b/packages/plugin-eval/src/loader.ts index bc17ac5778..5ba62ce63b 100644 --- a/packages/plugin-eval/src/loader.ts +++ b/packages/plugin-eval/src/loader.ts @@ -81,10 +81,10 @@ const files: Record = {} const cachedFiles: Record = {} export default async function prepare() { - if (!config.addonRoot) return + if (!config.root) return - const tsconfigPath = resolve(config.addonRoot, 'tsconfig.json') - const cachePath = resolve(config.addonRoot, config.cacheFile || '.koishi/cache') + const tsconfigPath = resolve(config.root, 'tsconfig.json') + const cachePath = resolve(config.root, config.cacheFile || '.koishi/cache') await Promise.all([ fs.readFile(tsconfigPath, 'utf8').then((tsconfig) => { Object.assign(compilerOptions, json5.parse(tsconfig)) @@ -126,7 +126,7 @@ async function loadSource(path: string): Promise<[source: string, identifier: st for (const postfix of suffixes) { try { const target = path + postfix - return [await fs.readFile(resolve(config.addonRoot, target), 'utf8'), target] + return [await fs.readFile(resolve(config.root, target), 'utf8'), target] } catch {} } throw new Error(`cannot load source file "${path}"`) diff --git a/packages/plugin-eval/src/worker.ts b/packages/plugin-eval/src/worker.ts index 74a9f0249c..e8d9dafa5e 100644 --- a/packages/plugin-eval/src/worker.ts +++ b/packages/plugin-eval/src/worker.ts @@ -1,8 +1,9 @@ -import { Channel, User, Logger, escapeRegExp, observe, difference, Time, segment, Random } from 'koishi-core' +import { Channel, User, Logger, escapeRegExp, observe, difference, Time, segment, Random, noop, Observed } from 'koishi-core' import { parentPort, workerData } from 'worker_threads' import { InspectOptions, formatWithOptions } from 'util' import { findSourceMap } from 'module' -import { dirname, sep } from 'path' +import { resolve, dirname, sep } from 'path' +import { promises as fs } from 'fs' /* eslint-disable import/first */ @@ -27,10 +28,11 @@ import { MainAPI } from '.' export * from './loader' export interface WorkerConfig { - setupFiles?: Record + root?: string inspect?: InspectOptions - addonRoot?: string cacheFile?: string + storageFile?: string + setupFiles?: Record } export interface WorkerData extends WorkerConfig { @@ -77,14 +79,28 @@ export interface ScopeData { channelWritable: Channel.Field[] } +type Serializable = string | number | boolean | Serializable[] | SerializableObject +type SerializableObject = { [K in string]: Serializable } + export interface Scope { + storage: Observed user: User.Observed channel: Channel.Observed send(...param: any[]): Promise exec(message: string): Promise } +let storage: Observed +const storagePath = resolve(config.root || process.cwd(), config.storageFile || '.koishi/storage') + +async function loadStorage() { + const source = await fs.readFile(storagePath, 'utf8') + return JSON.parse(source) +} + export const Scope = ({ id, user, userWritable, channel, channelWritable }: ScopeData): Scope => ({ + storage, + user: user && observe(user, async (diff) => { const diffKeys = difference(Object.keys(diff), userWritable) if (diffKeys.length) { @@ -138,6 +154,7 @@ export class WorkerAPI { async sync(scope: Scope) { await scope.user?._update() await scope.channel?._update() + await scope.storage?._update() } async eval(data: ScopeData, options: EvalOptions) { @@ -198,7 +215,13 @@ export function mapDirectory(identifier: string, filename: string) { Object.values(config.setupFiles).map(require) async function start() { - await prepare() + const data = await Promise.all([loadStorage().catch(noop), prepare()]) + storage = observe(data[0] || {}, async (diff) => { + console.log(diff) + await fs.mkdir(dirname(storagePath), { recursive: true }) + await fs.writeFile(storagePath, Buffer.from(JSON.stringify(storage))) + }) + response.commands = Object.keys(commandMap) mapDirectory('koishi/utils/', require.resolve('koishi-utils')) mapDirectory('koishi/', __filename)