diff --git a/frontend/mirai-console-pure/src/main/kotlin/net/mamoe/mirai/console/pure/ConsoleUtils.kt b/frontend/mirai-console-pure/src/main/kotlin/net/mamoe/mirai/console/pure/ConsoleUtils.kt new file mode 100644 index 000000000..a363e5e03 --- /dev/null +++ b/frontend/mirai-console-pure/src/main/kotlin/net/mamoe/mirai/console/pure/ConsoleUtils.kt @@ -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.pure + +import org.jline.reader.LineReader +import org.jline.reader.LineReaderBuilder +import org.jline.reader.impl.completer.NullCompleter +import org.jline.terminal.Terminal +import org.jline.terminal.TerminalBuilder + +object ConsoleUtils { + + val lineReader: LineReader + val terminal: Terminal + + init { + + val dumb = System.getProperty("java.class.path") + .contains("idea_rt.jar") || System.getProperty("mirai.idea") !== null + + terminal = TerminalBuilder.builder() + .dumb(dumb) + .build() + lineReader = LineReaderBuilder.builder() + .terminal(terminal) + .completer(NullCompleter()) + .build() + } +} \ No newline at end of file diff --git a/frontend/mirai-console-pure/src/main/kotlin/net/mamoe/mirai/console/pure/MiraiConsoleFrontEndPure.kt b/frontend/mirai-console-pure/src/main/kotlin/net/mamoe/mirai/console/pure/MiraiConsoleFrontEndPure.kt index e000b7a7d..39f329382 100644 --- a/frontend/mirai-console-pure/src/main/kotlin/net/mamoe/mirai/console/pure/MiraiConsoleFrontEndPure.kt +++ b/frontend/mirai-console-pure/src/main/kotlin/net/mamoe/mirai/console/pure/MiraiConsoleFrontEndPure.kt @@ -9,20 +9,86 @@ package net.mamoe.mirai.console.pure -import kotlinx.coroutines.delay +//import net.mamoe.mirai.console.command.CommandManager +//import net.mamoe.mirai.console.utils.MiraiConsoleFrontEnd 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.MiraiConsoleFrontEnd +import net.mamoe.mirai.console.MiraiConsoleFrontEnd import net.mamoe.mirai.utils.DefaultLogger import net.mamoe.mirai.utils.DefaultLoginSolver import net.mamoe.mirai.utils.LoginSolver import net.mamoe.mirai.utils.MiraiLogger +import org.fusesource.jansi.Ansi import java.text.SimpleDateFormat import java.util.* -import kotlin.concurrent.thread +import java.util.concurrent.ConcurrentHashMap + +@Suppress("unused") +object MiraiConsoleFrontEndPure : MiraiConsoleFrontEnd { + private val globalLogger = DefaultLogger("Mirai") + private val cachedLoggers = ConcurrentHashMap() + + // 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" + // } + + val sdf by lazy { + SimpleDateFormat("HH:mm:ss") + } + override fun loggerFor(identity: String?): MiraiLogger { + identity?.apply { + return cachedLoggers.computeIfAbsent(this, DefaultLogger) + } + return globalLogger + } + + override fun prePushBot(identity: Long) { + } + + override fun pushBot(bot: Bot) { + } + + override fun pushVersion(consoleVersion: String, consoleBuild: String, coreVersion: String) { + } + + override suspend fun requestInput(hint: String): String { + if (hint.isNotEmpty()) { + ConsoleUtils.lineReader.printAbove( + Ansi.ansi() + .fgCyan().a(sdf.format(Date())) + .fgMagenta().a(hint) + .toString() + ) + } + return ConsoleUtils.lineReader.readLine("> ") + } + + override fun pushBotAdminStatus(identity: Long, admins: List) { + } + + override fun createLoginSolver(): LoginSolver { + return DefaultLoginSolver( + input = suspend { + requestInput("") + } + ) + } + +} + +/* class MiraiConsoleFrontEndPure : MiraiConsoleFrontEnd { private var requesting = false private var requestStr = "" @@ -106,4 +172,4 @@ class MiraiConsoleFrontEndPure : MiraiConsoleFrontEnd { } - +*/ diff --git a/frontend/mirai-console-pure/src/main/kotlin/net/mamoe/mirai/console/pure/MiraiConsolePure.kt b/frontend/mirai-console-pure/src/main/kotlin/net/mamoe/mirai/console/pure/MiraiConsolePure.kt new file mode 100644 index 000000000..5e0ab01a9 --- /dev/null +++ b/frontend/mirai-console-pure/src/main/kotlin/net/mamoe/mirai/console/pure/MiraiConsolePure.kt @@ -0,0 +1,49 @@ +/* + * 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( + "INVISIBLE_MEMBER", + "INVISIBLE_REFERENCE", + "CANNOT_OVERRIDE_INVISIBLE_MEMBER", + "INVISIBLE_SETTER", + "INVISIBLE_GETTER", + "INVISIBLE_ABSTRACT_MEMBER_FROM_SUPER", + "INVISIBLE_ABSTRACT_MEMBER_FROM_SUPE_WARNING" +) + +package net.mamoe.mirai.console.pure + + +import kotlinx.coroutines.CoroutineScope +import net.mamoe.mirai.console.IMiraiConsole +import net.mamoe.mirai.console.MiraiConsoleFrontEnd +import net.mamoe.mirai.console.plugin.PluginLoader +import net.mamoe.mirai.utils.DefaultLogger +import net.mamoe.mirai.utils.MiraiLogger +import java.io.File +import java.util.* +import kotlin.coroutines.CoroutineContext +import kotlin.coroutines.EmptyCoroutineContext + +private val delegateScope = CoroutineScope(EmptyCoroutineContext) + +object MiraiConsolePure : IMiraiConsole { + override val build: String = "UNKNOWN" + override val builtInPluginLoaders: List> = LinkedList() + override val frontEnd: MiraiConsoleFrontEnd = MiraiConsoleFrontEndPure + override val mainLogger: MiraiLogger = DefaultLogger("Console") + override val rootDir: File = File("./test/console").also { + it.mkdirs() + } + override val version: String + get() = "UNKNOWN" + override val coroutineContext: CoroutineContext + get() = delegateScope.coroutineContext +} \ No newline at end of file diff --git a/frontend/mirai-console-pure/src/main/kotlin/net/mamoe/mirai/console/pure/MiraiConsolePureLoader.kt b/frontend/mirai-console-pure/src/main/kotlin/net/mamoe/mirai/console/pure/MiraiConsolePureLoader.kt index d5a144a5c..72dd8c6fa 100644 --- a/frontend/mirai-console-pure/src/main/kotlin/net/mamoe/mirai/console/pure/MiraiConsolePureLoader.kt +++ b/frontend/mirai-console-pure/src/main/kotlin/net/mamoe/mirai/console/pure/MiraiConsolePureLoader.kt @@ -7,68 +7,72 @@ * https://github.com/mamoe/mirai/blob/master/LICENSE */ +@file:Suppress( + "INVISIBLE_MEMBER", + "INVISIBLE_REFERENCE", + "CANNOT_OVERRIDE_INVISIBLE_MEMBER", + "INVISIBLE_SETTER", + "INVISIBLE_GETTER", + "INVISIBLE_ABSTRACT_MEMBER_FROM_SUPER", + "INVISIBLE_ABSTRACT_MEMBER_FROM_SUPE_WARNING" +) + 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 net.mamoe.mirai.console.MiraiConsoleInitializer +import net.mamoe.mirai.console.command.ConsoleCommandSender +import net.mamoe.mirai.console.command.executeCommand +import net.mamoe.mirai.message.data.Message +import net.mamoe.mirai.message.data.PlainText +import net.mamoe.mirai.utils.DefaultLogger +import net.mamoe.mirai.utils.PlatformLogger +import org.fusesource.jansi.Ansi 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() - }) +object MiraiConsolePureLoader { + @JvmStatic + fun main(args: Array?) { + startup() + } +} + +private val ANSI_RESET = Ansi().reset().toString() + +internal fun overrideLoggingSystem() { + DefaultLogger = { + PlatformLogger(identity = it, output = { line -> + ConsoleUtils.lineReader.printAbove(line + ANSI_RESET) + }) + } +} + +internal fun startup() { + overrideLoggingSystem() + MiraiConsoleInitializer.init(MiraiConsolePure) + startConsoleThread() +} + +internal fun startConsoleThread() { + thread(name = "Console", isDaemon = false) { + val consoleLogger = DefaultLogger("Console") + kotlinx.coroutines.runBlocking { + while (true) { + val next = MiraiConsoleFrontEndPure.requestInput("") + consoleLogger.debug("INPUT> $next") + kotlin.runCatching { + if (!ConsoleCS.executeCommand(PlainText(next))) { // No such command + consoleLogger.warning("Unknown command: " + next.split(' ')[0]) + } + }.onFailure { + consoleLogger.error("Exception in executing command: $next", it) + } + } } } } -/** - * 启动 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 +object ConsoleCS : ConsoleCommandSender() { + override suspend fun sendMessage(message: Message) { + ConsoleUtils.lineReader.printAbove(message.contentToString()) } - 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() } \ No newline at end of file