Support builtin settings; cleanup

This commit is contained in:
Him188 2020-07-11 20:04:18 +08:00
parent 58187f95f0
commit b636ea9b31
8 changed files with 109 additions and 70 deletions

View File

@ -57,6 +57,7 @@ kotlin {
getByName("main") { getByName("main") {
languageSettings.apply { languageSettings.apply {
languageVersion = "1.3" languageVersion = "1.3"
apiVersion = "1.3"
} }
} }
} }
@ -101,8 +102,8 @@ tasks {
val compileKotlin by getting {} val compileKotlin by getting {}
val fillBuildConstants by registering { val fillBuildConstants by registering {
group = "mirai"
doLast { doLast {
return@doLast //
(compileKotlin as KotlinCompile).source.filter { it.name == "MiraiConsole.kt" }.single().let { file -> (compileKotlin as KotlinCompile).source.filter { it.name == "MiraiConsole.kt" }.single().let { file ->
file.writeText(file.readText() file.writeText(file.readText()
.replace(Regex("""val buildDate: Date = Date\((.*)\) //(.*)""")) { .replace(Regex("""val buildDate: Date = Date\((.*)\) //(.*)""")) {
@ -121,10 +122,6 @@ tasks {
} }
} }
} }
"compileKotlin" {
dependsOn(fillBuildConstants)
}
} }
// region PUBLISHING // region PUBLISHING

View File

@ -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.center.PluginCenter
import net.mamoe.mirai.console.plugin.jvm.JarPluginLoader import net.mamoe.mirai.console.plugin.jvm.JarPluginLoader
import net.mamoe.mirai.console.setting.SettingStorage 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.ConsoleExperimentalAPI
import net.mamoe.mirai.console.utils.ConsoleInternalAPI import net.mamoe.mirai.console.utils.ConsoleInternalAPI
import net.mamoe.mirai.utils.DefaultLogger import net.mamoe.mirai.utils.DefaultLogger
@ -127,7 +128,8 @@ internal object MiraiConsoleInternal : CoroutineScope, IMiraiConsole, MiraiConso
override val builtInPluginLoaders: List<PluginLoader<*, *>> get() = instance.builtInPluginLoaders override val builtInPluginLoaders: List<PluginLoader<*, *>> get() = instance.builtInPluginLoaders
override val consoleCommandSender: ConsoleCommandSender get() = instance.consoleCommandSender 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 { init {
DefaultLogger = { identity -> this.newLogger(identity) } DefaultLogger = { identity -> this.newLogger(identity) }
@ -157,6 +159,8 @@ internal object MiraiConsoleInternal : CoroutineScope, IMiraiConsole, MiraiConso
PluginManagerImpl.loadEnablePlugins() PluginManagerImpl.loadEnablePlugins()
mainLogger.info { "${PluginManager.plugins.size} plugin(s) loaded." } mainLogger.info { "${PluginManager.plugins.size} plugin(s) loaded." }
mainLogger.info { "mirai-console started successfully." } mainLogger.info { "mirai-console started successfully." }
ConsoleBuiltInSettingStorage // init
// Only for initialize // Only for initialize
} }
} }
@ -186,7 +190,8 @@ internal interface IMiraiConsole : CoroutineScope {
val consoleCommandSender: ConsoleCommandSender val consoleCommandSender: ConsoleCommandSender
val settingStorage: SettingStorage val settingStorageForJarPluginLoader: SettingStorage
val settingStorageForBuiltIns: SettingStorage
} }
/** /**

View File

@ -46,7 +46,7 @@ internal object JarPluginLoaderImpl :
@ConsoleExperimentalAPI @ConsoleExperimentalAPI
override val settingStorage: SettingStorage override val settingStorage: SettingStorage
get() = MiraiConsoleInternal.settingStorage get() = MiraiConsoleInternal.settingStorageForJarPluginLoader
override val coroutineContext: CoroutineContext = override val coroutineContext: CoroutineContext =
MiraiConsole.coroutineContext + MiraiConsole.coroutineContext +

View File

@ -23,6 +23,8 @@ import kotlin.reflect.full.findAnnotation
/** /**
* [Setting] 存储容器 * [Setting] 存储容器
*
* @see SettingHolder
*/ */
public interface SettingStorage { public interface SettingStorage {
/** /**
@ -36,10 +38,35 @@ public interface SettingStorage {
public fun store(holder: SettingHolder, setting: Setting) 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? // TODO: 2020/7/11 here or companion?
public inline fun <T : Setting> SettingStorage.load(holder: SettingHolder, settingClass: KClass<T>): T = public inline fun <T : Setting> SettingStorage.load(holder: SettingHolder, settingClass: KClass<T>): T =
this.load(holder, settingClass.java) this.load(holder, settingClass.java)
// TODO: 2020/7/11 here or companion?
public inline fun <reified T : Setting> SettingStorage.load(holder: SettingHolder): T =
this.load(holder, T::class)
/** /**
* 可以持有相关 [Setting] 的对象. * 可以持有相关 [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
internal object MemorySettingStorageImpl : SettingStorage, MemorySettingStorage { internal class MemorySettingStorageImpl : SettingStorage, MemorySettingStorage {
private val list = mutableMapOf<Class<out Setting>, Setting>() private val list = mutableMapOf<Class<out Setting>, Setting>()
internal class MemorySettingImpl : AbstractSetting() { internal class MemorySettingImpl : AbstractSetting() {
@ -173,11 +183,12 @@ internal object MemorySettingStorageImpl : SettingStorage, MemorySettingStorage
} }
} }
internal class MultiFileSettingStorageImpl( public open class MultiFileSettingStorageImpl(
override val directory: File public final override val directory: File
) : SettingStorage, MultiFileSettingStorage { ) : SettingStorage, MultiFileSettingStorage {
override fun <T : Setting> load(holder: SettingHolder, settingClass: Class<T>): T = with(settingClass.kotlin) { public override fun <T : Setting> load(holder: SettingHolder, settingClass: Class<T>): T =
val file = settingFile(holder, settingClass::class) with(settingClass.kotlin) {
val file = getSettingFile(holder, settingClass::class)
@Suppress("UNCHECKED_CAST") @Suppress("UNCHECKED_CAST")
val instance = objectInstance ?: this.createInstanceOrNull() ?: kotlin.run { val instance = objectInstance ?: this.createInstanceOrNull() ?: kotlin.run {
@ -200,7 +211,7 @@ internal class MultiFileSettingStorageImpl(
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 name = findASerialName()
val dir = File(directory, holder.name) val dir = File(directory, holder.name)
@ -216,8 +227,8 @@ internal class MultiFileSettingStorageImpl(
} }
@ConsoleExperimentalAPI @ConsoleExperimentalAPI
override fun store(holder: SettingHolder, setting: Setting): Unit = with(setting::class) { public override fun store(holder: SettingHolder, setting: Setting): Unit = with(setting::class) {
val file = settingFile(holder, this) val file = getSettingFile(holder, this)
if (file.exists() && file.isFile && file.canRead()) { if (file.exists() && file.isFile && file.canRead()) {
file.writeText(Yaml.default.stringify(setting.updaterSerializer, Unit)) file.writeText(Yaml.default.stringify(setting.updaterSerializer, Unit))
@ -225,14 +236,14 @@ internal class MultiFileSettingStorageImpl(
} }
} }
private fun <T : Any> KClass<T>.createInstanceOrNull(): T? { internal fun <T : Any> KClass<T>.createInstanceOrNull(): T? {
val noArgsConstructor = constructors.singleOrNull { it.parameters.all(KParameter::isOptional) } val noArgsConstructor = constructors.singleOrNull { it.parameters.all(KParameter::isOptional) }
?: return null ?: return null
return noArgsConstructor.callBy(emptyMap()) return noArgsConstructor.callBy(emptyMap())
} }
private fun KClass<*>.findASerialName(): String = internal fun KClass<*>.findASerialName(): String =
findAnnotation<SerialName>()?.value findAnnotation<SerialName>()?.value
?: qualifiedName ?: qualifiedName
?: throw IllegalArgumentException("Cannot find a serial name for $this") ?: throw IllegalArgumentException("Cannot find a serial name for $this")

View File

@ -10,24 +10,49 @@
package net.mamoe.mirai.console.utils 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.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 net.mamoe.mirai.contact.User
import kotlin.coroutines.CoroutineContext
import kotlin.coroutines.EmptyCoroutineContext
/** /**
* 判断此用户是否为 console 管理员 * 判断此用户是否为 console 管理员
*/ */
public val User.isManager: Boolean public val User.isManager: Boolean get() = this.id in this.bot.managers
get() = this.bot.managers.contains(this.id)
internal fun Bot.addManager(long: Long): Boolean { public fun Bot.removeManager(id: Long): Boolean {
TODO() return ManagersConfig[this].remove(id)
return true
}
public fun Bot.removeManager(long: Long) {
TODO()
} }
public val Bot.managers: List<Long> public val Bot.managers: List<Long>
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<Long, MutableSet<Long>> by value()
internal operator fun get(bot: Bot): MutableSet<Long> = 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

View File

@ -49,7 +49,8 @@ fun initTestEnvironment() {
override val consoleCommandSender: ConsoleCommandSender = object : ConsoleCommandSender() { override val consoleCommandSender: ConsoleCommandSender = object : ConsoleCommandSender() {
override suspend fun sendMessage(message: Message) = println(message) 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() override val coroutineContext: CoroutineContext = SupervisorJob()
}) })
} }

