Fix Settings

This commit is contained in:
Him188 2020-08-20 23:46:51 +08:00
parent b00b3d97f0
commit c13076eea0
10 changed files with 61 additions and 35 deletions

View File

@ -24,6 +24,7 @@ import net.mamoe.mirai.utils.MiraiLogger
import java.io.File
import java.util.concurrent.locks.ReentrantLock
import kotlin.annotation.AnnotationTarget.*
import kotlin.coroutines.CoroutineContext
/**
@ -44,6 +45,11 @@ public annotation class ConsoleFrontEndImplementation
*/
@ConsoleFrontEndImplementation
public interface MiraiConsoleImplementation : CoroutineScope {
/**
* [MiraiConsole] [CoroutineScope.coroutineContext]
*/
public override val coroutineContext: CoroutineContext
/**
* Console 运行路径
*/

View File

@ -107,7 +107,7 @@ public object BuiltInCommands {
private val closingLock = Mutex()
@Handler
public suspend fun CommandSender.handle(): Unit {
public suspend fun CommandSender.handle() {
closingLock.withLock {
sendMessage("Stopping mirai-console")
kotlin.runCatching {

View File

@ -13,6 +13,6 @@ import java.util.*
internal object MiraiConsoleBuildConstants { // auto-filled on build (task :mirai-console:fillBuildConstants)
@JvmStatic
val buildDate: Date = Date(1596350800177L) // 2020-08-02 14:46:40
const val version: String = "1.0-M1"
val buildDate: Date = Date(1597935352287L) // 2020-08-20 22:55:52
const val version: String = "1.0-M2-1"
}

View File

@ -24,15 +24,20 @@ import kotlin.reflect.full.*
internal object CompositeCommandSubCommandAnnotationResolver :
AbstractReflectionCommand.SubCommandAnnotationResolver {
override fun hasAnnotation(function: KFunction<*>) = function.hasAnnotation<CompositeCommand.SubCommand>()
override fun getSubCommandNames(function: KFunction<*>): Array<out String> =
override fun hasAnnotation(baseCommand: AbstractReflectionCommand, function: KFunction<*>) =
function.hasAnnotation<CompositeCommand.SubCommand>()
override fun getSubCommandNames(baseCommand: AbstractReflectionCommand, function: KFunction<*>): Array<out String> =
function.findAnnotation<CompositeCommand.SubCommand>()!!.value
}
internal object SimpleCommandSubCommandAnnotationResolver :
AbstractReflectionCommand.SubCommandAnnotationResolver {
override fun hasAnnotation(function: KFunction<*>) = function.hasAnnotation<SimpleCommand.Handler>()
override fun getSubCommandNames(function: KFunction<*>): Array<out String> = arrayOf("")
override fun hasAnnotation(baseCommand: AbstractReflectionCommand, function: KFunction<*>) =
function.hasAnnotation<SimpleCommand.Handler>()
override fun getSubCommandNames(baseCommand: AbstractReflectionCommand, function: KFunction<*>): Array<out String> =
baseCommand.names
}
internal abstract class AbstractReflectionCommand @JvmOverloads constructor(
@ -74,12 +79,12 @@ internal abstract class AbstractReflectionCommand @JvmOverloads constructor(
}
interface SubCommandAnnotationResolver {
fun hasAnnotation(function: KFunction<*>): Boolean
fun getSubCommandNames(function: KFunction<*>): Array<out String>
fun hasAnnotation(baseCommand: AbstractReflectionCommand, function: KFunction<*>): Boolean
fun getSubCommandNames(baseCommand: AbstractReflectionCommand, function: KFunction<*>): Array<out String>
}
internal val subCommands: Array<SubCommandDescriptor> by lazy {
this::class.declaredFunctions.filter { subCommandAnnotationResolver.hasAnnotation(it) }
this::class.declaredFunctions.filter { subCommandAnnotationResolver.hasAnnotation(this, it) }
.also { subCommandFunctions ->
// overloading not yet supported
val overloadFunction = subCommandFunctions.groupBy { it.name }.entries.firstOrNull { it.value.size > 1 }
@ -278,7 +283,7 @@ internal fun AbstractReflectionCommand.createSubCommand(
}
val commandName =
subCommandAnnotationResolver.getSubCommandNames(function)
subCommandAnnotationResolver.getSubCommandNames(this, function)
.let { namesFromAnnotation ->
if (namesFromAnnotation.isNotEmpty()) {
namesFromAnnotation

View File

@ -11,10 +11,7 @@ package net.mamoe.mirai.console.internal.plugin
import kotlinx.atomicfu.AtomicLong
import kotlinx.atomicfu.locks.withLock
import kotlinx.coroutines.CoroutineExceptionHandler
import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.Job
import kotlinx.coroutines.SupervisorJob
import kotlinx.coroutines.*
import net.mamoe.mirai.console.MiraiConsole
import net.mamoe.mirai.console.plugin.Plugin
import net.mamoe.mirai.console.plugin.PluginManager
@ -69,6 +66,7 @@ internal abstract class JvmPluginInternal(
internal fun internalOnDisable() {
firstRun = false
this.onDisable()
this.cancel(CancellationException("plugin disabled"))
}
internal fun internalOnLoad() {

View File

@ -12,6 +12,8 @@
package net.mamoe.mirai.console.internal.plugin
import kotlinx.atomicfu.locks.withLock
import kotlinx.coroutines.InternalCoroutinesApi
import kotlinx.coroutines.Job
import net.mamoe.mirai.console.MiraiConsole
import net.mamoe.mirai.console.internal.setting.cast
import net.mamoe.mirai.console.plugin.*
@ -54,6 +56,12 @@ internal object PluginManagerImpl : PluginManager {
_pluginLoaders.remove(loader)
}
init {
@OptIn(InternalCoroutinesApi::class)
MiraiConsole.coroutineContext[Job]!!.invokeOnCompletion(true) {
plugins.forEach(Plugin::disable)
}
}
// region LOADING

View File

@ -10,10 +10,7 @@
package net.mamoe.mirai.console.internal.setting
import kotlinx.atomicfu.atomic
import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.Job
import kotlinx.coroutines.delay
import kotlinx.coroutines.launch
import kotlinx.coroutines.*
import net.mamoe.mirai.console.internal.command.qualifiedNameOrTip
import net.mamoe.mirai.console.internal.plugin.updateWhen
import net.mamoe.mirai.console.plugin.jvm.loadSetting
@ -36,7 +33,10 @@ import kotlin.reflect.full.findAnnotation
*
* @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() {
private lateinit var storage: SettingStorage
@ -54,7 +54,8 @@ internal open class AutoSaveSetting(private val owner: AutoSaveSettingHolder) :
internal var currentFirstStartTime = atomic(0L)
init {
owner.coroutineContext[Job]?.invokeOnCompletion { doSave() }
@OptIn(InternalCoroutinesApi::class)
owner.coroutineContext[Job]?.invokeOnCompletion(true) { doSave() }
}
private val updaterBlock: suspend CoroutineScope.() -> Unit = {
@ -125,10 +126,12 @@ internal class MemorySettingStorageImpl(
internal open class MultiFileSettingStorageImpl(
public final override val directory: File
) : SettingStorage, MultiFileSettingStorage {
init {
directory.mkdir()
}
public override fun <T : Setting> load(holder: SettingHolder, settingClass: Class<T>): T =
with(settingClass.kotlin) {
val file = getSettingFile(holder, this)
@Suppress("UNCHECKED_CAST")
val instance = objectInstance ?: this.createInstanceOrNull() ?: kotlin.run {
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"
}
if (holder is AutoSaveSettingHolder) {
AutoSaveSetting(holder) as T?
AutoSaveSetting(holder, this) as T?
} else null
} ?: throw IllegalArgumentException(
"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"
)
val file = getSettingFile(holder, this)
file.createNewFile()
check(file.exists() && file.isFile && file.canRead()) { "${file.absolutePath} cannot be read" }
Yaml.default.decodeFromString(instance.updaterSerializer, file.readText())
val text = file.readText()
if (text.isNotBlank()) {
Yaml.default.decodeFromString(instance.updaterSerializer, file.readText())
}
instance
}.also { it.setStorage(this) }
@ -155,6 +163,7 @@ internal open class MultiFileSettingStorageImpl(
if (dir.isFile) {
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)
if (file.isDirectory) {
@ -164,8 +173,9 @@ internal open class MultiFileSettingStorageImpl(
}
@ConsoleExperimentalAPI
public override fun store(holder: SettingHolder, setting: Setting): Unit = with(setting::class) {
val file = getSettingFile(holder, this)
public override fun store(holder: SettingHolder, setting: Setting) {
val file =
getSettingFile(holder, if (setting is AutoSaveSetting) setting.originSettingClass else setting::class)
if (file.exists() && file.isFile && file.canRead()) {
file.writeText(Yaml.default.encodeToString(setting.updaterSerializer, Unit))

View File

@ -178,10 +178,10 @@ public interface AutoSaveSettingHolder : SettingHolder, CoroutineScope {
*/
@JvmDefault
public override fun <T : Setting> newSettingInstance(type: KType): T {
val classifier = type.classifier?.cast<KClass<*>>()?.java
require(classifier == Setting::class.java) {
val classifier = type.classifier?.cast<KClass<Setting>>()
require(classifier != null && classifier.java == Setting::class.java) {
"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
}
}

View File

@ -46,7 +46,7 @@ internal fun startupConsoleThread() {
}
}
CoroutineScope(dispatch).launch {
CoroutineScope(dispatch + SupervisorJob()).launch {
val consoleLogger = DefaultLogger("console")
while (isActive) {
try {

View File

@ -48,14 +48,13 @@ class MiraiConsoleImplementationPure
@JvmOverloads constructor(
override val rootDir: File = File("."),
override val builtInPluginLoaders: List<PluginLoader<*, *>> = Collections.unmodifiableList(
listOf(
DeferredPluginLoader { JarPluginLoader })
listOf(DeferredPluginLoader { JarPluginLoader })
),
override val frontEnd: MiraiConsoleFrontEnd = MiraiConsoleFrontEndPure,
override val mainLogger: MiraiLogger = frontEnd.loggerFor("main"),
override val consoleCommandSender: ConsoleCommandSender = ConsoleCommandSenderImpl,
override val settingStorageForJarPluginLoader: SettingStorage = MultiFileSettingStorage(rootDir),
override val settingStorageForBuiltIns: SettingStorage = MultiFileSettingStorage(rootDir)
override val settingStorageForJarPluginLoader: SettingStorage = MultiFileSettingStorage(File(rootDir, "data")),
override val settingStorageForBuiltIns: SettingStorage = MultiFileSettingStorage(File(rootDir, "data"))
) : MiraiConsoleImplementation, CoroutineScope by CoroutineScope(SupervisorJob()) {
init {
rootDir.mkdir()