Skip to content

Commit

Permalink
feat(eval): delegated ctx.worker
Browse files Browse the repository at this point in the history
  • Loading branch information
shigma committed Apr 10, 2021
1 parent a280e52 commit 1e23160
Show file tree
Hide file tree
Showing 4 changed files with 31 additions and 34 deletions.
5 changes: 3 additions & 2 deletions packages/koishi-core/src/context.ts
Original file line number Diff line number Diff line change
Expand Up @@ -185,6 +185,7 @@ export class Context {
const modules = deps.map(safeRequire)
if (modules.includes(added)) this.teleport(modules, callback)
})
return this
}

plugin<T extends Plugin>(plugin: T, options?: Plugin.Config<T>): this
Expand Down Expand Up @@ -502,11 +503,11 @@ export class Context {
get() {
if (!this.app[privateKey]) return
const value = Object.create(this.app[privateKey])
value[Context.current] = this
defineProperty(value, Context.current, this)
return value
},
set(value) {
this.app[privateKey] = value
defineProperty(this.app, privateKey, value)
},
})
}
Expand Down
36 changes: 14 additions & 22 deletions packages/plugin-eval/src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@ import { WorkerResponse } from './worker'
export * from './main'

declare module 'koishi-core' {
interface App {
interface Context {
worker: EvalWorker
}

Expand Down Expand Up @@ -68,23 +68,15 @@ const logger = new Logger('eval')

export const name = 'eval'

Context.delegate('worker')

export function apply(ctx: Context, config: Config = {}) {
const { prefix, authority } = config = { ...defaultConfig, ...config }
const { app } = ctx

// addons are registered in another plugin
if (config.root) {
ctx.plugin(addon, config)
}
ctx.worker = new EvalWorker(ctx, config)

ctx.on('connect', () => {
app.worker = new EvalWorker(ctx.app, config)
app.worker.start()
})

ctx.before('disconnect', () => {
return app.worker?.stop()
})
// addons are registered in another plugin
if (config.root) ctx.plugin(addon, config)

ctx.before('command', ({ command, session }) => {
if (command.config.noEval && session._isEval) {
Expand All @@ -96,7 +88,7 @@ export function apply(ctx: Context, config: Config = {}) {
const channelAccess = Trap.resolve(config.channelFields)

// worker should be running for all the features
ctx = ctx.intersect(() => app.worker?.state === EvalWorker.State.open)
ctx = ctx.intersect(() => ctx.worker?.state === EvalWorker.State.open)

const command = ctx.command('evaluate [expr:text]', '执行 JavaScript 脚本', { noEval: true })
.alias('eval')
Expand All @@ -108,7 +100,7 @@ export function apply(ctx: Context, config: Config = {}) {
})
.action(async ({ options }) => {
if (options.restart) {
await app.worker.restart()
await ctx.worker.restart()
return '子线程已重启。'
}
})
Expand Down Expand Up @@ -137,11 +129,11 @@ export function apply(ctx: Context, config: Config = {}) {
}

const timer = setTimeout(async () => {
await app.worker.restart()
await ctx.worker.restart()
_resolve('执行超时。')
}, config.timeout)

const dispose = app.worker.onError((error: Error) => {
const dispose = ctx.worker.onError((error: Error) => {
let message = ERROR_CODES[error['code']]
if (!message) {
logger.warn(error)
Expand All @@ -150,7 +142,7 @@ export function apply(ctx: Context, config: Config = {}) {
_resolve(message)
})

app.worker.remote.eval(scope, {
ctx.worker.remote.eval(scope, {
silent: options.slient,
source: expr,
}).then(_resolve, (error) => {
Expand Down Expand Up @@ -204,9 +196,9 @@ function addon(ctx: Context, config: EvalConfig) {
.option('update', '-u 更新扩展模块', { authority: 3 })
.action(async ({ options }) => {
if (!options.update) return
const { files, summary } = await git.pull(ctx.app.worker.config.gitRemote)
const { files, summary } = await git.pull(ctx.worker.config.gitRemote)
if (!files.length) return '所有模块均已是最新。'
await ctx.app.worker.restart()
await ctx.worker.restart()
return `更新成功!(${summary.insertions}A ${summary.deletions}D ${summary.changes}M)`
})
})
Expand Down Expand Up @@ -252,7 +244,7 @@ function addon(ctx: Context, config: EvalConfig) {

Trap.action(cmd, userAccess, channelAccess, async ({ command, options, scope }, ...args) => {
const { name } = command
return ctx.app.worker.remote.callAddon(scope, { name, args, options })
return ctx.worker.remote.callAddon(scope, { name, args, options })
})

options.forEach((config) => {
Expand Down
22 changes: 13 additions & 9 deletions packages/plugin-eval/src/main.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import { App, Command, Channel, Argv as IArgv, User } from 'koishi-core'
import { App, Command, Channel, Argv as IArgv, User, Context } from 'koishi-core'
import { Logger, Observed, pick, union } from 'koishi-utils'
import { Worker, ResourceLimits } from 'worker_threads'
import { WorkerAPI, WorkerConfig, WorkerData, ScopeData } from './worker'
Expand Down Expand Up @@ -174,13 +174,17 @@ export class EvalWorker {

static readonly State = State

constructor(public app: App, public config: EvalConfig) {
this.local = new MainAPI(app)
constructor(public ctx: Context, public config: EvalConfig) {
this.local = new MainAPI(ctx.app)
ctx.on('connect', () => this.start())
ctx.before('disconnect', () => this.stop())
}

async start() {
// delegated class methods which use instance properties
// should be written in arrow functions
start = async () => {
this.state = State.opening
await this.app.parallel('eval/before-start')
await this.ctx.parallel('eval/before-start')
process.on('beforeExit', this.beforeExit)

let index = 0
Expand All @@ -206,7 +210,7 @@ export class EvalWorker {
this.remote = wrap(this.worker)

await this.remote.start().then((response) => {
this.app.emit('eval/start', response)
this.ctx.emit('eval/start', response)
logger.debug('worker started')
this.state = State.open

Expand All @@ -222,20 +226,20 @@ export class EvalWorker {
this.prevent = true
}

async stop() {
stop = async () => {
this.state = State.closing
this.beforeExit()
process.off('beforeExit', this.beforeExit)
await this.worker?.terminate()
}

async restart() {
restart = async () => {
this.state = State.closing
await this.worker?.terminate()
await this.promise
}

onError(listener: (error: Error) => void) {
onError = (listener: (error: Error) => void) => {
this.worker.on('error', listener)
return () => this.worker.off('error', listener)
}
Expand Down
2 changes: 1 addition & 1 deletion packages/plugin-eval/tests/index.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ import { resolve } from 'path'
import { promises as fs } from 'fs'
import * as eval from 'koishi-plugin-eval'

const app = new App()
const app = new App({ mockStart: false })

app.plugin(eval, {
root: resolve(__dirname, 'fixtures'),
Expand Down

0 comments on commit 1e23160

Please sign in to comment.