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
ff0acc87
Commit
ff0acc87
authored
Sep 13, 2019
by
Him188moe
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
send image
parent
37fa8055
Changes
30
Hide whitespace changes
Inline
Side-by-side
Showing
30 changed files
with
662 additions
and
207 deletions
+662
-207
mirai-core/pom.xml
mirai-core/pom.xml
+13
-0
mirai-core/src/main/java/net/mamoe/mirai/Bot.java
mirai-core/src/main/java/net/mamoe/mirai/Bot.java
+2
-1
mirai-core/src/main/java/net/mamoe/mirai/MiraiServer.java
mirai-core/src/main/java/net/mamoe/mirai/MiraiServer.java
+17
-10
mirai-core/src/main/java/net/mamoe/mirai/contact/Contact.kt
mirai-core/src/main/java/net/mamoe/mirai/contact/Contact.kt
+10
-0
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/message/FaceID.java
mirai-core/src/main/java/net/mamoe/mirai/message/FaceID.java
+2
-0
mirai-core/src/main/java/net/mamoe/mirai/message/Message.kt
mirai-core/src/main/java/net/mamoe/mirai/message/Message.kt
+12
-34
mirai-core/src/main/java/net/mamoe/mirai/message/defaults/Face.kt
...re/src/main/java/net/mamoe/mirai/message/defaults/Face.kt
+19
-7
mirai-core/src/main/java/net/mamoe/mirai/message/defaults/Image.kt
...e/src/main/java/net/mamoe/mirai/message/defaults/Image.kt
+30
-47
mirai-core/src/main/java/net/mamoe/mirai/message/defaults/MessageChain.kt
...ain/java/net/mamoe/mirai/message/defaults/MessageChain.kt
+7
-11
mirai-core/src/main/java/net/mamoe/mirai/message/defaults/UnsolvedImage.kt
...in/java/net/mamoe/mirai/message/defaults/UnsolvedImage.kt
+63
-0
mirai-core/src/main/java/net/mamoe/mirai/network/BotNetworkHandler.kt
...rc/main/java/net/mamoe/mirai/network/BotNetworkHandler.kt
+14
-4
mirai-core/src/main/java/net/mamoe/mirai/network/BotNetworkHandlerImpl.kt
...ain/java/net/mamoe/mirai/network/BotNetworkHandlerImpl.kt
+16
-31
mirai-core/src/main/java/net/mamoe/mirai/network/LoginSession.kt
...ore/src/main/java/net/mamoe/mirai/network/LoginSession.kt
+73
-0
mirai-core/src/main/java/net/mamoe/mirai/network/handler/DataPacketSocket.kt
.../java/net/mamoe/mirai/network/handler/DataPacketSocket.kt
+29
-1
mirai-core/src/main/java/net/mamoe/mirai/network/handler/MessagePacketHandler.kt
...a/net/mamoe/mirai/network/handler/MessagePacketHandler.kt
+19
-9
mirai-core/src/main/java/net/mamoe/mirai/network/handler/PacketHandler.kt
...ain/java/net/mamoe/mirai/network/handler/PacketHandler.kt
+2
-3
mirai-core/src/main/java/net/mamoe/mirai/network/handler/TemporaryPacketHandler.kt
...net/mamoe/mirai/network/handler/TemporaryPacketHandler.kt
+49
-0
mirai-core/src/main/java/net/mamoe/mirai/network/packet/ClientPacket.kt
.../main/java/net/mamoe/mirai/network/packet/ClientPacket.kt
+4
-1
mirai-core/src/main/java/net/mamoe/mirai/network/packet/ServerEvent.kt
...c/main/java/net/mamoe/mirai/network/packet/ServerEvent.kt
+5
-5
mirai-core/src/main/java/net/mamoe/mirai/network/packet/ServerPacket.kt
.../main/java/net/mamoe/mirai/network/packet/ServerPacket.kt
+36
-2
mirai-core/src/main/java/net/mamoe/mirai/network/packet/Touch.kt
...ore/src/main/java/net/mamoe/mirai/network/packet/Touch.kt
+2
-2
mirai-core/src/main/java/net/mamoe/mirai/network/packet/action/ClientSendFriendMessagePacket.kt
...ai/network/packet/action/ClientSendFriendMessagePacket.kt
+1
-1
mirai-core/src/main/java/net/mamoe/mirai/network/packet/action/ClientSendGroupMessagePacket.kt
...rai/network/packet/action/ClientSendGroupMessagePacket.kt
+11
-7
mirai-core/src/main/java/net/mamoe/mirai/network/packet/image/UploadGroupImage.kt
.../net/mamoe/mirai/network/packet/image/UploadGroupImage.kt
+10
-9
mirai-core/src/main/java/net/mamoe/mirai/utils/ContactList.java
...core/src/main/java/net/mamoe/mirai/utils/ContactList.java
+1
-2
mirai-core/src/main/java/net/mamoe/mirai/utils/ImageNetworkUtils.java
...rc/main/java/net/mamoe/mirai/utils/ImageNetworkUtils.java
+11
-12
mirai-core/src/main/java/net/mamoe/mirai/utils/MiraiSynchronizedLinkedHashMap.java
...net/mamoe/mirai/utils/MiraiSynchronizedLinkedHashMap.java
+6
-6
mirai-core/src/main/java/net/mamoe/mirai/utils/MiraiSynchronizedLinkedList.java
...va/net/mamoe/mirai/utils/MiraiSynchronizedLinkedList.java
+195
-0
mirai-core/src/main/java/net/mamoe/mirai/utils/config/MiraiConfigSection.java
...java/net/mamoe/mirai/utils/config/MiraiConfigSection.java
+2
-1
No files found.
mirai-core/pom.xml
View file @
ff0acc87
...
...
@@ -17,6 +17,19 @@
</parent>
<dependencies>
<dependency>
<groupId>
org.pcap4j
</groupId>
<artifactId>
pcap4j-core
</artifactId>
<version>
1.8.2
</version>
<scope>
compile
</scope>
</dependency>
<dependency>
<groupId>
org.pcap4j
</groupId>
<artifactId>
pcap4j-packetfactory-static
</artifactId>
<version>
1.8.2
</version>
<scope>
compile
</scope>
</dependency>
<dependency>
<groupId>
net.mamoe
</groupId>
<artifactId>
mirai-api
</artifactId>
...
...
mirai-core/src/main/java/net/mamoe/mirai/Bot.java
View file @
ff0acc87
...
...
@@ -3,6 +3,7 @@ package net.mamoe.mirai;
import
lombok.Getter
;
import
net.mamoe.mirai.contact.Group
;
import
net.mamoe.mirai.contact.QQ
;
import
net.mamoe.mirai.network.BotNetworkHandler
;
import
net.mamoe.mirai.network.BotNetworkHandlerImpl
;
import
net.mamoe.mirai.utils.BotAccount
;
import
net.mamoe.mirai.utils.ContactList
;
...
...
@@ -53,7 +54,7 @@ public final class Bot implements Closeable {
public
final
ContactSystem
contacts
=
new
ContactSystem
();
public
final
BotNetworkHandler
Impl
network
;
public
final
BotNetworkHandler
network
;
@Override
public
String
toString
()
{
...
...
mirai-core/src/main/java/net/mamoe/mirai/MiraiServer.java
View file @
ff0acc87
...
...
@@ -212,22 +212,29 @@ public final class MiraiServer {
}
String
qqList
=
"3150499752----1234567890\n"
+
"3119292829----987654321\n"
+
"2399148773----12345678910\n"
+
"3145561616----987654321\n"
+
"2374150554----12345678910\n"
+
"2375307394----12345678910\n"
+
"2401645747----12345678910\n"
+
"1515419818----1234567890\n"
+
"3107367848----987654321\n"
;
String
qqList
=
"2573990098----qq123456789\n"
+
"3303923865----q123456789\n"
+
"3349933294----q123456789\n"
+
"3303708824----q123456789\n"
+
"3227036647----q123456789\n"
+
"3451394431----q123456789\n"
+
"3533243484----q123456789\n"
+
"3364512686----q123456789\n"
+
"3137567463----q123456789\n"
+
"3414786399----q123456789\n"
+
"3347405939----q123456789\n"
+
"3544089622----q123456789\n"
+
"3108512993----q123456789\n"
+
"2985563549----q123456789\n"
+
"3463531892----q123456789\n"
;
private
Bot
getAvailableBot
()
throws
ExecutionException
,
InterruptedException
{
for
(
String
it
:
qqList
.
split
(
"\n"
))
{
var
strings
=
it
.
split
(
"----"
);
var
bot
=
new
Bot
(
new
BotAccount
(
Long
.
parseLong
(
strings
[
0
]),
strings
[
1
]),
List
.
of
());
if
(
bot
.
network
.
tryLogin
$mirai_core
(
).
get
()
==
LoginState
.
SUCCESS
)
{
if
(
bot
.
network
.
tryLogin
(
200
).
get
()
==
LoginState
.
SUCCESS
)
{
MiraiLoggerKt
.
success
(
bot
,
"Login succeed"
);
return
bot
;
}
...
...
mirai-core/src/main/java/net/mamoe/mirai/contact/Contact.kt
View file @
ff0acc87
...
...
@@ -4,6 +4,9 @@ import net.mamoe.mirai.Bot
import
net.mamoe.mirai.message.Message
import
net.mamoe.mirai.message.defaults.MessageChain
import
net.mamoe.mirai.message.defaults.PlainText
import
net.mamoe.mirai.message.defaults.UnsolvedImage
import
net.mamoe.mirai.network.LoginSession
import
java.util.concurrent.CompletableFuture
/**
* 联系人.
...
...
@@ -20,6 +23,13 @@ abstract class Contact internal constructor(val bot: Bot, val number: Long) {
*/
abstract
fun
sendMessage
(
message
:
MessageChain
)
/**
* 上传图片
*/
fun
uploadImage
(
session
:
LoginSession
,
image
:
UnsolvedImage
):
CompletableFuture
<
Unit
>
{
return
image
.
upload
(
session
,
this
)
}
fun
sendMessage
(
message
:
Message
)
{
if
(
message
is
MessageChain
)
{
return
sendMessage
(
message
)
...
...
mirai-core/src/main/java/net/mamoe/mirai/contact/QQ.kt
View file @
ff0acc87
...
...
@@ -12,7 +12,7 @@ import net.mamoe.mirai.message.defaults.MessageChain
* Java 获取 qq 号: `qq.getNumber()`
* Java 获取所属 bot: `qq.getBot()`
*
* A QQ instance helps you to receive message from or send message to.
* A QQ instance helps you to receive message from or send
Packet
message to.
* Notice that, one QQ instance belong to one [Bot], that is, QQ instances from different [Bot] are NOT the same.
*
* @author Him188moe
...
...
mirai-core/src/main/java/net/mamoe/mirai/message/FaceID.java
View file @
ff0acc87
...
...
@@ -4,6 +4,8 @@ package net.mamoe.mirai.message;
* @author Him188moe
*/
public
enum
FaceID
{
unknown
(
0xff
),
Face_jingya
(
0
),
Face_piezui
(
1
),
Face_se
(
2
),
...
...
mirai-core/src/main/java/net/mamoe/mirai/message/Message.kt
View file @
ff0acc87
...
...
@@ -2,10 +2,7 @@ package net.mamoe.mirai.message
import
net.mamoe.mirai.contact.Contact
import
net.mamoe.mirai.contact.QQ
import
net.mamoe.mirai.message.defaults.At
import
net.mamoe.mirai.message.defaults.Image
import
net.mamoe.mirai.message.defaults.MessageChain
import
net.mamoe.mirai.message.defaults.PlainText
import
net.mamoe.mirai.message.defaults.*
import
java.awt.image.BufferedImage
import
java.io.File
import
java.util.*
...
...
@@ -106,41 +103,22 @@ abstract class Message {
* @param tail tail
* @return message connected
*/
open
fun
concat
(
tail
:
Message
):
Message
{
open
fun
concat
(
tail
:
Message
):
Message
Chain
{
return
MessageChain
(
this
,
Objects
.
requireNonNull
(
tail
))
}
fun
concat
(
tail
:
String
):
Message
{
fun
concat
(
tail
:
String
):
Message
Chain
{
return
concat
(
PlainText
(
tail
))
}
fun
withImage
(
imageId
:
String
):
Message
{
infix
fun
withImage
(
imageId
:
String
):
MessageChain
=
this
+
Image
(
imageId
)
fun
withImage
(
filename
:
String
,
image
:
BufferedImage
):
MessageChain
=
this
+
UnsolvedImage
(
filename
,
image
)
infix
fun
withImage
(
imageFile
:
File
):
MessageChain
=
this
+
UnsolvedImage
(
imageFile
)
// TODO: 2019/9/1
return
this
}
fun
withImage
(
image
:
BufferedImage
):
Message
{
// TODO: 2019/9/1
return
this
infix
fun
withAt
(
target
:
QQ
):
MessageChain
=
this
+
target
.
at
()
infix
fun
withAt
(
target
:
Long
):
MessageChain
=
this
+
At
(
target
)
}
fun
withImage
(
image
:
File
):
Message
{
// TODO: 2019/9/1
return
this
}
fun
withAt
(
target
:
QQ
):
Message
{
this
.
concat
(
target
.
at
())
return
this
}
fun
withAt
(
target
:
Int
):
Message
{
this
.
concat
(
At
(
target
.
toLong
()))
return
this
}
open
fun
toChain
():
MessageChain
{
return
MessageChain
(
this
)
...
...
@@ -152,22 +130,22 @@ abstract class Message {
/**
* 实现使用 '+' 操作符连接 [Message] 与 [Message]
*/
infix
operator
fun
plus
(
another
:
Message
):
Message
=
this
.
concat
(
another
)
infix
operator
fun
plus
(
another
:
Message
):
Message
Chain
=
this
.
concat
(
another
)
/**
* 实现使用 '+' 操作符连接 [Message] 与 [String]
*/
infix
operator
fun
plus
(
another
:
String
):
Message
=
this
.
concat
(
another
)
infix
operator
fun
plus
(
another
:
String
):
Message
Chain
=
this
.
concat
(
another
)
/**
* 实现使用 '+' 操作符连接 [Message] 与 [Number]
*/
infix
operator
fun
plus
(
another
:
Number
):
Message
=
this
.
concat
(
another
.
toString
())
infix
operator
fun
plus
(
another
:
Number
):
Message
Chain
=
this
.
concat
(
another
.
toString
())
/**
* 连接 [String] 与 [Message]
*/
fun
String
.
concat
(
another
:
Message
):
Message
=
PlainText
(
this
).
concat
(
another
)
fun
String
.
concat
(
another
:
Message
):
Message
Chain
=
PlainText
(
this
).
concat
(
another
)
override
fun
hashCode
():
Int
{
return
javaClass
.
hashCode
()
...
...
mirai-core/src/main/java/net/mamoe/mirai/message/defaults/Face.kt
View file @
ff0acc87
...
...
@@ -3,26 +3,38 @@ package net.mamoe.mirai.message.defaults
import
net.mamoe.mirai.message.FaceID
import
net.mamoe.mirai.message.Message
import
net.mamoe.mirai.message.MessageId
import
net.mamoe.mirai.network.packet.writeHex
import
net.mamoe.mirai.network.packet.writeLVByteArray
import
net.mamoe.mirai.utils.lazyEncode
/**
* QQ 自带表情
*
* @author Him188moe
*/
class
Face
(
val
id
:
FaceID
?
)
:
Message
()
{
class
Face
(
val
id
:
FaceID
)
:
Message
()
{
override
val
type
:
Int
=
MessageId
.
FACE
override
fun
toStringImpl
():
String
{
return
if
(
id
==
null
)
{
"[face?]"
}
else
String
.
format
(
"[face%d]"
,
id
.
id
)
return
String
.
format
(
"[face%d]"
,
id
.
id
)
}
override
fun
toByteArray
():
ByteArray
{
TODO
()
override
fun
toByteArray
():
ByteArray
=
lazyEncode
{
section
->
section
.
writeByte
(
this
.
type
)
section
.
writeLVByteArray
(
lazyEncode
{
child
->
child
.
writeShort
(
1
)
child
.
writeByte
(
this
.
id
.
id
)
child
.
writeHex
(
"0B 00 08 00 01 00 04 52 CC F5 D0 FF"
)
child
.
writeShort
(
2
)
child
.
writeByte
(
0
x14
)
//??
child
.
writeByte
(
this
.
id
.
id
+
65
)
})
}
override
fun
valueEquals
(
another
:
Message
):
Boolean
{
if
(
another
!
is
Face
)
{
return
false
...
...
mirai-core/src/main/java/net/mamoe/mirai/message/defaults/Image.kt
View file @
ff0acc87
...
...
@@ -2,66 +2,49 @@ package net.mamoe.mirai.message.defaults
import
net.mamoe.mirai.message.Message
import
net.mamoe.mirai.message.MessageId
import
net.mamoe.mirai.network.packet.cutTail
import
net.mamoe.mirai.network.packet.md5
import
java.awt.image.BufferedImage
import
java.io.*
import
java.net.URL
import
javax.imageio.ImageIO
import
net.mamoe.mirai.network.packet.writeHex
import
net.mamoe.mirai.network.packet.writeLVByteArray
import
net.mamoe.mirai.network.packet.writeLVString
import
net.mamoe.mirai.utils.lazyEncode
/**
* 图片消息.
* 由接收消息时构建, 可直接发送
*
* @author Him188moe
*/
class
Image
:
Message
{
open
class
Image
internal
constructor
(
val
imageID
:
String
)
:
Message
()
{
override
val
type
:
Int
=
MessageId
.
IMAGE
private
var
imageID
:
String
?
=
null
constructor
(
inputStream
:
InputStream
)
{
}
constructor
(
image
:
BufferedImage
)
{
}
@Throws
(
FileNotFoundException
::
class
)
constructor
(
imageFile
:
File
)
:
this
(
FileInputStream
(
imageFile
))
{
}
@Throws
(
IOException
::
class
)
constructor
(
url
:
URL
)
:
this
(
ImageIO
.
read
(
url
))
{
}
/**
* {xxxxx}.jpg
*
* @param imageID
*/
constructor
(
imageID
:
String
)
{
this
.
imageID
=
imageID
}
override
fun
toStringImpl
():
String
{
return
imageID
!!
return
imageID
}
override
fun
toByteArray
():
ByteArray
{
TODO
()
override
fun
toByteArray
():
ByteArray
=
lazyEncode
{
section
->
section
.
writeByte
(
0
x03
)
//todo 可能是 0x03?
section
.
writeLVByteArray
(
lazyEncode
{
child
->
child
.
writeByte
(
0
x02
)
child
.
writeLVString
(
this
.
imageID
)
child
.
writeHex
(
"04 00 "
+
"04 9B 53 B0 08 "
+
"05 00 "
+
"04 D9 8A 5A 70 "
+
"06 00 "
+
"04 00 00 00 50 "
+
"07 00 "
+
"01 43 08 00 00 09 00 01 01 0B 00 00 14 00 04 11 00 00 00 15 00 04 00 00 02 BC 16 00 04 00 00 02 BC 18 00 04 00 00 7D 5E FF 00 5C 15 36 20 39 32 6B 41 31 43 39 62 35 33 62 30 30 38 64 39 38 61 35 61 37 30 20"
)
child
.
writeHex
(
"20 20 20 20 20 35 30 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20"
)
child
.
writeBytes
(
this
.
imageID
)
child
.
writeByte
(
0
x41
)
})
}
override
fun
valueEquals
(
another
:
Message
):
Boolean
{
if
(
another
!
is
Image
)
{
return
false
if
(
another
is
Image
)
{
return
this
.
imageID
==
another
.
imageID
}
return
this
.
imageID
==
another
.
imageID
}
companion
object
{
fun
getImageID
(
filename
:
String
):
ByteArray
=
md5
(
filename
).
cutTail
(
1
)
return
false
}
}
fun
main
()
{
println
(
0
xB0
)
}
\ No newline at end of file
mirai-core/src/main/java/net/mamoe/mirai/message/defaults/MessageChain.kt
View file @
ff0acc87
...
...
@@ -11,7 +11,7 @@ import java.util.stream.Stream
class
MessageChain
:
Message
{
override
val
type
:
Int
=
MessageId
.
CHAIN
internal
val
list
=
LinkedList
<
Message
>(
)
val
list
:
MutableList
<
Message
>
=
Collections
.
synchronizedList
(
LinkedList
<
Message
>()
)
constructor
(
head
:
Message
,
tail
:
Message
)
{
Objects
.
requireNonNull
(
head
)
...
...
@@ -26,17 +26,16 @@ class MessageChain : Message {
list
.
add
(
message
)
}
constructor
()
fun
toList
():
List
<
Message
>
{
return
list
.
toList
()
constructor
(
messages
:
Collection
<
Message
>)
{
list
.
addAll
(
messages
)
}
constructor
()
fun
size
():
Int
{
return
list
.
size
}
@Synchronized
fun
containsType
(
@MagicConstant
(
valuesFromClass
=
MessageId
::
class
)
type
:
Int
):
Boolean
{
for
(
message
in
list
)
{
if
(
message
.
type
==
type
)
{
...
...
@@ -47,21 +46,18 @@ class MessageChain : Message {
}
fun
stream
():
Stream
<
Message
>
{
return
ArrayList
(
list
)
.
stream
()
return
list
.
stream
()
}
@Synchronized
override
fun
toStringImpl
():
String
{
return
this
.
list
.
stream
().
map
{
it
.
toString
()
}.
collect
(
Collectors
.
joining
(
""
))
}
@Synchronized
override
fun
toObjectString
():
String
{
return
String
.
format
(
"MessageChain(%s)"
,
this
.
list
.
stream
().
map
{
it
.
toObjectString
()
}.
collect
(
Collectors
.
joining
(
", "
)))
}
@Synchronized
override
fun
concat
(
tail
:
Message
):
Message
{
override
fun
concat
(
tail
:
Message
):
MessageChain
{
this
.
list
.
add
(
tail
)
clearToStringCache
()
return
this
...
...
mirai-core/src/main/java/net/mamoe/mirai/message/defaults/UnsolvedImage.kt
0 → 100644
View file @
ff0acc87
package
net.mamoe.mirai.message.defaults
import
net.mamoe.mirai.contact.Contact
import
net.mamoe.mirai.network.LoginSession
import
net.mamoe.mirai.network.packet.image.ClientTryGetImageIDPacket
import
net.mamoe.mirai.network.packet.image.ServerTryUploadGroupImageFailedPacket
import
net.mamoe.mirai.network.packet.image.ServerTryUploadGroupImageResponsePacket
import
net.mamoe.mirai.network.packet.image.ServerTryUploadGroupImageSuccessPacket
import
net.mamoe.mirai.network.packet.md5
import
net.mamoe.mirai.utils.ImageNetworkUtils
import
net.mamoe.mirai.utils.toByteArray
import
net.mamoe.mirai.utils.toUHexString
import
java.awt.image.BufferedImage
import
java.io.File
import
java.net.URL
import
java.util.concurrent.CompletableFuture
import
javax.imageio.ImageIO
/**
* 不确定是否存在于服务器的 [Image].
* 必须在发送之前 [UnsolvedImage.upload] 或 [Contact.uploadImage], 否则会发送失败.
x *
* @author Him188moe
*/
class
UnsolvedImage
(
filename
:
String
,
val
image
:
BufferedImage
)
:
Image
(
getImageId
(
filename
))
{
constructor
(
imageFile
:
File
)
:
this
(
imageFile
.
name
,
ImageIO
.
read
(
imageFile
))
constructor
(
url
:
URL
)
:
this
(
File
(
url
.
file
))
fun
upload
(
session
:
LoginSession
,
contact
:
Contact
):
CompletableFuture
<
Unit
>
{
return
session
.
expectPacket
<
ServerTryUploadGroupImageResponsePacket
>
{
toSend
{
ClientTryGetImageIDPacket
(
session
.
bot
.
account
.
qqNumber
,
session
.
sessionKey
,
session
.
bot
.
account
.
qqNumber
,
image
)
}
expect
{
when
(
it
)
{
is
ServerTryUploadGroupImageFailedPacket
->
{
//已经存在于服务器了
}
is
ServerTryUploadGroupImageSuccessPacket
->
{
val
data
=
image
.
toByteArray
()
if
(!
ImageNetworkUtils
.
postImage
(
it
.
uKey
.
toUHexString
(),
data
.
size
,
session
.
bot
.
account
.
qqNumber
,
contact
.
number
,
data
))
{
throw
RuntimeException
(
"cannot upload image"
)
}
}
}
}
}
}
companion
object
{
@JvmStatic
fun
getImageId
(
filename
:
String
):
String
{
val
md5
=
md5
(
filename
)
return
"{"
+
md5
.
copyOfRange
(
0
,
4
).
toUHexString
(
""
)
+
"-"
.
plus
(
md5
.
copyOfRange
(
4
,
6
).
toUHexString
(
""
))
+
"-"
.
plus
(
md5
.
copyOfRange
(
6
,
8
).
toUHexString
(
""
))
+
"-"
.
plus
(
md5
.
copyOfRange
(
8
,
12
).
toUHexString
(
""
))
+
"-"
.
plus
(
md5
.
copyOfRange
(
12
,
16
).
toUHexString
(
""
))
+
"}."
+
if
(
filename
.
endsWith
(
".jpeg"
))
"jpg"
else
filename
.
substringAfter
(
"."
,
"jpg"
)
}
}
}
\ No newline at end of file
mirai-core/src/main/java/net/mamoe/mirai/network/BotNetworkHandler.kt
View file @
ff0acc87
...
...
@@ -2,15 +2,14 @@ package net.mamoe.mirai.network
import
net.mamoe.mirai.network.BotNetworkHandlerImpl.BotSocket
import
net.mamoe.mirai.network.BotNetworkHandlerImpl.Login
import
net.mamoe.mirai.network.handler.ActionPacketHandler
import
net.mamoe.mirai.network.handler.DataPacketSocket
import
net.mamoe.mirai.network.handler.MessagePacketHandler
import
net.mamoe.mirai.network.handler.PacketHandler
import
net.mamoe.mirai.network.handler.*
import
net.mamoe.mirai.network.packet.ClientPacket
import
net.mamoe.mirai.network.packet.Packet
import
net.mamoe.mirai.network.packet.ServerEventPacket
import
net.mamoe.mirai.network.packet.ServerPacket
import
net.mamoe.mirai.network.packet.login.LoginState
import
java.io.Closeable
import
java.util.concurrent.CompletableFuture
/**
* Mirai 的网络处理器, 它承担所有数据包([Packet])的处理任务.
...
...
@@ -51,4 +50,15 @@ interface BotNetworkHandler : Closeable {
* java 调用方式: `botNetWorkHandler.getAction()`
*/
var
action
:
ActionPacketHandler
fun
tryLogin
(
touchingTimeoutMillis
:
Long
=
200
):
CompletableFuture
<
LoginState
>
/**
* 添加一个临时包处理器
*
* @see [TemporaryPacketHandler]
*/
fun
addHandler
(
temporaryPacketHandler
:
TemporaryPacketHandler
<
*
>)
override
fun
close
()
}
\ No newline at end of file
mirai-core/src/main/java/net/mamoe/mirai/network/BotNetworkHandlerImpl.kt
View file @
ff0acc87
...
...
@@ -6,7 +6,6 @@ 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.*
...
...
@@ -21,7 +20,6 @@ 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] 以获取帮助
...
...
@@ -40,15 +38,20 @@ internal class BotNetworkHandlerImpl(private val bot: Bot) : BotNetworkHandler {
val
packetHandlers
:
PacketHandlerList
=
PacketHandlerList
()
internal
val
temporaryPacketHandlers
=
Collections
.
synchronizedList
(
mutableListOf
<
TemporaryPacketHandler
<
*
>>())
override
fun
addHandler
(
temporaryPacketHandler
:
TemporaryPacketHandler
<
*
>)
{
temporaryPacketHandler
.
send
(
action
.
session
)
temporaryPacketHandlers
.
add
(
temporaryPacketHandler
)
}
//private | internal
/**
* 尝试登录
. 多次重复登录
* 尝试登录
*
* @param touchingTimeoutMillis 连接每个服务器的 timeout
*/
@JvmOverloads
internal
fun
tryLogin
(
touchingTimeoutMillis
:
Long
=
200
):
CompletableFuture
<
LoginState
>
{
override
fun
tryLogin
(
touchingTimeoutMillis
:
Long
):
CompletableFuture
<
LoginState
>
{
val
ipQueue
:
LinkedList
<
String
>
=
LinkedList
(
Protocol
.
SERVER_IP
)
val
future
=
CompletableFuture
<
LoginState
>()
...
...
@@ -101,6 +104,10 @@ internal class BotNetworkHandlerImpl(private val bot: Bot) : BotNetworkHandler {
return
}
temporaryPacketHandlers
.
removeIf
{
it
.
onPacketReceived
(
action
.
session
,
packet
)
}
//For debug
kotlin
.
run
{
if
(!
packet
.
javaClass
.
name
.
endsWith
(
"Encrypted"
)
&&
!
packet
.
javaClass
.
name
.
endsWith
(
"Raw"
))
{
...
...
@@ -108,7 +115,7 @@ internal class BotNetworkHandlerImpl(private val bot: Bot) : BotNetworkHandler {
}
if
(
packet
is
ServerEventPacket
)
{
sendPacket
(
Client
Message
ResponsePacket
(
bot
.
account
.
qqNumber
,
packet
.
packetId
,
sessionKey
,
packet
.
eventIdentity
))
sendPacket
(
Client
Event
ResponsePacket
(
bot
.
account
.
qqNumber
,
packet
.
packetId
,
sessionKey
,
packet
.
eventIdentity
))
}
}
...
...
@@ -161,6 +168,7 @@ internal class BotNetworkHandlerImpl(private val bot: Bot) : BotNetworkHandler {
}.
start
()
}
/**
* Start network and touch the server
*/
...
...
@@ -173,7 +181,7 @@ internal class BotNetworkHandlerImpl(private val bot: Bot) : BotNetworkHandler {
this
.
loginFuture
=
CompletableFuture
()
serverIP
=
serverAddress
waitForPacket
(
ServerPacket
::
class
,
timeoutMillis
)
{
bot
.
waitForPacket
(
ServerPacket
::
class
,
timeoutMillis
)
{
loginFuture
!!
.
complete
(
LoginState
.
TIMEOUT
)
}
sendPacket
(
ClientTouchPacket
(
bot
.
account
.
qqNumber
,
serverIP
))
...
...
@@ -209,30 +217,7 @@ internal class BotNetworkHandlerImpl(private val bot: Bot) : BotNetworkHandler {
}
}
@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
getOwner
():
Bot
=
this
@BotNetworkHandlerImpl
.
bot
override
fun
close
()
{
this
.
socket
?.
close
()
...
...
mirai-core/src/main/java/net/mamoe/mirai/network/LoginSession.kt
View file @
ff0acc87
...
...
@@ -2,7 +2,11 @@ package net.mamoe.mirai.network
import
net.mamoe.mirai.Bot
import
net.mamoe.mirai.network.handler.DataPacketSocket
import
net.mamoe.mirai.network.handler.TemporaryPacketHandler
import
net.mamoe.mirai.network.packet.ClientPacket
import
net.mamoe.mirai.network.packet.ServerPacket
import
net.mamoe.mirai.utils.getGTK
import
java.util.concurrent.CompletableFuture
/**
* 登录会话. 当登录完成后, 客户端会拿到 sessionKey.
...
...
@@ -15,11 +19,80 @@ class LoginSession(
val
sessionKey
:
ByteArray
,
val
socket
:
DataPacketSocket
)
{
/**
* Web api 使用
*/
lateinit
var
cookies
:
String
/**
* Web api 使用
*/
var
sKey
:
String
=
""
set
(
value
)
{
field
=
value
gtk
=
getGTK
(
value
)
}
/**
* Web api 使用
*/
var
gtk
:
Int
=
0
/**
* 发送一个数据包, 并期待接受一个特定的 [ServerPacket]. 仅 Kotlin 使用
* 发送成功后, 该方法会等待收到 [ServerPacket] 直到超时.
*
* 实现方法:
* ```kotlin
* session.expectPacket<ServerPacketXXX> {
* toSend { ClientPacketXXX(...) }
* expect {//it: ServerPacketXXX
*
* }
* }
* ```
*
* @param P 期待的包
* @param handlerTemporary 处理器.
* @return future. 可进行超时处理
*
* Kotlin DSL: 仅 Kotlin 使用.
*/
@JvmSynthetic
inline
fun
<
reified
P
:
ServerPacket
>
expectPacket
(
handlerTemporary
:
TemporaryPacketHandler
<
P
>.()
->
Unit
):
CompletableFuture
<
Unit
>
{
val
future
=
CompletableFuture
<
Unit
>()
this
.
bot
.
network
.
addHandler
(
TemporaryPacketHandler
(
P
::
class
,
future
,
this
).
also
(
handlerTemporary
))
return
future
}
/**
* 发送一个数据包, 并期待接受一个特定的 [ServerPacket].
* 发送成功后, 该方法会等待收到 [ServerPacket] 直到超时.
* 由于包名可能过长, 可使用 `DataPacketSocket.expectPacket(PacketProcessor)` 替代.
*
* 实现方法:
* ```kotlin
* session.expectPacket<ServerPacketXXX>(ClientPacketXXX(...)) {//it: ServerPacketXXX
*
* }
* ```
*
* @param P 期待的包
* @param toSend 将要发送的包
* @param handler 处理期待的包
* @return future. 可进行超时处理
*
* Kotlin DSL: 仅 Kotlin 使用.
*/
@JvmSynthetic
inline
fun
<
reified
P
:
ServerPacket
>
expectPacket
(
toSend
:
ClientPacket
,
noinline
handler
:
(
P
)
->
Unit
):
CompletableFuture
<
Unit
>
{
val
future
=
CompletableFuture
<
Unit
>()
this
.
bot
.
network
.
addHandler
(
TemporaryPacketHandler
(
P
::
class
,
future
,
this
).
also
{
it
.
toSend
{
toSend
}
it
.
expect
(
handler
)
})
return
future
}
}
\ No newline at end of file
mirai-core/src/main/java/net/mamoe/mirai/network/handler/DataPacketSocket.kt
View file @
ff0acc87
package
net.mamoe.mirai.network.handler
import
net.mamoe.mirai.Bot
import
net.mamoe.mirai.event.events.network.ServerPacketReceivedEvent
import
net.mamoe.mirai.network.BotNetworkHandlerImpl
import
net.mamoe.mirai.network.LoginSession
import
net.mamoe.mirai.network.packet.ClientPacket
import
net.mamoe.mirai.network.packet.ServerPacket
import
net.mamoe.mirai.task.MiraiThreadPool
import
java.io.Closeable
import
java.util.concurrent.Future
/**
* 网络接口.
...
...
@@ -13,12 +18,35 @@ import java.io.Closeable
* @author Him188moe
*/
interface
DataPacketSocket
:
Closeable
{
fun
getOwner
():
Bot
/**
* 分发数据包给 [PacketHandler]
*/
fun
distributePacket
(
packet
:
ServerPacket
)
/**
* 发送一个数据包(非异步).
*
* 可通过 hook 事件 [ServerPacketReceivedEvent] 来获取服务器返回.
*
* @see [LoginSession.expectPacket] kotlin DSL
*/
fun
sendPacket
(
packet
:
ClientPacket
)
/**
* 发送一个数据包(异步).
*
* 可通过 hook 事件 [ServerPacketReceivedEvent] 来获取服务器返回.
*
* @see [LoginSession.expectPacket] kotlin DSL
*/
fun
sendPacketAsync
(
packet
:
ClientPacket
):
Future
<
*
>
{
return
MiraiThreadPool
.
getInstance
().
submit
{
sendPacket
(
packet
)
}
}
fun
isClosed
():
Boolean
override
fun
close
()
...
...
mirai-core/src/main/java/net/mamoe/mirai/network/handler/MessagePacketHandler.kt
View file @
ff0acc87
...
...
@@ -4,13 +4,16 @@ import net.mamoe.mirai.contact.Group
import
net.mamoe.mirai.contact.QQ
import
net.mamoe.mirai.event.events.qq.FriendMessageEvent
import
net.mamoe.mirai.event.hookWhile
import
net.mamoe.mirai.message.Message
import
net.mamoe.mirai.message.defaults.MessageChain
import
net.mamoe.mirai.message.defaults.PlainText
import
net.mamoe.mirai.message.defaults.UnsolvedImage
import
net.mamoe.mirai.network.LoginSession
import
net.mamoe.mirai.network.packet.*
import
net.mamoe.mirai.network.packet.action.ClientSendFriendMessagePacket
import
net.mamoe.mirai.network.packet.action.ClientSendGroupMessagePacket
import
net.mamoe.mirai.network.packet.action.ServerSendFriendMessageResponsePacket
import
net.mamoe.mirai.network.packet.action.ServerSendGroupMessageResponsePacket
import
java.io.File
/**
* 处理消息事件, 承担消息发送任务.
...
...
@@ -27,10 +30,18 @@ class MessagePacketHandler(session: LoginSession) : PacketHandler(session) {
if
(
session
.
socket
.
isClosed
())
{
return
@
hookWhile
false
}
if
(
it
.
message
()
valueEquals
"你好"
)
{
it
.
qq
.
sendMessage
(
"你好!"
)
}
else
if
(
it
.
message
().
toString
().
startsWith
(
"复读"
))
{
it
.
qq
.
sendMessage
(
it
.
message
())
when
{
it
.
message
()
valueEquals
"你好"
->
it
.
qq
.
sendMessage
(
"你好!"
)
it
.
message
().
toString
().
startsWith
(
"复读"
)
->
it
.
qq
.
sendMessage
(
it
.
message
())
it
.
message
().
toString
().
startsWith
(
"发群"
)
->
{
it
.
message
().
list
.
toMutableList
().
let
{
messages
->
messages
.
removeAt
(
0
)
sendGroupMessage
(
Group
(
session
.
bot
,
580266363
),
MessageChain
(
messages
))
}
}
it
.
message
()
valueEquals
"发图片"
->
sendGroupMessage
(
Group
(
session
.
bot
,
580266363
),
PlainText
(
"test"
)
+
UnsolvedImage
(
File
(
"C:\\Users\\Him18\\Desktop\\faceImage_1559564477775.jpg"
)).
also
{
image
->
image
.
upload
(
session
,
it
.
qq
).
get
()
})
}
return
@
hookWhile
true
...
...
@@ -71,11 +82,10 @@ class MessagePacketHandler(session: LoginSession) : PacketHandler(session) {
}
fun
sendFriendMessage
(
qq
:
QQ
,
message
:
MessageChain
)
{
session
.
socket
.
sendPacket
(
ClientSendFriendMessagePacket
(
session
.
bot
.
account
.
qqNumber
,
qq
.
number
,
session
.
sessionKey
,
message
))
session
.
socket
.
sendPacket
Async
(
ClientSendFriendMessagePacket
(
session
.
bot
.
account
.
qqNumber
,
qq
.
number
,
session
.
sessionKey
,
message
))
}
fun
sendGroupMessage
(
group
:
Group
,
message
:
Message
)
{
TODO
()
//sendPacket(ClientSendGroupMessagePacket(group.groupId, bot.account.qqNumber, sessionKey, message))
fun
sendGroupMessage
(
group
:
Group
,
message
:
MessageChain
)
{
session
.
socket
.
sendPacket
(
ClientSendGroupMessagePacket
(
group
.
groupId
,
session
.
bot
.
account
.
qqNumber
,
session
.
sessionKey
,
message
))
}
}
\ No newline at end of file
mirai-core/src/main/java/net/mamoe/mirai/network/handler/PacketHandler.kt
View file @
ff0acc87
...
...
@@ -2,9 +2,8 @@ package net.mamoe.mirai.network.handler
import
net.mamoe.mirai.network.LoginSession
import
net.mamoe.mirai.network.packet.ServerPacket
import
net.mamoe.mirai.utils.MiraiSynchronizedLinkedList
import
java.io.Closeable
import
java.util.*
import
kotlin.NoSuchElementException
/**
* 数据包(接受/发送)处理器
...
...
@@ -28,7 +27,7 @@ fun PacketHandler.asNode(): PacketHandlerNode<PacketHandler> {
return
PacketHandlerNode
(
this
.
javaClass
,
this
)
}
class
PacketHandlerList
:
LinkedList
<
PacketHandlerNode
<
*
>>()
{
class
PacketHandlerList
:
MiraiSynchronized
LinkedList
<
PacketHandlerNode
<
*
>>()
{
fun
<
T
:
PacketHandler
>
get
(
clazz
:
Class
<
T
>):
T
{
this
.
forEach
{
...
...
mirai-core/src/main/java/net/mamoe/mirai/network/handler/TemporaryPacketHandler.kt
0 → 100644
View file @
ff0acc87
package
net.mamoe.mirai.network.handler
import
net.mamoe.mirai.network.LoginSession
import
net.mamoe.mirai.network.packet.ClientPacket
import
net.mamoe.mirai.network.packet.ServerPacket
import
java.util.concurrent.CompletableFuture
import
kotlin.reflect.KClass
/**
* 临时数据包处理器
*
* @see LoginSession.expectPacket
*/
open
class
TemporaryPacketHandler
<
P
:
ServerPacket
>(
private
val
expectationClass
:
KClass
<
P
>,
private
val
future
:
CompletableFuture
<
Unit
>,
private
val
fromSession
:
LoginSession
)
{
private
lateinit
var
toSend
:
ClientPacket
private
lateinit
var
expect
:
(
P
)
->
Unit
lateinit
var
session
:
LoginSession
//无需覆盖
fun
toSend
(
packet
:
()
->
ClientPacket
)
{
this
.
toSend
=
packet
()
}
fun
expect
(
handler
:
(
P
)
->
Unit
)
{
this
.
expect
=
handler
}
fun
send
(
session
:
LoginSession
)
{
this
.
session
=
session
session
.
socket
.
sendPacket
(
toSend
)
}
fun
onPacketReceived
(
session
:
LoginSession
,
packet
:
ServerPacket
):
Boolean
{
if
(
expectationClass
.
isInstance
(
packet
)
&&
session
===
this
.
fromSession
)
{
@Suppress
(
"UNCHECKED_CAST"
)
expect
(
packet
as
P
)
future
.
complete
(
Unit
)
return
true
}
return
false
}
}
\ No newline at end of file
mirai-core/src/main/java/net/mamoe/mirai/network/packet/ClientPacket.kt
View file @
ff0acc87
...
...
@@ -217,7 +217,6 @@ fun DataOutputStream.writeQQ(qq: Long) {
this
.
write
(
qq
.
toUInt
().
toByteArray
())
}
@Throws
(
IOException
::
class
)
fun
DataOutputStream
.
writeGroup
(
groupIdOrGroupNumber
:
Long
)
{
this
.
write
(
groupIdOrGroupNumber
.
toUInt
().
toByteArray
())
...
...
@@ -230,4 +229,8 @@ fun DataOutputStream.writeLVByteArray(byteArray: ByteArray) {
fun
DataOutputStream
.
writeLVString
(
str
:
String
)
{
this
.
writeLVByteArray
(
str
.
toByteArray
())
}
fun
DataOutputStream
.
writeLVHex
(
hex
:
String
)
{
this
.
writeLVByteArray
(
hex
.
hexToBytes
())
}
\ No newline at end of file
mirai-core/src/main/java/net/mamoe/mirai/network/packet/ServerEvent.kt
View file @
ff0acc87
...
...
@@ -105,6 +105,7 @@ class ServerGroupMessageEventPacket(input: DataInputStream, packetId: ByteArray,
override
fun
decode
()
{
println
(
this
.
input
.
goto
(
0
).
readAllBytes
().
toUHexString
())
groupNumber
=
this
.
input
.
goto
(
51
).
readInt
().
toLong
()
qq
=
this
.
input
.
goto
(
56
).
readLong
()
val
fontLength
=
this
.
input
.
goto
(
108
).
readShort
()
...
...
@@ -225,16 +226,16 @@ class ServerFriendMessageEventPacket(input: DataInputStream, packetId: ByteArray
//00 01 AF 0B 00 08 00 01 00 04 52 CC F5 D0 FF 00 02 14 F0
//00 01 0C 0B 00 08 00 01 00 04 52 CC F5 D0 FF 00 02 14 4D
val
id1
=
FaceID
.
ofId
(
read
Var
Number
().
toInt
())
//可能这个是id, 也可能下面那个
val
id1
=
FaceID
.
ofId
(
read
LV
Number
().
toInt
())
//可能这个是id, 也可能下面那个
this
.
skip
(
this
.
readByte
().
toLong
())
this
.
read
Var
Number
()
//某id?
this
.
read
LV
Number
()
//某id?
return
Face
(
id1
)
}
0
x06
->
{
this
.
skip
(
sectionLength
-
37
-
1
)
val
imageId
=
String
(
this
.
readNBytes
(
36
))
this
.
skip
(
1
)
//0x41
return
Image
(
imageId
)
return
Image
(
"{$imageId}.jpg"
)
//todo 如何确定文件后缀??
}
else
->
null
}
...
...
@@ -294,8 +295,7 @@ B1 89 BE 09 8F 00 1A E5 00 0B 03 A2 09 90 BB 7A 1F 40 00 A6 00 00 00 20 00 05 00
* 告知服务器已经收到数据
*/
@PacketId
(
""
)
//随后写入
class
ClientMessageResponsePacket
(
class
ClientEventResponsePacket
(
private
val
qq
:
Long
,
private
val
packetIdFromServer
:
ByteArray
,
//4bytes
private
val
sessionKey
:
ByteArray
,
...
...
mirai-core/src/main/java/net/mamoe/mirai/network/packet/ServerPacket.kt
View file @
ff0acc87
...
...
@@ -4,14 +4,20 @@
package
net.mamoe.mirai.network.packet
import
net.mamoe.mirai.Bot
import
net.mamoe.mirai.event.events.network.ServerPacketReceivedEvent
import
net.mamoe.mirai.event.hookWhile
import
net.mamoe.mirai.network.packet.PacketNameFormatter.adjustName
import
net.mamoe.mirai.network.packet.action.ServerCanAddFriendResponsePacket
import
net.mamoe.mirai.network.packet.action.ServerSendFriendMessageResponsePacket
import
net.mamoe.mirai.network.packet.action.ServerSendGroupMessageResponsePacket
import
net.mamoe.mirai.network.packet.image.ServerTryUploadGroupImageResponsePacket
import
net.mamoe.mirai.network.packet.login.*
import
net.mamoe.mirai.task.MiraiThreadPool
import
net.mamoe.mirai.utils.*
import
java.io.DataInputStream
import
java.io.EOFException
import
kotlin.reflect.KClass
/**
* @author Him188moe
...
...
@@ -76,7 +82,7 @@ abstract class ServerPacket(val input: DataInputStream) : Packet {
println
(
bytes
.
size
)
return
ServerLoginResponseFailedPacket
(
when
(
bytes
.
size
)
{
63
,
319
,
135
,
351
->
LoginState
.
WRONG_PASSWORD
//这四个其中一个
也
是被冻结
63
,
319
,
135
,
351
->
LoginState
.
WRONG_PASSWORD
//这四个其中一个是被冻结
//135 -> LoginState.RETYPE_PASSWORD
279
->
LoginState
.
BLOCKED
263
->
LoginState
.
UNKNOWN_QQ_NUMBER
...
...
@@ -115,6 +121,8 @@ abstract class ServerPacket(val input: DataInputStream) : Packet {
"00 A7"
->
ServerCanAddFriendResponsePacket
(
stream
)
"03 88"
->
ServerTryUploadGroupImageResponsePacket
.
Encrypted
(
stream
)
else
->
throw
IllegalArgumentException
(
idHex
)
}
}.
apply
{
this
.
idHex
=
idHex
}
...
...
@@ -223,7 +231,7 @@ fun <N : Number> DataInputStream.readNBytes(length: N): ByteArray {
}
fun
DataInputStream
.
read
Var
Number
():
Number
{
fun
DataInputStream
.
read
LV
Number
():
Number
{
return
when
(
this
.
readShort
().
toInt
())
{
1
->
this
.
readByte
()
2
->
this
.
readShort
()
...
...
@@ -288,6 +296,32 @@ fun DataInputStream.gotoWhere(matcher: ByteArray): DataInputStream {
}
while
(
true
)
}
@Suppress
(
"UNCHECKED_CAST"
)
internal
fun
<
P
:
ServerPacket
>
Bot
.
waitForPacket
(
packetClass
:
KClass
<
P
>,
timeoutMillis
:
Long
=
Long
.
MAX_VALUE
,
timeout
:
()
->
Unit
=
{})
{
var
got
=
false
ServerPacketReceivedEvent
::
class
.
hookWhile
{
if
(
packetClass
.
isInstance
(
it
.
packet
)
&&
it
.
bot
===
this
)
{
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
)
}
}
}
/*
@Throws(EOFException::class)
fun DataInputStream.gotoWhere(matcher: ByteArray) {
...
...
mirai-core/src/main/java/net/mamoe/mirai/network/packet/Touch.kt
View file @
ff0acc87
...
...
@@ -17,7 +17,7 @@ import java.io.IOException
*
* @author Him188moe
*/
@Suppress
(
"EXPERIMENTAL_API_USAGE"
)
@Suppress
(
"EXPERIMENTAL_API_USAGE"
,
"EXPERIMENTAL_UNSIGNED_LITERALS"
)
@PacketId
(
"08 25 31 01"
)
class
ServerTouchResponsePacket
(
inputStream
:
DataInputStream
)
:
ServerPacket
(
inputStream
)
{
var
serverIP
:
String
?
=
null
...
...
@@ -33,7 +33,7 @@ class ServerTouchResponsePacket(inputStream: DataInputStream) : ServerPacket(inp
override
fun
decode
()
{
when
(
val
id
=
input
.
readByte
().
toInt
())
{
when
(
val
id
=
input
.
readByte
().
to
UByte
().
to
Int
())
{
0
xFE
->
{
input
.
skip
(
94
)
serverIP
=
input
.
readIP
()
...
...
mirai-core/src/main/java/net/mamoe/mirai/network/packet/action/ClientSendFriendMessagePacket.kt
View file @
ff0acc87
...
...
@@ -19,6 +19,7 @@ class ClientSendFriendMessagePacket(
)
:
ClientPacket
()
{
override
fun
encode
()
{
this
.
writeRandom
(
2
)
//part of packet id
this
.
writeQQ
(
botQQ
)
this
.
writeHex
(
Protocol
.
fixVer2
)
...
...
@@ -40,7 +41,6 @@ class ClientSendFriendMessagePacket(
it
.
writeHex
(
Protocol
.
friendMessageConst1
)
//... 85 E9 BB 91
it
.
writeZero
(
2
)
it
.
write
(
message
.
toByteArray
())
/*
...
...
mirai-core/src/main/java/net/mamoe/mirai/network/packet/action/ClientSendGroupMessagePacket.kt
View file @
ff0acc87
package
net.mamoe.mirai.network.packet.action
import
net.mamoe.mirai.message.defaults.MessageChain
import
net.mamoe.mirai.network.Protocol
import
net.mamoe.mirai.network.packet.*
import
net.mamoe.mirai.utils.toUHexString
...
...
@@ -9,12 +10,11 @@ import java.io.DataInputStream
* @author Him188moe
*/
@PacketId
(
"00 02"
)
class
ClientSendGroupMessagePacket
(
private
val
groupId
:
Long
,
//不是 number
private
val
botQQ
:
Long
,
private
val
sessionKey
:
ByteArray
,
private
val
message
:
String
private
val
message
:
MessageChain
)
:
ClientPacket
()
{
override
fun
encode
()
{
this
.
writeRandom
(
2
)
//part of packet id
...
...
@@ -25,20 +25,24 @@ class ClientSendGroupMessagePacket(
val
bytes
=
message
.
toByteArray
()
it
.
writeByte
(
0
x2A
)
it
.
writeGroup
(
groupId
)
it
.
writeShort
(
56
+
bytes
.
size
)
it
.
writeHex
(
"00 01 01 00 00 00 00 00 00 00 4D 53 47 00 00 00 00 00"
)
it
.
writeShort
(
50
+
bytes
.
size
)
it
.
writeHex
(
"00 01 01"
)
it
.
writeHex
(
"00 00 00 00 00 00 00 4D 53 47 00 00 00 00 00"
)
it
.
writeTime
()
it
.
writeRandom
(
4
)
it
.
writeHex
(
"Protocol.messageConst1"
)
it
.
writeHex
(
"00 00 00 00 09 00 86"
)
it
.
writeHex
(
Protocol
.
friendMessageConst1
)
it
.
writeZero
(
2
)
//messages
it
.
writeByte
(
0
x01
)
it
.
write
(
bytes
)
/*it.writeByte(0x01)
it.writeShort(bytes.size + 3)
it.writeByte(0x01)
it.writeShort(bytes.size)
it
.
write
(
bytes
)
it.write(bytes)
*/
println
(
it
.
toByteArray
().
toUHexString
())
}
...
...
mirai-core/src/main/java/net/mamoe/mirai/network/packet/image/UploadGroupImage.kt
View file @
ff0acc87
...
...
@@ -17,17 +17,16 @@ import java.io.DataInputStream
* @author Him188moe
*/
@PacketId
(
"03 88"
)
class
ClientTryGetGroupImageIDPacket
(
private
val
bot
:
Long
,
class
ClientTryGetImageIDPacket
(
private
val
botNumber
:
Long
,
private
val
sessionKey
:
ByteArray
,
private
val
group
:
Long
,
private
val
group
NumberOrQQNumber
:
Long
,
//todo 为什么还要有qq number呢? bot不就是了么
private
val
image
:
BufferedImage
)
:
ClientPacket
()
{
override
fun
encode
()
{
this
.
writeRandom
(
2
)
this
.
writeQQ
(
bot
)
this
.
writeQQ
(
bot
Number
)
this
.
writeHex
(
"04 00 00 00 01 01 01 00 00 68 20 00 00 00 00 00 00 00 00"
)
val
byteArray
=
image
.
toByteArray
()
...
...
@@ -46,10 +45,10 @@ class ClientTryGetGroupImageIDPacket(
it
.
writeHex
(
"5A"
)
it
.
writeHex
(
"08"
)
it
.
writeUVarInt
(
group
)
it
.
writeUVarInt
(
group
NumberOrQQNumber
)
it
.
writeHex
(
"10"
)
it
.
writeUVarInt
(
bot
)
it
.
writeUVarInt
(
bot
Number
)
it
.
writeHex
(
"18 00"
)
...
...
@@ -77,7 +76,7 @@ class ClientTryGetGroupImageIDPacket(
it
.
writeHex
(
"6A"
)
it
.
writeHex
(
"05"
)
it
.
writeHex
(
"32 36 36 35 36
05"
)
//6?
it
.
writeHex
(
"32 36 36 35 36
"
)
it
.
writeHex
(
"70 00"
)
...
...
@@ -95,7 +94,9 @@ abstract class ServerTryUploadGroupImageResponsePacket(input: DataInputStream) :
class
Encrypted
(
input
:
DataInputStream
)
:
ServerPacket
(
input
)
{
fun
decrypt
(
sessionKey
:
ByteArray
):
ServerTryUploadGroupImageResponsePacket
{
val
data
=
this
.
decryptAsByteArray
(
sessionKey
)
if
(
data
.
size
==
239
)
{
println
(
data
.
size
)
println
(
data
.
size
)
if
(
data
.
size
==
209
)
{
return
ServerTryUploadGroupImageSuccessPacket
(
data
.
dataInputStream
()).
setId
(
this
.
idHex
)
}
...
...
mirai-core/src/main/java/net/mamoe/mirai/utils/ContactList.java
View file @
ff0acc87
package
net.mamoe.mirai.utils
;
import
net.mamoe.mirai.contact.Contact
;
import
net.mamoe.mirai.utils.config.MiraiSynchronizedLinkedListMap
;
/**
* @author Him188moe
*/
public
class
ContactList
<
C
extends
Contact
>
extends
MiraiSynchronizedLinked
List
Map
<
Long
,
C
>
{
public
class
ContactList
<
C
extends
Contact
>
extends
MiraiSynchronizedLinked
Hash
Map
<
Long
,
C
>
{
}
mirai-core/src/main/java/net/mamoe/mirai/utils/ImageNetworkUtils.java
View file @
ff0acc87
package
net.mamoe.mirai.utils
;
import
org.apache.commons.httpclient.util.HttpURLConnection
;
import
java.io.IOException
;
import
java.net.HttpURLConnection
;
import
java.net.URL
;
/**
* @author NaturalHG
*/
public
class
ImageNetworkUtils
{
public
static
void
postImage
(
String
uKeyHex
,
int
fileSize
,
String
qqNumber
,
Stri
ng
groupCode
,
byte
[]
img
)
throws
IOException
{
public
static
boolean
postImage
(
String
uKeyHex
,
int
fileSize
,
long
qqNumber
,
lo
ng
groupCode
,
byte
[]
img
)
throws
IOException
{
//http://htdata2.qq.com/cgi-bin/httpconn?htcmd=0x6ff0071&ver=5515&term=pc&ukey=” + 删全部空 (ukey) + “&filesize=” + 到文本 (fileSize) + “&range=0&uin=” + g_uin + “&groupcode=” + Group
StringBuilder
builder
=
new
StringBuilder
(
"http://htdata2.qq.com/cgi-bin/httpconn?htcmd=0x6ff0071&ver=5515&term=pc"
);
builder
.
append
(
"&ukey="
)
.
append
(
uKeyHex
.
trim
())
.
append
(
"&filezise="
).
append
(
fileSize
)
.
append
(
"&range="
).
append
(
"0"
)
.
append
(
"&uin="
).
append
(
qqNumber
)
.
append
(
"&groupcode="
).
append
(
groupCode
);
HttpURLConnection
conn
=
(
HttpURLConnection
)
new
URL
(
builder
.
toString
()).
openConnection
();
String
builder
=
"http://htdata2.qq.com/cgi-bin/httpconn?htcmd=0x6ff0071&ver=5515&term=pc"
+
"&ukey="
+
uKeyHex
.
replace
(
" "
,
""
)
+
"&filezise="
+
fileSize
+
"&range="
+
"0"
+
"&uin="
+
qqNumber
+
"&groupcode="
+
groupCode
;
HttpURLConnection
conn
=
(
HttpURLConnection
)
new
URL
(
builder
).
openConnection
();
conn
.
setRequestProperty
(
"User-agent"
,
"QQClient"
);
conn
.
setRequestProperty
(
"Content-length"
,
""
+
fileSize
);
conn
.
setRequestMethod
(
"POST"
);
conn
.
setDoOutput
(
true
);
conn
.
getOutputStream
().
write
(
img
);
conn
.
connect
();
System
.
out
.
println
(
conn
.
getResponseCode
());
System
.
out
.
println
(
conn
.
getResponseMessage
());
return
conn
.
getResponseCode
()
==
200
;
}
}
mirai-core/src/main/java/net/mamoe/mirai/utils/
config/MiraiSynchronizedLinkedList
Map.java
→
mirai-core/src/main/java/net/mamoe/mirai/utils/
MiraiSynchronizedLinkedHash
Map.java
View file @
ff0acc87
package
net.mamoe.mirai.utils
.config
;
package
net.mamoe.mirai.utils
;
import
org.jetbrains.annotations.NotNull
;
import
org.jetbrains.annotations.Nullable
;
...
...
@@ -16,15 +16,15 @@ import java.util.function.Function;
*
* @author NaturalHG
*/
public
class
MiraiSynchronizedLinked
ListMap
<
K
,
V
>
extends
AbstractMap
<
K
,
V
>
{
public
class
MiraiSynchronizedLinked
HashMap
<
K
,
V
>
extends
AbstractMap
<
K
,
V
>
{
public
MiraiSynchronizedLinked
ListMap
()
{
public
MiraiSynchronizedLinked
HashMap
()
{
this
.
sortedMap
=
Collections
.
synchronizedMap
(
new
LinkedHashMap
<>());
}
protected
final
Map
<
K
,
V
>
sortedMap
;
public
MiraiSynchronizedLinked
ListMap
(
LinkedHashMap
<
K
,
V
>
map
)
{
public
MiraiSynchronizedLinked
HashMap
(
LinkedHashMap
<
K
,
V
>
map
)
{
this
.
sortedMap
=
Collections
.
synchronizedMap
(
map
);
}
...
...
@@ -155,13 +155,13 @@ public class MiraiSynchronizedLinkedListMap<K,V> extends AbstractMap<K,V> {
return
this
.
sortedMap
.
merge
(
key
,
value
,
remappingFunction
);
}
public
boolean
equals
(
MiraiSynchronizedLinked
List
Map
o
)
{
public
boolean
equals
(
MiraiSynchronizedLinked
Hash
Map
o
)
{
return
this
.
sortedMap
.
equals
(
o
.
sortedMap
);
}
@Override
public
boolean
equals
(
Object
o
)
{
return
o
instanceof
MiraiSynchronizedLinked
ListMap
?
this
.
equals
((
MiraiSynchronizedLinkedListMap
)
o
):
super
.
equals
(
o
);
return
o
instanceof
MiraiSynchronizedLinked
HashMap
?
this
.
equals
((
MiraiSynchronizedLinkedHashMap
)
o
)
:
super
.
equals
(
o
);
}
}
mirai-core/src/main/java/net/mamoe/mirai/utils/MiraiSynchronizedLinkedList.java
0 → 100644
View file @
ff0acc87
package
net.mamoe.mirai.utils
;
import
org.jetbrains.annotations.NotNull
;
import
java.util.*
;
import
java.util.function.Consumer
;
import
java.util.function.IntFunction
;
import
java.util.function.Predicate
;
import
java.util.function.UnaryOperator
;
import
java.util.stream.Stream
;
/**
* @author Him188moe
*/
public
class
MiraiSynchronizedLinkedList
<
E
>
extends
AbstractList
<
E
>
{
@SuppressWarnings
(
"WeakerAccess"
)
protected
final
List
<
E
>
syncList
;
public
MiraiSynchronizedLinkedList
()
{
this
.
syncList
=
Collections
.
synchronizedList
(
new
LinkedList
<>());
}
public
MiraiSynchronizedLinkedList
(
Collection
<
E
>
collection
)
{
this
.
syncList
=
Collections
.
synchronizedList
(
new
LinkedList
<>(
collection
));
}
@Override
public
E
get
(
int
index
)
{
return
this
.
syncList
.
get
(
index
);
}
@Override
public
void
forEach
(
Consumer
<?
super
E
>
action
)
{
this
.
syncList
.
forEach
(
action
);
}
@Override
public
Spliterator
<
E
>
spliterator
()
{
return
this
.
syncList
.
spliterator
();
}
@Override
public
Stream
<
E
>
stream
()
{
return
this
.
syncList
.
stream
();
}
@Override
public
Stream
<
E
>
parallelStream
()
{
return
this
.
syncList
.
parallelStream
();
}
@Override
public
int
size
()
{
return
this
.
syncList
.
size
();
}
@SuppressWarnings
(
"SuspiciousToArrayCall"
)
@Override
public
<
T
>
T
[]
toArray
(
IntFunction
<
T
[]>
generator
)
{
return
this
.
syncList
.
toArray
(
generator
);
}
@Override
public
boolean
removeIf
(
Predicate
<?
super
E
>
filter
)
{
return
this
.
syncList
.
removeIf
(
filter
);
}
@Override
public
void
replaceAll
(
UnaryOperator
<
E
>
operator
)
{
this
.
syncList
.
replaceAll
(
operator
);
}
@Override
public
void
sort
(
Comparator
<?
super
E
>
c
)
{
this
.
syncList
.
sort
(
c
);
}
@Override
public
boolean
add
(
E
e
)
{
return
this
.
syncList
.
add
(
e
);
}
@Override
public
E
set
(
int
index
,
E
element
)
{
return
this
.
syncList
.
set
(
index
,
element
);
}
@Override
public
void
add
(
int
index
,
E
element
)
{
this
.
syncList
.
add
(
index
,
element
);
}
@Override
public
E
remove
(
int
index
)
{
return
this
.
syncList
.
remove
(
index
);
}
@Override
public
int
indexOf
(
Object
o
)
{
return
this
.
syncList
.
indexOf
(
o
);
}
@Override
public
int
lastIndexOf
(
Object
o
)
{
return
this
.
syncList
.
lastIndexOf
(
o
);
}
@Override
public
void
clear
()
{
this
.
syncList
.
clear
();
}
@Override
public
boolean
addAll
(
int
index
,
Collection
<?
extends
E
>
c
)
{
return
this
.
syncList
.
addAll
(
index
,
c
);
}
@NotNull
@Override
public
Iterator
<
E
>
iterator
()
{
return
this
.
syncList
.
iterator
();
}
@NotNull
@Override
public
ListIterator
<
E
>
listIterator
()
{
return
this
.
syncList
.
listIterator
();
}
@NotNull
@Override
public
ListIterator
<
E
>
listIterator
(
int
index
)
{
return
this
.
syncList
.
listIterator
(
index
);
}
@NotNull
@Override
public
List
<
E
>
subList
(
int
fromIndex
,
int
toIndex
)
{
return
this
.
syncList
.
subList
(
fromIndex
,
toIndex
);
}
@Override
public
int
hashCode
()
{
return
this
.
syncList
.
hashCode
();
}
@Override
public
boolean
isEmpty
()
{
return
this
.
syncList
.
isEmpty
();
}
@Override
public
boolean
contains
(
Object
o
)
{
return
this
.
syncList
.
contains
(
o
);
}
@NotNull
@Override
public
Object
[]
toArray
()
{
return
this
.
syncList
.
toArray
();
}
@SuppressWarnings
(
"SuspiciousToArrayCall"
)
@NotNull
@Override
public
<
T
>
T
[]
toArray
(
@NotNull
T
[]
a
)
{
return
this
.
syncList
.
toArray
(
a
);
}
@Override
public
boolean
remove
(
Object
o
)
{
return
this
.
syncList
.
remove
(
o
);
}
@Override
public
boolean
containsAll
(
@NotNull
Collection
<?>
c
)
{
return
this
.
syncList
.
containsAll
(
c
);
}
@Override
public
boolean
addAll
(
@NotNull
Collection
<?
extends
E
>
c
)
{
return
this
.
syncList
.
addAll
(
c
);
}
@Override
public
boolean
removeAll
(
@NotNull
Collection
<?>
c
)
{
return
this
.
syncList
.
removeAll
(
c
);
}
@Override
public
boolean
retainAll
(
@NotNull
Collection
<?>
c
)
{
return
this
.
syncList
.
retainAll
(
c
);
}
}
mirai-core/src/main/java/net/mamoe/mirai/utils/config/MiraiConfigSection.java
View file @
ff0acc87
package
net.mamoe.mirai.utils.config
;
import
net.mamoe.mirai.utils.MiraiSynchronizedLinkedHashMap
;
import
org.jetbrains.annotations.Nullable
;
import
java.util.LinkedHashMap
;
...
...
@@ -10,7 +11,7 @@ import java.util.function.Supplier;
/**
* @author NaturalHG
*/
public
class
MiraiConfigSection
<
T
>
extends
MiraiSynchronizedLinked
List
Map
<
String
,
T
>
{
public
class
MiraiConfigSection
<
T
>
extends
MiraiSynchronizedLinked
Hash
Map
<
String
,
T
>
{
public
MiraiConfigSection
(){
super
();
...
...
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