Skip to content

Commit

Permalink
feat(eval): support persistent storage, fix #96
Browse files Browse the repository at this point in the history
  • Loading branch information
shigma committed Apr 3, 2021
1 parent fa03ede commit 1d8ee8f
Show file tree
Hide file tree
Showing 3 changed files with 35 additions and 12 deletions.
6 changes: 3 additions & 3 deletions packages/plugin-eval/src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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)
}

Expand Down Expand Up @@ -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)

Expand Down
8 changes: 4 additions & 4 deletions packages/plugin-eval/src/loader.ts
Original file line number Diff line number Diff line change
Expand Up @@ -81,10 +81,10 @@ const files: Record<string, FileCache> = {}
const cachedFiles: Record<string, FileCache> = {}

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))
Expand Down Expand Up @@ -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}"`)
Expand Down
33 changes: 28 additions & 5 deletions packages/plugin-eval/src/worker.ts
Original file line number Diff line number Diff line change
@@ -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 */

Expand All @@ -27,10 +28,11 @@ import { MainAPI } from '.'
export * from './loader'

export interface WorkerConfig {
setupFiles?: Record<string, string>
root?: string
inspect?: InspectOptions
addonRoot?: string
cacheFile?: string
storageFile?: string
setupFiles?: Record<string, string>
}

export interface WorkerData extends WorkerConfig {
Expand Down Expand Up @@ -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<SerializableObject>
user: User.Observed<any>
channel: Channel.Observed<any>
send(...param: any[]): Promise<void>
exec(message: string): Promise<string>
}

let storage: Observed<SerializableObject>
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) {
Expand Down Expand Up @@ -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) {
Expand Down Expand Up @@ -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)
Expand Down

0 comments on commit 1d8ee8f

Please sign in to comment.