fix: task disable error

Signed-off-by: MiaoWoo <admin@yumc.pw>
This commit is contained in:
MiaoWoo 2020-11-13 09:40:34 +08:00
parent c64d167893
commit d769a9c8ca
11 changed files with 122 additions and 70 deletions

View File

@ -133,6 +133,7 @@ export class MiaoScriptConsole implements Console {
} }
} }
stack(ex: Error, color: boolean = true): string[] { stack(ex: Error, color: boolean = true): string[] {
if (!ex) return []
let stack = ex.getStackTrace() let stack = ex.getStackTrace()
let cache = [(color ? '§c' : '') + ex] let cache = [(color ? '§c' : '') + ex]
//@ts-ignore //@ts-ignore

View File

@ -1,34 +1,66 @@
import { plugin } from './index' import { plugin } from './index'
import { injectable } from '@ccms/container' import { injectable } from '@ccms/container'
const AtomicInteger = Java.type("java.util.concurrent.atomic.AtomicInteger")
export namespace task { export namespace task {
@injectable() @injectable()
export abstract class TaskManager { export abstract class TaskManager {
protected cacheTasks = new Map<string, task.Task[]>() protected taskId: java.util.concurrent.atomic.AtomicInteger
protected cacheTasks = new Map<number, task.Task>()
protected pluginCacheTasks = new Map<string, Map<number, task.Task>>()
constructor() {
this.taskId = new AtomicInteger(0)
process.on('task.finish', (task: task.Task) => {
let taskId = task.getTaskId()
this.cacheTasks.delete(taskId)
let ownerName = task.getOwner()?.description.name
if (ownerName && this.pluginCacheTasks.has(ownerName)) {
this.pluginCacheTasks.get(ownerName).delete(taskId)
}
})
}
protected pluginCreate(plugin: plugin.Plugin, task: task.Task) { protected pluginCreate(plugin: plugin.Plugin, task: task.Task) {
if (!this.cacheTasks.has(plugin.description.name)) { if (!this.pluginCacheTasks.has(plugin.description.name)) {
this.cacheTasks.set(plugin.description.name, []) this.pluginCacheTasks.set(plugin.description.name, new Map())
} }
this.cacheTasks.get(plugin.description.name).push(task) this.pluginCacheTasks.get(plugin.description.name).set(task.getTaskId(), task)
return task return task
} }
protected pluginDisable(plugin: plugin.Plugin) { protected pluginDisable(plugin: plugin.Plugin) {
if (this.cacheTasks.has(plugin.description.name)) { if (this.pluginCacheTasks.has(plugin.description.name)) {
this.cacheTasks.get(plugin.description.name).forEach(task => task.cancel()) this.pluginCacheTasks.get(plugin.description.name).forEach((task) => {
this.cacheTasks.delete(plugin.description.name) task.cancel()
})
this.pluginCacheTasks.delete(plugin.description.name)
} }
} }
/**
* ID
*/
protected nextId() {
return this.taskId.incrementAndGet()
}
/** /**
* *
* @param func * @param func
*/ */
create(func: Function, plugin?: plugin.Plugin): task.Task { create(func: Function, plugin?: plugin.Plugin): task.Task {
if (Object.prototype.toString.call(func) !== "[object Function]") { throw TypeError('第一个参数 Task 必须为 function !') }; if (Object.prototype.toString.call(func) !== "[object Function]") { throw TypeError('第一个参数 Task 必须为 function !') };
let task = this.create0(func) let task = this.create0(plugin, func, this.nextId())
this.cacheTasks.set(task.getTaskId(), task)
if (plugin) { return this.pluginCreate(plugin, task) } if (plugin) { return this.pluginCreate(plugin, task) }
return task return task
} }
cancel(taskId: number) {
if (!this.cacheTasks.has(taskId)) { throw new Error(`Task ${taskId} not found!`) }
this.cacheTasks.get(taskId).cancel()
}
/** /**
* 线 * 线
* @param func * @param func
@ -41,22 +73,33 @@ export namespace task {
if (plugin) { return this.pluginDisable(plugin) } if (plugin) { return this.pluginDisable(plugin) }
this.disable0() this.disable0()
} }
protected abstract create0(func: Function): task.Task protected abstract create0(owner: plugin.Plugin, func: Function, id: number): task.Task
protected abstract disable0() protected abstract disable0()
} }
/** /**
* *
*/ */
export abstract class Task { export abstract class Task implements Cancelable {
protected plugin: any
protected func: Function protected func: Function
protected isAsync: boolean = false; protected isAsync: boolean = false;
protected laterTime: number = 0; protected laterTime: number = 0;
protected interval: number = 0; protected interval: number = 0;
protected owner: plugin.Plugin
protected taskId: number
protected innerTask: any
constructor(plugin: any, func: Function) { constructor(owner: plugin.Plugin, func: Function, id: number) {
this.plugin = plugin this.owner = owner
this.func = func this.func = func
this.taskId = id
}
getOwner() {
return this.owner
}
getTaskId() {
return this.taskId
} }
/** /**
@ -90,12 +133,15 @@ export namespace task {
* *
*/ */
cancel(): boolean { cancel(): boolean {
throw new Error("Method not implemented.") let result = this.cancel0()
process.emit('task.finish', this)
return result
} }
protected run(...args: any[]): void { protected run(...args: any[]): void {
try { try {
this.func(...args) this.func(...args)
!this.interval && process.emit('task.finish', this)
} catch (ex) { } catch (ex) {
console.console('§4插件执行任务时发生错误', ex) console.console('§4插件执行任务时发生错误', ex)
console.ex(ex) console.ex(ex)
@ -107,16 +153,21 @@ export namespace task {
* @param args * @param args
*/ */
submit(...args: any[]): Cancelable { submit(...args: any[]): Cancelable {
let cancelable = this.submit0(...args) this.innerTask = this.submit0(...args)
this.cancel = cancelable.cancel return this
return cancelable
} }
/** /**
* *
* @param args * @param args
*/ */
protected abstract submit0(...args: any[]): Cancelable protected abstract submit0(...args: any[]): any
/**
*
*/
protected cancel0(): boolean {
return this.innerTask?.cancel()
}
} }
/** /**
* *

View File

@ -7,17 +7,14 @@ const Callable = Java.type('java.util.concurrent.Callable')
@provideSingleton(task.TaskManager) @provideSingleton(task.TaskManager)
export class BukkitTaskManager extends task.TaskManager { export class BukkitTaskManager extends task.TaskManager {
@inject(plugin.PluginInstance) create0(owner: plugin.Plugin, func: Function, id: number): task.Task {
private pluginInstance: any return new BukkitTask(owner, func, id)
create0(func: Function): task.Task {
return new BukkitTask(this.pluginInstance, func)
} }
callSyncMethod(func: Function): any { callSyncMethod(func: Function): any {
return Bukkit.getScheduler().callSyncMethod(this.pluginInstance, new Callable({ call: () => func() })).get() return Bukkit.getScheduler().callSyncMethod(base.getInstance(), new Callable({ call: () => func() })).get()
} }
disable0() { disable0() {
Bukkit.getScheduler().cancelTasks(this.pluginInstance) Bukkit.getScheduler().cancelTasks(base.getInstance())
} }
} }
@ -26,9 +23,9 @@ export class BukkitTask extends task.Task {
let run = new BukkitRunnable({ run: () => this.run(...args) }) let run = new BukkitRunnable({ run: () => this.run(...args) })
let funcName = `runTask${this.interval ? 'Timer' : 'Later'}${this.isAsync ? 'Asynchronously' : ''}` let funcName = `runTask${this.interval ? 'Timer' : 'Later'}${this.isAsync ? 'Asynchronously' : ''}`
if (this.interval) { if (this.interval) {
return run[funcName](this.plugin, this.laterTime, this.interval) return run[funcName](base.getInstance(), this.laterTime, this.interval)
} else { } else {
return run[funcName](this.plugin, this.laterTime) return run[funcName](base.getInstance(), this.laterTime)
} }
} }
} }

View File

@ -6,17 +6,14 @@ let TimeUnit = Java.type('java.util.concurrent.TimeUnit')
@provideSingleton(task.TaskManager) @provideSingleton(task.TaskManager)
export class BungeeTaskManager extends task.TaskManager { export class BungeeTaskManager extends task.TaskManager {
@inject(plugin.PluginInstance) create0(owner: plugin.Plugin, func: Function, id: number): task.Task {
private pluginInstance: any return new BungeeTask(owner, func, id)
create0(func: Function): task.Task {
return new BungeeTask(this.pluginInstance, func)
} }
callSyncMethod(func: Function): any { callSyncMethod(func: Function): any {
return func() return func()
} }
disable0() { disable0() {
this.pluginInstance.getProxy().getScheduler().cancel(this.pluginInstance) base.getInstance().getProxy().getScheduler().cancel(base.getInstance())
} }
} }
@ -24,12 +21,12 @@ export class BungeeTask extends task.Task {
submit0(...args: any[]): task.Cancelable { submit0(...args: any[]): task.Cancelable {
let run = new Runnable({ run: () => this.run(...args) }) let run = new Runnable({ run: () => this.run(...args) })
if (this.isAsync) { if (this.isAsync) {
return this.plugin.getProxy().getScheduler().runAsync(this.plugin, run) return base.getInstance().getProxy().getScheduler().runAsync(base.getInstance(), run)
} }
if (this.interval) { if (this.interval) {
return this.plugin.getProxy().getScheduler().schedule(this.plugin, run, this.laterTime * 50, this.interval * 50, TimeUnit.MILLISECONDS) return base.getInstance().getProxy().getScheduler().schedule(base.getInstance(), run, this.laterTime * 50, this.interval * 50, TimeUnit.MILLISECONDS)
} else { } else {
return this.plugin.getProxy().getScheduler().schedule(this.plugin, run, this.laterTime * 50, TimeUnit.MILLISECONDS) return base.getInstance().getProxy().getScheduler().schedule(base.getInstance(), run, this.laterTime * 50, TimeUnit.MILLISECONDS)
} }
} }
} }

View File

@ -1,21 +1,25 @@
import { MiaoScriptConsole } from '@ccms/api' import { MiaoScriptConsole } from '@ccms/api'
let Nukkit = base.getInstance().getServer(); let Nukkit = base.getInstance().getServer()
let LogLevel = Java.type('cn.nukkit.utils.LogLevel')
let CommandSender = Java.type('cn.nukkit.command.CommandSender') let CommandSender = Java.type('cn.nukkit.command.CommandSender')
export class NukkitConsole extends MiaoScriptConsole { export class NukkitConsole extends MiaoScriptConsole {
sender(sender, ...args) { sender(sender, ...args) {
if (!(sender instanceof CommandSender)) { if (!(sender instanceof CommandSender)) {
this.error(`First parameter ${sender} not instanceof cn.nukkit.command.CommandSender can't send message!`) this.error(`First parameter ${sender} not instanceof cn.nukkit.command.CommandSender can't send message!`)
return; return
} }
if (Object.prototype.toString.call(args[0]) === "[object Array]") { if (Object.prototype.toString.call(args[0]) === "[object Array]") {
args[0].forEach(line => sender.sendMessage(this.prefix + line)) args[0].forEach(line => sender.sendMessage(this.prefix + line))
} else { } else {
sender.sendMessage(this.prefix + args.join(' ')); sender.sendMessage(this.prefix + args.join(' '))
} }
} }
console(...args: string[]): void { console(...args: string[]): void {
this.sender(Nukkit.getConsoleSender(), args.join(' ')); this.sender(Nukkit.getConsoleSender(), args.join(' '))
}
error(...args: any[]) {
this.logger.log(LogLevel.ERROR, this.name + args.join(' '))
} }
} }

View File

@ -5,17 +5,14 @@ const NukkitRunnable = Java.type('cn.nukkit.scheduler.NukkitRunnable')
@provideSingleton(task.TaskManager) @provideSingleton(task.TaskManager)
export class NukkitTaskManager extends task.TaskManager { export class NukkitTaskManager extends task.TaskManager {
@inject(plugin.PluginInstance) create0(owner: plugin.Plugin, func: Function, id: number): task.Task {
private pluginInstance: any return new NukkitTask(owner, func, id)
create0(func: Function): task.Task {
return new NukkitTask(this.pluginInstance, func)
} }
callSyncMethod(func: Function): any { callSyncMethod(func: Function): any {
return func() return func()
} }
disable0() { disable0() {
base.getInstance().getServer().getScheduler().cancelTask(this.pluginInstance) base.getInstance().getServer().getScheduler().cancelTask(base.getInstance())
} }
} }
@ -24,9 +21,9 @@ export class NukkitTask extends task.Task {
let run = new NukkitRunnable({ run: () => this.run(...args) }) let run = new NukkitRunnable({ run: () => this.run(...args) })
let funcName = `runTask${this.interval ? 'Timer' : 'Later'}${this.isAsync ? 'Asynchronously' : ''}` let funcName = `runTask${this.interval ? 'Timer' : 'Later'}${this.isAsync ? 'Asynchronously' : ''}`
if (this.interval) { if (this.interval) {
return run[funcName](this.plugin, this.laterTime, this.interval) return run[funcName](base.getInstance(), this.laterTime, this.interval)
} else { } else {
return run[funcName](this.plugin, this.laterTime) return run[funcName](base.getInstance(), this.laterTime)
} }
} }
} }

View File

@ -22,6 +22,19 @@ class Process extends EventEmitter {
} }
} }
platform = Packages.java.lang.System.getProperty("os.name") platform = Packages.java.lang.System.getProperty("os.name")
on(event: string | symbol, listener: (...args: any[]) => void) {
return super.on(event, (...args) => {
try {
listener(...args)
} catch (error) {
try {
super.emit('error', error)
} catch (error) {
console.ex(error)
}
}
})
}
nextTick(func: Function) { nextTick(func: Function) {
microTaskPool.execute(func) microTaskPool.execute(func)
} }

View File

@ -1,5 +1,5 @@
import { command, plugin, server } from '@ccms/api' import { command, plugin, server } from '@ccms/api'
import { provideSingleton, inject, Autowired } from '@ccms/container' import { provideSingleton, Autowired } from '@ccms/container'
import { getPluginCommandMetadata, getPluginTabCompleterMetadata } from './utils' import { getPluginCommandMetadata, getPluginTabCompleterMetadata } from './utils'
@provideSingleton(PluginCommandManager) @provideSingleton(PluginCommandManager)

View File

@ -7,7 +7,7 @@ export class PluginTaskManager {
private taskManager: task.TaskManager private taskManager: task.TaskManager
constructor() { constructor() {
process.on('plugin.after.disable', (plugin: plugin.Plugin) => this.cancelTask(plugin)) process.on('plugin.after.disable', this.cancelTask.bind(this))
} }
private cancelTask(pluginInstance: plugin.Plugin) { private cancelTask(pluginInstance: plugin.Plugin) {

View File

@ -9,24 +9,22 @@ const TimeUnit = Java.type('java.util.concurrent.TimeUnit')
@provideSingleton(task.TaskManager) @provideSingleton(task.TaskManager)
export class SpongeTaskManager extends task.TaskManager { export class SpongeTaskManager extends task.TaskManager {
@inject(plugin.PluginInstance)
private pluginInstance: any
private syncExecutor: any private syncExecutor: any
@postConstruct() @postConstruct()
initialize() { initialize() {
this.syncExecutor = Sponge.getScheduler().createSyncExecutor(this.pluginInstance) this.syncExecutor = Sponge.getScheduler().createSyncExecutor(base.getInstance())
} }
create0(func: Function): task.Task { create0(owner: plugin.Plugin, func: Function, id: number): task.Task {
return new SpongeTask(this.pluginInstance, func) return new SpongeTask(owner, func, id)
} }
callSyncMethod(func: Function): any { callSyncMethod(func: Function): any {
// @ts-ignore // @ts-ignore
return this.syncExecutor.schedule(new Callable({ call: () => func() }), java.lang.Long.valueOf(0), TimeUnit.NANOSECONDS).get() return this.syncExecutor.schedule(new Callable({ call: () => func() }), java.lang.Long.valueOf(0), TimeUnit.NANOSECONDS).get()
} }
disable0() { disable0() {
Sponge.getScheduler().getScheduledTasks(this.pluginInstance).forEach((task: task.Cancelable) => task.cancel()) Sponge.getScheduler().getScheduledTasks(base.getInstance()).forEach((task: task.Cancelable) => task.cancel())
} }
} }
@ -36,6 +34,6 @@ export class SpongeTask extends task.Task {
if (this.isAsync) { run.async() } if (this.isAsync) { run.async() }
if (this.laterTime) { run.delayTicks(this.laterTime) } if (this.laterTime) { run.delayTicks(this.laterTime) }
if (this.interval) { run.intervalTicks(this.interval) } if (this.interval) { run.intervalTicks(this.interval) }
return run.submit(this.plugin) return run.submit(base.getInstance())
} }
} }

View File

@ -2,7 +2,6 @@ import { task, plugin } from '@ccms/api'
import { inject, provideSingleton } from '@ccms/container' import { inject, provideSingleton } from '@ccms/container'
import thread_pool from '@ccms/common/dist/thread-pool' import thread_pool from '@ccms/common/dist/thread-pool'
const AtomicInteger = Java.type("java.util.concurrent.atomic.AtomicInteger")
const AtomicBoolean = Java.type("java.util.concurrent.atomic.AtomicBoolean") const AtomicBoolean = Java.type("java.util.concurrent.atomic.AtomicBoolean")
const Thread = Java.type('java.lang.Thread') const Thread = Java.type('java.lang.Thread')
@ -11,21 +10,19 @@ export class SpringTaskManager extends task.TaskManager {
@inject(plugin.PluginInstance) @inject(plugin.PluginInstance)
private pluginInstance: any private pluginInstance: any
private taskId: any
private tasks: { [s: string]: task.Cancelable } private tasks: { [s: string]: task.Cancelable }
private executor: java.util.concurrent.ThreadPoolExecutor private executor: java.util.concurrent.ThreadPoolExecutor
constructor() { constructor() {
super() super()
this.taskId = new AtomicInteger(0)
this.tasks = {} this.tasks = {}
this.executor = thread_pool.create({ this.executor = thread_pool.create({
groupName: '@ccms/spring' groupName: '@ccms/spring'
}) })
} }
create0(func: Function): task.Task { create0(owner: plugin.Plugin, func: Function, id: number): task.Task {
return new SpringTask(this.pluginInstance, func, this) return new SpringTask(owner, func, id, this)
} }
callSyncMethod(func: Function): any { callSyncMethod(func: Function): any {
return func() return func()
@ -51,8 +48,8 @@ export class SpringTask extends task.Task {
private taskManager: SpringTaskManager private taskManager: SpringTaskManager
private running = new AtomicBoolean(true) private running = new AtomicBoolean(true)
constructor(plugin: any, func: Function, taskManager: SpringTaskManager) { constructor(owner: plugin.Plugin, func: Function, id: number, taskManager: SpringTaskManager) {
super(plugin, func) super(owner, func, id)
this.id = taskManager.nextId() this.id = taskManager.nextId()
this.taskManager = taskManager this.taskManager = taskManager
} }
@ -83,19 +80,16 @@ export class SpringTask extends task.Task {
this.cancel() this.cancel()
} }
cancel0(): any { cancel0() {
var wasRunning = this.running.getAndSet(false) var wasRunning = this.running.getAndSet(false)
if (wasRunning) { if (wasRunning) {
this.taskManager.cancel(this.id) this.taskManager.cancel(this.id)
return true
} }
return false
} }
submit0(...args: any[]) { submit0(...args: any[]) {
this.taskManager.submit(this.id, this, () => this.run(...args)) this.taskManager.submit(this.id, this, () => this.run(...args))
return {
cancel: () => {
return this.cancel0()
}
}
} }
} }