mirror of
https://github.com/mamoe/mirai.git
synced 2025-01-25 15:40:28 +08:00
Improve JavaPluginScheduler
This commit is contained in:
parent
a861b73cc7
commit
d37d6881fc
@ -1,149 +0,0 @@
|
||||
package net.mamoe.mirai.console.scheduler
|
||||
|
||||
import kotlinx.coroutines.*
|
||||
import kotlinx.coroutines.sync.Mutex
|
||||
import kotlinx.coroutines.sync.withLock
|
||||
import net.mamoe.mirai.console.plugins.PluginBase
|
||||
import java.util.concurrent.Future
|
||||
import java.util.concurrent.TimeUnit
|
||||
import java.util.concurrent.TimeoutException
|
||||
import java.util.function.Supplier
|
||||
import kotlin.coroutines.CoroutineContext
|
||||
|
||||
|
||||
/**
|
||||
* 作为Java插件开发者, 你应该使用PluginScheduler
|
||||
* 他们使用kotlin更高效的协程实现,并在API上对java有很高的亲和度
|
||||
* 且可以保证在PluginBase关闭的时候结束所有任务
|
||||
*
|
||||
* 你应该使用SchedulerTaskManager获取PluginScheduler, 或直接通过PluginBase获取
|
||||
*/
|
||||
|
||||
class PluginScheduler(_coroutineContext: CoroutineContext) : CoroutineScope {
|
||||
override val coroutineContext: CoroutineContext = _coroutineContext + SupervisorJob(_coroutineContext[Job])
|
||||
|
||||
|
||||
class RepeatTaskReceipt(@Volatile var cancelled: Boolean = false)
|
||||
|
||||
/**
|
||||
* 新增一个 Repeat Task (定时任务)
|
||||
*
|
||||
* 这个 Runnable 会被每 [intervalMs] 调用一次(不包含 [runnable] 执行时间)
|
||||
*
|
||||
* 使用返回的 [RepeatTaskReceipt], 可以取消这个定时任务
|
||||
*/
|
||||
fun repeat(runnable: Runnable, intervalMs: Long): RepeatTaskReceipt {
|
||||
val receipt = RepeatTaskReceipt()
|
||||
|
||||
this.launch {
|
||||
while (isActive && (!receipt.cancelled)) {
|
||||
withContext(Dispatchers.IO) {
|
||||
runnable.run()
|
||||
}
|
||||
delay(intervalMs)
|
||||
}
|
||||
}
|
||||
|
||||
return receipt
|
||||
}
|
||||
|
||||
/**
|
||||
* 新增一个 Delay Task (延迟任务)
|
||||
*
|
||||
* 在延迟 [delayMs] 后执行 [runnable]
|
||||
*
|
||||
* 作为 Java 使用者, 你要注意可见性, 原子性
|
||||
*/
|
||||
fun delay(runnable: Runnable, delayMs: Long) {
|
||||
this.launch {
|
||||
delay(delayMs)
|
||||
withContext(Dispatchers.IO) {
|
||||
runnable.run()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 异步执行一个任务, 最终返回 [Future], 与 Java 使用方法无异, 但效率更高且可以在插件关闭时停止
|
||||
*/
|
||||
fun <T> async(supplier: Supplier<T>): Future<T> {
|
||||
return AsyncResult(
|
||||
this.async {
|
||||
withContext(Dispatchers.IO) {
|
||||
supplier.get()
|
||||
}
|
||||
}
|
||||
)
|
||||
}
|
||||
|
||||
/**
|
||||
* 异步执行一个任务, 没有返回
|
||||
*/
|
||||
fun async(runnable: Runnable) {
|
||||
this.launch {
|
||||
withContext(Dispatchers.IO) {
|
||||
runnable.run()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* 这个类作为 Java 与 Kotlin 的桥接
|
||||
* 用 Java 的 interface 进行了 Kotlin 的实现
|
||||
* 使得 Java 开发者可以使用 Kotlin 的协程 [CoroutineScope.async]
|
||||
* 具体使用方法与 Java 的 [Future] 没有区别
|
||||
*/
|
||||
class AsyncResult<T>(
|
||||
private val deferred: Deferred<T>
|
||||
) : Future<T> {
|
||||
|
||||
override fun isDone(): Boolean {
|
||||
return deferred.isCompleted
|
||||
}
|
||||
|
||||
override fun get(): T {
|
||||
return runBlocking {
|
||||
deferred.await()
|
||||
}
|
||||
}
|
||||
|
||||
@OptIn(ExperimentalCoroutinesApi::class)
|
||||
override fun get(p0: Long, p1: TimeUnit): T {
|
||||
return runBlocking {
|
||||
withTimeoutOrNull(p1.toMillis(p0)) {
|
||||
deferred.await()
|
||||
} ?: throw TimeoutException()
|
||||
}
|
||||
}
|
||||
|
||||
override fun cancel(p0: Boolean): Boolean {
|
||||
deferred.cancel()
|
||||
return true
|
||||
}
|
||||
|
||||
override fun isCancelled(): Boolean {
|
||||
return deferred.isCancelled
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
internal object SchedulerTaskManagerInstance {
|
||||
private val schedulerTaskManagerInstance = mutableMapOf<PluginBase, PluginScheduler>()
|
||||
|
||||
private val mutex = Mutex()
|
||||
|
||||
fun getPluginScheduler(pluginBase: PluginBase): PluginScheduler {
|
||||
runBlocking {
|
||||
mutex.withLock {
|
||||
if (!schedulerTaskManagerInstance.containsKey(pluginBase)) {
|
||||
schedulerTaskManagerInstance[pluginBase] = PluginScheduler(pluginBase.coroutineContext)
|
||||
}
|
||||
}
|
||||
}
|
||||
return schedulerTaskManagerInstance[pluginBase]!!
|
||||
}
|
||||
}
|
||||
|
@ -0,0 +1,86 @@
|
||||
package net.mamoe.mirai.console.utils
|
||||
|
||||
import kotlinx.coroutines.*
|
||||
import kotlinx.coroutines.future.future
|
||||
import net.mamoe.mirai.console.plugins.builtin.JavaPlugin
|
||||
import java.util.concurrent.Callable
|
||||
import java.util.concurrent.CompletableFuture
|
||||
import java.util.concurrent.Future
|
||||
import kotlin.coroutines.CoroutineContext
|
||||
|
||||
|
||||
/**
|
||||
* 拥有生命周期管理的 Java 线程池.
|
||||
*
|
||||
* 在插件被 [卸载][JavaPlugin.onDisable] 时将会自动停止.
|
||||
*
|
||||
* @see JavaPlugin.scheduler 获取实例
|
||||
*/
|
||||
class JavaPluginScheduler internal constructor(parentCoroutineContext: CoroutineContext) : CoroutineScope {
|
||||
override val coroutineContext: CoroutineContext =
|
||||
parentCoroutineContext + SupervisorJob(parentCoroutineContext[Job])
|
||||
|
||||
/**
|
||||
* 新增一个 Repeating Task (定时任务)
|
||||
*
|
||||
* 这个 Runnable 会被每 [intervalMs] 调用一次(不包含 [runnable] 执行时间)
|
||||
*
|
||||
* @see Future.cancel 取消这个任务
|
||||
*/
|
||||
fun repeating(intervalMs: Long, runnable: Runnable): Future<Void?> {
|
||||
return this.future {
|
||||
while (isActive) {
|
||||
withContext(Dispatchers.IO) { runnable.run() }
|
||||
delay(intervalMs)
|
||||
}
|
||||
null
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 新增一个 Delayed Task (延迟任务)
|
||||
*
|
||||
* 在延迟 [delayMillis] 后执行 [runnable]
|
||||
*/
|
||||
fun delayed(delayMillis: Long, runnable: Runnable): CompletableFuture<Void?> {
|
||||
return future {
|
||||
delay(delayMillis)
|
||||
withContext(Dispatchers.IO) {
|
||||
runnable.run()
|
||||
}
|
||||
null
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 新增一个 Delayed Task (延迟任务)
|
||||
*
|
||||
* 在延迟 [delayMillis] 后执行 [runnable]
|
||||
*/
|
||||
fun <R> delayed(delayMillis: Long, runnable: Callable<R>): CompletableFuture<Void?> {
|
||||
return future {
|
||||
delay(delayMillis)
|
||||
withContext(Dispatchers.IO) { runnable.call() }
|
||||
null
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 异步执行一个任务, 最终返回 [Future], 与 Java 使用方法无异, 但效率更高且可以在插件关闭时停止
|
||||
*/
|
||||
fun <R> async(supplier: Callable<R>): Future<R> {
|
||||
return future {
|
||||
withContext(Dispatchers.IO) { supplier.call() }
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 异步执行一个任务, 没有返回
|
||||
*/
|
||||
fun async(runnable: Runnable): Future<Void?> {
|
||||
return future {
|
||||
withContext(Dispatchers.IO) { runnable.run() }
|
||||
null
|
||||
}
|
||||
}
|
||||
}
|
Loading…
Reference in New Issue
Block a user