Commit d0fb1383 authored by jiahua.liu's avatar jiahua.liu

Mirai Console V0.01

parent 90157c8f
...@@ -7,9 +7,11 @@ class MiraiConsoleTerminalLoader { ...@@ -7,9 +7,11 @@ class MiraiConsoleTerminalLoader {
@JvmStatic @JvmStatic
fun main(args: Array<String>) { fun main(args: Array<String>) {
MiraiConsoleTerminalUI.start() MiraiConsoleTerminalUI.start()
MiraiConsole.start( thread {
MiraiConsoleTerminalUI MiraiConsole.start(
) MiraiConsoleTerminalUI
)
}
Runtime.getRuntime().addShutdownHook(thread(start = false) { Runtime.getRuntime().addShutdownHook(thread(start = false) {
MiraiConsole.stop() MiraiConsole.stop()
}) })
......
...@@ -25,6 +25,8 @@ import java.io.OutputStream ...@@ -25,6 +25,8 @@ import java.io.OutputStream
import java.io.PrintStream import java.io.PrintStream
import java.nio.charset.Charset import java.nio.charset.Charset
import java.util.* import java.util.*
import java.util.concurrent.ConcurrentHashMap
import java.util.concurrent.ConcurrentLinkedDeque
import java.util.concurrent.ConcurrentLinkedQueue import java.util.concurrent.ConcurrentLinkedQueue
import kotlin.concurrent.thread import kotlin.concurrent.thread
import kotlin.system.exitProcess import kotlin.system.exitProcess
...@@ -44,7 +46,7 @@ object MiraiConsoleTerminalUI : MiraiConsoleUI { ...@@ -44,7 +46,7 @@ object MiraiConsoleTerminalUI : MiraiConsoleUI {
val cacheLogSize = 50 val cacheLogSize = 50
override fun pushLog(identity: Long, message: String) { override fun pushLog(identity: Long, message: String) {
log[identity]!!.offer(message) log[identity]!!.push(message)
if (identity == screens[currentScreenId]) { if (identity == screens[currentScreenId]) {
drawLog(message) drawLog(message)
} }
...@@ -52,23 +54,49 @@ object MiraiConsoleTerminalUI : MiraiConsoleUI { ...@@ -52,23 +54,49 @@ object MiraiConsoleTerminalUI : MiraiConsoleUI {
override fun prePushBot(identity: Long) { override fun prePushBot(identity: Long) {
log[identity] = LimitLinkedQueue(cacheLogSize) log[identity] = LimitLinkedQueue(cacheLogSize)
botAdminCount[identity] = 0
screens.add(identity)
} }
override fun pushBot(bot: Bot) { override fun pushBot(bot: Bot) {
//nothing to do botAdminCount[bot.uin] = 0
screens.add(bot.uin)
drawFrame(this.getScreenName(currentScreenId))
if (terminal is SwingTerminalFrame) {
terminal.flush()
}
}
var requesting = false
var requestResult: String? = null
override suspend fun requestInput(question: String): String {
requesting = true
while (requesting) {
Thread.sleep(100)//不然会卡死 迷惑吧
}
return requestResult!!
}
fun provideInput(input: String) {
if (requesting) {
requestResult = input
requesting = false
} else {
MiraiConsole.CommandListener.commandChannel.offer(
commandBuilder.toString()
)
}
} }
override fun pushBotAdminStatus(identity: Long, admins: List<Long>) { override fun pushBotAdminStatus(identity: Long, admins: List<Long>) {
botAdminCount[identity] = admins.size botAdminCount[identity] = admins.size
} }
val log = mutableMapOf<Long, Queue<String>>().also { val log = ConcurrentHashMap<Long, LimitLinkedQueue<String>>().also {
it[0L] = LimitLinkedQueue(cacheLogSize) it[0L] = LimitLinkedQueue(cacheLogSize)
} }
val botAdminCount = mutableMapOf<Long, Int>() val botAdminCount = ConcurrentHashMap<Long, Int>()
private val screens = mutableListOf(0L) private val screens = mutableListOf(0L)
private var currentScreenId = 0 private var currentScreenId = 0
...@@ -202,9 +230,7 @@ object MiraiConsoleTerminalUI : MiraiConsoleUI { ...@@ -202,9 +230,7 @@ object MiraiConsoleTerminalUI : MiraiConsoleUI {
update() update()
} }
KeyType.Enter -> { KeyType.Enter -> {
MiraiConsole.CommandListener.commandChannel.offer( provideInput(commandBuilder.toString())
commandBuilder.toString()
)
emptyCommand() emptyCommand()
} }
KeyType.Escape -> { KeyType.Escape -> {
...@@ -333,6 +359,9 @@ object MiraiConsoleTerminalUI : MiraiConsoleUI { ...@@ -333,6 +359,9 @@ object MiraiConsoleTerminalUI : MiraiConsoleUI {
fun drawLog(string: String, flush: Boolean = true) { fun drawLog(string: String, flush: Boolean = true) {
val maxHeight = terminal.terminalSize.rows - 4 val maxHeight = terminal.terminalSize.rows - 4
val heightNeed = (string.length / (terminal.terminalSize.columns - 6)) + 1 val heightNeed = (string.length / (terminal.terminalSize.columns - 6)) + 1
if (heightNeed - 1 > maxHeight) {
return//拒绝打印
}
if (currentHeight + heightNeed > maxHeight) { if (currentHeight + heightNeed > maxHeight) {
cleanPage() cleanPage()
} }
...@@ -421,7 +450,7 @@ object MiraiConsoleTerminalUI : MiraiConsoleUI { ...@@ -421,7 +450,7 @@ object MiraiConsoleTerminalUI : MiraiConsoleUI {
private fun addCommandChar( private fun addCommandChar(
c: Char c: Char
) { ) {
if (commandBuilder.isEmpty() && c != '/') { if (!requesting && commandBuilder.isEmpty() && c != '/') {
addCommandChar('/') addCommandChar('/')
} }
textGraphics.foregroundColor = TextColor.ANSI.WHITE textGraphics.foregroundColor = TextColor.ANSI.WHITE
...@@ -488,11 +517,11 @@ object MiraiConsoleTerminalUI : MiraiConsoleUI { ...@@ -488,11 +517,11 @@ object MiraiConsoleTerminalUI : MiraiConsoleUI {
class LimitLinkedQueue<T>( class LimitLinkedQueue<T>(
val limit: Int = 50 val limit: Int = 50
) : ConcurrentLinkedQueue<T>() { ) : ConcurrentLinkedDeque<T>() {
override fun offer(e: T): Boolean { override fun push(e: T) {
if (size >= limit) { if (size >= limit) {
poll() this.pollLast()
} }
return super.offer(e) return super.push(e)
} }
} }
...@@ -11,7 +11,6 @@ package net.mamoe.mirai.console ...@@ -11,7 +11,6 @@ package net.mamoe.mirai.console
import kotlinx.coroutines.runBlocking import kotlinx.coroutines.runBlocking
import net.mamoe.mirai.Bot import net.mamoe.mirai.Bot
import net.mamoe.mirai.alsoLogin
import net.mamoe.mirai.api.http.MiraiHttpAPIServer import net.mamoe.mirai.api.http.MiraiHttpAPIServer
import net.mamoe.mirai.api.http.generateSessionKey import net.mamoe.mirai.api.http.generateSessionKey
import net.mamoe.mirai.console.plugins.PluginManager import net.mamoe.mirai.console.plugins.PluginManager
...@@ -19,7 +18,7 @@ import net.mamoe.mirai.console.plugins.loadAsConfig ...@@ -19,7 +18,7 @@ import net.mamoe.mirai.console.plugins.loadAsConfig
import net.mamoe.mirai.console.plugins.withDefaultWrite import net.mamoe.mirai.console.plugins.withDefaultWrite
import net.mamoe.mirai.console.plugins.withDefaultWriteSave import net.mamoe.mirai.console.plugins.withDefaultWriteSave
import net.mamoe.mirai.contact.sendMessage import net.mamoe.mirai.contact.sendMessage
import net.mamoe.mirai.utils.SimpleLogger import net.mamoe.mirai.utils.*
import java.io.File import java.io.File
import java.util.* import java.util.*
import java.util.concurrent.LinkedBlockingQueue import java.util.concurrent.LinkedBlockingQueue
...@@ -119,12 +118,39 @@ object MiraiConsole { ...@@ -119,12 +118,39 @@ object MiraiConsole {
logger("[Bot Login]", 0, "login...") logger("[Bot Login]", 0, "login...")
try { try {
runBlocking { runBlocking {
Bot(qqNumber, qqPassword).alsoLogin() frontEnd.prePushBot(qqNumber)
val bot = Bot(qqNumber, qqPassword) {
this.loginSolver = DefaultLoginSolver(object : LoginSolverInputReader {
override suspend fun read(question: String): String? {
return frontEnd.requestInput(question)
}
})
this.botLoggerSupplier = {
SimpleLogger("BOT $qqNumber") { _, message, e ->
logger("[BOT $qqNumber]", qqNumber, message)
if (e != null) {
logger("[NETWORK ERROR]", qqNumber, e.toString())//因为在一页 所以可以不打QQ
e.printStackTrace()
}
}
}
this.networkLoggerSupplier = {
SimpleLogger("BOT $qqNumber") { _, message, e ->
logger("[NETWORK]", qqNumber, message)//因为在一页 所以可以不打QQ
if (e != null) {
logger("[NETWORK ERROR]", qqNumber, e.toString())//因为在一页 所以可以不打QQ
e.printStackTrace()
}
}
}
}
bot.login()
logger( logger(
"[Bot Login]", "[Bot Login]",
0, 0,
"$qqNumber login successes" "$qqNumber login successes"
) )
frontEnd.pushBot(bot)
} }
} catch (e: Exception) { } catch (e: Exception) {
logger( logger(
...@@ -132,7 +158,6 @@ object MiraiConsole { ...@@ -132,7 +158,6 @@ object MiraiConsole {
0, 0,
"$qqNumber login failed -> " + e.message "$qqNumber login failed -> " + e.message
) )
e.printStackTrace()
} }
true true
} }
......
...@@ -10,7 +10,7 @@ import net.mamoe.mirai.Bot ...@@ -10,7 +10,7 @@ import net.mamoe.mirai.Bot
interface MiraiConsoleUI { interface MiraiConsoleUI {
/** /**
* 让UI层展示一条log * 让UI层展示一条log
* identityString: log前面的prefix *
* identity:log所属的screen, Main=0; Bot=Bot.uin * identity:log所属的screen, Main=0; Bot=Bot.uin
*/ */
fun pushLog( fun pushLog(
...@@ -32,6 +32,15 @@ interface MiraiConsoleUI { ...@@ -32,6 +32,15 @@ interface MiraiConsoleUI {
bot: Bot bot: Bot
) )
/**
* 让UI层提供一个Input
* 这个Input 不 等于 Command
*
*/
suspend fun requestInput(
question: String
): String
/** /**
* 让UI层更新BOT管理员的数据 * 让UI层更新BOT管理员的数据
*/ */
...@@ -39,4 +48,5 @@ interface MiraiConsoleUI { ...@@ -39,4 +48,5 @@ interface MiraiConsoleUI {
identity: Long, identity: Long,
admins: List<Long> admins: List<Long>
) )
} }
\ No newline at end of file
...@@ -39,7 +39,22 @@ import kotlin.coroutines.EmptyCoroutineContext ...@@ -39,7 +39,22 @@ import kotlin.coroutines.EmptyCoroutineContext
actual var defaultLoginSolver: LoginSolver = DefaultLoginSolver() actual var defaultLoginSolver: LoginSolver = DefaultLoginSolver()
internal class DefaultLoginSolver : LoginSolver() { interface LoginSolverInputReader{
suspend fun read(question:String):String?
suspend operator fun invoke(question: String):String?{
return read(question)
}
}
class DefaultLoginSolverInputReader: LoginSolverInputReader{
override suspend fun read(question: String): String? {
return readLine()
}
}
class DefaultLoginSolver(
val reader: LoginSolverInputReader = DefaultLoginSolverInputReader()
) : LoginSolver() {
override suspend fun onSolvePicCaptcha(bot: Bot, data: IoBuffer): String? = loginSolverLock.withLock { override suspend fun onSolvePicCaptcha(bot: Bot, data: IoBuffer): String? = loginSolverLock.withLock {
val tempFile: File = createTempFile(suffix = ".png").apply { deleteOnExit() } val tempFile: File = createTempFile(suffix = ".png").apply { deleteOnExit() }
withContext(Dispatchers.IO) { withContext(Dispatchers.IO) {
...@@ -62,7 +77,7 @@ internal class DefaultLoginSolver : LoginSolver() { ...@@ -62,7 +77,7 @@ internal class DefaultLoginSolver : LoginSolver() {
} }
} }
bot.logger.info("请输入 4 位字母验证码. 若要更换验证码, 请直接回车") bot.logger.info("请输入 4 位字母验证码. 若要更换验证码, 请直接回车")
return readLine()!!.takeUnless { it.isEmpty() || it.length != 4 }.also { return reader("请输入 4 位字母验证码. 若要更换验证码, 请直接回车")!!.takeUnless { it.isEmpty() || it.length != 4 }.also {
bot.logger.info("正在提交[$it]中...") bot.logger.info("正在提交[$it]中...")
} }
} }
...@@ -72,7 +87,7 @@ internal class DefaultLoginSolver : LoginSolver() { ...@@ -72,7 +87,7 @@ internal class DefaultLoginSolver : LoginSolver() {
bot.logger.info("请在任意浏览器中打开以下链接并完成验证码. ") bot.logger.info("请在任意浏览器中打开以下链接并完成验证码. ")
bot.logger.info("完成后请输入任意字符 ") bot.logger.info("完成后请输入任意字符 ")
bot.logger.info(url) bot.logger.info(url)
return readLine().also { return reader("完成后请输入任意字符").also {
bot.logger.info("正在提交中...") bot.logger.info("正在提交中...")
} }
} }
...@@ -84,7 +99,7 @@ internal class DefaultLoginSolver : LoginSolver() { ...@@ -84,7 +99,7 @@ internal class DefaultLoginSolver : LoginSolver() {
bot.logger.info("请将该链接在QQ浏览器中打开并完成认证, 成功后输入任意字符") bot.logger.info("请将该链接在QQ浏览器中打开并完成认证, 成功后输入任意字符")
bot.logger.info("这步操作将在后续的版本中优化") bot.logger.info("这步操作将在后续的版本中优化")
bot.logger.info(url) bot.logger.info(url)
return readLine().also { return reader("完成后请输入任意字符").also {
bot.logger.info("正在提交中...") bot.logger.info("正在提交中...")
} }
} }
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment