Merge remote-tracking branch 'origin/master'

This commit is contained in:
Him188 2020-02-12 23:31:20 +08:00
commit fcc6100cb6
2 changed files with 88 additions and 59 deletions

View File

@ -8,12 +8,11 @@
*/ */
import kotlinx.coroutines.runBlocking import kotlinx.coroutines.runBlocking
import kotlinx.serialization.UnstableDefault
import net.mamoe.mirai.Bot import net.mamoe.mirai.Bot
import net.mamoe.mirai.alsoLogin import net.mamoe.mirai.alsoLogin
import net.mamoe.mirai.api.http.generateSessionKey import net.mamoe.mirai.api.http.generateSessionKey
import net.mamoe.mirai.plugin.JsonConfig import net.mamoe.mirai.plugin.*
import net.mamoe.mirai.plugin.PluginBase
import net.mamoe.mirai.plugin.PluginManager
import java.io.File import java.io.File
import kotlin.concurrent.thread import kotlin.concurrent.thread
@ -112,24 +111,13 @@ object MiraiConsole {
} }
} }
@UnstableDefault
object MiraiProperties { object MiraiProperties {
var HTTP_API_ENABLE: Boolean = true var config = Config.load("$path/mirai.json")
var HTTP_API_PORT: Short = 8080
var HTTP_API_AUTH_KEY: String = ""
private val file = File(path + "/mirai.json".replace("//", "/"))
private lateinit var config: JsonConfig
fun load() {
if (!file.exists()) {
HTTP_API_AUTH_KEY = "INITKEY" + generateSessionKey()
save()
return
}
config = PluginBase
}
fun save() { var HTTP_API_ENABLE: Boolean by config.withDefault { true }
var HTTP_API_PORT: Int by config.withDefault { 8080 }
} var HTTP_API_AUTH_KEY: String by config.withDefault { "INITKEY" + generateSessionKey() }
} }
} }

View File

