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") {
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

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.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<PluginLoader<*, *>> 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
}
/**

View File

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

View File

@ -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 <T : Setting> SettingStorage.load(holder: SettingHolder, settingClass: KClass<T>): T =
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] 的对象.
*
@ -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<Class<out Setting>, Setting>()
internal class MemorySettingImpl : AbstractSetting() {
@ -173,11 +183,12 @@ 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 <T : Setting> load(holder: SettingHolder, settingClass: Class<T>): T = with(settingClass.kotlin) {
val file = settingFile(holder, settingClass::class)
public override fun <T : Setting> load(holder: SettingHolder, settingClass: Class<T>): T =
with(settingClass.kotlin) {
val file = getSettingFile(holder, settingClass::class)
@Suppress("UNCHECKED_CAST")
val instance = objectInstance ?: this.createInstanceOrNull() ?: kotlin.run {
@ -200,7 +211,7 @@ internal class MultiFileSettingStorageImpl(
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 <T : Any> KClass<T>.createInstanceOrNull(): T? {
internal fun <T : Any> KClass<T>.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<SerialName>()?.value
?: qualifiedName
?: throw IllegalArgumentException("Cannot find a serial name for $this")

View File

@ -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<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 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()
})
}

View File

@ -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 = {

View File

@ -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." }