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
ef98f22d
Commit
ef98f22d
authored
Sep 13, 2019
by
Him188moe
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
Updated network
parent
4a319bf5
Changes
17
Hide whitespace changes
Inline
Side-by-side
Showing
17 changed files
with
511 additions
and
460 deletions
+511
-460
mirai-api/src/main/java/net/mamoe/mirai/Bot.java
mirai-api/src/main/java/net/mamoe/mirai/Bot.java
+15
-0
mirai-api/src/main/java/net/mamoe/mirai/utils/BotAccount.java
...i-api/src/main/java/net/mamoe/mirai/utils/BotAccount.java
+0
-0
mirai-core/pom.xml
mirai-core/pom.xml
+7
-0
mirai-core/src/main/java/net/mamoe/mirai/Bot.java
mirai-core/src/main/java/net/mamoe/mirai/Bot.java
+5
-5
mirai-core/src/main/java/net/mamoe/mirai/contact/Group.kt
mirai-core/src/main/java/net/mamoe/mirai/contact/Group.kt
+1
-1
mirai-core/src/main/java/net/mamoe/mirai/contact/QQ.kt
mirai-core/src/main/java/net/mamoe/mirai/contact/QQ.kt
+1
-1
mirai-core/src/main/java/net/mamoe/mirai/network/BotNetworkHandler.kt
...rc/main/java/net/mamoe/mirai/network/BotNetworkHandler.kt
+34
-404
mirai-core/src/main/java/net/mamoe/mirai/network/BotNetworkHandlerImpl.kt
...ain/java/net/mamoe/mirai/network/BotNetworkHandlerImpl.kt
+413
-0
mirai-core/src/main/java/net/mamoe/mirai/network/LoginSession.kt
...ore/src/main/java/net/mamoe/mirai/network/LoginSession.kt
+2
-1
mirai-core/src/main/java/net/mamoe/mirai/network/handler/ActionPacketHandler.kt
...va/net/mamoe/mirai/network/handler/ActionPacketHandler.kt
+11
-7
mirai-core/src/main/java/net/mamoe/mirai/network/handler/DataPacketSocket.kt
.../java/net/mamoe/mirai/network/handler/DataPacketSocket.kt
+5
-0
mirai-core/src/main/java/net/mamoe/mirai/network/handler/DebugPacketHandler.kt
...ava/net/mamoe/mirai/network/handler/DebugPacketHandler.kt
+4
-2
mirai-core/src/main/java/net/mamoe/mirai/network/handler/MessagePacketHandler.kt
...a/net/mamoe/mirai/network/handler/MessagePacketHandler.kt
+4
-2
mirai-core/src/main/java/net/mamoe/mirai/network/handler/PacketHandler.kt
...ain/java/net/mamoe/mirai/network/handler/PacketHandler.kt
+2
-2
mirai-core/src/main/java/net/mamoe/mirai/network/packet/ServerEvent.kt
...c/main/java/net/mamoe/mirai/network/packet/ServerEvent.kt
+1
-1
mirai-core/src/main/java/net/mamoe/mirai/network/packet/Session.kt
...e/src/main/java/net/mamoe/mirai/network/packet/Session.kt
+1
-0
mirai-core/src/main/java/net/mamoe/mirai/network/packet/VerificationCode.kt
...n/java/net/mamoe/mirai/network/packet/VerificationCode.kt
+5
-34
No files found.
mirai-api/src/main/java/net/mamoe/mirai/Bot.java
0 → 100644
View file @
ef98f22d
package
net.mamoe.mirai
;
import
net.mamoe.mirai.utils.BotAccount
;
import
java.io.Closeable
;
/**
* @author Him188moe
*/
public
interface
Bot
extends
Closeable
{
BotAccount
getAccount
();
// TODO: 2019/9/13 add more
}
mirai-
core
/src/main/java/net/mamoe/mirai/utils/BotAccount.java
→
mirai-
api
/src/main/java/net/mamoe/mirai/utils/BotAccount.java
View file @
ef98f22d
File moved
mirai-core/pom.xml
View file @
ef98f22d
...
@@ -17,6 +17,13 @@
...
@@ -17,6 +17,13 @@
</parent>
</parent>
<dependencies>
<dependencies>
<dependency>
<groupId>
net.mamoe
</groupId>
<artifactId>
mirai-api
</artifactId>
<version>
1.0
</version>
<scope>
compile
</scope>
</dependency>
<dependency>
<dependency>
<groupId>
com.google.protobuf
</groupId>
<groupId>
com.google.protobuf
</groupId>
<artifactId>
protobuf-java
</artifactId>
<artifactId>
protobuf-java
</artifactId>
...
...
mirai-core/src/main/java/net/mamoe/mirai/Bot.java
View file @
ef98f22d
...
@@ -3,7 +3,7 @@ package net.mamoe.mirai;
...
@@ -3,7 +3,7 @@ package net.mamoe.mirai;
import
lombok.Getter
;
import
lombok.Getter
;
import
net.mamoe.mirai.contact.Group
;
import
net.mamoe.mirai.contact.Group
;
import
net.mamoe.mirai.contact.QQ
;
import
net.mamoe.mirai.contact.QQ
;
import
net.mamoe.mirai.network.BotNetworkHandler
;
import
net.mamoe.mirai.network.BotNetworkHandler
Impl
;
import
net.mamoe.mirai.utils.BotAccount
;
import
net.mamoe.mirai.utils.BotAccount
;
import
net.mamoe.mirai.utils.ContactList
;
import
net.mamoe.mirai.utils.ContactList
;
import
net.mamoe.mirai.utils.config.MiraiConfigSection
;
import
net.mamoe.mirai.utils.config.MiraiConfigSection
;
...
@@ -19,7 +19,7 @@ import java.util.concurrent.atomic.AtomicInteger;
...
@@ -19,7 +19,7 @@ import java.util.concurrent.atomic.AtomicInteger;
* <br>
* <br>
* {@link Bot} 由 3 个模块组成.
* {@link Bot} 由 3 个模块组成.
* {@linkplain ContactSystem 联系人管理}: 可通过 {@link Bot#contacts} 访问
* {@linkplain ContactSystem 联系人管理}: 可通过 {@link Bot#contacts} 访问
* {@linkplain BotNetworkHandler 网络处理器}: 可通过 {@link Bot#network} 访问
* {@linkplain BotNetworkHandler
Impl
网络处理器}: 可通过 {@link Bot#network} 访问
* {@linkplain BotAccount 机器人账号信息}: 可通过 {@link Bot#account} 访问
* {@linkplain BotAccount 机器人账号信息}: 可通过 {@link Bot#account} 访问
* <br>
* <br>
* 若你需要得到机器人的 QQ 账号, 请访问 {@link Bot#account}
* 若你需要得到机器人的 QQ 账号, 请访问 {@link Bot#account}
...
@@ -29,7 +29,7 @@ import java.util.concurrent.atomic.AtomicInteger;
...
@@ -29,7 +29,7 @@ import java.util.concurrent.atomic.AtomicInteger;
* Bot that is the base of the whole program.
* Bot that is the base of the whole program.
* It consists of
* It consists of
* a {@link ContactSystem}, which manage contacts such as {@link QQ} and {@link Group};
* a {@link ContactSystem}, which manage contacts such as {@link QQ} and {@link Group};
* a {@link BotNetworkHandler}, which manages the connection to the server;
* a {@link BotNetworkHandler
Impl
}, which manages the connection to the server;
* a {@link BotAccount}, which stores the account information(e.g. qq number the bot)
* a {@link BotAccount}, which stores the account information(e.g. qq number the bot)
* <br>
* <br>
* To get all the QQ contacts, access {@link Bot#account}
* To get all the QQ contacts, access {@link Bot#account}
...
@@ -53,7 +53,7 @@ public final class Bot implements Closeable {
...
@@ -53,7 +53,7 @@ public final class Bot implements Closeable {
public
final
ContactSystem
contacts
=
new
ContactSystem
();
public
final
ContactSystem
contacts
=
new
ContactSystem
();
public
final
BotNetworkHandler
network
;
public
final
BotNetworkHandler
Impl
network
;
@Override
@Override
public
String
toString
()
{
public
String
toString
()
{
...
@@ -118,7 +118,7 @@ public final class Bot implements Closeable {
...
@@ -118,7 +118,7 @@ public final class Bot implements Closeable {
Objects
.
requireNonNull
(
owners
);
Objects
.
requireNonNull
(
owners
);
this
.
account
=
account
;
this
.
account
=
account
;
this
.
owners
=
Collections
.
unmodifiableList
(
owners
);
this
.
owners
=
Collections
.
unmodifiableList
(
owners
);
this
.
network
=
new
BotNetworkHandler
(
this
);
this
.
network
=
new
BotNetworkHandler
Impl
(
this
);
}
}
...
...
mirai-core/src/main/java/net/mamoe/mirai/contact/Group.kt
View file @
ef98f22d
...
@@ -26,7 +26,7 @@ class Group(bot: Bot, number: Long) : Contact(bot, number), Closeable {
...
@@ -26,7 +26,7 @@ class Group(bot: Bot, number: Long) : Contact(bot, number), Closeable {
val
members
=
ContactList
<
QQ
>()
val
members
=
ContactList
<
QQ
>()
override
fun
sendMessage
(
message
:
MessageChain
)
{
override
fun
sendMessage
(
message
:
MessageChain
)
{
bot
.
network
.
message
Handler
.
sendGroupMessage
(
this
,
message
)
bot
.
network
.
message
.
sendGroupMessage
(
this
,
message
)
}
}
override
fun
sendXMLMessage
(
message
:
String
)
{
override
fun
sendXMLMessage
(
message
:
String
)
{
...
...
mirai-core/src/main/java/net/mamoe/mirai/contact/QQ.kt
View file @
ef98f22d
...
@@ -19,7 +19,7 @@ import net.mamoe.mirai.message.defaults.MessageChain
...
@@ -19,7 +19,7 @@ import net.mamoe.mirai.message.defaults.MessageChain
*/
*/
class
QQ
(
bot
:
Bot
,
number
:
Long
)
:
Contact
(
bot
,
number
)
{
class
QQ
(
bot
:
Bot
,
number
:
Long
)
:
Contact
(
bot
,
number
)
{
override
fun
sendMessage
(
message
:
MessageChain
)
{
override
fun
sendMessage
(
message
:
MessageChain
)
{
bot
.
network
.
message
Handler
.
sendFriendMessage
(
this
,
message
)
bot
.
network
.
message
.
sendFriendMessage
(
this
,
message
)
}
}
override
fun
sendXMLMessage
(
message
:
String
)
{
override
fun
sendXMLMessage
(
message
:
String
)
{
...
...
mirai-core/src/main/java/net/mamoe/mirai/network/BotNetworkHandler.kt
View file @
ef98f22d
@
file
:
JvmMultifileClass
@
file
:
JvmName
(
"BotNetworkHandler"
)
package
net.mamoe.mirai.network
package
net.mamoe.mirai.network
import
net.mamoe.mirai.Bot
import
net.mamoe.mirai.network.BotNetworkHandlerImpl.BotSocket
import
net.mamoe.mirai.MiraiServer
import
net.mamoe.mirai.network.BotNetworkHandlerImpl.Login
import
net.mamoe.mirai.event.events.bot.BotLoginSucceedEvent
import
net.mamoe.mirai.event.events.network.BeforePacketSendEvent
import
net.mamoe.mirai.event.events.network.PacketSentEvent
import
net.mamoe.mirai.event.events.network.ServerPacketReceivedEvent
import
net.mamoe.mirai.event.hookWhile
import
net.mamoe.mirai.network.BotNetworkHandler.Login
import
net.mamoe.mirai.network.BotNetworkHandler.SocketHandler
import
net.mamoe.mirai.network.handler.*
import
net.mamoe.mirai.network.handler.*
import
net.mamoe.mirai.network.packet.
*
import
net.mamoe.mirai.network.packet.
ClientPacket
import
net.mamoe.mirai.network.packet.
login.*
import
net.mamoe.mirai.network.packet.
Packet
import
net.mamoe.mirai.
task.MiraiThreadPool
import
net.mamoe.mirai.
network.packet.ServerEventPacket
import
net.mamoe.mirai.
utils.*
import
net.mamoe.mirai.
network.packet.ServerPacket
import
java.io.Closeable
import
java.io.Closeable
import
java.net.DatagramPacket
import
java.net.DatagramSocket
import
java.net.InetSocketAddress
import
java.util.*
import
java.util.concurrent.CompletableFuture
import
java.util.concurrent.ScheduledFuture
import
java.util.concurrent.TimeUnit
import
javax.imageio.ImageIO
import
kotlin.reflect.KClass
/**
/**
* Mirai 的网络处理器, 它
处理所有数据包([Packet])的发送和接收
.
* Mirai 的网络处理器, 它
承担所有数据包([Packet])的处理任务
.
* [BotNetworkHandler] 是全
程
异步和线程安全的.
* [BotNetworkHandler] 是全异步和线程安全的.
*
*
* [BotNetworkHandler] 由 2 个模块构成:
* [BotNetworkHandler] 由 2 个模块构成:
* - [
SocketHandler
]: 处理数据包底层的发送([ByteArray])
* - [
BotSocket
]: 处理数据包底层的发送([ByteArray])
* - [PacketHandler]: 制作 [
Packet] 并传递给 [SocketHandler] 继续处理; 分析来自服务器的数据包
并处理
* - [PacketHandler]: 制作 [
ClientPacket] 并传递给 [BotSocket] 发送; 分析 [ServerPacket]
并处理
*
*
* 其中, [PacketHandler] 由 4 个子模块构成:
* 其中, [PacketHandler] 由 4 个子模块构成:
* - [DebugHandler] 输出 [Packet.toString]
* - [Debug
Packet
Handler] 输出 [Packet.toString]
* - [Login] 处理 touch/login/verification code 相关
* - [Login] 处理 touch/login/verification code 相关
* - [MessageHandler] 处理消息相关(群消息/好友消息)([ServerEventPacket])
* - [Message
Packet
Handler] 处理消息相关(群消息/好友消息)([ServerEventPacket])
* - [ActionHandler] 处理动作相关(踢人/加入群/好友列表等)
* - [Action
Packet
Handler] 处理动作相关(踢人/加入群/好友列表等)
*
*
* A BotNetworkHandler is used to connect with Tencent servers.
* A BotNetworkHandler is used to connect with Tencent servers.
*
*
* @author Him188moe
* @author Him188moe
*/
*/
@Suppress
(
"EXPERIMENTAL_API_USAGE"
)
//to simplify code
interface
BotNetworkHandler
:
Closeable
{
class
BotNetworkHandler
(
private
val
bot
:
Bot
)
:
Closeable
{
private
val
socket
:
SocketHandler
=
SocketHandler
()
fun
getSocket
():
DataPacketSocket
{
return
socket
}
lateinit
var
debugHandler
:
DebugHandler
lateinit
var
login
:
Login
lateinit
var
messageHandler
:
MessageHandler
lateinit
var
actionHandler
:
ActionHandler
val
packetHandlers
:
PacketHandlerList
=
PacketHandlerList
()
//private | internal
/**
/**
*
尝试登录
*
网络层处理器. 用于编码/解码 [Packet], 发送/接受 [ByteArray]
*
*
*
@param touchingTimeoutMillis 连接每个服务器的 timeout
*
java 调用方式: `botNetWorkHandler.getSocket()`
*/
*/
@JvmOverloads
val
socket
:
DataPacketSocket
internal
fun
tryLogin
(
touchingTimeoutMillis
:
Long
=
200
):
CompletableFuture
<
LoginState
>
{
val
ipQueue
:
LinkedList
<
String
>
=
LinkedList
(
Protocol
.
SERVER_IP
)
val
future
=
CompletableFuture
<
LoginState
>()
fun
login
()
{
this
.
socket
.
close
()
val
ip
=
ipQueue
.
poll
()
if
(
ip
==
null
)
{
future
.
complete
(
LoginState
.
UNKNOWN
)
//所有服务器均返回 UNKNOWN
return
}
this
@BotNetworkHandler
.
socket
.
touch
(
ip
,
touchingTimeoutMillis
).
get
().
let
{
state
->
if
(
state
==
LoginState
.
UNKNOWN
||
state
==
LoginState
.
TIMEOUT
)
{
login
()
//超时或未知, 重试连接下一个服务器
}
else
{
future
.
complete
(
state
)
}
}
}
login
()
return
future
}
private
lateinit
var
sessionKey
:
ByteArray
override
fun
close
()
{
this
.
packetHandlers
.
forEach
{
it
.
instance
.
close
()
}
this
.
socket
.
close
()
}
private
inner
class
SocketHandler
:
Closeable
,
DataPacketSocket
{
override
fun
distributePacket
(
packet
:
ServerPacket
)
{
try
{
packet
.
decode
()
}
catch
(
e
:
java
.
lang
.
Exception
)
{
e
.
printStackTrace
()
bot
.
debugPacket
(
packet
)
return
}
if
(
ServerPacketReceivedEvent
(
bot
,
packet
).
broadcast
().
isCancelled
)
{
debugHandler
.
onPacketReceived
(
packet
)
return
}
login
.
onPacketReceived
(
packet
)
packetHandlers
.
forEach
{
it
.
instance
.
onPacketReceived
(
packet
)
}
}
private
var
socket
:
DatagramSocket
?
=
null
internal
var
serverIP
:
String
=
""
set
(
value
)
{
field
=
value
restartSocket
()
}
internal
var
loginFuture
:
CompletableFuture
<
LoginState
>?
=
null
@Synchronized
private
fun
restartSocket
()
{
socket
?.
close
()
socket
=
DatagramSocket
(
0
)
socket
!!
.
connect
(
InetSocketAddress
(
serverIP
,
8000
))
Thread
{
while
(
socket
!!
.
isConnected
)
{
val
packet
=
DatagramPacket
(
ByteArray
(
2048
),
2048
)
kotlin
.
runCatching
{
socket
?.
receive
(
packet
)
}
.
onSuccess
{
MiraiThreadPool
.
getInstance
().
submit
{
try
{
distributePacket
(
ServerPacket
.
ofByteArray
(
packet
.
data
.
removeZeroTail
()))
}
catch
(
e
:
Exception
)
{
e
.
printStackTrace
()
}
}
}.
onFailure
{
if
(
it
.
message
==
"Socket closed"
||
it
.
message
==
"socket closed"
)
{
return
@Thread
}
it
.
printStackTrace
()
}
}
}.
start
()
}
/**
* Start network and touch the server
*/
fun
touch
(
serverAddress
:
String
,
timeoutMillis
:
Long
):
CompletableFuture
<
LoginState
>
{
bot
.
info
(
"Connecting server: $serverAddress"
)
if
(
this
@BotNetworkHandler
::
login
.
isInitialized
)
{
login
.
close
()
}
login
=
Login
()
this
.
loginFuture
=
CompletableFuture
()
serverIP
=
serverAddress
waitForPacket
(
ServerPacket
::
class
,
timeoutMillis
)
{
loginFuture
!!
.
complete
(
LoginState
.
TIMEOUT
)
}
sendPacket
(
ClientTouchPacket
(
bot
.
account
.
qqNumber
,
serverIP
))
return
this
.
loginFuture
!!
}
/**
* Not async
*/
@Synchronized
@ExperimentalUnsignedTypes
override
fun
sendPacket
(
packet
:
ClientPacket
)
{
checkNotNull
(
socket
)
{
"network closed"
}
if
(
socket
!!
.
isClosed
)
{
return
}
try
{
packet
.
encodePacket
()
if
(
BeforePacketSendEvent
(
bot
,
packet
).
broadcast
().
isCancelled
)
{
return
}
val
data
=
packet
.
toByteArray
()
socket
!!
.
send
(
DatagramPacket
(
data
,
data
.
size
))
bot
.
cyanL
(
"Packet sent: $packet"
)
PacketSentEvent
(
bot
,
packet
).
broadcast
()
}
catch
(
e
:
Throwable
)
{
e
.
printStackTrace
()
}
}
@Suppress
(
"UNCHECKED_CAST"
)
internal
fun
<
P
:
ServerPacket
>
waitForPacket
(
packetClass
:
KClass
<
P
>,
timeoutMillis
:
Long
,
timeout
:
()
->
Unit
)
{
var
got
=
false
ServerPacketReceivedEvent
::
class
.
hookWhile
{
if
(
packetClass
.
isInstance
(
it
.
packet
)
&&
it
.
bot
===
bot
)
{
got
=
true
true
}
else
{
false
}
}
MiraiThreadPool
.
getInstance
().
submit
{
val
startingTime
=
System
.
currentTimeMillis
()
while
(!
got
)
{
if
(
System
.
currentTimeMillis
()
-
startingTime
>
timeoutMillis
)
{
timeout
.
invoke
()
return
@
submit
}
Thread
.
sleep
(
10
)
}
}
}
override
fun
close
()
{
this
.
socket
?.
close
()
if
(
this
.
loginFuture
!=
null
)
{
if
(!
this
.
loginFuture
!!
.
isDone
)
{
this
.
loginFuture
!!
.
cancel
(
true
)
}
this
.
loginFuture
=
null
}
}
override
fun
isClosed
():
Boolean
{
return
this
.
socket
?.
isClosed
?:
true
}
}
/**
/**
* 处理登录过程
* Debug 包处理器. 仅输出包的信息. 调试阶段使用
*
* java 调用方式: `botNetWorkHandler.getDebug()`
*/
*/
inner
class
Login
:
Closeable
{
var
debug
:
DebugPacketHandler
private
lateinit
var
token00BA
:
ByteArray
private
lateinit
var
token0825
:
ByteArray
private
var
loginTime
:
Int
=
0
private
lateinit
var
loginIP
:
String
private
var
tgtgtKey
:
ByteArray
=
getRandomByteArray
(
16
)
private
var
tlv0105
:
ByteArray
=
lazyEncode
{
it
.
writeHex
(
"01 05 00 30"
)
it
.
writeHex
(
"00 01 01 02 00 14 01 01 00 10"
)
it
.
writeRandom
(
16
)
it
.
writeHex
(
"00 14 01 02 00 10"
)
it
.
writeRandom
(
16
)
}
/**
* 0828_decr_key
*/
private
lateinit
var
sessionResponseDecryptionKey
:
ByteArray
private
var
captchaSectionId
:
Int
=
1
private
var
captchaCache
:
ByteArray
?
=
byteArrayOf
()
//每次包只发一部分验证码来
private
var
heartbeatFuture
:
ScheduledFuture
<
*
>?
=
null
fun
onPacketReceived
(
packet
:
ServerPacket
)
{
when
(
packet
)
{
is
ServerTouchResponsePacket
->
{
if
(
packet
.
serverIP
!=
null
)
{
//redirection
socket
.
serverIP
=
packet
.
serverIP
!!
//connect(packet.serverIP!!)
socket
.
sendPacket
(
ClientServerRedirectionPacket
(
packet
.
serverIP
!!
,
bot
.
account
.
qqNumber
))
}
else
{
//password submission
this
.
loginIP
=
packet
.
loginIP
this
.
loginTime
=
packet
.
loginTime
this
.
token0825
=
packet
.
token0825
socket
.
sendPacket
(
ClientPasswordSubmissionPacket
(
bot
.
account
.
qqNumber
,
bot
.
account
.
password
,
packet
.
loginTime
,
packet
.
loginIP
,
this
.
tgtgtKey
,
packet
.
token0825
))
}
}
is
ServerLoginResponseFailedPacket
->
{
socket
.
loginFuture
?.
complete
(
packet
.
loginState
)
return
}
is
ServerVerificationCodeCorrectPacket
->
{
this
.
tgtgtKey
=
getRandomByteArray
(
16
)
this
.
token00BA
=
packet
.
token00BA
socket
.
sendPacket
(
ClientLoginResendPacket3105
(
bot
.
account
.
qqNumber
,
bot
.
account
.
password
,
this
.
loginTime
,
this
.
loginIP
,
this
.
tgtgtKey
,
this
.
token0825
,
this
.
token00BA
))
}
is
ServerLoginResponseVerificationCodeInitPacket
->
{
//[token00BA]来源之一: 验证码
this
.
token00BA
=
packet
.
token00BA
this
.
captchaCache
=
packet
.
verifyCodePart1
if
(
packet
.
unknownBoolean
!=
null
&&
packet
.
unknownBoolean
!!
)
{
this
.
captchaSectionId
=
1
socket
.
sendPacket
(
ClientVerificationCodeTransmissionRequestPacket
(
1
,
bot
.
account
.
qqNumber
,
this
.
token0825
,
this
.
captchaSectionId
++,
this
.
token00BA
))
}
}
is
ServerVerificationCodeTransmissionPacket
->
{
if
(
packet
is
ServerVerificationCodeWrongPacket
)
{
bot
.
error
(
"验证码错误, 请重新输入"
)
captchaSectionId
=
1
this
.
captchaCache
=
byteArrayOf
()
}
this
.
captchaCache
=
this
.
captchaCache
!!
+
packet
.
captchaSectionN
this
.
token00BA
=
packet
.
token00BA
if
(
packet
.
transmissionCompleted
)
{
bot
.
notice
(
CharImageUtil
.
createCharImg
(
ImageIO
.
read
(
this
.
captchaCache
!!
.
inputStream
())))
bot
.
notice
(
"需要验证码登录, 验证码为 4 字母"
)
try
{
(
MiraiServer
.
getInstance
().
parentFolder
+
"VerificationCode.png"
).
writeBytes
(
this
.
captchaCache
!!
)
bot
.
notice
(
"若看不清字符图片, 请查看 Mirai 根目录下 VerificationCode.png"
)
}
catch
(
e
:
Exception
)
{
bot
.
notice
(
"无法写出验证码文件, 请尝试查看以上字符图片"
)
}
bot
.
notice
(
"若要更换验证码, 请直接回车"
)
val
code
=
Scanner
(
System
.
`in`
).
nextLine
()
if
(
code
.
isEmpty
()
||
code
.
length
!=
4
)
{
this
.
captchaCache
=
byteArrayOf
()
this
.
captchaSectionId
=
1
socket
.
sendPacket
(
ClientVerificationCodeRefreshPacket
(
packet
.
packetIdLast
+
1
,
bot
.
account
.
qqNumber
,
token0825
))
}
else
{
socket
.
sendPacket
(
ClientVerificationCodeSubmitPacket
(
packet
.
packetIdLast
+
1
,
bot
.
account
.
qqNumber
,
token0825
,
code
,
packet
.
verificationToken
))
}
}
else
{
socket
.
sendPacket
(
ClientVerificationCodeTransmissionRequestPacket
(
packet
.
packetIdLast
+
1
,
bot
.
account
.
qqNumber
,
token0825
,
captchaSectionId
++,
token00BA
))
}
}
is
ServerLoginResponseSuccessPacket
->
{
this
.
sessionResponseDecryptionKey
=
packet
.
sessionResponseDecryptionKey
socket
.
sendPacket
(
ClientSessionRequestPacket
(
bot
.
account
.
qqNumber
,
socket
.
serverIP
,
packet
.
token38
,
packet
.
token88
,
packet
.
encryptionKey
,
this
.
tlv0105
))
}
//是ClientPasswordSubmissionPacket之后服务器回复的
is
ServerLoginResponseKeyExchangePacket
->
{
//if (packet.tokenUnknown != null) {
//this.token00BA = packet.token00BA!!
//println("token00BA changed!!! to " + token00BA.toUByteArray())
//}
if
(
packet
.
flag
==
ServerLoginResponseKeyExchangePacket
.
Flag
.
`
08
36
31
03
`
)
{
this
.
tgtgtKey
=
packet
.
tgtgtKey
socket
.
sendPacket
(
ClientLoginResendPacket3104
(
bot
.
account
.
qqNumber
,
bot
.
account
.
password
,
loginTime
,
loginIP
,
tgtgtKey
,
token0825
,
packet
.
tokenUnknown
?:
this
.
token00BA
,
packet
.
tlv0006
))
}
else
{
socket
.
sendPacket
(
ClientLoginResendPacket3106
(
bot
.
account
.
qqNumber
,
bot
.
account
.
password
,
loginTime
,
loginIP
,
tgtgtKey
,
token0825
,
packet
.
tokenUnknown
?:
token00BA
,
packet
.
tlv0006
))
}
}
is
ServerSessionKeyResponsePacket
->
{
sessionKey
=
packet
.
sessionKey
heartbeatFuture
=
MiraiThreadPool
.
getInstance
().
scheduleWithFixedDelay
({
socket
.
sendPacket
(
ClientHeartbeatPacket
(
bot
.
account
.
qqNumber
,
sessionKey
))
},
90000
,
90000
,
TimeUnit
.
MILLISECONDS
)
BotLoginSucceedEvent
(
bot
).
broadcast
()
/**
* 消息处理. 如发送好友消息, 接受群消息并触发事件
//登录成功后会收到大量上次的消息, 忽略掉
*
MiraiThreadPool
.
getInstance
().
schedule
({
* java 调用方式: `botNetWorkHandler.getMessage()`
messageHandler
.
ignoreMessage
=
false
*/
},
3
,
TimeUnit
.
SECONDS
)
var
message
:
MessagePacketHandler
this
.
tlv0105
=
packet
.
tlv0105
socket
.
loginFuture
!!
.
complete
(
LoginState
.
SUCCESS
)
}
is
ServerEventPacket
.
Raw
->
socket
.
distributePacket
(
packet
.
distribute
())
is
ServerVerificationCodePacket
.
Encrypted
->
socket
.
distributePacket
(
packet
.
decrypt
())
is
ServerLoginResponseVerificationCodeInitPacket
.
Encrypted
->
socket
.
distributePacket
(
packet
.
decrypt
())
is
ServerLoginResponseKeyExchangePacket
.
Encrypted
->
socket
.
distributePacket
(
packet
.
decrypt
(
this
.
tgtgtKey
))
is
ServerLoginResponseSuccessPacket
.
Encrypted
->
socket
.
distributePacket
(
packet
.
decrypt
(
this
.
tgtgtKey
))
is
ServerSessionKeyResponsePacket
.
Encrypted
->
socket
.
distributePacket
(
packet
.
decrypt
(
this
.
sessionResponseDecryptionKey
))
is
ServerTouchResponsePacket
.
Encrypted
->
socket
.
distributePacket
(
packet
.
decrypt
())
is
ServerAccountInfoResponsePacket
.
Encrypted
->
socket
.
distributePacket
(
packet
.
decrypt
(
sessionKey
))
is
ServerEventPacket
.
Raw
.
Encrypted
->
socket
.
distributePacket
(
packet
.
decrypt
(
sessionKey
))
is
ServerLoginSuccessPacket
,
is
ServerHeartbeatResponsePacket
,
is
UnknownServerPacket
->
{
//ignored
}
else
->
{
}
}
}
override
fun
close
()
{
this
.
captchaCache
=
null
this
.
heartbeatFuture
?.
cancel
(
true
)
this
.
heartbeatFuture
=
null
/**
}
* 动作处理. 如发送好友请求, 处理别人发来的好友请求等
}
*
}
* java 调用方式: `botNetWorkHandler.getAction()`
*/
var
action
:
ActionPacketHandler
}
\ No newline at end of file
mirai-core/src/main/java/net/mamoe/mirai/network/BotNetworkHandlerImpl.kt
0 → 100644
View file @
ef98f22d
package
net.mamoe.mirai.network
import
net.mamoe.mirai.Bot
import
net.mamoe.mirai.MiraiServer
import
net.mamoe.mirai.event.events.bot.BotLoginSucceedEvent
import
net.mamoe.mirai.event.events.network.BeforePacketSendEvent
import
net.mamoe.mirai.event.events.network.PacketSentEvent
import
net.mamoe.mirai.event.events.network.ServerPacketReceivedEvent
import
net.mamoe.mirai.event.hookWhile
import
net.mamoe.mirai.network.handler.*
import
net.mamoe.mirai.network.packet.*
import
net.mamoe.mirai.network.packet.login.*
import
net.mamoe.mirai.task.MiraiThreadPool
import
net.mamoe.mirai.utils.*
import
java.io.Closeable
import
java.net.DatagramPacket
import
java.net.DatagramSocket
import
java.net.InetSocketAddress
import
java.util.*
import
java.util.concurrent.CompletableFuture
import
java.util.concurrent.ScheduledFuture
import
java.util.concurrent.TimeUnit
import
javax.imageio.ImageIO
import
kotlin.reflect.KClass
/**
* [BotNetworkHandler] 的内部实现, 该类不会有帮助理解的注解, 请查看 [BotNetworkHandler] 以获取帮助
*
* @see BotNetworkHandler
* @author Him188moe
*/
@Suppress
(
"EXPERIMENTAL_API_USAGE"
)
//to simplify code
internal
class
BotNetworkHandlerImpl
(
private
val
bot
:
Bot
)
:
BotNetworkHandler
{
override
val
socket
:
BotSocket
=
BotSocket
()
lateinit
var
login
:
Login
override
lateinit
var
debug
:
DebugPacketHandler
override
lateinit
var
message
:
MessagePacketHandler
override
lateinit
var
action
:
ActionPacketHandler
val
packetHandlers
:
PacketHandlerList
=
PacketHandlerList
()
//private | internal
/**
* 尝试登录. 多次重复登录
*
* @param touchingTimeoutMillis 连接每个服务器的 timeout
*/
@JvmOverloads
internal
fun
tryLogin
(
touchingTimeoutMillis
:
Long
=
200
):
CompletableFuture
<
LoginState
>
{
val
ipQueue
:
LinkedList
<
String
>
=
LinkedList
(
Protocol
.
SERVER_IP
)
val
future
=
CompletableFuture
<
LoginState
>()
fun
login
()
{
this
.
socket
.
close
()
val
ip
=
ipQueue
.
poll
()
if
(
ip
==
null
)
{
future
.
complete
(
LoginState
.
UNKNOWN
)
//所有服务器均返回 UNKNOWN
return
}
this
.
socket
.
touch
(
ip
,
touchingTimeoutMillis
).
get
().
let
{
state
->
if
(
state
==
LoginState
.
UNKNOWN
||
state
==
LoginState
.
TIMEOUT
)
{
login
()
//超时或未知, 重试连接下一个服务器
}
else
{
future
.
complete
(
state
)
}
}
}
login
()
return
future
}
private
fun
onLoggedIn
(
sessionKey
:
ByteArray
)
{
val
session
=
LoginSession
(
bot
,
sessionKey
,
socket
)
debug
=
DebugPacketHandler
(
session
)
message
=
MessagePacketHandler
(
session
)
action
=
ActionPacketHandler
(
session
)
packetHandlers
.
add
(
debug
.
asNode
())
packetHandlers
.
add
(
message
.
asNode
())
packetHandlers
.
add
(
action
.
asNode
())
}
private
lateinit
var
sessionKey
:
ByteArray
override
fun
close
()
{
this
.
packetHandlers
.
forEach
{
it
.
instance
.
close
()
}
this
.
socket
.
close
()
}
internal
inner
class
BotSocket
:
Closeable
,
DataPacketSocket
{
override
fun
distributePacket
(
packet
:
ServerPacket
)
{
try
{
packet
.
decode
()
}
catch
(
e
:
java
.
lang
.
Exception
)
{
e
.
printStackTrace
()
bot
.
debugPacket
(
packet
)
return
}
if
(
ServerPacketReceivedEvent
(
bot
,
packet
).
broadcast
().
isCancelled
)
{
debug
.
onPacketReceived
(
packet
)
return
}
login
.
onPacketReceived
(
packet
)
packetHandlers
.
forEach
{
it
.
instance
.
onPacketReceived
(
packet
)
}
}
private
var
socket
:
DatagramSocket
?
=
null
internal
var
serverIP
:
String
=
""
set
(
value
)
{
field
=
value
restartSocket
()
}
internal
var
loginFuture
:
CompletableFuture
<
LoginState
>?
=
null
@Synchronized
private
fun
restartSocket
()
{
socket
?.
close
()
socket
=
DatagramSocket
(
0
)
socket
!!
.
connect
(
InetSocketAddress
(
serverIP
,
8000
))
Thread
{
while
(
socket
!!
.
isConnected
)
{
val
packet
=
DatagramPacket
(
ByteArray
(
2048
),
2048
)
kotlin
.
runCatching
{
socket
?.
receive
(
packet
)
}
.
onSuccess
{
MiraiThreadPool
.
getInstance
().
submit
{
try
{
distributePacket
(
ServerPacket
.
ofByteArray
(
packet
.
data
.
removeZeroTail
()))
}
catch
(
e
:
Exception
)
{
e
.
printStackTrace
()
}
}
}.
onFailure
{
if
(
it
.
message
==
"Socket closed"
||
it
.
message
==
"socket closed"
)
{
return
@Thread
}
it
.
printStackTrace
()
}
}
}.
start
()
}
/**
* Start network and touch the server
*/
fun
touch
(
serverAddress
:
String
,
timeoutMillis
:
Long
):
CompletableFuture
<
LoginState
>
{
bot
.
info
(
"Connecting server: $serverAddress"
)
if
(
this
@BotNetworkHandlerImpl
::
login
.
isInitialized
)
{
login
.
close
()
}
login
=
Login
()
this
.
loginFuture
=
CompletableFuture
()
serverIP
=
serverAddress
waitForPacket
(
ServerPacket
::
class
,
timeoutMillis
)
{
loginFuture
!!
.
complete
(
LoginState
.
TIMEOUT
)
}
sendPacket
(
ClientTouchPacket
(
bot
.
account
.
qqNumber
,
serverIP
))
return
this
.
loginFuture
!!
}
/**
* Not async
*/
@Synchronized
@ExperimentalUnsignedTypes
override
fun
sendPacket
(
packet
:
ClientPacket
)
{
checkNotNull
(
socket
)
{
"network closed"
}
if
(
socket
!!
.
isClosed
)
{
return
}
try
{
packet
.
encodePacket
()
if
(
BeforePacketSendEvent
(
bot
,
packet
).
broadcast
().
isCancelled
)
{
return
}
val
data
=
packet
.
toByteArray
()
socket
!!
.
send
(
DatagramPacket
(
data
,
data
.
size
))
bot
.
cyanL
(
"Packet sent: $packet"
)
PacketSentEvent
(
bot
,
packet
).
broadcast
()
}
catch
(
e
:
Throwable
)
{
e
.
printStackTrace
()
}
}
@Suppress
(
"UNCHECKED_CAST"
)
internal
fun
<
P
:
ServerPacket
>
waitForPacket
(
packetClass
:
KClass
<
P
>,
timeoutMillis
:
Long
,
timeout
:
()
->
Unit
)
{
var
got
=
false
ServerPacketReceivedEvent
::
class
.
hookWhile
{
if
(
packetClass
.
isInstance
(
it
.
packet
)
&&
it
.
bot
===
bot
)
{
got
=
true
true
}
else
{
false
}
}
MiraiThreadPool
.
getInstance
().
submit
{
val
startingTime
=
System
.
currentTimeMillis
()
while
(!
got
)
{
if
(
System
.
currentTimeMillis
()
-
startingTime
>
timeoutMillis
)
{
timeout
.
invoke
()
return
@
submit
}
Thread
.
sleep
(
10
)
}
}
}
override
fun
close
()
{
this
.
socket
?.
close
()
if
(
this
.
loginFuture
!=
null
)
{
if
(!
this
.
loginFuture
!!
.
isDone
)
{
this
.
loginFuture
!!
.
cancel
(
true
)
}
this
.
loginFuture
=
null
}
}
override
fun
isClosed
():
Boolean
{
return
this
.
socket
?.
isClosed
?:
true
}
}
/**
* 处理登录过程
*/
inner
class
Login
:
Closeable
{
private
lateinit
var
token00BA
:
ByteArray
private
lateinit
var
token0825
:
ByteArray
private
var
loginTime
:
Int
=
0
private
lateinit
var
loginIP
:
String
private
var
tgtgtKey
:
ByteArray
=
getRandomByteArray
(
16
)
private
var
tlv0105
:
ByteArray
=
lazyEncode
{
it
.
writeHex
(
"01 05 00 30"
)
it
.
writeHex
(
"00 01 01 02 00 14 01 01 00 10"
)
it
.
writeRandom
(
16
)
it
.
writeHex
(
"00 14 01 02 00 10"
)
it
.
writeRandom
(
16
)
}
/**
* 0828_decr_key
*/
private
lateinit
var
sessionResponseDecryptionKey
:
ByteArray
private
var
captchaSectionId
:
Int
=
1
private
var
captchaCache
:
ByteArray
?
=
byteArrayOf
()
//每次包只发一部分验证码来
private
var
heartbeatFuture
:
ScheduledFuture
<
*
>?
=
null
fun
onPacketReceived
(
packet
:
ServerPacket
)
{
when
(
packet
)
{
is
ServerTouchResponsePacket
->
{
if
(
packet
.
serverIP
!=
null
)
{
//redirection
socket
.
serverIP
=
packet
.
serverIP
!!
//connect(packet.serverIP!!)
socket
.
sendPacket
(
ClientServerRedirectionPacket
(
packet
.
serverIP
!!
,
bot
.
account
.
qqNumber
))
}
else
{
//password submission
this
.
loginIP
=
packet
.
loginIP
this
.
loginTime
=
packet
.
loginTime
this
.
token0825
=
packet
.
token0825
socket
.
sendPacket
(
ClientPasswordSubmissionPacket
(
bot
.
account
.
qqNumber
,
bot
.
account
.
password
,
packet
.
loginTime
,
packet
.
loginIP
,
this
.
tgtgtKey
,
packet
.
token0825
))
}
}
is
ServerLoginResponseFailedPacket
->
{
socket
.
loginFuture
?.
complete
(
packet
.
loginState
)
return
}
is
ServerVerificationCodeCorrectPacket
->
{
this
.
tgtgtKey
=
getRandomByteArray
(
16
)
this
.
token00BA
=
packet
.
token00BA
socket
.
sendPacket
(
ClientLoginResendPacket3105
(
bot
.
account
.
qqNumber
,
bot
.
account
.
password
,
this
.
loginTime
,
this
.
loginIP
,
this
.
tgtgtKey
,
this
.
token0825
,
this
.
token00BA
))
}
is
ServerLoginResponseVerificationCodeInitPacket
->
{
//[token00BA]来源之一: 验证码
this
.
token00BA
=
packet
.
token00BA
this
.
captchaCache
=
packet
.
verifyCodePart1
if
(
packet
.
unknownBoolean
!=
null
&&
packet
.
unknownBoolean
!!
)
{
this
.
captchaSectionId
=
1
socket
.
sendPacket
(
ClientVerificationCodeTransmissionRequestPacket
(
1
,
bot
.
account
.
qqNumber
,
this
.
token0825
,
this
.
captchaSectionId
++,
this
.
token00BA
))
}
}
is
ServerVerificationCodeTransmissionPacket
->
{
if
(
packet
is
ServerVerificationCodeWrongPacket
)
{
bot
.
error
(
"验证码错误, 请重新输入"
)
captchaSectionId
=
1
this
.
captchaCache
=
byteArrayOf
()
}
this
.
captchaCache
=
this
.
captchaCache
!!
+
packet
.
captchaSectionN
this
.
token00BA
=
packet
.
token00BA
if
(
packet
.
transmissionCompleted
)
{
bot
.
notice
(
CharImageUtil
.
createCharImg
(
ImageIO
.
read
(
this
.
captchaCache
!!
.
inputStream
())))
bot
.
notice
(
"需要验证码登录, 验证码为 4 字母"
)
try
{
(
MiraiServer
.
getInstance
().
parentFolder
+
"VerificationCode.png"
).
writeBytes
(
this
.
captchaCache
!!
)
bot
.
notice
(
"若看不清字符图片, 请查看 Mirai 根目录下 VerificationCode.png"
)
}
catch
(
e
:
Exception
)
{
bot
.
notice
(
"无法写出验证码文件, 请尝试查看以上字符图片"
)
}
bot
.
notice
(
"若要更换验证码, 请直接回车"
)
val
code
=
Scanner
(
System
.
`in`
).
nextLine
()
if
(
code
.
isEmpty
()
||
code
.
length
!=
4
)
{
this
.
captchaCache
=
byteArrayOf
()
this
.
captchaSectionId
=
1
socket
.
sendPacket
(
ClientVerificationCodeRefreshPacket
(
packet
.
packetIdLast
+
1
,
bot
.
account
.
qqNumber
,
token0825
))
}
else
{
socket
.
sendPacket
(
ClientVerificationCodeSubmitPacket
(
packet
.
packetIdLast
+
1
,
bot
.
account
.
qqNumber
,
token0825
,
code
,
packet
.
verificationToken
))
}
}
else
{
socket
.
sendPacket
(
ClientVerificationCodeTransmissionRequestPacket
(
packet
.
packetIdLast
+
1
,
bot
.
account
.
qqNumber
,
token0825
,
captchaSectionId
++,
token00BA
))
}
}
is
ServerLoginResponseSuccessPacket
->
{
this
.
sessionResponseDecryptionKey
=
packet
.
sessionResponseDecryptionKey
socket
.
sendPacket
(
ClientSessionRequestPacket
(
bot
.
account
.
qqNumber
,
socket
.
serverIP
,
packet
.
token38
,
packet
.
token88
,
packet
.
encryptionKey
,
this
.
tlv0105
))
}
//是ClientPasswordSubmissionPacket之后服务器回复的
is
ServerLoginResponseKeyExchangePacket
->
{
//if (packet.tokenUnknown != null) {
//this.token00BA = packet.token00BA!!
//println("token00BA changed!!! to " + token00BA.toUByteArray())
//}
if
(
packet
.
flag
==
ServerLoginResponseKeyExchangePacket
.
Flag
.
`
08
36
31
03
`
)
{
this
.
tgtgtKey
=
packet
.
tgtgtKey
socket
.
sendPacket
(
ClientLoginResendPacket3104
(
bot
.
account
.
qqNumber
,
bot
.
account
.
password
,
loginTime
,
loginIP
,
tgtgtKey
,
token0825
,
packet
.
tokenUnknown
?:
this
.
token00BA
,
packet
.
tlv0006
))
}
else
{
socket
.
sendPacket
(
ClientLoginResendPacket3106
(
bot
.
account
.
qqNumber
,
bot
.
account
.
password
,
loginTime
,
loginIP
,
tgtgtKey
,
token0825
,
packet
.
tokenUnknown
?:
token00BA
,
packet
.
tlv0006
))
}
}
is
ServerSessionKeyResponsePacket
->
{
sessionKey
=
packet
.
sessionKey
heartbeatFuture
=
MiraiThreadPool
.
getInstance
().
scheduleWithFixedDelay
({
socket
.
sendPacket
(
ClientHeartbeatPacket
(
bot
.
account
.
qqNumber
,
sessionKey
))
},
90000
,
90000
,
TimeUnit
.
MILLISECONDS
)
BotLoginSucceedEvent
(
bot
).
broadcast
()
//登录成功后会收到大量上次的消息, 忽略掉
MiraiThreadPool
.
getInstance
().
schedule
({
message
.
ignoreMessage
=
false
},
3
,
TimeUnit
.
SECONDS
)
this
.
tlv0105
=
packet
.
tlv0105
socket
.
loginFuture
!!
.
complete
(
LoginState
.
SUCCESS
)
onLoggedIn
(
sessionKey
)
}
is
ServerVerificationCodePacket
.
Encrypted
->
socket
.
distributePacket
(
packet
.
decrypt
())
is
ServerLoginResponseVerificationCodeInitPacket
.
Encrypted
->
socket
.
distributePacket
(
packet
.
decrypt
())
is
ServerLoginResponseKeyExchangePacket
.
Encrypted
->
socket
.
distributePacket
(
packet
.
decrypt
(
this
.
tgtgtKey
))
is
ServerLoginResponseSuccessPacket
.
Encrypted
->
socket
.
distributePacket
(
packet
.
decrypt
(
this
.
tgtgtKey
))
is
ServerSessionKeyResponsePacket
.
Encrypted
->
socket
.
distributePacket
(
packet
.
decrypt
(
this
.
sessionResponseDecryptionKey
))
is
ServerTouchResponsePacket
.
Encrypted
->
socket
.
distributePacket
(
packet
.
decrypt
())
is
ServerLoginSuccessPacket
,
is
ServerHeartbeatResponsePacket
,
is
UnknownServerPacket
->
{
//ignored
}
else
->
{
}
}
}
override
fun
close
()
{
this
.
captchaCache
=
null
this
.
heartbeatFuture
?.
cancel
(
true
)
this
.
heartbeatFuture
=
null
}
}
}
mirai-core/src/main/java/net/mamoe/mirai/network/LoginSession.kt
View file @
ef98f22d
...
@@ -5,7 +5,8 @@ import net.mamoe.mirai.network.handler.DataPacketSocket
...
@@ -5,7 +5,8 @@ import net.mamoe.mirai.network.handler.DataPacketSocket
import
net.mamoe.mirai.utils.getGTK
import
net.mamoe.mirai.utils.getGTK
/**
/**
* 一次会话. 当登录完成后, 客户端会拿到 sessionKey. 此时建立 session, 开始处理消息等事务
* 登录会话. 当登录完成后, 客户端会拿到 sessionKey.
* 此时建立 session, 然后开始处理事务.
*
*
* @author Him188moe
* @author Him188moe
*/
*/
...
...
mirai-core/src/main/java/net/mamoe/mirai/network/handler/ActionHandler.kt
→
mirai-core/src/main/java/net/mamoe/mirai/network/handler/Action
Packet
Handler.kt
View file @
ef98f22d
...
@@ -12,9 +12,7 @@ import net.mamoe.mirai.network.packet.image.ServerTryUploadGroupImageSuccessPack
...
@@ -12,9 +12,7 @@ import net.mamoe.mirai.network.packet.image.ServerTryUploadGroupImageSuccessPack
import
net.mamoe.mirai.network.packet.login.ClientChangeOnlineStatusPacket
import
net.mamoe.mirai.network.packet.login.ClientChangeOnlineStatusPacket
import
net.mamoe.mirai.task.MiraiThreadPool
import
net.mamoe.mirai.task.MiraiThreadPool
import
net.mamoe.mirai.utils.ClientLoginStatus
import
net.mamoe.mirai.utils.ClientLoginStatus
import
net.mamoe.mirai.utils.ImageNetworkUtils
import
net.mamoe.mirai.utils.getGTK
import
net.mamoe.mirai.utils.getGTK
import
net.mamoe.mirai.utils.toUHexString
import
java.awt.image.BufferedImage
import
java.awt.image.BufferedImage
import
java.io.Closeable
import
java.io.Closeable
import
java.util.*
import
java.util.*
...
@@ -26,8 +24,10 @@ import java.util.function.Supplier
...
@@ -26,8 +24,10 @@ import java.util.function.Supplier
/**
/**
* 动作: 获取好友列表, 点赞, 踢人等.
* 动作: 获取好友列表, 点赞, 踢人等.
* 处理动作事件, 承担动作任务.
* 处理动作事件, 承担动作任务.
*
* @author Him188moe
*/
*/
class
ActionHandler
(
session
:
LoginSession
)
:
PacketHandler
(
session
)
{
class
Action
Packet
Handler
(
session
:
LoginSession
)
:
PacketHandler
(
session
)
{
private
val
addFriendSessions
=
Collections
.
synchronizedCollection
(
mutableListOf
<
AddFriendSession
>())
private
val
addFriendSessions
=
Collections
.
synchronizedCollection
(
mutableListOf
<
AddFriendSession
>())
private
val
uploadImageSessions
=
Collections
.
synchronizedCollection
(
mutableListOf
<
UploadImageSession
>())
private
val
uploadImageSessions
=
Collections
.
synchronizedCollection
(
mutableListOf
<
UploadImageSession
>())
...
@@ -42,7 +42,7 @@ class ActionHandler(session: LoginSession) : PacketHandler(session) {
...
@@ -42,7 +42,7 @@ class ActionHandler(session: LoginSession) : PacketHandler(session) {
}
}
}
}
is
ServerTryUploadGroupImageSuccessPacket
->
{
is
ServerTryUploadGroupImageSuccessPacket
->
{
ImageNetworkUtils
.
postImage
(
packet
.
uKey
.
toUHexString
(),
)
//
ImageNetworkUtils.postImage(packet.uKey.toUHexString(), )
}
}
is
ServerTryUploadGroupImageFailedPacket
->
{
is
ServerTryUploadGroupImageFailedPacket
->
{
...
@@ -51,6 +51,7 @@ class ActionHandler(session: LoginSession) : PacketHandler(session) {
...
@@ -51,6 +51,7 @@ class ActionHandler(session: LoginSession) : PacketHandler(session) {
is
ServerTryUploadGroupImageResponsePacket
.
Encrypted
->
session
.
socket
.
distributePacket
(
packet
.
decrypt
(
session
.
sessionKey
))
is
ServerTryUploadGroupImageResponsePacket
.
Encrypted
->
session
.
socket
.
distributePacket
(
packet
.
decrypt
(
session
.
sessionKey
))
is
ServerAccountInfoResponsePacket
.
Encrypted
->
session
.
socket
.
distributePacket
(
packet
.
decrypt
(
session
.
sessionKey
))
is
ServerAccountInfoResponsePacket
->
{
is
ServerAccountInfoResponsePacket
->
{
}
}
...
@@ -67,6 +68,9 @@ class ActionHandler(session: LoginSession) : PacketHandler(session) {
...
@@ -67,6 +68,9 @@ class ActionHandler(session: LoginSession) : PacketHandler(session) {
session
.
gtk
=
getGTK
(
session
.
sKey
)
session
.
gtk
=
getGTK
(
session
.
sKey
)
}
}
is
ServerEventPacket
.
Raw
.
Encrypted
->
session
.
socket
.
distributePacket
(
packet
.
decrypt
(
session
.
sessionKey
))
is
ServerEventPacket
.
Raw
->
session
.
socket
.
distributePacket
(
packet
.
distribute
())
else
->
{
else
->
{
}
}
}
}
...
@@ -82,7 +86,7 @@ class ActionHandler(session: LoginSession) : PacketHandler(session) {
...
@@ -82,7 +86,7 @@ class ActionHandler(session: LoginSession) : PacketHandler(session) {
fun
addFriend
(
qqNumber
:
Long
,
message
:
Lazy
<
String
>
=
lazyOf
(
""
)):
CompletableFuture
<
AddFriendResult
>
{
fun
addFriend
(
qqNumber
:
Long
,
message
:
Lazy
<
String
>
=
lazyOf
(
""
)):
CompletableFuture
<
AddFriendResult
>
{
val
future
=
CompletableFuture
<
AddFriendResult
>()
val
future
=
CompletableFuture
<
AddFriendResult
>()
val
session
=
AddFriendSession
(
qqNumber
,
future
,
message
)
val
session
=
AddFriendSession
(
qqNumber
,
future
,
message
)
uploadImageSessions
.
add
(
session
)
//
uploadImageSessions.add(session)
session
.
sendAddRequest
();
session
.
sendAddRequest
();
return
future
return
future
}
}
...
@@ -138,7 +142,7 @@ class ActionHandler(session: LoginSession) : PacketHandler(session) {
...
@@ -138,7 +142,7 @@ class ActionHandler(session: LoginSession) : PacketHandler(session) {
}
}
ServerCanAddFriendResponsePacket
.
State
.
REQUIRE_VERIFICATION
->
{
ServerCanAddFriendResponsePacket
.
State
.
REQUIRE_VERIFICATION
->
{
session
.
socket
.
sendPacket
(
ClientAddFriendPacket
(
session
.
bot
.
account
.
qqNumber
,
qq
,
session
.
sessionKey
))
//
session.socket.sendPacket(ClientAddFriendPacket(session.bot.account.qqNumber, qq, session.sessionKey))
}
}
ServerCanAddFriendResponsePacket
.
State
.
NOT_REQUIRE_VERIFICATION
->
{
ServerCanAddFriendResponsePacket
.
State
.
NOT_REQUIRE_VERIFICATION
->
{
...
@@ -210,7 +214,7 @@ class ActionHandler(session: LoginSession) : PacketHandler(session) {
...
@@ -210,7 +214,7 @@ class ActionHandler(session: LoginSession) : PacketHandler(session) {
}
}
override
fun
close
()
{
override
fun
close
()
{
uploadImageSessions
.
remove
(
this
)
//
uploadImageSessions.remove(this)
}
}
}
}
}
}
\ No newline at end of file
mirai-core/src/main/java/net/mamoe/mirai/network/handler/DataPacketSocket.kt
View file @
ef98f22d
package
net.mamoe.mirai.network.handler
package
net.mamoe.mirai.network.handler
import
net.mamoe.mirai.network.BotNetworkHandlerImpl
import
net.mamoe.mirai.network.packet.ClientPacket
import
net.mamoe.mirai.network.packet.ClientPacket
import
net.mamoe.mirai.network.packet.ServerPacket
import
net.mamoe.mirai.network.packet.ServerPacket
import
java.io.Closeable
import
java.io.Closeable
/**
/**
* 网络接口.
* 发包 / 处理包.
* 仅可通过 [BotNetworkHandlerImpl.socket] 得到实例.
*
* @author Him188moe
* @author Him188moe
*/
*/
interface
DataPacketSocket
:
Closeable
{
interface
DataPacketSocket
:
Closeable
{
...
...
mirai-core/src/main/java/net/mamoe/mirai/network/handler/DebugHandler.kt
→
mirai-core/src/main/java/net/mamoe/mirai/network/handler/Debug
Packet
Handler.kt
View file @
ef98f22d
...
@@ -8,13 +8,15 @@ import net.mamoe.mirai.utils.notice
...
@@ -8,13 +8,15 @@ import net.mamoe.mirai.utils.notice
/**
/**
* Kind of [PacketHandler] that prints all packets received in the format of hex byte array.
* Kind of [PacketHandler] that prints all packets received in the format of hex byte array.
*
* @author Him188moe
*/
*/
sealed
class
Debug
Handler
(
session
:
LoginSession
)
:
PacketHandler
(
session
)
{
class
DebugPacket
Handler
(
session
:
LoginSession
)
:
PacketHandler
(
session
)
{
@ExperimentalUnsignedTypes
@ExperimentalUnsignedTypes
override
fun
onPacketReceived
(
packet
:
ServerPacket
)
{
override
fun
onPacketReceived
(
packet
:
ServerPacket
)
{
if
(!
packet
.
javaClass
.
name
.
endsWith
(
"Encrypted"
)
&&
!
packet
.
javaClass
.
name
.
endsWith
(
"Raw"
))
{
if
(!
packet
.
javaClass
.
name
.
endsWith
(
"Encrypted"
)
&&
!
packet
.
javaClass
.
name
.
endsWith
(
"Raw"
))
{
session
.
bot
notice
"Packet received: $packet"
session
.
bot
.
notice
(
"Packet received: $packet"
)
}
}
if
(
packet
is
ServerEventPacket
)
{
if
(
packet
is
ServerEventPacket
)
{
...
...
mirai-core/src/main/java/net/mamoe/mirai/network/handler/MessageHandler.kt
→
mirai-core/src/main/java/net/mamoe/mirai/network/handler/Message
Packet
Handler.kt
View file @
ef98f22d
...
@@ -14,8 +14,11 @@ import net.mamoe.mirai.network.packet.action.ServerSendGroupMessageResponsePacke
...
@@ -14,8 +14,11 @@ import net.mamoe.mirai.network.packet.action.ServerSendGroupMessageResponsePacke
/**
/**
* 处理消息事件, 承担消息发送任务.
* 处理消息事件, 承担消息发送任务.
*
* @author Him188moe
*/
*/
class
MessageHandler
(
session
:
LoginSession
)
:
PacketHandler
(
session
)
{
@Suppress
(
"EXPERIMENTAL_API_USAGE"
)
class
MessagePacketHandler
(
session
:
LoginSession
)
:
PacketHandler
(
session
)
{
internal
var
ignoreMessage
:
Boolean
=
true
internal
var
ignoreMessage
:
Boolean
=
true
init
{
init
{
...
@@ -67,7 +70,6 @@ class MessageHandler(session: LoginSession) : PacketHandler(session) {
...
@@ -67,7 +70,6 @@ class MessageHandler(session: LoginSession) : PacketHandler(session) {
}
}
}
}
@ExperimentalUnsignedTypes
fun
sendFriendMessage
(
qq
:
QQ
,
message
:
MessageChain
)
{
fun
sendFriendMessage
(
qq
:
QQ
,
message
:
MessageChain
)
{
session
.
socket
.
sendPacket
(
ClientSendFriendMessagePacket
(
session
.
bot
.
account
.
qqNumber
,
qq
.
number
,
session
.
sessionKey
,
message
))
session
.
socket
.
sendPacket
(
ClientSendFriendMessagePacket
(
session
.
bot
.
account
.
qqNumber
,
qq
.
number
,
session
.
sessionKey
,
message
))
}
}
...
...
mirai-core/src/main/java/net/mamoe/mirai/network/handler/PacketHandler.kt
View file @
ef98f22d
...
@@ -24,8 +24,8 @@ class PacketHandlerNode<T : PacketHandler>(
...
@@ -24,8 +24,8 @@ class PacketHandlerNode<T : PacketHandler>(
val
instance
:
T
val
instance
:
T
)
)
infix
fun
PacketHandler
.
to
(
handler
:
PacketHandler
):
PacketHandlerNode
<
PacketHandler
>
{
fun
PacketHandler
.
asNode
(
):
PacketHandlerNode
<
PacketHandler
>
{
return
PacketHandlerNode
(
handler
.
javaClass
,
handler
)
return
PacketHandlerNode
(
this
.
javaClass
,
this
)
}
}
class
PacketHandlerList
:
LinkedList
<
PacketHandlerNode
<
*
>>()
{
class
PacketHandlerList
:
LinkedList
<
PacketHandlerNode
<
*
>>()
{
...
...
mirai-core/src/main/java/net/mamoe/mirai/network/packet/ServerEvent.kt
View file @
ef98f22d
...
@@ -119,7 +119,7 @@ class ServerGroupMessageEventPacket(input: DataInputStream, packetId: ByteArray,
...
@@ -119,7 +119,7 @@ class ServerGroupMessageEventPacket(input: DataInputStream, packetId: ByteArray,
0
x19
->
MessageType
.
ANONYMOUS
0
x19
->
MessageType
.
ANONYMOUS
else
->
{
else
->
{
MiraiLogger
debug
(
"ServerGroupMessageEventPacket id=$id"
)
MiraiLogger
.
debug
(
"ServerGroupMessageEventPacket id=$id"
)
MessageType
.
OTHER
MessageType
.
OTHER
}
}
}
}
...
...
mirai-core/src/main/java/net/mamoe/mirai/network/packet/Session.kt
View file @
ef98f22d
...
@@ -64,6 +64,7 @@ class ClientSessionRequestPacket(
...
@@ -64,6 +64,7 @@ class ClientSessionRequestPacket(
/**
/**
* @author Him188moe
* @author Him188moe
*/
*/
@PacketId
(
"08 28 04 34"
)
class
ServerSessionKeyResponsePacket
(
inputStream
:
DataInputStream
,
private
val
dataLength
:
Int
)
:
ServerPacket
(
inputStream
)
{
class
ServerSessionKeyResponsePacket
(
inputStream
:
DataInputStream
,
private
val
dataLength
:
Int
)
:
ServerPacket
(
inputStream
)
{
lateinit
var
sessionKey
:
ByteArray
lateinit
var
sessionKey
:
ByteArray
lateinit
var
tlv0105
:
ByteArray
lateinit
var
tlv0105
:
ByteArray
...
...
mirai-core/src/main/java/net/mamoe/mirai/network/packet/VerificationCode.kt
View file @
ef98f22d
package
net.mamoe.mirai.network.packet
package
net.mamoe.mirai.network.packet
import
net.mamoe.mirai.network.Protocol
import
net.mamoe.mirai.network.Protocol
import
net.mamoe.mirai.utils.*
import
net.mamoe.mirai.utils.TEA
import
net.mamoe.mirai.utils.TestedSuccessfully
import
net.mamoe.mirai.utils.hexToBytes
import
java.io.DataInputStream
import
java.io.DataInputStream
/**
/**
...
@@ -18,9 +20,6 @@ class ClientVerificationCodeTransmissionRequestPacket(
...
@@ -18,9 +20,6 @@ class ClientVerificationCodeTransmissionRequestPacket(
)
:
ClientPacket
()
{
)
:
ClientPacket
()
{
@TestedSuccessfully
@TestedSuccessfully
override
fun
encode
()
{
override
fun
encode
()
{
MiraiLogger
debug
"packetId=$packetId"
MiraiLogger
debug
"verificationSequence=$verificationSequence"
this
.
writeByte
(
packetId
)
//part of packet id
this
.
writeByte
(
packetId
)
//part of packet id
this
.
writeQQ
(
qq
)
this
.
writeQQ
(
qq
)
...
@@ -90,34 +89,6 @@ class ClientVerificationCodeSubmitPacket(
...
@@ -90,34 +89,6 @@ class ClientVerificationCodeSubmitPacket(
}
}
}
}
@ExperimentalUnsignedTypes
fun
main
()
{
val
token0825
=
"6E AF F9 2C 20 2B DE 21 B6 13 6F 26 43 F4 04 7B 1F 88 08 4E 8E BE E5 D1 3F E7 93 DE DD E0 6E 38 65 C7 C7 D3 20 7D AC 73 AD F9 85 F9 CC 2A 2C 26 C6 B1 5B FD 34 3F D4 F2"
.
hexToBytes
()
val
verificationCode
=
"AAAA"
val
verificationToken
=
"84 2D 1D 9D 07 04 34 80 17 9E 3F 58 02 20 9A 1C 22 D0 73 7D 8A 90 1B 2F F8 E6 79 A6 84 2F 98 F5 1E 66 3D 9A 24 59 18 34 42 BD 45 DA E1 22 2D BC 2D 36 80 86 AD 44 C2 94"
.
hexToBytes
()
//00 02 00 00 08 04 01 E0 00 00 04 53 00 00 00 01 00 00 15 85 01 00 38 6E AF F9 2C 20 2B DE 21 B6 13 6F 26 43 F4 04 7B 1F 88 08 4E 8E BE E5 D1 3F E7 93 DE DD E0 6E 38 65 C7 C7 D3 20 7D AC 73 AD F9 85 F9 CC 2A 2C 26 C6 B1 5B FD 34 3F D4 F2 01 03 00 19 02 6D 28 41 D2 A5 6F D2 FC 3E 2A 1F 03 75 DE 6E 28 8F A8 19 3E 5F 16 49 D3 14 00 05 00 00 00 00 00 04 58 51 4E 44 00 38 84 2D 1D 9D 07 04 34 80 17 9E 3F 58 02 20 9A 1C 22 D0 73 7D 8A 90 1B 2F F8 E6 79 A6 84 2F 98 F5 1E 66 3D 9A 24 59 18 34 42 BD 45 DA E1 22 2D BC 2D 36 80 86 AD 44 C2 94 00 10 69 20 D1 14 74 F5 B3 93 E4 D5 02 B3 71 1A CD 2A
ByteArrayDataOutputStream
().
let
{
it
.
writeHex
(
"00 02 00 00 08 04 01 E0"
)
it
.
writeHex
(
Protocol
.
constantData2
)
it
.
writeHex
(
"01 00 38"
)
it
.
write
(
token0825
)
it
.
writeHex
(
"01 03"
)
it
.
writeShort
(
25
)
it
.
writeHex
(
Protocol
.
publicKey
)
it
.
writeHex
(
"14 00 05 00 00 00 00 00 04"
)
it
.
write
(
verificationCode
.
substring
(
0
..
3
).
toByteArray
())
it
.
writeHex
(
"00 38"
)
it
.
write
(
verificationToken
)
it
.
writeHex
(
"00 10"
)
it
.
writeHex
(
Protocol
.
key00BAFix
)
println
(
it
.
toByteArray
().
toUHexString
())
}
}
/**
/**
* 刷新验证码
* 刷新验证码
*/
*/
...
@@ -152,7 +123,7 @@ class ClientVerificationCodeRefreshPacket(
...
@@ -152,7 +123,7 @@ class ClientVerificationCodeRefreshPacket(
}
}
/**
/**
* 验证码输入错误
* 验证码输入错误
, 同时也会给一部分验证码
*/
*/
@PacketId
(
"00 BA 32"
)
@PacketId
(
"00 BA 32"
)
class
ServerVerificationCodeWrongPacket
(
input
:
DataInputStream
,
dataSize
:
Int
,
packetId
:
ByteArray
)
:
ServerVerificationCodeTransmissionPacket
(
input
,
dataSize
,
packetId
)
class
ServerVerificationCodeWrongPacket
(
input
:
DataInputStream
,
dataSize
:
Int
,
packetId
:
ByteArray
)
:
ServerVerificationCodeTransmissionPacket
(
input
,
dataSize
,
packetId
)
...
@@ -163,7 +134,7 @@ class ServerVerificationCodeWrongPacket(input: DataInputStream, dataSize: Int, p
...
@@ -163,7 +134,7 @@ class ServerVerificationCodeWrongPacket(input: DataInputStream, dataSize: Int, p
* @author Him188moe
* @author Him188moe
*/
*/
@PacketId
(
"00 BA 31"
)
@PacketId
(
"00 BA 31"
)
abstract
class
ServerVerificationCodeTransmissionPacket
(
input
:
DataInputStream
,
private
val
dataSize
:
Int
,
private
val
packetId
:
ByteArray
)
:
ServerVerificationCodePacket
(
input
)
{
open
class
ServerVerificationCodeTransmissionPacket
(
input
:
DataInputStream
,
private
val
dataSize
:
Int
,
private
val
packetId
:
ByteArray
)
:
ServerVerificationCodePacket
(
input
)
{
lateinit
var
captchaSectionN
:
ByteArray
lateinit
var
captchaSectionN
:
ByteArray
lateinit
var
verificationToken
:
ByteArray
//56bytes
lateinit
var
verificationToken
:
ByteArray
//56bytes
...
...
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