Skip to content
Projects
Groups
Snippets
Help
Loading...
Help
Support
Keyboard shortcuts
?
Submit feedback
Sign in / Register
Toggle navigation
M
Mirai
Project overview
Project overview
Details
Activity
Releases
Repository
Repository
Files
Commits
Branches
Tags
Contributors
Graph
Compare
Locked Files
Issues
0
Issues
0
List
Boards
Labels
Service Desk
Milestones
Merge Requests
0
Merge Requests
0
CI / CD
CI / CD
Pipelines
Jobs
Schedules
Security & Compliance
Security & Compliance
Dependency List
License Compliance
Packages
Packages
List
Container Registry
Analytics
Analytics
CI / CD
Code Review
Insights
Issues
Repository
Value Stream
Wiki
Wiki
Snippets
Snippets
Members
Members
Collapse sidebar
Close sidebar
Activity
Graph
Create a new issue
Jobs
Commits
Issue Boards
Open sidebar
MyCard
Mirai
Commits
eb866066
Commit
eb866066
authored
Feb 16, 2020
by
Him188
Browse files
Options
Browse Files
Download
Plain Diff
Merge remote-tracking branch 'origin/master'
parents
dcddcc92
bd381b80
Changes
12
Hide whitespace changes
Inline
Side-by-side
Showing
12 changed files
with
795 additions
and
531 deletions
+795
-531
README.md
README.md
+1
-1
mirai-console-graphical/README.md
mirai-console-graphical/README.md
+6
-0
mirai-console-graphical/build.gradle.kts
mirai-console-graphical/build.gradle.kts
+34
-0
mirai-console-terminal/README.md
mirai-console-terminal/README.md
+6
-0
mirai-console-terminal/build.gradle.kts
mirai-console-terminal/build.gradle.kts
+44
-0
mirai-console-terminal/src/main/kotlin/net/mamoe/mirai/console/MiraiConsoleTerminalLoader.kt
...lin/net/mamoe/mirai/console/MiraiConsoleTerminalLoader.kt
+20
-0
mirai-console-terminal/src/main/kotlin/net/mamoe/mirai/console/MiraiConsoleTerminalUI.kt
.../kotlin/net/mamoe/mirai/console/MiraiConsoleTerminalUI.kt
+532
-0
mirai-console/build.gradle.kts
mirai-console/build.gradle.kts
+0
-6
mirai-console/src/main/kotlin/net/mamoe/mirai/console/MiraiConsole.kt
...e/src/main/kotlin/net/mamoe/mirai/console/MiraiConsole.kt
+49
-22
mirai-console/src/main/kotlin/net/mamoe/mirai/console/MiraiConsoleUI.kt
...src/main/kotlin/net/mamoe/mirai/console/MiraiConsoleUI.kt
+52
-479
mirai-core/src/jvmMain/kotlin/net/mamoe/mirai/utils/BotConfigurationJvm.kt
...mMain/kotlin/net/mamoe/mirai/utils/BotConfigurationJvm.kt
+49
-23
settings.gradle
settings.gradle
+2
-0
No files found.
README.md
View file @
eb866066
...
...
@@ -120,7 +120,7 @@ JVM 上启动需 80M 内存, 每多一个机器人实例需要 30M 内存.
现在体验低付出高效率的 Mirai
```
kotlin
val
bot
=
TIMPC
.
Bot
(
qqId
,
password
).
alsoLogin
()
val
bot
=
Bot
(
qqId
,
password
).
alsoLogin
()
bot
.
subscribeMessages
{
"你好"
reply
"你好!"
"profile"
reply
{
sender
.
queryProfile
()
}
...
...
mirai-console-graphical/README.md
0 → 100644
View file @
eb866066
### Mirai Console Graphical
支持windows/mac
有正式UI界面实现的CONSOLE
优点: 适合新手/完全不懂编程的/界面美丽
缺点: 不能在linux服务器运行
所使用插件系统与terminal版本一致 可以来回切换
\ No newline at end of file
mirai-console-graphical/build.gradle.kts
0 → 100644
View file @
eb866066
plugins
{
id
(
"kotlinx-serialization"
)
id
(
"kotlin"
)
id
(
"java"
)
}
apply
(
plugin
=
"com.github.johnrengelman.shadow"
)
val
kotlinVersion
:
String
by
rootProject
.
ext
val
atomicFuVersion
:
String
by
rootProject
.
ext
val
coroutinesVersion
:
String
by
rootProject
.
ext
val
kotlinXIoVersion
:
String
by
rootProject
.
ext
val
coroutinesIoVersion
:
String
by
rootProject
.
ext
val
klockVersion
:
String
by
rootProject
.
ext
val
ktorVersion
:
String
by
rootProject
.
ext
val
serializationVersion
:
String
by
rootProject
.
ext
fun
kotlinx
(
id
:
String
,
version
:
String
)
=
"org.jetbrains.kotlinx:kotlinx-$id:$version"
fun
ktor
(
id
:
String
,
version
:
String
)
=
"io.ktor:ktor-$id:$version"
dependencies
{
api
(
project
(
":mirai-core"
))
api
(
project
(
":mirai-core-qqandroid"
))
api
(
project
(
":mirai-api-http"
))
api
(
project
(
":mirai-console"
))
runtimeOnly
(
files
(
"../mirai-core-qqandroid/build/classes/kotlin/jvm/main"
))
api
(
group
=
"no.tornado"
,
name
=
"tornadofx"
,
version
=
"1.7.19"
)
api
(
"org.bouncycastle:bcprov-jdk15on:1.64"
)
// classpath is not set correctly by IDE
}
\ No newline at end of file
mirai-console-terminal/README.md
0 → 100644
View file @
eb866066
### Mirai Console Terminal
支持windows/mac/linux
在terminal环境下的Console, 由控制台富文本实现简易UI
优点: 可以在linux环境下运行/简洁使用效率高
缺点: 需要有略微的terminal知识
所使用插件系统与graphical版本一致 可以来回切换
\ No newline at end of file
mirai-console-terminal/build.gradle.kts
0 → 100644
View file @
eb866066
plugins
{
id
(
"kotlinx-serialization"
)
id
(
"kotlin"
)
id
(
"java"
)
}
apply
(
plugin
=
"com.github.johnrengelman.shadow"
)
tasks
.
withType
<
com
.
github
.
jengelman
.
gradle
.
plugins
.
shadow
.
tasks
.
ShadowJar
>()
{
manifest
{
attributes
[
"Main-Class"
]
=
"net.mamoe.mirai.console.MiraiConsoleTerminalLoader"
}
}
val
kotlinVersion
:
String
by
rootProject
.
ext
val
atomicFuVersion
:
String
by
rootProject
.
ext
val
coroutinesVersion
:
String
by
rootProject
.
ext
val
kotlinXIoVersion
:
String
by
rootProject
.
ext
val
coroutinesIoVersion
:
String
by
rootProject
.
ext
val
klockVersion
:
String
by
rootProject
.
ext
val
ktorVersion
:
String
by
rootProject
.
ext
val
serializationVersion
:
String
by
rootProject
.
ext
fun
kotlinx
(
id
:
String
,
version
:
String
)
=
"org.jetbrains.kotlinx:kotlinx-$id:$version"
fun
ktor
(
id
:
String
,
version
:
String
)
=
"io.ktor:ktor-$id:$version"
dependencies
{
api
(
project
(
":mirai-core"
))
api
(
project
(
":mirai-core-qqandroid"
))
api
(
project
(
":mirai-api-http"
))
api
(
project
(
":mirai-console"
))
runtimeOnly
(
files
(
"../mirai-core-qqandroid/build/classes/kotlin/jvm/main"
))
runtimeOnly
(
files
(
"../mirai-core/build/classes/kotlin/jvm/main"
))
api
(
group
=
"com.googlecode.lanterna"
,
name
=
"lanterna"
,
version
=
"3.0.2"
)
api
(
"org.bouncycastle:bcprov-jdk15on:1.64"
)
// classpath is not set correctly by IDE
}
\ No newline at end of file
mirai-console-terminal/src/main/kotlin/net/mamoe/mirai/console/MiraiConsoleTerminalLoader.kt
0 → 100644
View file @
eb866066
package
net.mamoe.mirai.console
import
kotlin.concurrent.thread
class
MiraiConsoleTerminalLoader
{
companion
object
{
@JvmStatic
fun
main
(
args
:
Array
<
String
>)
{
MiraiConsoleTerminalUI
.
start
()
thread
{
MiraiConsole
.
start
(
MiraiConsoleTerminalUI
)
}
Runtime
.
getRuntime
().
addShutdownHook
(
thread
(
start
=
false
)
{
MiraiConsole
.
stop
()
})
}
}
}
\ No newline at end of file
mirai-console-terminal/src/main/kotlin/net/mamoe/mirai/console/MiraiConsoleTerminalUI.kt
0 → 100644
View file @
eb866066
package
net.mamoe.mirai.console
import
com.googlecode.lanterna.SGR
import
com.googlecode.lanterna.TerminalSize
import
com.googlecode.lanterna.TextColor
import
com.googlecode.lanterna.graphics.TextGraphics
import
com.googlecode.lanterna.input.KeyStroke
import
com.googlecode.lanterna.input.KeyType
import
com.googlecode.lanterna.terminal.DefaultTerminalFactory
import
com.googlecode.lanterna.terminal.Terminal
import
com.googlecode.lanterna.terminal.TerminalResizeListener
import
com.googlecode.lanterna.terminal.swing.SwingTerminal
import
com.googlecode.lanterna.terminal.swing.SwingTerminalFontConfiguration
import
com.googlecode.lanterna.terminal.swing.SwingTerminalFrame
import
kotlinx.coroutines.GlobalScope
import
kotlinx.coroutines.Job
import
kotlinx.coroutines.delay
import
kotlinx.coroutines.launch
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
java.awt.Font
import
java.io.OutputStream
import
java.io.PrintStream
import
java.nio.charset.Charset
import
java.util.*
import
java.util.concurrent.ConcurrentHashMap
import
java.util.concurrent.ConcurrentLinkedDeque
import
java.util.concurrent.ConcurrentLinkedQueue
import
kotlin.concurrent.thread
import
kotlin.system.exitProcess
/**
* 此文件不推荐任何人看
* 可能导致
* 1:心肌梗死
* 2:呼吸困难
* 3:想要重写但是发现改任何一个看似不合理的地方都会崩
*
* @author NaturalHG
*
*/
object
MiraiConsoleTerminalUI
:
MiraiConsoleUI
{
val
cacheLogSize
=
50
var
mainTitle
=
"Mirai Console v0.01 Core v0.15"
override
fun
pushVersion
(
consoleVersion
:
String
,
consoleBuild
:
String
,
coreVersion
:
String
)
{
mainTitle
=
"Mirai Console(Terminal) $consoleVersion $consoleBuild Core $coreVersion"
}
override
fun
pushLog
(
identity
:
Long
,
message
:
String
)
{
log
[
identity
]
!!
.
push
(
message
)
if
(
identity
==
screens
[
currentScreenId
])
{
drawLog
(
message
)
}
}
override
fun
prePushBot
(
identity
:
Long
)
{
log
[
identity
]
=
LimitLinkedQueue
(
cacheLogSize
)
}
override
fun
pushBot
(
bot
:
Bot
)
{
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
)
{
delay
(
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
>)
{
botAdminCount
[
identity
]
=
admins
.
size
}
val
log
=
ConcurrentHashMap
<
Long
,
LimitLinkedQueue
<
String
>>().
also
{
it
[
0L
]
=
LimitLinkedQueue
(
cacheLogSize
)
}
val
botAdminCount
=
ConcurrentHashMap
<
Long
,
Int
>()
private
val
screens
=
mutableListOf
(
0L
)
private
var
currentScreenId
=
0
lateinit
var
terminal
:
Terminal
lateinit
var
textGraphics
:
TextGraphics
var
hasStart
=
false
private
lateinit
var
internalPrinter
:
PrintStream
fun
start
()
{
if
(
hasStart
)
{
return
}
internalPrinter
=
System
.
out
hasStart
=
true
val
defaultTerminalFactory
=
DefaultTerminalFactory
(
internalPrinter
,
System
.
`in`
,
Charset
.
defaultCharset
())
val
fontSize
=
12
defaultTerminalFactory
.
setInitialTerminalSize
(
TerminalSize
(
101
,
60
)
)
.
setTerminalEmulatorFontConfiguration
(
SwingTerminalFontConfiguration
.
newInstance
(
Font
(
"Monospaced"
,
Font
.
PLAIN
,
fontSize
)
)
)
try
{
terminal
=
defaultTerminalFactory
.
createTerminal
()
terminal
.
enterPrivateMode
()
terminal
.
clearScreen
()
terminal
.
setCursorVisible
(
false
)
}
catch
(
e
:
Exception
)
{
try
{
terminal
=
SwingTerminalFrame
(
"Mirai Console"
)
terminal
.
enterPrivateMode
()
terminal
.
clearScreen
()
terminal
.
setCursorVisible
(
false
)
}
catch
(
e
:
Exception
)
{
error
(
"can not create terminal"
)
}
}
textGraphics
=
terminal
.
newTextGraphics
()
/*
var lastRedrawTime = 0L
var lastNewWidth = 0
var lastNewHeight = 0
terminal.addResizeListener(TerminalResizeListener { terminal1: Terminal, newSize: TerminalSize ->
try {
if (lastNewHeight == newSize.rows
&&
lastNewWidth == newSize.columns
) {
return@TerminalResizeListener
}
lastNewHeight = newSize.rows
lastNewWidth = newSize.columns
terminal.clearScreen()
if(terminal !is SwingTerminalFrame) {
Thread.sleep(300)
}
update()
redrawCommand()
redrawLogs(log[screens[currentScreenId]]!!)
}catch (ignored:Exception){
}
})
*/
var
lastJob
:
Job
?
=
null
terminal
.
addResizeListener
(
TerminalResizeListener
{
terminal1
:
Terminal
,
newSize
:
TerminalSize
->
lastJob
=
GlobalScope
.
launch
{
delay
(
300
)
if
(
lastJob
==
coroutineContext
[
Job
])
{
terminal
.
clearScreen
()
//inited = false
update
()
redrawCommand
()
redrawLogs
(
log
[
screens
[
currentScreenId
]]
!!
)
}
}
})
if
(
terminal
!
is
SwingTerminalFrame
)
{
System
.
setOut
(
PrintStream
(
object
:
OutputStream
()
{
var
builder
=
java
.
lang
.
StringBuilder
()
override
fun
write
(
b
:
Int
)
{
with
(
b
.
toChar
())
{
if
(
this
==
'\n'
)
{
pushLog
(
0
,
builder
.
toString
())
builder
=
java
.
lang
.
StringBuilder
()
}
else
{
builder
.
append
(
this
)
}
}
}
}))
}
System
.
setErr
(
System
.
out
)
update
()
val
charList
=
listOf
(
','
,
'.'
,
'/'
,
'@'
,
'#'
,
'$'
,
'%'
,
'^'
,
'&'
,
'*'
,
'('
,
')'
,
'_'
,
'='
,
'+'
,
'!'
,
' '
)
thread
{
while
(
true
)
{
var
keyStroke
:
KeyStroke
=
terminal
.
readInput
()
when
(
keyStroke
.
keyType
)
{
KeyType
.
ArrowLeft
->
{
currentScreenId
=
getLeftScreenId
()
clearRows
(
2
)
cleanPage
()
update
()
}
KeyType
.
ArrowRight
->
{
currentScreenId
=
getRightScreenId
()
clearRows
(
2
)
cleanPage
()
update
()
}
KeyType
.
Enter
->
{
provideInput
(
commandBuilder
.
toString
())
emptyCommand
()
}
KeyType
.
Escape
->
{
exitProcess
(
0
)
}
else
->
{
if
(
keyStroke
.
character
!=
null
)
{
if
(
keyStroke
.
character
.
toInt
()
==
8
)
{
deleteCommandChar
()
}
if
(
keyStroke
.
character
.
isLetterOrDigit
()
||
charList
.
contains
(
keyStroke
.
character
))
{
addCommandChar
(
keyStroke
.
character
)
}
}
}
}
}
}
}
private
fun
getLeftScreenId
():
Int
{
var
newId
=
currentScreenId
-
1
if
(
newId
<
0
)
{
newId
=
screens
.
size
-
1
}
return
newId
}
private
fun
getRightScreenId
():
Int
{
var
newId
=
1
+
currentScreenId
if
(
newId
>=
screens
.
size
)
{
newId
=
0
}
return
newId
}
private
fun
getScreenName
(
id
:
Int
):
String
{
return
when
(
screens
[
id
])
{
0L
->
{
"Console Screen"
}
else
->
{
"Bot: ${screens[id]}"
}
}
}
fun
clearRows
(
row
:
Int
)
{
textGraphics
.
putString
(
0
,
row
,
" "
.
repeat
(
terminal
.
terminalSize
.
columns
)
)
}
fun
drawFrame
(
title
:
String
)
{
val
width
=
terminal
.
terminalSize
.
columns
val
height
=
terminal
.
terminalSize
.
rows
terminal
.
setBackgroundColor
(
TextColor
.
ANSI
.
DEFAULT
)
textGraphics
.
foregroundColor
=
TextColor
.
ANSI
.
WHITE
textGraphics
.
backgroundColor
=
TextColor
.
ANSI
.
GREEN
textGraphics
.
putString
((
width
-
mainTitle
.
length
)
/
2
,
1
,
mainTitle
,
SGR
.
BOLD
)
textGraphics
.
foregroundColor
=
TextColor
.
ANSI
.
DEFAULT
textGraphics
.
backgroundColor
=
TextColor
.
ANSI
.
DEFAULT
textGraphics
.
putString
(
2
,
3
,
"-"
.
repeat
(
width
-
4
))
textGraphics
.
putString
(
2
,
5
,
"-"
.
repeat
(
width
-
4
))
textGraphics
.
putString
(
2
,
height
-
4
,
"-"
.
repeat
(
width
-
4
))
textGraphics
.
putString
(
2
,
height
-
3
,
"|>>>"
)
textGraphics
.
putString
(
width
-
3
,
height
-
3
,
"|"
)
textGraphics
.
putString
(
2
,
height
-
2
,
"-"
.
repeat
(
width
-
4
))
textGraphics
.
foregroundColor
=
TextColor
.
ANSI
.
DEFAULT
textGraphics
.
backgroundColor
=
TextColor
.
ANSI
.
DEFAULT
val
leftName
=
getScreenName
(
getLeftScreenId
())
// clearRows(2)
textGraphics
.
putString
((
width
-
title
.
length
)
/
2
-
"$leftName << "
.
length
,
2
,
"$leftName << "
)
textGraphics
.
foregroundColor
=
TextColor
.
ANSI
.
WHITE
textGraphics
.
backgroundColor
=
TextColor
.
ANSI
.
YELLOW
textGraphics
.
putString
((
width
-
title
.
length
)
/
2
,
2
,
title
,
SGR
.
BOLD
)
textGraphics
.
foregroundColor
=
TextColor
.
ANSI
.
DEFAULT
textGraphics
.
backgroundColor
=
TextColor
.
ANSI
.
DEFAULT
val
rightName
=
getScreenName
(
getRightScreenId
())
textGraphics
.
putString
((
width
+
title
.
length
)
/
2
+
1
,
2
,
">> $rightName"
)
}
fun
drawMainFrame
(
onlineBotCount
:
Number
)
{
drawFrame
(
"Console Screen"
)
val
width
=
terminal
.
terminalSize
.
columns
textGraphics
.
foregroundColor
=
TextColor
.
ANSI
.
DEFAULT
textGraphics
.
backgroundColor
=
TextColor
.
ANSI
.
DEFAULT
clearRows
(
4
)
textGraphics
.
putString
(
2
,
4
,
"|Online Bots: $onlineBotCount"
)
textGraphics
.
putString
(
width
-
2
-
"Powered By Mamoe Technologies|"
.
length
,
4
,
"Powered By Mamoe Technologies|"
)
}
fun
drawBotFrame
(
qq
:
Long
,
adminCount
:
Number
)
{
drawFrame
(
"Bot: $qq"
)
val
width
=
terminal
.
terminalSize
.
columns
textGraphics
.
foregroundColor
=
TextColor
.
ANSI
.
DEFAULT
textGraphics
.
backgroundColor
=
TextColor
.
ANSI
.
DEFAULT
clearRows
(
4
)
textGraphics
.
putString
(
2
,
4
,
"|Admins: $adminCount"
)
textGraphics
.
putString
(
width
-
2
-
"Add admins via commands|"
.
length
,
4
,
"Add admins via commands|"
)
}
object
LoggerDrawer
{
var
currentHeight
=
6
fun
drawLog
(
string
:
String
,
flush
:
Boolean
=
true
)
{
val
maxHeight
=
terminal
.
terminalSize
.
rows
-
4
val
heightNeed
=
(
string
.
length
/
(
terminal
.
terminalSize
.
columns
-
6
))
+
1
if
(
heightNeed
-
1
>
maxHeight
)
{
return
//拒绝打印
}
if
(
currentHeight
+
heightNeed
>
maxHeight
)
{
cleanPage
()
}
val
width
=
terminal
.
terminalSize
.
columns
-
7
var
x
=
string
while
(
true
)
{
if
(
x
==
""
)
break
val
toWrite
=
if
(
x
.
length
>
width
)
{
x
.
substring
(
0
,
width
).
also
{
x
=
x
.
substring
(
width
)
}
}
else
{
x
.
also
{
x
=
""
}
}
try
{
textGraphics
.
foregroundColor
=
TextColor
.
ANSI
.
GREEN
textGraphics
.
backgroundColor
=
TextColor
.
ANSI
.
DEFAULT
textGraphics
.
putString
(
3
,
currentHeight
,
toWrite
,
SGR
.
ITALIC
)
}
catch
(
ignored
:
Exception
)
{
//
}
++
currentHeight
}
if
(
flush
&&
terminal
is
SwingTerminalFrame
)
{
terminal
.
flush
()
}
}
fun
cleanPage
()
{
for
(
index
in
6
until
terminal
.
terminalSize
.
rows
-
4
)
{
clearRows
(
index
)
}
currentHeight
=
6
}
fun
redrawLogs
(
toDraw
:
Queue
<
String
>)
{
//this.cleanPage()
currentHeight
=
6
var
logsToDraw
=
0
var
vara
=
0
val
toPrint
=
mutableListOf
<
String
>()
toDraw
.
forEach
{
val
heightNeed
=
(
it
.
length
/
(
terminal
.
terminalSize
.
columns
-
6
))
+
1
vara
+=
heightNeed
if
(
currentHeight
+
vara
<
terminal
.
terminalSize
.
rows
-
4
)
{
logsToDraw
++
toPrint
.
add
(
it
)
}
else
{
return
@
forEach
}
}
toPrint
.
reversed
().
forEach
{
drawLog
(
it
,
false
)
}
if
(
terminal
is
SwingTerminalFrame
)
{
terminal
.
flush
()
}
}
}
var
commandBuilder
=
StringBuilder
()
fun
redrawCommand
()
{
val
height
=
terminal
.
terminalSize
.
rows
val
width
=
terminal
.
terminalSize
.
columns
clearRows
(
height
-
3
)
textGraphics
.
foregroundColor
=
TextColor
.
ANSI
.
DEFAULT
textGraphics
.
putString
(
2
,
height
-
3
,
"|>>>"
)
textGraphics
.
putString
(
width
-
3
,
height
-
3
,
"|"
)
textGraphics
.
foregroundColor
=
TextColor
.
ANSI
.
WHITE
textGraphics
.
backgroundColor
=
TextColor
.
ANSI
.
BLACK
textGraphics
.
putString
(
7
,
height
-
3
,
commandBuilder
.
toString
())
if
(
terminal
is
SwingTerminalFrame
)
{
terminal
.
flush
()
}
textGraphics
.
backgroundColor
=
TextColor
.
ANSI
.
DEFAULT
}
private
fun
addCommandChar
(
c
:
Char
)
{
if
(!
requesting
&&
commandBuilder
.
isEmpty
()
&&
c
!=
'/'
)
{
addCommandChar
(
'/'
)
}
textGraphics
.
foregroundColor
=
TextColor
.
ANSI
.
WHITE
textGraphics
.
backgroundColor
=
TextColor
.
ANSI
.
BLACK
val
height
=
terminal
.
terminalSize
.
rows
commandBuilder
.
append
(
c
)
if
(
terminal
is
SwingTerminalFrame
)
{
redrawCommand
()
}
else
{
textGraphics
.
putString
(
6
+
commandBuilder
.
length
,
height
-
3
,
c
.
toString
())
}
textGraphics
.
backgroundColor
=
TextColor
.
ANSI
.
DEFAULT
}
private
fun
deleteCommandChar
()
{
if
(!
commandBuilder
.
isEmpty
())
{
commandBuilder
=
StringBuilder
(
commandBuilder
.
toString
().
substring
(
0
,
commandBuilder
.
length
-
1
))
}
val
height
=
terminal
.
terminalSize
.
rows
if
(
terminal
is
SwingTerminalFrame
)
{
redrawCommand
()
}
else
{
textGraphics
.
putString
(
7
+
commandBuilder
.
length
,
height
-
3
,
" "
)
}
}
var
lastEmpty
:
Job
?
=
null
private
fun
emptyCommand
()
{
commandBuilder
=
StringBuilder
()
if
(
terminal
is
SwingTerminal
)
{
redrawCommand
()
terminal
.
flush
()
}
else
{
lastEmpty
=
GlobalScope
.
launch
{
delay
(
100
)
if
(
lastEmpty
==
coroutineContext
[
Job
])
{
terminal
.
clearScreen
()
//inited = false
update
()
redrawCommand
()
redrawLogs
(
log
[
screens
[
currentScreenId
]]
!!
)
}
}
}
}
fun
update
()
{
when
(
screens
[
currentScreenId
])
{
0L
->
{
drawMainFrame
(
screens
.
size
-
1
)
}
else
->
{
drawBotFrame
(
screens
[
currentScreenId
],
0
)
}
}
redrawLogs
(
log
[
screens
[
currentScreenId
]]
!!
)
}
}
class
LimitLinkedQueue
<
T
>(
val
limit
:
Int
=
50
)
:
ConcurrentLinkedDeque
<
T
>()
{
override
fun
push
(
e
:
T
)
{
if
(
size
>=
limit
)
{
this
.
pollLast
()
}
return
super
.
push
(
e
)
}
}
mirai-console/build.gradle.kts
View file @
eb866066
...
...
@@ -8,12 +8,6 @@ plugins {
apply
(
plugin
=
"com.github.johnrengelman.shadow"
)
tasks
.
withType
<
com
.
github
.
jengelman
.
gradle
.
plugins
.
shadow
.
tasks
.
ShadowJar
>()
{
manifest
{
attributes
[
"Main-Class"
]
=
"net.mamoe.mirai.console.MiraiConsoleLoader"
}
}
val
kotlinVersion
:
String
by
rootProject
.
ext
val
atomicFuVersion
:
String
by
rootProject
.
ext
val
coroutinesVersion
:
String
by
rootProject
.
ext
...
...
mirai-console/src/main/kotlin/net/mamoe/mirai/console/MiraiConsole.kt
View file @
eb866066
...
...
@@ -11,7 +11,6 @@ package net.mamoe.mirai.console
import
kotlinx.coroutines.runBlocking
import
net.mamoe.mirai.Bot
import
net.mamoe.mirai.alsoLogin
import
net.mamoe.mirai.api.http.MiraiHttpAPIServer
import
net.mamoe.mirai.api.http.generateSessionKey
import
net.mamoe.mirai.console.plugins.PluginManager
...
...
@@ -19,7 +18,7 @@ import net.mamoe.mirai.console.plugins.loadAsConfig
import
net.mamoe.mirai.console.plugins.withDefaultWrite
import
net.mamoe.mirai.console.plugins.withDefaultWriteSave
import
net.mamoe.mirai.contact.sendMessage
import
net.mamoe.mirai.utils.
SimpleLogger
import
net.mamoe.mirai.utils.
*
import
java.io.File
import
java.util.*
import
java.util.concurrent.LinkedBlockingQueue
...
...
@@ -46,12 +45,19 @@ object MiraiConsole {
var
path
:
String
=
System
.
getProperty
(
"user.dir"
)
val
version
=
"0.01"
var
coreVersion
=
"
0.15
"
val
version
=
"
v
0.01"
var
coreVersion
=
"
v0.15.1
"
val
build
=
"Beta"
fun
start
()
{
logger
(
"Mirai-console [v$version $build | core version v$coreVersion] is still in testing stage, majority feature is available"
)
lateinit
var
frontEnd
:
MiraiConsoleUI
fun
start
(
frontEnd
:
MiraiConsoleUI
)
{
this
.
frontEnd
=
frontEnd
frontEnd
.
pushVersion
(
version
,
build
,
coreVersion
)
logger
(
"Mirai-console [$version $build | core version $coreVersion] is still in testing stage, majority feature is available"
)
logger
(
"Mirai-console now running under "
+
System
.
getProperty
(
"user.dir"
...
...
@@ -115,12 +121,47 @@ object MiraiConsole {
logger
(
"[Bot Login]"
,
0
,
"login..."
)
try
{
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
)
}
},
SimpleLogger
(
"Login Helper"
)
{
_
,
message
,
e
->
logger
(
"[Login Helper]"
,
qqNumber
,
message
)
if
(
e
!=
null
)
{
logger
(
"[NETWORK ERROR]"
,
qqNumber
,
e
.
toString
())
//因为在一页 所以可以不打QQ
e
.
printStackTrace
()
}
}
)
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
(
"[Bot Login]"
,
0
,
"$qqNumber login successes"
)
frontEnd
.
pushBot
(
bot
)
}
}
catch
(
e
:
Exception
)
{
logger
(
...
...
@@ -128,7 +169,6 @@ object MiraiConsole {
0
,
"$qqNumber login failed -> "
+
e
.
message
)
e
.
printStackTrace
()
}
true
}
...
...
@@ -283,7 +323,7 @@ object MiraiConsole {
operator
fun
invoke
(
identityStr
:
String
,
identity
:
Long
,
any
:
Any
?
=
null
)
{
if
(
any
!=
null
)
{
MiraiConsoleUI
.
pushLog
(
identity
,
"$identityStr: $any"
)
frontEnd
.
pushLog
(
identity
,
"$identityStr: $any"
)
}
}
}
...
...
@@ -301,18 +341,5 @@ object MiraiConsole {
}
class
MiraiConsoleLoader
{
companion
object
{
@JvmStatic
fun
main
(
args
:
Array
<
String
>)
{
MiraiConsoleUI
.
start
()
MiraiConsole
.
start
()
Runtime
.
getRuntime
().
addShutdownHook
(
thread
(
start
=
false
)
{
MiraiConsole
.
stop
()
})
}
}
}
mirai-console/src/main/kotlin/net/mamoe/mirai/console/MiraiConsoleUI.kt
View file @
eb866066
package
net.mamoe.mirai.console
import
com.googlecode.lanterna.SGR
import
com.googlecode.lanterna.TerminalSize
import
com.googlecode.lanterna.TextColor
import
com.googlecode.lanterna.graphics.TextGraphics
import
com.googlecode.lanterna.input.KeyStroke
import
com.googlecode.lanterna.input.KeyType
import
com.googlecode.lanterna.terminal.DefaultTerminalFactory
import
com.googlecode.lanterna.terminal.Terminal
import
com.googlecode.lanterna.terminal.TerminalResizeListener
import
com.googlecode.lanterna.terminal.swing.SwingTerminal
import
com.googlecode.lanterna.terminal.swing.SwingTerminalFontConfiguration
import
com.googlecode.lanterna.terminal.swing.SwingTerminalFrame
import
kotlinx.coroutines.GlobalScope
import
kotlinx.coroutines.Job
import
kotlinx.coroutines.delay
import
kotlinx.coroutines.launch
import
net.mamoe.mirai.console.MiraiConsoleUI.LoggerDrawer.cleanPage
import
net.mamoe.mirai.console.MiraiConsoleUI.LoggerDrawer.drawLog
import
net.mamoe.mirai.console.MiraiConsoleUI.LoggerDrawer.redrawLogs
import
java.awt.Font
import
java.io.OutputStream
import
java.io.PrintStream
import
java.nio.charset.Charset
import
java.util.*
import
kotlin.concurrent.thread
import
net.mamoe.mirai.Bot
/**
* 此文件不推荐任何人看
* 可能导致
* 1:心肌梗死
* 2:呼吸困难
* 3:想要重写但是发现改任何一个看似不合理的地方都会崩
*
* @author NaturalHG
*
* 只需要实现一个这个 传入MiraiConsole 就可以绑定UI层与Console层
* 注意线程
*/
@SuppressWarnings
(
"UNCHECKED"
)
object
MiraiConsoleUI
{
val
cacheLogSize
=
50
interface
MiraiConsoleUI
{
/**
* 让UI层展示一条log
*
* identity:log所属的screen, Main=0; Bot=Bot.uin
*/
fun
pushLog
(
identity
:
Long
,
message
:
String
)
/**
* 让UI层准备接受新增的一个BOT
*/
fun
prePushBot
(
identity
:
Long
)
/**
* 让UI层接受一个新的bot
* */
fun
pushBot
(
bot
:
Bot
)
fun
pushVersion
(
consoleVersion
:
String
,
consoleBuild
:
String
,
coreVersion
:
String
)
/**
* 让UI层提供一个Input
* 这个Input 不 等于 Command
*
*/
suspend
fun
requestInput
(
question
:
String
):
String
/**
* 让UI层更新BOT管理员的数据
*/
fun
pushBotAdminStatus
(
identity
:
Long
,
admins
:
List
<
Long
>
)
val
log
=
mutableMapOf
<
Long
,
LimitLinkedQueue
<
String
>>().
also
{
it
[
0L
]
=
LimitLinkedQueue
(
cacheLogSize
)
it
[
2821869985L
]
=
LimitLinkedQueue
(
cacheLogSize
)
}
val
botAdminCount
=
mutableMapOf
<
Long
,
Long
>()
private
val
screens
=
mutableListOf
(
0L
,
2821869985L
)
private
var
currentScreenId
=
0
fun
addBotScreen
(
uin
:
Long
)
{
screens
.
add
(
uin
)
log
[
uin
]
=
LimitLinkedQueue
(
cacheLogSize
)
botAdminCount
[
uin
]
=
0
}
lateinit
var
terminal
:
Terminal
lateinit
var
textGraphics
:
TextGraphics
var
hasStart
=
false
private
lateinit
var
internalPrinter
:
PrintStream
fun
start
()
{
if
(
hasStart
)
{
return
}
internalPrinter
=
System
.
out
hasStart
=
true
val
defaultTerminalFactory
=
DefaultTerminalFactory
(
internalPrinter
,
System
.
`in`
,
Charset
.
defaultCharset
())
val
fontSize
=
12
defaultTerminalFactory
.
setInitialTerminalSize
(
TerminalSize
(
101
,
60
)
)
.
setTerminalEmulatorFontConfiguration
(
SwingTerminalFontConfiguration
.
newInstance
(
Font
(
"Monospaced"
,
Font
.
PLAIN
,
fontSize
)
)
)
try
{
terminal
=
defaultTerminalFactory
.
createTerminal
()
terminal
.
enterPrivateMode
()
terminal
.
clearScreen
()
terminal
.
setCursorVisible
(
false
)
}
catch
(
e
:
Exception
)
{
try
{
terminal
=
SwingTerminalFrame
(
"Mirai Console"
)
terminal
.
enterPrivateMode
()
terminal
.
clearScreen
()
terminal
.
setCursorVisible
(
false
)
}
catch
(
e
:
Exception
)
{
error
(
"can not create terminal"
)
}
}
textGraphics
=
terminal
.
newTextGraphics
()
/*
var lastRedrawTime = 0L
var lastNewWidth = 0
var lastNewHeight = 0
terminal.addResizeListener(TerminalResizeListener { terminal1: Terminal, newSize: TerminalSize ->
try {
if (lastNewHeight == newSize.rows
&&
lastNewWidth == newSize.columns
) {
return@TerminalResizeListener
}
lastNewHeight = newSize.rows
lastNewWidth = newSize.columns
terminal.clearScreen()
if(terminal !is SwingTerminalFrame) {
Thread.sleep(300)
}
update()
redrawCommand()
redrawLogs(log[screens[currentScreenId]]!!)
}catch (ignored:Exception){
}
})
*/
var
lastJob
:
Job
?
=
null
terminal
.
addResizeListener
(
TerminalResizeListener
{
terminal1
:
Terminal
,
newSize
:
TerminalSize
->
lastJob
=
GlobalScope
.
launch
{
delay
(
300
)
if
(
lastJob
==
coroutineContext
[
Job
])
{
terminal
.
clearScreen
()
//inited = false
update
()
redrawCommand
()
redrawLogs
(
log
[
screens
[
currentScreenId
]]
!!
)
}
}
})
if
(
terminal
!
is
SwingTerminalFrame
)
{
System
.
setOut
(
PrintStream
(
object
:
OutputStream
()
{
var
builder
=
java
.
lang
.
StringBuilder
()
override
fun
write
(
b
:
Int
)
{
with
(
b
.
toChar
())
{
if
(
this
==
'\n'
)
{
pushLog
(
0
,
builder
.
toString
())
builder
=
java
.
lang
.
StringBuilder
()
}
else
{
builder
.
append
(
this
)
}
}
}
}))
}
System
.
setErr
(
System
.
out
)
update
()
val
charList
=
listOf
(
','
,
'.'
,
'/'
,
'@'
,
'#'
,
'$'
,
'%'
,
'^'
,
'&'
,
'*'
,
'('
,
')'
,
'_'
,
'='
,
'+'
,
'!'
,
' '
)
thread
{
while
(
true
)
{
var
keyStroke
:
KeyStroke
=
terminal
.
readInput
()
when
(
keyStroke
.
keyType
)
{
KeyType
.
ArrowLeft
->
{
currentScreenId
=
getLeftScreenId
()
clearRows
(
2
)
cleanPage
()
update
()
}
KeyType
.
ArrowRight
->
{
currentScreenId
=
getRightScreenId
()
clearRows
(
2
)
cleanPage
()
update
()
}
KeyType
.
Enter
->
{
MiraiConsole
.
CommandListener
.
commandChannel
.
offer
(
commandBuilder
.
toString
()
)
emptyCommand
()
}
else
->
{
if
(
keyStroke
.
character
!=
null
)
{
if
(
keyStroke
.
character
.
toInt
()
==
8
)
{
deleteCommandChar
()
}
if
(
keyStroke
.
character
.
isLetterOrDigit
()
||
charList
.
contains
(
keyStroke
.
character
))
{
addCommandChar
(
keyStroke
.
character
)
}
}
}
}
}
}
}
private
fun
getLeftScreenId
():
Int
{
var
newId
=
currentScreenId
-
1
if
(
newId
<
0
)
{
newId
=
screens
.
size
-
1
}
return
newId
}
private
fun
getRightScreenId
():
Int
{
var
newId
=
1
+
currentScreenId
if
(
newId
>=
screens
.
size
)
{
newId
=
0
}
return
newId
}
private
fun
getScreenName
(
id
:
Int
):
String
{
return
when
(
screens
[
id
])
{
0L
->
{
"Console Screen"
}
else
->
{
"Bot: ${screens[id]}"
}
}
}
fun
clearRows
(
row
:
Int
)
{
textGraphics
.
putString
(
0
,
row
,
" "
.
repeat
(
terminal
.
terminalSize
.
columns
)
)
}
fun
drawFrame
(
title
:
String
)
{
val
width
=
terminal
.
terminalSize
.
columns
val
height
=
terminal
.
terminalSize
.
rows
terminal
.
setBackgroundColor
(
TextColor
.
ANSI
.
DEFAULT
)
val
mainTitle
=
"Mirai Console v0.01 Core v0.15"
textGraphics
.
foregroundColor
=
TextColor
.
ANSI
.
WHITE
textGraphics
.
backgroundColor
=
TextColor
.
ANSI
.
GREEN
textGraphics
.
putString
((
width
-
mainTitle
.
length
)
/
2
,
1
,
mainTitle
,
SGR
.
BOLD
)
textGraphics
.
foregroundColor
=
TextColor
.
ANSI
.
DEFAULT
textGraphics
.
backgroundColor
=
TextColor
.
ANSI
.
DEFAULT
textGraphics
.
putString
(
2
,
3
,
"-"
.
repeat
(
width
-
4
))
textGraphics
.
putString
(
2
,
5
,
"-"
.
repeat
(
width
-
4
))
textGraphics
.
putString
(
2
,
height
-
4
,
"-"
.
repeat
(
width
-
4
))
textGraphics
.
putString
(
2
,
height
-
3
,
"|>>>"
)
textGraphics
.
putString
(
width
-
3
,
height
-
3
,
"|"
)
textGraphics
.
putString
(
2
,
height
-
2
,
"-"
.
repeat
(
width
-
4
))
textGraphics
.
foregroundColor
=
TextColor
.
ANSI
.
DEFAULT
textGraphics
.
backgroundColor
=
TextColor
.
ANSI
.
DEFAULT
val
leftName
=
getScreenName
(
getLeftScreenId
())
// clearRows(2)
textGraphics
.
putString
((
width
-
title
.
length
)
/
2
-
"$leftName << "
.
length
,
2
,
"$leftName << "
)
textGraphics
.
foregroundColor
=
TextColor
.
ANSI
.
WHITE
textGraphics
.
backgroundColor
=
TextColor
.
ANSI
.
YELLOW
textGraphics
.
putString
((
width
-
title
.
length
)
/
2
,
2
,
title
,
SGR
.
BOLD
)
textGraphics
.
foregroundColor
=
TextColor
.
ANSI
.
DEFAULT
textGraphics
.
backgroundColor
=
TextColor
.
ANSI
.
DEFAULT
val
rightName
=
getScreenName
(
getRightScreenId
())
textGraphics
.
putString
((
width
+
title
.
length
)
/
2
+
1
,
2
,
">> $rightName"
)
}
fun
drawMainFrame
(
onlineBotCount
:
Number
)
{
drawFrame
(
"Console Screen"
)
val
width
=
terminal
.
terminalSize
.
columns
textGraphics
.
foregroundColor
=
TextColor
.
ANSI
.
DEFAULT
textGraphics
.
backgroundColor
=
TextColor
.
ANSI
.
DEFAULT
clearRows
(
4
)
textGraphics
.
putString
(
2
,
4
,
"|Online Bots: $onlineBotCount"
)
textGraphics
.
putString
(
width
-
2
-
"Powered By Mamoe Technologies|"
.
length
,
4
,
"Powered By Mamoe Technologies|"
)
}
fun
drawBotFrame
(
qq
:
Long
,
adminCount
:
Number
)
{
drawFrame
(
"Bot: $qq"
)
val
width
=
terminal
.
terminalSize
.
columns
textGraphics
.
foregroundColor
=
TextColor
.
ANSI
.
DEFAULT
textGraphics
.
backgroundColor
=
TextColor
.
ANSI
.
DEFAULT
clearRows
(
4
)
textGraphics
.
putString
(
2
,
4
,
"|Admins: $adminCount"
)
textGraphics
.
putString
(
width
-
2
-
"Add admins via commands|"
.
length
,
4
,
"Add admins via commands|"
)
}
object
LoggerDrawer
{
var
currentHeight
=
6
fun
drawLog
(
string
:
String
,
flush
:
Boolean
=
true
)
{
val
maxHeight
=
terminal
.
terminalSize
.
rows
-
4
val
heightNeed
=
(
string
.
length
/
(
terminal
.
terminalSize
.
columns
-
6
))
+
1
if
(
currentHeight
+
heightNeed
>
maxHeight
)
{
cleanPage
()
}
val
width
=
terminal
.
terminalSize
.
columns
-
7
var
x
=
string
while
(
true
)
{
if
(
x
==
""
)
break
val
toWrite
=
if
(
x
.
length
>
width
)
{
x
.
substring
(
0
,
width
).
also
{
x
=
x
.
substring
(
width
)
}
}
else
{
x
.
also
{
x
=
""
}
}
try
{
textGraphics
.
foregroundColor
=
TextColor
.
ANSI
.
GREEN
textGraphics
.
backgroundColor
=
TextColor
.
ANSI
.
DEFAULT
textGraphics
.
putString
(
3
,
currentHeight
,
toWrite
,
SGR
.
ITALIC
)
}
catch
(
ignored
:
Exception
)
{
//
}
++
currentHeight
}
if
(
flush
&&
terminal
is
SwingTerminalFrame
)
{
terminal
.
flush
()
}
}
fun
cleanPage
()
{
for
(
index
in
6
until
terminal
.
terminalSize
.
rows
-
4
)
{
clearRows
(
index
)
}
currentHeight
=
6
}
fun
redrawLogs
(
toDraw
:
List
<
String
>)
{
//this.cleanPage()
currentHeight
=
6
var
logsToDraw
=
0
var
vara
=
0
toDraw
.
forEach
{
val
heightNeed
=
(
it
.
length
/
(
terminal
.
terminalSize
.
columns
-
6
))
+
1
vara
+=
heightNeed
if
(
currentHeight
+
vara
<
terminal
.
terminalSize
.
rows
-
4
)
{
logsToDraw
++
}
else
{
return
@
forEach
}
}
for
(
index
in
0
until
logsToDraw
)
{
drawLog
(
toDraw
[
logsToDraw
-
index
-
1
],
false
)
}
if
(
terminal
is
SwingTerminalFrame
)
{
terminal
.
flush
()
}
}
}
fun
pushLog
(
uin
:
Long
,
str
:
String
)
{
log
[
uin
]
!!
.
push
(
str
)
if
(
uin
==
screens
[
currentScreenId
])
{
drawLog
(
str
)
}
}
var
commandBuilder
=
StringBuilder
()
fun
redrawCommand
()
{
val
height
=
terminal
.
terminalSize
.
rows
val
width
=
terminal
.
terminalSize
.
columns
clearRows
(
height
-
3
)
textGraphics
.
foregroundColor
=
TextColor
.
ANSI
.
DEFAULT
textGraphics
.
putString
(
2
,
height
-
3
,
"|>>>"
)
textGraphics
.
putString
(
width
-
3
,
height
-
3
,
"|"
)
textGraphics
.
foregroundColor
=
TextColor
.
ANSI
.
WHITE
textGraphics
.
backgroundColor
=
TextColor
.
ANSI
.
BLACK
textGraphics
.
putString
(
7
,
height
-
3
,
commandBuilder
.
toString
())
if
(
terminal
is
SwingTerminalFrame
)
{
terminal
.
flush
()
}
textGraphics
.
backgroundColor
=
TextColor
.
ANSI
.
DEFAULT
}
private
fun
addCommandChar
(
c
:
Char
)
{
if
(
commandBuilder
.
isEmpty
()
&&
c
!=
'/'
)
{
addCommandChar
(
'/'
)
}
textGraphics
.
foregroundColor
=
TextColor
.
ANSI
.
WHITE
textGraphics
.
backgroundColor
=
TextColor
.
ANSI
.
BLACK
val
height
=
terminal
.
terminalSize
.
rows
commandBuilder
.
append
(
c
)
if
(
terminal
is
SwingTerminalFrame
)
{
redrawCommand
()
}
else
{
textGraphics
.
putString
(
6
+
commandBuilder
.
length
,
height
-
3
,
c
.
toString
())
}
textGraphics
.
backgroundColor
=
TextColor
.
ANSI
.
DEFAULT
}
private
fun
deleteCommandChar
()
{
if
(!
commandBuilder
.
isEmpty
())
{
commandBuilder
=
StringBuilder
(
commandBuilder
.
toString
().
substring
(
0
,
commandBuilder
.
length
-
1
))
}
val
height
=
terminal
.
terminalSize
.
rows
if
(
terminal
is
SwingTerminalFrame
)
{
redrawCommand
()
}
else
{
textGraphics
.
putString
(
7
+
commandBuilder
.
length
,
height
-
3
,
" "
)
}
}
var
lastEmpty
:
Job
?
=
null
private
fun
emptyCommand
()
{
commandBuilder
=
StringBuilder
()
if
(
terminal
is
SwingTerminal
)
{
redrawCommand
()
terminal
.
flush
()
}
else
{
lastEmpty
=
GlobalScope
.
launch
{
delay
(
100
)
if
(
lastEmpty
==
coroutineContext
[
Job
])
{
terminal
.
clearScreen
()
//inited = false
update
()
redrawCommand
()
redrawLogs
(
log
[
screens
[
currentScreenId
]]
!!
)
}
}
}
}
fun
update
()
{
when
(
screens
[
currentScreenId
])
{
0L
->
{
drawMainFrame
(
screens
.
size
-
1
)
}
else
->
{
drawBotFrame
(
screens
[
currentScreenId
],
0
)
}
}
redrawLogs
(
log
[
screens
[
currentScreenId
]]
!!
)
}
}
class
LimitLinkedQueue
<
T
>(
val
limit
:
Int
=
50
)
:
LinkedList
<
T
>(),
List
<
T
>
{
override
fun
push
(
e
:
T
)
{
if
(
size
>=
limit
)
{
pollLast
()
}
super
.
push
(
e
)
}
}
\ No newline at end of file
mirai-core/src/jvmMain/kotlin/net/mamoe/mirai/utils/BotConfigurationJvm.kt
View file @
eb866066
...
...
@@ -39,53 +39,79 @@ import kotlin.coroutines.EmptyCoroutineContext
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
(),
val
overrideLogger
:
MiraiLogger
?
=
null
)
:
LoginSolver
()
{
fun
getLogger
(
bot
:
Bot
):
MiraiLogger
{
if
(
overrideLogger
!=
null
){
return
overrideLogger
}
return
bot
.
logger
}
override
suspend
fun
onSolvePicCaptcha
(
bot
:
Bot
,
data
:
IoBuffer
):
String
?
=
loginSolverLock
.
withLock
{
val
logger
=
getLogger
(
bot
)
val
tempFile
:
File
=
createTempFile
(
suffix
=
".png"
).
apply
{
deleteOnExit
()
}
withContext
(
Dispatchers
.
IO
)
{
tempFile
.
createNewFile
()
bot
.
logger
.
info
(
"需要图片验证码登录, 验证码为 4 字母"
)
logger
.
info
(
"需要图片验证码登录, 验证码为 4 字母"
)
try
{
tempFile
.
writeChannel
().
apply
{
writeFully
(
data
);
close
()
}
bot
.
logger
.
info
(
"将会显示字符图片. 若看不清字符图片, 请查看文件 ${tempFile.absolutePath}"
)
logger
.
info
(
"将会显示字符图片. 若看不清字符图片, 请查看文件 ${tempFile.absolutePath}"
)
}
catch
(
e
:
Exception
)
{
bot
.
logger
.
info
(
"无法写出验证码文件(${e.message}), 请尝试查看以上字符图片"
)
logger
.
info
(
"无法写出验证码文件(${e.message}), 请尝试查看以上字符图片"
)
}
tempFile
.
inputStream
().
use
{
val
img
=
ImageIO
.
read
(
it
)
if
(
img
==
null
)
{
bot
.
logger
.
info
(
"无法创建字符图片. 请查看文件"
)
logger
.
info
(
"无法创建字符图片. 请查看文件"
)
}
else
{
bot
.
logger
.
info
(
img
.
createCharImg
())
logger
.
info
(
img
.
createCharImg
())
}
}
}
bot
.
logger
.
info
(
"请输入 4 位字母验证码. 若要更换验证码, 请直接回车"
)
return
readLine
(
)
!!
.
takeUnless
{
it
.
isEmpty
()
||
it
.
length
!=
4
}.
also
{
bot
.
logger
.
info
(
"正在提交[$it]中..."
)
logger
.
info
(
"请输入 4 位字母验证码. 若要更换验证码, 请直接回车"
)
return
reader
(
"请输入 4 位字母验证码. 若要更换验证码, 请直接回车"
)
!!
.
takeUnless
{
it
.
isEmpty
()
||
it
.
length
!=
4
}.
also
{
logger
.
info
(
"正在提交[$it]中..."
)
}
}
override
suspend
fun
onSolveSliderCaptcha
(
bot
:
Bot
,
url
:
String
):
String
?
=
loginSolverLock
.
withLock
{
bot
.
logger
.
info
(
"需要滑动验证码"
)
bot
.
logger
.
info
(
"请在任意浏览器中打开以下链接并完成验证码. "
)
bot
.
logger
.
info
(
"完成后请输入任意字符 "
)
bot
.
logger
.
info
(
url
)
return
readLine
().
also
{
bot
.
logger
.
info
(
"正在提交中..."
)
val
logger
=
getLogger
(
bot
)
logger
.
info
(
"需要滑动验证码"
)
logger
.
info
(
"请在任意浏览器中打开以下链接并完成验证码. "
)
logger
.
info
(
"完成后请输入任意字符 "
)
logger
.
info
(
url
)
return
reader
(
"完成后请输入任意字符"
).
also
{
logger
.
info
(
"正在提交中..."
)
}
}
override
suspend
fun
onSolveUnsafeDeviceLoginVerify
(
bot
:
Bot
,
url
:
String
):
String
?
=
loginSolverLock
.
withLock
{
bot
.
logger
.
info
(
"需要进行账户安全认证"
)
bot
.
logger
.
info
(
"该账户有[设备锁]/[不常用登陆地点]/[不常用设备登陆]的问题"
)
bot
.
logger
.
info
(
"完成以下账号认证即可成功登陆|理论本认证在mirai每个账户中最多出现1次"
)
bot
.
logger
.
info
(
"请将该链接在QQ浏览器中打开并完成认证, 成功后输入任意字符"
)
bot
.
logger
.
info
(
"这步操作将在后续的版本中优化"
)
bot
.
logger
.
info
(
url
)
return
readLine
().
also
{
bot
.
logger
.
info
(
"正在提交中..."
)
val
logger
=
getLogger
(
bot
)
logger
.
info
(
"需要进行账户安全认证"
)
logger
.
info
(
"该账户有[设备锁]/[不常用登陆地点]/[不常用设备登陆]的问题"
)
logger
.
info
(
"完成以下账号认证即可成功登陆|理论本认证在mirai每个账户中最多出现1次"
)
logger
.
info
(
"请将该链接在QQ浏览器中打开并完成认证, 成功后输入任意字符"
)
logger
.
info
(
"这步操作将在后续的版本中优化"
)
logger
.
info
(
url
)
return
reader
(
"完成后请输入任意字符"
).
also
{
logger
.
info
(
"正在提交中..."
)
}
}
...
...
settings.gradle
View file @
eb866066
...
...
@@ -44,6 +44,8 @@ include(':mirai-core-qqandroid')
include
(
':mirai-japt'
)
include
(
':mirai-console'
)
include
(
':mirai-console-graphical'
)
include
(
':mirai-console-terminal'
)
//include(':mirai-api')
include
(
':mirai-api-http'
)
include
(
':mirai-demos:mirai-demo-1'
)
...
...
Write
Preview
Markdown
is supported
0%
Try again
or
attach a new file
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment