Explicit APIs

This commit is contained in:
Him188 2020-07-11 19:26:31 +08:00
parent 55ec375e09
commit 58187f95f0
43 changed files with 651 additions and 584 deletions

View File

@ -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)
"""
)
}

View File

@ -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 {

View File

@ -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 {

View File

@ -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
}

View File

@ -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,27 +131,28 @@ 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()}" +
if (this is MessageEventContextAware<*>) {
this.fromEvent.selectMessagesUnit {
"stacktrace" reply {
throwable.stacktraceString
sendMessage(
"Login failed: ${throwable.localizedMessage ?: throwable.message ?: throwable.toString()}" +
if (this is MessageEventContextAware<*>) {
this.fromEvent.selectMessagesUnit {
"stacktrace" reply {
throwable.stacktraceString
}
}
}
"test"
} else "")
"test"
} else "")
throw throwable
}

View File

@ -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]

View File

@ -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)

View File

@ -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')"
}

View File

@ -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())
}

View File

@ -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,

View File

@ -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)"
}

View File

@ -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
}

View File

@ -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
}

View File

@ -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>)
}

View File

@ -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
}

View File

@ -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)

View File

@ -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]

View File

@ -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)
}

View File

@ -14,4 +14,4 @@ import net.mamoe.mirai.event.Event
/**
* 表示来自 mirai-console 的事件
*/
interface ConsoleEvent : Event
public interface ConsoleEvent : Event

View File

@ -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` ?
}

View File

@ -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()
}

View File

@ -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

View File

@ -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
}

View File

@ -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) {
@ -112,10 +113,10 @@ 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) {

View File

@ -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
/**

View File

@ -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)
}

View File

@ -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 +

View File

@ -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)
}

View File

@ -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)

View File

@ -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)"
}
}

View 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)
}
*/

View File

@ -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.

View File

@ -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()) {

View File

@ -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 ////

View File

@ -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) {

View File

@ -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)

View File

@ -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()

View File

@ -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
@Suppress("unused")
object ConsoleInput {
private val inputDispatcher = Executors.newFixedThreadPool(1).asCoroutineDispatcher()
/**
* Console 输入. 由于 console 接管了 stdin, [readLine] 等操作需要在这里进行.
*/
public interface ConsoleInput {
/**
* [提示][hint] 向用户索要一个输入
*/
@JvmSynthetic
public suspend fun requestInput(hint: String): String
/**
* 向用户索要一个Input
* 你需要提供一个hint提示并等待获取一个结果
* 具体索要方式将根据frontend不同而不同
* 如弹出框或一行字
* [提示][hint] 向用户索要一个输入. 仅供 Java 调用者使用
*/
suspend fun requestInput(
hint: String
): String {
return withContext(inputDispatcher) {
MiraiConsole.frontEnd.requestInput(hint)
}
@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)
}
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)
}
@Suppress("unused")
internal object ConsoleInputImpl : ConsoleInput {
private val inputLock = Mutex()
override suspend fun requestInput(
hint: String
): String = inputLock.withLock { MiraiConsole.frontEnd.requestInput(hint) }
@JavaFriendlyAPI
override fun requestInputBlocking(hint: String): String = runBlocking { requestInput(hint) }
}

View File

@ -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 = ""
)

View File

@ -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

View File

@ -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)
}

View File

@ -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)
}
}

View File

@ -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"