mirror of
https://github.com/mamoe/mirai.git
synced 2025-01-27 00:30:17 +08:00
Public API stabilization:
- Redesign MiraiConsoleFrontEndDescription - Redesign MiraiConsoleImplementation - Rework path-relevant properties - Add docs
This commit is contained in:
parent
bcd93ab34e
commit
218fb2bdcc
@ -12,6 +12,7 @@
|
|||||||
|
|
||||||
package net.mamoe.mirai.console
|
package net.mamoe.mirai.console
|
||||||
|
|
||||||
|
import com.vdurmont.semver4j.Semver
|
||||||
import kotlinx.coroutines.CoroutineScope
|
import kotlinx.coroutines.CoroutineScope
|
||||||
import kotlinx.coroutines.Job
|
import kotlinx.coroutines.Job
|
||||||
import net.mamoe.mirai.Bot
|
import net.mamoe.mirai.Bot
|
||||||
@ -24,8 +25,8 @@ import net.mamoe.mirai.console.util.ConsoleExperimentalAPI
|
|||||||
import net.mamoe.mirai.console.util.ConsoleInternalAPI
|
import net.mamoe.mirai.console.util.ConsoleInternalAPI
|
||||||
import net.mamoe.mirai.utils.BotConfiguration
|
import net.mamoe.mirai.utils.BotConfiguration
|
||||||
import net.mamoe.mirai.utils.MiraiLogger
|
import net.mamoe.mirai.utils.MiraiLogger
|
||||||
import java.io.File
|
import java.nio.file.Path
|
||||||
import java.util.*
|
import java.time.Instant
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -36,19 +37,20 @@ import java.util.*
|
|||||||
*/
|
*/
|
||||||
public interface MiraiConsole : CoroutineScope {
|
public interface MiraiConsole : CoroutineScope {
|
||||||
/**
|
/**
|
||||||
* Console 运行路径
|
* Console 运行根目录, 由前端决定确切路径.
|
||||||
|
*
|
||||||
|
* 所有子模块都会在这个目录之下创建子目录.
|
||||||
*/
|
*/
|
||||||
public val rootDir: File
|
public val rootPath: Path
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Console 前端接口
|
* Console 主日志.
|
||||||
*/
|
*
|
||||||
@ConsoleExperimentalAPI
|
* **实现细节**: 这个 [MiraiLogger] 的 [MiraiLogger.identity] 通常为 `main`
|
||||||
public val frontEnd: MiraiConsoleFrontEnd
|
*
|
||||||
|
* **注意**: 插件不应该在任何时刻使用它.
|
||||||
/**
|
|
||||||
* 与前端交互所使用的 Logger
|
|
||||||
*/
|
*/
|
||||||
|
@ConsoleInternalAPI
|
||||||
public val mainLogger: MiraiLogger
|
public val mainLogger: MiraiLogger
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -58,13 +60,22 @@ public interface MiraiConsole : CoroutineScope {
|
|||||||
*/
|
*/
|
||||||
public val builtInPluginLoaders: List<PluginLoader<*, *>>
|
public val builtInPluginLoaders: List<PluginLoader<*, *>>
|
||||||
|
|
||||||
public val buildDate: Date
|
/**
|
||||||
|
* 此 Console 后端构建时间
|
||||||
|
*/
|
||||||
|
public val buildDate: Instant
|
||||||
|
|
||||||
public val version: String
|
/**
|
||||||
|
* 此 Console 后端版本号
|
||||||
|
*/
|
||||||
|
public val version: Semver
|
||||||
|
|
||||||
@ConsoleExperimentalAPI
|
@ConsoleExperimentalAPI
|
||||||
public val pluginCenter: PluginCenter
|
public val pluginCenter: PluginCenter
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 创建一个 logger
|
||||||
|
*/
|
||||||
@ConsoleExperimentalAPI
|
@ConsoleExperimentalAPI
|
||||||
public fun newLogger(identity: String?): MiraiLogger
|
public fun newLogger(identity: String?): MiraiLogger
|
||||||
|
|
||||||
@ -88,8 +99,9 @@ public interface MiraiConsole : CoroutineScope {
|
|||||||
public fun addBot(id: Long, password: String, configuration: BotConfiguration.() -> Unit = {}): Bot =
|
public fun addBot(id: Long, password: String, configuration: BotConfiguration.() -> Unit = {}): Bot =
|
||||||
Bot(id, password) {
|
Bot(id, password) {
|
||||||
fileBasedDeviceInfo()
|
fileBasedDeviceInfo()
|
||||||
this.loginSolver = frontEnd.createLoginSolver()
|
|
||||||
redirectNetworkLogToDirectory()
|
redirectNetworkLogToDirectory()
|
||||||
|
|
||||||
|
this.loginSolver = MiraiConsoleImplementationBridge.createLoginSolver(id, this)
|
||||||
configuration()
|
configuration()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1,53 +0,0 @@
|
|||||||
/*
|
|
||||||
* Copyright 2019-2020 Mamoe Technologies and contributors.
|
|
||||||
*
|
|
||||||
* 此源代码的使用受 GNU AFFERO GENERAL PUBLIC LICENSE version 3 with Mamoe Exceptions 许可证的约束, 可以在以下链接找到该许可证.
|
|
||||||
* Use of this source code is governed by the GNU AFFERO GENERAL PUBLIC LICENSE version 3 with Mamoe Exceptions license that can be found via the following link.
|
|
||||||
*
|
|
||||||
* https://github.com/mamoe/mirai/blob/master/LICENSE
|
|
||||||
*/
|
|
||||||
|
|
||||||
package net.mamoe.mirai.console
|
|
||||||
|
|
||||||
import net.mamoe.mirai.Bot
|
|
||||||
import net.mamoe.mirai.console.util.ConsoleExperimentalAPI
|
|
||||||
import net.mamoe.mirai.utils.LoginSolver
|
|
||||||
import net.mamoe.mirai.utils.MiraiLogger
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 只需要实现一个这个传入 MiraiConsole 就可以绑定 UI 层与 Console 层
|
|
||||||
*
|
|
||||||
* 需要保证线程安全
|
|
||||||
*/
|
|
||||||
@ConsoleExperimentalAPI
|
|
||||||
@ConsoleFrontEndImplementation
|
|
||||||
public interface MiraiConsoleFrontEnd {
|
|
||||||
/**
|
|
||||||
* 名称
|
|
||||||
*/
|
|
||||||
public val name: String
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 版本
|
|
||||||
*/
|
|
||||||
public val version: String
|
|
||||||
|
|
||||||
public fun loggerFor(identity: String?): MiraiLogger
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 让 UI 层接受一个新的bot
|
|
||||||
* */
|
|
||||||
public fun pushBot(
|
|
||||||
bot: Bot
|
|
||||||
)
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 让 UI 层提供一个输入, 相当于 [readLine]
|
|
||||||
*/
|
|
||||||
public suspend fun requestInput(hint: String): String
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 由 UI 层创建一个 [LoginSolver]
|
|
||||||
*/
|
|
||||||
public fun createLoginSolver(): LoginSolver
|
|
||||||
}
|
|
@ -0,0 +1,37 @@
|
|||||||
|
/*
|
||||||
|
* 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
|
||||||
|
|
||||||
|
import com.vdurmont.semver4j.Semver
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 有关前端实现的信息
|
||||||
|
*/
|
||||||
|
public interface MiraiConsoleFrontEndDescription {
|
||||||
|
/**
|
||||||
|
* 此前端实现的名称
|
||||||
|
*/
|
||||||
|
public val name: String
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 此前端实现的提供者
|
||||||
|
*/
|
||||||
|
public val vendor: String
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 此前端实现的名称
|
||||||
|
*/
|
||||||
|
public val version: Semver
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 返回显示在 [MiraiConsole] 启动时的信息
|
||||||
|
*/
|
||||||
|
public fun render(): String = "Frontend ${name}: version ${version}, provided by $vendor"
|
||||||
|
}
|
@ -13,6 +13,7 @@ package net.mamoe.mirai.console
|
|||||||
|
|
||||||
import kotlinx.atomicfu.locks.withLock
|
import kotlinx.atomicfu.locks.withLock
|
||||||
import kotlinx.coroutines.CoroutineScope
|
import kotlinx.coroutines.CoroutineScope
|
||||||
|
import net.mamoe.mirai.Bot
|
||||||
import net.mamoe.mirai.console.MiraiConsoleImplementation.Companion.start
|
import net.mamoe.mirai.console.MiraiConsoleImplementation.Companion.start
|
||||||
import net.mamoe.mirai.console.command.ConsoleCommandSender
|
import net.mamoe.mirai.console.command.ConsoleCommandSender
|
||||||
import net.mamoe.mirai.console.data.PluginDataStorage
|
import net.mamoe.mirai.console.data.PluginDataStorage
|
||||||
@ -20,8 +21,11 @@ import net.mamoe.mirai.console.internal.MiraiConsoleImplementationBridge
|
|||||||
import net.mamoe.mirai.console.plugin.PluginLoader
|
import net.mamoe.mirai.console.plugin.PluginLoader
|
||||||
import net.mamoe.mirai.console.plugin.jvm.JarPluginLoader
|
import net.mamoe.mirai.console.plugin.jvm.JarPluginLoader
|
||||||
import net.mamoe.mirai.console.util.ConsoleExperimentalAPI
|
import net.mamoe.mirai.console.util.ConsoleExperimentalAPI
|
||||||
|
import net.mamoe.mirai.console.util.ConsoleInput
|
||||||
|
import net.mamoe.mirai.utils.BotConfiguration
|
||||||
|
import net.mamoe.mirai.utils.LoginSolver
|
||||||
import net.mamoe.mirai.utils.MiraiLogger
|
import net.mamoe.mirai.utils.MiraiLogger
|
||||||
import java.io.File
|
import java.nio.file.Path
|
||||||
import java.util.concurrent.locks.ReentrantLock
|
import java.util.concurrent.locks.ReentrantLock
|
||||||
import kotlin.annotation.AnnotationTarget.*
|
import kotlin.annotation.AnnotationTarget.*
|
||||||
import kotlin.coroutines.CoroutineContext
|
import kotlin.coroutines.CoroutineContext
|
||||||
@ -51,15 +55,16 @@ public interface MiraiConsoleImplementation : CoroutineScope {
|
|||||||
public override val coroutineContext: CoroutineContext
|
public override val coroutineContext: CoroutineContext
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Console 运行路径
|
* Console 运行根目录
|
||||||
|
* @see MiraiConsole.rootPath
|
||||||
*/
|
*/
|
||||||
public val rootDir: File
|
public val rootPath: Path
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Console 前端接口
|
* Console 前端接口
|
||||||
*/
|
*/
|
||||||
@ConsoleExperimentalAPI
|
@ConsoleExperimentalAPI
|
||||||
public val frontEnd: MiraiConsoleFrontEnd
|
public val frontEndDescription: MiraiConsoleFrontEndDescription
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 与前端交互所使用的 Logger
|
* 与前端交互所使用的 Logger
|
||||||
@ -79,6 +84,28 @@ public interface MiraiConsoleImplementation : CoroutineScope {
|
|||||||
public val configStorageForJarPluginLoader: PluginDataStorage
|
public val configStorageForJarPluginLoader: PluginDataStorage
|
||||||
public val dataStorageForBuiltIns: PluginDataStorage
|
public val dataStorageForBuiltIns: PluginDataStorage
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @see ConsoleInput 的实现
|
||||||
|
*/
|
||||||
|
public val consoleInput: ConsoleInput
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 创建一个 [LoginSolver]
|
||||||
|
*
|
||||||
|
* **调用备注**: 此函数通常在构造 [Bot] 实例时调用.
|
||||||
|
*
|
||||||
|
* @param requesterBot 请求者 [Bot.id]
|
||||||
|
* @param configuration 请求者 [Bot.configuration]
|
||||||
|
*
|
||||||
|
* @see LoginSolver.Default
|
||||||
|
*/
|
||||||
|
public fun createLoginSolver(requesterBot: Long, configuration: BotConfiguration): LoginSolver
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 创建一个 logger
|
||||||
|
*/
|
||||||
|
public fun newLogger(identity: String?): MiraiLogger
|
||||||
|
|
||||||
public companion object {
|
public companion object {
|
||||||
internal lateinit var instance: MiraiConsoleImplementation
|
internal lateinit var instance: MiraiConsoleImplementation
|
||||||
private val initLock = ReentrantLock()
|
private val initLock = ReentrantLock()
|
||||||
|
@ -19,6 +19,7 @@ import net.mamoe.mirai.console.MiraiConsole
|
|||||||
import net.mamoe.mirai.console.command.CommandManagerImpl.allRegisteredCommands
|
import net.mamoe.mirai.console.command.CommandManagerImpl.allRegisteredCommands
|
||||||
import net.mamoe.mirai.console.command.CommandManagerImpl.register
|
import net.mamoe.mirai.console.command.CommandManagerImpl.register
|
||||||
import net.mamoe.mirai.console.util.ConsoleExperimentalAPI
|
import net.mamoe.mirai.console.util.ConsoleExperimentalAPI
|
||||||
|
import net.mamoe.mirai.console.util.ConsoleInternalAPI
|
||||||
import net.mamoe.mirai.message.nextMessageOrNull
|
import net.mamoe.mirai.message.nextMessageOrNull
|
||||||
import net.mamoe.mirai.utils.secondsToMillis
|
import net.mamoe.mirai.utils.secondsToMillis
|
||||||
import kotlin.concurrent.thread
|
import kotlin.concurrent.thread
|
||||||
@ -79,6 +80,7 @@ public object BuiltInCommands {
|
|||||||
}.fold(
|
}.fold(
|
||||||
onSuccess = { sendMessage("mirai-console stopped successfully.") },
|
onSuccess = { sendMessage("mirai-console stopped successfully.") },
|
||||||
onFailure = {
|
onFailure = {
|
||||||
|
@OptIn(ConsoleInternalAPI::class)
|
||||||
MiraiConsole.mainLogger.error(it)
|
MiraiConsole.mainLogger.error(it)
|
||||||
sendMessage(it.localizedMessage ?: it.message ?: it.toString())
|
sendMessage(it.localizedMessage ?: it.message ?: it.toString())
|
||||||
}
|
}
|
||||||
|
@ -16,6 +16,7 @@ import net.mamoe.mirai.console.internal.data.MultiFilePluginDataStorageImpl
|
|||||||
import net.mamoe.mirai.console.plugin.jvm.JarPluginLoader
|
import net.mamoe.mirai.console.plugin.jvm.JarPluginLoader
|
||||||
import net.mamoe.mirai.console.plugin.jvm.JvmPlugin
|
import net.mamoe.mirai.console.plugin.jvm.JvmPlugin
|
||||||
import java.io.File
|
import java.io.File
|
||||||
|
import java.nio.file.Path
|
||||||
import kotlin.reflect.KClass
|
import kotlin.reflect.KClass
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -99,7 +100,7 @@ public interface MultiFilePluginDataStorage : PluginDataStorage {
|
|||||||
/**
|
/**
|
||||||
* 存放 [PluginData] 的目录.
|
* 存放 [PluginData] 的目录.
|
||||||
*/
|
*/
|
||||||
public val directory: File
|
public val directoryPath: Path
|
||||||
|
|
||||||
public companion object {
|
public companion object {
|
||||||
/**
|
/**
|
||||||
@ -109,7 +110,11 @@ public interface MultiFilePluginDataStorage : PluginDataStorage {
|
|||||||
*/
|
*/
|
||||||
@JvmStatic
|
@JvmStatic
|
||||||
@JvmName("create")
|
@JvmName("create")
|
||||||
public operator fun invoke(directory: File): MultiFilePluginDataStorage =
|
public operator fun invoke(directory: Path): MultiFilePluginDataStorage =
|
||||||
MultiFilePluginDataStorageImpl(directory)
|
MultiFilePluginDataStorageImpl(directory)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@get:JvmSynthetic
|
||||||
|
public inline val MultiFilePluginDataStorage.directory: File
|
||||||
|
get() = this.directoryPath.toFile()
|
@ -9,10 +9,13 @@
|
|||||||
|
|
||||||
package net.mamoe.mirai.console.internal
|
package net.mamoe.mirai.console.internal
|
||||||
|
|
||||||
import java.util.*
|
import com.vdurmont.semver4j.Semver
|
||||||
|
import java.time.Instant
|
||||||
|
|
||||||
internal object MiraiConsoleBuildConstants { // auto-filled on build (task :mirai-console:fillBuildConstants)
|
internal object MiraiConsoleBuildConstants { // auto-filled on build (task :mirai-console:fillBuildConstants)
|
||||||
@JvmStatic
|
@JvmStatic
|
||||||
val buildDate: Date = Date(1597935352287L) // 2020-08-20 22:55:52
|
val buildDate: Instant = Instant.ofEpochMilli(1597935352287L) // 2020-08-20 22:55:52
|
||||||
const val version: String = "1.0-M2-1"
|
|
||||||
|
@JvmStatic
|
||||||
|
val version: Semver = Semver("1.0-M2-1")
|
||||||
}
|
}
|
||||||
|
@ -11,12 +11,13 @@
|
|||||||
|
|
||||||
package net.mamoe.mirai.console.internal
|
package net.mamoe.mirai.console.internal
|
||||||
|
|
||||||
|
import com.vdurmont.semver4j.Semver
|
||||||
import kotlinx.coroutines.CoroutineScope
|
import kotlinx.coroutines.CoroutineScope
|
||||||
import kotlinx.coroutines.Job
|
import kotlinx.coroutines.Job
|
||||||
import net.mamoe.mirai.Bot
|
import net.mamoe.mirai.Bot
|
||||||
import net.mamoe.mirai.console.IllegalMiraiConsoleImplementationError
|
import net.mamoe.mirai.console.IllegalMiraiConsoleImplementationError
|
||||||
import net.mamoe.mirai.console.MiraiConsole
|
import net.mamoe.mirai.console.MiraiConsole
|
||||||
import net.mamoe.mirai.console.MiraiConsoleFrontEnd
|
import net.mamoe.mirai.console.MiraiConsoleFrontEndDescription
|
||||||
import net.mamoe.mirai.console.MiraiConsoleImplementation
|
import net.mamoe.mirai.console.MiraiConsoleImplementation
|
||||||
import net.mamoe.mirai.console.command.BuiltInCommands
|
import net.mamoe.mirai.console.command.BuiltInCommands
|
||||||
import net.mamoe.mirai.console.command.Command.Companion.primaryName
|
import net.mamoe.mirai.console.command.Command.Companion.primaryName
|
||||||
@ -30,12 +31,12 @@ import net.mamoe.mirai.console.plugin.PluginLoader
|
|||||||
import net.mamoe.mirai.console.plugin.PluginManager
|
import net.mamoe.mirai.console.plugin.PluginManager
|
||||||
import net.mamoe.mirai.console.plugin.center.PluginCenter
|
import net.mamoe.mirai.console.plugin.center.PluginCenter
|
||||||
import net.mamoe.mirai.console.util.ConsoleExperimentalAPI
|
import net.mamoe.mirai.console.util.ConsoleExperimentalAPI
|
||||||
import net.mamoe.mirai.utils.DefaultLogger
|
import net.mamoe.mirai.console.util.ConsoleInput
|
||||||
import net.mamoe.mirai.utils.MiraiLogger
|
import net.mamoe.mirai.console.util.ConsoleInternalAPI
|
||||||
import net.mamoe.mirai.utils.info
|
import net.mamoe.mirai.utils.*
|
||||||
import java.io.File
|
import java.nio.file.Path
|
||||||
import java.text.SimpleDateFormat
|
import java.text.SimpleDateFormat
|
||||||
import java.util.*
|
import java.time.Instant
|
||||||
import kotlin.coroutines.CoroutineContext
|
import kotlin.coroutines.CoroutineContext
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -45,36 +46,39 @@ internal object MiraiConsoleImplementationBridge : CoroutineScope, MiraiConsoleI
|
|||||||
MiraiConsole {
|
MiraiConsole {
|
||||||
override val pluginCenter: PluginCenter get() = CuiPluginCenter
|
override val pluginCenter: PluginCenter get() = CuiPluginCenter
|
||||||
|
|
||||||
private val instance: MiraiConsoleImplementation get() = MiraiConsoleImplementation.instance
|
private val instance: MiraiConsoleImplementation by MiraiConsoleImplementation.Companion::instance
|
||||||
override val buildDate: Date get() = MiraiConsoleBuildConstants.buildDate
|
override val buildDate: Instant by MiraiConsoleBuildConstants::buildDate
|
||||||
override val version: String get() = MiraiConsoleBuildConstants.version
|
override val version: Semver by MiraiConsoleBuildConstants::version
|
||||||
override val rootDir: File get() = instance.rootDir
|
override val rootPath: Path by instance::rootPath
|
||||||
override val frontEnd: MiraiConsoleFrontEnd get() = instance.frontEnd
|
override val frontEndDescription: MiraiConsoleFrontEndDescription by instance::frontEndDescription
|
||||||
|
|
||||||
@ConsoleExperimentalAPI
|
@OptIn(ConsoleInternalAPI::class)
|
||||||
override val mainLogger: MiraiLogger
|
override val mainLogger: MiraiLogger by instance::mainLogger
|
||||||
get() = instance.mainLogger
|
override val coroutineContext: CoroutineContext by instance::coroutineContext
|
||||||
override val coroutineContext: CoroutineContext get() = instance.coroutineContext
|
override val builtInPluginLoaders: List<PluginLoader<*, *>> by instance::builtInPluginLoaders
|
||||||
override val builtInPluginLoaders: List<PluginLoader<*, *>> get() = instance.builtInPluginLoaders
|
override val consoleCommandSender: ConsoleCommandSender by instance::consoleCommandSender
|
||||||
override val consoleCommandSender: ConsoleCommandSender get() = instance.consoleCommandSender
|
|
||||||
|
|
||||||
override val dataStorageForJarPluginLoader: PluginDataStorage get() = instance.dataStorageForJarPluginLoader
|
override val dataStorageForJarPluginLoader: PluginDataStorage by instance::dataStorageForJarPluginLoader
|
||||||
override val configStorageForJarPluginLoader: PluginDataStorage get() = instance.configStorageForJarPluginLoader
|
override val configStorageForJarPluginLoader: PluginDataStorage by instance::configStorageForJarPluginLoader
|
||||||
override val dataStorageForBuiltIns: PluginDataStorage get() = instance.dataStorageForBuiltIns
|
override val dataStorageForBuiltIns: PluginDataStorage by instance::dataStorageForBuiltIns
|
||||||
|
override val consoleInput: ConsoleInput by instance::consoleInput
|
||||||
|
|
||||||
|
override fun createLoginSolver(requesterBot: Long, configuration: BotConfiguration): LoginSolver =
|
||||||
|
instance.createLoginSolver(requesterBot, configuration)
|
||||||
|
|
||||||
init {
|
init {
|
||||||
DefaultLogger = { identity -> this.newLogger(identity) }
|
DefaultLogger = this::newLogger
|
||||||
}
|
}
|
||||||
|
|
||||||
@ConsoleExperimentalAPI
|
@ConsoleExperimentalAPI
|
||||||
override fun newLogger(identity: String?): MiraiLogger = frontEnd.loggerFor(identity)
|
override fun newLogger(identity: String?): MiraiLogger = instance.newLogger(identity)
|
||||||
|
|
||||||
@OptIn(ConsoleExperimentalAPI::class)
|
@OptIn(ConsoleExperimentalAPI::class)
|
||||||
internal fun doStart() {
|
internal fun doStart() {
|
||||||
val buildDateFormatted = SimpleDateFormat("yyyy-MM-dd").format(buildDate)
|
val buildDateFormatted = SimpleDateFormat("yyyy-MM-dd").format(buildDate)
|
||||||
mainLogger.info { "Starting mirai-console..." }
|
mainLogger.info { "Starting mirai-console..." }
|
||||||
mainLogger.info { "Backend: version $version, built on $buildDateFormatted." }
|
mainLogger.info { "Backend: version $version, built on $buildDateFormatted." }
|
||||||
mainLogger.info { "Frontend ${frontEnd.name}: version $version." }
|
mainLogger.info { frontEndDescription.render() }
|
||||||
|
|
||||||
if (coroutineContext[Job] == null) {
|
if (coroutineContext[Job] == null) {
|
||||||
throw IllegalMiraiConsoleImplementationError("The coroutineContext given to MiraiConsole must have a Job in it.")
|
throw IllegalMiraiConsoleImplementationError("The coroutineContext given to MiraiConsole must have a Job in it.")
|
||||||
|
@ -14,14 +14,15 @@ import net.mamoe.mirai.console.internal.command.qualifiedNameOrTip
|
|||||||
import net.mamoe.mirai.console.util.ConsoleExperimentalAPI
|
import net.mamoe.mirai.console.util.ConsoleExperimentalAPI
|
||||||
import net.mamoe.yamlkt.Yaml
|
import net.mamoe.yamlkt.Yaml
|
||||||
import java.io.File
|
import java.io.File
|
||||||
|
import java.nio.file.Path
|
||||||
import kotlin.reflect.KClass
|
import kotlin.reflect.KClass
|
||||||
|
|
||||||
@Suppress("RedundantVisibilityModifier") // might be public in the future
|
@Suppress("RedundantVisibilityModifier") // might be public in the future
|
||||||
internal open class MultiFilePluginDataStorageImpl(
|
internal open class MultiFilePluginDataStorageImpl(
|
||||||
public final override val directory: File
|
public final override val directoryPath: Path
|
||||||
) : PluginDataStorage, MultiFilePluginDataStorage {
|
) : PluginDataStorage, MultiFilePluginDataStorage {
|
||||||
init {
|
init {
|
||||||
directory.mkdir()
|
directoryPath.mkdir()
|
||||||
}
|
}
|
||||||
|
|
||||||
public override fun <T : PluginData> load(holder: PluginDataHolder, dataClass: Class<T>): T =
|
public override fun <T : PluginData> load(holder: PluginDataHolder, dataClass: Class<T>): T =
|
||||||
@ -53,17 +54,17 @@ internal open class MultiFilePluginDataStorageImpl(
|
|||||||
protected open fun getPluginDataFile(holder: PluginDataHolder, clazz: KClass<*>): File = with(clazz) {
|
protected open fun getPluginDataFile(holder: PluginDataHolder, clazz: KClass<*>): File = with(clazz) {
|
||||||
val name = findASerialName()
|
val name = findASerialName()
|
||||||
|
|
||||||
val dir = File(directory, holder.name)
|
val dir = directoryPath.resolve(holder.name)
|
||||||
if (dir.isFile) {
|
if (dir.isFile) {
|
||||||
error("Target directory ${dir.path} for holder $holder is occupied by a file therefore data $qualifiedNameOrTip can't be saved.")
|
error("Target directory $dir for holder $holder is occupied by a file therefore data $qualifiedNameOrTip can't be saved.")
|
||||||
}
|
}
|
||||||
dir.mkdir()
|
dir.mkdir()
|
||||||
|
|
||||||
val file = File(directory, name)
|
val file = directoryPath.resolve(name)
|
||||||
if (file.isDirectory) {
|
if (file.isDirectory) {
|
||||||
error("Target file $file is occupied by a directory therefore data $qualifiedNameOrTip can't be saved.")
|
error("Target file $file is occupied by a directory therefore data $qualifiedNameOrTip can't be saved.")
|
||||||
}
|
}
|
||||||
return file
|
return file.toFile()
|
||||||
}
|
}
|
||||||
|
|
||||||
@ConsoleExperimentalAPI
|
@ConsoleExperimentalAPI
|
||||||
@ -78,4 +79,8 @@ internal open class MultiFilePluginDataStorageImpl(
|
|||||||
file.writeText(Yaml.default.encodeToString(pluginData.updaterSerializer, Unit))
|
file.writeText(Yaml.default.encodeToString(pluginData.updaterSerializer, Unit))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
internal fun Path.mkdir(): Boolean = this.toFile().mkdir()
|
||||||
|
internal val Path.isFile: Boolean get() = this.toFile().isFile
|
||||||
|
internal val Path.isDirectory: Boolean get() = this.toFile().isDirectory
|
@ -13,6 +13,7 @@ import kotlinx.atomicfu.AtomicLong
|
|||||||
import kotlinx.atomicfu.locks.withLock
|
import kotlinx.atomicfu.locks.withLock
|
||||||
import kotlinx.coroutines.*
|
import kotlinx.coroutines.*
|
||||||
import net.mamoe.mirai.console.MiraiConsole
|
import net.mamoe.mirai.console.MiraiConsole
|
||||||
|
import net.mamoe.mirai.console.internal.data.mkdir
|
||||||
import net.mamoe.mirai.console.plugin.Plugin
|
import net.mamoe.mirai.console.plugin.Plugin
|
||||||
import net.mamoe.mirai.console.plugin.PluginManager
|
import net.mamoe.mirai.console.plugin.PluginManager
|
||||||
import net.mamoe.mirai.console.plugin.ResourceContainer.Companion.asResourceContainer
|
import net.mamoe.mirai.console.plugin.ResourceContainer.Companion.asResourceContainer
|
||||||
@ -20,8 +21,8 @@ import net.mamoe.mirai.console.plugin.jvm.JvmPlugin
|
|||||||
import net.mamoe.mirai.console.plugin.jvm.JvmPluginDescription
|
import net.mamoe.mirai.console.plugin.jvm.JvmPluginDescription
|
||||||
import net.mamoe.mirai.console.plugin.safeLoader
|
import net.mamoe.mirai.console.plugin.safeLoader
|
||||||
import net.mamoe.mirai.utils.MiraiLogger
|
import net.mamoe.mirai.utils.MiraiLogger
|
||||||
import java.io.File
|
|
||||||
import java.io.InputStream
|
import java.io.InputStream
|
||||||
|
import java.nio.file.Path
|
||||||
import java.util.concurrent.locks.ReentrantLock
|
import java.util.concurrent.locks.ReentrantLock
|
||||||
import kotlin.coroutines.CoroutineContext
|
import kotlin.coroutines.CoroutineContext
|
||||||
import kotlin.coroutines.EmptyCoroutineContext
|
import kotlin.coroutines.EmptyCoroutineContext
|
||||||
@ -60,11 +61,8 @@ internal abstract class JvmPluginInternal(
|
|||||||
|
|
||||||
private var firstRun = true
|
private var firstRun = true
|
||||||
|
|
||||||
final override val dataFolder: File by lazy {
|
final override val dataFolderPath: Path by lazy {
|
||||||
File(
|
PluginManager.pluginsPath.resolve(description.name).apply { mkdir() }
|
||||||
PluginManager.pluginsDataFolder,
|
|
||||||
description.name
|
|
||||||
).apply { mkdir() }
|
|
||||||
}
|
}
|
||||||
|
|
||||||
internal fun internalOnDisable() {
|
internal fun internalOnDisable() {
|
||||||
|
@ -16,14 +16,15 @@ import kotlinx.coroutines.InternalCoroutinesApi
|
|||||||
import kotlinx.coroutines.Job
|
import kotlinx.coroutines.Job
|
||||||
import net.mamoe.mirai.console.MiraiConsole
|
import net.mamoe.mirai.console.MiraiConsole
|
||||||
import net.mamoe.mirai.console.internal.data.cast
|
import net.mamoe.mirai.console.internal.data.cast
|
||||||
|
import net.mamoe.mirai.console.internal.data.mkdir
|
||||||
import net.mamoe.mirai.console.plugin.*
|
import net.mamoe.mirai.console.plugin.*
|
||||||
import net.mamoe.mirai.utils.info
|
import net.mamoe.mirai.utils.info
|
||||||
import java.io.File
|
import java.nio.file.Path
|
||||||
import java.util.concurrent.locks.ReentrantLock
|
import java.util.concurrent.locks.ReentrantLock
|
||||||
|
|
||||||
internal object PluginManagerImpl : PluginManager {
|
internal object PluginManagerImpl : PluginManager {
|
||||||
override val pluginsDir = File(MiraiConsole.rootDir, "plugins").apply { mkdir() }
|
override val pluginsPath: Path = MiraiConsole.rootPath.resolve("plugins").apply { mkdir() }
|
||||||
override val pluginsDataFolder = File(MiraiConsole.rootDir, "data").apply { mkdir() }
|
override val pluginsDataPath = MiraiConsole.rootPath.resolve("data").apply { mkdir() }
|
||||||
|
|
||||||
@Suppress("ObjectPropertyName")
|
@Suppress("ObjectPropertyName")
|
||||||
private val _pluginLoaders: MutableList<PluginLoader<*, *>> = mutableListOf()
|
private val _pluginLoaders: MutableList<PluginLoader<*, *>> = mutableListOf()
|
||||||
@ -45,15 +46,15 @@ internal object PluginManagerImpl : PluginManager {
|
|||||||
?.getDescription(this)
|
?.getDescription(this)
|
||||||
?: error("Plugin is unloaded")
|
?: error("Plugin is unloaded")
|
||||||
|
|
||||||
override fun registerPluginLoader(loader: PluginLoader<*, *>): Boolean = loadersLock.withLock {
|
override fun PluginLoader<*, *>.register(): Boolean = loadersLock.withLock {
|
||||||
if (_pluginLoaders.any { it::class == loader }) {
|
if (_pluginLoaders.any { it::class == this }) {
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
_pluginLoaders.add(loader)
|
_pluginLoaders.add(this)
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun unregisterPluginLoader(loader: PluginLoader<*, *>) = loadersLock.withLock {
|
override fun PluginLoader<*, *>.unregister() = loadersLock.withLock {
|
||||||
_pluginLoaders.remove(loader)
|
_pluginLoaders.remove(this)
|
||||||
}
|
}
|
||||||
|
|
||||||
init {
|
init {
|
||||||
|
@ -0,0 +1,15 @@
|
|||||||
|
package net.mamoe.mirai.console.internal.util
|
||||||
|
|
||||||
|
import kotlinx.coroutines.sync.Mutex
|
||||||
|
import kotlinx.coroutines.sync.withLock
|
||||||
|
import net.mamoe.mirai.console.MiraiConsole
|
||||||
|
import net.mamoe.mirai.console.util.ConsoleInput
|
||||||
|
import net.mamoe.mirai.console.util.requestInput
|
||||||
|
|
||||||
|
@Suppress("unused")
|
||||||
|
internal object ConsoleInputImpl : ConsoleInput {
|
||||||
|
private val inputLock = Mutex()
|
||||||
|
|
||||||
|
override suspend fun requestInput(hint: String): String =
|
||||||
|
inputLock.withLock { MiraiConsole.requestInput(hint) }
|
||||||
|
}
|
@ -0,0 +1,28 @@
|
|||||||
|
/*
|
||||||
|
* 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
|
||||||
|
*/
|
||||||
|
|
||||||
|
@file:Suppress("unused")
|
||||||
|
|
||||||
|
package net.mamoe.mirai.console.plugin
|
||||||
|
|
||||||
|
// TODO: 2020/8/22 Document PluginMissingDependencyException
|
||||||
|
public class PluginMissingDependencyException : PluginResolutionException {
|
||||||
|
public constructor() : super()
|
||||||
|
public constructor(message: String?) : super(message)
|
||||||
|
public constructor(message: String?, cause: Throwable?) : super(message, cause)
|
||||||
|
public constructor(cause: Throwable?) : super(cause)
|
||||||
|
}
|
||||||
|
|
||||||
|
// TODO: 2020/8/22 Document PluginResolutionException
|
||||||
|
public open class PluginResolutionException : Exception {
|
||||||
|
public constructor() : super()
|
||||||
|
public constructor(message: String?) : super(message)
|
||||||
|
public constructor(message: String?, cause: Throwable?) : super(message, cause)
|
||||||
|
public constructor(cause: Throwable?) : super(cause)
|
||||||
|
}
|
@ -14,11 +14,12 @@ package net.mamoe.mirai.console.plugin
|
|||||||
import net.mamoe.mirai.console.plugin.jvm.JvmPlugin
|
import net.mamoe.mirai.console.plugin.jvm.JvmPlugin
|
||||||
import net.mamoe.mirai.console.util.ConsoleExperimentalAPI
|
import net.mamoe.mirai.console.util.ConsoleExperimentalAPI
|
||||||
import java.io.File
|
import java.io.File
|
||||||
|
import java.nio.file.Path
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 表示一个 mirai-console 插件.
|
* 表示一个 mirai-console 插件.
|
||||||
*
|
*
|
||||||
* @see PluginDescription 插件描述
|
* @see PluginDescription 插件描述, 需由 [PluginLoader] 帮助提供([PluginLoader.description])
|
||||||
* @see JvmPlugin Java, Kotlin 或其他 JVM 平台插件
|
* @see JvmPlugin Java, Kotlin 或其他 JVM 平台插件
|
||||||
* @see PluginFileExtensions 支持文件系统存储的扩展
|
* @see PluginFileExtensions 支持文件系统存储的扩展
|
||||||
*
|
*
|
||||||
@ -71,13 +72,33 @@ public interface PluginFileExtensions {
|
|||||||
/**
|
/**
|
||||||
* 数据目录
|
* 数据目录
|
||||||
*/
|
*/
|
||||||
public val dataFolder: File
|
public val dataFolderPath: Path
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 从数据目录获取一个文件, 若不存在则创建文件.
|
* 从数据目录获取一个文件.
|
||||||
|
* @see dataFolderPath
|
||||||
*/
|
*/
|
||||||
@JvmDefault
|
@JvmDefault
|
||||||
public fun file(relativePath: String): File = File(dataFolder, relativePath).apply { createNewFile() }
|
public fun resolveDataFile(relativePath: String): File = dataFolderPath.resolve(relativePath).toFile()
|
||||||
|
|
||||||
// TODO: 2020/7/11 add `fun path(...): Path` ?
|
/**
|
||||||
|
* 从数据目录获取一个文件.
|
||||||
|
* @see dataFolderPath
|
||||||
|
*/
|
||||||
|
@JvmDefault
|
||||||
|
public fun resolveDataPath(relativePath: String): Path = dataFolderPath.resolve(relativePath)
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 从数据目录获取一个文件.
|
||||||
|
* @see dataFolderPath
|
||||||
|
*/
|
||||||
|
@JvmDefault
|
||||||
|
public fun resolveDataFile(relativePath: Path): File = dataFolderPath.resolve(relativePath).toFile()
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 从数据目录获取一个文件路径.
|
||||||
|
* @see dataFolderPath
|
||||||
|
*/
|
||||||
|
@JvmDefault
|
||||||
|
public fun resolveDataPath(relativePath: Path): Path = dataFolderPath.resolve(relativePath)
|
||||||
}
|
}
|
@ -21,18 +21,35 @@ import java.io.File
|
|||||||
*
|
*
|
||||||
* 有关插件的依赖和已加载的插件列表由 [PluginManager] 维护.
|
* 有关插件的依赖和已加载的插件列表由 [PluginManager] 维护.
|
||||||
*
|
*
|
||||||
|
* ### 内建加载器
|
||||||
|
* - [JarPluginLoader] Jar 插件加载器
|
||||||
|
*
|
||||||
|
* ### 扩展加载器
|
||||||
|
* 插件被允许扩展一个加载器。 可通过 [PluginManager.registerPluginLoader]
|
||||||
|
*
|
||||||
* @see JarPluginLoader Jar 插件加载器
|
* @see JarPluginLoader Jar 插件加载器
|
||||||
|
* @see PluginManager.registerPluginLoader 注册一个扩展的插件加载器
|
||||||
*/
|
*/
|
||||||
public interface PluginLoader<P : Plugin, D : PluginDescription> {
|
public interface PluginLoader<P : Plugin, D : PluginDescription> {
|
||||||
/**
|
/**
|
||||||
* 扫描并返回可以被加载的插件的 [描述][PluginDescription] 列表. 此函数只会被调用一次
|
* 扫描并返回可以被加载的插件的 [描述][PluginDescription] 列表.
|
||||||
|
*
|
||||||
|
* 在 console 启动时, [PluginManager] 会获取所有 [PluginDescription], 分析依赖关系, 确认插件加载顺序.
|
||||||
|
*
|
||||||
|
* **实现细节:** 此函数只*应该*在 console 启动时被调用一次. 但取决于前端实现不同, 或可能由于被一些插件需要, 此函数也可能会被多次调用.
|
||||||
*/
|
*/
|
||||||
public fun listPlugins(): List<D>
|
public fun listPlugins(): List<D>
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 获取此插件的描述
|
* 获取此插件的描述.
|
||||||
|
*
|
||||||
|
* **实现细节**: 此函数只允许抛出 [PluginLoadException] 作为正常失败原因, 其他任意异常都属于意外错误.
|
||||||
|
*
|
||||||
|
* 若在 console 启动并加载所有插件的过程中, 本函数抛出异常, 则会放弃此插件的加载, 并影响依赖它的其他插件.
|
||||||
*
|
*
|
||||||
* @throws PluginLoadException 在加载插件遇到意料之中的错误时抛出 (如无法读取插件信息等).
|
* @throws PluginLoadException 在加载插件遇到意料之中的错误时抛出 (如无法读取插件信息等).
|
||||||
|
*
|
||||||
|
* @see PluginDescription 插件描述
|
||||||
*/
|
*/
|
||||||
@get:JvmName("getPluginDescription")
|
@get:JvmName("getPluginDescription")
|
||||||
@get:Throws(PluginLoadException::class)
|
@get:Throws(PluginLoadException::class)
|
||||||
@ -41,11 +58,19 @@ public interface PluginLoader<P : Plugin, D : PluginDescription> {
|
|||||||
/**
|
/**
|
||||||
* 加载一个插件 (实例), 但不 [启用][enable] 它. 返回加载成功的主类实例
|
* 加载一个插件 (实例), 但不 [启用][enable] 它. 返回加载成功的主类实例
|
||||||
*
|
*
|
||||||
|
* **实现细节**: 此函数只允许抛出 [PluginLoadException] 作为正常失败原因, 其他任意异常都属于意外错误.
|
||||||
|
* 当异常发生时, 插件将会直接被放弃加载, 并影响依赖它的其他插件.
|
||||||
|
*
|
||||||
* @throws PluginLoadException 在加载插件遇到意料之中的错误时抛出 (如找不到主类等).
|
* @throws PluginLoadException 在加载插件遇到意料之中的错误时抛出 (如找不到主类等).
|
||||||
*/
|
*/
|
||||||
@Throws(PluginLoadException::class)
|
@Throws(PluginLoadException::class)
|
||||||
public fun load(description: D): P
|
public fun load(description: D): P
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 启用这个插件.
|
||||||
|
*
|
||||||
|
* **实现约定**: 若插件已经启用, 抛出
|
||||||
|
*/
|
||||||
public fun enable(plugin: P)
|
public fun enable(plugin: P)
|
||||||
public fun disable(plugin: P)
|
public fun disable(plugin: P)
|
||||||
}
|
}
|
||||||
@ -62,7 +87,7 @@ public open class PluginLoadException : RuntimeException {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* '/plugins' 目录中的插件的加载器. 每个加载器需绑定一个后缀.
|
* ['/plugins'][PluginManager.pluginsPath] 目录中的插件的加载器. 每个加载器需绑定一个后缀.
|
||||||
*
|
*
|
||||||
* @see AbstractFilePluginLoader 默认基础实现
|
* @see AbstractFilePluginLoader 默认基础实现
|
||||||
* @see JarPluginLoader 内建的 Jar (JVM) 插件加载器.
|
* @see JarPluginLoader 内建的 Jar (JVM) 插件加载器.
|
||||||
@ -75,13 +100,16 @@ public interface FilePluginLoader<P : Plugin, D : PluginDescription> : PluginLoa
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* [FilePluginLoader] 的默认基础实现
|
* [FilePluginLoader] 的默认基础实现.
|
||||||
|
*
|
||||||
|
* @see FilePluginLoader
|
||||||
*/
|
*/
|
||||||
public abstract class AbstractFilePluginLoader<P : Plugin, D : PluginDescription>(
|
public abstract class AbstractFilePluginLoader<P : Plugin, D : PluginDescription>(
|
||||||
public override val fileSuffix: String
|
public override val fileSuffix: String
|
||||||
) : FilePluginLoader<P, D> {
|
) : FilePluginLoader<P, D> {
|
||||||
private fun pluginsFilesSequence(): Sequence<File> =
|
private fun pluginsFilesSequence(): Sequence<File> =
|
||||||
PluginManager.pluginsDir.walk().filter { it.isFile && it.name.endsWith(fileSuffix, ignoreCase = true) }
|
PluginManager.pluginsPath.toFile().walk()
|
||||||
|
.filter { it.isFile && it.name.endsWith(fileSuffix, ignoreCase = true) }
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 读取扫描到的后缀与 [fileSuffix] 相同的文件中的 [PluginDescription]
|
* 读取扫描到的后缀与 [fileSuffix] 相同的文件中的 [PluginDescription]
|
||||||
|
@ -14,41 +14,74 @@ package net.mamoe.mirai.console.plugin
|
|||||||
import net.mamoe.mirai.console.MiraiConsole
|
import net.mamoe.mirai.console.MiraiConsole
|
||||||
import net.mamoe.mirai.console.internal.plugin.PluginManagerImpl
|
import net.mamoe.mirai.console.internal.plugin.PluginManagerImpl
|
||||||
import java.io.File
|
import java.io.File
|
||||||
|
import java.nio.file.Path
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 插件管理器.
|
* 插件管理器.
|
||||||
|
*
|
||||||
|
* [PluginManager] 管理所有 [插件加载器][PluginLoader], 储存对所有插件的引用 ([plugins]), 但不直接与 [插件实例][Plugin] 交互.
|
||||||
|
*
|
||||||
|
* 有关 [插件加载][PluginLoader.load], [插件启用][PluginLoader.enable] 等操作都由 [PluginLoader] 完成.
|
||||||
|
* [PluginManager] 仅作为一个联系所有 [插件加载器][PluginLoader], 使它们互相合作的桥梁.
|
||||||
|
*
|
||||||
|
* 若要主动加载一个插件, 请获取相应插件的 [PluginLoader], 然后使用 [PluginLoader.enable]
|
||||||
|
*
|
||||||
|
* @see Plugin 插件
|
||||||
|
* @see PluginLoader 插件加载器
|
||||||
*/
|
*/
|
||||||
public interface PluginManager {
|
public interface PluginManager {
|
||||||
/**
|
/**
|
||||||
* `$rootDir/plugins`
|
* 插件自身存放路径. 由前端决定具体路径.
|
||||||
|
*
|
||||||
|
* **实现细节**: 在 terminal 前端实现为 `$rootPath/plugins`
|
||||||
|
*
|
||||||
|
* @see pluginsFolder [File] 类型
|
||||||
*/
|
*/
|
||||||
public val pluginsDir: File
|
public val pluginsPath: Path
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* `$rootDir/data`
|
* 插件数据存放路径
|
||||||
|
*
|
||||||
|
* **实现细节**: 在 terminal 前端实现为 `$rootPath/data`
|
||||||
|
*
|
||||||
|
* @see pluginsDataFolder [File] 类型
|
||||||
*/
|
*/
|
||||||
public val pluginsDataFolder: File
|
public val pluginsDataPath: Path
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 已加载的插件列表
|
* 已加载的插件列表
|
||||||
|
*
|
||||||
|
* @return 只读列表
|
||||||
*/
|
*/
|
||||||
public val plugins: List<Plugin>
|
public val plugins: List<Plugin>
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 内建的插件加载器列表. 由 [MiraiConsole] 初始化.
|
* 内建的插件加载器列表. 由 [MiraiConsole] 初始化.
|
||||||
*
|
*
|
||||||
* @return 不可变的 list.
|
* @return 只读列表
|
||||||
*/
|
*/
|
||||||
public val builtInLoaders: List<PluginLoader<*, *>>
|
public val builtInLoaders: List<PluginLoader<*, *>>
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 由插件创建的 [PluginLoader]
|
* 由插件创建的 [PluginLoader]
|
||||||
|
*
|
||||||
|
* @return 只读列表
|
||||||
*/
|
*/
|
||||||
public val pluginLoaders: List<PluginLoader<*, *>>
|
public val pluginLoaders: List<PluginLoader<*, *>>
|
||||||
|
|
||||||
public fun registerPluginLoader(loader: PluginLoader<*, *>): Boolean
|
/**
|
||||||
|
* 注册一个扩展的插件加载器
|
||||||
|
*
|
||||||
|
* @see PluginLoader 插件加载器
|
||||||
|
*/
|
||||||
|
public fun PluginLoader<*, *>.register(): Boolean
|
||||||
|
|
||||||
public fun unregisterPluginLoader(loader: PluginLoader<*, *>): Boolean
|
/**
|
||||||
|
* 取消注册一个扩展的插件加载器
|
||||||
|
*
|
||||||
|
* @see PluginLoader 插件加载器
|
||||||
|
*/
|
||||||
|
public fun PluginLoader<*, *>.unregister(): Boolean
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 获取插件的 [描述][PluginDescription], 通过 [PluginLoader.getDescription]
|
* 获取插件的 [描述][PluginDescription], 通过 [PluginLoader.getDescription]
|
||||||
@ -56,26 +89,23 @@ public interface PluginManager {
|
|||||||
public val Plugin.description: PluginDescription
|
public val Plugin.description: PluginDescription
|
||||||
|
|
||||||
public companion object INSTANCE : PluginManager by PluginManagerImpl {
|
public companion object INSTANCE : PluginManager by PluginManagerImpl {
|
||||||
override val Plugin.description: PluginDescription get() = PluginManagerImpl.run { description }
|
// due to Kotlin's bug
|
||||||
|
public override val Plugin.description: PluginDescription get() = PluginManagerImpl.run { description }
|
||||||
|
public override fun PluginLoader<*, *>.register(): Boolean = PluginManagerImpl.run { register() }
|
||||||
|
public override fun PluginLoader<*, *>.unregister(): Boolean = PluginManagerImpl.run { unregister() }
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@JvmSynthetic
|
/**
|
||||||
public inline fun PluginLoader<*, *>.register(): Boolean = PluginManager.registerPluginLoader(this)
|
* @see PluginManager.pluginsPath
|
||||||
|
*/
|
||||||
|
@get:JvmSynthetic
|
||||||
|
public inline val PluginManager.pluginsFolder: File
|
||||||
|
get() = pluginsPath.toFile()
|
||||||
|
|
||||||
@JvmSynthetic
|
/**
|
||||||
public inline fun PluginLoader<*, *>.unregister(): Boolean = PluginManager.unregisterPluginLoader(this)
|
* @see PluginManager.pluginsDataPath
|
||||||
|
*/
|
||||||
public class PluginMissingDependencyException : PluginResolutionException {
|
@get:JvmSynthetic
|
||||||
public constructor() : super()
|
public inline val PluginManager.pluginsDataFolder: File
|
||||||
public constructor(message: String?) : super(message)
|
get() = pluginsDataPath.toFile()
|
||||||
public constructor(message: String?, cause: Throwable?) : super(message, cause)
|
|
||||||
public constructor(cause: Throwable?) : super(cause)
|
|
||||||
}
|
|
||||||
|
|
||||||
public open class PluginResolutionException : Exception {
|
|
||||||
public constructor() : super()
|
|
||||||
public constructor(message: String?) : super(message)
|
|
||||||
public constructor(message: String?, cause: Throwable?) : super(message, cause)
|
|
||||||
public constructor(cause: Throwable?) : super(cause)
|
|
||||||
}
|
|
@ -22,21 +22,53 @@ import java.io.File
|
|||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 插件描述
|
* 插件描述.
|
||||||
|
*
|
||||||
|
* @see Plugin
|
||||||
*/
|
*/
|
||||||
public interface PluginDescription {
|
public interface PluginDescription {
|
||||||
|
/**
|
||||||
|
* 插件类型. 将会决定加载顺序
|
||||||
|
*
|
||||||
|
* @see PluginKind
|
||||||
|
*/
|
||||||
public val kind: PluginKind
|
public val kind: PluginKind
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 插件名称.
|
||||||
|
*/
|
||||||
public val name: String
|
public val name: String
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 插件作者, 允许为空
|
||||||
|
*/
|
||||||
public val author: String
|
public val author: String
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 插件版本.
|
||||||
|
*
|
||||||
|
* 语法参考: ([语义化版本 2.0.0](https://semver.org/lang/zh-CN/))
|
||||||
|
*
|
||||||
|
* @see Semver 语义化版本
|
||||||
|
*/
|
||||||
public val version: Semver
|
public val version: Semver
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 插件信息, 允许为空
|
||||||
|
*/
|
||||||
public val info: String
|
public val info: String
|
||||||
|
|
||||||
/** 此插件依赖的其他插件, 将会在这些插件加载之后加载此插件 */
|
/**
|
||||||
|
* 此插件依赖的其他插件, 将会在这些插件加载之后加载此插件
|
||||||
|
*
|
||||||
|
* @see PluginDependency
|
||||||
|
*/
|
||||||
public val dependencies: List<@Serializable(with = PluginDependency.SmartSerializer::class) PluginDependency>
|
public val dependencies: List<@Serializable(with = PluginDependency.SmartSerializer::class) PluginDependency>
|
||||||
}
|
}
|
||||||
|
|
||||||
/** 插件类型 */
|
/**
|
||||||
|
* 插件类型
|
||||||
|
*/
|
||||||
@Serializable(with = PluginKind.AsStringSerializer::class)
|
@Serializable(with = PluginKind.AsStringSerializer::class)
|
||||||
public enum class PluginKind {
|
public enum class PluginKind {
|
||||||
/** 表示此插件提供一个 [PluginLoader], 应在加载其他 [NORMAL] 类型插件前加载 */
|
/** 表示此插件提供一个 [PluginLoader], 应在加载其他 [NORMAL] 类型插件前加载 */
|
||||||
@ -55,7 +87,11 @@ public enum class PluginKind {
|
|||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
/** 插件的一个依赖的信息 */
|
/**
|
||||||
|
* 插件的一个依赖的信息
|
||||||
|
*
|
||||||
|
* @see PluginDescription.dependencies
|
||||||
|
*/
|
||||||
@Serializable(with = PluginDependency.SmartSerializer::class)
|
@Serializable(with = PluginDependency.SmartSerializer::class)
|
||||||
public data class PluginDependency(
|
public data class PluginDependency(
|
||||||
/** 依赖插件名 */
|
/** 依赖插件名 */
|
||||||
|
@ -13,10 +13,9 @@
|
|||||||
|
|
||||||
package net.mamoe.mirai.console.util
|
package net.mamoe.mirai.console.util
|
||||||
|
|
||||||
import kotlinx.coroutines.sync.Mutex
|
|
||||||
import kotlinx.coroutines.sync.withLock
|
|
||||||
import net.mamoe.kjbb.JvmBlockingBridge
|
import net.mamoe.kjbb.JvmBlockingBridge
|
||||||
import net.mamoe.mirai.console.MiraiConsole
|
import net.mamoe.mirai.console.MiraiConsole
|
||||||
|
import net.mamoe.mirai.console.internal.util.ConsoleInputImpl
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Console 输入. 由于 console 接管了 [stdin][System. in], [readLine] 等操作需要在这里进行.
|
* Console 输入. 由于 console 接管了 [stdin][System. in], [readLine] 等操作需要在这里进行.
|
||||||
@ -28,16 +27,9 @@ public interface ConsoleInput {
|
|||||||
@JvmBlockingBridge
|
@JvmBlockingBridge
|
||||||
public suspend fun requestInput(hint: String): String
|
public suspend fun requestInput(hint: String): String
|
||||||
|
|
||||||
public companion object INSTANCE : ConsoleInput by ConsoleInputImpl {
|
public companion object INSTANCE : ConsoleInput by ConsoleInputImpl
|
||||||
@JvmSynthetic
|
|
||||||
public suspend inline fun MiraiConsole.requestInput(hint: String): String = ConsoleInput.requestInput(hint)
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Suppress("unused")
|
// don't move into INSTANCE, Compilation error
|
||||||
internal object ConsoleInputImpl : ConsoleInput {
|
@JvmSynthetic
|
||||||
private val inputLock = Mutex()
|
public suspend inline fun MiraiConsole.requestInput(hint: String): String = ConsoleInput.requestInput(hint)
|
||||||
|
|
||||||
override suspend fun requestInput(hint: String): String =
|
|
||||||
inputLock.withLock { MiraiConsole.frontEnd.requestInput(hint) }
|
|
||||||
}
|
|
@ -13,7 +13,6 @@ import kotlinx.coroutines.SupervisorJob
|
|||||||
import kotlinx.coroutines.runBlocking
|
import kotlinx.coroutines.runBlocking
|
||||||
import kotlinx.coroutines.suspendCancellableCoroutine
|
import kotlinx.coroutines.suspendCancellableCoroutine
|
||||||
import kotlinx.coroutines.withTimeout
|
import kotlinx.coroutines.withTimeout
|
||||||
import net.mamoe.mirai.Bot
|
|
||||||
import net.mamoe.mirai.console.MiraiConsoleImplementation.Companion.start
|
import net.mamoe.mirai.console.MiraiConsoleImplementation.Companion.start
|
||||||
import net.mamoe.mirai.console.command.CommandManager
|
import net.mamoe.mirai.console.command.CommandManager
|
||||||
import net.mamoe.mirai.console.command.ConsoleCommandSender
|
import net.mamoe.mirai.console.command.ConsoleCommandSender
|
||||||
@ -22,13 +21,15 @@ import net.mamoe.mirai.console.data.PluginDataStorage
|
|||||||
import net.mamoe.mirai.console.plugin.DeferredPluginLoader
|
import net.mamoe.mirai.console.plugin.DeferredPluginLoader
|
||||||
import net.mamoe.mirai.console.plugin.PluginLoader
|
import net.mamoe.mirai.console.plugin.PluginLoader
|
||||||
import net.mamoe.mirai.console.plugin.jvm.JarPluginLoader
|
import net.mamoe.mirai.console.plugin.jvm.JarPluginLoader
|
||||||
|
import net.mamoe.mirai.console.util.ConsoleExperimentalAPI
|
||||||
|
import net.mamoe.mirai.console.util.ConsoleInput
|
||||||
import net.mamoe.mirai.console.util.ConsoleInternalAPI
|
import net.mamoe.mirai.console.util.ConsoleInternalAPI
|
||||||
import net.mamoe.mirai.message.data.Message
|
import net.mamoe.mirai.message.data.Message
|
||||||
|
import net.mamoe.mirai.utils.BotConfiguration
|
||||||
import net.mamoe.mirai.utils.DefaultLogger
|
import net.mamoe.mirai.utils.DefaultLogger
|
||||||
import net.mamoe.mirai.utils.LoginSolver
|
import net.mamoe.mirai.utils.LoginSolver
|
||||||
import net.mamoe.mirai.utils.MiraiLogger
|
import net.mamoe.mirai.utils.MiraiLogger
|
||||||
import net.mamoe.mirai.utils.PlatformLogger
|
import java.nio.file.Path
|
||||||
import java.io.File
|
|
||||||
import kotlin.coroutines.Continuation
|
import kotlin.coroutines.Continuation
|
||||||
import kotlin.coroutines.CoroutineContext
|
import kotlin.coroutines.CoroutineContext
|
||||||
import kotlin.coroutines.resume
|
import kotlin.coroutines.resume
|
||||||
@ -37,22 +38,34 @@ import kotlin.test.assertNotNull
|
|||||||
@OptIn(ConsoleInternalAPI::class)
|
@OptIn(ConsoleInternalAPI::class)
|
||||||
fun initTestEnvironment() {
|
fun initTestEnvironment() {
|
||||||
object : MiraiConsoleImplementation {
|
object : MiraiConsoleImplementation {
|
||||||
override val rootDir: File = createTempDir()
|
override val rootPath: Path = createTempDir().toPath()
|
||||||
override val frontEnd: MiraiConsoleFrontEnd = object : MiraiConsoleFrontEnd {
|
|
||||||
override val name: String get() = "Test"
|
@ConsoleExperimentalAPI
|
||||||
override val version: String get() = "1.0.0"
|
override val frontEndDescription: MiraiConsoleFrontEndDescription
|
||||||
override fun loggerFor(identity: String?): MiraiLogger = PlatformLogger(identity)
|
get() = TODO("Not yet implemented")
|
||||||
override fun pushBot(bot: Bot) = println("pushBot: $bot")
|
|
||||||
override suspend fun requestInput(hint: String): String = readLine()!!
|
|
||||||
override fun createLoginSolver(): LoginSolver = LoginSolver.Default
|
|
||||||
}
|
|
||||||
override val mainLogger: MiraiLogger = DefaultLogger("main")
|
override val mainLogger: MiraiLogger = DefaultLogger("main")
|
||||||
override val builtInPluginLoaders: List<PluginLoader<*, *>> = listOf(DeferredPluginLoader { JarPluginLoader })
|
override val builtInPluginLoaders: List<PluginLoader<*, *>> = listOf(DeferredPluginLoader { JarPluginLoader })
|
||||||
override val consoleCommandSender: ConsoleCommandSender = object : ConsoleCommandSender() {
|
override val consoleCommandSender: ConsoleCommandSender = object : ConsoleCommandSender() {
|
||||||
override suspend fun sendMessage(message: Message) = println(message)
|
override suspend fun sendMessage(message: Message) = println(message)
|
||||||
}
|
}
|
||||||
override val dataStorageForJarPluginLoader: PluginDataStorage get() = MemoryPluginDataStorage()
|
override val dataStorageForJarPluginLoader: PluginDataStorage get() = MemoryPluginDataStorage()
|
||||||
|
override val configStorageForJarPluginLoader: PluginDataStorage
|
||||||
|
get() = TODO("Not yet implemented")
|
||||||
override val dataStorageForBuiltIns: PluginDataStorage get() = MemoryPluginDataStorage()
|
override val dataStorageForBuiltIns: PluginDataStorage get() = MemoryPluginDataStorage()
|
||||||
|
override val consoleInput: ConsoleInput = object : ConsoleInput {
|
||||||
|
override suspend fun requestInput(hint: String): String {
|
||||||
|
println(hint)
|
||||||
|
return readLine() ?: error("No stdin")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun createLoginSolver(requesterBot: Long, configuration: BotConfiguration): LoginSolver =
|
||||||
|
LoginSolver.Default
|
||||||
|
|
||||||
|
override fun newLogger(identity: String?): MiraiLogger {
|
||||||
|
return DefaultLogger(identity)
|
||||||
|
}
|
||||||
|
|
||||||
override val coroutineContext: CoroutineContext = SupervisorJob()
|
override val coroutineContext: CoroutineContext = SupervisorJob()
|
||||||
}.start()
|
}.start()
|
||||||
CommandManager
|
CommandManager
|
||||||
|
@ -17,6 +17,7 @@ import net.mamoe.mirai.console.command.CommandExecuteStatus
|
|||||||
import net.mamoe.mirai.console.command.CommandManager
|
import net.mamoe.mirai.console.command.CommandManager
|
||||||
import net.mamoe.mirai.console.command.CommandManager.INSTANCE.executeCommandDetailed
|
import net.mamoe.mirai.console.command.CommandManager.INSTANCE.executeCommandDetailed
|
||||||
import net.mamoe.mirai.console.util.ConsoleInternalAPI
|
import net.mamoe.mirai.console.util.ConsoleInternalAPI
|
||||||
|
import net.mamoe.mirai.console.util.requestInput
|
||||||
import net.mamoe.mirai.utils.DefaultLogger
|
import net.mamoe.mirai.utils.DefaultLogger
|
||||||
import org.fusesource.jansi.Ansi
|
import org.fusesource.jansi.Ansi
|
||||||
import java.util.*
|
import java.util.*
|
||||||
@ -50,11 +51,9 @@ internal fun startupConsoleThread() {
|
|||||||
val consoleLogger = DefaultLogger("console")
|
val consoleLogger = DefaultLogger("console")
|
||||||
while (isActive) {
|
while (isActive) {
|
||||||
try {
|
try {
|
||||||
val next = MiraiConsoleFrontEndPure.requestInput("").let {
|
val next = MiraiConsole.requestInput("").let {
|
||||||
when {
|
when {
|
||||||
it.startsWith(CommandManager.commandPrefix) -> {
|
it.startsWith(CommandManager.commandPrefix) -> it
|
||||||
it
|
|
||||||
}
|
|
||||||
it == "?" -> CommandManager.commandPrefix + BuiltInCommands.Help.primaryName
|
it == "?" -> CommandManager.commandPrefix + BuiltInCommands.Help.primaryName
|
||||||
else -> CommandManager.commandPrefix + it
|
else -> CommandManager.commandPrefix + it
|
||||||
}
|
}
|
||||||
@ -71,7 +70,7 @@ internal fun startupConsoleThread() {
|
|||||||
result.exception?.printStackTrace()
|
result.exception?.printStackTrace()
|
||||||
}
|
}
|
||||||
CommandExecuteStatus.COMMAND_NOT_FOUND -> {
|
CommandExecuteStatus.COMMAND_NOT_FOUND -> {
|
||||||
consoleLogger.warning("Unknown command: ${result.commandName}")
|
consoleLogger.warning("未知指令: ${result.commandName}, 输入 ? 获取帮助")
|
||||||
}
|
}
|
||||||
CommandExecuteStatus.PERMISSION_DENIED -> {
|
CommandExecuteStatus.PERMISSION_DENIED -> {
|
||||||
consoleLogger.warning("Permission denied.")
|
consoleLogger.warning("Permission denied.")
|
||||||
|
@ -22,20 +22,13 @@ package net.mamoe.mirai.console.pure
|
|||||||
|
|
||||||
//import net.mamoe.mirai.console.command.CommandManager
|
//import net.mamoe.mirai.console.command.CommandManager
|
||||||
//import net.mamoe.mirai.console.utils.MiraiConsoleFrontEnd
|
//import net.mamoe.mirai.console.utils.MiraiConsoleFrontEnd
|
||||||
import io.ktor.utils.io.concurrent.*
|
import com.vdurmont.semver4j.Semver
|
||||||
import kotlinx.coroutines.Dispatchers
|
import net.mamoe.mirai.console.MiraiConsoleFrontEndDescription
|
||||||
import kotlinx.coroutines.withContext
|
|
||||||
import net.mamoe.mirai.Bot
|
|
||||||
import net.mamoe.mirai.console.MiraiConsoleFrontEnd
|
|
||||||
import net.mamoe.mirai.console.util.ConsoleInternalAPI
|
import net.mamoe.mirai.console.util.ConsoleInternalAPI
|
||||||
import net.mamoe.mirai.utils.DefaultLoginSolver
|
|
||||||
import net.mamoe.mirai.utils.LoginSolver
|
|
||||||
import net.mamoe.mirai.utils.MiraiLogger
|
import net.mamoe.mirai.utils.MiraiLogger
|
||||||
import net.mamoe.mirai.utils.PlatformLogger
|
import net.mamoe.mirai.utils.PlatformLogger
|
||||||
import org.fusesource.jansi.Ansi
|
import org.fusesource.jansi.Ansi
|
||||||
import java.text.SimpleDateFormat
|
import java.text.SimpleDateFormat
|
||||||
import java.util.*
|
|
||||||
import java.util.concurrent.ConcurrentHashMap
|
|
||||||
|
|
||||||
private val ANSI_RESET = Ansi().reset().toString()
|
private val ANSI_RESET = Ansi().reset().toString()
|
||||||
|
|
||||||
@ -53,25 +46,7 @@ internal val LoggerCreator: (identity: String?) -> MiraiLogger = {
|
|||||||
*/
|
*/
|
||||||
@ConsoleInternalAPI
|
@ConsoleInternalAPI
|
||||||
@Suppress("unused")
|
@Suppress("unused")
|
||||||
object MiraiConsoleFrontEndPure : MiraiConsoleFrontEnd {
|
object MiraiConsoleFrontEndPure : MiraiConsoleFrontEndDescription {
|
||||||
private val globalLogger = LoggerCreator("Mirai")
|
|
||||||
private val cachedLoggers = ConcurrentHashMap<String, MiraiLogger>()
|
|
||||||
|
|
||||||
// companion object {
|
|
||||||
// ANSI color codes
|
|
||||||
const val COLOR_RED = "\u001b[38;5;196m"
|
|
||||||
const val COLOR_CYAN = "\u001b[38;5;87m"
|
|
||||||
const val COLOR_GREEN = "\u001b[38;5;82m"
|
|
||||||
|
|
||||||
// use a dark yellow(more like orange) instead of light one to save Solarized-light users
|
|
||||||
const val COLOR_YELLOW = "\u001b[38;5;220m"
|
|
||||||
const val COLOR_GREY = "\u001b[38;5;244m"
|
|
||||||
const val COLOR_BLUE = "\u001b[38;5;27m"
|
|
||||||
const val COLOR_NAVY = "\u001b[38;5;24m" // navy uniform blue
|
|
||||||
const val COLOR_PINK = "\u001b[38;5;207m"
|
|
||||||
const val COLOR_RESET = "\u001b[39;49m"
|
|
||||||
// }
|
|
||||||
|
|
||||||
internal val sdf by ThreadLocal.withInitial {
|
internal val sdf by ThreadLocal.withInitial {
|
||||||
// SimpleDateFormat not thread safe.
|
// SimpleDateFormat not thread safe.
|
||||||
SimpleDateFormat("HH:mm:ss")
|
SimpleDateFormat("HH:mm:ss")
|
||||||
@ -81,32 +56,9 @@ object MiraiConsoleFrontEndPure : MiraiConsoleFrontEnd {
|
|||||||
return this.get()
|
return this.get()
|
||||||
}
|
}
|
||||||
|
|
||||||
override val name: String
|
override val name: String get() = "Pure"
|
||||||
get() = "Pure"
|
override val version: Semver get() = net.mamoe.mirai.console.internal.MiraiConsoleBuildConstants.version
|
||||||
override val version: String
|
override val vendor: String get() = "Mamoe Technologies"
|
||||||
get() = net.mamoe.mirai.console.internal.MiraiConsoleBuildConstants.version
|
|
||||||
|
|
||||||
override fun loggerFor(identity: String?): MiraiLogger {
|
|
||||||
identity?.apply {
|
|
||||||
return cachedLoggers.computeIfAbsent(this, LoggerCreator)
|
|
||||||
}
|
|
||||||
return globalLogger
|
|
||||||
}
|
|
||||||
|
|
||||||
override fun pushBot(bot: Bot) {
|
|
||||||
}
|
|
||||||
|
|
||||||
override suspend fun requestInput(hint: String): String {
|
|
||||||
return ConsoleUtils.miraiLineReader(hint)
|
|
||||||
}
|
|
||||||
|
|
||||||
override fun createLoginSolver(): LoginSolver {
|
|
||||||
return DefaultLoginSolver(
|
|
||||||
input = suspend {
|
|
||||||
requestInput("LOGIN> ")
|
|
||||||
}
|
|
||||||
)
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@ -22,10 +22,12 @@
|
|||||||
package net.mamoe.mirai.console.pure
|
package net.mamoe.mirai.console.pure
|
||||||
|
|
||||||
|
|
||||||
|
import com.vdurmont.semver4j.Semver
|
||||||
import kotlinx.coroutines.CoroutineScope
|
import kotlinx.coroutines.CoroutineScope
|
||||||
import kotlinx.coroutines.SupervisorJob
|
import kotlinx.coroutines.SupervisorJob
|
||||||
import net.mamoe.mirai.console.ConsoleFrontEndImplementation
|
import net.mamoe.mirai.console.ConsoleFrontEndImplementation
|
||||||
import net.mamoe.mirai.console.MiraiConsoleFrontEnd
|
import net.mamoe.mirai.console.MiraiConsole
|
||||||
|
import net.mamoe.mirai.console.MiraiConsoleFrontEndDescription
|
||||||
import net.mamoe.mirai.console.MiraiConsoleImplementation
|
import net.mamoe.mirai.console.MiraiConsoleImplementation
|
||||||
import net.mamoe.mirai.console.command.ConsoleCommandSender
|
import net.mamoe.mirai.console.command.ConsoleCommandSender
|
||||||
import net.mamoe.mirai.console.data.MultiFilePluginDataStorage
|
import net.mamoe.mirai.console.data.MultiFilePluginDataStorage
|
||||||
@ -33,9 +35,15 @@ import net.mamoe.mirai.console.data.PluginDataStorage
|
|||||||
import net.mamoe.mirai.console.plugin.DeferredPluginLoader
|
import net.mamoe.mirai.console.plugin.DeferredPluginLoader
|
||||||
import net.mamoe.mirai.console.plugin.PluginLoader
|
import net.mamoe.mirai.console.plugin.PluginLoader
|
||||||
import net.mamoe.mirai.console.plugin.jvm.JarPluginLoader
|
import net.mamoe.mirai.console.plugin.jvm.JarPluginLoader
|
||||||
|
import net.mamoe.mirai.console.pure.ConsoleInputImpl.requestInput
|
||||||
|
import net.mamoe.mirai.console.util.ConsoleInput
|
||||||
import net.mamoe.mirai.console.util.ConsoleInternalAPI
|
import net.mamoe.mirai.console.util.ConsoleInternalAPI
|
||||||
|
import net.mamoe.mirai.utils.BotConfiguration
|
||||||
|
import net.mamoe.mirai.utils.DefaultLoginSolver
|
||||||
|
import net.mamoe.mirai.utils.LoginSolver
|
||||||
import net.mamoe.mirai.utils.MiraiLogger
|
import net.mamoe.mirai.utils.MiraiLogger
|
||||||
import java.io.File
|
import java.nio.file.Path
|
||||||
|
import java.nio.file.Paths
|
||||||
import java.util.*
|
import java.util.*
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -44,20 +52,43 @@ import java.util.*
|
|||||||
* @see MiraiConsoleFrontEndPure 前端实现
|
* @see MiraiConsoleFrontEndPure 前端实现
|
||||||
* @see MiraiConsolePureLoader CLI 入口点
|
* @see MiraiConsolePureLoader CLI 入口点
|
||||||
*/
|
*/
|
||||||
class MiraiConsoleImplementationPure
|
internal class MiraiConsoleImplementationPure
|
||||||
@JvmOverloads constructor(
|
@JvmOverloads constructor(
|
||||||
override val rootDir: File = File("."),
|
override val rootPath: Path = Paths.get("."),
|
||||||
override val builtInPluginLoaders: List<PluginLoader<*, *>> = Collections.unmodifiableList(
|
override val builtInPluginLoaders: List<PluginLoader<*, *>> = Collections.unmodifiableList(
|
||||||
listOf(DeferredPluginLoader { JarPluginLoader })
|
listOf(DeferredPluginLoader { JarPluginLoader })
|
||||||
),
|
),
|
||||||
override val frontEnd: MiraiConsoleFrontEnd = MiraiConsoleFrontEndPure,
|
override val frontEndDescription: MiraiConsoleFrontEndDescription = ConsoleFrontEndDescImpl,
|
||||||
override val mainLogger: MiraiLogger = frontEnd.loggerFor("main"),
|
|
||||||
override val consoleCommandSender: ConsoleCommandSender = ConsoleCommandSenderImpl,
|
override val consoleCommandSender: ConsoleCommandSender = ConsoleCommandSenderImpl,
|
||||||
override val dataStorageForJarPluginLoader: PluginDataStorage = MultiFilePluginDataStorage(File(rootDir, "data")),
|
override val dataStorageForJarPluginLoader: PluginDataStorage = MultiFilePluginDataStorage(rootPath.resolve("data")),
|
||||||
override val dataStorageForBuiltIns: PluginDataStorage = MultiFilePluginDataStorage(File(rootDir, "data"))
|
override val dataStorageForBuiltIns: PluginDataStorage = MultiFilePluginDataStorage(rootPath.resolve("data")),
|
||||||
|
override val configStorageForJarPluginLoader: PluginDataStorage = MultiFilePluginDataStorage(rootPath.resolve("config"))
|
||||||
) : MiraiConsoleImplementation, CoroutineScope by CoroutineScope(SupervisorJob()) {
|
) : MiraiConsoleImplementation, CoroutineScope by CoroutineScope(SupervisorJob()) {
|
||||||
init {
|
override val mainLogger: MiraiLogger by lazy {
|
||||||
rootDir.mkdir()
|
MiraiConsole.newLogger("main")
|
||||||
require(rootDir.isDirectory) { "rootDir ${rootDir.absolutePath} is not a directory" }
|
|
||||||
}
|
}
|
||||||
|
override val consoleInput: ConsoleInput get() = ConsoleInputImpl
|
||||||
|
|
||||||
|
override fun createLoginSolver(requesterBot: Long, configuration: BotConfiguration): LoginSolver {
|
||||||
|
return DefaultLoginSolver(input = { requestInput("LOGIN> ") })
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun newLogger(identity: String?): MiraiLogger = LoggerCreator(identity)
|
||||||
|
|
||||||
|
init {
|
||||||
|
with(rootPath.toFile()) {
|
||||||
|
mkdir()
|
||||||
|
require(isDirectory) { "rootDir $absolutePath is not a directory" }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private object ConsoleInputImpl : ConsoleInput {
|
||||||
|
override suspend fun requestInput(hint: String): String = ConsoleUtils.miraiLineReader(hint)
|
||||||
|
}
|
||||||
|
|
||||||
|
private object ConsoleFrontEndDescImpl : MiraiConsoleFrontEndDescription {
|
||||||
|
override val name: String get() = "Pure"
|
||||||
|
override val vendor: String get() = "Mamoe Technologies"
|
||||||
|
override val version: Semver = net.mamoe.mirai.console.internal.MiraiConsoleBuildConstants.version
|
||||||
}
|
}
|
@ -20,18 +20,9 @@
|
|||||||
|
|
||||||
package net.mamoe.mirai.console.pure
|
package net.mamoe.mirai.console.pure
|
||||||
|
|
||||||
import kotlinx.coroutines.runBlocking
|
|
||||||
import net.mamoe.mirai.alsoLogin
|
|
||||||
import net.mamoe.mirai.console.MiraiConsole
|
|
||||||
import net.mamoe.mirai.console.MiraiConsoleImplementation.Companion.start
|
import net.mamoe.mirai.console.MiraiConsoleImplementation.Companion.start
|
||||||
import net.mamoe.mirai.console.command.CommandManager.INSTANCE.register
|
|
||||||
import net.mamoe.mirai.console.command.CommandPermission
|
|
||||||
import net.mamoe.mirai.console.command.CommandSender
|
|
||||||
import net.mamoe.mirai.console.command.ConsoleCommandSender
|
import net.mamoe.mirai.console.command.ConsoleCommandSender
|
||||||
import net.mamoe.mirai.console.command.SimpleCommand
|
|
||||||
import net.mamoe.mirai.console.util.ConsoleInternalAPI
|
import net.mamoe.mirai.console.util.ConsoleInternalAPI
|
||||||
import net.mamoe.mirai.contact.Member
|
|
||||||
import net.mamoe.mirai.contact.nameCardOrNick
|
|
||||||
import net.mamoe.mirai.message.data.Message
|
import net.mamoe.mirai.message.data.Message
|
||||||
import net.mamoe.mirai.message.data.content
|
import net.mamoe.mirai.message.data.content
|
||||||
import net.mamoe.mirai.utils.DefaultLogger
|
import net.mamoe.mirai.utils.DefaultLogger
|
||||||
@ -44,29 +35,12 @@ object MiraiConsolePureLoader {
|
|||||||
@JvmStatic
|
@JvmStatic
|
||||||
fun main(args: Array<String>?) {
|
fun main(args: Array<String>?) {
|
||||||
startup()
|
startup()
|
||||||
YellowCommand.register()
|
|
||||||
runBlocking { MiraiConsole.addBot(1994701021, "Asd123456789asd").alsoLogin() }
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
object YellowCommand : SimpleCommand(
|
|
||||||
net.mamoe.mirai.console.command.ConsoleCommandOwner, "睡", "sleep",
|
|
||||||
prefixOptional = true,
|
|
||||||
description = "睡一个人",
|
|
||||||
permission = CommandPermission.Any
|
|
||||||
) {
|
|
||||||
@Handler
|
|
||||||
suspend fun CommandSender.handle(target: Member) {
|
|
||||||
target.mute(1)
|
|
||||||
|
|
||||||
sendMessage("${this.name} 睡了 ${target.nameCardOrNick}")
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
internal fun startup() {
|
internal fun startup() {
|
||||||
DefaultLogger = { MiraiConsoleFrontEndPure.loggerFor(it) }
|
|
||||||
overrideSTD()
|
|
||||||
MiraiConsoleImplementationPure().start()
|
MiraiConsoleImplementationPure().start()
|
||||||
|
overrideSTD()
|
||||||
startupConsoleThread()
|
startupConsoleThread()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user