View File

@ -37,7 +37,7 @@ dependencies {
testApi(project(":mirai-console")) testApi(project(":mirai-console"))
} }
ext { ext.apply {
// 傻逼 compileAndRuntime 没 exclude 掉 // 傻逼 compileAndRuntime 没 exclude 掉
// 傻逼 gradle 第二次配置 task 会覆盖掉第一次的配置 // 傻逼 gradle 第二次配置 task 会覆盖掉第一次的配置
val x: com.github.jengelman.gradle.plugins.shadow.tasks.ShadowJar.() -> Unit = { val x: com.github.jengelman.gradle.plugins.shadow.tasks.ShadowJar.() -> Unit = {

View File

@ -50,18 +50,18 @@ class MiraiConsolePure @JvmOverloads constructor(
override val frontEnd: MiraiConsoleFrontEnd = MiraiConsoleFrontEndPure, override val frontEnd: MiraiConsoleFrontEnd = MiraiConsoleFrontEndPure,
override val mainLogger: MiraiLogger = frontEnd.loggerFor("main"), override val mainLogger: MiraiLogger = frontEnd.loggerFor("main"),
override val consoleCommandSender: ConsoleCommandSender = ConsoleCommandSenderImpl, 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()) { ) : IMiraiConsole, CoroutineScope by CoroutineScope(SupervisorJob()) {
init { init {
rootDir.mkdir() rootDir.mkdir()
require(rootDir.isDirectory) { "rootDir ${rootDir.absolutePath} is not a directory" } require(rootDir.isDirectory) { "rootDir ${rootDir.absolutePath} is not a directory" }
} }
companion object { @JvmField
@Volatile internal var started: Boolean = false
@JvmStatic
private var started: Boolean = false
companion object {
@JvmStatic @JvmStatic
fun MiraiConsolePure.start() = synchronized(this) { fun MiraiConsolePure.start() = synchronized(this) {
check(!started) { "mirai-console is already started and can't be restarted." } check(!started) { "mirai-console is already started and can't be restarted." }