mirror of
https://github.com/mamoe/mirai.git
synced 2025-01-10 18:40:15 +08:00
Explicit APIs
This commit is contained in:
parent
55ec375e09
commit
58187f95f0
@ -7,7 +7,7 @@
|
||||
* https://github.com/mamoe/mirai/blob/master/LICENSE
|
||||
*/
|
||||
|
||||
@file:Suppress("PRE_RELEASE_CLASS", "ClassName")
|
||||
@file:Suppress("PRE_RELEASE_CLASS", "ClassName", "RedundantVisibilityModifier")
|
||||
|
||||
package net.mamoe.mirai.console.codegen
|
||||
|
||||
@ -15,7 +15,7 @@ import kotlin.reflect.full.functions
|
||||
import kotlin.reflect.full.hasAnnotation
|
||||
import kotlin.reflect.full.isSubclassOf
|
||||
|
||||
object ValueSettingCodegen {
|
||||
internal object ValueSettingCodegen {
|
||||
/**
|
||||
* The interface
|
||||
*/
|
||||
@ -31,7 +31,7 @@ object ValueSettingCodegen {
|
||||
/**
|
||||
* Represents a non-null [$ktType] value.
|
||||
*/
|
||||
interface ${ktType}Value : PrimitiveValue<$ktType>
|
||||
public interface ${ktType}Value : PrimitiveValue<$ktType>
|
||||
"""
|
||||
)
|
||||
}
|
||||
@ -47,7 +47,7 @@ object ValueSettingCodegen {
|
||||
kCode(
|
||||
"""
|
||||
@JvmStatic
|
||||
val ${ktType.standardName}SerializerDescriptor = ${ktType.standardName}.serializer().descriptor
|
||||
internal val ${ktType.standardName}SerializerDescriptor = ${ktType.standardName}.serializer().descriptor
|
||||
"""
|
||||
).lines().joinToString("\n") { " $it" }
|
||||
)
|
||||
@ -145,7 +145,7 @@ internal fun Setting.${ktType.lowerCaseName}ValueImpl(): SerializerAwareValue<${
|
||||
@Suppress("unused")
|
||||
appendKCode(
|
||||
"""
|
||||
fun Setting.value(default: ${ktType.standardName}): SerializerAwareValue<${ktType.standardName}> = valueImpl(default)
|
||||
public fun Setting.value(default: ${ktType.standardName}): SerializerAwareValue<${ktType.standardName}> = valueImpl(default)
|
||||
"""
|
||||
)
|
||||
}
|
||||
|
@ -23,6 +23,8 @@ tasks.withType(JavaCompile::class.java) {
|
||||
}
|
||||
|
||||
kotlin {
|
||||
explicitApiWarning()
|
||||
|
||||
sourceSets.all {
|
||||
target.compilations.all {
|
||||
kotlinOptions {
|
||||
@ -46,12 +48,17 @@ kotlin {
|
||||
}
|
||||
}
|
||||
|
||||
sourceSets {
|
||||
sourceSets.invoke {
|
||||
getByName("test") {
|
||||
languageSettings.apply {
|
||||
languageVersion = "1.4"
|
||||
}
|
||||
}
|
||||
getByName("main") {
|
||||
languageSettings.apply {
|
||||
languageVersion = "1.3"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -71,7 +78,7 @@ dependencies {
|
||||
testImplementation("org.junit.jupiter:junit-jupiter-api:5.2.0")
|
||||
testRuntimeOnly("org.junit.jupiter:junit-jupiter-engine:5.2.0")
|
||||
}
|
||||
ext {
|
||||
ext.apply {
|
||||
// 傻逼 compileAndRuntime 没 exclude 掉
|
||||
// 傻逼 gradle 第二次配置 task 会覆盖掉第一次的配置
|
||||
val x: com.github.jengelman.gradle.plugins.shadow.tasks.ShadowJar.() -> Unit = {
|
||||
@ -83,7 +90,7 @@ ext {
|
||||
}
|
||||
}
|
||||
}
|
||||
this.set("shadowJar", x)
|
||||
set("shadowJar", x)
|
||||
}
|
||||
|
||||
tasks {
|
||||
|
@ -23,6 +23,7 @@ import net.mamoe.mirai.console.command.internal.InternalCommandManager
|
||||
import net.mamoe.mirai.console.command.primaryName
|
||||
import net.mamoe.mirai.console.plugin.PluginLoader
|
||||
import net.mamoe.mirai.console.plugin.PluginManager
|
||||
import net.mamoe.mirai.console.plugin.PluginManagerImpl
|
||||
import net.mamoe.mirai.console.plugin.center.CuiPluginCenter
|
||||
import net.mamoe.mirai.console.plugin.center.PluginCenter
|
||||
import net.mamoe.mirai.console.plugin.jvm.JarPluginLoader
|
||||
@ -45,43 +46,47 @@ import kotlin.coroutines.CoroutineContext
|
||||
*
|
||||
* @see INSTANCE
|
||||
*/
|
||||
interface MiraiConsole : CoroutineScope {
|
||||
public interface MiraiConsole : CoroutineScope {
|
||||
/**
|
||||
* Console 运行路径
|
||||
*/
|
||||
val rootDir: File
|
||||
public val rootDir: File
|
||||
|
||||
/**
|
||||
* Console 前端接口
|
||||
*/
|
||||
val frontEnd: MiraiConsoleFrontEnd
|
||||
public val frontEnd: MiraiConsoleFrontEnd
|
||||
|
||||
/**
|
||||
* 与前端交互所使用的 Logger
|
||||
*/
|
||||
val mainLogger: MiraiLogger
|
||||
public val mainLogger: MiraiLogger
|
||||
|
||||
/**
|
||||
* 内建加载器列表, 一般需要包含 [JarPluginLoader]
|
||||
*/
|
||||
val builtInPluginLoaders: List<PluginLoader<*, *>>
|
||||
public val builtInPluginLoaders: List<PluginLoader<*, *>>
|
||||
|
||||
val buildDate: Date
|
||||
public val buildDate: Date
|
||||
|
||||
val version: String
|
||||
public val version: String
|
||||
|
||||
val pluginCenter: PluginCenter
|
||||
public val pluginCenter: PluginCenter
|
||||
|
||||
@ConsoleExperimentalAPI
|
||||
fun newLogger(identity: String?): MiraiLogger
|
||||
public fun newLogger(identity: String?): MiraiLogger
|
||||
|
||||
companion object INSTANCE : MiraiConsole by MiraiConsoleInternal
|
||||
public companion object INSTANCE : MiraiConsole by MiraiConsoleInternal
|
||||
}
|
||||
|
||||
public class IllegalMiraiConsoleImplementationError(
|
||||
override val message: String?
|
||||
) : Error()
|
||||
|
||||
/**
|
||||
* 获取 [MiraiConsole] 的 [Job]
|
||||
*/
|
||||
val MiraiConsole.job: Job
|
||||
public val MiraiConsole.job: Job
|
||||
get() = this.coroutineContext[Job] ?: error("Internal error: Job not found in MiraiConsole.coroutineContext")
|
||||
|
||||
//// internal
|
||||
@ -149,17 +154,13 @@ internal object MiraiConsoleInternal : CoroutineScope, IMiraiConsole, MiraiConso
|
||||
InternalCommandManager.commandListener // start
|
||||
|
||||
mainLogger.info { "Loading plugins..." }
|
||||
PluginManager.loadEnablePlugins()
|
||||
PluginManagerImpl.loadEnablePlugins()
|
||||
mainLogger.info { "${PluginManager.plugins.size} plugin(s) loaded." }
|
||||
mainLogger.info { "mirai-console started successfully." }
|
||||
// Only for initialize
|
||||
}
|
||||
}
|
||||
|
||||
class IllegalMiraiConsoleImplementationError(
|
||||
override val message: String?
|
||||
) : Error()
|
||||
|
||||
|
||||
// 前端使用
|
||||
internal interface IMiraiConsole : CoroutineScope {
|
||||
|
@ -17,33 +17,33 @@ import net.mamoe.mirai.utils.MiraiLogger
|
||||
* 只需要实现一个这个传入 MiraiConsole 就可以绑定 UI 层与 Console 层
|
||||
* 需要保证线程安全
|
||||
*/
|
||||
interface MiraiConsoleFrontEnd {
|
||||
public interface MiraiConsoleFrontEnd {
|
||||
/**
|
||||
* 名称
|
||||
*/
|
||||
val name: String
|
||||
public val name: String
|
||||
|
||||
/**
|
||||
* 版本
|
||||
*/
|
||||
val version: String
|
||||
public val version: String
|
||||
|
||||
fun loggerFor(identity: String?): MiraiLogger
|
||||
public fun loggerFor(identity: String?): MiraiLogger
|
||||
|
||||
/**
|
||||
* 让 UI 层接受一个新的bot
|
||||
* */
|
||||
fun pushBot(
|
||||
public fun pushBot(
|
||||
bot: Bot
|
||||
)
|
||||
|
||||
/**
|
||||
* 让 UI 层提供一个输入, 相当于 [readLine]
|
||||
*/
|
||||
suspend fun requestInput(hint: String): String
|
||||
public suspend fun requestInput(hint: String): String
|
||||
|
||||
/**
|
||||
* 由 UI 层创建一个 [LoginSolver]
|
||||
*/
|
||||
fun createLoginSolver(): LoginSolver
|
||||
public fun createLoginSolver(): LoginSolver
|
||||
}
|
@ -29,7 +29,7 @@ import kotlin.system.exitProcess
|
||||
/**
|
||||
* 添加一个 [Bot] 实例到全局 Bot 列表, 但不登录.
|
||||
*/
|
||||
fun MiraiConsole.addBot(id: Long, password: String): Bot {
|
||||
public fun MiraiConsole.addBot(id: Long, password: String): Bot {
|
||||
return Bot(id, password) {
|
||||
|
||||
/**
|
||||
@ -65,15 +65,15 @@ fun MiraiConsole.addBot(id: Long, password: String): Bot {
|
||||
}
|
||||
|
||||
@Suppress("EXPOSED_SUPER_INTERFACE")
|
||||
interface BuiltInCommand : Command, BuiltInCommandInternal
|
||||
public interface BuiltInCommand : Command, BuiltInCommandInternal
|
||||
|
||||
// for identification
|
||||
internal interface BuiltInCommandInternal : Command
|
||||
|
||||
@Suppress("unused")
|
||||
object BuiltInCommands {
|
||||
public object BuiltInCommands {
|
||||
|
||||
val all: Array<out Command> by lazy {
|
||||
public val all: Array<out Command> by lazy {
|
||||
this::class.nestedClasses.mapNotNull { it.objectInstance as? Command }.toTypedArray()
|
||||
}
|
||||
|
||||
@ -83,7 +83,7 @@ object BuiltInCommands {
|
||||
}
|
||||
}
|
||||
|
||||
object Help : SimpleCommand(
|
||||
public object Help : SimpleCommand(
|
||||
ConsoleCommandOwner, "help",
|
||||
description = "Gets help about the console."
|
||||
), BuiltInCommand {
|
||||
@ -94,13 +94,13 @@ object BuiltInCommands {
|
||||
}
|
||||
|
||||
@Handler
|
||||
suspend fun CommandSender.handle() {
|
||||
public suspend fun CommandSender.handle() {
|
||||
sendMessage("现在有指令: ${allRegisteredCommands.joinToString { it.primaryName }}")
|
||||
sendMessage("帮助还没写, 将就一下")
|
||||
}
|
||||
}
|
||||
|
||||
object Stop : SimpleCommand(
|
||||
public object Stop : SimpleCommand(
|
||||
ConsoleCommandOwner, "stop", "shutdown", "exit",
|
||||
description = "Stop the whole world."
|
||||
), BuiltInCommand {
|
||||
@ -116,7 +116,7 @@ object BuiltInCommands {
|
||||
private val closingLock = Mutex()
|
||||
|
||||
@Handler
|
||||
suspend fun CommandSender.handle(): Unit = closingLock.withLock {
|
||||
public suspend fun CommandSender.handle(): Unit = closingLock.withLock {
|
||||
sendMessage("Stopping mirai-console")
|
||||
kotlin.runCatching {
|
||||
MiraiConsole.job.cancelAndJoin()
|
||||
@ -131,19 +131,20 @@ object BuiltInCommands {
|
||||
}
|
||||
}
|
||||
|
||||
object Login : SimpleCommand(
|
||||
public object Login : SimpleCommand(
|
||||
ConsoleCommandOwner, "login",
|
||||
description = "Log in a bot account."
|
||||
), BuiltInCommand {
|
||||
@Handler
|
||||
suspend fun CommandSender.handle(id: Long, password: String) {
|
||||
public suspend fun CommandSender.handle(id: Long, password: String) {
|
||||
|
||||
kotlin.runCatching {
|
||||
MiraiConsole.addBot(id, password).alsoLogin()
|
||||
}.fold(
|
||||
onSuccess = { sendMessage("${it.nick} ($id) Login succeed") },
|
||||
onFailure = { throwable ->
|
||||
sendMessage("Login failed: ${throwable.localizedMessage ?: throwable.message ?: throwable.toString()}" +
|
||||
sendMessage(
|
||||
"Login failed: ${throwable.localizedMessage ?: throwable.message ?: throwable.toString()}" +
|
||||
if (this is MessageEventContextAware<*>) {
|
||||
this.fromEvent.selectMessagesUnit {
|
||||
"stacktrace" reply {
|
||||
|
@ -22,55 +22,58 @@ import net.mamoe.mirai.message.data.SingleMessage
|
||||
* @see RawCommand
|
||||
* @see CompositeCommand
|
||||
*/
|
||||
interface Command {
|
||||
public interface Command {
|
||||
/**
|
||||
* 指令名. 需要至少有一个元素. 所有元素都不能带有空格
|
||||
*/
|
||||
val names: Array<out String>
|
||||
public val names: Array<out String>
|
||||
|
||||
val usage: String
|
||||
public val usage: String
|
||||
|
||||
val description: String
|
||||
public val description: String
|
||||
|
||||
/**
|
||||
* 指令权限
|
||||
*/
|
||||
val permission: CommandPermission
|
||||
public val permission: CommandPermission
|
||||
|
||||
/**
|
||||
* 为 `true` 时表示 [指令前缀][CommandPrefix] 可选
|
||||
*/
|
||||
val prefixOptional: Boolean
|
||||
public val prefixOptional: Boolean
|
||||
|
||||
val owner: CommandOwner
|
||||
public val owner: CommandOwner
|
||||
|
||||
/**
|
||||
* @param args 指令参数. 可能是 [SingleMessage] 或 [String]. 且已经以 ' ' 分割.
|
||||
*
|
||||
* @see Command.execute
|
||||
*/ // TODO: 2020/6/28 Java-friendly bridges
|
||||
suspend fun CommandSender.onCommand(args: Array<out Any>)
|
||||
public suspend fun CommandSender.onCommand(args: Array<out Any>)
|
||||
}
|
||||
|
||||
/**
|
||||
* [Command] 的基础实现
|
||||
*/
|
||||
abstract class AbstractCommand @JvmOverloads constructor(
|
||||
final override val owner: CommandOwner,
|
||||
public abstract class AbstractCommand @JvmOverloads constructor(
|
||||
public final override val owner: CommandOwner,
|
||||
vararg names: String,
|
||||
description: String = "<no description available>",
|
||||
final override val permission: CommandPermission = CommandPermission.Default,
|
||||
final override val prefixOptional: Boolean = false
|
||||
public final override val permission: CommandPermission = CommandPermission.Default,
|
||||
public final override val prefixOptional: Boolean = false
|
||||
) : Command {
|
||||
final override val description = description.trimIndent()
|
||||
final override val names: Array<out String> =
|
||||
public final override val description: String = description.trimIndent()
|
||||
public final override val names: Array<out String> =
|
||||
names.map(String::trim).filterNot(String::isEmpty).map(String::toLowerCase).also { list ->
|
||||
list.firstOrNull { !it.isValidSubName() }?.let { error("Invalid name: $it") }
|
||||
}.toTypedArray()
|
||||
|
||||
}
|
||||
|
||||
suspend inline fun Command.onCommand(sender: CommandSender, args: Array<out Any>) = sender.run { onCommand(args) }
|
||||
public suspend inline fun Command.onCommand(sender: CommandSender, args: Array<out Any>): Unit =
|
||||
sender.run { onCommand(args) }
|
||||
|
||||
/**
|
||||
* 主要指令名. 为 [Command.names] 的第一个元素.
|
||||
*/
|
||||
val Command.primaryName: String get() = names[0]
|
||||
public val Command.primaryName: String get() = names[0]
|
@ -20,94 +20,94 @@ import kotlin.contracts.contract
|
||||
*
|
||||
* @see CommandExecuteStatus
|
||||
*/
|
||||
sealed class CommandExecuteResult {
|
||||
public sealed class CommandExecuteResult {
|
||||
/** 指令最终执行状态 */
|
||||
abstract val status: CommandExecuteStatus
|
||||
public abstract val status: CommandExecuteStatus
|
||||
|
||||
/** 指令执行时发生的错误 (如果有) */
|
||||
abstract val exception: Throwable?
|
||||
public abstract val exception: Throwable?
|
||||
|
||||
/** 尝试执行的指令 (如果匹配到) */
|
||||
abstract val command: Command?
|
||||
public abstract val command: Command?
|
||||
|
||||
/** 尝试执行的指令名 (如果匹配到) */
|
||||
abstract val commandName: String?
|
||||
public abstract val commandName: String?
|
||||
|
||||
/** 基础分割后的实际参数列表, 元素类型可能为 [Message] 或 [String] */
|
||||
abstract val args: Array<out Any>?
|
||||
public abstract val args: Array<out Any>?
|
||||
|
||||
// abstract val to allow smart casting
|
||||
|
||||
/** 指令执行成功 */
|
||||
class Success(
|
||||
public class Success(
|
||||
/** 尝试执行的指令 */
|
||||
override val command: Command,
|
||||
public override val command: Command,
|
||||
/** 尝试执行的指令名 */
|
||||
override val commandName: String,
|
||||
public override val commandName: String,
|
||||
/** 基础分割后的实际参数列表, 元素类型可能为 [Message] 或 [String] */
|
||||
override val args: Array<out Any>
|
||||
public override val args: Array<out Any>
|
||||
) : CommandExecuteResult() {
|
||||
/** 指令执行时发生的错误, 总是 `null` */
|
||||
override val exception: Nothing? get() = null
|
||||
public override val exception: Nothing? get() = null
|
||||
|
||||
/** 指令最终执行状态, 总是 [CommandExecuteStatus.SUCCESSFUL] */
|
||||
override val status: CommandExecuteStatus get() = CommandExecuteStatus.SUCCESSFUL
|
||||
public override val status: CommandExecuteStatus get() = CommandExecuteStatus.SUCCESSFUL
|
||||
}
|
||||
|
||||
/** 指令执行过程出现了错误 */
|
||||
class ExecutionException(
|
||||
public class ExecutionException(
|
||||
/** 指令执行时发生的错误 */
|
||||
override val exception: Throwable,
|
||||
public override val exception: Throwable,
|
||||
/** 尝试执行的指令 */
|
||||
override val command: Command,
|
||||
public override val command: Command,
|
||||
/** 尝试执行的指令名 */
|
||||
override val commandName: String,
|
||||
public override val commandName: String,
|
||||
/** 基础分割后的实际参数列表, 元素类型可能为 [Message] 或 [String] */
|
||||
override val args: Array<out Any>
|
||||
public override val args: Array<out Any>
|
||||
) : CommandExecuteResult() {
|
||||
/** 指令最终执行状态, 总是 [CommandExecuteStatus.EXECUTION_EXCEPTION] */
|
||||
override val status: CommandExecuteStatus get() = CommandExecuteStatus.EXECUTION_EXCEPTION
|
||||
public override val status: CommandExecuteStatus get() = CommandExecuteStatus.EXECUTION_EXCEPTION
|
||||
}
|
||||
|
||||
/** 没有匹配的指令 */
|
||||
class CommandNotFound(
|
||||
public class CommandNotFound(
|
||||
/** 尝试执行的指令名 */
|
||||
override val commandName: String
|
||||
public override val commandName: String
|
||||
) : CommandExecuteResult() {
|
||||
/** 指令执行时发生的错误, 总是 `null` */
|
||||
override val exception: Nothing? get() = null
|
||||
public override val exception: Nothing? get() = null
|
||||
|
||||
/** 尝试执行的指令, 总是 `null` */
|
||||
override val command: Nothing? get() = null
|
||||
public override val command: Nothing? get() = null
|
||||
|
||||
/** 基础分割后的实际参数列表, 元素类型可能为 [Message] 或 [String] */
|
||||
override val args: Nothing? get() = null
|
||||
public override val args: Nothing? get() = null
|
||||
|
||||
/** 指令最终执行状态, 总是 [CommandExecuteStatus.COMMAND_NOT_FOUND] */
|
||||
override val status: CommandExecuteStatus get() = CommandExecuteStatus.COMMAND_NOT_FOUND
|
||||
public override val status: CommandExecuteStatus get() = CommandExecuteStatus.COMMAND_NOT_FOUND
|
||||
}
|
||||
|
||||
/** 权限不足 */
|
||||
class PermissionDenied(
|
||||
public class PermissionDenied(
|
||||
/** 尝试执行的指令 */
|
||||
override val command: Command,
|
||||
public override val command: Command,
|
||||
/** 尝试执行的指令名 */
|
||||
override val commandName: String
|
||||
public override val commandName: String
|
||||
) : CommandExecuteResult() {
|
||||
/** 基础分割后的实际参数列表, 元素类型可能为 [Message] 或 [String] */
|
||||
override val args: Nothing? get() = null
|
||||
public override val args: Nothing? get() = null
|
||||
|
||||
/** 指令执行时发生的错误, 总是 `null` */
|
||||
override val exception: Nothing? get() = null
|
||||
public override val exception: Nothing? get() = null
|
||||
|
||||
/** 指令最终执行状态, 总是 [CommandExecuteStatus.PERMISSION_DENIED] */
|
||||
override val status: CommandExecuteStatus get() = CommandExecuteStatus.PERMISSION_DENIED
|
||||
public override val status: CommandExecuteStatus get() = CommandExecuteStatus.PERMISSION_DENIED
|
||||
}
|
||||
|
||||
/**
|
||||
* 指令的执行状态
|
||||
*/
|
||||
enum class CommandExecuteStatus {
|
||||
public enum class CommandExecuteStatus {
|
||||
/** 指令执行成功 */
|
||||
SUCCESSFUL,
|
||||
|
||||
@ -124,13 +124,13 @@ sealed class CommandExecuteResult {
|
||||
|
||||
|
||||
@Suppress("RemoveRedundantQualifierName")
|
||||
typealias CommandExecuteStatus = CommandExecuteResult.CommandExecuteStatus
|
||||
public typealias CommandExecuteStatus = CommandExecuteResult.CommandExecuteStatus
|
||||
|
||||
/**
|
||||
* 当 [this] 为 [CommandExecuteResult.Success] 时返回 `true`
|
||||
*/
|
||||
@JvmSynthetic
|
||||
fun CommandExecuteResult.isSuccess(): Boolean {
|
||||
public fun CommandExecuteResult.isSuccess(): Boolean {
|
||||
contract {
|
||||
returns(true) implies (this@isSuccess is CommandExecuteResult.Success)
|
||||
returns(false) implies (this@isSuccess !is CommandExecuteResult.Success)
|
||||
@ -142,7 +142,7 @@ fun CommandExecuteResult.isSuccess(): Boolean {
|
||||
* 当 [this] 为 [CommandExecuteResult.ExecutionException] 时返回 `true`
|
||||
*/
|
||||
@JvmSynthetic
|
||||
fun CommandExecuteResult.isExecutionException(): Boolean {
|
||||
public fun CommandExecuteResult.isExecutionException(): Boolean {
|
||||
contract {
|
||||
returns(true) implies (this@isExecutionException is CommandExecuteResult.ExecutionException)
|
||||
returns(false) implies (this@isExecutionException !is CommandExecuteResult.ExecutionException)
|
||||
@ -154,7 +154,7 @@ fun CommandExecuteResult.isExecutionException(): Boolean {
|
||||
* 当 [this] 为 [CommandExecuteResult.ExecutionException] 时返回 `true`
|
||||
*/
|
||||
@JvmSynthetic
|
||||
fun CommandExecuteResult.isPermissionDenied(): Boolean {
|
||||
public fun CommandExecuteResult.isPermissionDenied(): Boolean {
|
||||
contract {
|
||||
returns(true) implies (this@isPermissionDenied is CommandExecuteResult.PermissionDenied)
|
||||
returns(false) implies (this@isPermissionDenied !is CommandExecuteResult.PermissionDenied)
|
||||
@ -166,7 +166,7 @@ fun CommandExecuteResult.isPermissionDenied(): Boolean {
|
||||
* 当 [this] 为 [CommandExecuteResult.ExecutionException] 时返回 `true`
|
||||
*/
|
||||
@JvmSynthetic
|
||||
fun CommandExecuteResult.isCommandNotFound(): Boolean {
|
||||
public fun CommandExecuteResult.isCommandNotFound(): Boolean {
|
||||
contract {
|
||||
returns(true) implies (this@isCommandNotFound is CommandExecuteResult.CommandNotFound)
|
||||
returns(false) implies (this@isCommandNotFound !is CommandExecuteResult.CommandNotFound)
|
||||
@ -178,7 +178,7 @@ fun CommandExecuteResult.isCommandNotFound(): Boolean {
|
||||
* 当 [this] 为 [CommandExecuteResult.ExecutionException] 或 [CommandExecuteResult.CommandNotFound] 时返回 `true`
|
||||
*/
|
||||
@JvmSynthetic
|
||||
fun CommandExecuteResult.isFailure(): Boolean {
|
||||
public fun CommandExecuteResult.isFailure(): Boolean {
|
||||
contract {
|
||||
returns(true) implies (this@isFailure !is CommandExecuteResult.Success)
|
||||
returns(false) implies (this@isFailure is CommandExecuteResult.Success)
|
||||
|
@ -14,21 +14,21 @@ package net.mamoe.mirai.console.command
|
||||
/**
|
||||
* 在 [executeCommand] 中, [Command.onCommand] 抛出异常时包装的异常.
|
||||
*/
|
||||
class CommandExecutionException(
|
||||
public class CommandExecutionException(
|
||||
/**
|
||||
* 执行过程发生异常的指令
|
||||
*/
|
||||
val command: Command,
|
||||
public val command: Command,
|
||||
/**
|
||||
* 匹配到的指令名
|
||||
*/
|
||||
val name: String,
|
||||
public val name: String,
|
||||
cause: Throwable
|
||||
) : RuntimeException(
|
||||
"Exception while executing command '${command.primaryName}'",
|
||||
cause
|
||||
) {
|
||||
override fun toString(): String =
|
||||
public override fun toString(): String =
|
||||
"CommandExecutionException(command=$command, name='$name')"
|
||||
}
|
||||
|
||||
|
@ -27,12 +27,12 @@ import net.mamoe.mirai.message.data.MessageChain
|
||||
* 指令的所有者.
|
||||
* @see PluginCommandOwner
|
||||
*/
|
||||
sealed class CommandOwner
|
||||
public sealed class CommandOwner
|
||||
|
||||
/**
|
||||
* 插件指令所有者. 插件只能通过 [PluginCommandOwner] 管理指令.
|
||||
*/
|
||||
abstract class PluginCommandOwner(val plugin: Plugin) : CommandOwner() {
|
||||
public abstract class PluginCommandOwner(public val plugin: Plugin) : CommandOwner() {
|
||||
init {
|
||||
if (plugin is CoroutineScope) { // JVM Plugin
|
||||
plugin.coroutineContext[Job]?.invokeOnCompletion {
|
||||
@ -45,33 +45,33 @@ abstract class PluginCommandOwner(val plugin: Plugin) : CommandOwner() {
|
||||
/**
|
||||
* 代表控制台所有者. 所有的 mirai-console 内建的指令都属于 [ConsoleCommandOwner].
|
||||
*/
|
||||
object ConsoleCommandOwner : CommandOwner()
|
||||
public object ConsoleCommandOwner : CommandOwner()
|
||||
|
||||
/**
|
||||
* 获取已经注册了的属于这个 [CommandOwner] 的指令列表.
|
||||
* @see JCommandManager.getRegisteredCommands Java 方法
|
||||
*/
|
||||
val CommandOwner.registeredCommands: List<Command> get() = InternalCommandManager.registeredCommands.filter { it.owner == this }
|
||||
public val CommandOwner.registeredCommands: List<Command> get() = InternalCommandManager.registeredCommands.filter { it.owner == this }
|
||||
|
||||
/**
|
||||
* 获取所有已经注册了指令列表.
|
||||
* @see JCommandManager.getRegisteredCommands Java 方法
|
||||
*/
|
||||
val allRegisteredCommands: List<Command> get() = InternalCommandManager.registeredCommands.toList() // copy
|
||||
public val allRegisteredCommands: List<Command> get() = InternalCommandManager.registeredCommands.toList() // copy
|
||||
|
||||
/**
|
||||
* 指令前缀, 如 '/'
|
||||
* @see JCommandManager.getCommandPrefix Java 方法
|
||||
*/
|
||||
@get:JvmName("getCommandPrefix")
|
||||
val CommandPrefix: String
|
||||
public val CommandPrefix: String
|
||||
get() = InternalCommandManager.COMMAND_PREFIX
|
||||
|
||||
/**
|
||||
* 取消注册所有属于 [this] 的指令
|
||||
* @see JCommandManager.unregisterAllCommands Java 方法
|
||||
*/
|
||||
fun CommandOwner.unregisterAllCommands() {
|
||||
public fun CommandOwner.unregisterAllCommands() {
|
||||
for (registeredCommand in registeredCommands) {
|
||||
registeredCommand.unregister()
|
||||
}
|
||||
@ -94,7 +94,7 @@ fun CommandOwner.unregisterAllCommands() {
|
||||
* @see JCommandManager.register Java 方法
|
||||
*/
|
||||
@JvmOverloads
|
||||
fun Command.register(override: Boolean = false): Boolean {
|
||||
public fun Command.register(override: Boolean = false): Boolean {
|
||||
if (this is CompositeCommand) this.subCommands // init
|
||||
|
||||
InternalCommandManager.modifyLock.withLock {
|
||||
@ -124,7 +124,7 @@ fun Command.register(override: Boolean = false): Boolean {
|
||||
*
|
||||
* @see JCommandManager.findDuplicate Java 方法
|
||||
*/
|
||||
fun Command.findDuplicate(): Command? =
|
||||
public fun Command.findDuplicate(): Command? =
|
||||
InternalCommandManager.registeredCommands.firstOrNull { it.names intersectsIgnoringCase this.names }
|
||||
|
||||
/**
|
||||
@ -132,7 +132,7 @@ fun Command.findDuplicate(): Command? =
|
||||
*
|
||||
* @see JCommandManager.unregister Java 方法
|
||||
*/
|
||||
fun Command.unregister(): Boolean = InternalCommandManager.modifyLock.withLock {
|
||||
public fun Command.unregister(): Boolean = InternalCommandManager.modifyLock.withLock {
|
||||
if (this.prefixOptional) {
|
||||
this.names.forEach {
|
||||
InternalCommandManager.optionalPrefixCommandMap.remove(it)
|
||||
@ -147,7 +147,7 @@ fun Command.unregister(): Boolean = InternalCommandManager.modifyLock.withLock {
|
||||
/**
|
||||
* 当 [this] 已经 [注册][register] 后返回 `true`
|
||||
*/
|
||||
fun Command.isRegistered(): Boolean = this in InternalCommandManager.registeredCommands
|
||||
public fun Command.isRegistered(): Boolean = this in InternalCommandManager.registeredCommands
|
||||
|
||||
//// executing without detailed result (faster)
|
||||
|
||||
@ -161,7 +161,7 @@ fun Command.isRegistered(): Boolean = this in InternalCommandManager.registeredC
|
||||
*
|
||||
* @see JCommandManager.executeCommand Java 方法
|
||||
*/
|
||||
suspend fun CommandSender.executeCommand(vararg messages: Any): Command? {
|
||||
public suspend fun CommandSender.executeCommand(vararg messages: Any): Command? {
|
||||
if (messages.isEmpty()) return null
|
||||
return matchAndExecuteCommandInternal(messages, messages[0].toString().substringBefore(' '))
|
||||
}
|
||||
@ -175,7 +175,7 @@ suspend fun CommandSender.executeCommand(vararg messages: Any): Command? {
|
||||
* @see JCommandManager.executeCommand Java 方法
|
||||
*/
|
||||
@Throws(CommandExecutionException::class)
|
||||
suspend fun CommandSender.executeCommand(message: MessageChain): Command? {
|
||||
public suspend fun CommandSender.executeCommand(message: MessageChain): Command? {
|
||||
if (message.isEmpty()) return null
|
||||
return matchAndExecuteCommandInternal(message, message[0].toString().substringBefore(' '))
|
||||
}
|
||||
@ -190,7 +190,7 @@ suspend fun CommandSender.executeCommand(message: MessageChain): Command? {
|
||||
*/
|
||||
@JvmOverloads
|
||||
@Throws(CommandExecutionException::class)
|
||||
suspend fun Command.execute(sender: CommandSender, args: MessageChain, checkPermission: Boolean = true) {
|
||||
public suspend fun Command.execute(sender: CommandSender, args: MessageChain, checkPermission: Boolean = true) {
|
||||
sender.executeCommandInternal(
|
||||
this,
|
||||
args.flattenCommandComponents().toTypedArray(),
|
||||
@ -209,7 +209,7 @@ suspend fun Command.execute(sender: CommandSender, args: MessageChain, checkPerm
|
||||
*/
|
||||
@JvmOverloads
|
||||
@Throws(CommandExecutionException::class)
|
||||
suspend fun Command.execute(sender: CommandSender, vararg args: Any, checkPermission: Boolean = true) {
|
||||
public suspend fun Command.execute(sender: CommandSender, vararg args: Any, checkPermission: Boolean = true) {
|
||||
sender.executeCommandInternal(
|
||||
this,
|
||||
args.flattenCommandComponents().toTypedArray(),
|
||||
@ -229,7 +229,7 @@ suspend fun Command.execute(sender: CommandSender, vararg args: Any, checkPermis
|
||||
*
|
||||
* @see JCommandManager.executeCommandDetailed Java 方法
|
||||
*/
|
||||
suspend fun CommandSender.executeCommandDetailed(vararg messages: Any): CommandExecuteResult {
|
||||
public suspend fun CommandSender.executeCommandDetailed(vararg messages: Any): CommandExecuteResult {
|
||||
if (messages.isEmpty()) return CommandExecuteResult.CommandNotFound("")
|
||||
return executeCommandDetailedInternal(messages, messages[0].toString().substringBefore(' '))
|
||||
}
|
||||
@ -243,7 +243,7 @@ suspend fun CommandSender.executeCommandDetailed(vararg messages: Any): CommandE
|
||||
*
|
||||
* @see JCommandManager.executeCommandDetailed Java 方法
|
||||
*/
|
||||
suspend fun CommandSender.executeCommandDetailed(messages: MessageChain): CommandExecuteResult {
|
||||
public suspend fun CommandSender.executeCommandDetailed(messages: MessageChain): CommandExecuteResult {
|
||||
if (messages.isEmpty()) return CommandExecuteResult.CommandNotFound("")
|
||||
return executeCommandDetailedInternal(messages, messages[0].toString())
|
||||
}
|
||||
|
@ -22,48 +22,48 @@ import net.mamoe.mirai.contact.isOwner
|
||||
*
|
||||
* @see AnonymousCommandPermission
|
||||
*/
|
||||
interface CommandPermission {
|
||||
public interface CommandPermission {
|
||||
/**
|
||||
* 判断 [this] 是否拥有这个指令的权限
|
||||
*
|
||||
* @see CommandSender.hasPermission
|
||||
* @see CommandPermission.testPermission
|
||||
*/
|
||||
fun CommandSender.hasPermission(): Boolean
|
||||
public fun CommandSender.hasPermission(): Boolean
|
||||
|
||||
|
||||
/**
|
||||
* 满足两个权限其中一个即可使用指令
|
||||
*/ // no extension for Java
|
||||
@JvmDefault
|
||||
infix fun or(another: CommandPermission): CommandPermission = OrCommandPermission(this, another)
|
||||
public infix fun or(another: CommandPermission): CommandPermission = OrCommandPermission(this, another)
|
||||
|
||||
/**
|
||||
* 同时拥有两个权限才能使用指令
|
||||
*/ // no extension for Java
|
||||
@JvmDefault
|
||||
infix fun and(another: CommandPermission): CommandPermission = AndCommandPermission(this, another)
|
||||
public infix fun and(another: CommandPermission): CommandPermission = AndCommandPermission(this, another)
|
||||
|
||||
|
||||
/**
|
||||
* 任何人都可以使用这个指令
|
||||
*/
|
||||
object Any : CommandPermission {
|
||||
override fun CommandSender.hasPermission(): Boolean = true
|
||||
public object Any : CommandPermission {
|
||||
public override fun CommandSender.hasPermission(): Boolean = true
|
||||
}
|
||||
|
||||
/**
|
||||
* 任何人都不能使用这个指令. 指令只能通过调用 [Command.onCommand] 执行.
|
||||
*/
|
||||
object None : CommandPermission {
|
||||
override fun CommandSender.hasPermission(): Boolean = false
|
||||
public object None : CommandPermission {
|
||||
public override fun CommandSender.hasPermission(): Boolean = false
|
||||
}
|
||||
|
||||
/**
|
||||
* 来自任何 [Bot] 的任何一个管理员或群主都可以使用这个指令
|
||||
*/
|
||||
object Operator : CommandPermission {
|
||||
override fun CommandSender.hasPermission(): Boolean {
|
||||
public object Operator : CommandPermission {
|
||||
public override fun CommandSender.hasPermission(): Boolean {
|
||||
return this is MemberCommandSender && this.user.isOperator()
|
||||
}
|
||||
}
|
||||
@ -71,8 +71,8 @@ interface CommandPermission {
|
||||
/**
|
||||
* 来自任何 [Bot] 的任何一个群主都可以使用这个指令
|
||||
*/
|
||||
object GroupOwner : CommandPermission {
|
||||
override fun CommandSender.hasPermission(): Boolean {
|
||||
public object GroupOwner : CommandPermission {
|
||||
public override fun CommandSender.hasPermission(): Boolean {
|
||||
return this is MemberCommandSender && this.user.isOwner()
|
||||
}
|
||||
}
|
||||
@ -80,8 +80,8 @@ interface CommandPermission {
|
||||
/**
|
||||
* 管理员 (不包含群主) 可以使用这个指令
|
||||
*/
|
||||
object Administrator : CommandPermission {
|
||||
override fun CommandSender.hasPermission(): Boolean {
|
||||
public object Administrator : CommandPermission {
|
||||
public override fun CommandSender.hasPermission(): Boolean {
|
||||
return this is MemberCommandSender && this.user.isAdministrator()
|
||||
}
|
||||
}
|
||||
@ -89,8 +89,8 @@ interface CommandPermission {
|
||||
/**
|
||||
* 任何 [Bot] 的 manager 都可以使用这个指令
|
||||
*/
|
||||
object Manager : CommandPermission {
|
||||
override fun CommandSender.hasPermission(): Boolean {
|
||||
public object Manager : CommandPermission {
|
||||
public override fun CommandSender.hasPermission(): Boolean {
|
||||
return this is MemberCommandSender && this.user.isManager
|
||||
}
|
||||
}
|
||||
@ -98,11 +98,11 @@ interface CommandPermission {
|
||||
/**
|
||||
* 仅控制台能使用和这个指令
|
||||
*/
|
||||
object Console : CommandPermission {
|
||||
override fun CommandSender.hasPermission(): Boolean = this is ConsoleCommandSender
|
||||
public object Console : CommandPermission {
|
||||
public override fun CommandSender.hasPermission(): Boolean = this is ConsoleCommandSender
|
||||
}
|
||||
|
||||
object Default : CommandPermission by (Manager or Console)
|
||||
public object Default : CommandPermission by (Manager or Console)
|
||||
}
|
||||
|
||||
/**
|
||||
@ -110,19 +110,19 @@ interface CommandPermission {
|
||||
*/
|
||||
@JvmSynthetic
|
||||
@Suppress("FunctionName")
|
||||
inline fun AnonymousCommandPermission(crossinline block: CommandSender.() -> Boolean): CommandPermission {
|
||||
public inline fun AnonymousCommandPermission(crossinline block: CommandSender.() -> Boolean): CommandPermission {
|
||||
return object : CommandPermission {
|
||||
override fun CommandSender.hasPermission(): Boolean = block()
|
||||
}
|
||||
}
|
||||
|
||||
inline fun CommandSender.hasPermission(permission: CommandPermission): Boolean =
|
||||
public inline fun CommandSender.hasPermission(permission: CommandPermission): Boolean =
|
||||
permission.run { this@hasPermission.hasPermission() }
|
||||
|
||||
|
||||
inline fun CommandPermission.testPermission(sender: CommandSender): Boolean = this.run { sender.hasPermission() }
|
||||
public inline fun CommandPermission.testPermission(sender: CommandSender): Boolean = this.run { sender.hasPermission() }
|
||||
|
||||
inline fun Command.testPermission(sender: CommandSender): Boolean = sender.hasPermission(this.permission)
|
||||
public inline fun Command.testPermission(sender: CommandSender): Boolean = sender.hasPermission(this.permission)
|
||||
|
||||
internal class OrCommandPermission(
|
||||
private val first: CommandPermission,
|
||||
|
@ -14,12 +14,12 @@ package net.mamoe.mirai.console.command
|
||||
*
|
||||
* 总是作为 [CommandExecutionException.cause].
|
||||
*/
|
||||
class CommandPermissionDeniedException(
|
||||
public class CommandPermissionDeniedException(
|
||||
/**
|
||||
* 执行过程发生异常的指令
|
||||
*/
|
||||
val command: Command
|
||||
public val command: Command
|
||||
) : RuntimeException("Permission denied while executing command '${command.primaryName}'") {
|
||||
override fun toString(): String =
|
||||
public override fun toString(): String =
|
||||
"CommandPermissionDeniedException(command=$command)"
|
||||
}
|
@ -28,55 +28,55 @@ import net.mamoe.mirai.message.data.PlainText
|
||||
* @see UserCommandSender
|
||||
*/
|
||||
@Suppress("FunctionName")
|
||||
interface CommandSender {
|
||||
public interface CommandSender {
|
||||
/**
|
||||
* 与这个 [CommandSender] 相关的 [Bot]. 当通过控制台执行时为 null.
|
||||
*/
|
||||
val bot: Bot?
|
||||
public val bot: Bot?
|
||||
|
||||
/**
|
||||
* 立刻发送一条消息
|
||||
*/
|
||||
@JvmSynthetic
|
||||
suspend fun sendMessage(message: Message)
|
||||
public suspend fun sendMessage(message: Message)
|
||||
|
||||
@JvmDefault
|
||||
@JavaFriendlyAPI
|
||||
@JvmName("sendMessage")
|
||||
fun __sendMessageBlocking(messageChain: Message) = runBlocking { sendMessage(messageChain) }
|
||||
public fun __sendMessageBlocking(messageChain: Message): Unit = runBlocking { sendMessage(messageChain) }
|
||||
|
||||
@JvmDefault
|
||||
@JavaFriendlyAPI
|
||||
@JvmName("sendMessage")
|
||||
fun __sendMessageBlocking(message: String) = runBlocking { sendMessage(message) }
|
||||
public fun __sendMessageBlocking(message: String): Unit = runBlocking { sendMessage(message) }
|
||||
}
|
||||
|
||||
/**
|
||||
* 可以知道其 [Bot] 的 [CommandSender]
|
||||
*/
|
||||
interface BotAwareCommandSender : CommandSender {
|
||||
override val bot: Bot
|
||||
public interface BotAwareCommandSender : CommandSender {
|
||||
public override val bot: Bot
|
||||
}
|
||||
|
||||
suspend inline fun CommandSender.sendMessage(message: String) = sendMessage(PlainText(message))
|
||||
public suspend inline fun CommandSender.sendMessage(message: String): Unit = sendMessage(PlainText(message))
|
||||
|
||||
/**
|
||||
* 控制台指令执行者. 代表由控制台执行指令
|
||||
*/
|
||||
// 前端实现
|
||||
abstract class ConsoleCommandSender internal constructor() : CommandSender {
|
||||
final override val bot: Nothing? get() = null
|
||||
public abstract class ConsoleCommandSender internal constructor() : CommandSender {
|
||||
public final override val bot: Nothing? get() = null
|
||||
|
||||
companion object {
|
||||
public companion object {
|
||||
internal val instance get() = MiraiConsoleInternal.consoleCommandSender
|
||||
}
|
||||
}
|
||||
|
||||
fun Friend.asCommandSender(): FriendCommandSender = FriendCommandSender(this)
|
||||
public fun Friend.asCommandSender(): FriendCommandSender = FriendCommandSender(this)
|
||||
|
||||
fun Member.asCommandSender(): MemberCommandSender = MemberCommandSender(this)
|
||||
public fun Member.asCommandSender(): MemberCommandSender = MemberCommandSender(this)
|
||||
|
||||
fun User.asCommandSender(): UserCommandSender {
|
||||
public fun User.asCommandSender(): UserCommandSender {
|
||||
return when (this) {
|
||||
is Friend -> this.asCommandSender()
|
||||
is Member -> this.asCommandSender()
|
||||
@ -87,28 +87,28 @@ fun User.asCommandSender(): UserCommandSender {
|
||||
/**
|
||||
* 表示由 [MessageEvent] 触发的指令
|
||||
*/
|
||||
interface MessageEventContextAware<E : MessageEvent> : MessageEventExtensions<User, Contact> {
|
||||
val fromEvent: E
|
||||
public interface MessageEventContextAware<E : MessageEvent> : MessageEventExtensions<User, Contact> {
|
||||
public val fromEvent: E
|
||||
}
|
||||
|
||||
/**
|
||||
* 代表一个用户私聊机器人执行指令
|
||||
* @see User.asCommandSender
|
||||
*/
|
||||
sealed class UserCommandSender : CommandSender, BotAwareCommandSender {
|
||||
public sealed class UserCommandSender : CommandSender, BotAwareCommandSender {
|
||||
/**
|
||||
* @see MessageEvent.sender
|
||||
*/
|
||||
abstract val user: User
|
||||
public abstract val user: User
|
||||
|
||||
/**
|
||||
* @see MessageEvent.subject
|
||||
*/
|
||||
abstract val subject: Contact
|
||||
public abstract val subject: Contact
|
||||
|
||||
override val bot: Bot get() = user.bot
|
||||
public override val bot: Bot get() = user.bot
|
||||
|
||||
final override suspend fun sendMessage(message: Message) {
|
||||
public final override suspend fun sendMessage(message: Message) {
|
||||
subject.sendMessage(message)
|
||||
}
|
||||
}
|
||||
@ -117,37 +117,39 @@ sealed class UserCommandSender : CommandSender, BotAwareCommandSender {
|
||||
* 代表一个用户私聊机器人执行指令
|
||||
* @see Friend.asCommandSender
|
||||
*/
|
||||
open class FriendCommandSender(final override val user: Friend) : UserCommandSender() {
|
||||
override val subject: Contact get() = user
|
||||
public open class FriendCommandSender(final override val user: Friend) : UserCommandSender() {
|
||||
public override val subject: Contact get() = user
|
||||
}
|
||||
|
||||
/**
|
||||
* 代表一个用户私聊机器人执行指令
|
||||
* @see Friend.asCommandSender
|
||||
*/
|
||||
class FriendCommandSenderOnMessage(override val fromEvent: FriendMessageEvent) : FriendCommandSender(fromEvent.sender),
|
||||
public class FriendCommandSenderOnMessage(override val fromEvent: FriendMessageEvent) :
|
||||
FriendCommandSender(fromEvent.sender),
|
||||
MessageEventContextAware<FriendMessageEvent>, MessageEventExtensions<User, Contact> by fromEvent {
|
||||
override val subject: Contact get() = super.subject
|
||||
override val bot: Bot get() = super.bot
|
||||
public override val subject: Contact get() = super.subject
|
||||
public override val bot: Bot get() = super.bot
|
||||
}
|
||||
|
||||
/**
|
||||
* 代表一个群成员执行指令.
|
||||
* @see Member.asCommandSender
|
||||
*/
|
||||
open class MemberCommandSender(final override val user: Member) : UserCommandSender() {
|
||||
inline val group: Group get() = user.group
|
||||
override val subject: Contact get() = group
|
||||
public open class MemberCommandSender(final override val user: Member) : UserCommandSender() {
|
||||
public inline val group: Group get() = user.group
|
||||
public override val subject: Contact get() = group
|
||||
}
|
||||
|
||||
/**
|
||||
* 代表一个群成员在群内执行指令.
|
||||
* @see Member.asCommandSender
|
||||
*/
|
||||
class MemberCommandSenderOnMessage(override val fromEvent: GroupMessageEvent) : MemberCommandSender(fromEvent.sender),
|
||||
public class MemberCommandSenderOnMessage(override val fromEvent: GroupMessageEvent) :
|
||||
MemberCommandSender(fromEvent.sender),
|
||||
MessageEventContextAware<GroupMessageEvent>, MessageEventExtensions<User, Contact> by fromEvent {
|
||||
override val subject: Contact get() = super.subject
|
||||
override val bot: Bot get() = super.bot
|
||||
public override val subject: Contact get() = super.subject
|
||||
public override val bot: Bot get() = super.bot
|
||||
}
|
||||
|
||||
/**
|
||||
@ -155,8 +157,9 @@ class MemberCommandSenderOnMessage(override val fromEvent: GroupMessageEvent) :
|
||||
* @see Member.asCommandSender
|
||||
*/
|
||||
@ConsoleExperimentalAPI
|
||||
class TempCommandSenderOnMessage(override val fromEvent: TempMessageEvent) : MemberCommandSender(fromEvent.sender),
|
||||
public class TempCommandSenderOnMessage(override val fromEvent: TempMessageEvent) :
|
||||
MemberCommandSender(fromEvent.sender),
|
||||
MessageEventContextAware<TempMessageEvent>, MessageEventExtensions<User, Contact> by fromEvent {
|
||||
override val subject: Contact get() = super.subject
|
||||
override val bot: Bot get() = super.bot
|
||||
public override val subject: Contact get() = super.subject
|
||||
public override val bot: Bot get() = super.bot
|
||||
}
|
@ -11,8 +11,8 @@
|
||||
"EXPOSED_SUPER_CLASS",
|
||||
"NOTHING_TO_INLINE",
|
||||
"unused",
|
||||
"WRONG_MODIFIER_TARGET",
|
||||
"WRONG_MODIFIER_CONTAINING_DECLARATION"
|
||||
"WRONG_MODIFIER_TARGET", "CANNOT_WEAKEN_ACCESS_PRIVILEGE",
|
||||
"WRONG_MODIFIER_CONTAINING_DECLARATION", "RedundantVisibilityModifier"
|
||||
)
|
||||
|
||||
package net.mamoe.mirai.console.command
|
||||
@ -29,7 +29,7 @@ import kotlin.reflect.KClass
|
||||
* 复合指令.
|
||||
*/
|
||||
@ConsoleExperimentalAPI
|
||||
abstract class CompositeCommand @JvmOverloads constructor(
|
||||
public abstract class CompositeCommand @JvmOverloads constructor(
|
||||
owner: CommandOwner,
|
||||
vararg names: String,
|
||||
description: String = "no description available",
|
||||
@ -41,7 +41,7 @@ abstract class CompositeCommand @JvmOverloads constructor(
|
||||
/**
|
||||
* [CommandArgParser] 的环境
|
||||
*/
|
||||
final override val context: CommandParserContext = CommandParserContext.Builtins + overrideContext
|
||||
public final override val context: CommandParserContext = CommandParserContext.Builtins + overrideContext
|
||||
|
||||
/**
|
||||
* 标记一个函数为子指令, 当 [value] 为空时使用函数名.
|
||||
@ -66,16 +66,17 @@ abstract class CompositeCommand @JvmOverloads constructor(
|
||||
@Target(AnnotationTarget.VALUE_PARAMETER)
|
||||
protected annotation class Name(val value: String)
|
||||
|
||||
override suspend fun CommandSender.onDefault(rawArgs: Array<out Any>) {
|
||||
sendMessage(usage)
|
||||
}
|
||||
|
||||
final override suspend fun CommandSender.onCommand(args: Array<out Any>) {
|
||||
public final override suspend fun CommandSender.onCommand(args: Array<out Any>) {
|
||||
matchSubCommand(args)?.parseAndExecute(this, args, true) ?: kotlin.run {
|
||||
defaultSubCommand.onCommand(this, args)
|
||||
}
|
||||
}
|
||||
|
||||
final override val subCommandAnnotationResolver: SubCommandAnnotationResolver
|
||||
|
||||
internal override suspend fun CommandSender.onDefault(rawArgs: Array<out Any>) {
|
||||
sendMessage(usage)
|
||||
}
|
||||
|
||||
internal final override val subCommandAnnotationResolver: SubCommandAnnotationResolver
|
||||
get() = CompositeCommandSubCommandAnnotationResolver
|
||||
}
|
||||
|
@ -1,12 +1,12 @@
|
||||
package net.mamoe.mirai.console.command
|
||||
|
||||
abstract class RawCommand(
|
||||
override val owner: CommandOwner,
|
||||
override vararg val names: String,
|
||||
override val usage: String = "<no usages given>",
|
||||
override val description: String = "<no descriptions given>",
|
||||
override val permission: CommandPermission = CommandPermission.Default,
|
||||
override val prefixOptional: Boolean = false
|
||||
public abstract class RawCommand(
|
||||
public override val owner: CommandOwner,
|
||||
public override vararg val names: String,
|
||||
public override val usage: String = "<no usages given>",
|
||||
public override val description: String = "<no descriptions given>",
|
||||
public override val permission: CommandPermission = CommandPermission.Default,
|
||||
public override val prefixOptional: Boolean = false
|
||||
) : Command {
|
||||
abstract override suspend fun CommandSender.onCommand(args: Array<out Any>)
|
||||
public abstract override suspend fun CommandSender.onCommand(args: Array<out Any>)
|
||||
}
|
||||
|
@ -11,8 +11,8 @@
|
||||
"EXPOSED_SUPER_CLASS",
|
||||
"NOTHING_TO_INLINE",
|
||||
"unused",
|
||||
"WRONG_MODIFIER_TARGET",
|
||||
"WRONG_MODIFIER_CONTAINING_DECLARATION"
|
||||
"WRONG_MODIFIER_TARGET", "CANNOT_WEAKEN_ACCESS_PRIVILEGE",
|
||||
"WRONG_MODIFIER_CONTAINING_DECLARATION", "RedundantVisibilityModifier"
|
||||
)
|
||||
|
||||
package net.mamoe.mirai.console.command
|
||||
@ -24,7 +24,7 @@ import net.mamoe.mirai.console.command.description.plus
|
||||
import net.mamoe.mirai.console.command.internal.AbstractReflectionCommand
|
||||
import net.mamoe.mirai.console.command.internal.SimpleCommandSubCommandAnnotationResolver
|
||||
|
||||
abstract class SimpleCommand @JvmOverloads constructor(
|
||||
public abstract class SimpleCommand @JvmOverloads constructor(
|
||||
owner: CommandOwner,
|
||||
vararg names: String,
|
||||
description: String = "no description available",
|
||||
@ -34,7 +34,7 @@ abstract class SimpleCommand @JvmOverloads constructor(
|
||||
) : Command, AbstractReflectionCommand(owner, names, description, permission, prefixOptional),
|
||||
CommandParserContextAware {
|
||||
|
||||
override val usage: String
|
||||
public override val usage: String
|
||||
get() = super.usage
|
||||
|
||||
/**
|
||||
@ -42,20 +42,20 @@ abstract class SimpleCommand @JvmOverloads constructor(
|
||||
*/
|
||||
protected annotation class Handler
|
||||
|
||||
final override val context: CommandParserContext = CommandParserContext.Builtins + overrideContext
|
||||
public final override val context: CommandParserContext = CommandParserContext.Builtins + overrideContext
|
||||
|
||||
override fun checkSubCommand(subCommands: Array<SubCommandDescriptor>) {
|
||||
internal override fun checkSubCommand(subCommands: Array<SubCommandDescriptor>) {
|
||||
super.checkSubCommand(subCommands)
|
||||
check(subCommands.size == 1) { "There can only be exactly one function annotated with Handler at this moment as overloading is not yet supported." }
|
||||
}
|
||||
|
||||
@Deprecated("prohibited", level = DeprecationLevel.HIDDEN)
|
||||
override suspend fun CommandSender.onDefault(rawArgs: Array<out Any>) = sendMessage(usage)
|
||||
internal override suspend fun CommandSender.onDefault(rawArgs: Array<out Any>) = sendMessage(usage)
|
||||
|
||||
final override suspend fun CommandSender.onCommand(args: Array<out Any>) {
|
||||
public final override suspend fun CommandSender.onCommand(args: Array<out Any>) {
|
||||
subCommands.single().parseAndExecute(this, args, false)
|
||||
}
|
||||
|
||||
final override val subCommandAnnotationResolver: SubCommandAnnotationResolver
|
||||
internal final override val subCommandAnnotationResolver: SubCommandAnnotationResolver
|
||||
get() = SimpleCommandSubCommandAnnotationResolver
|
||||
}
|
@ -20,14 +20,14 @@ import kotlin.contracts.contract
|
||||
* this output type of that arg
|
||||
* input is always String
|
||||
*/
|
||||
interface CommandArgParser<out T : Any> {
|
||||
fun parse(raw: String, sender: CommandSender): T
|
||||
public interface CommandArgParser<out T : Any> {
|
||||
public fun parse(raw: String, sender: CommandSender): T
|
||||
|
||||
@JvmDefault
|
||||
fun parse(raw: SingleMessage, sender: CommandSender): T = parse(raw.content, sender)
|
||||
public fun parse(raw: SingleMessage, sender: CommandSender): T = parse(raw.content, sender)
|
||||
}
|
||||
|
||||
fun <T : Any> CommandArgParser<T>.parse(raw: Any, sender: CommandSender): T {
|
||||
public fun <T : Any> CommandArgParser<T>.parse(raw: Any, sender: CommandSender): T {
|
||||
contract {
|
||||
returns() implies (raw is String || raw is SingleMessage)
|
||||
}
|
||||
@ -41,12 +41,12 @@ fun <T : Any> CommandArgParser<T>.parse(raw: Any, sender: CommandSender): T {
|
||||
|
||||
@Suppress("unused")
|
||||
@JvmSynthetic
|
||||
inline fun CommandArgParser<*>.illegalArgument(message: String, cause: Throwable? = null): Nothing {
|
||||
public inline fun CommandArgParser<*>.illegalArgument(message: String, cause: Throwable? = null): Nothing {
|
||||
throw ParserException(message, cause)
|
||||
}
|
||||
|
||||
@JvmSynthetic
|
||||
inline fun CommandArgParser<*>.checkArgument(
|
||||
public inline fun CommandArgParser<*>.checkArgument(
|
||||
condition: Boolean,
|
||||
crossinline message: () -> String = { "Check failed." }
|
||||
) {
|
||||
@ -61,7 +61,7 @@ inline fun CommandArgParser<*>.checkArgument(
|
||||
*/
|
||||
@Suppress("FunctionName")
|
||||
@JvmSynthetic
|
||||
inline fun <T : Any> CommandArgParser(
|
||||
public inline fun <T : Any> CommandArgParser(
|
||||
crossinline stringParser: CommandArgParser<T>.(s: String, sender: CommandSender) -> T
|
||||
): CommandArgParser<T> = object : CommandArgParser<T> {
|
||||
override fun parse(raw: String, sender: CommandSender): T = stringParser(raw, sender)
|
||||
@ -72,7 +72,7 @@ inline fun <T : Any> CommandArgParser(
|
||||
*/
|
||||
@Suppress("FunctionName")
|
||||
@JvmSynthetic
|
||||
inline fun <T : Any> CommandArgParser(
|
||||
public inline fun <T : Any> CommandArgParser(
|
||||
crossinline stringParser: CommandArgParser<T>.(s: String, sender: CommandSender) -> T,
|
||||
crossinline messageParser: CommandArgParser<T>.(m: SingleMessage, sender: CommandSender) -> T
|
||||
): CommandArgParser<T> = object : CommandArgParser<T> {
|
||||
@ -84,4 +84,4 @@ inline fun <T : Any> CommandArgParser(
|
||||
/**
|
||||
* 在解析参数时遇到的 _正常_ 错误. 如参数不符合规范.
|
||||
*/
|
||||
class ParserException(message: String, cause: Throwable? = null) : RuntimeException(message, cause)
|
||||
public class ParserException(message: String, cause: Throwable? = null) : RuntimeException(message, cause)
|
@ -23,44 +23,44 @@ import net.mamoe.mirai.message.data.SingleMessage
|
||||
import net.mamoe.mirai.message.data.content
|
||||
|
||||
|
||||
object IntArgParser : CommandArgParser<Int> {
|
||||
override fun parse(raw: String, sender: CommandSender): Int =
|
||||
public object IntArgParser : CommandArgParser<Int> {
|
||||
public override fun parse(raw: String, sender: CommandSender): Int =
|
||||
raw.toIntOrNull() ?: illegalArgument("无法解析 $raw 为整数")
|
||||
}
|
||||
|
||||
object LongArgParser : CommandArgParser<Long> {
|
||||
override fun parse(raw: String, sender: CommandSender): Long =
|
||||
public object LongArgParser : CommandArgParser<Long> {
|
||||
public override fun parse(raw: String, sender: CommandSender): Long =
|
||||
raw.toLongOrNull() ?: illegalArgument("无法解析 $raw 为长整数")
|
||||
}
|
||||
|
||||
object ShortArgParser : CommandArgParser<Short> {
|
||||
override fun parse(raw: String, sender: CommandSender): Short =
|
||||
public object ShortArgParser : CommandArgParser<Short> {
|
||||
public override fun parse(raw: String, sender: CommandSender): Short =
|
||||
raw.toShortOrNull() ?: illegalArgument("无法解析 $raw 为短整数")
|
||||
}
|
||||
|
||||
object ByteArgParser : CommandArgParser<Byte> {
|
||||
override fun parse(raw: String, sender: CommandSender): Byte =
|
||||
public object ByteArgParser : CommandArgParser<Byte> {
|
||||
public override fun parse(raw: String, sender: CommandSender): Byte =
|
||||
raw.toByteOrNull() ?: illegalArgument("无法解析 $raw 为字节")
|
||||
}
|
||||
|
||||
object DoubleArgParser : CommandArgParser<Double> {
|
||||
override fun parse(raw: String, sender: CommandSender): Double =
|
||||
public object DoubleArgParser : CommandArgParser<Double> {
|
||||
public override fun parse(raw: String, sender: CommandSender): Double =
|
||||
raw.toDoubleOrNull() ?: illegalArgument("无法解析 $raw 为小数")
|
||||
}
|
||||
|
||||
object FloatArgParser : CommandArgParser<Float> {
|
||||
override fun parse(raw: String, sender: CommandSender): Float =
|
||||
public object FloatArgParser : CommandArgParser<Float> {
|
||||
public override fun parse(raw: String, sender: CommandSender): Float =
|
||||
raw.toFloatOrNull() ?: illegalArgument("无法解析 $raw 为小数")
|
||||
}
|
||||
|
||||
object StringArgParser : CommandArgParser<String> {
|
||||
override fun parse(raw: String, sender: CommandSender): String {
|
||||
public object StringArgParser : CommandArgParser<String> {
|
||||
public override fun parse(raw: String, sender: CommandSender): String {
|
||||
return raw
|
||||
}
|
||||
}
|
||||
|
||||
object BooleanArgParser : CommandArgParser<Boolean> {
|
||||
override fun parse(raw: String, sender: CommandSender): Boolean = raw.trim().let { str ->
|
||||
public object BooleanArgParser : CommandArgParser<Boolean> {
|
||||
public override fun parse(raw: String, sender: CommandSender): Boolean = raw.trim().let { str ->
|
||||
str.equals("true", ignoreCase = true)
|
||||
|| str.equals("yes", ignoreCase = true)
|
||||
|| str.equals("enabled", ignoreCase = true)
|
||||
@ -73,18 +73,18 @@ object BooleanArgParser : CommandArgParser<Boolean> {
|
||||
* output: Bot
|
||||
* errors: String->Int convert, Bot Not Exist
|
||||
*/
|
||||
object ExistBotArgParser : CommandArgParser<Bot> {
|
||||
override fun parse(raw: String, sender: CommandSender): Bot {
|
||||
public object ExistBotArgParser : CommandArgParser<Bot> {
|
||||
public override fun parse(raw: String, sender: CommandSender): Bot {
|
||||
val uin = raw.toLongOrNull() ?: illegalArgument("无法识别 QQ ID: $raw")
|
||||
return Bot.getInstanceOrNull(uin) ?: illegalArgument("无法找到 Bot $uin")
|
||||
}
|
||||
}
|
||||
|
||||
object ExistFriendArgParser : CommandArgParser<Friend> {
|
||||
public object ExistFriendArgParser : CommandArgParser<Friend> {
|
||||
//Bot.friend
|
||||
//friend
|
||||
//~ = self
|
||||
override fun parse(raw: String, sender: CommandSender): Friend {
|
||||
public override fun parse(raw: String, sender: CommandSender): Friend {
|
||||
if (raw == "~") {
|
||||
if (sender !is BotAwareCommandSender) {
|
||||
illegalArgument("无法解析~作为默认")
|
||||
@ -115,7 +115,7 @@ object ExistFriendArgParser : CommandArgParser<Friend> {
|
||||
}
|
||||
}
|
||||
|
||||
override fun parse(raw: SingleMessage, sender: CommandSender): Friend {
|
||||
public override fun parse(raw: SingleMessage, sender: CommandSender): Friend {
|
||||
if (raw is At) {
|
||||
assert(sender is MemberCommandSender)
|
||||
return (sender as BotAwareCommandSender).bot.friends.getOrNull(raw.target) ?: illegalArgument("At的对象非Bot好友")
|
||||
@ -125,8 +125,8 @@ object ExistFriendArgParser : CommandArgParser<Friend> {
|
||||
}
|
||||
}
|
||||
|
||||
object ExistGroupArgParser : CommandArgParser<Group> {
|
||||
override fun parse(raw: String, sender: CommandSender): Group {
|
||||
public object ExistGroupArgParser : CommandArgParser<Group> {
|
||||
public override fun parse(raw: String, sender: CommandSender): Group {
|
||||
//by default
|
||||
if ((raw == "" || raw == "~") && sender is MemberCommandSender) {
|
||||
return sender.group
|
||||
@ -160,12 +160,12 @@ object ExistGroupArgParser : CommandArgParser<Group> {
|
||||
}
|
||||
}
|
||||
|
||||
object ExistMemberArgParser : CommandArgParser<Member> {
|
||||
public object ExistMemberArgParser : CommandArgParser<Member> {
|
||||
//后台: Bot.Group.Member[QQ/名片]
|
||||
//私聊: Group.Member[QQ/名片]
|
||||
//群内: Q号
|
||||
//群内: 名片
|
||||
override fun parse(raw: String, sender: CommandSender): Member {
|
||||
public override fun parse(raw: String, sender: CommandSender): Member {
|
||||
if (sender !is BotAwareCommandSender) {
|
||||
with(raw.split(".")) {
|
||||
checkArgument(this.size >= 3) {
|
||||
@ -226,7 +226,7 @@ object ExistMemberArgParser : CommandArgParser<Member> {
|
||||
}
|
||||
}
|
||||
|
||||
override fun parse(raw: SingleMessage, sender: CommandSender): Member {
|
||||
public override fun parse(raw: SingleMessage, sender: CommandSender): Member {
|
||||
return if (raw is At) {
|
||||
checkArgument(sender is MemberCommandSender)
|
||||
(sender.group).members[raw.target]
|
||||
|
@ -27,20 +27,20 @@ import kotlin.reflect.full.isSubclassOf
|
||||
* [KClass] 到 [CommandArgParser] 的匹配
|
||||
* @see CustomCommandParserContext 自定义
|
||||
*/
|
||||
interface CommandParserContext {
|
||||
data class ParserPair<T : Any>(
|
||||
public interface CommandParserContext {
|
||||
public data class ParserPair<T : Any>(
|
||||
val klass: KClass<T>,
|
||||
val parser: CommandArgParser<T>
|
||||
)
|
||||
|
||||
operator fun <T : Any> get(klass: KClass<out T>): CommandArgParser<T>?
|
||||
public operator fun <T : Any> get(klass: KClass<out T>): CommandArgParser<T>?
|
||||
|
||||
fun toList(): List<ParserPair<*>>
|
||||
public fun toList(): List<ParserPair<*>>
|
||||
|
||||
/**
|
||||
* 内建的默认 [CommandArgParser]
|
||||
*/
|
||||
object Builtins : CommandParserContext by (CommandParserContext {
|
||||
public object Builtins : CommandParserContext by (CommandParserContext {
|
||||
Int::class with IntArgParser
|
||||
Byte::class with ByteArgParser
|
||||
Short::class with ShortArgParser
|
||||
@ -60,19 +60,19 @@ interface CommandParserContext {
|
||||
/**
|
||||
* 拥有 [CommandParserContext] 的类
|
||||
*/
|
||||
interface CommandParserContextAware {
|
||||
public interface CommandParserContextAware {
|
||||
/**
|
||||
* [CommandArgParser] 的环境
|
||||
*/
|
||||
val context: CommandParserContext
|
||||
public val context: CommandParserContext
|
||||
}
|
||||
|
||||
object EmptyCommandParserContext : CommandParserContext by CustomCommandParserContext(listOf())
|
||||
public object EmptyCommandParserContext : CommandParserContext by CustomCommandParserContext(listOf())
|
||||
|
||||
/**
|
||||
* 合并两个 [CommandParserContext], [replacer] 将会替换 [this] 中重复的 parser.
|
||||
*/
|
||||
operator fun CommandParserContext.plus(replacer: CommandParserContext): CommandParserContext {
|
||||
public operator fun CommandParserContext.plus(replacer: CommandParserContext): CommandParserContext {
|
||||
if (replacer == EmptyCommandParserContext) return this
|
||||
if (this == EmptyCommandParserContext) return replacer
|
||||
return object : CommandParserContext {
|
||||
@ -84,7 +84,7 @@ operator fun CommandParserContext.plus(replacer: CommandParserContext): CommandP
|
||||
/**
|
||||
* 合并 [this] 与 [replacer], [replacer] 将会替换 [this] 中重复的 parser.
|
||||
*/
|
||||
operator fun CommandParserContext.plus(replacer: List<ParserPair<*>>): CommandParserContext {
|
||||
public operator fun CommandParserContext.plus(replacer: List<ParserPair<*>>): CommandParserContext {
|
||||
if (replacer.isEmpty()) return this
|
||||
if (this == EmptyCommandParserContext) return CustomCommandParserContext(replacer)
|
||||
return object : CommandParserContext {
|
||||
@ -97,7 +97,7 @@ operator fun CommandParserContext.plus(replacer: List<ParserPair<*>>): CommandPa
|
||||
}
|
||||
|
||||
@Suppress("UNCHECKED_CAST")
|
||||
open class CustomCommandParserContext(val list: List<ParserPair<*>>) : CommandParserContext {
|
||||
public open class CustomCommandParserContext(public val list: List<ParserPair<*>>) : CommandParserContext {
|
||||
|
||||
override fun <T : Any> get(klass: KClass<out T>): CommandArgParser<T>? =
|
||||
this.list.firstOrNull { klass.isSubclassOf(it.klass) }?.parser as CommandArgParser<T>?
|
||||
@ -125,16 +125,16 @@ open class CustomCommandParserContext(val list: List<ParserPair<*>>) : CommandPa
|
||||
*/
|
||||
@Suppress("FunctionName")
|
||||
@JvmSynthetic
|
||||
inline fun CommandParserContext(block: CommandParserContextBuilder.() -> Unit): CommandParserContext {
|
||||
public inline fun CommandParserContext(block: CommandParserContextBuilder.() -> Unit): CommandParserContext {
|
||||
return CustomCommandParserContext(CommandParserContextBuilder().apply(block).distinctByReversed { it.klass })
|
||||
}
|
||||
|
||||
/**
|
||||
* @see CommandParserContext
|
||||
*/
|
||||
class CommandParserContextBuilder : MutableList<ParserPair<*>> by mutableListOf() {
|
||||
public class CommandParserContextBuilder : MutableList<ParserPair<*>> by mutableListOf() {
|
||||
@JvmName("add")
|
||||
inline infix fun <T : Any> KClass<T>.with(parser: CommandArgParser<T>): ParserPair<*> =
|
||||
public inline infix fun <T : Any> KClass<T>.with(parser: CommandArgParser<T>): ParserPair<*> =
|
||||
ParserPair(this, parser).also { add(it) }
|
||||
|
||||
/**
|
||||
@ -142,7 +142,7 @@ class CommandParserContextBuilder : MutableList<ParserPair<*>> by mutableListOf(
|
||||
*/
|
||||
@JvmSynthetic
|
||||
@LowPriorityInOverloadResolution
|
||||
inline infix fun <T : Any> KClass<T>.with(
|
||||
public inline infix fun <T : Any> KClass<T>.with(
|
||||
crossinline parser: CommandArgParser<T>.(s: String, sender: CommandSender) -> T
|
||||
): ParserPair<*> = ParserPair(this, CommandArgParser(parser)).also { add(it) }
|
||||
|
||||
@ -150,12 +150,12 @@ class CommandParserContextBuilder : MutableList<ParserPair<*>> by mutableListOf(
|
||||
* 添加一个指令解析器
|
||||
*/
|
||||
@JvmSynthetic
|
||||
inline infix fun <T : Any> KClass<T>.with(
|
||||
public inline infix fun <T : Any> KClass<T>.with(
|
||||
crossinline parser: CommandArgParser<T>.(s: String) -> T
|
||||
): ParserPair<*> = ParserPair(this, CommandArgParser { s: String, _: CommandSender -> parser(s) }).also { add(it) }
|
||||
|
||||
@JvmSynthetic
|
||||
inline fun <reified T : Any> add(parser: CommandArgParser<T>): ParserPair<*> =
|
||||
public inline fun <reified T : Any> add(parser: CommandArgParser<T>): ParserPair<*> =
|
||||
ParserPair(T::class, parser).also { add(it) }
|
||||
|
||||
/**
|
||||
@ -163,7 +163,7 @@ class CommandParserContextBuilder : MutableList<ParserPair<*>> by mutableListOf(
|
||||
*/
|
||||
@ConsoleExperimentalAPI
|
||||
@JvmSynthetic
|
||||
inline infix fun <reified T : Any> add(
|
||||
public inline infix fun <reified T : Any> add(
|
||||
crossinline parser: CommandArgParser<*>.(s: String) -> T
|
||||
): ParserPair<*> = T::class with CommandArgParser { s: String, _: CommandSender -> parser(s) }
|
||||
|
||||
@ -173,7 +173,7 @@ class CommandParserContextBuilder : MutableList<ParserPair<*>> by mutableListOf(
|
||||
@ConsoleExperimentalAPI
|
||||
@JvmSynthetic
|
||||
@LowPriorityInOverloadResolution
|
||||
inline infix fun <reified T : Any> add(
|
||||
public inline infix fun <reified T : Any> add(
|
||||
crossinline parser: CommandArgParser<*>.(s: String, sender: CommandSender) -> T
|
||||
): ParserPair<*> = T::class with CommandArgParser(parser)
|
||||
}
|
||||
|
@ -14,4 +14,4 @@ import net.mamoe.mirai.event.Event
|
||||
/**
|
||||
* 表示来自 mirai-console 的事件
|
||||
*/
|
||||
interface ConsoleEvent : Event
|
||||
public interface ConsoleEvent : Event
|
@ -22,15 +22,16 @@ import java.io.File
|
||||
*
|
||||
* @see PluginLoader 插件加载器
|
||||
*/
|
||||
interface Plugin {
|
||||
public interface Plugin {
|
||||
/**
|
||||
* 所属插件加载器实例, 此加载器必须能加载这个 [Plugin].
|
||||
*/
|
||||
val loader: PluginLoader<*, *>
|
||||
public val loader: PluginLoader<*, *>
|
||||
}
|
||||
|
||||
@get:JvmSynthetic
|
||||
@Suppress("UNCHECKED_CAST")
|
||||
inline val <P : Plugin> P.safeLoader: PluginLoader<P, PluginDescription>
|
||||
public inline val <P : Plugin> P.safeLoader: PluginLoader<P, PluginDescription>
|
||||
get() = this.loader as PluginLoader<P, PluginDescription>
|
||||
|
||||
/**
|
||||
@ -39,15 +40,17 @@ inline val <P : Plugin> P.safeLoader: PluginLoader<P, PluginDescription>
|
||||
* @see JvmPlugin
|
||||
*/
|
||||
@ConsoleExperimentalAPI("classname is subject to change")
|
||||
interface PluginFileExtensions {
|
||||
public interface PluginFileExtensions {
|
||||
/**
|
||||
* 数据目录
|
||||
*/
|
||||
val dataFolder: File
|
||||
public val dataFolder: File
|
||||
|
||||
/**
|
||||
* 从数据目录获取一个文件, 若不存在则创建文件.
|
||||
*/
|
||||
@JvmDefault
|
||||
fun file(relativePath: String): File = File(dataFolder, relativePath).apply { createNewFile() }
|
||||
public fun file(relativePath: String): File = File(dataFolder, relativePath).apply { createNewFile() }
|
||||
|
||||
// TODO: 2020/7/11 add `fun path(...): Path` ?
|
||||
}
|
@ -7,7 +7,7 @@
|
||||
* https://github.com/mamoe/mirai/blob/master/LICENSE
|
||||
*/
|
||||
|
||||
@file:Suppress("unused", "INAPPLICABLE_JVM_NAME")
|
||||
@file:Suppress("unused", "INAPPLICABLE_JVM_NAME", "NOTHING_TO_INLINE")
|
||||
|
||||
package net.mamoe.mirai.console.plugin
|
||||
|
||||
@ -23,11 +23,11 @@ import java.io.File
|
||||
*
|
||||
* @see JarPluginLoader Jar 插件加载器
|
||||
*/
|
||||
interface PluginLoader<P : Plugin, D : PluginDescription> {
|
||||
public interface PluginLoader<P : Plugin, D : PluginDescription> {
|
||||
/**
|
||||
* 扫描并返回可以被加载的插件的 [描述][PluginDescription] 列表. 此函数只会被调用一次
|
||||
*/
|
||||
fun listPlugins(): List<D>
|
||||
public fun listPlugins(): List<D>
|
||||
|
||||
/**
|
||||
* 获取此插件的描述
|
||||
@ -36,7 +36,7 @@ interface PluginLoader<P : Plugin, D : PluginDescription> {
|
||||
*/
|
||||
@get:JvmName("getPluginDescription")
|
||||
@get:Throws(PluginLoadException::class)
|
||||
val P.description: D
|
||||
public val P.description: D // Java signature: `public P getDescription(P)`
|
||||
|
||||
/**
|
||||
* 加载一个插件 (实例), 但不 [启用][enable] 它. 返回加载成功的主类实例
|
||||
@ -44,19 +44,20 @@ interface PluginLoader<P : Plugin, D : PluginDescription> {
|
||||
* @throws PluginLoadException 在加载插件遇到意料之中的错误时抛出 (如找不到主类等).
|
||||
*/
|
||||
@Throws(PluginLoadException::class)
|
||||
fun load(description: D): P
|
||||
public fun load(description: D): P
|
||||
|
||||
fun enable(plugin: P)
|
||||
fun disable(plugin: P)
|
||||
public fun enable(plugin: P)
|
||||
public fun disable(plugin: P)
|
||||
}
|
||||
|
||||
fun <D : PluginDescription, P : Plugin> PluginLoader<P, D>.getDescription(plugin: P): D = plugin.description
|
||||
public inline fun <D : PluginDescription, P : Plugin> PluginLoader<P, D>.getDescription(plugin: P): D =
|
||||
plugin.description
|
||||
|
||||
open class PluginLoadException : RuntimeException {
|
||||
constructor() : super()
|
||||
constructor(message: String?) : super(message)
|
||||
constructor(message: String?, cause: Throwable?) : super(message, cause)
|
||||
constructor(cause: Throwable?) : super(cause)
|
||||
public open class PluginLoadException : RuntimeException {
|
||||
public constructor() : super()
|
||||
public constructor(message: String?) : super(message)
|
||||
public constructor(message: String?, cause: Throwable?) : super(message, cause)
|
||||
public constructor(cause: Throwable?) : super(cause)
|
||||
}
|
||||
|
||||
/**
|
||||
@ -65,18 +66,18 @@ open class PluginLoadException : RuntimeException {
|
||||
* @see AbstractFilePluginLoader 默认基础实现
|
||||
* @see JarPluginLoader 内建的 Jar (JVM) 插件加载器.
|
||||
*/
|
||||
interface FilePluginLoader<P : Plugin, D : PluginDescription> : PluginLoader<P, D> {
|
||||
public interface FilePluginLoader<P : Plugin, D : PluginDescription> : PluginLoader<P, D> {
|
||||
/**
|
||||
* 所支持的插件文件后缀, 含 '.'. 如 [JarPluginLoader] 为 ".jar"
|
||||
*/
|
||||
val fileSuffix: String
|
||||
public val fileSuffix: String
|
||||
}
|
||||
|
||||
/**
|
||||
* [FilePluginLoader] 的默认基础实现
|
||||
*/
|
||||
abstract class AbstractFilePluginLoader<P : Plugin, D : PluginDescription>(
|
||||
override val fileSuffix: String
|
||||
public abstract class AbstractFilePluginLoader<P : Plugin, D : PluginDescription>(
|
||||
public override val fileSuffix: String
|
||||
) : FilePluginLoader<P, D> {
|
||||
private fun pluginsFilesSequence(): Sequence<File> =
|
||||
PluginManager.pluginsDir.walk().filter { it.isFile && it.name.endsWith(fileSuffix, ignoreCase = true) }
|
||||
@ -86,7 +87,7 @@ abstract class AbstractFilePluginLoader<P : Plugin, D : PluginDescription>(
|
||||
*/
|
||||
protected abstract fun Sequence<File>.mapToDescription(): List<D>
|
||||
|
||||
final override fun listPlugins(): List<D> = pluginsFilesSequence().mapToDescription()
|
||||
public final override fun listPlugins(): List<D> = pluginsFilesSequence().mapToDescription()
|
||||
}
|
||||
|
||||
|
||||
|
@ -18,18 +18,68 @@ import net.mamoe.mirai.utils.info
|
||||
import java.io.File
|
||||
import java.util.concurrent.locks.ReentrantLock
|
||||
|
||||
val Plugin.description: PluginDescription
|
||||
get() = PluginManager.resolvedPlugins.firstOrNull { it == this }?.loader?.cast<PluginLoader<Plugin, PluginDescription>>()
|
||||
?.getDescription(
|
||||
this
|
||||
) ?: error("Plugin is unloaded")
|
||||
// TODO: 2020/7/11 top-level or in PluginManager.companion?
|
||||
public val Plugin.description: PluginDescription
|
||||
get() = PluginManagerImpl.resolvedPlugins.firstOrNull { it == this }
|
||||
?.loader?.cast<PluginLoader<Plugin, PluginDescription>>()
|
||||
?.getDescription(this)
|
||||
?: error("Plugin is unloaded")
|
||||
|
||||
inline fun PluginLoader<*, *>.register() = PluginManager.registerPluginLoader(this)
|
||||
inline fun PluginLoader<*, *>.unregister() = PluginManager.unregisterPluginLoader(this)
|
||||
@JvmSynthetic
|
||||
public inline fun PluginLoader<*, *>.register(): Boolean = PluginManager.registerPluginLoader(this)
|
||||
|
||||
object PluginManager {
|
||||
val pluginsDir = File(MiraiConsole.rootDir, "plugins").apply { mkdir() }
|
||||
val pluginsDataFolder = File(MiraiConsole.rootDir, "data").apply { mkdir() }
|
||||
@JvmSynthetic
|
||||
public inline fun PluginLoader<*, *>.unregister(): Boolean = PluginManager.unregisterPluginLoader(this)
|
||||
|
||||
// TODO: 2020/7/11 document
|
||||
public interface PluginManager {
|
||||
public val pluginsDir: File
|
||||
|
||||
public val pluginsDataFolder: File
|
||||
|
||||
/**
|
||||
* 已加载的插件列表
|
||||
*/
|
||||
public val plugins: List<Plugin>
|
||||
|
||||
/**
|
||||
* 内建的插件加载器列表. 由 [MiraiConsole] 初始化
|
||||
*/
|
||||
public val builtInLoaders: List<PluginLoader<*, *>>
|
||||
|
||||
/**
|
||||
* 由插件创建的 [PluginLoader]
|
||||
*/
|
||||
public val pluginLoaders: List<PluginLoader<*, *>>
|
||||
|
||||
public fun registerPluginLoader(loader: PluginLoader<*, *>): Boolean
|
||||
|
||||
public fun unregisterPluginLoader(loader: PluginLoader<*, *>): Boolean
|
||||
|
||||
public companion object INSTANCE : PluginManager by PluginManagerImpl
|
||||
}
|
||||
|
||||
public class PluginMissingDependencyException : PluginResolutionException {
|
||||
public constructor() : super()
|
||||
public constructor(message: String?) : super(message)
|
||||
public constructor(message: String?, cause: Throwable?) : super(message, cause)
|
||||
public constructor(cause: Throwable?) : super(cause)
|
||||
}
|
||||
|
||||
public open class PluginResolutionException : Exception {
|
||||
public constructor() : super()
|
||||
public constructor(message: String?) : super(message)
|
||||
public constructor(message: String?, cause: Throwable?) : super(message, cause)
|
||||
public constructor(cause: Throwable?) : super(cause)
|
||||
}
|
||||
|
||||
|
||||
// internal
|
||||
|
||||
|
||||
internal object PluginManagerImpl : PluginManager {
|
||||
override val pluginsDir = File(MiraiConsole.rootDir, "plugins").apply { mkdir() }
|
||||
override val pluginsDataFolder = File(MiraiConsole.rootDir, "data").apply { mkdir() }
|
||||
|
||||
@Suppress("ObjectPropertyName")
|
||||
private val _pluginLoaders: MutableList<PluginLoader<*, *>> = mutableListOf()
|
||||
@ -38,38 +88,21 @@ object PluginManager {
|
||||
|
||||
@JvmField
|
||||
internal val resolvedPlugins: MutableList<Plugin> = mutableListOf()
|
||||
|
||||
/**
|
||||
* 已加载的插件列表
|
||||
*/
|
||||
@JvmStatic
|
||||
val plugins: List<Plugin>
|
||||
override val plugins: List<Plugin>
|
||||
get() = resolvedPlugins.toList()
|
||||
|
||||
/**
|
||||
* 内建的插件加载器列表. 由 [MiraiConsole] 初始化
|
||||
*/
|
||||
@JvmStatic
|
||||
val builtInLoaders: List<PluginLoader<*, *>>
|
||||
override val builtInLoaders: List<PluginLoader<*, *>>
|
||||
get() = MiraiConsole.builtInPluginLoaders
|
||||
|
||||
/**
|
||||
* 由插件创建的 [PluginLoader]
|
||||
*/
|
||||
@JvmStatic
|
||||
val pluginLoaders: List<PluginLoader<*, *>>
|
||||
override val pluginLoaders: List<PluginLoader<*, *>>
|
||||
get() = _pluginLoaders.toList()
|
||||
|
||||
@JvmStatic
|
||||
fun registerPluginLoader(loader: PluginLoader<*, *>): Boolean = loadersLock.withLock {
|
||||
override fun registerPluginLoader(loader: PluginLoader<*, *>): Boolean = loadersLock.withLock {
|
||||
if (_pluginLoaders.any { it::class == loader }) {
|
||||
return false
|
||||
}
|
||||
_pluginLoaders.add(loader)
|
||||
}
|
||||
|
||||
@JvmStatic
|
||||
fun unregisterPluginLoader(loader: PluginLoader<*, *>) = loadersLock.withLock {
|
||||
override fun unregisterPluginLoader(loader: PluginLoader<*, *>) = loadersLock.withLock {
|
||||
_pluginLoaders.remove(loader)
|
||||
}
|
||||
|
||||
@ -177,8 +210,10 @@ object PluginManager {
|
||||
this.consumeLoadable().also { resultPlugins ->
|
||||
check(resultPlugins.size < beforeSize) {
|
||||
throw PluginMissingDependencyException(resultPlugins.joinToString("\n") { badPlugin ->
|
||||
"Cannot load plugin ${badPlugin.name}, missing dependencies: ${badPlugin.dependencies.filterIsMissing()
|
||||
.joinToString()}"
|
||||
"Cannot load plugin ${badPlugin.name}, missing dependencies: ${
|
||||
badPlugin.dependencies.filterIsMissing()
|
||||
.joinToString()
|
||||
}"
|
||||
})
|
||||
}
|
||||
}.doSort()
|
||||
@ -191,16 +226,6 @@ object PluginManager {
|
||||
// endregion
|
||||
}
|
||||
|
||||
class PluginMissingDependencyException(message: String?) : PluginResolutionException(message)
|
||||
|
||||
open class PluginResolutionException : Exception {
|
||||
constructor() : super()
|
||||
constructor(message: String?) : super(message)
|
||||
constructor(message: String?, cause: Throwable?) : super(message, cause)
|
||||
constructor(cause: Throwable?) : super(cause)
|
||||
}
|
||||
|
||||
|
||||
internal data class PluginDescriptionWithLoader(
|
||||
@JvmField val loader: PluginLoader<*, PluginDescription>, // easier type
|
||||
@JvmField val delegate: PluginDescription
|
||||
|
@ -15,10 +15,11 @@ import net.mamoe.mirai.console.utils.ConsoleExperimentalAPI
|
||||
import java.io.File
|
||||
|
||||
@ConsoleExperimentalAPI
|
||||
interface PluginCenter {
|
||||
public interface PluginCenter {
|
||||
|
||||
@Serializable
|
||||
data class PluginInsight(
|
||||
@ConsoleExperimentalAPI
|
||||
public data class PluginInsight(
|
||||
val name: String,
|
||||
val version: String,
|
||||
@SerialName("core")
|
||||
@ -31,8 +32,9 @@ interface PluginCenter {
|
||||
val commands: List<String>
|
||||
)
|
||||
|
||||
@ConsoleExperimentalAPI
|
||||
@Serializable
|
||||
data class PluginInfo(
|
||||
public data class PluginInfo(
|
||||
val name: String,
|
||||
val version: String,
|
||||
@SerialName("core")
|
||||
@ -54,24 +56,24 @@ interface PluginCenter {
|
||||
* 能获取到多少由实际的 [PluginCenter] 决定
|
||||
* 返回 插件名->Insight
|
||||
*/
|
||||
suspend fun fetchPlugin(page: Int): Map<String, PluginInsight>
|
||||
public suspend fun fetchPlugin(page: Int): Map<String, PluginInsight>
|
||||
|
||||
/**
|
||||
* 尝试获取到某个插件 by 全名, case sensitive
|
||||
* null 则没有
|
||||
*/
|
||||
suspend fun findPlugin(name: String): PluginInfo?
|
||||
public suspend fun findPlugin(name: String): PluginInfo?
|
||||
|
||||
|
||||
suspend fun <T : Any> T.downloadPlugin(name: String, progressListener: T.(Float) -> Unit): File
|
||||
public suspend fun <T : Any> T.downloadPlugin(name: String, progressListener: T.(Float) -> Unit): File
|
||||
|
||||
suspend fun downloadPlugin(name: String, progressListener: PluginCenter.(Float) -> Unit): File =
|
||||
public suspend fun downloadPlugin(name: String, progressListener: PluginCenter.(Float) -> Unit): File =
|
||||
downloadPlugin<PluginCenter>(name, progressListener)
|
||||
|
||||
/**
|
||||
* 刷新
|
||||
*/
|
||||
suspend fun refresh()
|
||||
public suspend fun refresh()
|
||||
|
||||
val name: String
|
||||
public val name: String
|
||||
}
|
||||
|
@ -9,7 +9,8 @@
|
||||
|
||||
package net.mamoe.mirai.console.plugin
|
||||
|
||||
import kotlinx.serialization.*
|
||||
import kotlinx.serialization.KSerializer
|
||||
import kotlinx.serialization.Serializable
|
||||
import kotlinx.serialization.builtins.serializer
|
||||
import net.mamoe.mirai.console.setting.internal.map
|
||||
import net.mamoe.yamlkt.Yaml
|
||||
@ -19,14 +20,14 @@ import java.io.File
|
||||
|
||||
/** 插件类型 */
|
||||
@Serializable(with = PluginKind.AsStringSerializer::class)
|
||||
enum class PluginKind {
|
||||
public enum class PluginKind {
|
||||
/** 表示此插件提供一个 [PluginLoader], 应在加载其他 [NORMAL] 类型插件前加载 */
|
||||
LOADER,
|
||||
|
||||
/** 表示此插件为一个通常的插件, 按照正常的依赖关系加载. */
|
||||
NORMAL;
|
||||
|
||||
object AsStringSerializer : KSerializer<PluginKind> by String.serializer().map(
|
||||
public object AsStringSerializer : KSerializer<PluginKind> by String.serializer().map(
|
||||
serializer = { it.name },
|
||||
deserializer = { str ->
|
||||
values().firstOrNull {
|
||||
@ -39,38 +40,38 @@ enum class PluginKind {
|
||||
/**
|
||||
* 插件描述
|
||||
*/
|
||||
interface PluginDescription {
|
||||
val kind: PluginKind
|
||||
public interface PluginDescription {
|
||||
public val kind: PluginKind
|
||||
|
||||
val name: String
|
||||
val author: String
|
||||
val version: String
|
||||
val info: String
|
||||
public val name: String
|
||||
public val author: String
|
||||
public val version: String
|
||||
public val info: String
|
||||
|
||||
/** 此插件依赖的其他插件, 将会在这些插件加载之后加载此插件 */
|
||||
val dependencies: List<@Serializable(with = PluginDependency.SmartSerializer::class) PluginDependency>
|
||||
public val dependencies: List<@Serializable(with = PluginDependency.SmartSerializer::class) PluginDependency>
|
||||
}
|
||||
|
||||
/** 插件的一个依赖的信息 */
|
||||
@Serializable
|
||||
data class PluginDependency(
|
||||
public data class PluginDependency(
|
||||
/** 依赖插件名 */
|
||||
val name: String,
|
||||
public val name: String,
|
||||
/**
|
||||
* 依赖版本号. 为 null 时则为不限制版本.
|
||||
* @see versionKind 版本号类型
|
||||
*/
|
||||
val version: String? = null,
|
||||
public val version: String? = null,
|
||||
/** 版本号类型 */
|
||||
val versionKind: VersionKind = VersionKind.AT_LEAST,
|
||||
public val versionKind: VersionKind = VersionKind.AT_LEAST,
|
||||
/**
|
||||
* 若为 `false`, 插件在找不到此依赖时也能正常加载.
|
||||
*/
|
||||
val isOptional: Boolean = false
|
||||
public val isOptional: Boolean = false
|
||||
) {
|
||||
/** 版本号类型 */
|
||||
@Serializable(with = VersionKind.AsStringSerializer::class)
|
||||
enum class VersionKind(
|
||||
public enum class VersionKind(
|
||||
private vararg val serialNames: String
|
||||
) {
|
||||
/** 要求依赖精确的版本 */
|
||||
@ -82,7 +83,7 @@ data class PluginDependency(
|
||||
/** 要求依赖最高版本 */
|
||||
AT_MOST("at_most", "AtMost", "most", "highest", "-");
|
||||
|
||||
object AsStringSerializer : KSerializer<VersionKind> by String.serializer().map(
|
||||
public object AsStringSerializer : KSerializer<VersionKind> by String.serializer().map(
|
||||
serializer = { it.serialNames.first() },
|
||||
deserializer = { str ->
|
||||
values().firstOrNull {
|
||||
@ -92,7 +93,7 @@ data class PluginDependency(
|
||||
)
|
||||
}
|
||||
|
||||
override fun toString(): String {
|
||||
public override fun toString(): String {
|
||||
return "$name ${versionKind.toEnglishString()}v$version"
|
||||
}
|
||||
|
||||
@ -100,7 +101,7 @@ data class PluginDependency(
|
||||
/**
|
||||
* 可支持解析 [String] 作为 [PluginDependency.version] 或单个 [PluginDependency]
|
||||
*/
|
||||
object SmartSerializer : KSerializer<PluginDependency> by YamlDynamicSerializer.map(
|
||||
public object SmartSerializer : KSerializer<PluginDependency> by YamlDynamicSerializer.map(
|
||||
serializer = { it },
|
||||
deserializer = { any ->
|
||||
when (any) {
|
||||
@ -114,8 +115,8 @@ data class PluginDependency(
|
||||
/**
|
||||
* 基于文件的插件 的描述
|
||||
*/
|
||||
interface FilePluginDescription : PluginDescription {
|
||||
val file: File
|
||||
public interface FilePluginDescription : PluginDescription {
|
||||
public val file: File
|
||||
}
|
||||
|
||||
internal fun PluginDependency.VersionKind.toEnglishString(): String = when (this) {
|
||||
|
@ -39,8 +39,8 @@ internal abstract class JvmPluginInternal(
|
||||
) : JvmPlugin,
|
||||
CoroutineScope {
|
||||
|
||||
private val resourceConsoleDelegate by lazy { this::class.asResourceContainer() }
|
||||
override fun getResourceAsStream(name: String): InputStream = resourceConsoleDelegate.getResourceAsStream(name)
|
||||
private val resourceContainerDelegate by lazy { this::class.asResourceContainer() }
|
||||
override fun getResourceAsStream(name: String): InputStream = resourceContainerDelegate.getResourceAsStream(name)
|
||||
|
||||
// region JvmPlugin
|
||||
/**
|
||||
|
@ -22,10 +22,10 @@ import kotlin.coroutines.EmptyCoroutineContext
|
||||
* @see JavaPlugin
|
||||
* @see KotlinPlugin
|
||||
*/
|
||||
abstract class AbstractJvmPlugin @JvmOverloads constructor(
|
||||
public abstract class AbstractJvmPlugin @JvmOverloads constructor(
|
||||
parentCoroutineContext: CoroutineContext = EmptyCoroutineContext
|
||||
) : JvmPlugin, JvmPluginInternal(parentCoroutineContext) {
|
||||
final override val name: String get() = this.description.name
|
||||
public final override val name: String get() = this.description.name
|
||||
|
||||
override fun <T : Setting> getSetting(clazz: Class<T>): T = loader.settingStorage.load(this, clazz)
|
||||
public override fun <T : Setting> getSetting(clazz: Class<T>): T = loader.settingStorage.load(this, clazz)
|
||||
}
|
@ -13,6 +13,7 @@ import kotlinx.coroutines.*
|
||||
import net.mamoe.mirai.console.MiraiConsole
|
||||
import net.mamoe.mirai.console.MiraiConsoleInternal
|
||||
import net.mamoe.mirai.console.plugin.AbstractFilePluginLoader
|
||||
import net.mamoe.mirai.console.plugin.FilePluginLoader
|
||||
import net.mamoe.mirai.console.plugin.PluginLoadException
|
||||
import net.mamoe.mirai.console.plugin.internal.JvmPluginInternal
|
||||
import net.mamoe.mirai.console.plugin.internal.PluginsLoader
|
||||
@ -28,11 +29,24 @@ import kotlin.reflect.full.createInstance
|
||||
/**
|
||||
* 内建的 Jar (JVM) 插件加载器
|
||||
*/
|
||||
object JarPluginLoader : AbstractFilePluginLoader<JvmPlugin, JvmPluginDescription>(".jar"), CoroutineScope {
|
||||
public interface JarPluginLoader : CoroutineScope, FilePluginLoader<JvmPlugin, JvmPluginDescription> {
|
||||
@ConsoleExperimentalAPI
|
||||
public val settingStorage: SettingStorage
|
||||
|
||||
public companion object INSTANCE : JarPluginLoader by JarPluginLoaderImpl
|
||||
}
|
||||
|
||||
|
||||
internal object JarPluginLoaderImpl :
|
||||
AbstractFilePluginLoader<JvmPlugin, JvmPluginDescription>(".jar"),
|
||||
CoroutineScope,
|
||||
JarPluginLoader {
|
||||
|
||||
private val logger: MiraiLogger = MiraiConsole.newLogger(JarPluginLoader::class.simpleName!!)
|
||||
|
||||
@ConsoleExperimentalAPI
|
||||
val settingStorage: SettingStorage = MiraiConsoleInternal.settingStorage
|
||||
override val settingStorage: SettingStorage
|
||||
get() = MiraiConsoleInternal.settingStorage
|
||||
|
||||
override val coroutineContext: CoroutineContext =
|
||||
MiraiConsole.coroutineContext +
|
||||
|
@ -18,14 +18,12 @@ import kotlin.coroutines.EmptyCoroutineContext
|
||||
/**
|
||||
* Java 插件的父类
|
||||
*/
|
||||
abstract class JavaPlugin @JvmOverloads constructor(
|
||||
public abstract class JavaPlugin @JvmOverloads constructor(
|
||||
parentCoroutineContext: CoroutineContext = EmptyCoroutineContext
|
||||
) : JvmPlugin, AbstractJvmPlugin(parentCoroutineContext) {
|
||||
|
||||
|
||||
/**
|
||||
* Java API Scheduler
|
||||
*/
|
||||
val scheduler: JavaPluginScheduler =
|
||||
JavaPluginScheduler(this.coroutineContext)
|
||||
public val scheduler: JavaPluginScheduler = JavaPluginScheduler(this.coroutineContext)
|
||||
}
|
@ -7,7 +7,7 @@
|
||||
* https://github.com/mamoe/mirai/blob/master/LICENSE
|
||||
*/
|
||||
|
||||
@file:Suppress("INVISIBLE_MEMBER", "INVISIBLE_REFERENCE", "EXPOSED_SUPER_CLASS")
|
||||
@file:Suppress("INVISIBLE_MEMBER", "INVISIBLE_REFERENCE", "EXPOSED_SUPER_CLASS", "NOTHING_TO_INLINE")
|
||||
|
||||
package net.mamoe.mirai.console.plugin.jvm
|
||||
|
||||
@ -32,34 +32,39 @@ import kotlin.reflect.KClass
|
||||
* @see JvmPlugin 支持文件系统扩展
|
||||
* @see ResourceContainer 支持资源获取 (如 Jar 中的资源文件)
|
||||
*/
|
||||
interface JvmPlugin : Plugin, CoroutineScope, PluginFileExtensions, ResourceContainer, AutoSaveSettingHolder {
|
||||
public interface JvmPlugin : Plugin, CoroutineScope,
|
||||
PluginFileExtensions, ResourceContainer, AutoSaveSettingHolder {
|
||||
/** 日志 */
|
||||
val logger: MiraiLogger
|
||||
public val logger: MiraiLogger
|
||||
|
||||
/** 插件描述 */
|
||||
val description: JvmPluginDescription
|
||||
public val description: JvmPluginDescription
|
||||
|
||||
/** 所属插件加载器实例 */
|
||||
override val loader: JarPluginLoader get() = JarPluginLoader
|
||||
public override val loader: JarPluginLoader get() = JarPluginLoader
|
||||
|
||||
/**
|
||||
* 获取一个 [Setting] 实例
|
||||
*/
|
||||
fun <T : Setting> getSetting(clazz: Class<T>): T
|
||||
public fun <T : Setting> getSetting(clazz: Class<T>): T
|
||||
|
||||
|
||||
// TODO: 2020/7/11 document onLoad, onEnable, onDisable
|
||||
@JvmDefault
|
||||
fun onLoad() {
|
||||
public fun onLoad() {
|
||||
}
|
||||
|
||||
@JvmDefault
|
||||
fun onEnable() {
|
||||
public fun onEnable() {
|
||||
}
|
||||
|
||||
@JvmDefault
|
||||
fun onDisable() {
|
||||
public fun onDisable() {
|
||||
}
|
||||
}
|
||||
|
||||
fun <T : Setting> JvmPlugin.getSetting(clazz: KClass<T>) = this.getSetting(clazz.java)
|
||||
inline fun <reified T : Setting> JvmPlugin.getSetting() = this.getSetting(T::class)
|
||||
@JvmSynthetic
|
||||
public inline fun <T : Setting> JvmPlugin.getSetting(clazz: KClass<T>): T = this.getSetting(clazz.java)
|
||||
|
||||
@JvmSynthetic
|
||||
public inline fun <reified T : Setting> JvmPlugin.getSetting(): T = this.getSetting(T::class)
|
@ -19,23 +19,23 @@ import net.mamoe.mirai.console.plugin.PluginKind
|
||||
import java.io.File
|
||||
|
||||
@Serializable
|
||||
class JvmPluginDescription internal constructor(
|
||||
override val kind: PluginKind = PluginKind.NORMAL,
|
||||
override val name: String,
|
||||
public class JvmPluginDescription internal constructor(
|
||||
public override val kind: PluginKind = PluginKind.NORMAL,
|
||||
public override val name: String,
|
||||
@SerialName("main")
|
||||
val mainClassName: String,
|
||||
override val author: String = "",
|
||||
override val version: String,
|
||||
override val info: String = "",
|
||||
public val mainClassName: String,
|
||||
public override val author: String = "",
|
||||
public override val version: String,
|
||||
public override val info: String = "",
|
||||
@SerialName("depends")
|
||||
override val dependencies: List<@Serializable(with = PluginDependency.SmartSerializer::class) PluginDependency> = listOf()
|
||||
public override val dependencies: List<@Serializable(with = PluginDependency.SmartSerializer::class) PluginDependency> = listOf()
|
||||
) : PluginDescription, FilePluginDescription {
|
||||
|
||||
/**
|
||||
* 在手动实现时使用这个构造器.
|
||||
*/
|
||||
@Suppress("unused")
|
||||
constructor(
|
||||
public constructor(
|
||||
kind: PluginKind, name: String, mainClassName: String, author: String,
|
||||
version: String, info: String, depends: List<PluginDependency>,
|
||||
file: File
|
||||
@ -43,7 +43,7 @@ class JvmPluginDescription internal constructor(
|
||||
this._file = file
|
||||
}
|
||||
|
||||
override val file: File
|
||||
public override val file: File
|
||||
get() = _file ?: error("Internal error: JvmPluginDescription(name=$name)._file == null")
|
||||
|
||||
|
||||
@ -52,7 +52,7 @@ class JvmPluginDescription internal constructor(
|
||||
@JvmField
|
||||
internal var _file: File? = null
|
||||
|
||||
override fun toString(): String {
|
||||
public override fun toString(): String {
|
||||
return "JvmPluginDescription(kind=$kind, name='$name', mainClassName='$mainClassName', author='$author', version='$version', info='$info', dependencies=$dependencies, _file=$_file)"
|
||||
}
|
||||
}
|
@ -7,13 +7,10 @@
|
||||
* https://github.com/mamoe/mirai/blob/master/LICENSE
|
||||
*/
|
||||
|
||||
@file:Suppress("INVISIBLE_MEMBER", "INVISIBLE_REFERENCE", "EXPOSED_SUPER_CLASS")
|
||||
@file:Suppress("INVISIBLE_MEMBER", "INVISIBLE_REFERENCE", "EXPOSED_SUPER_CLASS", "RedundantVisibilityModifier")
|
||||
|
||||
package net.mamoe.mirai.console.plugin.jvm
|
||||
|
||||
import net.mamoe.mirai.console.setting.Setting
|
||||
import net.mamoe.mirai.console.setting.getValue
|
||||
import net.mamoe.mirai.console.setting.value
|
||||
import net.mamoe.mirai.console.utils.ConsoleExperimentalAPI
|
||||
import kotlin.coroutines.CoroutineContext
|
||||
import kotlin.coroutines.EmptyCoroutineContext
|
||||
@ -23,7 +20,7 @@ import kotlin.coroutines.EmptyCoroutineContext
|
||||
*
|
||||
* 必须通过 "plugin.yml" 指定主类并由 [JarPluginLoader] 加载.
|
||||
*/
|
||||
abstract class KotlinPlugin @JvmOverloads constructor(
|
||||
public abstract class KotlinPlugin @JvmOverloads constructor(
|
||||
parentCoroutineContext: CoroutineContext = EmptyCoroutineContext
|
||||
) : JvmPlugin, AbstractJvmPlugin(parentCoroutineContext)
|
||||
|
||||
@ -32,11 +29,11 @@ abstract class KotlinPlugin @JvmOverloads constructor(
|
||||
* 在内存动态加载的插件.
|
||||
*/
|
||||
@ConsoleExperimentalAPI
|
||||
abstract class KotlinMemoryPlugin @JvmOverloads constructor(
|
||||
public abstract class KotlinMemoryPlugin @JvmOverloads constructor(
|
||||
description: JvmPluginDescription,
|
||||
parentCoroutineContext: CoroutineContext = EmptyCoroutineContext
|
||||
) : JvmPlugin, AbstractJvmPlugin(parentCoroutineContext) {
|
||||
final override var _description: JvmPluginDescription
|
||||
internal final override var _description: JvmPluginDescription
|
||||
get() = super._description
|
||||
set(value) {
|
||||
super._description = value
|
||||
@ -47,8 +44,11 @@ abstract class KotlinMemoryPlugin @JvmOverloads constructor(
|
||||
}
|
||||
}
|
||||
|
||||
object MyPlugin : KotlinPlugin()
|
||||
/*
|
||||
|
||||
object AccountSetting : Setting by MyPlugin.getSetting() {
|
||||
val s by value(1)
|
||||
public object MyPlugin : KotlinPlugin()
|
||||
|
||||
public object AccountSetting : Setting by MyPlugin.getSetting() {
|
||||
public val s by value(1)
|
||||
}
|
||||
*/
|
@ -29,11 +29,11 @@ import kotlin.reflect.KType
|
||||
* ```
|
||||
*/
|
||||
// TODO: 2020/6/26 document
|
||||
typealias SerialName = kotlinx.serialization.SerialName
|
||||
public typealias SerialName = kotlinx.serialization.SerialName
|
||||
|
||||
// TODO: 2020/6/26 document
|
||||
abstract class AbstractSetting : Setting, SettingImpl() {
|
||||
final override operator fun <T> SerializerAwareValue<T>.provideDelegate(
|
||||
public abstract class AbstractSetting : Setting, SettingImpl() {
|
||||
public final override operator fun <T> SerializerAwareValue<T>.provideDelegate(
|
||||
thisRef: Any?,
|
||||
property: KProperty<*>
|
||||
): SerializerAwareValue<T> {
|
||||
@ -42,34 +42,34 @@ abstract class AbstractSetting : Setting, SettingImpl() {
|
||||
return this
|
||||
}
|
||||
|
||||
final override val updaterSerializer: KSerializer<Unit> get() = super.updaterSerializer
|
||||
public final override val updaterSerializer: KSerializer<Unit> get() = super.updaterSerializer
|
||||
}
|
||||
|
||||
// TODO: 2020/6/26 document
|
||||
interface Setting {
|
||||
public interface Setting {
|
||||
// TODO: 2020/6/26 document
|
||||
operator fun <T> SerializerAwareValue<T>.provideDelegate(
|
||||
public operator fun <T> SerializerAwareValue<T>.provideDelegate(
|
||||
thisRef: Any?,
|
||||
property: KProperty<*>
|
||||
): SerializerAwareValue<T>
|
||||
|
||||
// TODO: 2020/6/26 document
|
||||
val updaterSerializer: KSerializer<Unit>
|
||||
public val updaterSerializer: KSerializer<Unit>
|
||||
|
||||
fun onValueChanged(value: Value<*>)
|
||||
public fun onValueChanged(value: Value<*>)
|
||||
}
|
||||
|
||||
//// region Setting_value_primitives CODEGEN ////
|
||||
|
||||
fun Setting.value(default: Byte): SerializerAwareValue<Byte> = valueImpl(default)
|
||||
fun Setting.value(default: Short): SerializerAwareValue<Short> = valueImpl(default)
|
||||
fun Setting.value(default: Int): SerializerAwareValue<Int> = valueImpl(default)
|
||||
fun Setting.value(default: Long): SerializerAwareValue<Long> = valueImpl(default)
|
||||
fun Setting.value(default: Float): SerializerAwareValue<Float> = valueImpl(default)
|
||||
fun Setting.value(default: Double): SerializerAwareValue<Double> = valueImpl(default)
|
||||
fun Setting.value(default: Char): SerializerAwareValue<Char> = valueImpl(default)
|
||||
fun Setting.value(default: Boolean): SerializerAwareValue<Boolean> = valueImpl(default)
|
||||
fun Setting.value(default: String): SerializerAwareValue<String> = valueImpl(default)
|
||||
public fun Setting.value(default: Byte): SerializerAwareValue<Byte> = valueImpl(default)
|
||||
public fun Setting.value(default: Short): SerializerAwareValue<Short> = valueImpl(default)
|
||||
public fun Setting.value(default: Int): SerializerAwareValue<Int> = valueImpl(default)
|
||||
public fun Setting.value(default: Long): SerializerAwareValue<Long> = valueImpl(default)
|
||||
public fun Setting.value(default: Float): SerializerAwareValue<Float> = valueImpl(default)
|
||||
public fun Setting.value(default: Double): SerializerAwareValue<Double> = valueImpl(default)
|
||||
public fun Setting.value(default: Char): SerializerAwareValue<Char> = valueImpl(default)
|
||||
public fun Setting.value(default: Boolean): SerializerAwareValue<Boolean> = valueImpl(default)
|
||||
public fun Setting.value(default: String): SerializerAwareValue<String> = valueImpl(default)
|
||||
|
||||
//// endregion Setting_value_primitives CODEGEN ////
|
||||
|
||||
@ -84,7 +84,7 @@ fun Setting.value(default: String): SerializerAwareValue<String> = valueImpl(def
|
||||
*/
|
||||
@Suppress("UNCHECKED_CAST")
|
||||
@LowPriorityInOverloadResolution
|
||||
inline fun <reified T> Setting.value(default: T): SerializerAwareValue<T> = valueFromKType(typeOf0<T>(), default)
|
||||
public inline fun <reified T> Setting.value(default: T): SerializerAwareValue<T> = valueFromKType(typeOf0<T>(), default)
|
||||
|
||||
/**
|
||||
* Creates a [Value] with reified type, and set default value by reflection to its no-arg public constructor.
|
||||
@ -95,13 +95,13 @@ inline fun <reified T> Setting.value(default: T): SerializerAwareValue<T> = valu
|
||||
* (typically annotated with [kotlinx.serialization.Serializable])
|
||||
*/
|
||||
@LowPriorityInOverloadResolution
|
||||
inline fun <reified T> Setting.value(): SerializerAwareValue<T> = value(T::class.createInstance() as T)
|
||||
public inline fun <reified T> Setting.value(): SerializerAwareValue<T> = value(T::class.createInstance() as T)
|
||||
|
||||
/**
|
||||
* Creates a [Value] with specified [KType], and set default value.
|
||||
*/
|
||||
@Suppress("UNCHECKED_CAST")
|
||||
fun <T> Setting.valueFromKType(type: KType, default: T): SerializerAwareValue<T> =
|
||||
public fun <T> Setting.valueFromKType(type: KType, default: T): SerializerAwareValue<T> =
|
||||
(valueFromKTypeImpl(type) as SerializerAwareValue<Any?>).apply { this.value = default } as SerializerAwareValue<T>
|
||||
|
||||
// TODO: 2020/6/24 Introduce class TypeToken for compound types for Java.
|
@ -1,3 +1,5 @@
|
||||
@file:Suppress("NOTHING_TO_INLINE")
|
||||
|
||||
package net.mamoe.mirai.console.setting
|
||||
|
||||
import kotlinx.atomicfu.atomic
|
||||
@ -22,19 +24,20 @@ import kotlin.reflect.full.findAnnotation
|
||||
/**
|
||||
* [Setting] 存储容器
|
||||
*/
|
||||
interface SettingStorage {
|
||||
public interface SettingStorage {
|
||||
/**
|
||||
* 读取一个实例
|
||||
*/
|
||||
fun <T : Setting> load(holder: SettingHolder, settingClass: Class<T>): T
|
||||
public fun <T : Setting> load(holder: SettingHolder, settingClass: Class<T>): T
|
||||
|
||||
/**
|
||||
* 保存一个实例
|
||||
*/
|
||||
fun store(holder: SettingHolder, setting: Setting)
|
||||
public fun store(holder: SettingHolder, setting: Setting)
|
||||
}
|
||||
|
||||
fun <T : Setting> SettingStorage.load(holder: SettingHolder, settingClass: KClass<T>): T =
|
||||
// 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)
|
||||
|
||||
/**
|
||||
@ -45,17 +48,19 @@ fun <T : Setting> SettingStorage.load(holder: SettingHolder, settingClass: KClas
|
||||
*
|
||||
* @see AutoSaveSettingHolder 自动保存
|
||||
*/
|
||||
interface SettingHolder {
|
||||
public interface SettingHolder {
|
||||
/**
|
||||
* 保存时使用的分类名
|
||||
*/
|
||||
val name: String
|
||||
public val name: String
|
||||
}
|
||||
|
||||
/**
|
||||
* 可以持有相关 [AutoSaveSetting] 的对象.
|
||||
*
|
||||
* @see net.mamoe.mirai.console.plugin.jvm.JvmPlugin
|
||||
*/
|
||||
interface AutoSaveSettingHolder : SettingHolder, CoroutineScope {
|
||||
public interface AutoSaveSettingHolder : SettingHolder, CoroutineScope {
|
||||
/**
|
||||
* [AutoSaveSetting] 每次自动保存时间间隔
|
||||
*
|
||||
@ -63,8 +68,11 @@ interface AutoSaveSettingHolder : SettingHolder, CoroutineScope {
|
||||
* - 区间的右端点为最大间隔, 一个 [Value] 被修改后, 最多不超过这个时间段后就会被保存.
|
||||
*
|
||||
* 若 [coroutineContext] 含有 [Job], 则 [AutoSaveSetting] 会通过 [Job.invokeOnCompletion] 在 Job 完结时触发自动保存.
|
||||
*
|
||||
* @see LongRange Java 用户使用 [LongRange] 的构造器创建
|
||||
* @see Long.rangeTo Kotlin 用户使用 [Long.rangeTo] 创建, 如 `3000..50000`
|
||||
*/
|
||||
val autoSaveIntervalMillis: LongRange
|
||||
public val autoSaveIntervalMillis: LongRange
|
||||
get() = 30.secondsToMillis..10.minutesToSeconds
|
||||
|
||||
/**
|
||||
@ -75,7 +83,7 @@ interface AutoSaveSettingHolder : SettingHolder, CoroutineScope {
|
||||
*
|
||||
* @see getSetting
|
||||
*/
|
||||
open class AutoSaveSetting(private val owner: AutoSaveSettingHolder, private val storage: SettingStorage) :
|
||||
public open class AutoSaveSetting(private val owner: AutoSaveSettingHolder, private val storage: SettingStorage) :
|
||||
AbstractSetting() {
|
||||
@Volatile
|
||||
internal var lastAutoSaveJob: Job? = null
|
||||
@ -111,7 +119,26 @@ interface AutoSaveSettingHolder : SettingHolder, CoroutineScope {
|
||||
|
||||
}
|
||||
|
||||
object MemorySettingStorage : SettingStorage {
|
||||
// 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 {
|
||||
private val list = mutableMapOf<Class<out Setting>, Setting>()
|
||||
|
||||
internal class MemorySettingImpl : AbstractSetting() {
|
||||
@ -146,9 +173,9 @@ object MemorySettingStorage : SettingStorage {
|
||||
}
|
||||
}
|
||||
|
||||
class MultiFileSettingStorage(
|
||||
private val directory: File
|
||||
) : SettingStorage {
|
||||
internal class MultiFileSettingStorageImpl(
|
||||
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)
|
||||
|
||||
@ -161,7 +188,7 @@ class MultiFileSettingStorage(
|
||||
)
|
||||
}
|
||||
if (holder is AutoSaveSettingHolder) {
|
||||
AutoSaveSetting(holder, this@MultiFileSettingStorage) as T?
|
||||
AutoSaveSetting(holder, this@MultiFileSettingStorageImpl) as T?
|
||||
} else null
|
||||
} ?: throw IllegalArgumentException(
|
||||
"Cannot create Setting instance. Make sure 'holder' is a AutoSaveSettingHolder, " +
|
||||
@ -189,7 +216,7 @@ class MultiFileSettingStorage(
|
||||
}
|
||||
|
||||
@ConsoleExperimentalAPI
|
||||
override fun store(holder: SettingHolder, setting: Setting) = with(setting::class) {
|
||||
override fun store(holder: SettingHolder, setting: Setting): Unit = with(setting::class) {
|
||||
val file = settingFile(holder, this)
|
||||
|
||||
if (file.exists() && file.isFile && file.canRead()) {
|
||||
|
@ -29,14 +29,14 @@ import kotlin.reflect.KProperty
|
||||
* @see PrimitiveValue
|
||||
* @see CompositeValue
|
||||
*/
|
||||
interface Value<T> {
|
||||
var value: T
|
||||
public interface Value<T> {
|
||||
public var value: T
|
||||
}
|
||||
|
||||
/**
|
||||
* Typically returned by [Setting.value] functions.
|
||||
*/
|
||||
class SerializableValue<T>(
|
||||
public class SerializableValue<T>(
|
||||
private val delegate: Value<T>,
|
||||
/**
|
||||
* The serializer used to update and dump [delegate]
|
||||
@ -46,7 +46,7 @@ class SerializableValue<T>(
|
||||
override fun toString(): String = delegate.toString()
|
||||
}
|
||||
|
||||
fun <T> Value<T>.serializableValueWith(
|
||||
public fun <T> Value<T>.serializableValueWith(
|
||||
serializer: KSerializer<T>
|
||||
): SerializableValue<T> {
|
||||
return SerializableValue(
|
||||
@ -58,27 +58,30 @@ fun <T> Value<T>.serializableValueWith(
|
||||
/**
|
||||
* @see SerializableValue
|
||||
*/
|
||||
interface SerializerAwareValue<T> : Value<T> {
|
||||
val serializer: KSerializer<Unit>
|
||||
public interface SerializerAwareValue<T> : Value<T> {
|
||||
public val serializer: KSerializer<Unit>
|
||||
}
|
||||
|
||||
fun <T> SerializerAwareValue<T>.serialize(format: StringFormat): String {
|
||||
public fun <T> SerializerAwareValue<T>.serialize(format: StringFormat): String {
|
||||
return format.stringify(this.serializer, Unit)
|
||||
}
|
||||
|
||||
fun <T> SerializerAwareValue<T>.serialize(format: BinaryFormat): ByteArray {
|
||||
public fun <T> SerializerAwareValue<T>.serialize(format: BinaryFormat): ByteArray {
|
||||
return format.dump(this.serializer, Unit)
|
||||
}
|
||||
|
||||
inline operator fun <T> Value<T>.getValue(mySetting: Any?, property: KProperty<*>): T = value
|
||||
inline operator fun <T> Value<T>.setValue(mySetting: Any?, property: KProperty<*>, value: T) {
|
||||
@JvmSynthetic
|
||||
public inline operator fun <T> Value<T>.getValue(mySetting: Any?, property: KProperty<*>): T = value
|
||||
|
||||
@JvmSynthetic
|
||||
public inline operator fun <T> Value<T>.setValue(mySetting: Any?, property: KProperty<*>, value: T) {
|
||||
this.value = value
|
||||
}
|
||||
|
||||
/**
|
||||
* The serializer for a specific kind of [Value].
|
||||
*/
|
||||
typealias ValueSerializer<T> = KSerializer<Value<T>>
|
||||
public typealias ValueSerializer<T> = KSerializer<Value<T>>
|
||||
|
||||
/**
|
||||
* Represents a observable *primitive* value wrapping.
|
||||
@ -92,7 +95,7 @@ typealias ValueSerializer<T> = KSerializer<Value<T>>
|
||||
* Note: The values are actually *boxed* because of the generic type T.
|
||||
* *Primitive* indicates only it is one of the 9 types mentioned above.
|
||||
*/
|
||||
interface PrimitiveValue<T> : Value<T>
|
||||
public interface PrimitiveValue<T> : Value<T>
|
||||
|
||||
|
||||
//// region PrimitiveValues CODEGEN ////
|
||||
@ -100,77 +103,77 @@ interface PrimitiveValue<T> : Value<T>
|
||||
/**
|
||||
* Represents a non-null [Byte] value.
|
||||
*/
|
||||
interface ByteValue : PrimitiveValue<Byte>
|
||||
public interface ByteValue : PrimitiveValue<Byte>
|
||||
|
||||
/**
|
||||
* Represents a non-null [Short] value.
|
||||
*/
|
||||
interface ShortValue : PrimitiveValue<Short>
|
||||
public interface ShortValue : PrimitiveValue<Short>
|
||||
|
||||
/**
|
||||
* Represents a non-null [Int] value.
|
||||
*/
|
||||
interface IntValue : PrimitiveValue<Int>
|
||||
public interface IntValue : PrimitiveValue<Int>
|
||||
|
||||
/**
|
||||
* Represents a non-null [Long] value.
|
||||
*/
|
||||
interface LongValue : PrimitiveValue<Long>
|
||||
public interface LongValue : PrimitiveValue<Long>
|
||||
|
||||
/**
|
||||
* Represents a non-null [Float] value.
|
||||
*/
|
||||
interface FloatValue : PrimitiveValue<Float>
|
||||
public interface FloatValue : PrimitiveValue<Float>
|
||||
|
||||
/**
|
||||
* Represents a non-null [Double] value.
|
||||
*/
|
||||
interface DoubleValue : PrimitiveValue<Double>
|
||||
public interface DoubleValue : PrimitiveValue<Double>
|
||||
|
||||
/**
|
||||
* Represents a non-null [Char] value.
|
||||
*/
|
||||
interface CharValue : PrimitiveValue<Char>
|
||||
public interface CharValue : PrimitiveValue<Char>
|
||||
|
||||
/**
|
||||
* Represents a non-null [Boolean] value.
|
||||
*/
|
||||
interface BooleanValue : PrimitiveValue<Boolean>
|
||||
public interface BooleanValue : PrimitiveValue<Boolean>
|
||||
|
||||
/**
|
||||
* Represents a non-null [String] value.
|
||||
*/
|
||||
interface StringValue : PrimitiveValue<String>
|
||||
public interface StringValue : PrimitiveValue<String>
|
||||
|
||||
//// endregion PrimitiveValues CODEGEN ////
|
||||
|
||||
|
||||
@ConsoleExperimentalAPI
|
||||
interface CompositeValue<T> : Value<T>
|
||||
public interface CompositeValue<T> : Value<T>
|
||||
|
||||
|
||||
/**
|
||||
* Superclass of [CompositeListValue], [PrimitiveListValue].
|
||||
*/
|
||||
interface ListValue<E> : CompositeValue<List<E>>
|
||||
public interface ListValue<E> : CompositeValue<List<E>>
|
||||
|
||||
/**
|
||||
* Elements can by anything, wrapped as [Value].
|
||||
* @param E is not primitive types.
|
||||
*/
|
||||
interface CompositeListValue<E> : ListValue<E>
|
||||
public interface CompositeListValue<E> : ListValue<E>
|
||||
|
||||
/**
|
||||
* Elements can only be primitives, not wrapped.
|
||||
* @param E is not primitive types.
|
||||
*/
|
||||
interface PrimitiveListValue<E> : ListValue<E>
|
||||
public interface PrimitiveListValue<E> : ListValue<E>
|
||||
|
||||
|
||||
//// region PrimitiveListValue CODEGEN ////
|
||||
|
||||
interface PrimitiveIntListValue : PrimitiveListValue<Int>
|
||||
interface PrimitiveLongListValue : PrimitiveListValue<Long>
|
||||
public interface PrimitiveIntListValue : PrimitiveListValue<Int>
|
||||
public interface PrimitiveLongListValue : PrimitiveListValue<Long>
|
||||
// TODO + codegen
|
||||
|
||||
//// endregion PrimitiveListValue CODEGEN ////
|
||||
@ -179,25 +182,25 @@ interface PrimitiveLongListValue : PrimitiveListValue<Long>
|
||||
/**
|
||||
* Superclass of [CompositeSetValue], [PrimitiveSetValue].
|
||||
*/
|
||||
interface SetValue<E> : CompositeValue<Set<E>>
|
||||
public interface SetValue<E> : CompositeValue<Set<E>>
|
||||
|
||||
/**
|
||||
* Elements can by anything, wrapped as [Value].
|
||||
* @param E is not primitive types.
|
||||
*/
|
||||
interface CompositeSetValue<E> : SetValue<E>
|
||||
public interface CompositeSetValue<E> : SetValue<E>
|
||||
|
||||
/**
|
||||
* Elements can only be primitives, not wrapped.
|
||||
* @param E is not primitive types.
|
||||
*/
|
||||
interface PrimitiveSetValue<E> : SetValue<E>
|
||||
public interface PrimitiveSetValue<E> : SetValue<E>
|
||||
|
||||
|
||||
//// region PrimitiveSetValue CODEGEN ////
|
||||
|
||||
interface PrimitiveIntSetValue : PrimitiveSetValue<Int>
|
||||
interface PrimitiveLongSetValue : PrimitiveSetValue<Long>
|
||||
public interface PrimitiveIntSetValue : PrimitiveSetValue<Int>
|
||||
public interface PrimitiveLongSetValue : PrimitiveSetValue<Long>
|
||||
// TODO + codegen
|
||||
|
||||
//// endregion PrimitiveSetValue CODEGEN ////
|
||||
@ -206,17 +209,17 @@ interface PrimitiveLongSetValue : PrimitiveSetValue<Long>
|
||||
/**
|
||||
* Superclass of [CompositeMapValue], [PrimitiveMapValue].
|
||||
*/
|
||||
interface MapValue<K, V> : CompositeValue<Map<K, V>>
|
||||
public interface MapValue<K, V> : CompositeValue<Map<K, V>>
|
||||
|
||||
interface CompositeMapValue<K, V> : MapValue<K, V>
|
||||
public interface CompositeMapValue<K, V> : MapValue<K, V>
|
||||
|
||||
interface PrimitiveMapValue<K, V> : MapValue<K, V>
|
||||
public interface PrimitiveMapValue<K, V> : MapValue<K, V>
|
||||
|
||||
|
||||
//// region PrimitiveMapValue CODEGEN ////
|
||||
|
||||
interface PrimitiveIntIntMapValue : PrimitiveMapValue<Int, Int>
|
||||
interface PrimitiveIntLongMapValue : PrimitiveMapValue<Int, Long>
|
||||
public interface PrimitiveIntIntMapValue : PrimitiveMapValue<Int, Int>
|
||||
public interface PrimitiveIntLongMapValue : PrimitiveMapValue<Int, Long>
|
||||
// TODO + codegen
|
||||
|
||||
//// endregion PrimitiveSetValue CODEGEN ////
|
||||
|
@ -98,7 +98,6 @@ internal abstract class ShortValueImpl : ShortValue, SerializerAwareValue<Short>
|
||||
else value.hashCode() * 31
|
||||
}
|
||||
}
|
||||
|
||||
internal abstract class IntValueImpl : IntValue, SerializerAwareValue<Int>, KSerializer<Unit>, AbstractValueImpl<Int> {
|
||||
constructor()
|
||||
constructor(default: Int) {
|
||||
|
@ -19,31 +19,31 @@ internal object BuiltInSerializerConstants {
|
||||
//// region BuiltInSerializerConstantsPrimitives CODEGEN ////
|
||||
|
||||
@JvmStatic
|
||||
val ByteSerializerDescriptor = Byte.serializer().descriptor
|
||||
internal val ByteSerializerDescriptor = Byte.serializer().descriptor
|
||||
|
||||
@JvmStatic
|
||||
val ShortSerializerDescriptor = Short.serializer().descriptor
|
||||
internal val ShortSerializerDescriptor = Short.serializer().descriptor
|
||||
|
||||
@JvmStatic
|
||||
val IntSerializerDescriptor = Int.serializer().descriptor
|
||||
internal val IntSerializerDescriptor = Int.serializer().descriptor
|
||||
|
||||
@JvmStatic
|
||||
val LongSerializerDescriptor = Long.serializer().descriptor
|
||||
internal val LongSerializerDescriptor = Long.serializer().descriptor
|
||||
|
||||
@JvmStatic
|
||||
val FloatSerializerDescriptor = Float.serializer().descriptor
|
||||
internal val FloatSerializerDescriptor = Float.serializer().descriptor
|
||||
|
||||
@JvmStatic
|
||||
val DoubleSerializerDescriptor = Double.serializer().descriptor
|
||||
internal val DoubleSerializerDescriptor = Double.serializer().descriptor
|
||||
|
||||
@JvmStatic
|
||||
val CharSerializerDescriptor = Char.serializer().descriptor
|
||||
internal val CharSerializerDescriptor = Char.serializer().descriptor
|
||||
|
||||
@JvmStatic
|
||||
val BooleanSerializerDescriptor = Boolean.serializer().descriptor
|
||||
internal val BooleanSerializerDescriptor = Boolean.serializer().descriptor
|
||||
|
||||
@JvmStatic
|
||||
val StringSerializerDescriptor = String.serializer().descriptor
|
||||
internal val StringSerializerDescriptor = String.serializer().descriptor
|
||||
|
||||
//// endregion BuiltInSerializerConstantsPrimitives CODEGEN ////
|
||||
}
|
||||
@ -76,103 +76,86 @@ internal fun Setting.valueImpl(default: Byte): SerializerAwareValue<Byte> {
|
||||
override fun onChanged() = this@valueImpl.onValueChanged(this)
|
||||
}
|
||||
}
|
||||
|
||||
internal fun Setting.byteValueImpl(): SerializerAwareValue<Byte> {
|
||||
return object : ByteValueImpl() {
|
||||
override fun onChanged() = this@byteValueImpl.onValueChanged(this)
|
||||
}
|
||||
}
|
||||
|
||||
internal fun Setting.valueImpl(default: Short): SerializerAwareValue<Short> {
|
||||
return object : ShortValueImpl(default) {
|
||||
override fun onChanged() = this@valueImpl.onValueChanged(this)
|
||||
}
|
||||
}
|
||||
|
||||
internal fun Setting.shortValueImpl(): SerializerAwareValue<Short> {
|
||||
return object : ShortValueImpl() {
|
||||
override fun onChanged() = this@shortValueImpl.onValueChanged(this)
|
||||
}
|
||||
}
|
||||
|
||||
internal fun Setting.valueImpl(default: Int): SerializerAwareValue<Int> {
|
||||
return object : IntValueImpl(default) {
|
||||
override fun onChanged() = this@valueImpl.onValueChanged(this)
|
||||
}
|
||||
}
|
||||
|
||||
internal fun Setting.intValueImpl(): SerializerAwareValue<Int> {
|
||||
return object : IntValueImpl() {
|
||||
override fun onChanged() = this@intValueImpl.onValueChanged(this)
|
||||
}
|
||||
}
|
||||
|
||||
internal fun Setting.valueImpl(default: Long): SerializerAwareValue<Long> {
|
||||
return object : LongValueImpl(default) {
|
||||
override fun onChanged() = this@valueImpl.onValueChanged(this)
|
||||
}
|
||||
}
|
||||
|
||||
internal fun Setting.longValueImpl(): SerializerAwareValue<Long> {
|
||||
return object : LongValueImpl() {
|
||||
override fun onChanged() = this@longValueImpl.onValueChanged(this)
|
||||
}
|
||||
}
|
||||
|
||||
internal fun Setting.valueImpl(default: Float): SerializerAwareValue<Float> {
|
||||
return object : FloatValueImpl(default) {
|
||||
override fun onChanged() = this@valueImpl.onValueChanged(this)
|
||||
}
|
||||
}
|
||||
|
||||
internal fun Setting.floatValueImpl(): SerializerAwareValue<Float> {
|
||||
return object : FloatValueImpl() {
|
||||
override fun onChanged() = this@floatValueImpl.onValueChanged(this)
|
||||
}
|
||||
}
|
||||
|
||||
internal fun Setting.valueImpl(default: Double): SerializerAwareValue<Double> {
|
||||
return object : DoubleValueImpl(default) {
|
||||
override fun onChanged() = this@valueImpl.onValueChanged(this)
|
||||
}
|
||||
}
|
||||
|
||||
internal fun Setting.doubleValueImpl(): SerializerAwareValue<Double> {
|
||||
return object : DoubleValueImpl() {
|
||||
override fun onChanged() = this@doubleValueImpl.onValueChanged(this)
|
||||
}
|
||||
}
|
||||
|
||||
internal fun Setting.valueImpl(default: Char): SerializerAwareValue<Char> {
|
||||
return object : CharValueImpl(default) {
|
||||
override fun onChanged() = this@valueImpl.onValueChanged(this)
|
||||
}
|
||||
}
|
||||
|
||||
internal fun Setting.charValueImpl(): SerializerAwareValue<Char> {
|
||||
return object : CharValueImpl() {
|
||||
override fun onChanged() = this@charValueImpl.onValueChanged(this)
|
||||
}
|
||||
}
|
||||
|
||||
internal fun Setting.valueImpl(default: Boolean): SerializerAwareValue<Boolean> {
|
||||
return object : BooleanValueImpl(default) {
|
||||
override fun onChanged() = this@valueImpl.onValueChanged(this)
|
||||
}
|
||||
}
|
||||
|
||||
internal fun Setting.booleanValueImpl(): SerializerAwareValue<Boolean> {
|
||||
return object : BooleanValueImpl() {
|
||||
override fun onChanged() = this@booleanValueImpl.onValueChanged(this)
|
||||
}
|
||||
}
|
||||
|
||||
internal fun Setting.valueImpl(default: String): SerializerAwareValue<String> {
|
||||
return object : StringValueImpl(default) {
|
||||
override fun onChanged() = this@valueImpl.onValueChanged(this)
|
||||
}
|
||||
}
|
||||
|
||||
internal fun Setting.stringValueImpl(): SerializerAwareValue<String> {
|
||||
return object : StringValueImpl() {
|
||||
override fun onChanged() = this@stringValueImpl.onValueChanged(this)
|
||||
|
@ -17,7 +17,7 @@ import net.mamoe.mirai.contact.User
|
||||
/**
|
||||
* 判断此用户是否为 console 管理员
|
||||
*/
|
||||
val User.isManager: Boolean
|
||||
public val User.isManager: Boolean
|
||||
get() = this.bot.managers.contains(this.id)
|
||||
|
||||
internal fun Bot.addManager(long: Long): Boolean {
|
||||
@ -25,9 +25,9 @@ internal fun Bot.addManager(long: Long): Boolean {
|
||||
return true
|
||||
}
|
||||
|
||||
fun Bot.removeManager(long: Long) {
|
||||
public fun Bot.removeManager(long: Long) {
|
||||
TODO()
|
||||
}
|
||||
|
||||
val Bot.managers: List<Long>
|
||||
public val Bot.managers: List<Long>
|
||||
get() = TODO()
|
||||
|
@ -7,47 +7,45 @@
|
||||
* https://github.com/mamoe/mirai/blob/master/LICENSE
|
||||
*/
|
||||
|
||||
@file:Suppress("INAPPLICABLE_JVM_NAME", "unused")
|
||||
|
||||
package net.mamoe.mirai.console.utils
|
||||
|
||||
import kotlinx.coroutines.*
|
||||
import kotlinx.coroutines.runBlocking
|
||||
import kotlinx.coroutines.sync.Mutex
|
||||
import kotlinx.coroutines.sync.withLock
|
||||
import net.mamoe.mirai.console.MiraiConsole
|
||||
import java.util.concurrent.Executors
|
||||
|
||||
/**
|
||||
* Console 输入. 由于 console 接管了 stdin, [readLine] 等操作需要在这里进行.
|
||||
*/
|
||||
public interface ConsoleInput {
|
||||
/**
|
||||
* 以 [提示][hint] 向用户索要一个输入
|
||||
*/
|
||||
@JvmSynthetic
|
||||
public suspend fun requestInput(hint: String): String
|
||||
|
||||
/**
|
||||
* 以 [提示][hint] 向用户索要一个输入. 仅供 Java 调用者使用
|
||||
*/
|
||||
@JvmName("requestInput")
|
||||
@JavaFriendlyAPI
|
||||
public fun requestInputBlocking(hint: String): String
|
||||
|
||||
public companion object INSTANCE : ConsoleInput by ConsoleInputImpl {
|
||||
public suspend inline fun MiraiConsole.requestInput(hint: String): String = ConsoleInput.requestInput(hint)
|
||||
}
|
||||
}
|
||||
|
||||
@Suppress("unused")
|
||||
object ConsoleInput {
|
||||
private val inputDispatcher = Executors.newFixedThreadPool(1).asCoroutineDispatcher()
|
||||
internal object ConsoleInputImpl : ConsoleInput {
|
||||
private val inputLock = Mutex()
|
||||
|
||||
/**
|
||||
* 向用户索要一个Input
|
||||
* 你需要提供一个hint(提示)并等待获取一个结果
|
||||
* 具体索要方式将根据frontend不同而不同
|
||||
* 如弹出框,或一行字
|
||||
*/
|
||||
suspend fun requestInput(
|
||||
override suspend fun requestInput(
|
||||
hint: String
|
||||
): String {
|
||||
return withContext(inputDispatcher) {
|
||||
MiraiConsole.frontEnd.requestInput(hint)
|
||||
): String = inputLock.withLock { MiraiConsole.frontEnd.requestInput(hint) }
|
||||
|
||||
@JavaFriendlyAPI
|
||||
override fun requestInputBlocking(hint: String): String = runBlocking { requestInput(hint) }
|
||||
}
|
||||
}
|
||||
|
||||
fun requestInputBlocking(hint: String): String = runBlocking { requestInput(hint) }
|
||||
|
||||
/**
|
||||
* asnyc获取
|
||||
*/
|
||||
fun requestInputAsync(
|
||||
scope: CoroutineScope,
|
||||
hint: String
|
||||
): Deferred<String> {
|
||||
return scope.async {
|
||||
requestInput(hint)
|
||||
}
|
||||
}
|
||||
|
||||
suspend fun MiraiConsole.requestInput(hint: String): String = requestInput(hint)
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
@ -19,7 +19,7 @@ internal annotation class JavaFriendlyAPI
|
||||
@RequiresOptIn(level = RequiresOptIn.Level.ERROR)
|
||||
@Target(CLASS, TYPEALIAS, FUNCTION, PROPERTY, FIELD, CONSTRUCTOR, CLASS, FUNCTION, PROPERTY)
|
||||
@MustBeDocumented
|
||||
annotation class ConsoleInternalAPI(
|
||||
public annotation class ConsoleInternalAPI(
|
||||
val message: String = ""
|
||||
)
|
||||
|
||||
@ -33,6 +33,6 @@ annotation class ConsoleInternalAPI(
|
||||
@RequiresOptIn(level = RequiresOptIn.Level.WARNING)
|
||||
@Target(CLASS, TYPEALIAS, FUNCTION, PROPERTY, FIELD, CONSTRUCTOR)
|
||||
@MustBeDocumented
|
||||
annotation class ConsoleExperimentalAPI(
|
||||
public annotation class ConsoleExperimentalAPI(
|
||||
val message: String = ""
|
||||
)
|
||||
|
@ -25,8 +25,8 @@ import kotlin.coroutines.CoroutineContext
|
||||
*
|
||||
* @see JavaPlugin.scheduler 获取实例
|
||||
*/
|
||||
class JavaPluginScheduler internal constructor(parentCoroutineContext: CoroutineContext) : CoroutineScope {
|
||||
override val coroutineContext: CoroutineContext =
|
||||
public class JavaPluginScheduler internal constructor(parentCoroutineContext: CoroutineContext) : CoroutineScope {
|
||||
public override val coroutineContext: CoroutineContext =
|
||||
parentCoroutineContext + SupervisorJob(parentCoroutineContext[Job])
|
||||
|
||||
/**
|
||||
@ -36,7 +36,7 @@ class JavaPluginScheduler internal constructor(parentCoroutineContext: Coroutine
|
||||
*
|
||||
* @see Future.cancel 取消这个任务
|
||||
*/
|
||||
fun repeating(intervalMs: Long, runnable: Runnable): Future<Void?> {
|
||||
public fun repeating(intervalMs: Long, runnable: Runnable): Future<Void?> {
|
||||
return this.future {
|
||||
while (isActive) {
|
||||
withContext(Dispatchers.IO) { runnable.run() }
|
||||
@ -51,7 +51,7 @@ class JavaPluginScheduler internal constructor(parentCoroutineContext: Coroutine
|
||||
*
|
||||
* 在延迟 [delayMillis] 后执行 [runnable]
|
||||
*/
|
||||
fun delayed(delayMillis: Long, runnable: Runnable): CompletableFuture<Void?> {
|
||||
public fun delayed(delayMillis: Long, runnable: Runnable): CompletableFuture<Void?> {
|
||||
return future {
|
||||
delay(delayMillis)
|
||||
withContext(Dispatchers.IO) {
|
||||
@ -66,7 +66,7 @@ class JavaPluginScheduler internal constructor(parentCoroutineContext: Coroutine
|
||||
*
|
||||
* 在延迟 [delayMillis] 后执行 [runnable]
|
||||
*/
|
||||
fun <R> delayed(delayMillis: Long, runnable: Callable<R>): CompletableFuture<Void?> {
|
||||
public fun <R> delayed(delayMillis: Long, runnable: Callable<R>): CompletableFuture<Void?> {
|
||||
return future {
|
||||
delay(delayMillis)
|
||||
withContext(Dispatchers.IO) { runnable.call() }
|
||||
@ -77,7 +77,7 @@ class JavaPluginScheduler internal constructor(parentCoroutineContext: Coroutine
|
||||
/**
|
||||
* 异步执行一个任务, 最终返回 [Future], 与 Java 使用方法无异, 但效率更高且可以在插件关闭时停止
|
||||
*/
|
||||
fun <R> async(supplier: Callable<R>): Future<R> {
|
||||
public fun <R> async(supplier: Callable<R>): Future<R> {
|
||||
return future {
|
||||
withContext(Dispatchers.IO) { supplier.call() }
|
||||
}
|
||||
@ -86,7 +86,7 @@ class JavaPluginScheduler internal constructor(parentCoroutineContext: Coroutine
|
||||
/**
|
||||
* 异步执行一个任务, 没有返回
|
||||
*/
|
||||
fun async(runnable: Runnable): Future<Void?> {
|
||||
public fun async(runnable: Runnable): Future<Void?> {
|
||||
return future {
|
||||
withContext(Dispatchers.IO) { runnable.run() }
|
||||
null
|
||||
|
@ -10,26 +10,26 @@ import kotlin.reflect.KClass
|
||||
/**
|
||||
* 资源容器.
|
||||
*/
|
||||
interface ResourceContainer {
|
||||
public interface ResourceContainer {
|
||||
/**
|
||||
* 获取一个资源文件
|
||||
*/
|
||||
fun getResourceAsStream(name: String): InputStream
|
||||
public fun getResourceAsStream(name: String): InputStream
|
||||
|
||||
/**
|
||||
* 读取一个资源文件并以 [Charsets.UTF_8] 编码为 [String]
|
||||
*/
|
||||
@JvmDefault
|
||||
fun getResource(name: String): String = getResource(name, Charsets.UTF_8)
|
||||
public fun getResource(name: String): String = getResource(name, Charsets.UTF_8)
|
||||
|
||||
/**
|
||||
* 读取一个资源文件并以 [charset] 编码为 [String]
|
||||
*/
|
||||
@JvmDefault
|
||||
fun getResource(name: String, charset: Charset): String =
|
||||
public fun getResource(name: String, charset: Charset): String =
|
||||
this.getResourceAsStream(name).use { it.readBytes() }.encodeToString()
|
||||
|
||||
companion object {
|
||||
public companion object {
|
||||
/**
|
||||
* 使用 [Class.getResourceAsStream] 读取资源文件
|
||||
*
|
||||
@ -37,22 +37,23 @@ interface ResourceContainer {
|
||||
*/
|
||||
@JvmStatic
|
||||
@JavaFriendlyAPI
|
||||
fun byClass(clazz: Class<*>): ResourceContainer = clazz.asResourceContainer()
|
||||
public fun byClass(clazz: Class<*>): ResourceContainer = clazz.asResourceContainer()
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 使用 [Class.getResourceAsStream] 读取资源文件
|
||||
*/
|
||||
public fun KClass<*>.asResourceContainer(): ResourceContainer = ClassAsResourceContainer(this.java)
|
||||
|
||||
/**
|
||||
* 使用 [Class.getResourceAsStream] 读取资源文件
|
||||
*/
|
||||
public fun Class<*>.asResourceContainer(): ResourceContainer = ClassAsResourceContainer(this)
|
||||
|
||||
|
||||
internal class ClassAsResourceContainer(
|
||||
private val clazz: Class<*>
|
||||
) : ResourceContainer {
|
||||
override fun getResourceAsStream(name: String): InputStream = clazz.getResourceAsStream(name)
|
||||
}
|
||||
|
||||
/**
|
||||
* 使用 [Class.getResourceAsStream] 读取资源文件
|
||||
*/
|
||||
fun KClass<*>.asResourceContainer(): ResourceContainer = ClassAsResourceContainer(this.java)
|
||||
|
||||
/**
|
||||
* 使用 [Class.getResourceAsStream] 读取资源文件
|
||||
*/
|
||||
fun Class<*>.asResourceContainer(): ResourceContainer = ClassAsResourceContainer(this)
|
@ -14,34 +14,25 @@ package net.mamoe.mirai.console.utils
|
||||
import org.jetbrains.annotations.Range
|
||||
import kotlin.contracts.InvocationKind
|
||||
import kotlin.contracts.contract
|
||||
import kotlin.internal.InlineOnly
|
||||
|
||||
/**
|
||||
* 执行 [n] 次 [block], 在第一次成功时返回执行结果, 在捕获到异常时返回异常.
|
||||
*/
|
||||
@kotlin.internal.InlineOnly
|
||||
inline fun <R> retryCatching(n: @Range(from = 1, to = Long.MAX_VALUE) Int, block: () -> R): Result<R> {
|
||||
@InlineOnly
|
||||
public inline fun <R> retryCatching(n: @Range(from = 1, to = Int.MAX_VALUE.toLong()) Int, block: () -> R): Result<R> {
|
||||
contract {
|
||||
callsInPlace(block, InvocationKind.AT_LEAST_ONCE)
|
||||
}
|
||||
require(n >= 0) { "param n for retryCatching must not be negative" }
|
||||
require(n >= 1) { "param n for retryCatching must not be negative" }
|
||||
var exception: Throwable? = null
|
||||
repeat(n) {
|
||||
try {
|
||||
return Result.success(block())
|
||||
} catch (e: Throwable) {
|
||||
exception?.addSuppressedMirai(e)
|
||||
exception?.addSuppressed(e)
|
||||
exception = e
|
||||
}
|
||||
}
|
||||
return Result.failure(exception!!)
|
||||
}
|
||||
|
||||
@PublishedApi
|
||||
internal fun Throwable.addSuppressedMirai(e: Throwable) {
|
||||
if (e === this) {
|
||||
return
|
||||
}
|
||||
kotlin.runCatching {
|
||||
this.addSuppressed(e)
|
||||
}
|
||||
}
|
@ -14,7 +14,7 @@ object Versions {
|
||||
const val consoleTerminal = "0.1.0"
|
||||
const val consolePure = "0.1-dev-1"
|
||||
|
||||
const val kotlin = "1.3.72"
|
||||
const val kotlin = "1.4-M3"
|
||||
const val coroutines = "1.3.7"
|
||||
const val serialization = "0.20.0"
|
||||
const val ktor = "1.3.2"
|
||||
|
Loading…
Reference in New Issue
Block a user