Commit b5fcc6e8 authored by jiahua.liu's avatar jiahua.liu

Config supported 10/11

parent 17af6861
...@@ -45,7 +45,6 @@ object MiraiConsole { ...@@ -45,7 +45,6 @@ object MiraiConsole {
logger("\"/login qqnumber qqpassword \" to login a bot") logger("\"/login qqnumber qqpassword \" to login a bot")
logger("\"/login qq号 qq密码 \" 来登陆一个BOT") logger("\"/login qq号 qq密码 \" 来登陆一个BOT")
MiraiProperties()
CommandManager.register(DefaultCommands.DefaultLoginCommand()) CommandManager.register(DefaultCommands.DefaultLoginCommand())
pluginManager.loadPlugins() pluginManager.loadPlugins()
CommandListener.start() CommandListener.start()
...@@ -117,21 +116,15 @@ object MiraiConsole { ...@@ -117,21 +116,15 @@ object MiraiConsole {
} }
object MiraiProperties { object MiraiProperties {
val init = !File("$path/mirai.json").exists() var config = File("$path/mirai.json").loadAsConfig()
var config = Config.load("$path/mirai.json") var HTTP_API_ENABLE: Boolean by config.withDefaultWrite { true }
var HTTP_API_PORT: Int by config.withDefaultWrite { 8080 }
var HTTP_API_ENABLE: Boolean by config.withDefault { true } var HTTP_API_AUTH_KEY: String by config.withDefaultWriteSave {
var HTTP_API_PORT: Int by config.withDefault { 8080 } "InitKey".also {
var HTTP_API_AUTH_KEY: String by config logger("Mirai HTTPAPI auth key 已随机生成 请注意修改")
} + generateSessionKey()
operator fun invoke() {
if (init) {
HTTP_API_AUTH_KEY = "INITKEY" + generateSessionKey()
logger("Mirai HTTPAPI authkey 已随机生成, 请注意修改")
} }
}
} }
} }
......
...@@ -14,12 +14,11 @@ import com.alibaba.fastjson.JSONObject ...@@ -14,12 +14,11 @@ import com.alibaba.fastjson.JSONObject
import com.alibaba.fastjson.TypeReference import com.alibaba.fastjson.TypeReference
import com.alibaba.fastjson.parser.Feature import com.alibaba.fastjson.parser.Feature
import kotlinx.serialization.* import kotlinx.serialization.*
import kotlinx.serialization.json.Json
import net.mamoe.mirai.utils.cryptor.contentToString
import java.io.File import java.io.File
import java.util.concurrent.ConcurrentHashMap import java.util.concurrent.ConcurrentHashMap
import java.util.function.BiConsumer import java.util.concurrent.ConcurrentSkipListMap
import kotlin.properties.ReadWriteProperty import kotlin.properties.ReadWriteProperty
import kotlin.reflect.KClass
import kotlin.reflect.KProperty import kotlin.reflect.KProperty
import kotlin.reflect.full.isSubclassOf import kotlin.reflect.full.isSubclassOf
...@@ -47,6 +46,7 @@ interface Config { ...@@ -47,6 +46,7 @@ interface Config {
operator fun set(key: String, value: Any) operator fun set(key: String, value: Any)
operator fun get(key: String): Any? operator fun get(key: String): Any?
fun exist(key: String): Boolean fun exist(key: String): Boolean
fun setIfAbsent(key: String, value: Any)
fun asMap(): Map<String, Any> fun asMap(): Map<String, Any>
fun save() fun save()
...@@ -67,47 +67,109 @@ interface Config { ...@@ -67,47 +67,109 @@ interface Config {
} }
} }
fun File.loadAsConfig(): Config {
return Config.load(this)
}
/* 最简单的代理 */
inline operator fun <reified T : Any> Config.getValue(thisRef: Any?, property: KProperty<*>): T {
return smartCast(property)
}
inline operator fun <reified T : Any> Config.setValue(thisRef: Any?, property: KProperty<*>, value: T) {
this[property.name] = value
}
/* 带有默认值的代理 */
inline fun <reified T : Any> Config.withDefault( inline fun <reified T : Any> Config.withDefault(
autoSave: Boolean = true, noinline defaultValue: () -> T
crossinline defaultValue: () -> T
): ReadWriteProperty<Any, T> { ): ReadWriteProperty<Any, T> {
val default by lazy { defaultValue.invoke() }
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)) {//unsafe
return defaultValue.invoke() return this@withDefault.smartCast(property)
} }
return smartCast(property) return default
} }
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") /* 带有默认值且如果为空会写入的代理 */
inline fun <reified T> Config.smartCast(property: KProperty<*>): T { inline fun <reified T : Any> Config.withDefaultWrite(
return when (T::class) { noinline defaultValue: () -> T
String::class -> this.getString(property.name) ): WithDefaultWriteLoader<T> {
Int::class -> this.getInt(property.name) return WithDefaultWriteLoader(T::class, this, defaultValue, false)
Float::class -> this.getFloat(property.name) }
Double::class -> this.getDouble(property.name)
Long::class -> this.getLong(property.name) /* 带有默认值且如果为空会写入保存的代理 */
Boolean::class -> this.getBoolean(property.name) inline fun <reified T : Any> Config.withDefaultWriteSave(
noinline defaultValue: () -> T
): WithDefaultWriteLoader<T> {
return WithDefaultWriteLoader(T::class, this, defaultValue, true)
}
class WithDefaultWriteLoader<T : Any>(
private val _class: KClass<T>,
private val config: Config,
private val defaultValue: () -> T,
private val save: Boolean
) {
operator fun provideDelegate(
thisRef: Any,
prop: KProperty<*>
): ReadWriteProperty<Any, T> {
val defaultValue by lazy { defaultValue.invoke() }
config.setIfAbsent(prop.name, defaultValue)
if (save) {
config.save()
}
return object : ReadWriteProperty<Any, T> {
override fun getValue(thisRef: Any, property: KProperty<*>): T {
if (config.exist(property.name)) {//unsafe
return config._smartCast(property.name, _class)
}
return defaultValue
}
override fun setValue(thisRef: Any, property: KProperty<*>, value: T) {
config[property.name] = value
}
}
}
}
inline fun <reified T : Any> Config.smartCast(property: KProperty<*>): T {
return _smartCast(property.name, T::class)
}
@Suppress("IMPLICIT_CAST_TO_ANY", "UNCHECKED_CAST")
fun <T : Any> Config._smartCast(propertyName: String, _class: KClass<T>): T {
return when (_class) {
String::class -> this.getString(propertyName)
Int::class -> this.getInt(propertyName)
Float::class -> this.getFloat(propertyName)
Double::class -> this.getDouble(propertyName)
Long::class -> this.getLong(propertyName)
Boolean::class -> this.getBoolean(propertyName)
else -> when { else -> when {
T::class.isSubclassOf(ConfigSection::class) -> this.getConfigSection(property.name) _class.isSubclassOf(ConfigSection::class) -> this.getConfigSection(propertyName)
T::class == List::class || T::class == MutableList::class -> { _class == List::class || _class == MutableList::class -> {
val list = this.getList(property.name) val list = this.getList(propertyName)
return if (list.isEmpty()) { return if (list.isEmpty()) {
list list
} else { } else {
when (list[0]!!::class) { when (list[0]!!::class) {
String::class -> getStringList(property.name) String::class -> getStringList(propertyName)
Int::class -> getIntList(property.name) Int::class -> getIntList(propertyName)
Float::class -> getFloatList(property.name) Float::class -> getFloatList(propertyName)
Double::class -> getDoubleList(property.name) Double::class -> getDoubleList(propertyName)
Long::class -> getLongList(property.name) Long::class -> getLongList(propertyName)
else -> { else -> {
error("unsupported type") error("unsupported type")
} }
...@@ -121,14 +183,6 @@ inline fun <reified T> Config.smartCast(property: KProperty<*>): T { ...@@ -121,14 +183,6 @@ inline fun <reified T> Config.smartCast(property: KProperty<*>): T {
} as T } as T
} }
inline operator fun <reified T> Config.getValue(thisRef: Any?, property: KProperty<*>): T {
return smartCast(property)
}
inline operator fun <reified T> Config.setValue(thisRef: Any?, property: KProperty<*>, value: T) {
this[property.name] = value!!
this.save()
}
interface ConfigSection : Config { interface ConfigSection : Config {
...@@ -187,12 +241,16 @@ interface ConfigSection : Config { ...@@ -187,12 +241,16 @@ interface ConfigSection : Config {
override fun exist(key: String): Boolean { override fun exist(key: String): Boolean {
return get(key) != null return get(key) != null
} }
override fun setIfAbsent(key: String, value: Any) {
if (!exist(key)) set(key, value)
}
} }
@Serializable @Serializable
open class ConfigSectionImpl() : ConcurrentHashMap<String, Any>(), ConfigSection { open class ConfigSectionImpl() : ConcurrentHashMap<String, Any>(), ConfigSection {
override fun set(key: String, value: Any) { override fun set(key: String, value: Any) {
this.put(key, value) super.put(key, value)
} }
override operator fun get(key: String): Any? { override operator fun get(key: String): Any? {
...@@ -210,6 +268,10 @@ open class ConfigSectionImpl() : ConcurrentHashMap<String, Any>(), ConfigSection ...@@ -210,6 +268,10 @@ open class ConfigSectionImpl() : ConcurrentHashMap<String, Any>(), ConfigSection
override fun save() { override fun save() {
} }
override fun setIfAbsent(key: String, value: Any) {
this.putIfAbsent(key, value)//atomic
}
} }
...@@ -255,26 +317,15 @@ class JsonConfig internal constructor(file: File) : FileConfigImpl(file) { ...@@ -255,26 +317,15 @@ class JsonConfig internal constructor(file: File) : FileConfigImpl(file) {
if (content.isEmpty() || content.isBlank() || content == "{}") { if (content.isEmpty() || content.isBlank() || content == "{}") {
return ConfigSectionImpl() return ConfigSectionImpl()
} }
val section = JSON.parseObject( return JSON.parseObject<ConfigSectionImpl>(
content, content,
object : TypeReference<ConfigSectionImpl>() {}, object : TypeReference<ConfigSectionImpl>() {},
Feature.OrderedField Feature.OrderedField
) )
return section
} }
@UnstableDefault @UnstableDefault
override fun serialize(config: ConfigSection): String { override fun serialize(config: ConfigSection): String {
return JSONObject.toJSONString(config) return JSONObject.toJSONString(config)
} }
internal class AnySerializer(override val descriptor: SerialDescriptor) : KSerializer<Any> {
override fun deserialize(decoder: Decoder): Any {
TODO("not implemented") //To change body of created functions use File | Settings | File Templates.
}
override fun serialize(encoder: Encoder, obj: Any) {
TODO("not implemented") //To change body of created functions use File | Settings | File Templates.
}
}
} }
\ No newline at end of file
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment