diff --git a/backend/mirai-console/build.gradle.kts b/backend/mirai-console/build.gradle.kts index 12593c75c..0e1124988 100644 --- a/backend/mirai-console/build.gradle.kts +++ b/backend/mirai-console/build.gradle.kts @@ -57,6 +57,7 @@ kotlin { getByName("main") { languageSettings.apply { languageVersion = "1.3" + apiVersion = "1.3" } } } @@ -101,8 +102,8 @@ tasks { val compileKotlin by getting {} val fillBuildConstants by registering { + group = "mirai" doLast { - return@doLast // (compileKotlin as KotlinCompile).source.filter { it.name == "MiraiConsole.kt" }.single().let { file -> file.writeText(file.readText() .replace(Regex("""val buildDate: Date = Date\((.*)\) //(.*)""")) { @@ -121,10 +122,6 @@ tasks { } } } - - "compileKotlin" { - dependsOn(fillBuildConstants) - } } // region PUBLISHING diff --git a/backend/mirai-console/src/main/kotlin/net/mamoe/mirai/console/MiraiConsole.kt b/backend/mirai-console/src/main/kotlin/net/mamoe/mirai/console/MiraiConsole.kt index cc4eea42c..70dc85a36 100644 --- a/backend/mirai-console/src/main/kotlin/net/mamoe/mirai/console/MiraiConsole.kt +++ b/backend/mirai-console/src/main/kotlin/net/mamoe/mirai/console/MiraiConsole.kt @@ -28,6 +28,7 @@ import net.mamoe.mirai.console.plugin.center.CuiPluginCenter import net.mamoe.mirai.console.plugin.center.PluginCenter import net.mamoe.mirai.console.plugin.jvm.JarPluginLoader import net.mamoe.mirai.console.setting.SettingStorage +import net.mamoe.mirai.console.utils.ConsoleBuiltInSettingStorage import net.mamoe.mirai.console.utils.ConsoleExperimentalAPI import net.mamoe.mirai.console.utils.ConsoleInternalAPI import net.mamoe.mirai.utils.DefaultLogger @@ -127,7 +128,8 @@ internal object MiraiConsoleInternal : CoroutineScope, IMiraiConsole, MiraiConso override val builtInPluginLoaders: List> get() = instance.builtInPluginLoaders override val consoleCommandSender: ConsoleCommandSender get() = instance.consoleCommandSender - override val settingStorage: SettingStorage get() = instance.settingStorage + override val settingStorageForJarPluginLoader: SettingStorage get() = instance.settingStorageForJarPluginLoader + override val settingStorageForBuiltIns: SettingStorage get() = instance.settingStorageForBuiltIns init { DefaultLogger = { identity -> this.newLogger(identity) } @@ -157,6 +159,8 @@ internal object MiraiConsoleInternal : CoroutineScope, IMiraiConsole, MiraiConso PluginManagerImpl.loadEnablePlugins() mainLogger.info { "${PluginManager.plugins.size} plugin(s) loaded." } mainLogger.info { "mirai-console started successfully." } + + ConsoleBuiltInSettingStorage // init // Only for initialize } } @@ -186,7 +190,8 @@ internal interface IMiraiConsole : CoroutineScope { val consoleCommandSender: ConsoleCommandSender - val settingStorage: SettingStorage + val settingStorageForJarPluginLoader: SettingStorage + val settingStorageForBuiltIns: SettingStorage } /** diff --git a/backend/mirai-console/src/main/kotlin/net/mamoe/mirai/console/plugin/jvm/JarPluginLoader.kt b/backend/mirai-console/src/main/kotlin/net/mamoe/mirai/console/plugin/jvm/JarPluginLoader.kt index 802f29380..2a906f733 100644 --- a/backend/mirai-console/src/main/kotlin/net/mamoe/mirai/console/plugin/jvm/JarPluginLoader.kt +++ b/backend/mirai-console/src/main/kotlin/net/mamoe/mirai/console/plugin/jvm/JarPluginLoader.kt @@ -46,7 +46,7 @@ internal object JarPluginLoaderImpl : @ConsoleExperimentalAPI override val settingStorage: SettingStorage - get() = MiraiConsoleInternal.settingStorage + get() = MiraiConsoleInternal.settingStorageForJarPluginLoader override val coroutineContext: CoroutineContext = MiraiConsole.coroutineContext + diff --git a/backend/mirai-console/src/main/kotlin/net/mamoe/mirai/console/setting/SettingStorage.kt b/backend/mirai-console/src/main/kotlin/net/mamoe/mirai/console/setting/SettingStorage.kt index 6805460ee..2eb754fb3 100644 --- a/backend/mirai-console/src/main/kotlin/net/mamoe/mirai/console/setting/SettingStorage.kt +++ b/backend/mirai-console/src/main/kotlin/net/mamoe/mirai/console/setting/SettingStorage.kt @@ -23,6 +23,8 @@ import kotlin.reflect.full.findAnnotation /** * [Setting] 存储容器 + * + * @see SettingHolder */ public interface SettingStorage { /** @@ -36,10 +38,35 @@ public interface SettingStorage { public fun store(holder: SettingHolder, setting: Setting) } +// TODO: 2020/7/11 document +public interface MemorySettingStorage : SettingStorage { + public companion object { + @JvmStatic + @JvmName("create") + public operator fun invoke(): MemorySettingStorage = MemorySettingStorageImpl() + } +} + +// TODO: 2020/7/11 document +public interface MultiFileSettingStorage : SettingStorage { + public val directory: File + + public companion object { + @JvmStatic + @JvmName("create") + public operator fun invoke(directory: File): MultiFileSettingStorage = MultiFileSettingStorageImpl(directory) + } +} + + // TODO: 2020/7/11 here or companion? public inline fun SettingStorage.load(holder: SettingHolder, settingClass: KClass): T = this.load(holder, settingClass.java) +// TODO: 2020/7/11 here or companion? +public inline fun SettingStorage.load(holder: SettingHolder): T = + this.load(holder, T::class) + /** * 可以持有相关 [Setting] 的对象. * @@ -119,26 +146,9 @@ public interface AutoSaveSettingHolder : SettingHolder, CoroutineScope { } -// TODO: 2020/7/11 document -public interface MemorySettingStorage : SettingStorage { - public companion object INSTANCE : MemorySettingStorage by MemorySettingStorageImpl -} - -// TODO: 2020/7/11 document -public interface MultiFileSettingStorage : SettingStorage { - public val directory: File - - public companion object { - @JvmStatic - @JvmName("create") - public operator fun invoke(directory: File): MultiFileSettingStorage = MultiFileSettingStorageImpl(directory) - } -} - - // internal -internal object MemorySettingStorageImpl : SettingStorage, MemorySettingStorage { +internal class MemorySettingStorageImpl : SettingStorage, MemorySettingStorage { private val list = mutableMapOf, Setting>() internal class MemorySettingImpl : AbstractSetting() { @@ -173,34 +183,35 @@ internal object MemorySettingStorageImpl : SettingStorage, MemorySettingStorage } } -internal class MultiFileSettingStorageImpl( - override val directory: File +public open class MultiFileSettingStorageImpl( + public final override val directory: File ) : SettingStorage, MultiFileSettingStorage { - override fun load(holder: SettingHolder, settingClass: Class): T = with(settingClass.kotlin) { - val file = settingFile(holder, settingClass::class) + public override fun load(holder: SettingHolder, settingClass: Class): T = + with(settingClass.kotlin) { + val file = getSettingFile(holder, settingClass::class) - @Suppress("UNCHECKED_CAST") - val instance = objectInstance ?: this.createInstanceOrNull() ?: kotlin.run { - if (settingClass != Setting::class.java) { - throw IllegalArgumentException( - "Cannot create Setting instance. Make sure settingClass is Setting::class.java or a Kotlin's object, " + - "or has a constructor which either has no parameters or all parameters of which are optional" - ) + @Suppress("UNCHECKED_CAST") + val instance = objectInstance ?: this.createInstanceOrNull() ?: kotlin.run { + if (settingClass != Setting::class.java) { + throw IllegalArgumentException( + "Cannot create Setting instance. Make sure settingClass is Setting::class.java or a Kotlin's object, " + + "or has a constructor which either has no parameters or all parameters of which are optional" + ) + } + if (holder is AutoSaveSettingHolder) { + AutoSaveSetting(holder, this@MultiFileSettingStorageImpl) as T? + } else null + } ?: throw IllegalArgumentException( + "Cannot create Setting instance. Make sure 'holder' is a AutoSaveSettingHolder, " + + "or 'setting' is an object or has a constructor which either has no parameters or all parameters of which are optional" + ) + if (file.exists() && file.isFile && file.canRead()) { + Yaml.default.parse(instance.updaterSerializer, file.readText()) } - if (holder is AutoSaveSettingHolder) { - AutoSaveSetting(holder, this@MultiFileSettingStorageImpl) as T? - } else null - } ?: throw IllegalArgumentException( - "Cannot create Setting instance. Make sure 'holder' is a AutoSaveSettingHolder, " + - "or 'setting' is an object or has a constructor which either has no parameters or all parameters of which are optional" - ) - if (file.exists() && file.isFile && file.canRead()) { - Yaml.default.parse(instance.updaterSerializer, file.readText()) + instance } - instance - } - private fun settingFile(holder: SettingHolder, clazz: KClass<*>): File = with(clazz) { + protected open fun getSettingFile(holder: SettingHolder, clazz: KClass<*>): File = with(clazz) { val name = findASerialName() val dir = File(directory, holder.name) @@ -216,8 +227,8 @@ internal class MultiFileSettingStorageImpl( } @ConsoleExperimentalAPI - override fun store(holder: SettingHolder, setting: Setting): Unit = with(setting::class) { - val file = settingFile(holder, this) + public override fun store(holder: SettingHolder, setting: Setting): Unit = with(setting::class) { + val file = getSettingFile(holder, this) if (file.exists() && file.isFile && file.canRead()) { file.writeText(Yaml.default.stringify(setting.updaterSerializer, Unit)) @@ -225,14 +236,14 @@ internal class MultiFileSettingStorageImpl( } } -private fun KClass.createInstanceOrNull(): T? { +internal fun KClass.createInstanceOrNull(): T? { val noArgsConstructor = constructors.singleOrNull { it.parameters.all(KParameter::isOptional) } ?: return null return noArgsConstructor.callBy(emptyMap()) } -private fun KClass<*>.findASerialName(): String = +internal fun KClass<*>.findASerialName(): String = findAnnotation()?.value ?: qualifiedName ?: throw IllegalArgumentException("Cannot find a serial name for $this") \ No newline at end of file diff --git a/backend/mirai-console/src/main/kotlin/net/mamoe/mirai/console/utils/BotManagers.kt b/backend/mirai-console/src/main/kotlin/net/mamoe/mirai/console/utils/BotManagers.kt index a2e258099..861fc1bc8 100644 --- a/backend/mirai-console/src/main/kotlin/net/mamoe/mirai/console/utils/BotManagers.kt +++ b/backend/mirai-console/src/main/kotlin/net/mamoe/mirai/console/utils/BotManagers.kt @@ -10,24 +10,49 @@ package net.mamoe.mirai.console.utils +import kotlinx.coroutines.CoroutineScope +import kotlinx.coroutines.Job +import kotlinx.coroutines.SupervisorJob import net.mamoe.mirai.Bot +import net.mamoe.mirai.console.MiraiConsole +import net.mamoe.mirai.console.MiraiConsoleInternal +import net.mamoe.mirai.console.setting.* import net.mamoe.mirai.contact.User +import kotlin.coroutines.CoroutineContext +import kotlin.coroutines.EmptyCoroutineContext /** * 判断此用户是否为 console 管理员 */ -public val User.isManager: Boolean - get() = this.bot.managers.contains(this.id) +public val User.isManager: Boolean get() = this.id in this.bot.managers -internal fun Bot.addManager(long: Long): Boolean { - TODO() - return true -} - -public fun Bot.removeManager(long: Long) { - TODO() +public fun Bot.removeManager(id: Long): Boolean { + return ManagersConfig[this].remove(id) } public val Bot.managers: List - get() = TODO() + get() = ManagersConfig[this].toList() + +internal fun Bot.addManager(id: Long): Boolean { + return ManagersConfig[this].add(id) +} + + +internal object ManagersConfig : Setting by (ConsoleBuiltInSettingStorage.load(ConsoleBuiltInSettingHolder)) { + private val managers: MutableMap> by value() + + internal operator fun get(bot: Bot): MutableSet = managers.getOrPut(bot.id, ::mutableSetOf) +} + + +internal fun CoroutineContext.overrideWithSupervisorJob(): CoroutineContext = this + SupervisorJob(this[Job]) +internal fun CoroutineScope.childScope(context: CoroutineContext = EmptyCoroutineContext): CoroutineScope = + CoroutineScope(this.coroutineContext.overrideWithSupervisorJob() + context) + +internal object ConsoleBuiltInSettingHolder : AutoSaveSettingHolder, + CoroutineScope by MiraiConsole.childScope() { + override val name: String get() = "ConsoleBuiltIns" +} + +internal object ConsoleBuiltInSettingStorage : SettingStorage by MiraiConsoleInternal.settingStorageForJarPluginLoader \ No newline at end of file diff --git a/backend/mirai-console/src/test/kotlin/net/mamoe/mirai/console/TestMiraiConosle.kt b/backend/mirai-console/src/test/kotlin/net/mamoe/mirai/console/TestMiraiConosle.kt index d718d48d4..cc9a02567 100644 --- a/backend/mirai-console/src/test/kotlin/net/mamoe/mirai/console/TestMiraiConosle.kt +++ b/backend/mirai-console/src/test/kotlin/net/mamoe/mirai/console/TestMiraiConosle.kt @@ -49,7 +49,8 @@ fun initTestEnvironment() { override val consoleCommandSender: ConsoleCommandSender = object : ConsoleCommandSender() { override suspend fun sendMessage(message: Message) = println(message) } - override val settingStorage: SettingStorage get() = MemorySettingStorage + override val settingStorageForJarPluginLoader: SettingStorage get() = MemorySettingStorage() + override val settingStorageForBuiltIns: SettingStorage get() = MemorySettingStorage() override val coroutineContext: CoroutineContext = SupervisorJob() }) } diff --git a/frontend/mirai-console-pure/build.gradle.kts b/frontend/mirai-console-pure/build.gradle.kts index 60e13f5c0..9e2f02879 100644 --- a/frontend/mirai-console-pure/build.gradle.kts +++ b/frontend/mirai-console-pure/build.gradle.kts @@ -37,7 +37,7 @@ dependencies { testApi(project(":mirai-console")) } -ext { +ext.apply { // 傻逼 compileAndRuntime 没 exclude 掉 // 傻逼 gradle 第二次配置 task 会覆盖掉第一次的配置 val x: com.github.jengelman.gradle.plugins.shadow.tasks.ShadowJar.() -> Unit = { diff --git a/frontend/mirai-console-pure/src/main/kotlin/net/mamoe/mirai/console/pure/MiraiConsolePure.kt b/frontend/mirai-console-pure/src/main/kotlin/net/mamoe/mirai/console/pure/MiraiConsolePure.kt index eebb794d6..47a5dfe8e 100644 --- a/frontend/mirai-console-pure/src/main/kotlin/net/mamoe/mirai/console/pure/MiraiConsolePure.kt +++ b/frontend/mirai-console-pure/src/main/kotlin/net/mamoe/mirai/console/pure/MiraiConsolePure.kt @@ -50,18 +50,18 @@ class MiraiConsolePure @JvmOverloads constructor( override val frontEnd: MiraiConsoleFrontEnd = MiraiConsoleFrontEndPure, override val mainLogger: MiraiLogger = frontEnd.loggerFor("main"), override val consoleCommandSender: ConsoleCommandSender = ConsoleCommandSenderImpl, - override val settingStorage: SettingStorage = MultiFileSettingStorage(rootDir) + override val settingStorageForJarPluginLoader: SettingStorage = MultiFileSettingStorage(rootDir), + override val settingStorageForBuiltIns: SettingStorage = MultiFileSettingStorage(rootDir) ) : IMiraiConsole, CoroutineScope by CoroutineScope(SupervisorJob()) { init { rootDir.mkdir() require(rootDir.isDirectory) { "rootDir ${rootDir.absolutePath} is not a directory" } } - companion object { - @Volatile - @JvmStatic - private var started: Boolean = false + @JvmField + internal var started: Boolean = false + companion object { @JvmStatic fun MiraiConsolePure.start() = synchronized(this) { check(!started) { "mirai-console is already started and can't be restarted." }