|
@@ -9,32 +9,71 @@
|
|
|
|
|
|
package net.mamoe.mirai.spi
|
|
|
|
|
|
-import net.mamoe.mirai.utils.MiraiExperimentalApi
|
|
|
+import kotlinx.atomicfu.locks.SynchronizedObject
|
|
|
+import kotlinx.atomicfu.locks.synchronized
|
|
|
import net.mamoe.mirai.utils.MiraiLogger
|
|
|
-import kotlin.jvm.JvmField
|
|
|
+import net.mamoe.mirai.utils.lateinitMutableProperty
|
|
|
+import net.mamoe.mirai.utils.loadServices
|
|
|
import kotlin.reflect.KClass
|
|
|
|
|
|
/**
|
|
|
* 基本 SPI 接口
|
|
|
* @since 2.8.0
|
|
|
- */
|
|
|
-@MiraiExperimentalApi
|
|
|
+ */ // stable since 2.15
|
|
|
public interface BaseService {
|
|
|
/** 使用优先级, 值越小越先使用 */
|
|
|
- public val priority: Int get() = 5
|
|
|
+ public val priority: Int get() = 0
|
|
|
}
|
|
|
|
|
|
-@OptIn(MiraiExperimentalApi::class)
|
|
|
-internal expect class SPIServiceLoader<T : BaseService>(
|
|
|
- defaultService: T,
|
|
|
+internal fun <T : BaseService> SpiServiceLoader(
|
|
|
serviceType: KClass<T>,
|
|
|
-) {
|
|
|
- @JvmField
|
|
|
- var service: T
|
|
|
+ defaultImplementation: () -> T
|
|
|
+): SpiServiceLoader<T> {
|
|
|
+ return SpiServiceLoaderImpl(serviceType, defaultImplementation)
|
|
|
+}
|
|
|
+
|
|
|
+
|
|
|
+internal fun <T : BaseService> SpiServiceLoader(
|
|
|
+ serviceType: KClass<T>
|
|
|
+): SpiServiceLoader<T?> {
|
|
|
+ return SpiServiceLoaderImpl(serviceType, null)
|
|
|
+}
|
|
|
+
|
|
|
+internal interface SpiServiceLoader<T : BaseService?> {
|
|
|
+ val service: T
|
|
|
+}
|
|
|
|
|
|
- fun reload()
|
|
|
+internal class SpiServiceLoaderImpl<T : BaseService?>(
|
|
|
+ private val serviceType: KClass<T & Any>,
|
|
|
+ defaultService: (() -> T)?
|
|
|
+) : SpiServiceLoader<T> {
|
|
|
+ private val defaultInstance: T? by lazy {
|
|
|
+ defaultService?.invoke()
|
|
|
+ }
|
|
|
+ private val lock = SynchronizedObject()
|
|
|
+
|
|
|
+ override val service: T get() = _service
|
|
|
+
|
|
|
+ private var _service: T by lateinitMutableProperty {
|
|
|
+ synchronized(lock) {
|
|
|
+ reloadAndSelect()
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ fun reload() {
|
|
|
+ synchronized(lock) {
|
|
|
+ _service = reloadAndSelect()
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ private fun reloadAndSelect(): T {
|
|
|
+ @Suppress("UNCHECKED_CAST")
|
|
|
+ return (loadServices(serviceType).minByOrNull { it.priority } ?: defaultInstance) as T
|
|
|
+ }
|
|
|
|
|
|
companion object {
|
|
|
- val SPI_SERVICE_LOADER_LOGGER: MiraiLogger
|
|
|
+ val SPI_SERVICE_LOADER_LOGGER: MiraiLogger by lazy {
|
|
|
+ MiraiLogger.Factory.create(SpiServiceLoader::class, "spi-service-loader")
|
|
|
+ }
|
|
|
}
|
|
|
}
|