mirror of
https://github.com/mamoe/mirai.git
synced 2025-01-10 18:40:15 +08:00
Rework logger structure, extract pure frontend from miraio-console
This commit is contained in:
parent
33022deeae
commit
41112affa8
@ -10,190 +10,66 @@
|
||||
package net.mamoe.mirai.console
|
||||
|
||||
import kotlinx.coroutines.CoroutineScope
|
||||
import kotlinx.coroutines.Job
|
||||
import kotlinx.io.charsets.Charset
|
||||
import net.mamoe.mirai.Bot
|
||||
import net.mamoe.mirai.console.command.CommandManager
|
||||
import net.mamoe.mirai.console.command.DefaultCommands
|
||||
import net.mamoe.mirai.console.plugins.PluginManager
|
||||
import net.mamoe.mirai.console.utils.MiraiConsoleUI
|
||||
import net.mamoe.mirai.utils.SimpleLogger.LogPriority
|
||||
import net.mamoe.mirai.utils.WeakRef
|
||||
import net.mamoe.mirai.console.utils.MiraiConsoleFrontEnd
|
||||
import net.mamoe.mirai.utils.MiraiLogger
|
||||
import java.io.ByteArrayOutputStream
|
||||
import java.io.PrintStream
|
||||
import kotlin.coroutines.EmptyCoroutineContext
|
||||
import kotlin.coroutines.CoroutineContext
|
||||
|
||||
|
||||
object MiraiConsole : CoroutineScope by CoroutineScope(EmptyCoroutineContext) {
|
||||
/**
|
||||
* 发布的版本名
|
||||
*/
|
||||
const val build = "Pkmon"
|
||||
|
||||
lateinit var version: String
|
||||
internal set
|
||||
|
||||
/**
|
||||
* 获取从Console登陆上的Bot, Bots
|
||||
* */
|
||||
@Suppress("DEPRECATION")
|
||||
@Deprecated("use Bot.instances from mirai-core", replaceWith = ReplaceWith("Bot.instances", "net.mamoe.mirai.Bot"))
|
||||
val bots: List<WeakRef<Bot>>
|
||||
get() = Bot.instances
|
||||
|
||||
fun getBotOrNull(uin: Long): Bot? {
|
||||
return Bot.botInstances.firstOrNull { it.id == uin }
|
||||
}
|
||||
|
||||
class BotNotFoundException(uin: Long) : Exception("Bot $uin Not Found")
|
||||
|
||||
fun getBotOrThrow(uin: Long): Bot {
|
||||
return Bot.botInstances.firstOrNull { it.id == uin } ?: throw BotNotFoundException(uin)
|
||||
}
|
||||
|
||||
/**
|
||||
* 与前端交互所使用的Logger
|
||||
*/
|
||||
internal var logger = MiraiConsoleLogger
|
||||
// 前端使用
|
||||
interface IMiraiConsole : CoroutineScope {
|
||||
val build: String
|
||||
val version: String
|
||||
|
||||
/**
|
||||
* Console运行路径
|
||||
*/
|
||||
lateinit var path: String
|
||||
internal set
|
||||
val path: String
|
||||
|
||||
/**
|
||||
* Console前端接口
|
||||
*/
|
||||
lateinit var frontEnd: MiraiConsoleUI
|
||||
internal set
|
||||
|
||||
|
||||
private var started = false
|
||||
|
||||
|
||||
@Deprecated("for binary compatibility", level = DeprecationLevel.HIDDEN)
|
||||
@Suppress("FunctionName")
|
||||
@JvmSynthetic
|
||||
@JvmStatic
|
||||
fun /* synthetic */`start$default`(
|
||||
miraiConsole: MiraiConsole,
|
||||
miraiConsoleUI: MiraiConsoleUI?,
|
||||
string: String?,
|
||||
string2: String?,
|
||||
n: Int,
|
||||
@Suppress("UNUSED_PARAMETER") `object`: Any?
|
||||
) {
|
||||
@Suppress("NAME_SHADOWING")
|
||||
var string = string
|
||||
|
||||
@Suppress("NAME_SHADOWING")
|
||||
var string2 = string2
|
||||
if (n and 2 != 0) {
|
||||
string = "0.0.0"
|
||||
}
|
||||
if (n and 4 != 0) {
|
||||
string2 = "0.0.0"
|
||||
}
|
||||
miraiConsole.start(miraiConsoleUI!!, string!!, string2!!)
|
||||
}
|
||||
val frontEnd: MiraiConsoleFrontEnd
|
||||
|
||||
/**
|
||||
* 启动Console
|
||||
* 与前端交互所使用的Logger
|
||||
*/
|
||||
@JvmOverloads
|
||||
fun start(
|
||||
frontEnd: MiraiConsoleUI,
|
||||
coreVersion: String = "0.0.0",
|
||||
consoleVersion: String = "0.0.0",
|
||||
path: String = System.getProperty("user.dir")
|
||||
) {
|
||||
if (started) {
|
||||
return
|
||||
}
|
||||
started = true
|
||||
this.path = path
|
||||
/* 初始化前端 */
|
||||
this.version = consoleVersion
|
||||
this.frontEnd = frontEnd
|
||||
this.frontEnd.pushVersion(consoleVersion, build, coreVersion)
|
||||
logger("Mirai-console now running under $path")
|
||||
logger("Get news in github: https://github.com/mamoe/mirai")
|
||||
logger("Mirai为开源项目,请自觉遵守开源项目协议")
|
||||
logger("Powered by Mamoe Technologies and contributors")
|
||||
val mainLogger: MiraiLogger
|
||||
}
|
||||
|
||||
/* 依次启用功能 */
|
||||
DefaultCommands()
|
||||
PluginManager.loadPlugins()
|
||||
CommandManager.start()
|
||||
object MiraiConsole : CoroutineScope, IMiraiConsole {
|
||||
private lateinit var instance: IMiraiConsole
|
||||
|
||||
/* 通知启动完成 */
|
||||
logger("Mirai-console 启动完成")
|
||||
logger("\"login qqnumber qqpassword \" to login a bot")
|
||||
logger("\"login qq号 qq密码 \" 来登录一个BOT")
|
||||
|
||||
/* 尝试从系统配置自动登录 */
|
||||
DefaultCommands.tryLoginAuto()
|
||||
/** 由前端调用 */
|
||||
internal fun init(instance: IMiraiConsole) {
|
||||
this.instance = instance
|
||||
}
|
||||
|
||||
/**
|
||||
* 关闭 Console
|
||||
*/
|
||||
fun stop() {
|
||||
override val build: String get() = instance.build
|
||||
override val version: String get() = instance.version
|
||||
override val path: String get() = instance.path
|
||||
override val frontEnd: MiraiConsoleFrontEnd get() = instance.frontEnd
|
||||
override val mainLogger: MiraiLogger get() = instance.mainLogger
|
||||
override val coroutineContext: CoroutineContext get() = instance.coroutineContext
|
||||
|
||||
init {
|
||||
this.coroutineContext[Job]!!.invokeOnCompletion {
|
||||
PluginManager.disablePlugins()
|
||||
CommandManager.cancel()
|
||||
try {
|
||||
Bot.botInstances.forEach {
|
||||
it.close()
|
||||
}
|
||||
} catch (ignored: Exception) {
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
internal object MiraiConsoleLogger {
|
||||
operator fun invoke(any: Any?) {
|
||||
invoke(
|
||||
"[Mirai ${MiraiConsole.version} ${MiraiConsole.build}]",
|
||||
0L,
|
||||
any
|
||||
)
|
||||
}
|
||||
|
||||
operator fun invoke(e: Throwable?) {
|
||||
invoke(
|
||||
"[Mirai ${MiraiConsole.version} ${MiraiConsole.build}]",
|
||||
0L,
|
||||
e
|
||||
)
|
||||
}
|
||||
|
||||
operator fun invoke(priority: LogPriority, identityStr: String, identity: Long, any: Any? = null) {
|
||||
if (any != null) {
|
||||
MiraiConsole.frontEnd.pushLog(priority, identityStr, identity, "$any")
|
||||
}
|
||||
}
|
||||
|
||||
operator fun invoke(priority: LogPriority, identityStr: String, identity: Long, e: Throwable? = null) {
|
||||
if (e != null) {
|
||||
MiraiConsole.frontEnd.pushLog(priority, identityStr, identity, e.stacktraceString)
|
||||
}
|
||||
}
|
||||
|
||||
// 设置默认的pushLog输出为 INFO 类型
|
||||
operator fun invoke(identityStr: String, identity: Long, any: Any? = null) {
|
||||
if (any != null) {
|
||||
MiraiConsole.frontEnd.pushLog(LogPriority.INFO, identityStr, identity, "$any")
|
||||
}
|
||||
}
|
||||
|
||||
operator fun invoke(identityStr: String, identity: Long, e: Throwable? = null) {
|
||||
if (e != null) {
|
||||
MiraiConsole.frontEnd.pushLog(LogPriority.INFO, identityStr, identity, e.stacktraceString)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
internal val Throwable.stacktraceString: String
|
||||
get() =
|
||||
ByteArrayOutputStream().apply {
|
||||
|
@ -55,9 +55,3 @@ interface PluginCenter {
|
||||
|
||||
val name:String
|
||||
}
|
||||
|
||||
internal fun handleReplacement(
|
||||
|
||||
){
|
||||
|
||||
}
|
||||
|
@ -1,220 +1,3 @@
|
||||
/*
|
||||
* 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", "MemberVisibilityCanBePrivate")
|
||||
|
||||
package net.mamoe.mirai.console.command
|
||||
|
||||
import kotlinx.coroutines.*
|
||||
import kotlinx.coroutines.channels.Channel
|
||||
import net.mamoe.mirai.console.MiraiConsole
|
||||
import net.mamoe.mirai.console.command.CommandManager.processCommandQueue
|
||||
import net.mamoe.mirai.console.plugins.PluginBase
|
||||
import net.mamoe.mirai.console.plugins.PluginManager
|
||||
import java.util.concurrent.Executors
|
||||
|
||||
interface CommandOwner
|
||||
|
||||
class PluginCommandOwner(val pluginBase: PluginBase) : CommandOwner
|
||||
internal object ConsoleCommandOwner : CommandOwner
|
||||
|
||||
fun PluginBase.asCommandOwner() = PluginCommandOwner(this)
|
||||
|
||||
|
||||
object CommandManager : Job by {
|
||||
GlobalScope.launch(start = CoroutineStart.LAZY) {
|
||||
processCommandQueue()
|
||||
}
|
||||
}() {
|
||||
private val registeredCommand: MutableMap<String, Command> = mutableMapOf()
|
||||
val commands: Collection<Command> get() = registeredCommand.values
|
||||
private val pluginCommands: MutableMap<PluginBase, MutableCollection<Command>> = mutableMapOf()
|
||||
|
||||
internal fun clearPluginsCommands() {
|
||||
pluginCommands.values.forEach { a ->
|
||||
a.forEach {
|
||||
unregister(it)
|
||||
}
|
||||
}
|
||||
pluginCommands.clear()
|
||||
}
|
||||
|
||||
internal fun clearPluginCommands(
|
||||
pluginBase: PluginBase
|
||||
) {
|
||||
pluginCommands[pluginBase]?.run {
|
||||
this.forEach { unregister(it) }
|
||||
this.clear()
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 注册这个指令.
|
||||
*
|
||||
* @throws IllegalStateException 当已注册的指令与 [command] 重名时
|
||||
*/
|
||||
fun register(commandOwner: CommandOwner, command: Command) {
|
||||
val allNames = mutableListOf(command.name).also { it.addAll(command.alias) }
|
||||
allNames.forEach {
|
||||
if (registeredCommand.containsKey(it)) {
|
||||
error("Command Name(or Alias) $it is already registered, consider if same functional plugin was installed")
|
||||
}
|
||||
}
|
||||
allNames.forEach {
|
||||
registeredCommand[it] = command
|
||||
}
|
||||
if (commandOwner is PluginCommandOwner) {
|
||||
pluginCommands.computeIfAbsent(commandOwner.pluginBase) { mutableSetOf() }.add(command)
|
||||
}
|
||||
}
|
||||
|
||||
fun register(pluginBase: PluginBase, command: Command) =
|
||||
CommandManager.register(pluginBase.asCommandOwner(), command)
|
||||
|
||||
fun unregister(command: Command) {
|
||||
command.alias.forEach {
|
||||
registeredCommand.remove(it)
|
||||
}
|
||||
registeredCommand.remove(command.name)
|
||||
}
|
||||
|
||||
fun unregister(commandName: String): Boolean {
|
||||
return registeredCommand.remove(commandName) != null
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* 最基础的执行指令的方式
|
||||
* 指令将会被加入队列,依次执行
|
||||
*
|
||||
* @param sender 指令执行者, 可为 [ConsoleCommandSender] 或 [ContactCommandSender]
|
||||
*/
|
||||
fun runCommand(sender: CommandSender, command: String) {
|
||||
commandChannel.offer(
|
||||
FullCommand(sender, command)
|
||||
)
|
||||
}
|
||||
|
||||
/**
|
||||
* 插队异步执行一个指令并返回 [Deferred]
|
||||
*
|
||||
* @param sender 指令执行者, 可为 [ConsoleCommandSender] 或 [ContactCommandSender]
|
||||
* @see PluginBase.runCommandAsync 扩展
|
||||
*/
|
||||
fun runCommandAsync(pluginBase: PluginBase, sender: CommandSender, command: String): Deferred<Boolean> {
|
||||
return pluginBase.async {
|
||||
processCommand(sender, command)
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 插队执行一个指令并返回 [Deferred]
|
||||
*
|
||||
* @param sender 指令执行者, 可为 [ConsoleCommandSender] 或 [ContactCommandSender]
|
||||
* @see PluginBase.runCommandAsync 扩展
|
||||
*/
|
||||
@Suppress("KDocUnresolvedReference")
|
||||
suspend fun dispatchCommand(sender: CommandSender, command: String): Boolean {
|
||||
return processCommand(sender, command)
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* 阻塞当前线程, 插队执行一个指令
|
||||
*
|
||||
* @param sender 指令执行者, 可为 [ConsoleCommandSender] 或 [ContactCommandSender]
|
||||
*/
|
||||
// for java
|
||||
fun dispatchCommandBlocking(sender: CommandSender, command: String): Boolean =
|
||||
runBlocking { dispatchCommand(sender, command) }
|
||||
|
||||
|
||||
// internal
|
||||
|
||||
/**
|
||||
* 单线程执行指令
|
||||
*/
|
||||
private val commandDispatcher = Executors.newFixedThreadPool(1).asCoroutineDispatcher()
|
||||
|
||||
private suspend fun processCommand(sender: CommandSender, fullCommand: String): Boolean {
|
||||
return withContext(commandDispatcher) {
|
||||
processCommandImpl(sender, fullCommand)
|
||||
}
|
||||
}
|
||||
|
||||
private suspend fun processCommandImpl(sender: CommandSender, fullCommand: String): Boolean {
|
||||
val blocks = fullCommand.split(" ")
|
||||
val commandHead = blocks[0].removePrefix(DefaultCommands.commandPrefix)
|
||||
val args = blocks.drop(1)
|
||||
return registeredCommand[commandHead]?.run {
|
||||
try {
|
||||
return onCommand(sender, ArrayList(args)).also {
|
||||
if (it) {
|
||||
PluginManager.onCommand(this, sender, args)
|
||||
} else {
|
||||
sender.sendMessage(this.usage)
|
||||
}
|
||||
}
|
||||
} catch (e: Exception) {
|
||||
sender.sendMessage("在运行指令时出现了未知错误")
|
||||
MiraiConsole.logger(e)
|
||||
false
|
||||
} finally {
|
||||
(sender as AbstractCommandSender).flushMessage()
|
||||
}
|
||||
} ?: throw UnknownCommandException(commandHead)
|
||||
}
|
||||
|
||||
internal class FullCommand(
|
||||
val sender: CommandSender,
|
||||
val commandLine: String
|
||||
)
|
||||
|
||||
private val commandChannel: Channel<FullCommand> = Channel(Channel.UNLIMITED)
|
||||
|
||||
private tailrec suspend fun processCommandQueue() {
|
||||
val command = commandChannel.receive()
|
||||
try {
|
||||
processCommand(command.sender, command.commandLine)
|
||||
} catch (e: UnknownCommandException) {
|
||||
command.sender.sendMessage("未知指令 " + command.commandLine)
|
||||
(command.sender as? ConsoleCommandSender)?.apply {
|
||||
val cmd = command.commandLine.let {
|
||||
val index = it.indexOf(' ')
|
||||
if (index == -1) return@let it
|
||||
return@let it.substring(0, index)
|
||||
}
|
||||
if (cmd.isNotEmpty()) {
|
||||
if (cmd[0] == '/') {
|
||||
registeredCommand[cmd.substring(1)]?.let {
|
||||
sendMessage("请问你是不是想执行 `${command.commandLine.substring(1)}`")
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
} catch (e: Throwable) {//should never happen
|
||||
MiraiConsole.logger(e)
|
||||
}
|
||||
if (isActive) {
|
||||
processCommandQueue()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 插队异步执行一个指令并返回 [Deferred]
|
||||
*
|
||||
* @param sender 指令执行者, 可为 [ConsoleCommandSender] 或 [ContactCommandSender]
|
||||
* @see PluginBase.runCommandAsync 扩展
|
||||
*/
|
||||
fun PluginBase.runCommandAsync(sender: CommandSender, command: String): Deferred<Boolean> =
|
||||
CommandManager.runCommandAsync(this, sender, command)
|
||||
|
||||
|
||||
class UnknownCommandException(command: String) : Exception("unknown command \"$command\"")
|
||||
object CommandManager
|
@ -28,6 +28,7 @@ interface CommandSender {
|
||||
suspend fun sendMessage(messageChain: Message)
|
||||
|
||||
suspend fun sendMessage(message: String)
|
||||
|
||||
/**
|
||||
* 写入要发送的内容 所有内容最后会被以一条发出
|
||||
*/
|
||||
@ -74,8 +75,8 @@ object ConsoleCommandSender : AbstractCommandSender() {
|
||||
* 指向性CommandSender
|
||||
* 你可以获得用户在和哪个Bot说指令
|
||||
*/
|
||||
interface BotAware{
|
||||
val bot:Bot
|
||||
interface BotAware {
|
||||
val bot: Bot
|
||||
}
|
||||
|
||||
|
||||
@ -83,7 +84,7 @@ interface BotAware{
|
||||
* 联系人指令执行者. 代表由一个 QQ 用户私聊执行指令
|
||||
*/
|
||||
@Suppress("MemberVisibilityCanBePrivate")
|
||||
open class ContactCommandSender(override val bot: Bot, val contact: Contact) : AbstractCommandSender(), BotAware{
|
||||
open class ContactCommandSender(override val bot: Bot, val contact: Contact) : AbstractCommandSender(), BotAware {
|
||||
override suspend fun sendMessage(messageChain: Message) {
|
||||
contact.sendMessage(messageChain)
|
||||
}
|
||||
@ -100,4 +101,4 @@ open class GroupContactCommandSender(
|
||||
bot: Bot,
|
||||
val realSender: Member,
|
||||
subject: Contact
|
||||
):ContactCommandSender(bot,subject)
|
||||
) : ContactCommandSender(bot, subject)
|
@ -27,7 +27,7 @@ import java.util.jar.JarFile
|
||||
|
||||
val PluginBase.description: PluginDescription get() = PluginManager.getPluginDescription(this)
|
||||
|
||||
object PluginManager {
|
||||
object PluginManagerOld {
|
||||
/**
|
||||
* 通过插件获取介绍
|
||||
* @see description
|
@ -1,32 +0,0 @@
|
||||
/*
|
||||
* 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.pure
|
||||
|
||||
import net.mamoe.mirai.console.MiraiConsole
|
||||
import kotlin.concurrent.thread
|
||||
|
||||
class MiraiConsolePureLoader {
|
||||
companion object {
|
||||
@JvmStatic
|
||||
fun load(
|
||||
coreVersion: String,
|
||||
consoleVersion: String
|
||||
) {
|
||||
MiraiConsole.start(
|
||||
MiraiConsoleUIPure(),
|
||||
coreVersion,
|
||||
consoleVersion
|
||||
)
|
||||
Runtime.getRuntime().addShutdownHook(thread(start = false) {
|
||||
MiraiConsole.stop()
|
||||
})
|
||||
}
|
||||
}
|
||||
}
|
@ -14,35 +14,20 @@ import net.mamoe.mirai.console.center.CuiPluginCenter
|
||||
import net.mamoe.mirai.console.center.PluginCenter
|
||||
import net.mamoe.mirai.utils.LoginSolver
|
||||
import net.mamoe.mirai.utils.MiraiInternalAPI
|
||||
import net.mamoe.mirai.utils.SimpleLogger.LogPriority
|
||||
import net.mamoe.mirai.utils.MiraiLogger
|
||||
|
||||
/**
|
||||
* 只需要实现一个这个传入 MiraiConsole 就可以绑定 UI 层与 Console 层
|
||||
* 需要保证线程安全
|
||||
*/
|
||||
@MiraiInternalAPI
|
||||
interface MiraiConsoleUI {
|
||||
interface MiraiConsoleFrontEnd {
|
||||
/**
|
||||
* 提供 [PluginCenter]
|
||||
*/
|
||||
val pluginCenter: PluginCenter get() = CuiPluginCenter
|
||||
|
||||
/**
|
||||
* 让 UI 层展示一条 log
|
||||
*
|
||||
* identity:log 所属的 screen, Main=0; Bot=Bot.uin
|
||||
*/
|
||||
fun pushLog(
|
||||
identity: Long,
|
||||
message: String
|
||||
)
|
||||
|
||||
fun pushLog(
|
||||
priority: LogPriority,
|
||||
identityStr: String,
|
||||
identity: Long,
|
||||
message: String
|
||||
)
|
||||
fun loggerFor(identity: Long): MiraiLogger
|
||||
|
||||
/**
|
||||
* 让 UI 层准备接受新增的一个BOT
|
@ -10,7 +10,7 @@
|
||||
package net.mamoe.mirai.console.graphical
|
||||
|
||||
import net.mamoe.mirai.console.MiraiConsole
|
||||
import net.mamoe.mirai.console.graphical.controller.MiraiGraphicalUIController
|
||||
import net.mamoe.mirai.console.graphical.controller.MiraiGraphicalFrontEndController
|
||||
import net.mamoe.mirai.console.graphical.stylesheet.PrimaryStyleSheet
|
||||
import net.mamoe.mirai.console.graphical.view.Decorator
|
||||
import tornadofx.App
|
||||
@ -28,7 +28,11 @@ class MiraiGraphicalUI : App(Decorator::class, PrimaryStyleSheet::class) {
|
||||
|
||||
override fun init() {
|
||||
super.init()
|
||||
MiraiConsole.start(find<MiraiGraphicalUIController>(),MiraiConsoleGraphicalLoader.coreVersion,MiraiConsoleGraphicalLoader.consoleVersion)
|
||||
MiraiConsole.start(
|
||||
find<MiraiGraphicalFrontEndController>(),
|
||||
MiraiConsoleGraphicalLoader.coreVersion,
|
||||
MiraiConsoleGraphicalLoader.consoleVersion
|
||||
)
|
||||
}
|
||||
|
||||
override fun stop() {
|
||||
|
@ -16,16 +16,25 @@ import net.mamoe.mirai.console.graphical.model.*
|
||||
import net.mamoe.mirai.console.graphical.view.dialog.InputDialog
|
||||
import net.mamoe.mirai.console.graphical.view.dialog.VerificationCodeFragment
|
||||
import net.mamoe.mirai.console.plugins.PluginManager
|
||||
import net.mamoe.mirai.console.utils.MiraiConsoleUI
|
||||
import net.mamoe.mirai.console.utils.MiraiConsoleFrontEnd
|
||||
import net.mamoe.mirai.network.CustomLoginFailedException
|
||||
import net.mamoe.mirai.utils.LoginSolver
|
||||
import net.mamoe.mirai.utils.MiraiLogger
|
||||
import net.mamoe.mirai.utils.SimpleLogger
|
||||
import net.mamoe.mirai.utils.SimpleLogger.LogPriority
|
||||
import tornadofx.*
|
||||
import tornadofx.Controller
|
||||
import tornadofx.Scope
|
||||
import tornadofx.find
|
||||
import tornadofx.observableListOf
|
||||
import java.text.SimpleDateFormat
|
||||
import java.util.*
|
||||
import kotlin.collections.List
|
||||
import kotlin.collections.forEach
|
||||
import kotlin.collections.mutableMapOf
|
||||
import kotlin.collections.set
|
||||
import kotlin.coroutines.resume
|
||||
|
||||
class MiraiGraphicalUIController : Controller(), MiraiConsoleUI {
|
||||
class MiraiGraphicalFrontEndController : Controller(), MiraiConsoleFrontEnd {
|
||||
|
||||
private val settingModel = find<GlobalSettingModel>()
|
||||
private val loginSolver = GraphicalLoginSolver()
|
||||
@ -38,7 +47,7 @@ class MiraiGraphicalUIController : Controller(), MiraiConsoleUI {
|
||||
|
||||
private val consoleInfo = ConsoleInfo()
|
||||
|
||||
private val sdf by lazy { SimpleDateFormat("HH:mm:ss") }
|
||||
internal val sdf by lazy { SimpleDateFormat("HH:mm:ss") }
|
||||
|
||||
init {
|
||||
// 监听插件重载事件,以重新从console获取插件列表
|
||||
@ -65,27 +74,23 @@ class MiraiGraphicalUIController : Controller(), MiraiConsoleUI {
|
||||
|
||||
fun sendCommand(command: String) = runCommand(ConsoleCommandSender, command)
|
||||
|
||||
override fun pushLog(identity: Long, message: String) = Platform.runLater {
|
||||
this.pushLog(LogPriority.INFO, "", identity, message)
|
||||
}
|
||||
|
||||
// 修改interface之后用来暂时占位
|
||||
override fun pushLog(priority: LogPriority, identityStr: String, identity: Long, message: String) {
|
||||
private val mainLogger = SimpleLogger(null) { priority: LogPriority, message: String?, e: Throwable? ->
|
||||
Platform.runLater {
|
||||
|
||||
val time = sdf.format(Date())
|
||||
|
||||
if (identity == 0L) {
|
||||
mainLog
|
||||
} else {
|
||||
cache[identity]?.logHistory
|
||||
}?.apply {
|
||||
add("[$time] $identityStr $message" to priority.name)
|
||||
mainLog.apply {
|
||||
add("[$time] $message" to priority.name)
|
||||
trim()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
override fun loggerFor(identity: Long): MiraiLogger {
|
||||
return if (identity == 0L) return mainLogger
|
||||
else cache[identity]?.logger ?: kotlin.error("bot not found: $identity")
|
||||
}
|
||||
|
||||
|
||||
override fun prePushBot(identity: Long) = Platform.runLater {
|
||||
if (!cache.containsKey(identity)) {
|
||||
BotModel(identity).also {
|
||||
@ -123,13 +128,6 @@ class MiraiGraphicalUIController : Controller(), MiraiConsoleUI {
|
||||
private fun getPluginsFromConsole(): ObservableList<PluginModel> =
|
||||
PluginManager.getAllPluginDescriptions().map(::PluginModel).toObservable()
|
||||
|
||||
|
||||
private fun ObservableList<*>.trim() {
|
||||
while (size > settingModel.item.maxLongNum) {
|
||||
this.removeAt(0)
|
||||
}
|
||||
}
|
||||
|
||||
fun checkUpdate(plugin: PluginModel) {
|
||||
pluginList.forEach {
|
||||
if (it.name == plugin.name && it.author == plugin.author) {
|
||||
@ -153,6 +151,12 @@ class MiraiGraphicalUIController : Controller(), MiraiConsoleUI {
|
||||
return false
|
||||
}
|
||||
|
||||
internal fun ObservableList<*>.trim() {
|
||||
while (size > settingModel.item.maxLongNum) {
|
||||
this.removeAt(0)
|
||||
}
|
||||
}
|
||||
|
||||
fun reloadPlugins() {
|
||||
|
||||
with(PluginManager) {
|
@ -2,16 +2,30 @@ package net.mamoe.mirai.console.graphical.model
|
||||
|
||||
import javafx.beans.property.SimpleObjectProperty
|
||||
import net.mamoe.mirai.Bot
|
||||
import tornadofx.ItemViewModel
|
||||
import tornadofx.getValue
|
||||
import tornadofx.observableListOf
|
||||
import tornadofx.setValue
|
||||
import net.mamoe.mirai.console.graphical.controller.MiraiGraphicalFrontEndController
|
||||
import net.mamoe.mirai.utils.SimpleLogger
|
||||
import tornadofx.*
|
||||
import java.util.*
|
||||
|
||||
class BotModel(val uin: Long) {
|
||||
val botProperty = SimpleObjectProperty<Bot>(null)
|
||||
var bot: Bot by botProperty
|
||||
|
||||
val logHistory = observableListOf<Pair<String, String>>()
|
||||
val logger: SimpleLogger =
|
||||
SimpleLogger(uin.toString()) { priority: SimpleLogger.LogPriority, message: String?, e: Throwable? ->
|
||||
|
||||
val frontend = find<MiraiGraphicalFrontEndController>()
|
||||
|
||||
frontend.run {
|
||||
logHistory.apply {
|
||||
val time = sdf.format(Date())
|
||||
add("[$time] $uin $message" to priority.name)
|
||||
trim()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
val admins = observableListOf<Long>()
|
||||
}
|
||||
|
||||
|
@ -4,7 +4,7 @@ import javafx.beans.property.SimpleStringProperty
|
||||
import javafx.geometry.Pos
|
||||
import javafx.scene.image.Image
|
||||
import kotlinx.coroutines.runBlocking
|
||||
import net.mamoe.mirai.console.graphical.controller.MiraiGraphicalUIController
|
||||
import net.mamoe.mirai.console.graphical.controller.MiraiGraphicalFrontEndController
|
||||
import net.mamoe.mirai.console.graphical.stylesheet.LoginViewStyleSheet
|
||||
import net.mamoe.mirai.console.graphical.util.jfxButton
|
||||
import net.mamoe.mirai.console.graphical.util.jfxPasswordfield
|
||||
@ -13,7 +13,7 @@ import tornadofx.*
|
||||
|
||||
class LoginView : View("CNM") {
|
||||
|
||||
private val controller = find<MiraiGraphicalUIController>()
|
||||
private val controller = find<MiraiGraphicalFrontEndController>()
|
||||
private val qq = SimpleStringProperty("")
|
||||
private val psd = SimpleStringProperty("")
|
||||
|
||||
|
@ -8,7 +8,7 @@ import javafx.scene.control.Button
|
||||
import javafx.scene.control.TreeTableCell
|
||||
import kotlinx.coroutines.runBlocking
|
||||
import net.mamoe.mirai.console.MiraiConsole
|
||||
import net.mamoe.mirai.console.graphical.controller.MiraiGraphicalUIController
|
||||
import net.mamoe.mirai.console.graphical.controller.MiraiGraphicalFrontEndController
|
||||
import net.mamoe.mirai.console.graphical.event.ReloadEvent
|
||||
import net.mamoe.mirai.console.graphical.model.PluginModel
|
||||
import net.mamoe.mirai.console.graphical.stylesheet.PluginViewStyleSheet
|
||||
@ -19,7 +19,7 @@ import tornadofx.*
|
||||
|
||||
class PluginsCenterView : View() {
|
||||
|
||||
private val controller = find<MiraiGraphicalUIController>()
|
||||
private val controller = find<MiraiGraphicalFrontEndController>()
|
||||
private val center get() = MiraiConsole.frontEnd.pluginCenter
|
||||
private val plugins: ObservableList<PluginModel> = observableListOf()
|
||||
|
||||
|
@ -2,7 +2,7 @@ package net.mamoe.mirai.console.graphical.view
|
||||
|
||||
import com.jfoenix.controls.JFXTreeTableColumn
|
||||
import javafx.scene.control.TreeTableCell
|
||||
import net.mamoe.mirai.console.graphical.controller.MiraiGraphicalUIController
|
||||
import net.mamoe.mirai.console.graphical.controller.MiraiGraphicalFrontEndController
|
||||
import net.mamoe.mirai.console.graphical.model.PluginModel
|
||||
import net.mamoe.mirai.console.graphical.stylesheet.PluginViewStyleSheet
|
||||
import net.mamoe.mirai.console.graphical.util.jfxButton
|
||||
@ -13,7 +13,7 @@ import tornadofx.visibleWhen
|
||||
|
||||
class PluginsView : View() {
|
||||
|
||||
private val controller = find<MiraiGraphicalUIController>()
|
||||
private val controller = find<MiraiGraphicalFrontEndController>()
|
||||
val plugins = controller.pluginList
|
||||
|
||||
override val root = jfxTreeTableView(plugins) {
|
||||
|
@ -14,14 +14,14 @@ import javafx.scene.input.KeyCode
|
||||
import javafx.scene.layout.Priority
|
||||
import javafx.stage.FileChooser
|
||||
import kotlinx.coroutines.runBlocking
|
||||
import net.mamoe.mirai.console.graphical.controller.MiraiGraphicalUIController
|
||||
import net.mamoe.mirai.console.graphical.controller.MiraiGraphicalFrontEndController
|
||||
import net.mamoe.mirai.console.graphical.model.BotModel
|
||||
import net.mamoe.mirai.console.graphical.util.*
|
||||
import tornadofx.*
|
||||
|
||||
class PrimaryView : View() {
|
||||
|
||||
private val controller = find<MiraiGraphicalUIController>()
|
||||
private val controller = find<MiraiGraphicalFrontEndController>()
|
||||
private lateinit var mainTabPane: TabPane
|
||||
|
||||
override val root = borderpane {
|
||||
|
@ -1,7 +1,7 @@
|
||||
package net.mamoe.mirai.console.graphical.view
|
||||
|
||||
import javafx.geometry.Pos
|
||||
import net.mamoe.mirai.console.graphical.controller.MiraiGraphicalUIController
|
||||
import net.mamoe.mirai.console.graphical.controller.MiraiGraphicalFrontEndController
|
||||
import net.mamoe.mirai.console.graphical.model.GlobalSettingModel
|
||||
import net.mamoe.mirai.console.graphical.util.jfxButton
|
||||
import net.mamoe.mirai.console.graphical.util.jfxTextfield
|
||||
@ -12,7 +12,7 @@ import java.io.File
|
||||
|
||||
class SettingsView : View() {
|
||||
|
||||
private val controller = find<MiraiGraphicalUIController>()
|
||||
private val controller = find<MiraiGraphicalFrontEndController>()
|
||||
private val settingModel = find<GlobalSettingModel>()
|
||||
|
||||
override val root = vbox {
|
||||
|
@ -27,6 +27,7 @@ kotlin {
|
||||
}
|
||||
dependencies {
|
||||
compileOnly(project(":mirai-console"))
|
||||
compileOnly("net.mamoe:mirai-core:${Versions.Mirai.core}")
|
||||
compileOnly(kotlin("stdlib")) // embedded by core
|
||||
|
||||
testApi("net.mamoe:mirai-core-qqandroid:${Versions.Mirai.core}")
|
||||
|
@ -13,16 +13,17 @@ import kotlinx.coroutines.delay
|
||||
import net.mamoe.mirai.Bot
|
||||
import net.mamoe.mirai.console.command.CommandManager
|
||||
import net.mamoe.mirai.console.command.ConsoleCommandSender
|
||||
import net.mamoe.mirai.console.utils.MiraiConsoleUI
|
||||
import net.mamoe.mirai.console.utils.MiraiConsoleFrontEnd
|
||||
import net.mamoe.mirai.utils.DefaultLogger
|
||||
import net.mamoe.mirai.utils.DefaultLoginSolver
|
||||
import net.mamoe.mirai.utils.LoginSolver
|
||||
import net.mamoe.mirai.utils.SimpleLogger.LogPriority
|
||||
import net.mamoe.mirai.utils.MiraiLogger
|
||||
import java.text.SimpleDateFormat
|
||||
import java.util.*
|
||||
import kotlin.concurrent.thread
|
||||
|
||||
|
||||
class MiraiConsoleUIPure : MiraiConsoleUI {
|
||||
class MiraiConsoleFrontEndPure : MiraiConsoleFrontEnd {
|
||||
private var requesting = false
|
||||
private var requestStr = ""
|
||||
|
||||
@ -60,34 +61,12 @@ class MiraiConsoleUIPure : MiraiConsoleUI {
|
||||
SimpleDateFormat("HH:mm:ss")
|
||||
}
|
||||
|
||||
override fun pushLog(identity: Long, message: String) {
|
||||
override val logger: MiraiLogger = DefaultLogger("Console") // CLI logger from mirai-core
|
||||
|
||||
fun pushLog(identity: Long, message: String) {
|
||||
println("\u001b[0m " + sdf.format(Date()) + " $message")
|
||||
}
|
||||
|
||||
override fun pushLog(priority: LogPriority, identityStr: String, identity: Long, message: String) {
|
||||
var priorityStr = "[${priority.name}]"
|
||||
/*
|
||||
* 通过ANSI控制码添加颜色
|
||||
* 更多的颜色定义在 [MiraiConsoleUIPure] 的 companion
|
||||
*/
|
||||
priorityStr = when (priority) {
|
||||
LogPriority.ERROR
|
||||
-> COLOR_RED + priorityStr + COLOR_RESET
|
||||
|
||||
LogPriority.WARNING
|
||||
-> COLOR_RED + priorityStr + COLOR_RESET
|
||||
|
||||
LogPriority.VERBOSE
|
||||
-> COLOR_NAVY + priorityStr + COLOR_RESET
|
||||
|
||||
LogPriority.DEBUG
|
||||
-> COLOR_PINK + priorityStr + COLOR_RESET
|
||||
|
||||
else -> priorityStr
|
||||
}
|
||||
println("\u001b[0m " + sdf.format(Date()) + " $priorityStr $identityStr ${message + COLOR_RESET}")
|
||||
}
|
||||
|
||||
override fun prePushBot(identity: Long) {
|
||||
|
||||
}
|
||||
@ -100,8 +79,8 @@ class MiraiConsoleUIPure : MiraiConsoleUI {
|
||||
|
||||
}
|
||||
|
||||
override suspend fun requestInput(hint:String): String {
|
||||
if(hint.isNotEmpty()){
|
||||
override suspend fun requestInput(hint: String): String {
|
||||
if (hint.isNotEmpty()) {
|
||||
println("\u001b[0m " + sdf.format(Date()) + COLOR_PINK + " $hint")
|
||||
}
|
||||
requesting = true
|
@ -0,0 +1,74 @@
|
||||
/*
|
||||
* 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.pure
|
||||
|
||||
import net.mamoe.mirai.console.MiraiConsole
|
||||
import net.mamoe.mirai.console.command.CommandManager
|
||||
import net.mamoe.mirai.console.command.DefaultCommands
|
||||
import net.mamoe.mirai.console.plugins.PluginManager
|
||||
import net.mamoe.mirai.console.utils.MiraiConsoleFrontEnd
|
||||
import kotlin.concurrent.thread
|
||||
|
||||
class MiraiConsolePureLoader {
|
||||
companion object {
|
||||
@JvmStatic
|
||||
fun load(
|
||||
coreVersion: String,
|
||||
consoleVersion: String
|
||||
) {
|
||||
start(
|
||||
MiraiConsoleFrontEndPure(),
|
||||
coreVersion,
|
||||
consoleVersion
|
||||
)
|
||||
Runtime.getRuntime().addShutdownHook(thread(start = false) {
|
||||
MiraiConsole.stop()
|
||||
})
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 启动 Console
|
||||
*/
|
||||
@JvmOverloads
|
||||
internal fun start(
|
||||
frontEnd: MiraiConsoleFrontEnd,
|
||||
coreVersion: String = "0.0.0",
|
||||
consoleVersion: String = "0.0.0",
|
||||
path: String = System.getProperty("user.dir")
|
||||
) {
|
||||
if (MiraiConsole.started) {
|
||||
return
|
||||
}
|
||||
MiraiConsole.started = true
|
||||
this.path = path
|
||||
/* 初始化前端 */
|
||||
this.version = consoleVersion
|
||||
this.frontEnd = frontEnd
|
||||
this.frontEnd.pushVersion(consoleVersion, MiraiConsole.build, coreVersion)
|
||||
logger("Mirai-console now running under $path")
|
||||
logger("Get news in github: https://github.com/mamoe/mirai")
|
||||
logger("Mirai为开源项目,请自觉遵守开源项目协议")
|
||||
logger("Powered by Mamoe Technologies and contributors")
|
||||
|
||||
/* 依次启用功能 */
|
||||
DefaultCommands()
|
||||
PluginManager.loadPlugins()
|
||||
CommandManager.start()
|
||||
|
||||
/* 通知启动完成 */
|
||||
logger("Mirai-console 启动完成")
|
||||
logger("\"login qqnumber qqpassword \" to login a bot")
|
||||
logger("\"login qq号 qq密码 \" 来登录一个BOT")
|
||||
|
||||
/* 尝试从系统配置自动登录 */
|
||||
DefaultCommands.tryLoginAuto()
|
||||
}
|
@ -19,12 +19,12 @@ import kotlinx.coroutines.io.jvm.nio.copyTo
|
||||
import kotlinx.coroutines.io.reader
|
||||
import kotlinx.io.core.use
|
||||
import net.mamoe.mirai.Bot
|
||||
import net.mamoe.mirai.console.MiraiConsoleTerminalUI.LoggerDrawer.cleanPage
|
||||
import net.mamoe.mirai.console.MiraiConsoleTerminalUI.LoggerDrawer.drawLog
|
||||
import net.mamoe.mirai.console.MiraiConsoleTerminalUI.LoggerDrawer.redrawLogs
|
||||
import net.mamoe.mirai.console.MiraiConsoleTerminalFrontEnd.LoggerDrawer.cleanPage
|
||||
import net.mamoe.mirai.console.MiraiConsoleTerminalFrontEnd.LoggerDrawer.drawLog
|
||||
import net.mamoe.mirai.console.MiraiConsoleTerminalFrontEnd.LoggerDrawer.redrawLogs
|
||||
import net.mamoe.mirai.console.command.CommandManager
|
||||
import net.mamoe.mirai.console.command.ConsoleCommandSender
|
||||
import net.mamoe.mirai.console.utils.MiraiConsoleUI
|
||||
import net.mamoe.mirai.console.utils.MiraiConsoleFrontEnd
|
||||
import net.mamoe.mirai.utils.LoginSolver
|
||||
import net.mamoe.mirai.utils.SimpleLogger.LogPriority
|
||||
import java.awt.Image
|
||||
@ -72,7 +72,7 @@ val String.isChineseChar: Boolean
|
||||
}
|
||||
|
||||
|
||||
object MiraiConsoleTerminalUI : MiraiConsoleUI {
|
||||
object MiraiConsoleTerminalFrontEnd : MiraiConsoleFrontEnd {
|
||||
const val cacheLogSize = 50
|
||||
var mainTitle = "Mirai Console v0.01 Core v0.15"
|
||||
|
@ -15,16 +15,16 @@ class MiraiConsoleTerminalLoader {
|
||||
println("[MiraiConsoleTerminalLoader]: 将以Pure[兼容模式]启动Console")
|
||||
MiraiConsole.start(MiraiConsoleUIPure())
|
||||
} else {
|
||||
MiraiConsoleTerminalUI.start()
|
||||
MiraiConsoleTerminalFrontEnd.start()
|
||||
thread {
|
||||
MiraiConsole.start(
|
||||
MiraiConsoleTerminalUI
|
||||
MiraiConsoleTerminalFrontEnd
|
||||
)
|
||||
}
|
||||
}
|
||||
Runtime.getRuntime().addShutdownHook(thread(start = false) {
|
||||
MiraiConsole.stop()
|
||||
MiraiConsoleTerminalUI.exit()
|
||||
MiraiConsoleTerminalFrontEnd.exit()
|
||||
})
|
||||
}
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user