mirror of
https://github.com/mamoe/mirai.git
synced 2025-01-11 02:50:15 +08:00
Merge remote-tracking branch 'origin/master' into dependencies
This commit is contained in:
commit
95e1486e3f
@ -84,46 +84,46 @@ internal object MessageScopeCodegen {
|
||||
)
|
||||
appendLine()
|
||||
}
|
||||
//
|
||||
// for ((a, b) in (TypeCandidatesForMessageScope + KtMessageScope).arrangements()) {
|
||||
// appendKCode(
|
||||
// """
|
||||
// @LowPriorityInOverloadResolution
|
||||
// public fun ${a}.scopeWith(vararg others: ${b}): MessageScope {
|
||||
// return others.fold(this.asMessageScope()) { acc, other -> CombinedScope(acc, other.asMessageScope()) }
|
||||
// }
|
||||
// """
|
||||
// )
|
||||
// appendLine()
|
||||
// }
|
||||
|
||||
for ((a, b) in (TypeCandidatesForMessageScope + KtMessageScope).arrangements()) {
|
||||
appendKCode(
|
||||
"""
|
||||
@LowPriorityInOverloadResolution
|
||||
public fun ${a}.scopeWith(vararg others: ${b}): MessageScope {
|
||||
return others.fold(this.asMessageScope()) { acc, other -> CombinedScope(acc, other.asMessageScope()) }
|
||||
public fun ${a}?.scopeWith(vararg others: ${b}?): MessageScope {
|
||||
return others.fold(this.asMessageScopeOrNoop()) { acc, other -> acc.scopeWith(other?.asMessageScope()) }
|
||||
}
|
||||
"""
|
||||
)
|
||||
appendLine()
|
||||
}
|
||||
//
|
||||
// for ((a, b) in (TypeCandidatesForMessageScope + KtMessageScope).arrangements()) {
|
||||
// appendKCode(
|
||||
// """
|
||||
// public fun ${a}.scopeWith(other: ${b}): MessageScope {
|
||||
// return CombinedScope(asMessageScope(), other.asMessageScope())
|
||||
// }
|
||||
// """
|
||||
// )
|
||||
// appendLine()
|
||||
// }
|
||||
|
||||
for ((a, b) in (TypeCandidatesForMessageScope + KtMessageScope).arrangements()) {
|
||||
appendKCode(
|
||||
"""
|
||||
@LowPriorityInOverloadResolution
|
||||
public fun ${a}?.scopeWithNotNull(vararg others: ${b}?): MessageScope {
|
||||
return others.fold(this.asMessageScopeOrNoop()) { acc, other -> acc.scopeWithNotNull(other?.asMessageScope()) }
|
||||
}
|
||||
"""
|
||||
)
|
||||
appendLine()
|
||||
}
|
||||
|
||||
for ((a, b) in (TypeCandidatesForMessageScope + KtMessageScope).arrangements()) {
|
||||
appendKCode(
|
||||
"""
|
||||
public fun ${a}.scopeWith(other: ${b}): MessageScope {
|
||||
return CombinedScope(asMessageScope(), other.asMessageScope())
|
||||
}
|
||||
"""
|
||||
)
|
||||
appendLine()
|
||||
}
|
||||
|
||||
for ((a, b) in (TypeCandidatesForMessageScope + KtMessageScope).arrangements()) {
|
||||
appendKCode(
|
||||
"""
|
||||
public fun ${a}?.scopeWithNotNull(other: ${b}?): MessageScope {
|
||||
public fun ${a}?.scopeWith(other: ${b}?): MessageScope {
|
||||
@Suppress("DuplicatedCode")
|
||||
return when {
|
||||
this == null && other == null -> NoopMessageScope
|
||||
@ -137,11 +137,22 @@ internal object MessageScopeCodegen {
|
||||
)
|
||||
appendLine()
|
||||
}
|
||||
//
|
||||
// for ((a, b) in (TypeCandidatesForMessageScope + KtMessageScope).arrangements()) {
|
||||
// appendKCode(
|
||||
// """
|
||||
// public inline fun <R> ${a}.scopeWith(vararg others: ${b}, action: MessageScope.() -> R): R {
|
||||
// return scopeWith(*others).invoke(action)
|
||||
// }
|
||||
// """
|
||||
// )
|
||||
// appendLine()
|
||||
// }
|
||||
|
||||
for ((a, b) in (TypeCandidatesForMessageScope + KtMessageScope).arrangements()) {
|
||||
appendKCode(
|
||||
"""
|
||||
public inline fun <R> ${a}.scopeWith(vararg others: ${b}, action: MessageScope.() -> R): R {
|
||||
public inline fun <R> ${a}?.scopeWith(vararg others: ${b}?, action: MessageScope.() -> R): R {
|
||||
return scopeWith(*others).invoke(action)
|
||||
}
|
||||
"""
|
||||
@ -149,17 +160,6 @@ internal object MessageScopeCodegen {
|
||||
appendLine()
|
||||
}
|
||||
|
||||
for ((a, b) in (TypeCandidatesForMessageScope + KtMessageScope).arrangements()) {
|
||||
appendKCode(
|
||||
"""
|
||||
public inline fun <R> ${a}?.scopeWithNotNull(vararg others: ${b}?, action: MessageScope.() -> R): R {
|
||||
return scopeWithNotNull(*others).invoke(action)
|
||||
}
|
||||
"""
|
||||
)
|
||||
appendLine()
|
||||
}
|
||||
|
||||
for (a in (TypeCandidatesForMessageScope + KtMessageScope)) {
|
||||
appendKCode(
|
||||
"""
|
||||
|
@ -1,193 +0,0 @@
|
||||
# mirai-console backend
|
||||
|
||||
欢迎来到 mirai-console 后端开发文档。
|
||||
|
||||
[`Plugin`]: src/main/kotlin/net/mamoe/mirai/console/plugin/Plugin.kt
|
||||
[`PluginDescription`]: src/main/kotlin/net/mamoe/mirai/console/plugin/description/PluginDescription.kt
|
||||
[`PluginLoader`]: src/main/kotlin/net/mamoe/mirai/console/plugin/PluginLoader.kt
|
||||
[`PluginManager`]: src/main/kotlin/net/mamoe/mirai/console/plugin/PluginManager.kt
|
||||
[`JarPluginLoader`]: src/main/kotlin/net/mamoe/mirai/console/plugin/jvm/JarPluginLoader.kt
|
||||
[`JvmPlugin`]: src/main/kotlin/net/mamoe/mirai/console/plugin/jvm/JvmPlugin.kt
|
||||
[`JvmPluginDescription`]: src/main/kotlin/net/mamoe/mirai/console/plugin/jvm/JvmPluginDescription.kt
|
||||
[`AbstractJvmPlugin`]: src/main/kotlin/net/mamoe/mirai/console/plugin/jvm/AbstractJvmPlugin.kt
|
||||
[`KotlinPlugin`]: src/main/kotlin/net/mamoe/mirai/console/plugin/jvm/KotlinPlugin.kt
|
||||
[`JavaPlugin`]: src/main/kotlin/net/mamoe/mirai/console/plugin/jvm/JavaPlugin.kt
|
||||
|
||||
|
||||
[`PluginData`]: src/main/kotlin/net/mamoe/mirai/console/data/PluginData.kt
|
||||
[`PluginConfig`]: src/main/kotlin/net/mamoe/mirai/console/data/PluginConfig.kt
|
||||
[`PluginDataStorage`]: src/main/kotlin/net/mamoe/mirai/console/data/PluginDataStorage.kt
|
||||
|
||||
[`MiraiConsole`]: src/main/kotlin/net/mamoe/mirai/console/MiraiConsole.kt
|
||||
[`MiraiConsoleImplementation`]: src/main/kotlin/net/mamoe/mirai/console/MiraiConsoleImplementation.kt
|
||||
<!--[MiraiConsoleFrontEnd]: src/main/kotlin/net/mamoe/mirai/console/MiraiConsoleFrontEnd.kt-->
|
||||
|
||||
[`Command`]: src/main/kotlin/net/mamoe/mirai/console/command/Command.kt
|
||||
[`CompositeCommand`]: src/main/kotlin/net/mamoe/mirai/console/command/CompositeCommand.kt
|
||||
[`SimpleCommand`]: src/main/kotlin/net/mamoe/mirai/console/command/SimpleCommand.kt
|
||||
[`RawCommand`]: src/main/kotlin/net/mamoe/mirai/console/command/RawCommand.kt
|
||||
[`CommandManager`]: src/main/kotlin/net/mamoe/mirai/console/command/CommandManager.kt
|
||||
|
||||
[`BotManager`]: src/main/kotlin/net/mamoe/mirai/console/util/BotManager.kt
|
||||
[`Annotations`]: src/main/kotlin/net/mamoe/mirai/console/util/Annotations.kt
|
||||
[`ConsoleInput`]: src/main/kotlin/net/mamoe/mirai/console/util/ConsoleInput.kt
|
||||
[`JavaPluginScheduler`]: src/main/kotlin/net/mamoe/mirai/console/plugin/jvm/JavaPluginScheduler.kt
|
||||
[`ResourceContainer`]: src/main/kotlin/net/mamoe/mirai/console/plugin/ResourceContainer.kt
|
||||
|
||||
|
||||
## 基础
|
||||
|
||||
### `Plugin` 模块
|
||||
|
||||
Console 支持拥有强扩展性的插件加载器。内建 JVM 插件支持 ([`JarPluginLoader`])。
|
||||
|
||||
#### [插件加载器 `PluginLoader`][`PluginLoader`] 和 [插件管理器][`PluginManager`]
|
||||
Console 本身是一套高扩展性的「框架」,拥有通用的 [插件加载器][`PluginLoader`]。
|
||||
|
||||
Console 内置 [`JarPluginLoader`],支持加载使用 Kotlin、 Java,或其他 JVM 平台编程语言并打包为 ‘jar’ 的插件 (详见下文 `JvmPlugin`)。
|
||||
|
||||
扩展的 [插件加载器][`PluginLoader`] 可以由一个特别的 [JVM 插件][`JvmPlugin`] 提供。
|
||||
|
||||
|
||||
##### 服务器启动过程中的插件加载流程
|
||||
|
||||
在服务器启动过程中, Console 首先加载那些提供扩展 [插件加载器][`PluginLoader`] 的插件。
|
||||
随后对插件按依赖顺序调用 `onLoad()`, 告知插件主类加载完毕, 相关依赖解决完毕.
|
||||
当所有插件的 `onLoad()` 都被调用后, [`PluginManager`] 按依赖顺序依次调用 `onEnable()`
|
||||
|
||||
如果 A 依赖 B, B 依赖 C. 那么启动时的调用顺序为:
|
||||
`C.onLoad()` -> `B.onLoad()` -> `A.onLoad()` -> `C.onEnable` -> `B.onEnable()` -> `A.onEnable()`
|
||||
|
||||
#### [`Plugin`]
|
||||
所有 Console 插件都必须实现 [`Plugin`] 接口。
|
||||
|
||||
`Plugin` 很通用,它只拥有很少的成员:
|
||||
```kotlin
|
||||
interface Plugin : CommandOwner {
|
||||
val isEnabled: Boolean
|
||||
val loader: PluginLoader<*, *> // 能处理这个 Plugin 的 PluginLoader
|
||||
}
|
||||
```
|
||||
|
||||
[`Plugin`] 可在相应 [插件加载器 `PluginLoader`][`PluginLoader`] 的帮助下,成为任何语言实现的插件与 Console 建立联系的桥梁。
|
||||
|
||||
|
||||
#### [JVM 插件][`JvmPlugin`]
|
||||
|
||||
##### [`JvmPlugin`]
|
||||
|
||||
```kotlin
|
||||
interface JvmPlugin : Plugin, CoroutineScope, PluginFileExtensions, ResourceContainer, AutoSavePluginDataHolder {
|
||||
val logger: MiraiLogger
|
||||
val description: JvmPluginDescription
|
||||
val loader: JarPluginLoader
|
||||
fun <T : PluginData> loadPluginData(clazz: Class<T>): T
|
||||
fun <T : PluginConfig> loadPluginConfig(clazz: Class<T>): T
|
||||
fun onLoad() {}
|
||||
fun onEnable() {}
|
||||
fun onDisable() {}
|
||||
}
|
||||
```
|
||||
|
||||
##### 提供插件信息
|
||||
|
||||
JVM 插件, 通常需要打包为 `jar` 后才能被加载. Console 使用类似 Java ServiceLoader 的方式加载插件.
|
||||
|
||||
- 方法 A. (推荐) 自动创建 service 文件 (使用 Google auto-service)
|
||||
在 `build.gradle.kts` 添加:
|
||||
```kotlin
|
||||
plugins {
|
||||
kotlin("kapt")
|
||||
}
|
||||
dependencies {
|
||||
val autoService = "1.0-rc7"
|
||||
kapt("com.google.auto.service", "auto-service", autoService)
|
||||
compileOnly("com.google.auto.service", "auto-service-annotations", autoService)
|
||||
}
|
||||
```
|
||||
*对于 `build.gradle` 用户, 请自行按照 Groovy DSL 语法翻译*
|
||||
|
||||
- 方法 B. 手动创建 service 文件
|
||||
在 `jar` 内 `META-INF/services/net.mamoe.mirai.console.plugin.jvm.JvmPlugin` 文件内存放插件主类全名.
|
||||
|
||||
|
||||
**注意**:
|
||||
- 插件自身的版本要求遵循 [语义化版本 2.0.0](https://semver.org/lang/zh-CN/) 规范, 合格的版本例如: `1.0.0`, `1.0`, `1.0-M1`, `1.0-pre-1`
|
||||
- 插件依赖的版本遵循 [语义化版本 2.0.0](https://semver.org/lang/zh-CN/) 规范, 同时支持 [Apache Ivy 风格表示方法](http://ant.apache.org/ivy/history/latest-milestone/settings/version-matchers.html).
|
||||
|
||||
|
||||
#### 实现 Kotlin 插件
|
||||
|
||||
一个 Kotlin 插件的主类通常需:
|
||||
- 继承 [`KotlinPlugin`]
|
||||
- 访问权限为 `public` 或默认 (不指定)
|
||||
|
||||
```kotlin
|
||||
@AutoService(JvmPlugin::class) // 让 Console 知道这个 object 是一个插件主类.
|
||||
object SchedulePlugin : KotlinPlugin(
|
||||
SimpleJvmPluginDescription( // 插件的描述, name 和 version 是必须的
|
||||
name = "Schedule",
|
||||
version = "1.0.0",
|
||||
// author, description, ...
|
||||
)
|
||||
) {
|
||||
// ...
|
||||
}
|
||||
```
|
||||
|
||||
#### 实现 Java 插件
|
||||
|
||||
一个 Java 插件的主类通常需:
|
||||
- 继承 [`KotlinPlugin`]
|
||||
- 访问权限为 `public` 或默认 (不指定)
|
||||
|
||||
(推荐) 静态初始化:
|
||||
```java
|
||||
@AutoService(JvmPlugin.class)
|
||||
public final class JExample extends JavaPlugin {
|
||||
public static final JExample INSTANCE = new JExample(); // 可以像 Kotlin 一样静态初始化单例
|
||||
private JExample() {
|
||||
super(new SimpleJvmPluginDescription(
|
||||
"JExample", // name
|
||||
"1.0.0" // version
|
||||
));
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
由 Console 初始化:
|
||||
```java
|
||||
@AutoService(JvmPlugin.class)
|
||||
public final class JExample extends JavaPlugin {
|
||||
private static final JExample instance;
|
||||
public static JExample getInstance() {
|
||||
return instance;
|
||||
}
|
||||
public JExample() { // 此时必须 public
|
||||
super(new SimpleJvmPluginDescription(
|
||||
"JExample", // name
|
||||
"1.0.0" // version
|
||||
));
|
||||
instance = this;
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
#### 获取资源文件 [`ResourceContainer`]
|
||||
|
||||
[`JvmPlugin`] 实现接口 [`ResourceContainer`], 可在 `jar` 包内搜索资源文件.
|
||||
|
||||
提供三个获取方法:
|
||||
```kotlin
|
||||
interface ResourceContainer {
|
||||
fun getResourceAsStream(path: String): InputStream?
|
||||
fun getResource(path: String): String?
|
||||
fun getResource(path: String, charset: Charset): String?
|
||||
}
|
||||
```
|
||||
|
||||
### [`PluginData`] 模块
|
||||
|
||||
[`PluginData`]
|
||||
|
||||
... 待续
|
@ -16,17 +16,13 @@ import net.mamoe.mirai.Bot
|
||||
import net.mamoe.mirai.alsoLogin
|
||||
import net.mamoe.mirai.console.MiraiConsole
|
||||
import net.mamoe.mirai.console.command.CommandManager.INSTANCE.register
|
||||
import net.mamoe.mirai.console.command.description.PermissibleIdentifierArgumentParser
|
||||
import net.mamoe.mirai.console.command.description.PermissionIdArgumentParser
|
||||
import net.mamoe.mirai.console.command.description.buildCommandArgumentContext
|
||||
import net.mamoe.mirai.console.command.description.*
|
||||
import net.mamoe.mirai.console.internal.command.CommandManagerImpl
|
||||
import net.mamoe.mirai.console.internal.command.CommandManagerImpl.allRegisteredCommands
|
||||
import net.mamoe.mirai.console.internal.command.qualifiedNameOrTip
|
||||
import net.mamoe.mirai.console.permission.ExperimentalPermission
|
||||
import net.mamoe.mirai.console.permission.PermissibleIdentifier
|
||||
import net.mamoe.mirai.console.permission.PermissionId
|
||||
import net.mamoe.mirai.console.permission.PermissionService
|
||||
import net.mamoe.mirai.console.permission.*
|
||||
import net.mamoe.mirai.console.permission.PermissionService.Companion.denyPermission
|
||||
import net.mamoe.mirai.console.permission.PermissionService.Companion.findCorrespondingPermissionOrFail
|
||||
import net.mamoe.mirai.console.permission.PermissionService.Companion.getGrantedPermissions
|
||||
import net.mamoe.mirai.console.permission.PermissionService.Companion.grantPermission
|
||||
import net.mamoe.mirai.console.util.ConsoleExperimentalAPI
|
||||
@ -51,6 +47,7 @@ internal interface BuiltInCommandInternal : Command
|
||||
*/
|
||||
@ConsoleExperimentalAPI
|
||||
@Suppress("unused")
|
||||
@OptIn(ExperimentalPermission::class)
|
||||
public object BuiltInCommands {
|
||||
|
||||
public val all: Array<out Command> by lazy {
|
||||
@ -63,9 +60,10 @@ public object BuiltInCommands {
|
||||
}
|
||||
}
|
||||
|
||||
public object Help : SimpleCommand(
|
||||
public object HelpCommand : SimpleCommand(
|
||||
ConsoleCommandOwner, "help",
|
||||
description = "Command list"
|
||||
description = "Command list",
|
||||
parentPermission = RootConsoleBuiltInPermission,
|
||||
), BuiltInCommand {
|
||||
@Handler
|
||||
public suspend fun CommandSender.handle() {
|
||||
@ -82,9 +80,10 @@ public object BuiltInCommands {
|
||||
})
|
||||
}
|
||||
|
||||
public object Stop : SimpleCommand(
|
||||
public object StopCommand : SimpleCommand(
|
||||
ConsoleCommandOwner, "stop", "shutdown", "exit",
|
||||
description = "Stop the whole world."
|
||||
description = "Stop the whole world.",
|
||||
parentPermission = RootConsoleBuiltInPermission,
|
||||
), BuiltInCommand {
|
||||
|
||||
private val closingLock = Mutex()
|
||||
@ -117,9 +116,10 @@ public object BuiltInCommands {
|
||||
}
|
||||
}
|
||||
|
||||
public object Login : SimpleCommand(
|
||||
public object LoginCommand : SimpleCommand(
|
||||
ConsoleCommandOwner, "login", "登录",
|
||||
description = "Log in a bot account."
|
||||
description = "Log in a bot account.",
|
||||
parentPermission = RootConsoleBuiltInPermission,
|
||||
), BuiltInCommand {
|
||||
@Handler
|
||||
public suspend fun CommandSender.handle(id: Long, password: String) {
|
||||
@ -145,23 +145,28 @@ public object BuiltInCommands {
|
||||
}
|
||||
|
||||
@OptIn(ExperimentalPermission::class)
|
||||
public object Permission : CompositeCommand(
|
||||
ConsoleCommandOwner, "permission", "权限",
|
||||
public object PermissionCommand : CompositeCommand(
|
||||
ConsoleCommandOwner, "permission", "权限", "perm",
|
||||
description = "Manage permissions",
|
||||
overrideContext = buildCommandArgumentContext {
|
||||
PermissibleIdentifier::class with PermissibleIdentifierArgumentParser
|
||||
PermissionId::class with PermissionIdArgumentParser
|
||||
Permission::class with PermissionIdArgumentParser.map { id ->
|
||||
kotlin.runCatching {
|
||||
id.findCorrespondingPermissionOrFail()
|
||||
}.getOrElse { illegalArgument("指令不存在: $id", it) }
|
||||
}
|
||||
},
|
||||
parentPermission = RootConsoleBuiltInPermission,
|
||||
), BuiltInCommand {
|
||||
// TODO: 2020/9/10 improve Permission command
|
||||
@SubCommand
|
||||
public suspend fun CommandSender.grant(target: PermissibleIdentifier, permission: PermissionId) {
|
||||
public suspend fun CommandSender.grant(target: PermissibleIdentifier, permission: Permission) {
|
||||
target.grantPermission(permission)
|
||||
sendMessage("OK")
|
||||
}
|
||||
|
||||
@SubCommand
|
||||
public suspend fun CommandSender.deny(target: PermissibleIdentifier, permission: PermissionId) {
|
||||
public suspend fun CommandSender.deny(target: PermissibleIdentifier, permission: Permission) {
|
||||
target.denyPermission(permission)
|
||||
sendMessage("OK")
|
||||
}
|
||||
|
@ -15,11 +15,10 @@ import net.mamoe.kjbb.JvmBlockingBridge
|
||||
import net.mamoe.mirai.console.command.CommandManager.INSTANCE.executeCommand
|
||||
import net.mamoe.mirai.console.command.CommandManager.INSTANCE.register
|
||||
import net.mamoe.mirai.console.command.java.JCommand
|
||||
import net.mamoe.mirai.console.internal.command.createCommandPermission
|
||||
import net.mamoe.mirai.console.internal.command.createOrFindCommandPermission
|
||||
import net.mamoe.mirai.console.internal.command.isValidSubName
|
||||
import net.mamoe.mirai.console.permission.ExperimentalPermission
|
||||
import net.mamoe.mirai.console.permission.Permission
|
||||
import net.mamoe.mirai.console.permission.PermissionId
|
||||
import net.mamoe.mirai.message.data.MessageChain
|
||||
import net.mamoe.mirai.message.data.SingleMessage
|
||||
|
||||
@ -107,7 +106,7 @@ public abstract class AbstractCommand
|
||||
public override val owner: CommandOwner,
|
||||
vararg names: String,
|
||||
description: String = "<no description available>",
|
||||
parentPermission: PermissionId = owner.basePermission,
|
||||
parentPermission: Permission = owner.parentPermission,
|
||||
/** 为 `true` 时表示 [指令前缀][CommandManager.commandPrefix] 可选 */
|
||||
public override val prefixOptional: Boolean = false
|
||||
) : Command {
|
||||
@ -118,5 +117,5 @@ public abstract class AbstractCommand
|
||||
}.toTypedArray()
|
||||
|
||||
@OptIn(ExperimentalPermission::class)
|
||||
public override val permission: Permission by lazy { createCommandPermission(parentPermission) }
|
||||
public override val permission: Permission by lazy { createOrFindCommandPermission(parentPermission) }
|
||||
}
|
@ -10,10 +10,7 @@
|
||||
package net.mamoe.mirai.console.command
|
||||
|
||||
import net.mamoe.mirai.console.command.CommandManager.INSTANCE.unregisterAllCommands
|
||||
import net.mamoe.mirai.console.permission.ExperimentalPermission
|
||||
import net.mamoe.mirai.console.permission.PermissionId
|
||||
import net.mamoe.mirai.console.permission.PermissionIdNamespace
|
||||
import net.mamoe.mirai.console.permission.RootPermission
|
||||
import net.mamoe.mirai.console.permission.*
|
||||
import net.mamoe.mirai.console.plugin.jvm.JvmPlugin
|
||||
|
||||
/**
|
||||
@ -27,12 +24,12 @@ import net.mamoe.mirai.console.plugin.jvm.JvmPlugin
|
||||
@OptIn(ExperimentalPermission::class)
|
||||
public interface CommandOwner : PermissionIdNamespace {
|
||||
/**
|
||||
* 此 [PermissionIdNamespace] 拥有的指令都默认将 [basePermission] 作为父权限.
|
||||
* 此 [PermissionIdNamespace] 拥有的指令都默认将 [parentPermission] 作为父权限.
|
||||
*
|
||||
* TODO document
|
||||
*/
|
||||
@ExperimentalPermission
|
||||
public val basePermission: PermissionId
|
||||
public val parentPermission: Permission
|
||||
}
|
||||
|
||||
/**
|
||||
@ -40,8 +37,8 @@ public interface CommandOwner : PermissionIdNamespace {
|
||||
*/
|
||||
internal object ConsoleCommandOwner : CommandOwner {
|
||||
@ExperimentalPermission
|
||||
override val basePermission: PermissionId
|
||||
get() = RootPermission.id
|
||||
override val parentPermission: Permission
|
||||
get() = RootPermission
|
||||
|
||||
@ExperimentalPermission
|
||||
override fun permissionId(id: String): PermissionId = PermissionId("console", id)
|
||||
|
@ -21,7 +21,7 @@ import net.mamoe.mirai.console.command.description.*
|
||||
import net.mamoe.mirai.console.internal.command.AbstractReflectionCommand
|
||||
import net.mamoe.mirai.console.internal.command.CompositeCommandSubCommandAnnotationResolver
|
||||
import net.mamoe.mirai.console.permission.ExperimentalPermission
|
||||
import net.mamoe.mirai.console.permission.PermissionId
|
||||
import net.mamoe.mirai.console.permission.Permission
|
||||
import net.mamoe.mirai.console.util.ConsoleExperimentalAPI
|
||||
import net.mamoe.mirai.message.data.MessageChain
|
||||
import kotlin.annotation.AnnotationRetention.RUNTIME
|
||||
@ -86,7 +86,7 @@ public abstract class CompositeCommand @OptIn(ExperimentalPermission::class) con
|
||||
owner: CommandOwner,
|
||||
vararg names: String,
|
||||
description: String = "no description available",
|
||||
parentPermission: PermissionId = owner.basePermission,
|
||||
parentPermission: Permission = owner.parentPermission,
|
||||
prefixOptional: Boolean = false,
|
||||
overrideContext: CommandArgumentContext = EmptyCommandArgumentContext
|
||||
) : Command, AbstractReflectionCommand(owner, names, description, parentPermission, prefixOptional),
|
||||
@ -110,12 +110,6 @@ public abstract class CompositeCommand @OptIn(ExperimentalPermission::class) con
|
||||
@Target(FUNCTION)
|
||||
protected annotation class SubCommand(vararg val value: String)
|
||||
|
||||
/** 指定子指令要求的权限 */
|
||||
@Retention(RUNTIME)
|
||||
@Target(FUNCTION)
|
||||
@ExperimentalPermission
|
||||
protected annotation class Permission(val value: String)
|
||||
|
||||
/** 指令描述 */
|
||||
@Retention(RUNTIME)
|
||||
@Target(FUNCTION)
|
||||
|
@ -14,10 +14,9 @@ package net.mamoe.mirai.console.command
|
||||
import net.mamoe.mirai.console.command.CommandManager.INSTANCE.execute
|
||||
import net.mamoe.mirai.console.command.CommandManager.INSTANCE.executeCommand
|
||||
import net.mamoe.mirai.console.command.java.JRawCommand
|
||||
import net.mamoe.mirai.console.internal.command.createCommandPermission
|
||||
import net.mamoe.mirai.console.internal.command.createOrFindCommandPermission
|
||||
import net.mamoe.mirai.console.permission.ExperimentalPermission
|
||||
import net.mamoe.mirai.console.permission.Permission
|
||||
import net.mamoe.mirai.console.permission.PermissionId
|
||||
import net.mamoe.mirai.message.data.MessageChain
|
||||
|
||||
/**
|
||||
@ -44,12 +43,12 @@ public abstract class RawCommand @OptIn(ExperimentalPermission::class) construct
|
||||
/** 指令描述, 用于显示在 [BuiltInCommands.Help] */
|
||||
public override val description: String = "<no descriptions given>",
|
||||
/** 指令父权限 */
|
||||
parentPermission: PermissionId = owner.basePermission,
|
||||
parentPermission: Permission = owner.parentPermission,
|
||||
/** 为 `true` 时表示 [指令前缀][CommandManager.commandPrefix] 可选 */
|
||||
public override val prefixOptional: Boolean = false
|
||||
) : Command {
|
||||
@OptIn(ExperimentalPermission::class)
|
||||
public override val permission: Permission by lazy { createCommandPermission(parentPermission) }
|
||||
public override val permission: Permission by lazy { createOrFindCommandPermission(parentPermission) }
|
||||
|
||||
/**
|
||||
* 在指令被执行时调用.
|
||||
|
@ -23,7 +23,7 @@ import net.mamoe.mirai.console.command.java.JSimpleCommand
|
||||
import net.mamoe.mirai.console.internal.command.AbstractReflectionCommand
|
||||
import net.mamoe.mirai.console.internal.command.SimpleCommandSubCommandAnnotationResolver
|
||||
import net.mamoe.mirai.console.permission.ExperimentalPermission
|
||||
import net.mamoe.mirai.console.permission.PermissionId
|
||||
import net.mamoe.mirai.console.permission.Permission
|
||||
import net.mamoe.mirai.message.data.MessageChain
|
||||
|
||||
/**
|
||||
@ -53,10 +53,10 @@ public abstract class SimpleCommand @OptIn(ExperimentalPermission::class) constr
|
||||
owner: CommandOwner,
|
||||
vararg names: String,
|
||||
description: String = "no description available",
|
||||
basePermission: PermissionId = owner.basePermission,
|
||||
parentPermission: Permission = owner.parentPermission,
|
||||
prefixOptional: Boolean = false,
|
||||
overrideContext: CommandArgumentContext = EmptyCommandArgumentContext
|
||||
) : Command, AbstractReflectionCommand(owner, names, description, basePermission, prefixOptional),
|
||||
) : Command, AbstractReflectionCommand(owner, names, description, parentPermission, prefixOptional),
|
||||
CommandArgumentContextAware {
|
||||
|
||||
/**
|
||||
|
@ -81,6 +81,21 @@ public interface CommandArgumentParser<out T : Any> {
|
||||
public fun parse(raw: MessageContent, sender: CommandSender): T = parse(raw.content, sender)
|
||||
}
|
||||
|
||||
/**
|
||||
* 使用原 [this] 解析, 成功后使用 [mapper] 映射为另一个类型.
|
||||
*/
|
||||
public fun <T : Any, R : Any> CommandArgumentParser<T>.map(
|
||||
mapper: CommandArgumentParser<R>.(T) -> R
|
||||
): CommandArgumentParser<R> = MappingCommandArgumentParser(this, mapper)
|
||||
|
||||
private class MappingCommandArgumentParser<T : Any, R : Any>(
|
||||
private val original: CommandArgumentParser<T>,
|
||||
private val mapper: CommandArgumentParser<R>.(T) -> R
|
||||
) : CommandArgumentParser<R> {
|
||||
override fun parse(raw: String, sender: CommandSender): R = mapper(original.parse(raw, sender))
|
||||
override fun parse(raw: MessageContent, sender: CommandSender): R = mapper(original.parse(raw, sender))
|
||||
}
|
||||
|
||||
/**
|
||||
* 解析一个字符串或 [SingleMessage] 为 [T] 类型参数
|
||||
*
|
||||
|
@ -321,7 +321,7 @@ public object PermissionIdArgumentParser : CommandArgumentParser<PermissionId> {
|
||||
public object PermissibleIdentifierArgumentParser : CommandArgumentParser<PermissibleIdentifier> {
|
||||
override fun parse(raw: String, sender: CommandSender): PermissibleIdentifier {
|
||||
return kotlin.runCatching { AbstractPermissibleIdentifier.parseFromString(raw) }.getOrElse {
|
||||
illegalArgument("无法解析 $raw 为 PermissionId")
|
||||
illegalArgument("无法解析 $raw 为 PermissibleIdentifier")
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -15,7 +15,7 @@ import net.mamoe.mirai.console.command.CommandOwner
|
||||
import net.mamoe.mirai.console.command.CompositeCommand
|
||||
import net.mamoe.mirai.console.command.description.buildCommandArgumentContext
|
||||
import net.mamoe.mirai.console.permission.ExperimentalPermission
|
||||
import net.mamoe.mirai.console.permission.PermissionId
|
||||
import net.mamoe.mirai.console.permission.Permission
|
||||
import net.mamoe.mirai.console.util.ConsoleExperimentalAPI
|
||||
|
||||
/**
|
||||
@ -73,14 +73,14 @@ public abstract class JCompositeCommand @OptIn(ExperimentalPermission::class)
|
||||
@JvmOverloads constructor(
|
||||
owner: CommandOwner,
|
||||
vararg names: String,
|
||||
parentPermission: PermissionId = owner.basePermission,
|
||||
parentPermission: Permission = owner.parentPermission,
|
||||
) : CompositeCommand(owner, *names, parentPermission = parentPermission) {
|
||||
/** 指令描述, 用于显示在 [BuiltInCommands.Help] */
|
||||
public final override var description: String = "<no descriptions given>"
|
||||
protected set
|
||||
|
||||
@OptIn(ExperimentalPermission::class)
|
||||
public final override var permission: net.mamoe.mirai.console.permission.Permission = super.permission
|
||||
public final override var permission: Permission = super.permission
|
||||
protected set
|
||||
|
||||
/** 为 `true` 时表示 [指令前缀][CommandManager.commandPrefix] 可选 */
|
||||
|
@ -13,10 +13,9 @@ import kotlinx.coroutines.Dispatchers
|
||||
import kotlinx.coroutines.withContext
|
||||
import net.mamoe.mirai.console.command.*
|
||||
import net.mamoe.mirai.console.command.CommandManager.INSTANCE.execute
|
||||
import net.mamoe.mirai.console.internal.command.createCommandPermission
|
||||
import net.mamoe.mirai.console.internal.command.createOrFindCommandPermission
|
||||
import net.mamoe.mirai.console.permission.ExperimentalPermission
|
||||
import net.mamoe.mirai.console.permission.Permission
|
||||
import net.mamoe.mirai.console.permission.PermissionId
|
||||
import net.mamoe.mirai.message.data.MessageChain
|
||||
import net.mamoe.mirai.message.data.SingleMessage
|
||||
|
||||
@ -55,7 +54,7 @@ public abstract class JRawCommand @OptIn(ExperimentalPermission::class)
|
||||
public override val owner: CommandOwner,
|
||||
/** 指令名. 需要至少有一个元素. 所有元素都不能带有空格 */
|
||||
public override vararg val names: String,
|
||||
parentPermission: PermissionId = owner.basePermission,
|
||||
parentPermission: Permission = owner.parentPermission,
|
||||
) : Command {
|
||||
/** 用法说明, 用于发送给用户 */
|
||||
public override var usage: String = "<no usages given>"
|
||||
@ -67,7 +66,7 @@ public abstract class JRawCommand @OptIn(ExperimentalPermission::class)
|
||||
|
||||
/** 指令权限 */
|
||||
@ExperimentalPermission
|
||||
public final override var permission: Permission = createCommandPermission(parentPermission)
|
||||
public final override var permission: Permission = createOrFindCommandPermission(parentPermission)
|
||||
protected set
|
||||
|
||||
/** 为 `true` 时表示 [指令前缀][CommandManager.commandPrefix] 可选 */
|
||||
|
@ -16,7 +16,6 @@ import net.mamoe.mirai.console.command.SimpleCommand
|
||||
import net.mamoe.mirai.console.command.description.CommandArgumentContext
|
||||
import net.mamoe.mirai.console.permission.ExperimentalPermission
|
||||
import net.mamoe.mirai.console.permission.Permission
|
||||
import net.mamoe.mirai.console.permission.PermissionId
|
||||
|
||||
/**
|
||||
* Java 实现:
|
||||
@ -44,8 +43,8 @@ import net.mamoe.mirai.console.permission.PermissionId
|
||||
public abstract class JSimpleCommand @OptIn(ExperimentalPermission::class) constructor(
|
||||
owner: CommandOwner,
|
||||
vararg names: String,
|
||||
basePermission: PermissionId,
|
||||
) : SimpleCommand(owner, *names, basePermission = basePermission) {
|
||||
basePermission: Permission,
|
||||
) : SimpleCommand(owner, *names, parentPermission = basePermission) {
|
||||
public override var description: String = super.description
|
||||
protected set
|
||||
|
||||
|
@ -11,6 +11,7 @@ package net.mamoe.mirai.console.extension
|
||||
|
||||
import net.mamoe.mirai.console.extensions.PermissionServiceProvider
|
||||
import net.mamoe.mirai.console.extensions.PluginLoaderProvider
|
||||
import net.mamoe.mirai.console.extensions.SingletonExtensionSelector
|
||||
import net.mamoe.mirai.console.util.ConsoleExperimentalAPI
|
||||
|
||||
/**
|
||||
@ -28,6 +29,8 @@ public interface FunctionExtension : Extension
|
||||
/**
|
||||
* 为某单例服务注册的 [Extension].
|
||||
*
|
||||
* 若同时有多个实例可用, 将会使用 [SingletonExtensionSelector.selectSingleton] 选择
|
||||
*
|
||||
* @see PermissionServiceProvider
|
||||
*/
|
||||
@ConsoleExperimentalAPI
|
||||
|
@ -5,12 +5,14 @@ import net.mamoe.mirai.console.extension.SingletonExtension
|
||||
import net.mamoe.mirai.console.extension.SingletonExtensionPoint
|
||||
import net.mamoe.mirai.console.permission.ExperimentalPermission
|
||||
import net.mamoe.mirai.console.permission.PermissionService
|
||||
import net.mamoe.mirai.console.plugin.description.PluginKind
|
||||
import net.mamoe.mirai.console.plugin.description.PluginLoadPriority
|
||||
|
||||
/**
|
||||
* [权限服务][PermissionService] 提供器.
|
||||
*
|
||||
* 此扩展可由 [PluginKind.LOADER] 和 [PluginKind.HIGH_PRIORITY_EXTENSIONS] 插件提供
|
||||
* 当插件注册 [PermissionService] 后, 默认会使用插件的 [PermissionService].
|
||||
*
|
||||
* 此扩展可由 [PluginLoadPriority.BEFORE_EXTENSIONS] 和 [PluginLoadPriority.ON_EXTENSIONS] 插件提供
|
||||
*/
|
||||
@ExperimentalPermission
|
||||
public interface PermissionServiceProvider : SingletonExtension<PermissionService<*>> {
|
||||
|
@ -3,12 +3,12 @@ package net.mamoe.mirai.console.extensions
|
||||
import net.mamoe.mirai.console.extension.AbstractExtensionPoint
|
||||
import net.mamoe.mirai.console.extension.InstanceExtension
|
||||
import net.mamoe.mirai.console.plugin.PluginLoader
|
||||
import net.mamoe.mirai.console.plugin.description.PluginKind
|
||||
import net.mamoe.mirai.console.plugin.description.PluginLoadPriority
|
||||
|
||||
/**
|
||||
* 提供扩展 [PluginLoader]
|
||||
*
|
||||
* 此扩展可由 [PluginKind.LOADER] 插件提供
|
||||
* 此扩展可由 [PluginLoadPriority.BEFORE_EXTENSIONS] 插件提供
|
||||
*/
|
||||
public interface PluginLoaderProvider : InstanceExtension<PluginLoader<*, *>> {
|
||||
public companion object ExtensionPoint : AbstractExtensionPoint<PluginLoaderProvider>(PluginLoaderProvider::class)
|
||||
|
@ -12,7 +12,7 @@ package net.mamoe.mirai.console.extensions
|
||||
import net.mamoe.mirai.console.MiraiConsole
|
||||
import net.mamoe.mirai.console.extension.*
|
||||
import net.mamoe.mirai.console.internal.extensions.BuiltInSingletonExtensionSelector
|
||||
import net.mamoe.mirai.console.plugin.description.PluginKind
|
||||
import net.mamoe.mirai.console.plugin.description.PluginLoadPriority
|
||||
import net.mamoe.mirai.console.plugin.name
|
||||
import net.mamoe.mirai.utils.info
|
||||
import kotlin.reflect.KClass
|
||||
@ -22,7 +22,7 @@ import kotlin.reflect.KClass
|
||||
*
|
||||
* 如有多个 [SingletonExtensionSelector] 注册, 将会停止服务器.
|
||||
*
|
||||
* 此扩展可由 [PluginKind.LOADER] 和 [PluginKind.HIGH_PRIORITY_EXTENSIONS] 插件提供
|
||||
* 此扩展可由 [PluginLoadPriority.BEFORE_EXTENSIONS] 插件提供
|
||||
*/
|
||||
public interface SingletonExtensionSelector : FunctionExtension {
|
||||
|
||||
|
@ -33,7 +33,9 @@ import net.mamoe.mirai.console.extensions.SingletonExtensionSelector
|
||||
import net.mamoe.mirai.console.internal.command.CommandManagerImpl
|
||||
import net.mamoe.mirai.console.internal.data.builtins.AutoLoginConfig
|
||||
import net.mamoe.mirai.console.internal.data.builtins.ConsoleDataScope
|
||||
import net.mamoe.mirai.console.internal.extensions.BuiltInSingletonExtensionSelector
|
||||
import net.mamoe.mirai.console.internal.plugin.PluginManagerImpl
|
||||
import net.mamoe.mirai.console.internal.util.autoHexToBytes
|
||||
import net.mamoe.mirai.console.permission.BuiltInPermissionService
|
||||
import net.mamoe.mirai.console.permission.ExperimentalPermission
|
||||
import net.mamoe.mirai.console.permission.PermissionService
|
||||
@ -124,13 +126,22 @@ internal object MiraiConsoleImplementationBridge : CoroutineScope, MiraiConsoleI
|
||||
|
||||
val pluginLoadSession: PluginManagerImpl.PluginLoadSession
|
||||
|
||||
phase `load plugins`@{
|
||||
phase `load BEFORE_EXTENSIONS plugins`@{
|
||||
PluginManager // init
|
||||
|
||||
mainLogger.verbose { "Loading PluginLoader provider plugins..." }
|
||||
PluginManagerImpl.loadEnablePluginProviderPlugins()
|
||||
mainLogger.verbose { "${PluginManager.plugins.size} such plugin(s) loaded." }
|
||||
}
|
||||
|
||||
phase `load SingletonExtensionSelector`@{
|
||||
val instance = SingletonExtensionSelector.instance
|
||||
if (instance is BuiltInSingletonExtensionSelector) {
|
||||
ConsoleDataScope.addAndReloadConfig(instance.config)
|
||||
}
|
||||
}
|
||||
|
||||
phase `load ON_EXTENSIONS plugins`@{
|
||||
mainLogger.verbose { "Scanning high-priority extension and normal plugins..." }
|
||||
pluginLoadSession = PluginManagerImpl.scanPluginsUsingPluginLoadersIncludingThoseFromPluginLoaderProvider()
|
||||
mainLogger.verbose { "${pluginLoadSession.allKindsOfPlugins.size} plugin(s) found." }
|
||||
@ -140,8 +151,6 @@ internal object MiraiConsoleImplementationBridge : CoroutineScope, MiraiConsoleI
|
||||
mainLogger.verbose { "${PluginManager.plugins.size} such plugin(s) loaded." }
|
||||
}
|
||||
|
||||
SingletonExtensionSelector.instance // init
|
||||
|
||||
phase `load PermissionService`@{
|
||||
mainLogger.verbose { "Loading PermissionService..." }
|
||||
PermissionService.INSTANCE.let { ps ->
|
||||
@ -162,7 +171,7 @@ internal object MiraiConsoleImplementationBridge : CoroutineScope, MiraiConsoleI
|
||||
CommandManagerImpl.commandListener // start
|
||||
}
|
||||
|
||||
phase `load normal plugins`@{
|
||||
phase `load AFTER_EXTENSION plugins`@{
|
||||
mainLogger.verbose { "Loading normal plugins..." }
|
||||
val count = PluginManagerImpl.loadEnableNormalPlugins(pluginLoadSession)
|
||||
mainLogger.verbose { "$count normal plugin(s) loaded." }
|
||||
@ -172,14 +181,19 @@ internal object MiraiConsoleImplementationBridge : CoroutineScope, MiraiConsoleI
|
||||
|
||||
phase `auto-login bots`@{
|
||||
runBlocking {
|
||||
for ((id, password) in AutoLoginConfig.plainPasswords) {
|
||||
for ((id, password) in AutoLoginConfig.plainPasswords.filterNot { it.key == 123456654321L }) {
|
||||
mainLogger.info { "Auto-login $id" }
|
||||
MiraiConsole.addBot(id, password).alsoLogin()
|
||||
}
|
||||
|
||||
for ((id, password) in AutoLoginConfig.md5Passwords) {
|
||||
for ((id, password) in AutoLoginConfig.md5Passwords.filterNot { it.key == 123456654321L }) {
|
||||
mainLogger.info { "Auto-login $id" }
|
||||
MiraiConsole.addBot(id, password).alsoLogin()
|
||||
val x = runCatching {
|
||||
password.autoHexToBytes()
|
||||
}.getOrElse {
|
||||
error("Bad auto-login md5: '$password'")
|
||||
}
|
||||
MiraiConsole.addBot(id, x).alsoLogin()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -18,8 +18,6 @@ import net.mamoe.mirai.console.command.description.CommandArgumentContextAware
|
||||
import net.mamoe.mirai.console.internal.data.kClassQualifiedNameOrTip
|
||||
import net.mamoe.mirai.console.permission.ExperimentalPermission
|
||||
import net.mamoe.mirai.console.permission.Permission
|
||||
import net.mamoe.mirai.console.permission.PermissionId
|
||||
import net.mamoe.mirai.console.permission.PermissionService
|
||||
import net.mamoe.mirai.console.permission.PermissionService.Companion.testPermission
|
||||
import net.mamoe.mirai.message.data.*
|
||||
import kotlin.reflect.KAnnotatedElement
|
||||
@ -53,7 +51,7 @@ internal abstract class AbstractReflectionCommand @OptIn(ExperimentalPermission:
|
||||
owner: CommandOwner,
|
||||
names: Array<out String>,
|
||||
description: String = "<no description available>",
|
||||
parentPermission: PermissionId = owner.basePermission,
|
||||
parentPermission: Permission = owner.parentPermission,
|
||||
prefixOptional: Boolean = false
|
||||
) : Command, AbstractCommand(
|
||||
owner,
|
||||
@ -79,7 +77,7 @@ internal abstract class AbstractReflectionCommand @OptIn(ExperimentalPermission:
|
||||
internal val defaultSubCommand: DefaultSubCommandDescriptor by lazy {
|
||||
DefaultSubCommandDescriptor(
|
||||
"",
|
||||
createCommandPermission(parentPermission),
|
||||
createOrFindCommandPermission(parentPermission),
|
||||
onCommand = { sender: CommandSender, args: MessageChain ->
|
||||
sender.onDefault(args)
|
||||
}
|
||||
@ -144,7 +142,7 @@ internal abstract class AbstractReflectionCommand @OptIn(ExperimentalPermission:
|
||||
argsWithSubCommandNameNotRemoved: MessageChain,
|
||||
removeSubName: Boolean
|
||||
) {
|
||||
val args = parseArgs(sender, argsWithSubCommandNameNotRemoved, if (removeSubName) names.size else 0)
|
||||
val args = parseArgs(sender, argsWithSubCommandNameNotRemoved, if (removeSubName) 1 else 0)
|
||||
if (!this.permission.testPermission(sender)) {
|
||||
sender.sendMessage(usage) // TODO: 2020/8/26 #127
|
||||
return
|
||||
@ -259,7 +257,7 @@ internal fun AbstractReflectionCommand.createSubCommand(
|
||||
context: CommandArgumentContext
|
||||
): AbstractReflectionCommand.SubCommandDescriptor {
|
||||
val notStatic = !function.hasAnnotation<JvmStatic>()
|
||||
val overridePermission = function.findAnnotation<CompositeCommand.Permission>()//optional
|
||||
//val overridePermission = null//function.findAnnotation<CompositeCommand.PermissionId>()//optional
|
||||
val subDescription =
|
||||
function.findAnnotation<CompositeCommand.Description>()?.value ?: ""
|
||||
|
||||
@ -331,7 +329,7 @@ internal fun AbstractReflectionCommand.createSubCommand(
|
||||
commandName,
|
||||
params,
|
||||
subDescription, // overridePermission?.value
|
||||
overridePermission?.value?.let { PermissionService.INSTANCE[PermissionId.parseFromString(it)] } ?: permission,
|
||||
permission,//overridePermission?.value?.let { PermissionService.INSTANCE[PermissionId.parseFromString(it)] } ?: permission,
|
||||
onCommand = { sender: CommandSender, args: Array<out Any> ->
|
||||
val result = if (notStatic) {
|
||||
if (hasSenderParam) {
|
||||
|
@ -13,7 +13,6 @@ import net.mamoe.mirai.console.command.*
|
||||
import net.mamoe.mirai.console.command.Command.Companion.primaryName
|
||||
import net.mamoe.mirai.console.permission.ExperimentalPermission
|
||||
import net.mamoe.mirai.console.permission.Permission
|
||||
import net.mamoe.mirai.console.permission.PermissionId
|
||||
import net.mamoe.mirai.console.permission.PermissionService
|
||||
import net.mamoe.mirai.console.permission.PermissionService.Companion.testPermission
|
||||
import net.mamoe.mirai.contact.Group
|
||||
@ -143,8 +142,9 @@ internal fun Group.fuzzySearchMember(
|
||||
}
|
||||
|
||||
@OptIn(ExperimentalPermission::class)
|
||||
internal fun Command.createCommandPermission(parent: PermissionId): Permission {
|
||||
return PermissionService.INSTANCE.register(owner.permissionId(primaryName), description, parent)
|
||||
internal fun Command.createOrFindCommandPermission(parent: Permission): Permission {
|
||||
val id = owner.permissionId(primaryName)
|
||||
return PermissionService.INSTANCE[id] ?: PermissionService.INSTANCE.register(id, description, parent)
|
||||
}
|
||||
|
||||
//// internal
|
||||
|
@ -3,6 +3,8 @@ package net.mamoe.mirai.console.internal.data.builtins
|
||||
import net.mamoe.mirai.console.data.AutoSavePluginConfig
|
||||
import net.mamoe.mirai.console.data.ValueDescription
|
||||
import net.mamoe.mirai.console.data.value
|
||||
import net.mamoe.mirai.console.internal.util.md5
|
||||
import net.mamoe.mirai.console.internal.util.toUHexString
|
||||
|
||||
internal object AutoLoginConfig : AutoSavePluginConfig() {
|
||||
override val saveName: String
|
||||
@ -13,7 +15,7 @@ internal object AutoLoginConfig : AutoSavePluginConfig() {
|
||||
账号和明文密码列表
|
||||
"""
|
||||
)
|
||||
val plainPasswords: MutableMap<Long, String> by value(mutableMapOf())
|
||||
val plainPasswords: MutableMap<Long, String> by value(mutableMapOf(123456654321L to "example"))
|
||||
|
||||
|
||||
@ValueDescription(
|
||||
@ -21,5 +23,9 @@ internal object AutoLoginConfig : AutoSavePluginConfig() {
|
||||
账号和 MD5 密码列表
|
||||
"""
|
||||
)
|
||||
val md5Passwords: MutableMap<Long, String> by value(mutableMapOf())
|
||||
val md5Passwords: MutableMap<Long, String> by value(
|
||||
mutableMapOf(
|
||||
123456654321L to "example".toByteArray().md5().toUHexString()
|
||||
)
|
||||
)
|
||||
}
|
@ -2,7 +2,7 @@ package net.mamoe.mirai.console.internal.extensions
|
||||
|
||||
import kotlinx.coroutines.runBlocking
|
||||
import net.mamoe.mirai.console.MiraiConsole
|
||||
import net.mamoe.mirai.console.data.AutoSavePluginData
|
||||
import net.mamoe.mirai.console.data.AutoSavePluginConfig
|
||||
import net.mamoe.mirai.console.data.value
|
||||
import net.mamoe.mirai.console.extension.Extension
|
||||
import net.mamoe.mirai.console.extension.ExtensionRegistry
|
||||
@ -15,9 +15,9 @@ import kotlin.reflect.KClass
|
||||
|
||||
internal object BuiltInSingletonExtensionSelector : SingletonExtensionSelector {
|
||||
|
||||
private val config: SaveData = SaveData()
|
||||
internal val config: SaveData = SaveData()
|
||||
|
||||
private class SaveData : AutoSavePluginData() {
|
||||
internal class SaveData : AutoSavePluginConfig() {
|
||||
override val saveName: String get() = "ExtensionSelector"
|
||||
|
||||
val value: MutableMap<String, String> by value()
|
||||
|
@ -16,6 +16,7 @@ import net.mamoe.mirai.console.MiraiConsole
|
||||
import net.mamoe.mirai.console.data.runCatchingLog
|
||||
import net.mamoe.mirai.console.internal.data.mkdir
|
||||
import net.mamoe.mirai.console.permission.ExperimentalPermission
|
||||
import net.mamoe.mirai.console.permission.Permission
|
||||
import net.mamoe.mirai.console.permission.PermissionId
|
||||
import net.mamoe.mirai.console.permission.PermissionService
|
||||
import net.mamoe.mirai.console.permission.PermissionService.Companion.allocatePermissionIdForPlugin
|
||||
@ -44,11 +45,11 @@ internal abstract class JvmPluginInternal(
|
||||
) : JvmPlugin, CoroutineScope {
|
||||
|
||||
@OptIn(ExperimentalPermission::class)
|
||||
final override val basePermission: PermissionId by lazy {
|
||||
final override val parentPermission: Permission by lazy {
|
||||
PermissionService.INSTANCE.register(
|
||||
PermissionService.INSTANCE.allocatePermissionIdForPlugin(name, "*"),
|
||||
"The base permission"
|
||||
).id
|
||||
)
|
||||
}
|
||||
|
||||
final override var isEnabled: Boolean = false
|
||||
@ -110,7 +111,7 @@ internal abstract class JvmPluginInternal(
|
||||
}
|
||||
|
||||
internal fun internalOnEnable(): Boolean {
|
||||
basePermission
|
||||
parentPermission
|
||||
if (!firstRun) refreshCoroutineContext()
|
||||
kotlin.runCatching {
|
||||
onEnable()
|
||||
|
@ -22,7 +22,7 @@ import net.mamoe.mirai.console.internal.data.mkdir
|
||||
import net.mamoe.mirai.console.plugin.*
|
||||
import net.mamoe.mirai.console.plugin.description.PluginDependency
|
||||
import net.mamoe.mirai.console.plugin.description.PluginDescription
|
||||
import net.mamoe.mirai.console.plugin.description.PluginKind
|
||||
import net.mamoe.mirai.console.plugin.description.PluginLoadPriority
|
||||
import net.mamoe.mirai.console.plugin.jvm.JvmPlugin
|
||||
import net.mamoe.mirai.console.util.CoroutineScopeUtils.childScope
|
||||
import net.mamoe.mirai.utils.info
|
||||
@ -131,7 +131,7 @@ internal object PluginManagerImpl : PluginManager, CoroutineScope by MiraiConsol
|
||||
internal fun loadEnableHighPriorityExtensionPlugins(session: PluginLoadSession): Int {
|
||||
loadersLock.withLock {
|
||||
session.allKindsOfPlugins.flatMap { it.second }
|
||||
.filter { it.kind == PluginKind.HIGH_PRIORITY_EXTENSIONS }
|
||||
.filter { it.loadPriority == PluginLoadPriority.ON_EXTENSIONS }
|
||||
.sortByDependencies()
|
||||
.also { it.loadAndEnableAllInOrder() }
|
||||
.let { return it.size }
|
||||
@ -142,7 +142,7 @@ internal object PluginManagerImpl : PluginManager, CoroutineScope by MiraiConsol
|
||||
internal fun loadEnableNormalPlugins(session: PluginLoadSession): Int {
|
||||
loadersLock.withLock {
|
||||
session.allKindsOfPlugins.flatMap { it.second }
|
||||
.filter { it.kind == PluginKind.NORMAL }
|
||||
.filter { it.loadPriority == PluginLoadPriority.AFTER_EXTENSIONS }
|
||||
.sortByDependencies()
|
||||
.also { it.loadAndEnableAllInOrder() }
|
||||
.let { return it.size }
|
||||
@ -191,7 +191,8 @@ internal object PluginManagerImpl : PluginManager, CoroutineScope by MiraiConsol
|
||||
loader as PluginLoader<Plugin, PluginDescription>
|
||||
|
||||
descriptions.forEach(PluginManagerImpl::checkPluginDescription)
|
||||
descriptions.filter { it.kind == PluginKind.LOADER }.sortByDependencies().loadAndEnableAllInOrder()
|
||||
descriptions.filter { it.loadPriority == PluginLoadPriority.BEFORE_EXTENSIONS }.sortByDependencies()
|
||||
.loadAndEnableAllInOrder()
|
||||
}
|
||||
.flatMap { it.second.asSequence() }
|
||||
|
||||
|
@ -0,0 +1,54 @@
|
||||
/*
|
||||
* Copyright 2020 Mamoe Technologies and contributors.
|
||||
*
|
||||
* 此源代码的使用受 GNU AFFERO GENERAL PUBLIC LICENSE version 3 许可证的约束, 可以在以下链接找到该许可证.
|
||||
* Use of this source code is governed by the GNU AGPLv3 license that can be found through the following link.
|
||||
*
|
||||
* https://github.com/mamoe/mirai/blob/master/LICENSE
|
||||
*/
|
||||
|
||||
package net.mamoe.mirai.console.internal.util
|
||||
|
||||
import java.security.MessageDigest
|
||||
|
||||
|
||||
@Suppress("DuplicatedCode") // false positive. `this` is not the same for `List<Byte>` and `ByteArray`
|
||||
internal fun ByteArray.checkOffsetAndLength(offset: Int, length: Int) {
|
||||
require(offset >= 0) { "offset shouldn't be negative: $offset" }
|
||||
require(length >= 0) { "length shouldn't be negative: $length" }
|
||||
require(offset + length <= this.size) { "offset ($offset) + length ($length) > array.size (${this.size})" }
|
||||
}
|
||||
|
||||
internal fun String.autoHexToBytes(): ByteArray =
|
||||
this.trim(Char::isWhitespace).asSequence().chunked(2).map {
|
||||
(it[0].toString() + it[1]).toUByte(16).toByte()
|
||||
}.toList().toByteArray()
|
||||
|
||||
internal fun ByteArray.md5(offset: Int = 0, length: Int = this.size - offset): ByteArray {
|
||||
this.checkOffsetAndLength(offset, length)
|
||||
return MessageDigest.getInstance("MD5").apply { update(this@md5, offset, length) }.digest()
|
||||
}
|
||||
|
||||
@JvmOverloads
|
||||
@Suppress("DuplicatedCode") // false positive. foreach is not common to UByteArray and ByteArray
|
||||
internal fun ByteArray.toUHexString(
|
||||
separator: String = " ",
|
||||
offset: Int = 0,
|
||||
length: Int = this.size - offset
|
||||
): String {
|
||||
this.checkOffsetAndLength(offset, length)
|
||||
if (length == 0) {
|
||||
return ""
|
||||
}
|
||||
val lastIndex = offset + length
|
||||
return buildString(length * 2) {
|
||||
this@toUHexString.forEachIndexed { index, it ->
|
||||
if (index in offset until lastIndex) {
|
||||
var ret = it.toUByte().toString(16).toUpperCase()
|
||||
if (ret.length == 1) ret = "0$ret"
|
||||
append(ret)
|
||||
if (index < lastIndex - 1) append(separator)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
@ -9,28 +9,27 @@
|
||||
|
||||
package net.mamoe.mirai.console.permission
|
||||
|
||||
import net.mamoe.mirai.console.data.PluginDataExtensions
|
||||
import net.mamoe.mirai.console.permission.PermissibleIdentifier.Companion.grantedWith
|
||||
import java.util.concurrent.CopyOnWriteArrayList
|
||||
|
||||
/**
|
||||
*
|
||||
*/
|
||||
@ExperimentalPermission
|
||||
public abstract class AbstractConcurrentPermissionService<P : Permission> : PermissionService<P> {
|
||||
internal abstract class AbstractConcurrentPermissionService<P : Permission> : PermissionService<P> {
|
||||
protected abstract val permissions: MutableMap<PermissionId, P>
|
||||
protected abstract val grantedPermissionsMap: MutableMap<PermissionId, MutableCollection<PermissibleIdentifier>>
|
||||
protected abstract val grantedPermissionsMap: PluginDataExtensions.NotNullMutableMap<PermissionId, MutableCollection<PermissibleIdentifier>>
|
||||
|
||||
protected abstract fun createPermission(
|
||||
id: PermissionId,
|
||||
description: String,
|
||||
base: PermissionId = RootPermission.id
|
||||
parent: Permission
|
||||
): P
|
||||
|
||||
override fun get(id: PermissionId): P? = permissions[id]
|
||||
|
||||
override fun register(id: PermissionId, description: String, base: PermissionId): P {
|
||||
grantedPermissionsMap[id] = CopyOnWriteArrayList() // mutations are not quite often performed
|
||||
val instance = createPermission(id, description, base)
|
||||
override fun register(id: PermissionId, description: String, parent: Permission): P {
|
||||
val instance = createPermission(id, description, parent)
|
||||
val old = permissions.putIfAbsent(id, instance)
|
||||
if (old != null) throw DuplicatedPermissionRegistrationException(instance, old)
|
||||
return instance
|
||||
@ -38,16 +37,15 @@ public abstract class AbstractConcurrentPermissionService<P : Permission> : Perm
|
||||
|
||||
override fun grant(permissibleIdentifier: PermissibleIdentifier, permission: P) {
|
||||
val id = permission.id
|
||||
grantedPermissionsMap[id]?.add(permissibleIdentifier)
|
||||
?: error("Bad PermissionService implementation: grantedPermissionsMap[id] is null.")
|
||||
grantedPermissionsMap[id].add(permissibleIdentifier)
|
||||
}
|
||||
|
||||
override fun deny(permissibleIdentifier: PermissibleIdentifier, permission: P) {
|
||||
grantedPermissionsMap[permission.id]?.remove(permissibleIdentifier)
|
||||
grantedPermissionsMap[permission.id].remove(permissibleIdentifier)
|
||||
}
|
||||
|
||||
override fun getRegisteredPermissions(): Sequence<P> = permissions.values.asSequence()
|
||||
public override fun getGrantedPermissions(permissibleIdentifier: PermissibleIdentifier): Sequence<P> = sequence<P> {
|
||||
override fun getGrantedPermissions(permissibleIdentifier: PermissibleIdentifier): Sequence<P> = sequence<P> {
|
||||
for ((permissionIdentifier, permissibleIdentifiers) in grantedPermissionsMap) {
|
||||
|
||||
val granted =
|
||||
|
@ -9,28 +9,28 @@
|
||||
|
||||
package net.mamoe.mirai.console.permission
|
||||
|
||||
import kotlinx.serialization.Serializable
|
||||
import net.mamoe.mirai.console.data.AutoSavePluginConfig
|
||||
import net.mamoe.mirai.console.data.PluginDataExtensions
|
||||
import net.mamoe.mirai.console.data.PluginDataExtensions.withDefault
|
||||
import net.mamoe.mirai.console.data.value
|
||||
import java.util.concurrent.ConcurrentHashMap
|
||||
import java.util.concurrent.CopyOnWriteArrayList
|
||||
import java.util.concurrent.CopyOnWriteArraySet
|
||||
import kotlin.reflect.KClass
|
||||
import kotlin.reflect.KType
|
||||
import kotlin.reflect.full.createType
|
||||
|
||||
|
||||
@ExperimentalPermission
|
||||
public object AllGrantPermissionService : PermissionService<PermissionImpl> {
|
||||
internal object AllGrantPermissionService : PermissionService<PermissionImpl> {
|
||||
private val all = ConcurrentHashMap<PermissionId, PermissionImpl>()
|
||||
override val permissionType: KClass<PermissionImpl>
|
||||
get() = PermissionImpl::class
|
||||
override val permissionType: KClass<PermissionImpl> get() = PermissionImpl::class
|
||||
override val rootPermission: PermissionImpl get() = RootPermissionImpl.also { all[it.id] = it }
|
||||
|
||||
override fun register(
|
||||
id: PermissionId,
|
||||
description: String,
|
||||
base: PermissionId
|
||||
parent: Permission
|
||||
): PermissionImpl {
|
||||
val new = PermissionImpl(id, description, base)
|
||||
val new = PermissionImpl(id, description, parent)
|
||||
val old = all.putIfAbsent(id, new)
|
||||
if (old != null) throw DuplicatedPermissionRegistrationException(new, old)
|
||||
return new
|
||||
@ -51,18 +51,23 @@ public object AllGrantPermissionService : PermissionService<PermissionImpl> {
|
||||
}
|
||||
}
|
||||
|
||||
@Suppress("DEPRECATION")
|
||||
@OptIn(ExperimentalPermission::class)
|
||||
private val RootPermissionImpl = PermissionImpl(PermissionId("*", "*"), "The root permission").also { it.parent = it }
|
||||
|
||||
@ExperimentalPermission
|
||||
public object AllDenyPermissionService : PermissionService<PermissionImpl> {
|
||||
internal object AllDenyPermissionService : PermissionService<PermissionImpl> {
|
||||
private val all = ConcurrentHashMap<PermissionId, PermissionImpl>()
|
||||
override val permissionType: KClass<PermissionImpl>
|
||||
get() = PermissionImpl::class
|
||||
override val rootPermission: PermissionImpl = RootPermissionImpl.also { all[it.id] = it }
|
||||
|
||||
override fun register(
|
||||
id: PermissionId,
|
||||
description: String,
|
||||
base: PermissionId
|
||||
parent: Permission
|
||||
): PermissionImpl {
|
||||
val new = PermissionImpl(id, description, base)
|
||||
val new = PermissionImpl(id, description, parent)
|
||||
val old = all.putIfAbsent(id, new)
|
||||
if (old != null) throw DuplicatedPermissionRegistrationException(new, old)
|
||||
return new
|
||||
@ -90,41 +95,75 @@ internal object BuiltInPermissionService : AbstractConcurrentPermissionService<P
|
||||
@ExperimentalPermission
|
||||
override val permissionType: KClass<PermissionImpl>
|
||||
get() = PermissionImpl::class
|
||||
override val permissions: MutableMap<PermissionId, PermissionImpl> = ConcurrentHashMap()
|
||||
override val permissions: ConcurrentHashMap<PermissionId, PermissionImpl> = ConcurrentHashMap()
|
||||
override val rootPermission: PermissionImpl = RootPermissionImpl.also { permissions[it.id] = it }
|
||||
|
||||
@Suppress("UNCHECKED_CAST")
|
||||
override val grantedPermissionsMap: MutableMap<PermissionId, MutableCollection<PermissibleIdentifier>>
|
||||
get() = config.grantedPermissionMap as MutableMap<PermissionId, MutableCollection<PermissibleIdentifier>>
|
||||
override val grantedPermissionsMap: PluginDataExtensions.NotNullMutableMap<PermissionId, MutableCollection<PermissibleIdentifier>>
|
||||
get() = config.grantedPermissionMap as PluginDataExtensions.NotNullMutableMap<PermissionId, MutableCollection<PermissibleIdentifier>>
|
||||
|
||||
override fun createPermission(id: PermissionId, description: String, base: PermissionId): PermissionImpl =
|
||||
PermissionImpl(id, description, base)
|
||||
override fun createPermission(id: PermissionId, description: String, parent: Permission): PermissionImpl =
|
||||
PermissionImpl(id, description, parent)
|
||||
|
||||
internal val config: ConcurrentSaveData<PermissionImpl> =
|
||||
ConcurrentSaveData(
|
||||
PermissionImpl::class.createType(),
|
||||
"PermissionService",
|
||||
|
||||
)
|
||||
internal val config: ConcurrentSaveData =
|
||||
ConcurrentSaveData("PermissionService")
|
||||
|
||||
@Suppress("RedundantVisibilityModifier")
|
||||
@ExperimentalPermission
|
||||
internal class ConcurrentSaveData<P : Permission> private constructor(
|
||||
permissionType: KType,
|
||||
internal class ConcurrentSaveData private constructor(
|
||||
public override val saveName: String,
|
||||
// delegate: PluginConfig,
|
||||
@Suppress("UNUSED_PARAMETER") primaryConstructorMark: Any?
|
||||
) : AutoSavePluginConfig() {
|
||||
public val grantedPermissionMap: MutableMap<PermissionId, MutableList<AbstractPermissibleIdentifier>>
|
||||
by value<MutableMap<PermissionId, MutableList<AbstractPermissibleIdentifier>>>(ConcurrentHashMap())
|
||||
.withDefault { CopyOnWriteArrayList() }
|
||||
public val grantedPermissionMap: PluginDataExtensions.NotNullMutableMap<PermissionId, MutableSet<AbstractPermissibleIdentifier>>
|
||||
by value<MutableMap<PermissionId, MutableSet<AbstractPermissibleIdentifier>>>(ConcurrentHashMap())
|
||||
.withDefault { CopyOnWriteArraySet() }
|
||||
|
||||
public companion object {
|
||||
@JvmStatic
|
||||
public operator fun <P : Permission> invoke(
|
||||
permissionType: KType,
|
||||
public operator fun invoke(
|
||||
saveName: String,
|
||||
// delegate: PluginConfig,
|
||||
): ConcurrentSaveData<P> = ConcurrentSaveData(permissionType, saveName, null)
|
||||
): ConcurrentSaveData = ConcurrentSaveData(saveName, null)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* [Permission] 的简单实现
|
||||
*/
|
||||
@Serializable
|
||||
@ExperimentalPermission
|
||||
internal data class PermissionImpl @Deprecated("Only for Root") constructor(
|
||||
override val id: PermissionId,
|
||||
override val description: String,
|
||||
) : Permission {
|
||||
override lateinit var parent: Permission
|
||||
|
||||
@Suppress("DEPRECATION")
|
||||
constructor(id: PermissionId, description: String, parent: Permission) : this(id, description) {
|
||||
this.parent = parent
|
||||
}
|
||||
|
||||
override fun equals(other: Any?): Boolean {
|
||||
if (this === other) return true
|
||||
if (javaClass != other?.javaClass) return false
|
||||
|
||||
other as PermissionImpl
|
||||
|
||||
if (id != other.id) return false
|
||||
if (description != other.description) return false
|
||||
if (parent !== other.parent) return false
|
||||
|
||||
return true
|
||||
}
|
||||
|
||||
override fun hashCode(): Int {
|
||||
var result = id.hashCode()
|
||||
result = 31 * result + description.hashCode()
|
||||
result = 31 * result + if (parent == this) 1 else parent.hashCode()
|
||||
return result
|
||||
}
|
||||
|
||||
override fun toString(): String =
|
||||
"PermissionImpl(id=$id, description='$description', parent=${if (parent === this) "<self>" else parent.toString()})"
|
||||
}
|
@ -46,36 +46,67 @@ public sealed class AbstractPermissibleIdentifier(
|
||||
public companion object {
|
||||
@JvmStatic
|
||||
public fun parseFromString(string: String): AbstractPermissibleIdentifier {
|
||||
val str = string.trim()
|
||||
objects.find { it.toString() == str }?.let { return it as AbstractPermissibleIdentifier }
|
||||
for ((regex, block) in regexes) {
|
||||
val result = regex.find(str) ?: continue
|
||||
if (result.range.last != str.lastIndex) continue
|
||||
if (result.range.first != 0) continue
|
||||
return result.destructured.run(block)
|
||||
val str = string.trim { it.isWhitespace() }.toLowerCase()
|
||||
if (str == "console") return Console
|
||||
if (str.isNotEmpty()) {
|
||||
when (str[0]) {
|
||||
'g' -> {
|
||||
val arg = str.substring(1)
|
||||
if (arg == "*") return AnyGroup
|
||||
else arg.toLongOrNull()?.let(::ExactGroup)?.let { return it }
|
||||
}
|
||||
'f' -> {
|
||||
val arg = str.substring(1)
|
||||
if (arg == "*") return AnyFriend
|
||||
else arg.toLongOrNull()?.let(::ExactFriend)?.let { return it }
|
||||
}
|
||||
'u' -> {
|
||||
val arg = str.substring(1)
|
||||
if (arg == "*") return AnyUser
|
||||
else arg.toLongOrNull()?.let(::ExactUser)?.let { return it }
|
||||
}
|
||||
'c' -> {
|
||||
val arg = str.substring(1)
|
||||
if (arg == "*") return AnyContact
|
||||
}
|
||||
'm' -> kotlin.run {
|
||||
val arg = str.substring(1)
|
||||
if (arg == "*") return AnyMemberFromAnyGroup
|
||||
else {
|
||||
val components = arg.split('.')
|
||||
|
||||
if (components.size == 2) {
|
||||
val groupId = components[0].toLongOrNull() ?: return@run
|
||||
|
||||
if (components[1] == "*") return AnyMember(groupId)
|
||||
else {
|
||||
val memberId = components[1].toLongOrNull() ?: return@run
|
||||
return ExactMember(groupId, memberId)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
't' -> kotlin.run {
|
||||
val arg = str.substring(1)
|
||||
if (arg == "*") return AnyTempFromAnyGroup
|
||||
else {
|
||||
val components = arg.split('.')
|
||||
|
||||
if (components.size == 2) {
|
||||
val groupId = components[0].toLongOrNull() ?: return@run
|
||||
|
||||
if (components[1] == "*") return AnyTemp(groupId)
|
||||
else {
|
||||
val memberId = components[1].toLongOrNull() ?: return@run
|
||||
return ExactTemp(groupId, memberId)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
error("Cannot deserialize '$str' as AbstractPermissibleIdentifier")
|
||||
}
|
||||
|
||||
internal val objects by lazy {
|
||||
// https://youtrack.jetbrains.com/issue/KT-41782
|
||||
AbstractPermissibleIdentifier::class.nestedClasses.mapNotNull { it.objectInstance }
|
||||
}
|
||||
|
||||
internal val regexes: List<Pair<Regex, (matchGroup: MatchResult.Destructured) -> AbstractPermissibleIdentifier>> =
|
||||
listOf(
|
||||
Regex("""ExactGroup\(\s*([0-9]+)\s*\)""") to { (id) -> ExactGroup(id.toLong()) },
|
||||
Regex("""ExactFriend\(\s*([0-9]+)\s*\)""") to { (id) -> ExactFriend(id.toLong()) },
|
||||
Regex("""ExactUser\(\s*([0-9]+)\s*\)""") to { (id) -> ExactUser(id.toLong()) },
|
||||
Regex("""AnyMember\(\s*([0-9]+)\s*\)""") to { (id) -> AnyMember(id.toLong()) },
|
||||
Regex("""ExactMember\(\s*([0-9]+)\s*([0-9]+)\s*\)""") to { (a, b) ->
|
||||
ExactMember(
|
||||
a.toLong(),
|
||||
b.toLong()
|
||||
)
|
||||
},
|
||||
Regex("""ExactTemp\(\s*([0-9]+)\s*([0-9]+)\s*\)""") to { (a, b) -> ExactTemp(a.toLong(), b.toLong()) },
|
||||
)
|
||||
}
|
||||
|
||||
@ConsoleExperimentalAPI
|
||||
@ -86,54 +117,70 @@ public sealed class AbstractPermissibleIdentifier(
|
||||
)
|
||||
|
||||
public object AnyGroup : AbstractPermissibleIdentifier(AnyContact) {
|
||||
override fun toString(): String = "AnyGroup"
|
||||
override fun toString(): String = "g*"
|
||||
}
|
||||
|
||||
public data class ExactGroup(public val groupId: Long) : AbstractPermissibleIdentifier(AnyGroup)
|
||||
public data class ExactGroup(public val groupId: Long) : AbstractPermissibleIdentifier(AnyGroup) {
|
||||
override fun toString(): String = "g$groupId"
|
||||
}
|
||||
|
||||
public data class AnyMember(public val groupId: Long) : AbstractPermissibleIdentifier(AnyMemberFromAnyGroup)
|
||||
public data class AnyMember(public val groupId: Long) : AbstractPermissibleIdentifier(AnyMemberFromAnyGroup) {
|
||||
override fun toString(): String = "m$groupId.*"
|
||||
}
|
||||
|
||||
public object AnyMemberFromAnyGroup : AbstractPermissibleIdentifier(AnyUser) {
|
||||
override fun toString(): String = "AnyMemberFromAnyGroup"
|
||||
override fun toString(): String = "m*"
|
||||
}
|
||||
|
||||
public object AnyTempFromAnyGroup : AbstractPermissibleIdentifier(AnyUser) {
|
||||
override fun toString(): String = "t*"
|
||||
}
|
||||
|
||||
public data class ExactMember(
|
||||
public val groupId: Long,
|
||||
public val memberId: Long
|
||||
) : AbstractPermissibleIdentifier(AnyMember(groupId), ExactUser(memberId))
|
||||
) : AbstractPermissibleIdentifier(AnyMember(groupId), ExactUser(memberId)) {
|
||||
override fun toString(): String = "m$groupId.$memberId"
|
||||
}
|
||||
|
||||
public object AnyFriend : AbstractPermissibleIdentifier(AnyUser) {
|
||||
override fun toString(): String = "AnyFriend"
|
||||
override fun toString(): String = "f*"
|
||||
}
|
||||
|
||||
public data class ExactFriend(
|
||||
public val id: Long
|
||||
) : AbstractPermissibleIdentifier(ExactUser(id)) {
|
||||
override fun toString(): String = "ExactFriend"
|
||||
override fun toString(): String = "f$id"
|
||||
}
|
||||
|
||||
public object AnyTemp : AbstractPermissibleIdentifier(AnyUser) {
|
||||
override fun toString(): String = "AnyTemp"
|
||||
public data class AnyTemp(
|
||||
public val groupId: Long,
|
||||
) : AbstractPermissibleIdentifier(AnyUser, AnyMember(groupId)) {
|
||||
override fun toString(): String = "t$groupId.*"
|
||||
}
|
||||
|
||||
public data class ExactTemp(
|
||||
public val groupId: Long,
|
||||
public val id: Long
|
||||
) : AbstractPermissibleIdentifier(ExactUser(groupId)) // TODO: 2020/9/8 ExactMember ?
|
||||
public val memberId: Long
|
||||
) : AbstractPermissibleIdentifier(ExactUser(groupId), ExactMember(groupId, memberId)) {
|
||||
override fun toString(): String = "t$groupId.$memberId"
|
||||
}
|
||||
|
||||
public object AnyUser : AbstractPermissibleIdentifier(AnyContact) {
|
||||
override fun toString(): String = "AnyUser"
|
||||
override fun toString(): String = "u*"
|
||||
}
|
||||
|
||||
public data class ExactUser(
|
||||
public val id: Long
|
||||
) : AbstractPermissibleIdentifier(AnyUser)
|
||||
) : AbstractPermissibleIdentifier(AnyUser) {
|
||||
override fun toString(): String = "u$id"
|
||||
}
|
||||
|
||||
public object AnyContact : AbstractPermissibleIdentifier() {
|
||||
override fun toString(): String = "AnyContact"
|
||||
override fun toString(): String = "*"
|
||||
}
|
||||
|
||||
public object Console : AbstractPermissibleIdentifier() {
|
||||
override fun toString(): String = "Console"
|
||||
override fun toString(): String = "console"
|
||||
}
|
||||
}
|
@ -9,8 +9,6 @@
|
||||
|
||||
package net.mamoe.mirai.console.permission
|
||||
|
||||
import kotlinx.serialization.Serializable
|
||||
import net.mamoe.mirai.console.permission.PermissionService.Companion.findCorrespondingPermission
|
||||
import net.mamoe.mirai.console.util.ConsoleExperimentalAPI
|
||||
|
||||
|
||||
@ -25,22 +23,29 @@ import net.mamoe.mirai.console.util.ConsoleExperimentalAPI
|
||||
public interface Permission {
|
||||
public val id: PermissionId
|
||||
public val description: String
|
||||
public val parentId: PermissionId
|
||||
}
|
||||
|
||||
@OptIn(ExperimentalPermission::class)
|
||||
private val ROOT_PERMISSION_ID = PermissionId("*", "*")
|
||||
/**
|
||||
* [RootPermission] 的 parent 为自身
|
||||
*/
|
||||
public val parent: Permission
|
||||
}
|
||||
|
||||
/**
|
||||
* 所有权限的父权限.
|
||||
*/
|
||||
@get:JvmName("getRootPermission")
|
||||
@ExperimentalPermission
|
||||
public val RootPermission: Permission by lazy {
|
||||
public val RootPermission: Permission
|
||||
get() = PermissionService.INSTANCE.rootPermission
|
||||
|
||||
/**
|
||||
* 所有内建指令的权限
|
||||
*/
|
||||
@ExperimentalPermission
|
||||
public val RootConsoleBuiltInPermission: Permission by lazy {
|
||||
PermissionService.INSTANCE.register(
|
||||
ROOT_PERMISSION_ID,
|
||||
"The parent of any permission",
|
||||
ROOT_PERMISSION_ID
|
||||
PermissionId("console", "*"),
|
||||
"The parent of any built-in commands"
|
||||
)
|
||||
}
|
||||
|
||||
@ -48,16 +53,5 @@ public val RootPermission: Permission by lazy {
|
||||
@ExperimentalPermission
|
||||
public fun Permission.parentsWithSelfSequence(): Sequence<Permission> =
|
||||
generateSequence(this) { p ->
|
||||
p.parentId.findCorrespondingPermission()?.takeIf { parent -> parent != p }
|
||||
p.parent.takeIf { parent -> parent != p }
|
||||
}
|
||||
|
||||
/**
|
||||
* [Permission] 的简单实现
|
||||
*/
|
||||
@Serializable
|
||||
@ExperimentalPermission
|
||||
public class PermissionImpl(
|
||||
override val id: PermissionId,
|
||||
override val description: String,
|
||||
override val parentId: PermissionId = RootPermission.id
|
||||
) : Permission
|
@ -23,6 +23,7 @@ import kotlin.reflect.full.isSuperclassOf
|
||||
public interface PermissionService<P : Permission> {
|
||||
@ExperimentalPermission
|
||||
public val permissionType: KClass<P>
|
||||
public val rootPermission: P
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////
|
||||
|
||||
@ -46,7 +47,7 @@ public interface PermissionService<P : Permission> {
|
||||
public fun register(
|
||||
id: PermissionId,
|
||||
description: String,
|
||||
base: PermissionId = RootPermission.id
|
||||
parent: Permission = RootPermission
|
||||
): P
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////
|
||||
|
@ -18,7 +18,7 @@ import net.mamoe.mirai.console.plugin.PluginManager.INSTANCE.enable
|
||||
import net.mamoe.mirai.console.plugin.PluginManager.INSTANCE.safeLoader
|
||||
import net.mamoe.mirai.console.plugin.description.PluginDependency
|
||||
import net.mamoe.mirai.console.plugin.description.PluginDescription
|
||||
import net.mamoe.mirai.console.plugin.description.PluginKind
|
||||
import net.mamoe.mirai.console.plugin.description.PluginLoadPriority
|
||||
import net.mamoe.mirai.console.plugin.jvm.JvmPlugin
|
||||
|
||||
/**
|
||||
@ -65,9 +65,9 @@ public inline val Plugin.name: String get() = this.description.name
|
||||
public inline val Plugin.version: Semver get() = this.description.version
|
||||
|
||||
/**
|
||||
* 获取 [PluginDescription.kind]
|
||||
* 获取 [PluginDescription.loadPriority]
|
||||
*/
|
||||
public inline val Plugin.kind: PluginKind get() = this.description.kind
|
||||
public inline val Plugin.loadPriority: PluginLoadPriority get() = this.description.loadPriority
|
||||
|
||||
/**
|
||||
* 获取 [PluginDescription.info]
|
||||
|
@ -23,9 +23,9 @@ public interface PluginDescription {
|
||||
/**
|
||||
* 插件类型. 将会决定加载顺序
|
||||
*
|
||||
* @see PluginKind
|
||||
* @see PluginLoadPriority
|
||||
*/
|
||||
public val kind: PluginKind
|
||||
public val loadPriority: PluginLoadPriority
|
||||
|
||||
/**
|
||||
* 插件 ID, 必须全英文, 仅允许英文字母, '-', '_', '.'.
|
||||
|
@ -14,39 +14,46 @@ import kotlinx.serialization.builtins.serializer
|
||||
import net.mamoe.mirai.console.extension.Extension
|
||||
import net.mamoe.mirai.console.extensions.BotConfigurationAlterer
|
||||
import net.mamoe.mirai.console.extensions.PermissionServiceProvider
|
||||
import net.mamoe.mirai.console.extensions.PluginLoaderProvider
|
||||
import net.mamoe.mirai.console.extensions.SingletonExtensionSelector
|
||||
import net.mamoe.mirai.console.internal.data.map
|
||||
import net.mamoe.mirai.console.plugin.PluginLoader
|
||||
import net.mamoe.mirai.console.plugin.description.PluginKind.*
|
||||
import net.mamoe.mirai.console.plugin.description.PluginLoadPriority.*
|
||||
|
||||
/**
|
||||
* 插件类型.
|
||||
*
|
||||
* 插件类型将影响加载顺序: [LOADER] -> [HIGH_PRIORITY_EXTENSIONS] -> [NORMAL].
|
||||
* 插件类型将影响加载顺序: [BEFORE_EXTENSIONS] -> [ON_EXTENSIONS] -> [AFTER_EXTENSIONS].
|
||||
*
|
||||
* 依赖解决过程与插件类型有很大关联. 在一个较早的阶段, 只会解决在此阶段加载的插件. 意味着 [LOADER] 不允许依赖一个 [NORMAL] 类型的插件.
|
||||
* 依赖解决过程与插件类型有很大关联. 在一个较早的阶段, 只会解决在此阶段加载的插件. 意味着 [BEFORE_EXTENSIONS] 不允许依赖一个 [AFTER_EXTENSIONS] 类型的插件.
|
||||
*/
|
||||
public enum class PluginKind {
|
||||
/** 表示此插件提供一个 [PluginLoader], 也可以同时提供其他 [Extension] 应最早被加载 */
|
||||
LOADER,
|
||||
public enum class PluginLoadPriority {
|
||||
/**
|
||||
* 表示此插件最早被加载. 在 Console 启动时的第一初始化阶段就会加载这些插件.
|
||||
*
|
||||
* 一般只有提供 [PluginLoaderProvider] 或 [SingletonExtensionSelector] 的插件才需要在此阶段加载.
|
||||
*/
|
||||
BEFORE_EXTENSIONS,
|
||||
|
||||
/**
|
||||
* 表示此插件提供一些高优先级的 [Extension], 应在加载其他 [NORMAL] 类型插件前加载
|
||||
* 表示此插件提供一些高优先级的 [Extension], 应在加载其他 [AFTER_EXTENSIONS] 类型插件前加载
|
||||
*
|
||||
* 高优先级的 [Extension] 通常是覆盖 Console 内置的部分服务的扩展. 如 [PermissionServiceProvider].
|
||||
*
|
||||
* 一些普通的 [Extension], 如 [BotConfigurationAlterer], 也可以使用 [NORMAL] 类型插件注册.
|
||||
* 一些普通的 [Extension], 如 [BotConfigurationAlterer], 也可以使用 [AFTER_EXTENSIONS] 类型插件注册.
|
||||
*/
|
||||
HIGH_PRIORITY_EXTENSIONS,
|
||||
ON_EXTENSIONS,
|
||||
|
||||
/** 表示此插件为一个通常的插件, 按照正常的依赖关系加载. */
|
||||
NORMAL;
|
||||
/**
|
||||
* 表示此插件为一个通常的插件, 在扩展处理完毕后加载.
|
||||
*/
|
||||
AFTER_EXTENSIONS;
|
||||
|
||||
public object AsStringSerializer : KSerializer<PluginKind> by String.serializer().map(
|
||||
public object AsStringSerializer : KSerializer<PluginLoadPriority> by String.serializer().map(
|
||||
serializer = { it.name },
|
||||
deserializer = { str ->
|
||||
values().firstOrNull {
|
||||
it.name.equals(str, ignoreCase = true)
|
||||
} ?: NORMAL
|
||||
} ?: AFTER_EXTENSIONS
|
||||
}
|
||||
)
|
||||
}
|
@ -14,7 +14,7 @@ package net.mamoe.mirai.console.plugin.jvm
|
||||
import com.vdurmont.semver4j.Semver
|
||||
import net.mamoe.mirai.console.plugin.description.PluginDependency
|
||||
import net.mamoe.mirai.console.plugin.description.PluginDescription
|
||||
import net.mamoe.mirai.console.plugin.description.PluginKind
|
||||
import net.mamoe.mirai.console.plugin.description.PluginLoadPriority
|
||||
import kotlin.internal.LowPriorityInOverloadResolution
|
||||
|
||||
/**
|
||||
@ -82,7 +82,7 @@ public class JvmPluginDescriptionBuilder(
|
||||
private var author: String = ""
|
||||
private var info: String = ""
|
||||
private var dependencies: MutableSet<PluginDependency> = mutableSetOf()
|
||||
private var kind: PluginKind = PluginKind.NORMAL
|
||||
private var loadPriority: PluginLoadPriority = PluginLoadPriority.AFTER_EXTENSIONS
|
||||
|
||||
@ILoveKuriyamaMiraiForever
|
||||
public fun name(value: String): JvmPluginDescriptionBuilder = apply { this.name = value.trim() }
|
||||
@ -104,17 +104,19 @@ public class JvmPluginDescriptionBuilder(
|
||||
public fun info(value: String): JvmPluginDescriptionBuilder = apply { this.info = value.trimIndent() }
|
||||
|
||||
@ILoveKuriyamaMiraiForever
|
||||
public fun kind(value: PluginKind): JvmPluginDescriptionBuilder = apply { this.kind = value }
|
||||
public fun kind(value: PluginLoadPriority): JvmPluginDescriptionBuilder = apply { this.loadPriority = value }
|
||||
|
||||
@ILoveKuriyamaMiraiForever
|
||||
public fun normalPlugin(): JvmPluginDescriptionBuilder = apply { this.kind = PluginKind.NORMAL }
|
||||
public fun normalPlugin(): JvmPluginDescriptionBuilder =
|
||||
apply { this.loadPriority = PluginLoadPriority.AFTER_EXTENSIONS }
|
||||
|
||||
@ILoveKuriyamaMiraiForever
|
||||
public fun loaderProviderPlugin(): JvmPluginDescriptionBuilder = apply { this.kind = PluginKind.LOADER }
|
||||
public fun loaderProviderPlugin(): JvmPluginDescriptionBuilder =
|
||||
apply { this.loadPriority = PluginLoadPriority.BEFORE_EXTENSIONS }
|
||||
|
||||
@ILoveKuriyamaMiraiForever
|
||||
public fun highPriorityExtensionsPlugin(): JvmPluginDescriptionBuilder =
|
||||
apply { this.kind = PluginKind.HIGH_PRIORITY_EXTENSIONS }
|
||||
apply { this.loadPriority = PluginLoadPriority.ON_EXTENSIONS }
|
||||
|
||||
@ILoveKuriyamaMiraiForever
|
||||
public fun dependsOn(
|
||||
@ -152,7 +154,7 @@ public class JvmPluginDescriptionBuilder(
|
||||
|
||||
@Suppress("DEPRECATION_ERROR")
|
||||
public fun build(): JvmPluginDescription =
|
||||
SimpleJvmPluginDescription(name, version, id, author, info, dependencies, kind)
|
||||
SimpleJvmPluginDescription(name, version, id, author, info, dependencies, loadPriority)
|
||||
|
||||
@Retention(AnnotationRetention.SOURCE)
|
||||
@DslMarker
|
||||
@ -192,7 +194,7 @@ public data class SimpleJvmPluginDescription
|
||||
public override val author: String = "",
|
||||
public override val info: String = "",
|
||||
public override val dependencies: Set<PluginDependency> = setOf(),
|
||||
public override val kind: PluginKind = PluginKind.NORMAL,
|
||||
public override val loadPriority: PluginLoadPriority = PluginLoadPriority.AFTER_EXTENSIONS,
|
||||
) : JvmPluginDescription {
|
||||
|
||||
@Deprecated(
|
||||
@ -214,8 +216,8 @@ public data class SimpleJvmPluginDescription
|
||||
author: String = "",
|
||||
info: String = "",
|
||||
dependencies: Set<PluginDependency> = setOf(),
|
||||
kind: PluginKind = PluginKind.NORMAL,
|
||||
) : this(name, Semver(version, Semver.SemverType.LOOSE), id, author, info, dependencies, kind)
|
||||
loadPriority: PluginLoadPriority = PluginLoadPriority.AFTER_EXTENSIONS,
|
||||
) : this(name, Semver(version, Semver.SemverType.LOOSE), id, author, info, dependencies, loadPriority)
|
||||
|
||||
init {
|
||||
require(!name.contains(':')) { "':' is forbidden in plugin name" }
|
||||
@ -240,8 +242,8 @@ public fun JvmPluginDescription(
|
||||
author: String = "",
|
||||
info: String = "",
|
||||
dependencies: Set<PluginDependency> = setOf(),
|
||||
kind: PluginKind = PluginKind.NORMAL
|
||||
): JvmPluginDescription = SimpleJvmPluginDescription(name, version, id, author, info, dependencies, kind)
|
||||
loadPriority: PluginLoadPriority = PluginLoadPriority.AFTER_EXTENSIONS
|
||||
): JvmPluginDescription = SimpleJvmPluginDescription(name, version, id, author, info, dependencies, loadPriority)
|
||||
|
||||
@Deprecated(
|
||||
"JvmPluginDescription 没有构造器. 请使用 SimpleJvmPluginDescription.",
|
||||
@ -260,5 +262,5 @@ public fun JvmPluginDescription(
|
||||
author: String = "",
|
||||
info: String = "",
|
||||
dependencies: Set<PluginDependency> = setOf(),
|
||||
kind: PluginKind = PluginKind.NORMAL
|
||||
): JvmPluginDescription = SimpleJvmPluginDescription(name, version, id, author, info, dependencies, kind)
|
||||
loadPriority: PluginLoadPriority = PluginLoadPriority.AFTER_EXTENSIONS
|
||||
): JvmPluginDescription = SimpleJvmPluginDescription(name, version, id, author, info, dependencies, loadPriority)
|
||||
|
@ -22,7 +22,6 @@ import net.mamoe.mirai.console.command.CommandSender
|
||||
import net.mamoe.mirai.contact.Contact
|
||||
import net.mamoe.mirai.contact.User
|
||||
import net.mamoe.mirai.message.data.Message
|
||||
import kotlin.internal.InlineOnly
|
||||
import kotlin.internal.LowPriorityInOverloadResolution
|
||||
|
||||
/**
|
||||
@ -38,10 +37,10 @@ import kotlin.internal.LowPriorityInOverloadResolution
|
||||
* - `C<A>.toMessageScope()`. 其中 `C` 表示 `Iterable`, `Sequence`, `Flow`, `Array` 其中任一.
|
||||
*
|
||||
* ## 连接 [MessageScope]
|
||||
* - `A.scopeWith(vararg B)`.
|
||||
* - `A.scopeWith(vararg A)`.
|
||||
* - `A.scopeWithNotNull(vararg B?)`. 类似 [listOfNotNull].
|
||||
* - `A.scopeWithNotNull(vararg A?)`. 类似 [listOfNotNull].
|
||||
* - `A?.scopeWith(vararg B?)`.
|
||||
* - `A?.scopeWith(vararg A?)`.
|
||||
*
|
||||
* `null` 项将会被过滤.
|
||||
*
|
||||
* ## 自动去重
|
||||
* 在连接时, [MessageScope] 会自动根据真实的 [收信对象][CommandSender.subject] 去重.
|
||||
@ -83,12 +82,12 @@ import kotlin.internal.LowPriorityInOverloadResolution
|
||||
*
|
||||
* // 使用 MessageScope, 清晰逻辑
|
||||
* // 表示至少发送给 `this`, 当 `this` 的真实发信对象与 `target.group` 不同时, 还额外发送给 `target.group`
|
||||
* this.scopeWithNotNull(target.group) {
|
||||
* this.scopeWith(target.group) {
|
||||
* sendMessage("${name} 禁言了 ${target.nameCardOrNick} $duration 秒")
|
||||
* }
|
||||
*
|
||||
* // 同样地, 可以扩展用法, 同时私聊指令执行者:
|
||||
* // this.scopeWithNotNull(
|
||||
* // this.scopeWith(
|
||||
* // target,
|
||||
* // target.group
|
||||
* // ) { ... }
|
||||
@ -143,132 +142,51 @@ public fun Contact.asMessageScope(): MessageScope = createScopeDelegate(this)
|
||||
public fun CommandSender.asMessageScope(): MessageScope = createScopeDelegate(this)
|
||||
|
||||
@LowPriorityInOverloadResolution
|
||||
public fun Contact.scopeWith(vararg others: Contact): MessageScope {
|
||||
return others.fold(this.asMessageScope()) { acc, other -> CombinedScope(acc, other.asMessageScope()) }
|
||||
public fun Contact?.scopeWith(vararg others: Contact?): MessageScope {
|
||||
return others.fold(this.asMessageScopeOrNoop()) { acc, other -> acc.scopeWith(other?.asMessageScope()) }
|
||||
}
|
||||
|
||||
@LowPriorityInOverloadResolution
|
||||
public fun Contact.scopeWith(vararg others: CommandSender): MessageScope {
|
||||
return others.fold(this.asMessageScope()) { acc, other -> CombinedScope(acc, other.asMessageScope()) }
|
||||
public fun Contact?.scopeWith(vararg others: CommandSender?): MessageScope {
|
||||
return others.fold(this.asMessageScopeOrNoop()) { acc, other -> acc.scopeWith(other?.asMessageScope()) }
|
||||
}
|
||||
|
||||
@LowPriorityInOverloadResolution
|
||||
public fun Contact.scopeWith(vararg others: MessageScope): MessageScope {
|
||||
return others.fold(this.asMessageScope()) { acc, other -> CombinedScope(acc, other.asMessageScope()) }
|
||||
public fun Contact?.scopeWith(vararg others: MessageScope?): MessageScope {
|
||||
return others.fold(this.asMessageScopeOrNoop()) { acc, other -> acc.scopeWith(other?.asMessageScope()) }
|
||||
}
|
||||
|
||||
@LowPriorityInOverloadResolution
|
||||
public fun CommandSender.scopeWith(vararg others: Contact): MessageScope {
|
||||
return others.fold(this.asMessageScope()) { acc, other -> CombinedScope(acc, other.asMessageScope()) }
|
||||
public fun CommandSender?.scopeWith(vararg others: Contact?): MessageScope {
|
||||
return others.fold(this.asMessageScopeOrNoop()) { acc, other -> acc.scopeWith(other?.asMessageScope()) }
|
||||
}
|
||||
|
||||
@LowPriorityInOverloadResolution
|
||||
public fun CommandSender.scopeWith(vararg others: CommandSender): MessageScope {
|
||||
return others.fold(this.asMessageScope()) { acc, other -> CombinedScope(acc, other.asMessageScope()) }
|
||||
public fun CommandSender?.scopeWith(vararg others: CommandSender?): MessageScope {
|
||||
return others.fold(this.asMessageScopeOrNoop()) { acc, other -> acc.scopeWith(other?.asMessageScope()) }
|
||||
}
|
||||
|
||||
@LowPriorityInOverloadResolution
|
||||
public fun CommandSender.scopeWith(vararg others: MessageScope): MessageScope {
|
||||
return others.fold(this.asMessageScope()) { acc, other -> CombinedScope(acc, other.asMessageScope()) }
|
||||
public fun CommandSender?.scopeWith(vararg others: MessageScope?): MessageScope {
|
||||
return others.fold(this.asMessageScopeOrNoop()) { acc, other -> acc.scopeWith(other?.asMessageScope()) }
|
||||
}
|
||||
|
||||
@LowPriorityInOverloadResolution
|
||||
public fun MessageScope.scopeWith(vararg others: Contact): MessageScope {
|
||||
return others.fold(this.asMessageScope()) { acc, other -> CombinedScope(acc, other.asMessageScope()) }
|
||||
public fun MessageScope?.scopeWith(vararg others: Contact?): MessageScope {
|
||||
return others.fold(this.asMessageScopeOrNoop()) { acc, other -> acc.scopeWith(other?.asMessageScope()) }
|
||||
}
|
||||
|
||||
@LowPriorityInOverloadResolution
|
||||
public fun MessageScope.scopeWith(vararg others: CommandSender): MessageScope {
|
||||
return others.fold(this.asMessageScope()) { acc, other -> CombinedScope(acc, other.asMessageScope()) }
|
||||
public fun MessageScope?.scopeWith(vararg others: CommandSender?): MessageScope {
|
||||
return others.fold(this.asMessageScopeOrNoop()) { acc, other -> acc.scopeWith(other?.asMessageScope()) }
|
||||
}
|
||||
|
||||
@LowPriorityInOverloadResolution
|
||||
public fun MessageScope.scopeWith(vararg others: MessageScope): MessageScope {
|
||||
return others.fold(this.asMessageScope()) { acc, other -> CombinedScope(acc, other.asMessageScope()) }
|
||||
public fun MessageScope?.scopeWith(vararg others: MessageScope?): MessageScope {
|
||||
return others.fold(this.asMessageScopeOrNoop()) { acc, other -> acc.scopeWith(other?.asMessageScope()) }
|
||||
}
|
||||
|
||||
@LowPriorityInOverloadResolution
|
||||
public fun Contact?.scopeWithNotNull(vararg others: Contact?): MessageScope {
|
||||
return others.fold(this.asMessageScopeOrNoop()) { acc, other -> acc.scopeWithNotNull(other?.asMessageScope()) }
|
||||
}
|
||||
|
||||
@LowPriorityInOverloadResolution
|
||||
public fun Contact?.scopeWithNotNull(vararg others: CommandSender?): MessageScope {
|
||||
return others.fold(this.asMessageScopeOrNoop()) { acc, other -> acc.scopeWithNotNull(other?.asMessageScope()) }
|
||||
}
|
||||
|
||||
@LowPriorityInOverloadResolution
|
||||
public fun Contact?.scopeWithNotNull(vararg others: MessageScope?): MessageScope {
|
||||
return others.fold(this.asMessageScopeOrNoop()) { acc, other -> acc.scopeWithNotNull(other?.asMessageScope()) }
|
||||
}
|
||||
|
||||
@LowPriorityInOverloadResolution
|
||||
public fun CommandSender?.scopeWithNotNull(vararg others: Contact?): MessageScope {
|
||||
return others.fold(this.asMessageScopeOrNoop()) { acc, other -> acc.scopeWithNotNull(other?.asMessageScope()) }
|
||||
}
|
||||
|
||||
@LowPriorityInOverloadResolution
|
||||
public fun CommandSender?.scopeWithNotNull(vararg others: CommandSender?): MessageScope {
|
||||
return others.fold(this.asMessageScopeOrNoop()) { acc, other -> acc.scopeWithNotNull(other?.asMessageScope()) }
|
||||
}
|
||||
|
||||
@LowPriorityInOverloadResolution
|
||||
public fun CommandSender?.scopeWithNotNull(vararg others: MessageScope?): MessageScope {
|
||||
return others.fold(this.asMessageScopeOrNoop()) { acc, other -> acc.scopeWithNotNull(other?.asMessageScope()) }
|
||||
}
|
||||
|
||||
@LowPriorityInOverloadResolution
|
||||
public fun MessageScope?.scopeWithNotNull(vararg others: Contact?): MessageScope {
|
||||
return others.fold(this.asMessageScopeOrNoop()) { acc, other -> acc.scopeWithNotNull(other?.asMessageScope()) }
|
||||
}
|
||||
|
||||
@LowPriorityInOverloadResolution
|
||||
public fun MessageScope?.scopeWithNotNull(vararg others: CommandSender?): MessageScope {
|
||||
return others.fold(this.asMessageScopeOrNoop()) { acc, other -> acc.scopeWithNotNull(other?.asMessageScope()) }
|
||||
}
|
||||
|
||||
@LowPriorityInOverloadResolution
|
||||
public fun MessageScope?.scopeWithNotNull(vararg others: MessageScope?): MessageScope {
|
||||
return others.fold(this.asMessageScopeOrNoop()) { acc, other -> acc.scopeWithNotNull(other?.asMessageScope()) }
|
||||
}
|
||||
|
||||
public fun Contact.scopeWith(other: Contact): MessageScope {
|
||||
return CombinedScope(asMessageScope(), other.asMessageScope())
|
||||
}
|
||||
|
||||
public fun Contact.scopeWith(other: CommandSender): MessageScope {
|
||||
return CombinedScope(asMessageScope(), other.asMessageScope())
|
||||
}
|
||||
|
||||
public fun Contact.scopeWith(other: MessageScope): MessageScope {
|
||||
return CombinedScope(asMessageScope(), other.asMessageScope())
|
||||
}
|
||||
|
||||
public fun CommandSender.scopeWith(other: Contact): MessageScope {
|
||||
return CombinedScope(asMessageScope(), other.asMessageScope())
|
||||
}
|
||||
|
||||
public fun CommandSender.scopeWith(other: CommandSender): MessageScope {
|
||||
return CombinedScope(asMessageScope(), other.asMessageScope())
|
||||
}
|
||||
|
||||
public fun CommandSender.scopeWith(other: MessageScope): MessageScope {
|
||||
return CombinedScope(asMessageScope(), other.asMessageScope())
|
||||
}
|
||||
|
||||
public fun MessageScope.scopeWith(other: Contact): MessageScope {
|
||||
return CombinedScope(asMessageScope(), other.asMessageScope())
|
||||
}
|
||||
|
||||
public fun MessageScope.scopeWith(other: CommandSender): MessageScope {
|
||||
return CombinedScope(asMessageScope(), other.asMessageScope())
|
||||
}
|
||||
|
||||
public fun MessageScope.scopeWith(other: MessageScope): MessageScope {
|
||||
return CombinedScope(asMessageScope(), other.asMessageScope())
|
||||
}
|
||||
|
||||
public fun Contact?.scopeWithNotNull(other: Contact?): MessageScope {
|
||||
public fun Contact?.scopeWith(other: Contact?): MessageScope {
|
||||
@Suppress("DuplicatedCode")
|
||||
return when {
|
||||
this == null && other == null -> NoopMessageScope
|
||||
@ -279,7 +197,7 @@ public fun Contact?.scopeWithNotNull(other: Contact?): MessageScope {
|
||||
}
|
||||
}
|
||||
|
||||
public fun Contact?.scopeWithNotNull(other: CommandSender?): MessageScope {
|
||||
public fun Contact?.scopeWith(other: CommandSender?): MessageScope {
|
||||
@Suppress("DuplicatedCode")
|
||||
return when {
|
||||
this == null && other == null -> NoopMessageScope
|
||||
@ -290,7 +208,7 @@ public fun Contact?.scopeWithNotNull(other: CommandSender?): MessageScope {
|
||||
}
|
||||
}
|
||||
|
||||
public fun Contact?.scopeWithNotNull(other: MessageScope?): MessageScope {
|
||||
public fun Contact?.scopeWith(other: MessageScope?): MessageScope {
|
||||
@Suppress("DuplicatedCode")
|
||||
return when {
|
||||
this == null && other == null -> NoopMessageScope
|
||||
@ -301,7 +219,7 @@ public fun Contact?.scopeWithNotNull(other: MessageScope?): MessageScope {
|
||||
}
|
||||
}
|
||||
|
||||
public fun CommandSender?.scopeWithNotNull(other: Contact?): MessageScope {
|
||||
public fun CommandSender?.scopeWith(other: Contact?): MessageScope {
|
||||
@Suppress("DuplicatedCode")
|
||||
return when {
|
||||
this == null && other == null -> NoopMessageScope
|
||||
@ -312,7 +230,7 @@ public fun CommandSender?.scopeWithNotNull(other: Contact?): MessageScope {
|
||||
}
|
||||
}
|
||||
|
||||
public fun CommandSender?.scopeWithNotNull(other: CommandSender?): MessageScope {
|
||||
public fun CommandSender?.scopeWith(other: CommandSender?): MessageScope {
|
||||
@Suppress("DuplicatedCode")
|
||||
return when {
|
||||
this == null && other == null -> NoopMessageScope
|
||||
@ -323,7 +241,7 @@ public fun CommandSender?.scopeWithNotNull(other: CommandSender?): MessageScope
|
||||
}
|
||||
}
|
||||
|
||||
public fun CommandSender?.scopeWithNotNull(other: MessageScope?): MessageScope {
|
||||
public fun CommandSender?.scopeWith(other: MessageScope?): MessageScope {
|
||||
@Suppress("DuplicatedCode")
|
||||
return when {
|
||||
this == null && other == null -> NoopMessageScope
|
||||
@ -334,7 +252,7 @@ public fun CommandSender?.scopeWithNotNull(other: MessageScope?): MessageScope {
|
||||
}
|
||||
}
|
||||
|
||||
public fun MessageScope?.scopeWithNotNull(other: Contact?): MessageScope {
|
||||
public fun MessageScope?.scopeWith(other: Contact?): MessageScope {
|
||||
@Suppress("DuplicatedCode")
|
||||
return when {
|
||||
this == null && other == null -> NoopMessageScope
|
||||
@ -345,7 +263,7 @@ public fun MessageScope?.scopeWithNotNull(other: Contact?): MessageScope {
|
||||
}
|
||||
}
|
||||
|
||||
public fun MessageScope?.scopeWithNotNull(other: CommandSender?): MessageScope {
|
||||
public fun MessageScope?.scopeWith(other: CommandSender?): MessageScope {
|
||||
@Suppress("DuplicatedCode")
|
||||
return when {
|
||||
this == null && other == null -> NoopMessageScope
|
||||
@ -356,7 +274,7 @@ public fun MessageScope?.scopeWithNotNull(other: CommandSender?): MessageScope {
|
||||
}
|
||||
}
|
||||
|
||||
public fun MessageScope?.scopeWithNotNull(other: MessageScope?): MessageScope {
|
||||
public fun MessageScope?.scopeWith(other: MessageScope?): MessageScope {
|
||||
@Suppress("DuplicatedCode")
|
||||
return when {
|
||||
this == null && other == null -> NoopMessageScope
|
||||
@ -367,78 +285,42 @@ public fun MessageScope?.scopeWithNotNull(other: MessageScope?): MessageScope {
|
||||
}
|
||||
}
|
||||
|
||||
public inline fun <R> Contact.scopeWith(vararg others: Contact, action: MessageScope.() -> R): R {
|
||||
public inline fun <R> Contact?.scopeWith(vararg others: Contact?, action: MessageScope.() -> R): R {
|
||||
return scopeWith(*others).invoke(action)
|
||||
}
|
||||
|
||||
public inline fun <R> Contact.scopeWith(vararg others: CommandSender, action: MessageScope.() -> R): R {
|
||||
public inline fun <R> Contact?.scopeWith(vararg others: CommandSender?, action: MessageScope.() -> R): R {
|
||||
return scopeWith(*others).invoke(action)
|
||||
}
|
||||
|
||||
public inline fun <R> Contact.scopeWith(vararg others: MessageScope, action: MessageScope.() -> R): R {
|
||||
public inline fun <R> Contact?.scopeWith(vararg others: MessageScope?, action: MessageScope.() -> R): R {
|
||||
return scopeWith(*others).invoke(action)
|
||||
}
|
||||
|
||||
public inline fun <R> CommandSender.scopeWith(vararg others: Contact, action: MessageScope.() -> R): R {
|
||||
public inline fun <R> CommandSender?.scopeWith(vararg others: Contact?, action: MessageScope.() -> R): R {
|
||||
return scopeWith(*others).invoke(action)
|
||||
}
|
||||
|
||||
public inline fun <R> CommandSender.scopeWith(vararg others: CommandSender, action: MessageScope.() -> R): R {
|
||||
public inline fun <R> CommandSender?.scopeWith(vararg others: CommandSender?, action: MessageScope.() -> R): R {
|
||||
return scopeWith(*others).invoke(action)
|
||||
}
|
||||
|
||||
public inline fun <R> CommandSender.scopeWith(vararg others: MessageScope, action: MessageScope.() -> R): R {
|
||||
public inline fun <R> CommandSender?.scopeWith(vararg others: MessageScope?, action: MessageScope.() -> R): R {
|
||||
return scopeWith(*others).invoke(action)
|
||||
}
|
||||
|
||||
public inline fun <R> MessageScope.scopeWith(vararg others: Contact, action: MessageScope.() -> R): R {
|
||||
public inline fun <R> MessageScope?.scopeWith(vararg others: Contact?, action: MessageScope.() -> R): R {
|
||||
return scopeWith(*others).invoke(action)
|
||||
}
|
||||
|
||||
public inline fun <R> MessageScope.scopeWith(vararg others: CommandSender, action: MessageScope.() -> R): R {
|
||||
public inline fun <R> MessageScope?.scopeWith(vararg others: CommandSender?, action: MessageScope.() -> R): R {
|
||||
return scopeWith(*others).invoke(action)
|
||||
}
|
||||
|
||||
public inline fun <R> MessageScope.scopeWith(vararg others: MessageScope, action: MessageScope.() -> R): R {
|
||||
public inline fun <R> MessageScope?.scopeWith(vararg others: MessageScope?, action: MessageScope.() -> R): R {
|
||||
return scopeWith(*others).invoke(action)
|
||||
}
|
||||
|
||||
public inline fun <R> Contact?.scopeWithNotNull(vararg others: Contact?, action: MessageScope.() -> R): R {
|
||||
return scopeWithNotNull(*others).invoke(action)
|
||||
}
|
||||
|
||||
public inline fun <R> Contact?.scopeWithNotNull(vararg others: CommandSender?, action: MessageScope.() -> R): R {
|
||||
return scopeWithNotNull(*others).invoke(action)
|
||||
}
|
||||
|
||||
public inline fun <R> Contact?.scopeWithNotNull(vararg others: MessageScope?, action: MessageScope.() -> R): R {
|
||||
return scopeWithNotNull(*others).invoke(action)
|
||||
}
|
||||
|
||||
public inline fun <R> CommandSender?.scopeWithNotNull(vararg others: Contact?, action: MessageScope.() -> R): R {
|
||||
return scopeWithNotNull(*others).invoke(action)
|
||||
}
|
||||
|
||||
public inline fun <R> CommandSender?.scopeWithNotNull(vararg others: CommandSender?, action: MessageScope.() -> R): R {
|
||||
return scopeWithNotNull(*others).invoke(action)
|
||||
}
|
||||
|
||||
public inline fun <R> CommandSender?.scopeWithNotNull(vararg others: MessageScope?, action: MessageScope.() -> R): R {
|
||||
return scopeWithNotNull(*others).invoke(action)
|
||||
}
|
||||
|
||||
public inline fun <R> MessageScope?.scopeWithNotNull(vararg others: Contact?, action: MessageScope.() -> R): R {
|
||||
return scopeWithNotNull(*others).invoke(action)
|
||||
}
|
||||
|
||||
public inline fun <R> MessageScope?.scopeWithNotNull(vararg others: CommandSender?, action: MessageScope.() -> R): R {
|
||||
return scopeWithNotNull(*others).invoke(action)
|
||||
}
|
||||
|
||||
public inline fun <R> MessageScope?.scopeWithNotNull(vararg others: MessageScope?, action: MessageScope.() -> R): R {
|
||||
return scopeWithNotNull(*others).invoke(action)
|
||||
}
|
||||
|
||||
@Deprecated(
|
||||
"Senseless scopeWith. Use asMessageScope.",
|
||||
ReplaceWith("this.asMessageScope()", "net.mamoe.mirai.console.util.asMessageScope")
|
||||
@ -623,27 +505,23 @@ public suspend fun Flow<MessageScope>.toMessageScope(): MessageScope { // Flow<A
|
||||
// [MessageScope] 实现
|
||||
|
||||
@PublishedApi
|
||||
@InlineOnly
|
||||
internal inline fun MessageScope.asMessageScope(): MessageScope = this
|
||||
|
||||
@InlineOnly
|
||||
private inline fun MessageScope?.asMessageScopeOrNoop(): MessageScope = this?.asMessageScope() ?: NoopMessageScope
|
||||
|
||||
@InlineOnly
|
||||
private inline fun Contact?.asMessageScopeOrNoop(): MessageScope = this?.asMessageScope() ?: NoopMessageScope
|
||||
|
||||
@InlineOnly
|
||||
private inline fun CommandSender?.asMessageScopeOrNoop(): MessageScope = this?.asMessageScope() ?: NoopMessageScope
|
||||
|
||||
@InlineOnly
|
||||
private inline fun createScopeDelegate(o: CommandSender) = CommandSenderAsMessageScope(o)
|
||||
|
||||
@InlineOnly
|
||||
private inline fun createScopeDelegate(o: Contact) = ContactAsMessageScope(o)
|
||||
|
||||
private fun MessageScope.asSequence(): Sequence<MessageScope> {
|
||||
internal fun MessageScope.asSequence(): Sequence<MessageScope> {
|
||||
return if (this is CombinedScope) {
|
||||
sequenceOf(this.first.asSequence(), this.second.asSequence()).flatten()
|
||||
val a = this.first.asSequence()
|
||||
val b = this.second.asSequence() // don't inline. fuck compilers
|
||||
sequenceOf(a, b).flatten()
|
||||
} else sequenceOf(this)
|
||||
}
|
||||
|
||||
|
@ -23,8 +23,8 @@ object Versions {
|
||||
const val consoleTerminal = "0.1.0"
|
||||
const val consolePure = console
|
||||
|
||||
const val kotlinCompiler = "1.4.0"
|
||||
const val kotlinStdlib = "1.4.0"
|
||||
const val kotlinCompiler = "1.4.10"
|
||||
const val kotlinStdlib = kotlinCompiler
|
||||
|
||||
const val coroutines = "1.3.9"
|
||||
const val collectionsImmutable = "0.3.2"
|
||||
@ -37,5 +37,5 @@ object Versions {
|
||||
const val bintray = "1.8.5"
|
||||
|
||||
const val blockingBridge = "1.0.5"
|
||||
const val yamlkt = "0.5.1"
|
||||
const val yamlkt = "0.5.2"
|
||||
}
|
@ -26,7 +26,6 @@
|
||||
[`RawCommand`]: ../backend/mirai-console/src/main/kotlin/net/mamoe/mirai/console/command/RawCommand.kt
|
||||
[`CommandManager`]: ../backend/mirai-console/src/main/kotlin/net/mamoe/mirai/console/command/CommandManager.kt
|
||||
|
||||
[`BotManager`]: ../backend/mirai-console/src/main/kotlin/net/mamoe/mirai/console/util/BotManager.kt
|
||||
[`Annotations`]: ../backend/mirai-console/src/main/kotlin/net/mamoe/mirai/console/util/Annotations.kt
|
||||
[`ConsoleInput`]: ../backend/mirai-console/src/main/kotlin/net/mamoe/mirai/console/util/ConsoleInput.kt
|
||||
[`JavaPluginScheduler`]: ../backend/mirai-console/src/main/kotlin/net/mamoe/mirai/console/plugin/jvm/JavaPluginScheduler.kt
|
||||
@ -75,9 +74,9 @@ Mirai Console 提供一些基础的实现,即 [`AbstractJvmPlugin`],并将 [
|
||||
#### 描述
|
||||
插件描述需要在主类构造器传递给 `super`。因此插件不需要 `plugin.yml`, `plugin.xml` 等配置文件来指示信息。
|
||||
|
||||
Mirai Console 使用 `ServiceLoader` 加载插件。
|
||||
Mirai Console 使用类似 `ServiceLoader` 的机制加载插件。
|
||||
在 Kotlin,可([使用 AutoService])自动配置 service 信息。
|
||||
在 Kotlin 或其他语言,手动创建 service 文件: 在 `jar` 内 `META-INF/services/net.mamoe.mirai.console.plugin.jvm.JvmPlugin` 文件内存放插件主类全名(以纯文本 UTF-8 存储,文件内容只包含一行插件主类全名).
|
||||
在 Kotlin 或其他语言,可手动创建 service 文件: 在 `jar` 内 `META-INF/services/net.mamoe.mirai.console.plugin.jvm.JvmPlugin` 文件内存放插件主类全名(以纯文本 UTF-8 存储,文件内容只包含一行插件主类全名).
|
||||
|
||||
|
||||
有关插件版本号的限制:
|
||||
@ -94,13 +93,16 @@ Mirai Console 使用 `ServiceLoader` 加载插件。
|
||||
- 访问权限为 `public` 或默认 (不指定)
|
||||
|
||||
```kotlin
|
||||
@AutoService(JvmPlugin::class) // 如果选用上述自动配置的方法
|
||||
object SchedulePlugin : KotlinPlugin(
|
||||
SimpleJvmPluginDescription( // 插件的描述, name 和 version 是必须的
|
||||
name = "Schedule",
|
||||
JvmPluginDescription(
|
||||
id = "org.example.my-schedule-plugin",
|
||||
version = "1.0.0",
|
||||
// author, description, ...
|
||||
)
|
||||
) {
|
||||
name("Schedule")
|
||||
|
||||
// author("...")
|
||||
// dependsOn("...")
|
||||
}
|
||||
) {
|
||||
// ...
|
||||
}
|
||||
@ -117,10 +119,14 @@ object SchedulePlugin : KotlinPlugin(
|
||||
public final class JExample extends JavaPlugin {
|
||||
public static final JExample INSTANCE = new JExample(); // 可以像 Kotlin 一样静态初始化单例
|
||||
private JExample() {
|
||||
super(new SimpleJvmPluginDescription(
|
||||
super(new JvmPluginDescriptionBuilder(
|
||||
"JExample", // name
|
||||
"1.0.0" // version
|
||||
));
|
||||
)
|
||||
// .author("...")
|
||||
// .info("...")
|
||||
.build()
|
||||
);
|
||||
}
|
||||
}
|
||||
```
|
||||
@ -133,10 +139,14 @@ public final class JExample extends JavaPlugin {
|
||||
return instance;
|
||||
}
|
||||
public JExample() { // 此时必须 public
|
||||
super(new SimpleJvmPluginDescription(
|
||||
super(new JvmPluginDescriptionBuilder(
|
||||
"JExample", // name
|
||||
"1.0.0" // version
|
||||
));
|
||||
)
|
||||
// .author("...")
|
||||
// .info("...")
|
||||
.build()
|
||||
);
|
||||
instance = this;
|
||||
}
|
||||
}
|
||||
@ -248,5 +258,31 @@ Java:
|
||||
**仅可在插件 onEnable() 时及其之后才能使用这些方法。**
|
||||
**在插件 onDisable() 之后不能使用这些方法。**
|
||||
|
||||
#### 使用示例
|
||||
|
||||
```kotlin
|
||||
object SchedulePlugin : KotlinPlugin(
|
||||
JvmPluginDescription(
|
||||
id = "org.example.my-schedule-plugin",
|
||||
version = "1.0.0",
|
||||
) {
|
||||
name("Schedule")
|
||||
|
||||
// author("...")
|
||||
// dependsOn("...")
|
||||
}
|
||||
) {
|
||||
// ...
|
||||
|
||||
override fun onEnable() {
|
||||
MyData.reload() // 仅需此行,保证启动时更新数据,在之后自动存储数据。
|
||||
}
|
||||
}
|
||||
|
||||
object MyData : AutoSavePluginData() {
|
||||
val value: Map<String, String> by value()
|
||||
}
|
||||
```
|
||||
|
||||
### 附录:Java 插件的多线程调度器 - [`JavaPluginScheduler`]
|
||||
拥有生命周期管理的简单 Java 线程池。
|
||||
拥有生命周期管理的简单 Java 线程池。其中所有的任务都会在插件被关闭时自动停止。
|
@ -35,7 +35,7 @@ internal fun startupConsoleThread() {
|
||||
val next = MiraiConsole.requestInput("").let {
|
||||
when {
|
||||
it.startsWith(CommandManager.commandPrefix) -> it
|
||||
it == "?" -> CommandManager.commandPrefix + BuiltInCommands.Help.primaryName
|
||||
it == "?" -> CommandManager.commandPrefix + BuiltInCommands.HelpCommand.primaryName
|
||||
else -> CommandManager.commandPrefix + it
|
||||
}
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user