mirror of
https://github.com/mamoe/mirai.git
synced 2025-01-11 02:50:15 +08:00
Fix Settings
This commit is contained in:
parent
b00b3d97f0
commit
c13076eea0
@ -24,6 +24,7 @@ import net.mamoe.mirai.utils.MiraiLogger
|
|||||||
import java.io.File
|
import java.io.File
|
||||||
import java.util.concurrent.locks.ReentrantLock
|
import java.util.concurrent.locks.ReentrantLock
|
||||||
import kotlin.annotation.AnnotationTarget.*
|
import kotlin.annotation.AnnotationTarget.*
|
||||||
|
import kotlin.coroutines.CoroutineContext
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -44,6 +45,11 @@ public annotation class ConsoleFrontEndImplementation
|
|||||||
*/
|
*/
|
||||||
@ConsoleFrontEndImplementation
|
@ConsoleFrontEndImplementation
|
||||||
public interface MiraiConsoleImplementation : CoroutineScope {
|
public interface MiraiConsoleImplementation : CoroutineScope {
|
||||||
|
/**
|
||||||
|
* [MiraiConsole] 的 [CoroutineScope.coroutineContext]
|
||||||
|
*/
|
||||||
|
public override val coroutineContext: CoroutineContext
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Console 运行路径
|
* Console 运行路径
|
||||||
*/
|
*/
|
||||||
|
@ -107,7 +107,7 @@ public object BuiltInCommands {
|
|||||||
private val closingLock = Mutex()
|
private val closingLock = Mutex()
|
||||||
|
|
||||||
@Handler
|
@Handler
|
||||||
public suspend fun CommandSender.handle(): Unit {
|
public suspend fun CommandSender.handle() {
|
||||||
closingLock.withLock {
|
closingLock.withLock {
|
||||||
sendMessage("Stopping mirai-console")
|
sendMessage("Stopping mirai-console")
|
||||||
kotlin.runCatching {
|
kotlin.runCatching {
|
||||||
|
@ -13,6 +13,6 @@ import java.util.*
|
|||||||
|
|
||||||
internal object MiraiConsoleBuildConstants { // auto-filled on build (task :mirai-console:fillBuildConstants)
|
internal object MiraiConsoleBuildConstants { // auto-filled on build (task :mirai-console:fillBuildConstants)
|
||||||
@JvmStatic
|
@JvmStatic
|
||||||
val buildDate: Date = Date(1596350800177L) // 2020-08-02 14:46:40
|
val buildDate: Date = Date(1597935352287L) // 2020-08-20 22:55:52
|
||||||
const val version: String = "1.0-M1"
|
const val version: String = "1.0-M2-1"
|
||||||
}
|
}
|
||||||
|
@ -24,15 +24,20 @@ import kotlin.reflect.full.*
|
|||||||
|
|
||||||
internal object CompositeCommandSubCommandAnnotationResolver :
|
internal object CompositeCommandSubCommandAnnotationResolver :
|
||||||
AbstractReflectionCommand.SubCommandAnnotationResolver {
|
AbstractReflectionCommand.SubCommandAnnotationResolver {
|
||||||
override fun hasAnnotation(function: KFunction<*>) = function.hasAnnotation<CompositeCommand.SubCommand>()
|
override fun hasAnnotation(baseCommand: AbstractReflectionCommand, function: KFunction<*>) =
|
||||||
override fun getSubCommandNames(function: KFunction<*>): Array<out String> =
|
function.hasAnnotation<CompositeCommand.SubCommand>()
|
||||||
|
|
||||||
|
override fun getSubCommandNames(baseCommand: AbstractReflectionCommand, function: KFunction<*>): Array<out String> =
|
||||||
function.findAnnotation<CompositeCommand.SubCommand>()!!.value
|
function.findAnnotation<CompositeCommand.SubCommand>()!!.value
|
||||||
}
|
}
|
||||||
|
|
||||||
internal object SimpleCommandSubCommandAnnotationResolver :
|
internal object SimpleCommandSubCommandAnnotationResolver :
|
||||||
AbstractReflectionCommand.SubCommandAnnotationResolver {
|
AbstractReflectionCommand.SubCommandAnnotationResolver {
|
||||||
override fun hasAnnotation(function: KFunction<*>) = function.hasAnnotation<SimpleCommand.Handler>()
|
override fun hasAnnotation(baseCommand: AbstractReflectionCommand, function: KFunction<*>) =
|
||||||
override fun getSubCommandNames(function: KFunction<*>): Array<out String> = arrayOf("")
|
function.hasAnnotation<SimpleCommand.Handler>()
|
||||||
|
|
||||||
|
override fun getSubCommandNames(baseCommand: AbstractReflectionCommand, function: KFunction<*>): Array<out String> =
|
||||||
|
baseCommand.names
|
||||||
}
|
}
|
||||||
|
|
||||||
internal abstract class AbstractReflectionCommand @JvmOverloads constructor(
|
internal abstract class AbstractReflectionCommand @JvmOverloads constructor(
|
||||||
@ -74,12 +79,12 @@ internal abstract class AbstractReflectionCommand @JvmOverloads constructor(
|
|||||||
}
|
}
|
||||||
|
|
||||||
interface SubCommandAnnotationResolver {
|
interface SubCommandAnnotationResolver {
|
||||||
fun hasAnnotation(function: KFunction<*>): Boolean
|
fun hasAnnotation(baseCommand: AbstractReflectionCommand, function: KFunction<*>): Boolean
|
||||||
fun getSubCommandNames(function: KFunction<*>): Array<out String>
|
fun getSubCommandNames(baseCommand: AbstractReflectionCommand, function: KFunction<*>): Array<out String>
|
||||||
}
|
}
|
||||||
|
|
||||||
internal val subCommands: Array<SubCommandDescriptor> by lazy {
|
internal val subCommands: Array<SubCommandDescriptor> by lazy {
|
||||||
this::class.declaredFunctions.filter { subCommandAnnotationResolver.hasAnnotation(it) }
|
this::class.declaredFunctions.filter { subCommandAnnotationResolver.hasAnnotation(this, it) }
|
||||||
.also { subCommandFunctions ->
|
.also { subCommandFunctions ->
|
||||||
// overloading not yet supported
|
// overloading not yet supported
|
||||||
val overloadFunction = subCommandFunctions.groupBy { it.name }.entries.firstOrNull { it.value.size > 1 }
|
val overloadFunction = subCommandFunctions.groupBy { it.name }.entries.firstOrNull { it.value.size > 1 }
|
||||||
@ -278,7 +283,7 @@ internal fun AbstractReflectionCommand.createSubCommand(
|
|||||||
}
|
}
|
||||||
|
|
||||||
val commandName =
|
val commandName =
|
||||||
subCommandAnnotationResolver.getSubCommandNames(function)
|
subCommandAnnotationResolver.getSubCommandNames(this, function)
|
||||||
.let { namesFromAnnotation ->
|
.let { namesFromAnnotation ->
|
||||||
if (namesFromAnnotation.isNotEmpty()) {
|
if (namesFromAnnotation.isNotEmpty()) {
|
||||||
namesFromAnnotation
|
namesFromAnnotation
|
||||||
|
@ -11,10 +11,7 @@ package net.mamoe.mirai.console.internal.plugin
|
|||||||
|
|
||||||
import kotlinx.atomicfu.AtomicLong
|
import kotlinx.atomicfu.AtomicLong
|
||||||
import kotlinx.atomicfu.locks.withLock
|
import kotlinx.atomicfu.locks.withLock
|
||||||
import kotlinx.coroutines.CoroutineExceptionHandler
|
import kotlinx.coroutines.*
|
||||||
import kotlinx.coroutines.CoroutineScope
|
|
||||||
import kotlinx.coroutines.Job
|
|
||||||
import kotlinx.coroutines.SupervisorJob
|
|
||||||
import net.mamoe.mirai.console.MiraiConsole
|
import net.mamoe.mirai.console.MiraiConsole
|
||||||
import net.mamoe.mirai.console.plugin.Plugin
|
import net.mamoe.mirai.console.plugin.Plugin
|
||||||
import net.mamoe.mirai.console.plugin.PluginManager
|
import net.mamoe.mirai.console.plugin.PluginManager
|
||||||
@ -69,6 +66,7 @@ internal abstract class JvmPluginInternal(
|
|||||||
internal fun internalOnDisable() {
|
internal fun internalOnDisable() {
|
||||||
firstRun = false
|
firstRun = false
|
||||||
this.onDisable()
|
this.onDisable()
|
||||||
|
this.cancel(CancellationException("plugin disabled"))
|
||||||
}
|
}
|
||||||
|
|
||||||
internal fun internalOnLoad() {
|
internal fun internalOnLoad() {
|
||||||
|
@ -12,6 +12,8 @@
|
|||||||
package net.mamoe.mirai.console.internal.plugin
|
package net.mamoe.mirai.console.internal.plugin
|
||||||
|
|
||||||
import kotlinx.atomicfu.locks.withLock
|
import kotlinx.atomicfu.locks.withLock
|
||||||
|
import kotlinx.coroutines.InternalCoroutinesApi
|
||||||
|
import kotlinx.coroutines.Job
|
||||||
import net.mamoe.mirai.console.MiraiConsole
|
import net.mamoe.mirai.console.MiraiConsole
|
||||||
import net.mamoe.mirai.console.internal.setting.cast
|
import net.mamoe.mirai.console.internal.setting.cast
|
||||||
import net.mamoe.mirai.console.plugin.*
|
import net.mamoe.mirai.console.plugin.*
|
||||||
@ -54,6 +56,12 @@ internal object PluginManagerImpl : PluginManager {
|
|||||||
_pluginLoaders.remove(loader)
|
_pluginLoaders.remove(loader)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
init {
|
||||||
|
@OptIn(InternalCoroutinesApi::class)
|
||||||
|
MiraiConsole.coroutineContext[Job]!!.invokeOnCompletion(true) {
|
||||||
|
plugins.forEach(Plugin::disable)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// region LOADING
|
// region LOADING
|
||||||
|
|
||||||
|
@ -10,10 +10,7 @@
|
|||||||
package net.mamoe.mirai.console.internal.setting
|
package net.mamoe.mirai.console.internal.setting
|
||||||
|
|
||||||
import kotlinx.atomicfu.atomic
|
import kotlinx.atomicfu.atomic
|
||||||
import kotlinx.coroutines.CoroutineScope
|
import kotlinx.coroutines.*
|
||||||
import kotlinx.coroutines.Job
|
|
||||||
import kotlinx.coroutines.delay
|
|
||||||
import kotlinx.coroutines.launch
|
|
||||||
import net.mamoe.mirai.console.internal.command.qualifiedNameOrTip
|
import net.mamoe.mirai.console.internal.command.qualifiedNameOrTip
|
||||||
import net.mamoe.mirai.console.internal.plugin.updateWhen
|
import net.mamoe.mirai.console.internal.plugin.updateWhen
|
||||||
import net.mamoe.mirai.console.plugin.jvm.loadSetting
|
import net.mamoe.mirai.console.plugin.jvm.loadSetting
|
||||||
@ -36,7 +33,10 @@ import kotlin.reflect.full.findAnnotation
|
|||||||
*
|
*
|
||||||
* @see loadSetting
|
* @see loadSetting
|
||||||
*/
|
*/
|
||||||
internal open class AutoSaveSetting(private val owner: AutoSaveSettingHolder) :
|
internal open class AutoSaveSetting(
|
||||||
|
private val owner: AutoSaveSettingHolder,
|
||||||
|
internal val originSettingClass: KClass<out Setting>
|
||||||
|
) :
|
||||||
AbstractSetting() {
|
AbstractSetting() {
|
||||||
private lateinit var storage: SettingStorage
|
private lateinit var storage: SettingStorage
|
||||||
|
|
||||||
@ -54,7 +54,8 @@ internal open class AutoSaveSetting(private val owner: AutoSaveSettingHolder) :
|
|||||||
internal var currentFirstStartTime = atomic(0L)
|
internal var currentFirstStartTime = atomic(0L)
|
||||||
|
|
||||||
init {
|
init {
|
||||||
owner.coroutineContext[Job]?.invokeOnCompletion { doSave() }
|
@OptIn(InternalCoroutinesApi::class)
|
||||||
|
owner.coroutineContext[Job]?.invokeOnCompletion(true) { doSave() }
|
||||||
}
|
}
|
||||||
|
|
||||||
private val updaterBlock: suspend CoroutineScope.() -> Unit = {
|
private val updaterBlock: suspend CoroutineScope.() -> Unit = {
|
||||||
@ -125,10 +126,12 @@ internal class MemorySettingStorageImpl(
|
|||||||
internal open class MultiFileSettingStorageImpl(
|
internal open class MultiFileSettingStorageImpl(
|
||||||
public final override val directory: File
|
public final override val directory: File
|
||||||
) : SettingStorage, MultiFileSettingStorage {
|
) : SettingStorage, MultiFileSettingStorage {
|
||||||
|
init {
|
||||||
|
directory.mkdir()
|
||||||
|
}
|
||||||
|
|
||||||
public override fun <T : Setting> load(holder: SettingHolder, settingClass: Class<T>): T =
|
public override fun <T : Setting> load(holder: SettingHolder, settingClass: Class<T>): T =
|
||||||
with(settingClass.kotlin) {
|
with(settingClass.kotlin) {
|
||||||
val file = getSettingFile(holder, this)
|
|
||||||
|
|
||||||
@Suppress("UNCHECKED_CAST")
|
@Suppress("UNCHECKED_CAST")
|
||||||
val instance = objectInstance ?: this.createInstanceOrNull() ?: kotlin.run {
|
val instance = objectInstance ?: this.createInstanceOrNull() ?: kotlin.run {
|
||||||
require(settingClass == Setting::class.java) {
|
require(settingClass == Setting::class.java) {
|
||||||
@ -136,15 +139,20 @@ internal open class MultiFileSettingStorageImpl(
|
|||||||
"or has a constructor which either has no parameters or all parameters of which are optional"
|
"or has a constructor which either has no parameters or all parameters of which are optional"
|
||||||
}
|
}
|
||||||
if (holder is AutoSaveSettingHolder) {
|
if (holder is AutoSaveSettingHolder) {
|
||||||
AutoSaveSetting(holder) as T?
|
AutoSaveSetting(holder, this) as T?
|
||||||
} else null
|
} else null
|
||||||
} ?: throw IllegalArgumentException(
|
} ?: throw IllegalArgumentException(
|
||||||
"Cannot create Setting instance. Make sure 'holder' is a AutoSaveSettingHolder, " +
|
"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"
|
"or 'setting' is an object or has a constructor which either has no parameters or all parameters of which are optional"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
val file = getSettingFile(holder, this)
|
||||||
file.createNewFile()
|
file.createNewFile()
|
||||||
check(file.exists() && file.isFile && file.canRead()) { "${file.absolutePath} cannot be read" }
|
check(file.exists() && file.isFile && file.canRead()) { "${file.absolutePath} cannot be read" }
|
||||||
|
val text = file.readText()
|
||||||
|
if (text.isNotBlank()) {
|
||||||
Yaml.default.decodeFromString(instance.updaterSerializer, file.readText())
|
Yaml.default.decodeFromString(instance.updaterSerializer, file.readText())
|
||||||
|
}
|
||||||
instance
|
instance
|
||||||
}.also { it.setStorage(this) }
|
}.also { it.setStorage(this) }
|
||||||
|
|
||||||
@ -155,6 +163,7 @@ internal open class MultiFileSettingStorageImpl(
|
|||||||
if (dir.isFile) {
|
if (dir.isFile) {
|
||||||
error("Target directory ${dir.path} for holder $holder is occupied by a file therefore setting $qualifiedNameOrTip can't be saved.")
|
error("Target directory ${dir.path} for holder $holder is occupied by a file therefore setting $qualifiedNameOrTip can't be saved.")
|
||||||
}
|
}
|
||||||
|
dir.mkdir()
|
||||||
|
|
||||||
val file = File(directory, name)
|
val file = File(directory, name)
|
||||||
if (file.isDirectory) {
|
if (file.isDirectory) {
|
||||||
@ -164,8 +173,9 @@ internal open class MultiFileSettingStorageImpl(
|
|||||||
}
|
}
|
||||||
|
|
||||||
@ConsoleExperimentalAPI
|
@ConsoleExperimentalAPI
|
||||||
public override fun store(holder: SettingHolder, setting: Setting): Unit = with(setting::class) {
|
public override fun store(holder: SettingHolder, setting: Setting) {
|
||||||
val file = getSettingFile(holder, this)
|
val file =
|
||||||
|
getSettingFile(holder, if (setting is AutoSaveSetting) setting.originSettingClass else setting::class)
|
||||||
|
|
||||||
if (file.exists() && file.isFile && file.canRead()) {
|
if (file.exists() && file.isFile && file.canRead()) {
|
||||||
file.writeText(Yaml.default.encodeToString(setting.updaterSerializer, Unit))
|
file.writeText(Yaml.default.encodeToString(setting.updaterSerializer, Unit))
|
||||||
|
@ -178,10 +178,10 @@ public interface AutoSaveSettingHolder : SettingHolder, CoroutineScope {
|
|||||||
*/
|
*/
|
||||||
@JvmDefault
|
@JvmDefault
|
||||||
public override fun <T : Setting> newSettingInstance(type: KType): T {
|
public override fun <T : Setting> newSettingInstance(type: KType): T {
|
||||||
val classifier = type.classifier?.cast<KClass<*>>()?.java
|
val classifier = type.classifier?.cast<KClass<Setting>>()
|
||||||
require(classifier == Setting::class.java) {
|
require(classifier != null && classifier.java == Setting::class.java) {
|
||||||
"Cannot create Setting instance. AutoSaveSettingHolder supports only Setting type."
|
"Cannot create Setting instance. AutoSaveSettingHolder supports only Setting type."
|
||||||
}
|
}
|
||||||
return AutoSaveSetting(this) as T // T is always Setting
|
return AutoSaveSetting(this, classifier) as T // T is always Setting
|
||||||
}
|
}
|
||||||
}
|
}
|
@ -46,7 +46,7 @@ internal fun startupConsoleThread() {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
CoroutineScope(dispatch).launch {
|
CoroutineScope(dispatch + SupervisorJob()).launch {
|
||||||
val consoleLogger = DefaultLogger("console")
|
val consoleLogger = DefaultLogger("console")
|
||||||
while (isActive) {
|
while (isActive) {
|
||||||
try {
|
try {
|
||||||
|
@ -48,14 +48,13 @@ class MiraiConsoleImplementationPure
|
|||||||
@JvmOverloads constructor(
|
@JvmOverloads constructor(
|
||||||
override val rootDir: File = File("."),
|
override val rootDir: File = File("."),
|
||||||
override val builtInPluginLoaders: List<PluginLoader<*, *>> = Collections.unmodifiableList(
|
override val builtInPluginLoaders: List<PluginLoader<*, *>> = Collections.unmodifiableList(
|
||||||
listOf(
|
listOf(DeferredPluginLoader { JarPluginLoader })
|
||||||
DeferredPluginLoader { JarPluginLoader })
|
|
||||||
),
|
),
|
||||||
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 settingStorageForJarPluginLoader: SettingStorage = MultiFileSettingStorage(rootDir),
|
override val settingStorageForJarPluginLoader: SettingStorage = MultiFileSettingStorage(File(rootDir, "data")),
|
||||||
override val settingStorageForBuiltIns: SettingStorage = MultiFileSettingStorage(rootDir)
|
override val settingStorageForBuiltIns: SettingStorage = MultiFileSettingStorage(File(rootDir, "data"))
|
||||||
) : MiraiConsoleImplementation, CoroutineScope by CoroutineScope(SupervisorJob()) {
|
) : MiraiConsoleImplementation, CoroutineScope by CoroutineScope(SupervisorJob()) {
|
||||||
init {
|
init {
|
||||||
rootDir.mkdir()
|
rootDir.mkdir()
|
||||||
|
Loading…
Reference in New Issue
Block a user