feat: optimize task impl

Signed-off-by: MiaoWoo <admin@yumc.pw>
This commit is contained in:
MiaoWoo 2020-09-22 18:42:39 +08:00
parent e7077b1315
commit b87fb08d1c
9 changed files with 167 additions and 90 deletions

View File

@ -1,34 +1,62 @@
import { plugin } from './index'
import { injectable } from '@ccms/container'
export namespace task { export namespace task {
export const TaskManager = Symbol('TaskManager') @injectable()
export interface TaskManager { export abstract class TaskManager {
protected cacheTasks = new Map<string, task.Task[]>()
protected pluginCreate(plugin: plugin.Plugin, task: task.Task) {
if (!this.cacheTasks.has(plugin.description.name)) {
this.cacheTasks.set(plugin.description.name, [])
}
this.cacheTasks.get(plugin.description.name).push(task)
return task
}
protected pluginDisable(plugin: plugin.Plugin) {
if (this.cacheTasks.has(plugin.description.name)) {
this.cacheTasks.get(plugin.description.name).forEach(task => task.cancel())
this.cacheTasks.delete(plugin.description.name)
}
}
/** /**
* *
* @param func * @param func
*/ */
create(func: Function): task.Task; create(func: Function, plugin?: plugin.Plugin): task.Task {
if (Object.prototype.toString.call(func) !== "[object Function]") { throw TypeError('第一个参数 Task 必须为 function !') };
let task = this.create0(func)
if (plugin) { return this.pluginCreate(plugin, task) }
return task
}
abstract create0(func: Function): task.Task
/** /**
* 线 * 线
* @param func * @param func
*/ */
callSyncMethod(func: Function): any; abstract callSyncMethod(func: Function): any
/** /**
* *
*/ */
disable(); disable(plugin?: plugin.Plugin) {
if (plugin) { return this.pluginDisable(plugin) }
this.disable0()
}
abstract disable0()
} }
/** /**
* *
*/ */
export abstract class Task { export abstract class Task {
protected plugin: any; 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;
constructor(plugin: any, func: Function) { constructor(plugin: any, func: Function) {
this.plugin = plugin; this.plugin = plugin
this.func = func; this.func = func
} }
/** /**
@ -36,8 +64,8 @@ export namespace task {
* @param isAsync * @param isAsync
*/ */
async(isAsync: boolean = true): task.Task { async(isAsync: boolean = true): task.Task {
this.isAsync = isAsync; this.isAsync = isAsync
return this; return this
} }
/** /**
@ -45,8 +73,8 @@ export namespace task {
* @param tick Tick * @param tick Tick
*/ */
later(tick: number): task.Task { later(tick: number): task.Task {
this.laterTime = tick; this.laterTime = tick
return this; return this
} }
/** /**
@ -54,16 +82,23 @@ export namespace task {
* @param tick Tick * @param tick Tick
*/ */
timer(tick: number): task.Task { timer(tick: number): task.Task {
this.interval = tick; this.interval = tick
return this; return this
}
/**
*
*/
cancel(): boolean {
throw new Error("Method not implemented.")
} }
protected run(...args: any[]): void { protected run(...args: any[]): void {
try { try {
this.func(...args); this.func(...args)
} catch (ex) { } catch (ex) {
console.console('§4插件执行任务时发生错误', ex) console.console('§4插件执行任务时发生错误', ex)
console.ex(ex); console.ex(ex)
} }
} }
@ -71,12 +106,22 @@ export namespace task {
* *
* @param args * @param args
*/ */
abstract submit(...args: any[]): Cancelable; submit(...args: any[]): Cancelable {
let cancelable = this.submit0(...args)
this.cancel = cancelable.cancel
return cancelable
}
/**
*
* @param args
*/
abstract submit0(...args: any[]): Cancelable
} }
/** /**
* *
*/ */
export interface Cancelable { export interface Cancelable {
cancel(): boolean; cancel(): boolean
} }
} }

View File

@ -1,29 +1,28 @@
import { task, plugin } from '@ccms/api' import { task, plugin } from '@ccms/api'
import { inject, provideSingleton } from '@ccms/container'; import { inject, provideSingleton } from '@ccms/container'
const Bukkit = Java.type('org.bukkit.Bukkit'); const Bukkit = Java.type('org.bukkit.Bukkit')
const BukkitRunnable = Java.type('org.bukkit.scheduler.BukkitRunnable'); const BukkitRunnable = Java.type('org.bukkit.scheduler.BukkitRunnable')
const Callable = Java.type('java.util.concurrent.Callable') const Callable = Java.type('java.util.concurrent.Callable')
@provideSingleton(task.TaskManager) @provideSingleton(task.TaskManager)
export class BukkitTaskManager implements task.TaskManager { export class BukkitTaskManager extends task.TaskManager {
@inject(plugin.PluginInstance) @inject(plugin.PluginInstance)
private pluginInstance: any; private pluginInstance: any
create(func: Function): task.Task { create0(func: Function): task.Task {
if (Object.prototype.toString.call(func) !== "[object Function]") { throw TypeError('第一个参数 Task 必须为 function !'); }; return new BukkitTask(this.pluginInstance, func)
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(this.pluginInstance, new Callable({ call: () => func() })).get()
} }
disable() { disable0() {
Bukkit.getScheduler().cancelTasks(this.pluginInstance); Bukkit.getScheduler().cancelTasks(this.pluginInstance)
} }
} }
export class BukkitTask extends task.Task { export class BukkitTask extends task.Task {
submit(...args: any[]): task.Cancelable { submit0(...args: any[]): task.Cancelable {
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) {

View File

@ -1,28 +1,31 @@
import { task, plugin } from '@ccms/api' import { task, plugin } from '@ccms/api'
import { inject, provideSingleton } from '@ccms/container'; import { inject, provideSingleton } from '@ccms/container'
var Runnable = Java.type('java.lang.Runnable') var Runnable = Java.type('java.lang.Runnable')
let TimeUnit = Java.type('java.util.concurrent.TimeUnit') let TimeUnit = Java.type('java.util.concurrent.TimeUnit')
@provideSingleton(task.TaskManager) @provideSingleton(task.TaskManager)
export class BungeeTaskManager implements task.TaskManager { export class BungeeTaskManager extends task.TaskManager {
@inject(plugin.PluginInstance) @inject(plugin.PluginInstance)
private pluginInstance: any; private pluginInstance: any
create(func: Function): 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 !') };
return new BungeeTask(this.pluginInstance, func); let task = new BungeeTask(this.pluginInstance, func)
if (plugin) { return this.pluginCreate(plugin, task) }
return task
} }
callSyncMethod(func: Function): any { callSyncMethod(func: Function): any {
return func(); return func()
} }
disable() { disable(plugin?: plugin.Plugin) {
if (plugin) { return this.pluginDisable(plugin) }
this.pluginInstance.getProxy().getScheduler().cancel(this.pluginInstance) this.pluginInstance.getProxy().getScheduler().cancel(this.pluginInstance)
} }
} }
export class BungeeTask extends task.Task { export class BungeeTask extends task.Task {
submit(...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 this.plugin.getProxy().getScheduler().runAsync(this.plugin, run)

View File

@ -1,34 +1,32 @@
import { task, plugin } from '@ccms/api' import { task, plugin } from '@ccms/api'
import { inject, provideSingleton } from '@ccms/container'; import { inject, provideSingleton } from '@ccms/container'
const NukkitRunnable = Java.type('cn.nukkit.scheduler.NukkitRunnable'); const NukkitRunnable = Java.type('cn.nukkit.scheduler.NukkitRunnable')
@provideSingleton(task.TaskManager) @provideSingleton(task.TaskManager)
export class NukkitTaskManager implements task.TaskManager { export class NukkitTaskManager extends task.TaskManager {
@inject(plugin.PluginInstance) @inject(plugin.PluginInstance)
private pluginInstance: any; private pluginInstance: any
create(func: Function): task.Task { create0(func: Function): task.Task {
if (Object.prototype.toString.call(func) !== "[object Function]") { throw TypeError('第一个参数 Task 必须为 function !'); }; return new NukkitTask(this.pluginInstance, func)
return new NukkitTask(this.pluginInstance, func);
} }
callSyncMethod(func: Function): any { callSyncMethod(func: Function): any {
return func() return func()
} }
disable() { disable0() {
base.getInstance().getServer().getScheduler().cancelTask(this.pluginInstance) base.getInstance().getServer().getScheduler().cancelTask(this.pluginInstance)
} }
} }
export class NukkitTask extends task.Task { export class NukkitTask extends task.Task {
submit(...args: any[]): task.Cancelable { submit0(...args: any[]): task.Cancelable {
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) {
run[funcName](this.plugin, this.laterTime, this.interval); return run[funcName](this.plugin, this.laterTime, this.interval)
} else { } else {
run[funcName](this.plugin, this.laterTime); return run[funcName](this.plugin, this.laterTime)
} }
return run;
} }
} }

View File

@ -4,8 +4,9 @@ import { inject, provideSingleton, Container, ContainerInstance } from '@ccms/co
import './config' import './config'
import { interfaces } from './interfaces' import { interfaces } from './interfaces'
import { PluginCommandManager } from './command' import { PluginTaskManager } from './task'
import { PluginEventManager } from './event' import { PluginEventManager } from './event'
import { PluginCommandManager } from './command'
const Thread = Java.type('java.lang.Thread') const Thread = Java.type('java.lang.Thread')
@ -22,10 +23,12 @@ export class PluginManagerImpl implements plugin.PluginManager {
@inject(server.ServerChecker) @inject(server.ServerChecker)
private serverChecker: server.ServerChecker private serverChecker: server.ServerChecker
@inject(PluginCommandManager) @inject(PluginTaskManager)
private commandManager: PluginCommandManager private taskManager: PluginTaskManager
@inject(PluginEventManager) @inject(PluginEventManager)
private eventManager: PluginEventManager private eventManager: PluginEventManager
@inject(PluginCommandManager)
private commandManager: PluginCommandManager
private initialized: boolean = false private initialized: boolean = false
@ -43,8 +46,9 @@ export class PluginManagerImpl implements plugin.PluginManager {
this.metadataMap = new Map() this.metadataMap = new Map()
// ignore unused // ignore unused
this.commandManager this.taskManager
this.eventManager this.eventManager
this.commandManager
} }
initialize() { initialize() {
@ -131,7 +135,7 @@ export class PluginManagerImpl implements plugin.PluginManager {
if (loader.require(loadMetadata).loaded) { if (loader.require(loadMetadata).loaded) {
loadMetadata.loader = loader loadMetadata.loader = loader
let metadata = loadMetadata.metadata let metadata = loadMetadata.metadata
if (this.metadataMap.has(metadata.name)) { if (this.metadataMap.has(metadata.name) && this.instanceMap.has(metadata.name)) {
let oldMetadata = this.metadataMap.get(metadata.name) let oldMetadata = this.metadataMap.get(metadata.name)
throw new Error(`Plugin ${oldMetadata.name} is already load from ${oldMetadata.source}...`) throw new Error(`Plugin ${oldMetadata.name} is already load from ${oldMetadata.source}...`)
} }

View File

@ -0,0 +1,16 @@
import { plugin, task } from '@ccms/api'
import { provideSingleton, inject } from '@ccms/container'
@provideSingleton(PluginTaskManager)
export class PluginTaskManager {
@inject(task.TaskManager)
private taskManager: task.TaskManager
constructor() {
process.on('plugin.after.disable', (plugin: plugin.Plugin) => this.cancelTask(plugin))
}
private cancelTask(pluginInstance: plugin.Plugin) {
this.taskManager.disable(pluginInstance)
}
}

View File

@ -8,7 +8,7 @@ const Callable = Java.type('java.util.concurrent.Callable')
const TimeUnit = Java.type('java.util.concurrent.TimeUnit') const TimeUnit = Java.type('java.util.concurrent.TimeUnit')
@provideSingleton(task.TaskManager) @provideSingleton(task.TaskManager)
export class SpongeTaskManager implements task.TaskManager { export class SpongeTaskManager extends task.TaskManager {
@inject(plugin.PluginInstance) @inject(plugin.PluginInstance)
private pluginInstance: any private pluginInstance: any
private syncExecutor: any private syncExecutor: any
@ -18,21 +18,20 @@ export class SpongeTaskManager implements task.TaskManager {
this.syncExecutor = Sponge.getScheduler().createSyncExecutor(this.pluginInstance) this.syncExecutor = Sponge.getScheduler().createSyncExecutor(this.pluginInstance)
} }
create(func: Function): task.Task { create0(func: Function): task.Task {
if (Object.prototype.toString.call(func) !== "[object Function]") { throw TypeError('第一个参数 Task 必须为 function !') }
return new SpongeTask(this.pluginInstance, func) return new SpongeTask(this.pluginInstance, func)
} }
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()
} }
disable() { disable0() {
Sponge.getScheduler().getScheduledTasks(this.pluginInstance).forEach((task: task.Cancelable) => task.cancel()) Sponge.getScheduler().getScheduledTasks(this.pluginInstance).forEach((task: task.Cancelable) => task.cancel())
} }
} }
export class SpongeTask extends task.Task { export class SpongeTask extends task.Task {
submit(...args: any[]): task.Cancelable { submit0(...args: any[]): task.Cancelable {
let run = Task.builder().execute(new Consumer({ accept: () => this.run(...args) })) let run = Task.builder().execute(new Consumer({ accept: () => this.run(...args) }))
if (this.isAsync) { run.async() } if (this.isAsync) { run.async() }
if (this.laterTime) { run.delayTicks(this.laterTime) } if (this.laterTime) { run.delayTicks(this.laterTime) }

View File

@ -20,10 +20,11 @@ export default function SpringImpl(container: Container) {
} }
const beanFactory = base.getInstance().getAutowireCapableBeanFactory() const beanFactory = base.getInstance().getAutowireCapableBeanFactory()
container.bind(server.Console).toConstantValue(SpringConsole) container.bind(server.Console).toConstantValue(SpringConsole)
container.bind(ioc.Autowired).toDynamicValue((ctx) => { container.rebind(ioc.Autowired).toDynamicValue((ctx) => {
var metadata: any = reduceMetadata(ctx) var metadata: any = reduceMetadata(ctx)
if (toString.call(metadata.named) === "[object Symbol]") { return container.get(metadata.named) } let key = toString.call(metadata.named)
if (toString.call(metadata.named) === '[object jdk.internal.dynalink.beans.StaticClass]') { metadata.named = metadata.named.class } if (key === "[object Function]" || key === "[object Symbol]") { return container.get(metadata.named) }
if (key === '[object jdk.internal.dynalink.beans.StaticClass]') { metadata.named = metadata.named.class }
return beanFactory.getBean(metadata.named) return beanFactory.getBean(metadata.named)
}) })
} }

View File

@ -6,44 +6,57 @@ 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')
const taskId = new AtomicInteger(0)
const tasks: { [key: number]: task.Cancelable } = {}
const executor = thread_pool.create({
groupName: '@ccms/spring'
})
@provideSingleton(task.TaskManager) @provideSingleton(task.TaskManager)
export class SpringTaskManager implements task.TaskManager { export class SpringTaskManager extends task.TaskManager {
@inject(plugin.PluginInstance) @inject(plugin.PluginInstance)
private pluginInstance: any private pluginInstance: any
private innerTaskId: any private taskId: any
private innerTasks: { [s: string]: task.Cancelable } private tasks: { [s: string]: task.Cancelable }
private innerExecutor: java.util.concurrent.ThreadPoolExecutor private executor: java.util.concurrent.ThreadPoolExecutor
constructor() { constructor() {
this.innerTaskId = taskId super()
this.innerTasks = tasks this.taskId = new AtomicInteger(0)
this.innerExecutor = executor this.tasks = {}
this.executor = thread_pool.create({
groupName: '@ccms/spring'
})
} }
create(func: Function): task.Task { create0(func: Function): task.Task {
if (Object.prototype.toString.call(func) !== "[object Function]") { throw TypeError('第一个参数 Task 必须为 function !') } return new SpringTask(this.pluginInstance, func, this)
return new SpringTask(this.pluginInstance, func)
} }
callSyncMethod(func: Function): any { callSyncMethod(func: Function): any {
return func() return func()
} }
disable() { disable0() {
Object.values(this.innerTasks).forEach((task) => task?.cancel()) Object.values(this.tasks).forEach((task) => task?.cancel())
this.innerExecutor.shutdown() this.executor.shutdown()
}
nextId() {
return this.taskId.incrementAndGet()
}
submit(id: number, task: SpringTask, func: Function) {
this.tasks[id] = task
this.executor.execute(func as any)
}
cancel(id: number) {
delete this.tasks[id]
} }
} }
export class SpringTask extends task.Task { export class SpringTask extends task.Task {
public id = taskId.incrementAndGet() private id: number
private taskManager: SpringTaskManager
private running = new AtomicBoolean(true) private running = new AtomicBoolean(true)
constructor(plugin: any, func: Function, taskManager: SpringTaskManager) {
super(plugin, func)
this.id = taskManager.nextId()
this.taskManager = taskManager
}
run(...args: any[]) { run(...args: any[]) {
if (this.laterTime > 0) { if (this.laterTime > 0) {
try { try {
@ -70,19 +83,18 @@ export class SpringTask extends task.Task {
this.cancel() this.cancel()
} }
cancel(): any { cancel0(): any {
var wasRunning = this.running.getAndSet(false) var wasRunning = this.running.getAndSet(false)
if (wasRunning) { if (wasRunning) {
delete tasks[this.id] this.taskManager.cancel(this.id)
} }
} }
submit(...args: any[]): task.Cancelable { submit0(...args: any[]) {
tasks[this.id] = this this.taskManager.submit(this.id, this, () => this.run(...args))
executor.execute((() => this.run(...args)) as any)
return { return {
cancel: () => { cancel: () => {
return this.cancel() return this.cancel0()
} }
} }
} }