Rework logger structure, extract pure frontend from miraio-console

This commit is contained in:
Him188 2020-05-14 09:02:02 +08:00
parent 33022deeae
commit 41112affa8
20 changed files with 194 additions and 511 deletions

View File

@ -10,190 +10,66 @@
package net.mamoe.mirai.console package net.mamoe.mirai.console
import kotlinx.coroutines.CoroutineScope import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.Job
import kotlinx.io.charsets.Charset import kotlinx.io.charsets.Charset
import net.mamoe.mirai.Bot import net.mamoe.mirai.Bot
import net.mamoe.mirai.console.command.CommandManager 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.plugins.PluginManager
import net.mamoe.mirai.console.utils.MiraiConsoleUI import net.mamoe.mirai.console.utils.MiraiConsoleFrontEnd
import net.mamoe.mirai.utils.SimpleLogger.LogPriority import net.mamoe.mirai.utils.MiraiLogger
import net.mamoe.mirai.utils.WeakRef
import java.io.ByteArrayOutputStream import java.io.ByteArrayOutputStream
import java.io.PrintStream import java.io.PrintStream
import kotlin.coroutines.EmptyCoroutineContext import kotlin.coroutines.CoroutineContext
// 前端使用
object MiraiConsole : CoroutineScope by CoroutineScope(EmptyCoroutineContext) { interface IMiraiConsole : CoroutineScope {
/** val build: String
* 发布的版本名 val version: String
*/
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
/** /**
* Console运行路径 * Console运行路径
*/ */
lateinit var path: String val path: String
internal set
/** /**
* Console前端接口 * Console前端接口
*/ */
lateinit var frontEnd: MiraiConsoleUI val frontEnd: MiraiConsoleFrontEnd
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!!)
}
/** /**
* 启动Console * 与前端交互所使用的Logger
*/ */
@JvmOverloads val mainLogger: MiraiLogger
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")
/* 依次启用功能 */ object MiraiConsole : CoroutineScope, IMiraiConsole {
DefaultCommands() private lateinit var instance: IMiraiConsole
PluginManager.loadPlugins()
CommandManager.start()
/* 通知启动完成 */ /** 由前端调用 */
logger("Mirai-console 启动完成") internal fun init(instance: IMiraiConsole) {
logger("\"login qqnumber qqpassword \" to login a bot") this.instance = instance
logger("\"login qq号 qq密码 \" 来登录一个BOT")
/* 尝试从系统配置自动登录 */
DefaultCommands.tryLoginAuto()
} }
/** override val build: String get() = instance.build
* 关闭 Console override val version: String get() = instance.version
*/ override val path: String get() = instance.path
fun stop() { 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() PluginManager.disablePlugins()
CommandManager.cancel() CommandManager.cancel()
try {
Bot.botInstances.forEach { Bot.botInstances.forEach {
it.close() 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 internal val Throwable.stacktraceString: String
get() = get() =
ByteArrayOutputStream().apply { ByteArrayOutputStream().apply {

View File

@ -55,9 +55,3 @@ interface PluginCenter {
val name:String val name:String
} }
internal fun handleReplacement(
){
}

View File

@ -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 package net.mamoe.mirai.console.command
import kotlinx.coroutines.* object CommandManager
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\"")

View File

@ -28,6 +28,7 @@ interface CommandSender {
suspend fun sendMessage(messageChain: Message) suspend fun sendMessage(messageChain: Message)
suspend fun sendMessage(message: String) suspend fun sendMessage(message: String)
/** /**
* 写入要发送的内容 所有内容最后会被以一条发出 * 写入要发送的内容 所有内容最后会被以一条发出
*/ */
@ -74,8 +75,8 @@ object ConsoleCommandSender : AbstractCommandSender() {
* 指向性CommandSender * 指向性CommandSender
* 你可以获得用户在和哪个Bot说指令 * 你可以获得用户在和哪个Bot说指令
*/ */
interface BotAware{ interface BotAware {
val bot:Bot val bot: Bot
} }
@ -83,7 +84,7 @@ interface BotAware{
* 联系人指令执行者. 代表由一个 QQ 用户私聊执行指令 * 联系人指令执行者. 代表由一个 QQ 用户私聊执行指令
*/ */
@Suppress("MemberVisibilityCanBePrivate") @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) { override suspend fun sendMessage(messageChain: Message) {
contact.sendMessage(messageChain) contact.sendMessage(messageChain)
} }
@ -100,4 +101,4 @@ open class GroupContactCommandSender(
bot: Bot, bot: Bot,
val realSender: Member, val realSender: Member,
subject: Contact subject: Contact
):ContactCommandSender(bot,subject) ) : ContactCommandSender(bot, subject)

View File

@ -27,7 +27,7 @@ import java.util.jar.JarFile
val PluginBase.description: PluginDescription get() = PluginManager.getPluginDescription(this) val PluginBase.description: PluginDescription get() = PluginManager.getPluginDescription(this)
object PluginManager { object PluginManagerOld {
/** /**
* 通过插件获取介绍 * 通过插件获取介绍
* @see description * @see description

View File

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

View File

@ -14,35 +14,20 @@ import net.mamoe.mirai.console.center.CuiPluginCenter
import net.mamoe.mirai.console.center.PluginCenter import net.mamoe.mirai.console.center.PluginCenter
import net.mamoe.mirai.utils.LoginSolver import net.mamoe.mirai.utils.LoginSolver
import net.mamoe.mirai.utils.MiraiInternalAPI import net.mamoe.mirai.utils.MiraiInternalAPI
import net.mamoe.mirai.utils.SimpleLogger.LogPriority import net.mamoe.mirai.utils.MiraiLogger
/** /**
* 只需要实现一个这个传入 MiraiConsole 就可以绑定 UI 层与 Console * 只需要实现一个这个传入 MiraiConsole 就可以绑定 UI 层与 Console
* 需要保证线程安全 * 需要保证线程安全
*/ */
@MiraiInternalAPI @MiraiInternalAPI
interface MiraiConsoleUI { interface MiraiConsoleFrontEnd {
/** /**
* 提供 [PluginCenter] * 提供 [PluginCenter]
*/ */
val pluginCenter: PluginCenter get() = CuiPluginCenter val pluginCenter: PluginCenter get() = CuiPluginCenter
/** fun loggerFor(identity: Long): MiraiLogger
* UI 层展示一条 log
*
* identitylog 所属的 screen, Main=0; Bot=Bot.uin
*/
fun pushLog(
identity: Long,
message: String
)
fun pushLog(
priority: LogPriority,
identityStr: String,
identity: Long,
message: String
)
/** /**
* UI 层准备接受新增的一个BOT * UI 层准备接受新增的一个BOT

View File

@ -10,7 +10,7 @@
package net.mamoe.mirai.console.graphical package net.mamoe.mirai.console.graphical
import net.mamoe.mirai.console.MiraiConsole 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.stylesheet.PrimaryStyleSheet
import net.mamoe.mirai.console.graphical.view.Decorator import net.mamoe.mirai.console.graphical.view.Decorator
import tornadofx.App import tornadofx.App
@ -28,7 +28,11 @@ class MiraiGraphicalUI : App(Decorator::class, PrimaryStyleSheet::class) {
override fun init() { override fun init() {
super.init() super.init()
MiraiConsole.start(find<MiraiGraphicalUIController>(),MiraiConsoleGraphicalLoader.coreVersion,MiraiConsoleGraphicalLoader.consoleVersion) MiraiConsole.start(
find<MiraiGraphicalFrontEndController>(),
MiraiConsoleGraphicalLoader.coreVersion,
MiraiConsoleGraphicalLoader.consoleVersion
)
} }
override fun stop() { override fun stop() {

View File

@ -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.InputDialog
import net.mamoe.mirai.console.graphical.view.dialog.VerificationCodeFragment import net.mamoe.mirai.console.graphical.view.dialog.VerificationCodeFragment
import net.mamoe.mirai.console.plugins.PluginManager 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.network.CustomLoginFailedException
import net.mamoe.mirai.utils.LoginSolver 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 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.text.SimpleDateFormat
import java.util.* import java.util.*
import kotlin.collections.List
import kotlin.collections.forEach
import kotlin.collections.mutableMapOf
import kotlin.collections.set
import kotlin.coroutines.resume import kotlin.coroutines.resume
class MiraiGraphicalUIController : Controller(), MiraiConsoleUI { class MiraiGraphicalFrontEndController : Controller(), MiraiConsoleFrontEnd {
private val settingModel = find<GlobalSettingModel>() private val settingModel = find<GlobalSettingModel>()
private val loginSolver = GraphicalLoginSolver() private val loginSolver = GraphicalLoginSolver()
@ -38,7 +47,7 @@ class MiraiGraphicalUIController : Controller(), MiraiConsoleUI {
private val consoleInfo = ConsoleInfo() private val consoleInfo = ConsoleInfo()
private val sdf by lazy { SimpleDateFormat("HH:mm:ss") } internal val sdf by lazy { SimpleDateFormat("HH:mm:ss") }
init { init {
// 监听插件重载事件以重新从console获取插件列表 // 监听插件重载事件以重新从console获取插件列表
@ -65,27 +74,23 @@ class MiraiGraphicalUIController : Controller(), MiraiConsoleUI {
fun sendCommand(command: String) = runCommand(ConsoleCommandSender, command) fun sendCommand(command: String) = runCommand(ConsoleCommandSender, command)
override fun pushLog(identity: Long, message: String) = Platform.runLater {
this.pushLog(LogPriority.INFO, "", identity, message)
}
// 修改interface之后用来暂时占位 private val mainLogger = SimpleLogger(null) { priority: LogPriority, message: String?, e: Throwable? ->
override fun pushLog(priority: LogPriority, identityStr: String, identity: Long, message: String) {
Platform.runLater { Platform.runLater {
val time = sdf.format(Date()) val time = sdf.format(Date())
mainLog.apply {
if (identity == 0L) { add("[$time] $message" to priority.name)
mainLog
} else {
cache[identity]?.logHistory
}?.apply {
add("[$time] $identityStr $message" to priority.name)
trim() 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 { override fun prePushBot(identity: Long) = Platform.runLater {
if (!cache.containsKey(identity)) { if (!cache.containsKey(identity)) {
BotModel(identity).also { BotModel(identity).also {
@ -123,13 +128,6 @@ class MiraiGraphicalUIController : Controller(), MiraiConsoleUI {
private fun getPluginsFromConsole(): ObservableList<PluginModel> = private fun getPluginsFromConsole(): ObservableList<PluginModel> =
PluginManager.getAllPluginDescriptions().map(::PluginModel).toObservable() PluginManager.getAllPluginDescriptions().map(::PluginModel).toObservable()
private fun ObservableList<*>.trim() {
while (size > settingModel.item.maxLongNum) {
this.removeAt(0)
}
}
fun checkUpdate(plugin: PluginModel) { fun checkUpdate(plugin: PluginModel) {
pluginList.forEach { pluginList.forEach {
if (it.name == plugin.name && it.author == plugin.author) { if (it.name == plugin.name && it.author == plugin.author) {
@ -153,6 +151,12 @@ class MiraiGraphicalUIController : Controller(), MiraiConsoleUI {
return false return false
} }
internal fun ObservableList<*>.trim() {
while (size > settingModel.item.maxLongNum) {
this.removeAt(0)
}
}
fun reloadPlugins() { fun reloadPlugins() {
with(PluginManager) { with(PluginManager) {

View File

@ -2,16 +2,30 @@ package net.mamoe.mirai.console.graphical.model
import javafx.beans.property.SimpleObjectProperty import javafx.beans.property.SimpleObjectProperty
import net.mamoe.mirai.Bot import net.mamoe.mirai.Bot
import tornadofx.ItemViewModel import net.mamoe.mirai.console.graphical.controller.MiraiGraphicalFrontEndController
import tornadofx.getValue import net.mamoe.mirai.utils.SimpleLogger
import tornadofx.observableListOf import tornadofx.*
import tornadofx.setValue import java.util.*
class BotModel(val uin: Long) { class BotModel(val uin: Long) {
val botProperty = SimpleObjectProperty<Bot>(null) val botProperty = SimpleObjectProperty<Bot>(null)
var bot: Bot by botProperty var bot: Bot by botProperty
val logHistory = observableListOf<Pair<String, String>>() 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>() val admins = observableListOf<Long>()
} }

View File

@ -4,7 +4,7 @@ import javafx.beans.property.SimpleStringProperty
import javafx.geometry.Pos import javafx.geometry.Pos
import javafx.scene.image.Image import javafx.scene.image.Image
import kotlinx.coroutines.runBlocking 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.stylesheet.LoginViewStyleSheet
import net.mamoe.mirai.console.graphical.util.jfxButton import net.mamoe.mirai.console.graphical.util.jfxButton
import net.mamoe.mirai.console.graphical.util.jfxPasswordfield import net.mamoe.mirai.console.graphical.util.jfxPasswordfield
@ -13,7 +13,7 @@ import tornadofx.*
class LoginView : View("CNM") { class LoginView : View("CNM") {
private val controller = find<MiraiGraphicalUIController>() private val controller = find<MiraiGraphicalFrontEndController>()
private val qq = SimpleStringProperty("") private val qq = SimpleStringProperty("")
private val psd = SimpleStringProperty("") private val psd = SimpleStringProperty("")

View File

@ -8,7 +8,7 @@ import javafx.scene.control.Button
import javafx.scene.control.TreeTableCell import javafx.scene.control.TreeTableCell
import kotlinx.coroutines.runBlocking import kotlinx.coroutines.runBlocking
import net.mamoe.mirai.console.MiraiConsole 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.event.ReloadEvent
import net.mamoe.mirai.console.graphical.model.PluginModel import net.mamoe.mirai.console.graphical.model.PluginModel
import net.mamoe.mirai.console.graphical.stylesheet.PluginViewStyleSheet import net.mamoe.mirai.console.graphical.stylesheet.PluginViewStyleSheet
@ -19,7 +19,7 @@ import tornadofx.*
class PluginsCenterView : View() { class PluginsCenterView : View() {
private val controller = find<MiraiGraphicalUIController>() private val controller = find<MiraiGraphicalFrontEndController>()
private val center get() = MiraiConsole.frontEnd.pluginCenter private val center get() = MiraiConsole.frontEnd.pluginCenter
private val plugins: ObservableList<PluginModel> = observableListOf() private val plugins: ObservableList<PluginModel> = observableListOf()

View File

@ -2,7 +2,7 @@ package net.mamoe.mirai.console.graphical.view
import com.jfoenix.controls.JFXTreeTableColumn import com.jfoenix.controls.JFXTreeTableColumn
import javafx.scene.control.TreeTableCell 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.model.PluginModel
import net.mamoe.mirai.console.graphical.stylesheet.PluginViewStyleSheet import net.mamoe.mirai.console.graphical.stylesheet.PluginViewStyleSheet
import net.mamoe.mirai.console.graphical.util.jfxButton import net.mamoe.mirai.console.graphical.util.jfxButton
@ -13,7 +13,7 @@ import tornadofx.visibleWhen
class PluginsView : View() { class PluginsView : View() {
private val controller = find<MiraiGraphicalUIController>() private val controller = find<MiraiGraphicalFrontEndController>()
val plugins = controller.pluginList val plugins = controller.pluginList
override val root = jfxTreeTableView(plugins) { override val root = jfxTreeTableView(plugins) {

View File

@ -14,14 +14,14 @@ import javafx.scene.input.KeyCode
import javafx.scene.layout.Priority import javafx.scene.layout.Priority
import javafx.stage.FileChooser import javafx.stage.FileChooser
import kotlinx.coroutines.runBlocking 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.model.BotModel
import net.mamoe.mirai.console.graphical.util.* import net.mamoe.mirai.console.graphical.util.*
import tornadofx.* import tornadofx.*
class PrimaryView : View() { class PrimaryView : View() {
private val controller = find<MiraiGraphicalUIController>() private val controller = find<MiraiGraphicalFrontEndController>()
private lateinit var mainTabPane: TabPane private lateinit var mainTabPane: TabPane
override val root = borderpane { override val root = borderpane {

View File

@ -1,7 +1,7 @@
package net.mamoe.mirai.console.graphical.view package net.mamoe.mirai.console.graphical.view
import javafx.geometry.Pos 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.model.GlobalSettingModel
import net.mamoe.mirai.console.graphical.util.jfxButton import net.mamoe.mirai.console.graphical.util.jfxButton
import net.mamoe.mirai.console.graphical.util.jfxTextfield import net.mamoe.mirai.console.graphical.util.jfxTextfield
@ -12,7 +12,7 @@ import java.io.File
class SettingsView : View() { class SettingsView : View() {
private val controller = find<MiraiGraphicalUIController>() private val controller = find<MiraiGraphicalFrontEndController>()
private val settingModel = find<GlobalSettingModel>() private val settingModel = find<GlobalSettingModel>()
override val root = vbox { override val root = vbox {

View File

@ -27,6 +27,7 @@ kotlin {
} }
dependencies { dependencies {
compileOnly(project(":mirai-console")) compileOnly(project(":mirai-console"))
compileOnly("net.mamoe:mirai-core:${Versions.Mirai.core}")
compileOnly(kotlin("stdlib")) // embedded by core compileOnly(kotlin("stdlib")) // embedded by core
testApi("net.mamoe:mirai-core-qqandroid:${Versions.Mirai.core}") testApi("net.mamoe:mirai-core-qqandroid:${Versions.Mirai.core}")

View File

@ -13,16 +13,17 @@ import kotlinx.coroutines.delay
import net.mamoe.mirai.Bot import net.mamoe.mirai.Bot
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
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.DefaultLoginSolver
import net.mamoe.mirai.utils.LoginSolver 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.text.SimpleDateFormat
import java.util.* import java.util.*
import kotlin.concurrent.thread import kotlin.concurrent.thread
class MiraiConsoleUIPure : MiraiConsoleUI { class MiraiConsoleFrontEndPure : MiraiConsoleFrontEnd {
private var requesting = false private var requesting = false
private var requestStr = "" private var requestStr = ""
@ -60,34 +61,12 @@ class MiraiConsoleUIPure : MiraiConsoleUI {
SimpleDateFormat("HH:mm:ss") 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") 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) { override fun prePushBot(identity: Long) {
} }
@ -100,8 +79,8 @@ class MiraiConsoleUIPure : MiraiConsoleUI {
} }
override suspend fun requestInput(hint:String): String { override suspend fun requestInput(hint: String): String {
if(hint.isNotEmpty()){ if (hint.isNotEmpty()) {
println("\u001b[0m " + sdf.format(Date()) + COLOR_PINK + " $hint") println("\u001b[0m " + sdf.format(Date()) + COLOR_PINK + " $hint")
} }
requesting = true requesting = true

View File

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

View File

@ -19,12 +19,12 @@ import kotlinx.coroutines.io.jvm.nio.copyTo
import kotlinx.coroutines.io.reader import kotlinx.coroutines.io.reader
import kotlinx.io.core.use import kotlinx.io.core.use
import net.mamoe.mirai.Bot import net.mamoe.mirai.Bot
import net.mamoe.mirai.console.MiraiConsoleTerminalUI.LoggerDrawer.cleanPage import net.mamoe.mirai.console.MiraiConsoleTerminalFrontEnd.LoggerDrawer.cleanPage
import net.mamoe.mirai.console.MiraiConsoleTerminalUI.LoggerDrawer.drawLog import net.mamoe.mirai.console.MiraiConsoleTerminalFrontEnd.LoggerDrawer.drawLog
import net.mamoe.mirai.console.MiraiConsoleTerminalUI.LoggerDrawer.redrawLogs import net.mamoe.mirai.console.MiraiConsoleTerminalFrontEnd.LoggerDrawer.redrawLogs
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
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.LoginSolver
import net.mamoe.mirai.utils.SimpleLogger.LogPriority import net.mamoe.mirai.utils.SimpleLogger.LogPriority
import java.awt.Image import java.awt.Image
@ -72,7 +72,7 @@ val String.isChineseChar: Boolean
} }
object MiraiConsoleTerminalUI : MiraiConsoleUI { object MiraiConsoleTerminalFrontEnd : MiraiConsoleFrontEnd {
const val cacheLogSize = 50 const val cacheLogSize = 50
var mainTitle = "Mirai Console v0.01 Core v0.15" var mainTitle = "Mirai Console v0.01 Core v0.15"

View File

@ -15,16 +15,16 @@ class MiraiConsoleTerminalLoader {
println("[MiraiConsoleTerminalLoader]: 将以Pure[兼容模式]启动Console") println("[MiraiConsoleTerminalLoader]: 将以Pure[兼容模式]启动Console")
MiraiConsole.start(MiraiConsoleUIPure()) MiraiConsole.start(MiraiConsoleUIPure())
} else { } else {
MiraiConsoleTerminalUI.start() MiraiConsoleTerminalFrontEnd.start()
thread { thread {
MiraiConsole.start( MiraiConsole.start(
MiraiConsoleTerminalUI MiraiConsoleTerminalFrontEnd
) )
} }
} }
Runtime.getRuntime().addShutdownHook(thread(start = false) { Runtime.getRuntime().addShutdownHook(thread(start = false) {
MiraiConsole.stop() MiraiConsole.stop()
MiraiConsoleTerminalUI.exit() MiraiConsoleTerminalFrontEnd.exit()
}) })
} }
} }