@ -9,20 +9,19 @@
package net.mamoe.mirai.plugin package net.mamoe.mirai.plugin
import kotlinx.serialization.KSerializer
import kotlinx.serialization.Serializable import kotlinx.serialization.Serializable
import kotlinx.serialization.Transient
import kotlinx.serialization.UnstableDefault import kotlinx.serialization.UnstableDefault
import kotlinx.serialization.json.Json import kotlinx.serialization.json.Json
import java.io.File import java.io.File
import java.util.concurrent.ConcurrentHashMap import java.util.concurrent.ConcurrentHashMap
import kotlin.properties.Delegates
import kotlin.properties.ReadWriteProperty import kotlin.properties.ReadWriteProperty
import kotlin.reflect.KProperty import kotlin.reflect.KProperty
import kotlin.reflect.full.isSubclassOf import kotlin.reflect.full.isSubclassOf
/** /**
* TODO: support all config types * TODO: support all config types
* only JSON is now supported
*
*/ */
interface Config { interface Config {
@ -42,9 +41,29 @@ interface Config {
operator fun get(key: String): Any? operator fun get(key: String): Any?
fun exist(key: String): Boolean fun exist(key: String): Boolean
fun asMap(): Map<String, Any> fun asMap(): Map<String, Any>
fun save()
companion object {
fun load(fileName: String): Config {
return load(File(fileName.replace("//", "/")))
}
fun load(file: File): Config {
if (!file.exists()) {
file.createNewFile()
}
return when (file.extension.toLowerCase()) {
"json" -> JsonConfig(file)
else -> error("Unsupported file config type ${file.extension.toLowerCase()}")
}
}
}
} }
inline fun <reified T : Any> Config.withDefault(crossinline defaultValue: () -> T): ReadWriteProperty<Any, T> { inline fun <reified T : Any> Config.withDefault(
autoSave: Boolean = true,
crossinline defaultValue: () -> T
): ReadWriteProperty<Any, T> {
return object : ReadWriteProperty<Any, T> { return object : ReadWriteProperty<Any, T> {
override fun getValue(thisRef: Any, property: KProperty<*>): T { override fun getValue(thisRef: Any, property: KProperty<*>): T {
if (!this@withDefault.exist(property.name)) { if (!this@withDefault.exist(property.name)) {
@ -55,12 +74,13 @@ inline fun <reified T : Any> Config.withDefault(crossinline defaultValue: () ->
override fun setValue(thisRef: Any, property: KProperty<*>, value: T) { override fun setValue(thisRef: Any, property: KProperty<*>, value: T) {
this@withDefault[property.name] = value this@withDefault[property.name] = value
if (autoSave) save()
} }
} }
} }
@Suppress("IMPLICIT_CAST_TO_ANY") @Suppress("IMPLICIT_CAST_TO_ANY")
inline operator fun <reified T> ConfigSection.getValue(thisRef: Any?, property: KProperty<*>): T { inline operator fun <reified T> Config.getValue(thisRef: Any?, property: KProperty<*>): T {
return when (T::class) { return when (T::class) {
String::class -> this.getString(property.name) String::class -> this.getString(property.name)
Int::class -> this.getInt(property.name) Int::class -> this.getInt(property.name)
@ -93,7 +113,7 @@ inline operator fun <reified T> ConfigSection.getValue(thisRef: Any?, property:
} as T } as T
} }
inline operator fun <reified T> ConfigSection.setValue(thisRef: Any?, property: KProperty<*>, value: T) { inline operator fun <reified T> Config.setValue(thisRef: Any?, property: KProperty<*>, value: T) {
this[property.name] = value!! this[property.name] = value!!
} }
@ -147,14 +167,17 @@ interface ConfigSection : Config {
return ((get(key) ?: error("ConfigSection does not contain $key ")) as List<*>).map { it.toString().toLong() } return ((get(key) ?: error("ConfigSection does not contain $key ")) as List<*>).map { it.toString().toLong() }
} }
override operator fun set(key: String, value: Any) { override fun exist(key: String): Boolean {
this[key] = value return get(key) != null
} }
} }
@Serializable @Serializable
open class ConfigSectionImpl() : ConcurrentHashMap<String, Any>(), ConfigSection { open class ConfigSectionImpl() : ConcurrentHashMap<String, Any>(), ConfigSection {
override fun set(key: String, value: Any) {
this[key] = value
}
override operator fun get(key: String): Any? { override operator fun get(key: String): Any? {
return super.get(key) return super.get(key)
} }
@ -166,48 +189,66 @@ open class ConfigSectionImpl() : ConcurrentHashMap<String, Any>(), ConfigSection
override fun asMap(): Map<String, Any> { override fun asMap(): Map<String, Any> {
return this return this
} }
override fun save() {
}
} }
interface FileConfig { interface FileConfig : Config {
fun deserialize(content: String): ConfigSectionImpl
fun serialize(config: ConfigSectionImpl): String
}
abstract class FileConfigImpl internal constructor(
private val file: File
) : FileConfig, ConfigSection {
private val content by lazy {
deserialize(file.readText())
}
override fun save() {
if (!file.exists()) {
file.createNewFile()
}
file.writeText(serialize(content))
}
override fun get(key: String): Any? {
return content[key]
}
override fun set(key: String, value: Any) {
content[key] = value
}
override fun asMap(): Map<String, Any> {
return content
}
} }
@Serializable class JsonConfig internal constructor(file: File) : FileConfigImpl(file) {
abstract class FileConfigImpl internal constructor() : ConfigSectionImpl(), FileConfig {
}
@Serializable
class JsonConfig internal constructor() : FileConfigImpl() {
companion object {
@UnstableDefault @UnstableDefault
fun load(file: File): Config { override fun deserialize(content: String): ConfigSectionImpl {
require(file.extension.toLowerCase() == "json") if (content.isEmpty() || content.isBlank() || content == "{}") {
val content = file.apply { return ConfigSectionImpl()
if (!this.exists()) this.createNewFile()
}.readText()
if (content.isEmpty() || content.isBlank()) {
return JsonConfig()
} }
return Json.parse( return Json.parse(
JsonConfig.serializer(), ConfigSectionImpl.serializer(),
content content
) )
} }
@UnstableDefault @UnstableDefault
fun save(file: File, config: JsonConfig) { override fun serialize(config: ConfigSectionImpl): String {
require(file.extension.toLowerCase() == "json") if (config.isEmpty()) {
val content = Json.stringify( return "{}"
JsonConfig.serializer(),
config
)
file.apply {
if (!this.exists()) this.createNewFile()
}.writeText(content)
} }
return Json.stringify(ConfigSectionImpl.serializer(), config)
} }
} }