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
170418b5
Commit
170418b5
authored
Feb 21, 2020
by
ryoii
Browse files
Options
Browse Files
Download
Plain Diff
Merge remote-tracking branch 'origin/master'
parents
e5546d92
e580992e
Changes
34
Hide whitespace changes
Inline
Side-by-side
Showing
34 changed files
with
848 additions
and
218 deletions
+848
-218
docs/guide_getting_started.md
docs/guide_getting_started.md
+2
-2
docs/guide_subscribe_events.md
docs/guide_subscribe_events.md
+114
-0
mirai-core-qqandroid/src/commonMain/kotlin/net/mamoe/mirai/qqandroid/ContactImpl.kt
...ommonMain/kotlin/net/mamoe/mirai/qqandroid/ContactImpl.kt
+46
-6
mirai-core-qqandroid/src/commonMain/kotlin/net/mamoe/mirai/qqandroid/message/MessageSourceFromMsg.kt
...net/mamoe/mirai/qqandroid/message/MessageSourceFromMsg.kt
+11
-0
mirai-core-qqandroid/src/commonMain/kotlin/net/mamoe/mirai/qqandroid/message/messages.kt
...Main/kotlin/net/mamoe/mirai/qqandroid/message/messages.kt
+22
-12
mirai-core-qqandroid/src/commonMain/kotlin/net/mamoe/mirai/qqandroid/network/protocol/data/proto/MsgRevokeUserDef.kt
...qqandroid/network/protocol/data/proto/MsgRevokeUserDef.kt
+38
-0
mirai-core-qqandroid/src/commonMain/kotlin/net/mamoe/mirai/qqandroid/network/protocol/packet/PacketFactory.kt
.../mirai/qqandroid/network/protocol/packet/PacketFactory.kt
+3
-1
mirai-core-qqandroid/src/commonMain/kotlin/net/mamoe/mirai/qqandroid/network/protocol/packet/chat/PbMessageSvc.kt
...ai/qqandroid/network/protocol/packet/chat/PbMessageSvc.kt
+91
-0
mirai-core-qqandroid/src/commonMain/kotlin/net/mamoe/mirai/qqandroid/network/protocol/packet/chat/receive/MessageSvc.kt
...ndroid/network/protocol/packet/chat/receive/MessageSvc.kt
+67
-6
mirai-core-qqandroid/src/commonMain/kotlin/net/mamoe/mirai/qqandroid/network/protocol/packet/chat/receive/OnlinePush.kt
...ndroid/network/protocol/packet/chat/receive/OnlinePush.kt
+13
-3
mirai-core-qqandroid/src/jvmTest/kotlin/androidPacketTests/clientToServer.kt
...d/src/jvmTest/kotlin/androidPacketTests/clientToServer.kt
+2
-0
mirai-core-qqandroid/src/jvmTest/kotlin/test/ProtoBufDataClassGenerator.kt
...oid/src/jvmTest/kotlin/test/ProtoBufDataClassGenerator.kt
+1
-1
mirai-core/src/commonMain/kotlin/net.mamoe.mirai/Bot.kt
mirai-core/src/commonMain/kotlin/net.mamoe.mirai/Bot.kt
+1
-3
mirai-core/src/commonMain/kotlin/net.mamoe.mirai/contact/Contact.kt
.../src/commonMain/kotlin/net.mamoe.mirai/contact/Contact.kt
+9
-3
mirai-core/src/commonMain/kotlin/net.mamoe.mirai/contact/ContactList.kt
.../commonMain/kotlin/net.mamoe.mirai/contact/ContactList.kt
+9
-0
mirai-core/src/commonMain/kotlin/net.mamoe.mirai/contact/Group.kt
...re/src/commonMain/kotlin/net.mamoe.mirai/contact/Group.kt
+89
-1
mirai-core/src/commonMain/kotlin/net.mamoe.mirai/contact/QQ.kt
...-core/src/commonMain/kotlin/net.mamoe.mirai/contact/QQ.kt
+19
-0
mirai-core/src/commonMain/kotlin/net.mamoe.mirai/data/GroupInfo.kt
...e/src/commonMain/kotlin/net.mamoe.mirai/data/GroupInfo.kt
+11
-0
mirai-core/src/commonMain/kotlin/net.mamoe.mirai/event/Event.kt
...core/src/commonMain/kotlin/net.mamoe.mirai/event/Event.kt
+0
-0
mirai-core/src/commonMain/kotlin/net.mamoe.mirai/event/linear.kt
...ore/src/commonMain/kotlin/net.mamoe.mirai/event/linear.kt
+11
-0
mirai-core/src/commonMain/kotlin/net.mamoe.mirai/event/subscribeMessages.kt
...monMain/kotlin/net.mamoe.mirai/event/subscribeMessages.kt
+0
-0
mirai-core/src/commonMain/kotlin/net.mamoe.mirai/event/subscriber.kt
...src/commonMain/kotlin/net.mamoe.mirai/event/subscriber.kt
+0
-0
mirai-core/src/commonMain/kotlin/net.mamoe.mirai/message/GroupMessage.kt
...commonMain/kotlin/net.mamoe.mirai/message/GroupMessage.kt
+7
-3
mirai-core/src/commonMain/kotlin/net.mamoe.mirai/message/MessagePacket.kt
...ommonMain/kotlin/net.mamoe.mirai/message/MessagePacket.kt
+9
-22
mirai-core/src/commonMain/kotlin/net.mamoe.mirai/message/MessageReceipt.kt
...mmonMain/kotlin/net.mamoe.mirai/message/MessageReceipt.kt
+125
-0
mirai-core/src/commonMain/kotlin/net.mamoe.mirai/message/data/AtAll.kt
...c/commonMain/kotlin/net.mamoe.mirai/message/data/AtAll.kt
+4
-2
mirai-core/src/commonMain/kotlin/net.mamoe.mirai/message/data/MessageChain.kt
...nMain/kotlin/net.mamoe.mirai/message/data/MessageChain.kt
+17
-119
mirai-core/src/commonMain/kotlin/net.mamoe.mirai/message/data/MessageSource.kt
...Main/kotlin/net.mamoe.mirai/message/data/MessageSource.kt
+13
-1
mirai-core/src/commonMain/kotlin/net.mamoe.mirai/message/data/PlainText.kt
...mmonMain/kotlin/net.mamoe.mirai/message/data/PlainText.kt
+1
-12
mirai-core/src/commonMain/kotlin/net.mamoe.mirai/utils/ExternalImage.kt
.../commonMain/kotlin/net.mamoe.mirai/utils/ExternalImage.kt
+32
-11
mirai-japt/src/main/java/net/mamoe/mirai/japt/BlockingContact.java
...t/src/main/java/net/mamoe/mirai/japt/BlockingContact.java
+4
-4
mirai-japt/src/main/java/net/mamoe/mirai/japt/BlockingGroup.java
...apt/src/main/java/net/mamoe/mirai/japt/BlockingGroup.java
+33
-0
mirai-japt/src/main/java/net/mamoe/mirai/japt/BlockingQQ.java
...i-japt/src/main/java/net/mamoe/mirai/japt/BlockingQQ.java
+37
-0
mirai-japt/src/main/kotlin/net/mamoe/mirai/japt/internal/BlockingContactsImpl.kt
...lin/net/mamoe/mirai/japt/internal/BlockingContactsImpl.kt
+7
-6
No files found.
docs/guide_getting_started.md
View file @
170418b5
...
...
@@ -69,7 +69,7 @@ JDK要求6以上
### 4 Try Bot
-
在src/main文件夹下新建文件夹,命名为
```kotlin```
-
在
```kotlin```
下新建包(在
```kotlin```
文件夹上右键-
```New```
-
```Package
s
```
) 包名为
```net.mamoe.mirai.simpleloader```
-
在
```kotlin```
下新建包(在
```kotlin```
文件夹上右键-
```New```
-
```Package```
) 包名为
```net.mamoe.mirai.simpleloader```
-
在包下新建kotlin文件
```MyLoader.kt```
...
...
@@ -103,9 +103,9 @@ suspend fun main() {
-
本例的功能中,在任意群内任意成员发送包含“舔”字或“刘老板”字样的消息,MiraiBot会回复“刘老板太强了”
至此,简单的入门已经结束,下面可根据不同的需求参阅wiki进行功能的添加。
下面,可以尝试对不同事件进行监听
[
Mirai Guide - Subscribe Events
](
/docs/guide_subscribe_events.md
)
### 此外,还可以使用Maven作为包管理工具
本项目推荐使用gradle,因此不提供详细入门指导
...
...
docs/guide_subscribe_events.md
0 → 100644
View file @
170418b5
# Mirai Guide - Subscribe Events
由于Mirai项目在快速推进中,因此内容时有变动,本文档的最后更新日期为
```2020-02-21```
,对应版本
```0.17.0```
本页面采用Kotlin作为开发语言,
**若你希望使用 Java 开发**
, 请参阅:
[
mirai-japt
](
mirai-japt/README.md
)
本页面是
[
Mirai Guide - Getting Started
](
/docs/guide_getting_started.md
)
的后续Guide
## 消息事件-Message Event
首先我们来回顾上一个Guide的源码
```
kotlin
suspend
fun
main
()
{
val
qqId
=
10000L
//Bot的QQ号,需为Long类型,在结尾处添加大写L
val
password
=
"your_password"
//Bot的密码
val
miraiBot
=
Bot
(
qqId
,
password
).
alsoLogin
()
//新建Bot并登录
miraiBot
.
subscribeMessages
{
"你好"
reply
"你好!"
case
(
"at me"
)
{
reply
(
sender
.
at
()
+
" 给爷爬 "
)
}
(
contains
(
"舔"
)
or
contains
(
"刘老板"
))
{
"刘老板太强了"
.
reply
()
}
}
miraiBot
.
join
()
// 等待 Bot 离线, 避免主线程退出
}
```
在本例中,
```miraiBot```
是一个Bot对象,让其登录,然后对
```Message Event```
进行了监听。
对于
``````Message Event``````
,
```Mirai```
提供了较其他Event更强大的
[
MessageSubscribersBuilder
](
https://github.com/mamoe/mirai/wiki/mirai-core/src/commonMain/kotlin/net.mamoe.mirai/event/MessageSubscribers.kt#L140
)
,本例也采用了
[
MessageSubscribersBuilder
](
https://github.com/mamoe/mirai/wiki/mirai-core/src/commonMain/kotlin/net.mamoe.mirai/event/MessageSubscribers.kt#L140
)
。其他具体使用方法可以参考
[
Wiki:Message Event
](
https://github.com/mamoe/mirai/wiki/Development-Guide---Kotlin#Message-Event
)
部分。
## 事件-Event
上一节中提到的
```Message Event```
仅仅是众多
```Event```
的这一种,其他
```Event```
有群员加入群,离开群,私聊等等...
具体doc暂不提供,现可翻阅源码
[
**BotEvents.kt**
](
https://github.com/mamoe/mirai/blob/master/mirai-core/src/commonMain/kotlin/net.mamoe.mirai/event/events/BotEvents.kt
)
,查看注释。当前事件仍在扩充中,可能有一定不足。
下面我们开始示例对一些事件进行监听。
## 尝试监听事件-Try Subscribing Events
### 监听加群事件
在代码中的
```miraiBot.join()```
前添加
```
kotlin
miraiBot
.
subscribeAlways
<
MemberJoinEvent
>
{
it
.
group
.
sendMessage
(
"欢迎 ${it.member.nameCardOrNick} 加入本群!"
)
}
```
本段语句监听了加入群的事件。
### 监听禁言事件
在代码中添加
```
kotlin
miraiBot
.
subscribeAlways
<
MemberMuteEvent
>
(){
it
.
group
.
sendMessage
(
"恭喜老哥 ${it.member.nameCardOrNick} 喜提禁言套餐一份"
)
}
```
在被禁言后,Bot将发送恭喜语句。
### 添加后的可执行代码
至此,当前的代码为
```
kotlin
package
net.mamoe.mirai.simpleloader
import
kotlinx.coroutines.*
import
net.mamoe.mirai.Bot
import
net.mamoe.mirai.alsoLogin
import
net.mamoe.mirai.event.subscribeMessages
import
net.mamoe.mirai.contact.nameCardOrNick
import
net.mamoe.mirai.contact.sendMessage
import
net.mamoe.mirai.event.events.MemberJoinEvent
import
net.mamoe.mirai.event.events.MemberMuteEvent
import
net.mamoe.mirai.event.subscribeAlways
suspend
fun
main
()
{
val
qqId
=
10000L
//Bot的QQ号,需为Long类型,在结尾处添加大写L
val
password
=
"your_password"
//Bot的密码
val
miraiBot
=
Bot
(
qqId
,
password
).
alsoLogin
()
//新建Bot并登录
miraiBot
.
subscribeMessages
{
"你好"
reply
"你好!"
case
(
"at me"
)
{
reply
(
sender
.
at
()
+
" 给爷爬 "
)
}
(
contains
(
"舔"
)
or
contains
(
"刘老板"
))
{
"刘老板太强了"
.
reply
()
}
}
miraiBot
.
subscribeAlways
<
MemberJoinEvent
>
{
it
.
group
.
sendMessage
(
"欢迎 ${it.member.nameCardOrNick} 加入本群!"
)
}
miraiBot
.
subscribeAlways
<
MemberMuteEvent
>
(){
it
.
group
.
sendMessage
(
"恭喜老哥 ${it.member.nameCardOrNick} 喜提禁言套餐一份"
)
}
miraiBot
.
join
()
// 等待 Bot 离线, 避免主线程退出
}
```
mirai-core-qqandroid/src/commonMain/kotlin/net/mamoe/mirai/qqandroid/ContactImpl.kt
View file @
170418b5
...
...
@@ -16,14 +16,13 @@ import net.mamoe.mirai.event.broadcast
import
net.mamoe.mirai.event.events.*
import
net.mamoe.mirai.event.events.MessageSendEvent.FriendMessageSendEvent
import
net.mamoe.mirai.event.events.MessageSendEvent.GroupMessageSendEvent
import
net.mamoe.mirai.message.data.CustomFaceFromFile
import
net.mamoe.mirai.message.data.Image
import
net.mamoe.mirai.message.data.MessageChain
import
net.mamoe.mirai.message.data.NotOnlineImageFromFile
import
net.mamoe.mirai.message.MessageReceipt
import
net.mamoe.mirai.message.data.*
import
net.mamoe.mirai.qqandroid.network.highway.HighwayHelper
import
net.mamoe.mirai.qqandroid.network.highway.postImage
import
net.mamoe.mirai.qqandroid.network.protocol.data.jce.StTroopMemberInfo
import
net.mamoe.mirai.qqandroid.network.protocol.data.proto.Cmd0x352
import
net.mamoe.mirai.qqandroid.network.protocol.packet.chat.PbMessageSvc
import
net.mamoe.mirai.qqandroid.network.protocol.packet.chat.TroopManagement
import
net.mamoe.mirai.qqandroid.network.protocol.packet.chat.image.ImgStore
import
net.mamoe.mirai.qqandroid.network.protocol.packet.chat.image.LongConn
...
...
@@ -66,7 +65,7 @@ internal class QQImpl(
override
val
nick
:
String
get
()
=
friendInfo
.
nick
override
suspend
fun
sendMessage
(
message
:
MessageChain
)
{
override
suspend
fun
sendMessage
(
message
:
MessageChain
)
:
MessageReceipt
<
QQ
>
{
val
event
=
FriendMessageSendEvent
(
this
,
message
).
broadcast
()
if
(
event
.
isCancelled
)
{
throw
EventCancelledException
(
"cancelled by FriendMessageSendEvent"
)
...
...
@@ -80,6 +79,7 @@ internal class QQImpl(
).
sendAndExpect
<
MessageSvc
.
PbSendMsg
.
Response
>()
is
MessageSvc
.
PbSendMsg
.
Response
.
SUCCESS
)
{
"send message failed"
}
}
return
MessageReceipt
(
message
,
this
)
}
override
suspend
fun
uploadImage
(
image
:
ExternalImage
):
Image
=
try
{
...
...
@@ -325,6 +325,24 @@ internal class GroupImpl(
override
lateinit
var
owner
:
Member
@UseExperimental
(
MiraiExperimentalAPI
::
class
)
override
val
botAsMember
:
Member
by
lazy
{
Member
(
object
:
MemberInfo
{
override
val
nameCard
:
String
get
()
=
bot
.
nick
// TODO: 2020/2/21 机器人在群内的昵称获取
override
val
permission
:
MemberPermission
get
()
=
botPermission
override
val
specialTitle
:
String
get
()
=
""
// TODO: 2020/2/21 获取机器人在群里的头衔
override
val
muteTimestamp
:
Int
get
()
=
botMuteRemaining
override
val
uin
:
Long
get
()
=
bot
.
uin
override
val
nick
:
String
get
()
=
bot
.
nick
})
}
@UseExperimental
(
MiraiExperimentalAPI
::
class
)
override
lateinit
var
botPermission
:
MemberPermission
...
...
@@ -340,6 +358,9 @@ internal class GroupImpl(
override
val
members
:
ContactList
<
Member
>
=
ContactList
(
members
.
mapNotNull
{
if
(
it
.
uin
==
bot
.
uin
)
{
botPermission
=
it
.
permission
if
(
it
.
permission
==
MemberPermission
.
OWNER
)
{
owner
=
botAsMember
}
null
}
else
Member
(
it
).
also
{
member
->
if
(
member
.
permission
==
MemberPermission
.
OWNER
)
{
...
...
@@ -475,6 +496,20 @@ internal class GroupImpl(
TODO
(
"not implemented"
)
}
override
suspend
fun
recall
(
source
:
MessageSource
)
{
if
(
source
.
senderId
!=
bot
.
uin
)
{
checkBotPermissionOperator
()
}
source
.
ensureSequenceIdAvailable
()
bot
.
network
.
run
{
val
response
=
PbMessageSvc
.
PbMsgWithDraw
.
Group
(
bot
.
client
,
this
@GroupImpl
.
id
,
source
.
sequenceId
,
source
.
messageUid
.
toInt
())
.
sendAndExpect
<
PbMessageSvc
.
PbMsgWithDraw
.
Response
>()
check
(
response
is
PbMessageSvc
.
PbMsgWithDraw
.
Response
.
Success
)
{
"Failed to recall message #${source.sequenceId}: $response"
}
}
}
@UseExperimental
(
MiraiExperimentalAPI
::
class
)
override
fun
Member
(
memberInfo
:
MemberInfo
):
Member
{
return
MemberImpl
(
...
...
@@ -498,7 +533,7 @@ internal class GroupImpl(
return
members
.
delegate
.
filteringGetOrNull
{
it
.
id
==
id
}
}
override
suspend
fun
sendMessage
(
message
:
MessageChain
)
{
override
suspend
fun
sendMessage
(
message
:
MessageChain
)
:
MessageReceipt
<
Group
>
{
check
(!
isBotMuted
)
{
"bot is muted. Remaining seconds=$botMuteRemaining"
}
val
event
=
GroupMessageSendEvent
(
this
,
message
).
broadcast
()
if
(
event
.
isCancelled
)
{
...
...
@@ -514,6 +549,11 @@ internal class GroupImpl(
response
is
MessageSvc
.
PbSendMsg
.
Response
.
SUCCESS
)
{
"send message failed: $response"
}
}
((
message
.
last
()
as
MessageSource
)
as
MessageSvc
.
PbSendMsg
.
MessageSourceFromSend
)
.
startWaitingSequenceId
(
this
)
return
MessageReceipt
(
message
,
this
)
}
override
suspend
fun
uploadImage
(
image
:
ExternalImage
):
Image
=
try
{
...
...
mirai-core-qqandroid/src/commonMain/kotlin/net/mamoe/mirai/qqandroid/message/MessageSourceFromMsg.kt
View file @
170418b5
...
...
@@ -22,6 +22,12 @@ internal inline class MessageSourceFromServer(
val
delegate
:
ImMsgBody
.
SourceMsg
)
:
MessageSource
{
override
val
time
:
Long
get
()
=
delegate
.
time
.
toLong
()
and
0
xFFFFFFFF
override
val
sequenceId
:
Int
get
()
=
delegate
.
origSeqs
?.
firstOrNull
()
?:
error
(
"cannot find sequenceId from ImMsgBody.SourceMsg"
)
override
suspend
fun
ensureSequenceIdAvailable
()
{
// nothing to do
}
override
val
messageUid
:
Long
get
()
=
delegate
.
pbReserve
.
loadAs
(
SourceMsg
.
ResvAttr
.
serializer
()).
origUids
!!
override
val
sourceMessage
:
MessageChain
get
()
=
delegate
.
toMessageChain
()
override
val
senderId
:
Long
get
()
=
delegate
.
senderUin
...
...
@@ -34,6 +40,11 @@ internal inline class MessageSourceFromMsg(
val
delegate
:
MsgComm
.
Msg
)
:
MessageSource
{
override
val
time
:
Long
get
()
=
delegate
.
msgHead
.
msgTime
.
toLong
()
and
0
xFFFFFFFF
override
val
sequenceId
:
Int
get
()
=
delegate
.
msgHead
.
msgSeq
override
suspend
fun
ensureSequenceIdAvailable
()
{
// nothing to do
}
override
val
messageUid
:
Long
get
()
=
delegate
.
msgBody
.
richText
.
attr
!!
.
random
.
toLong
()
override
val
sourceMessage
:
MessageChain
get
()
=
delegate
.
toMessageChain
()
override
val
senderId
:
Long
get
()
=
delegate
.
msgHead
.
fromUin
...
...
mirai-core-qqandroid/src/commonMain/kotlin/net/mamoe/mirai/qqandroid/message/messages.kt
View file @
170418b5
...
...
@@ -15,6 +15,7 @@ import kotlinx.io.core.readUInt
import
net.mamoe.mirai.message.data.*
import
net.mamoe.mirai.qqandroid.network.protocol.data.proto.ImMsgBody
import
net.mamoe.mirai.qqandroid.network.protocol.data.proto.MsgComm
import
net.mamoe.mirai.utils.ExternalImage
import
net.mamoe.mirai.utils.MiraiDebugAPI
import
net.mamoe.mirai.utils.MiraiInternalAPI
import
net.mamoe.mirai.utils.io.discardExact
...
...
@@ -27,12 +28,13 @@ internal fun At.toJceData(): ImMsgBody.Text {
return
ImMsgBody
.
Text
(
str
=
text
,
attr6Buf
=
buildPacket
{
writeShort
(
1
)
writeShort
(
0
)
writeShort
(
text
.
length
.
toShort
())
writeByte
(
1
)
writeInt
(
target
.
toInt
())
writeShort
(
0
)
// MessageForText$AtTroopMemberInfo
writeShort
(
1
)
// const
writeShort
(
0
)
// startPos
writeShort
(
text
.
length
.
toShort
())
// textLen
writeByte
(
0
)
// flag, may=1
writeInt
(
target
.
toInt
())
// uin
writeShort
(
0
)
// const
}.
readBytes
()
)
}
...
...
@@ -206,7 +208,15 @@ notOnlineImage=NotOnlineImage#2050019814 {
private
val
atAllData
=
ImMsgBody
.
Elem
(
text
=
ImMsgBody
.
Text
(
str
=
"@全体成员"
,
attr6Buf
=
"00 01 00 00 00 05 01 00 00 00 00 00 00"
.
hexToBytes
()
attr6Buf
=
buildPacket
{
// MessageForText$AtTroopMemberInfo
writeShort
(
1
)
// const
writeShort
(
0
)
// startPos
writeShort
(
"@全体成员"
.
length
.
toShort
())
// textLen
writeByte
(
1
)
// flag, may=1
writeInt
(
0
)
// uin
writeShort
(
0
)
// const
}.
readBytes
()
)
)
...
...
@@ -224,7 +234,7 @@ internal fun MessageChain.toRichTextElems(): MutableList<ImMsgBody.Elem> {
this
.
forEach
{
when
(
it
)
{
is
PlainText
->
elements
.
add
(
ImMsgBody
.
Elem
(
text
=
ImMsgBody
.
Text
(
str
=
it
.
stringValue
)))
is
At
->
elements
.
add
(
ImMsgBody
.
Elem
(
text
=
it
.
toJceData
()))
is
At
->
elements
.
add
(
ImMsgBody
.
Elem
(
text
=
it
.
toJceData
()))
.
also
{
elements
.
add
(
ImMsgBody
.
Elem
(
text
=
ImMsgBody
.
Text
(
str
=
" "
)))
}
is
CustomFaceFromFile
->
elements
.
add
(
ImMsgBody
.
Elem
(
customFace
=
it
.
toJceData
()))
is
CustomFaceFromServer
->
elements
.
add
(
ImMsgBody
.
Elem
(
customFace
=
it
.
delegate
))
is
NotOnlineImageFromServer
->
elements
.
add
(
ImMsgBody
.
Elem
(
notOnlineImage
=
it
.
delegate
))
...
...
@@ -249,7 +259,7 @@ internal fun MessageChain.toRichTextElems(): MutableList<ImMsgBody.Elem> {
internal
class
CustomFaceFromServer
(
internal
val
delegate
:
ImMsgBody
.
CustomFace
)
:
CustomFace
()
{
override
val
filepath
:
String
get
()
=
delegate
.
filePath
override
val
filepath
:
String
=
delegate
.
filePath
override
val
fileId
:
Int
get
()
=
delegate
.
fileId
override
val
serverIp
:
Int
get
()
=
delegate
.
serverIp
override
val
serverPort
:
Int
get
()
=
delegate
.
serverPort
...
...
@@ -265,14 +275,14 @@ internal class CustomFaceFromServer(
override
val
size
:
Int
get
()
=
delegate
.
size
override
val
original
:
Int
get
()
=
delegate
.
origin
override
val
pbReserve
:
ByteArray
get
()
=
delegate
.
pbReserve
override
val
imageId
:
String
get
()
=
delegate
.
filePath
override
val
imageId
:
String
=
ExternalImage
.
generateImageId
(
delegate
.
md5
,
imageType
)
override
fun
equals
(
other
:
Any
?):
Boolean
{
return
other
is
CustomFaceFromServer
&&
other
.
filepath
==
this
.
filepath
&&
other
.
md5
.
contentEquals
(
this
.
md5
)
}
override
fun
hashCode
():
Int
{
return
filepath
.
hashCode
()
+
31
*
md5
.
hashCode
()
return
imageId
.
hashCode
()
+
31
*
md5
.
hashCode
()
}
}
...
...
@@ -296,7 +306,7 @@ internal class NotOnlineImageFromServer(
}
override
fun
hashCode
():
Int
{
return
resourc
eId
.
hashCode
()
+
31
*
md5
.
hashCode
()
return
imag
eId
.
hashCode
()
+
31
*
md5
.
hashCode
()
}
}
...
...
mirai-core-qqandroid/src/commonMain/kotlin/net/mamoe/mirai/qqandroid/network/protocol/data/proto/MsgRevokeUserDef.kt
0 → 100644
View file @
170418b5
/*
* Copyright 2020 Mamoe Technologies and contributors.
*
* 此源代码的使用受 GNU AFFERO GENERAL PUBLIC LICENSE version 3 许可证的约束, 可以在以下链接找到该许可证.
* Use of this source code is governed by the GNU AGPLv3 license that can be found through the following link.
*
* https://github.com/mamoe/mirai/blob/master/LICENSE
*/
package
net.mamoe.mirai.qqandroid.network.protocol.data.proto
import
kotlinx.serialization.SerialId
import
kotlinx.serialization.Serializable
import
net.mamoe.mirai.qqandroid.io.ProtoBuf
class
MsgRevokeUserDef
:
ProtoBuf
{
@Serializable
class
MsgInfoUserDef
(
@SerialId
(
1
)
val
longMessageFlag
:
Int
=
0
,
@SerialId
(
2
)
val
longMsgInfo
:
List
<
MsgInfoDef
>?
=
null
,
@SerialId
(
3
)
val
fileUuid
:
List
<
String
>
=
listOf
()
)
:
ProtoBuf
{
@Serializable
class
MsgInfoDef
(
@SerialId
(
1
)
val
msgSeq
:
Int
=
0
,
@SerialId
(
2
)
val
longMsgId
:
Int
=
0
,
@SerialId
(
3
)
val
longMsgNum
:
Int
=
0
,
@SerialId
(
4
)
val
longMsgIndex
:
Int
=
0
)
:
ProtoBuf
}
@Serializable
class
UinTypeUserDef
(
@SerialId
(
1
)
val
fromUinType
:
Int
=
0
,
@SerialId
(
2
)
val
fromGroupCode
:
Long
=
0L
,
@SerialId
(
3
)
val
fileUuid
:
List
<
String
>
=
listOf
()
)
:
ProtoBuf
}
\ No newline at end of file
mirai-core-qqandroid/src/commonMain/kotlin/net/mamoe/mirai/qqandroid/network/protocol/packet/PacketFactory.kt
View file @
170418b5
...
...
@@ -14,6 +14,7 @@ import kotlinx.io.pool.useInstance
import
net.mamoe.mirai.data.Packet
import
net.mamoe.mirai.event.Event
import
net.mamoe.mirai.qqandroid.QQAndroidBot
import
net.mamoe.mirai.qqandroid.network.protocol.packet.chat.PbMessageSvc
import
net.mamoe.mirai.qqandroid.network.protocol.packet.chat.TroopManagement
import
net.mamoe.mirai.qqandroid.network.protocol.packet.chat.image.ImgStore
import
net.mamoe.mirai.qqandroid.network.protocol.packet.chat.image.LongConn
...
...
@@ -138,7 +139,8 @@ internal object KnownPacketFactories {
TroopManagement
.
GetGroupInfo
,
TroopManagement
.
EditGroupNametag
,
TroopManagement
.
Kick
,
Heartbeat
.
Alive
Heartbeat
.
Alive
,
PbMessageSvc
.
PbMsgWithDraw
)
object
IncomingFactories
:
List
<
IncomingPacketFactory
<
*
>>
by
mutableListOf
(
...
...
mirai-core-qqandroid/src/commonMain/kotlin/net/mamoe/mirai/qqandroid/network/protocol/packet/chat/PbMessageSvc.kt
0 → 100644
View file @
170418b5
/*
* Copyright 2020 Mamoe Technologies and contributors.
*
* 此源代码的使用受 GNU AFFERO GENERAL PUBLIC LICENSE version 3 许可证的约束, 可以在以下链接找到该许可证.
* Use of this source code is governed by the GNU AGPLv3 license that can be found through the following link.
*
* https://github.com/mamoe/mirai/blob/master/LICENSE
*/
package
net.mamoe.mirai.qqandroid.network.protocol.packet.chat
import
kotlinx.io.core.ByteReadPacket
import
net.mamoe.mirai.data.Packet
import
net.mamoe.mirai.qqandroid.QQAndroidBot
import
net.mamoe.mirai.qqandroid.io.serialization.readProtoBuf
import
net.mamoe.mirai.qqandroid.io.serialization.toByteArray
import
net.mamoe.mirai.qqandroid.io.serialization.writeProtoBuf
import
net.mamoe.mirai.qqandroid.network.QQAndroidClient
import
net.mamoe.mirai.qqandroid.network.protocol.data.proto.MsgRevokeUserDef
import
net.mamoe.mirai.qqandroid.network.protocol.data.proto.MsgSvc
import
net.mamoe.mirai.qqandroid.network.protocol.packet.OutgoingPacket
import
net.mamoe.mirai.qqandroid.network.protocol.packet.OutgoingPacketFactory
import
net.mamoe.mirai.qqandroid.network.protocol.packet.buildOutgoingUniPacket
internal
class
PbMessageSvc
{
object
PbMsgWithDraw
:
OutgoingPacketFactory
<
PbMsgWithDraw
.
Response
>(
"PbMessageSvc.PbMsgWithDraw"
)
{
sealed
class
Response
:
Packet
{
object
Success
:
Response
()
{
override
fun
toString
():
String
{
return
"PbMessageSvc.PbMsgWithDraw.Response.Success"
}
}
data class
Failed
(
val
result
:
Int
,
val
errorMessage
:
String
)
:
Response
()
}
// 12 1A 08 01 10 00 18 E7 C1 AD B8 02 22 0A 08 BF BA 03 10 BF 81 CB B7 03 2A 02 08 00
fun
Group
(
client
:
QQAndroidClient
,
groupCode
:
Long
,
messageSequenceId
:
Int
,
// 56639
messageRandom
:
Int
,
// 921878719
messageType
:
Int
=
0
):
OutgoingPacket
=
buildOutgoingUniPacket
(
client
)
{
writeProtoBuf
(
MsgSvc
.
PbMsgWithDrawReq
.
serializer
(),
MsgSvc
.
PbMsgWithDrawReq
(
groupWithDraw
=
listOf
(
MsgSvc
.
PbGroupMsgWithDrawReq
(
subCmd
=
1
,
groupType
=
0
,
// 普通群
groupCode
=
groupCode
,
msgList
=
listOf
(
MsgSvc
.
PbGroupMsgWithDrawReq
.
MessageInfo
(
msgSeq
=
messageSequenceId
,
msgRandom
=
messageRandom
,
msgType
=
messageType
)
),
userdef
=
MsgRevokeUserDef
.
MsgInfoUserDef
(
longMessageFlag
=
0
).
toByteArray
(
MsgRevokeUserDef
.
MsgInfoUserDef
.
serializer
())
)
)
)
)
}
override
suspend
fun
ByteReadPacket
.
decode
(
bot
:
QQAndroidBot
):
Response
{
val
resp
=
readProtoBuf
(
MsgSvc
.
PbMsgWithDrawResp
.
serializer
())
resp
.
groupWithDraw
?.
firstOrNull
()
?.
let
{
if
(
it
.
result
!=
0
)
{
return
Response
.
Failed
(
it
.
result
,
it
.
errmsg
)
}
return
Response
.
Success
}
resp
.
c2cWithDraw
?.
firstOrNull
()
?.
let
{
if
(
it
.
result
!=
0
)
{
return
Response
.
Failed
(
it
.
result
,
it
.
errmsg
)
}
return
Response
.
Success
}
return
Response
.
Failed
(-
1
,
"No response"
)
}
}
}
\ No newline at end of file
mirai-core-qqandroid/src/commonMain/kotlin/net/mamoe/mirai/qqandroid/network/protocol/packet/chat/receive/MessageSvc.kt
View file @
170418b5
...
...
@@ -9,18 +9,25 @@
package
net.mamoe.mirai.qqandroid.network.protocol.packet.chat.receive
import
kotlinx.coroutines.CompletableDeferred
import
kotlinx.coroutines.ExperimentalCoroutinesApi
import
kotlinx.io.core.ByteReadPacket
import
kotlinx.io.core.discardExact
import
net.mamoe.mirai.contact.Contact
import
net.mamoe.mirai.contact.Group
import
net.mamoe.mirai.contact.MemberPermission
import
net.mamoe.mirai.data.MemberInfo
import
net.mamoe.mirai.data.MultiPacket
import
net.mamoe.mirai.data.Packet
import
net.mamoe.mirai.event.ListeningStatus
import
net.mamoe.mirai.event.events.BotJoinGroupEvent
import
net.mamoe.mirai.event.events.BotOfflineEvent
import
net.mamoe.mirai.event.events.MemberJoinEvent
import
net.mamoe.mirai.event.subscribe
import
net.mamoe.mirai.message.FriendMessage
import
net.mamoe.mirai.message.data.MessageChain
import
net.mamoe.mirai.message.data.MessageSource
import
net.mamoe.mirai.message.data.addOrRemove
import
net.mamoe.mirai.qqandroid.GroupImpl
import
net.mamoe.mirai.qqandroid.QQAndroidBot
import
net.mamoe.mirai.qqandroid.io.serialization.decodeUniPacket
...
...
@@ -256,12 +263,49 @@ internal class MessageSvc {
override
fun
toString
():
String
=
"MessageSvc.PbSendMsg.Response.SUCCESS"
}
/**
* 121: 被限制? 个别号才不能发
*/
data class
Failed
(
val
resultType
:
Int
,
val
errorCode
:
Int
,
val
errorMessage
:
String
)
:
Response
()
{
override
fun
toString
():
String
=
"MessageSvc.PbSendMsg.Response.Failed(resultType=$resultType, errorCode=$errorCode, errorMessage=$errorMessage)"
}
}
internal
class
MessageSourceFromSend
(
override
val
messageUid
:
Long
,
override
val
time
:
Long
,
override
val
senderId
:
Long
,
override
val
groupId
:
Long
,
override
val
sourceMessage
:
MessageChain
)
:
MessageSource
{
lateinit
var
sequenceIdDeferred
:
CompletableDeferred
<
Int
>
fun
startWaitingSequenceId
(
contact
:
Contact
)
{
sequenceIdDeferred
=
CompletableDeferred
()
contact
.
subscribe
<
OnlinePush
.
PbPushGroupMsg
.
SendGroupMessageReceipt
>
{
event
->
if
(
event
.
messageRandom
==
messageUid
.
toInt
())
{
sequenceIdDeferred
.
complete
(
event
.
sequenceId
)
return
@
subscribe
ListeningStatus
.
STOPPED
}
return
@
subscribe
ListeningStatus
.
LISTENING
}
}
@UseExperimental
(
ExperimentalCoroutinesApi
::
class
)
override
val
sequenceId
:
Int
get
()
=
sequenceIdDeferred
.
getCompleted
()
override
suspend
fun
ensureSequenceIdAvailable
()
{
sequenceIdDeferred
.
join
()
}
override
fun
toString
():
String
{
return
""
}
}
/**
* 发送好友消息
*/
...
...
@@ -271,9 +315,17 @@ internal class MessageSvc {
toUin
:
Long
,
message
:
MessageChain
):
OutgoingPacket
=
buildOutgoingUniPacket
(
client
)
{
///writeFully("0A 08 0A 06 08 89 FC A6 8C 0B 12 06 08 01 10 00 18 00 1A 1F 0A 1D 12 08 0A 06 0A 04 F0 9F 92 A9 12 11 AA 02 0E 88 01 00 9A 01 08 78 00 F8 01 00 C8 02 00 20 9B 7A 28 F4 CA 9B B8 03 32 34 08 92 C2 C4 F1 05 10 92 C2 C4 F1 05 18 E6 ED B9 C3 02 20 89 FE BE A4 06 28 89 84 F9 A2 06 48 DE 8C EA E5 0E 58 D9 BD BB A0 09 60 1D 68 92 C2 C4 F1 05 70 00 40 01".hexToBytes())
val
source
=
MessageSourceFromSend
(
messageUid
=
Random
.
nextInt
().
absoluteValue
.
toLong
()
and
0
xffffffff
,
senderId
=
client
.
uin
,
time
=
currentTimeSeconds
+
client
.
timeDifference
,
groupId
=
0
,
sourceMessage
=
message
)
message
.
addOrRemove
(
source
)
///return@buildOutgoingUniPacket
writeProtoBuf
(
MsgSvc
.
PbSendMsgReq
.
serializer
(),
MsgSvc
.
PbSendMsgReq
(
...
...
@@ -285,8 +337,8 @@ internal class MessageSvc {
)
),
msgSeq
=
client
.
atomicNextMessageSequenceId
(),
msgRand
=
Random
.
nextInt
().
absoluteValue
,
syncCookie
=
SyncCookie
(
time
=
currentTimeSeconds
).
toByteArray
(
SyncCookie
.
serializer
())
msgRand
=
source
.
messageUid
.
toInt
()
,
syncCookie
=
SyncCookie
(
time
=
source
.
time
).
toByteArray
(
SyncCookie
.
serializer
())
// msgVia = 1
)
)
...
...
@@ -302,11 +354,18 @@ internal class MessageSvc {
message
:
MessageChain
):
OutgoingPacket
=
buildOutgoingUniPacket
(
client
)
{
val
source
=
MessageSourceFromSend
(
messageUid
=
Random
.
nextInt
().
absoluteValue
.
toLong
(),
senderId
=
client
.
uin
,
time
=
currentTimeSeconds
+
client
.
timeDifference
,
groupId
=
groupCode
,
sourceMessage
=
message
)
///writeFully("0A 08 0A 06 08 89 FC A6 8C 0B 12 06 08 01 10 00 18 00 1A 1F 0A 1D 12 08 0A 06 0A 04 F0 9F 92 A9 12 11 AA 02 0E 88 01 00 9A 01 08 78 00 F8 01 00 C8 02 00 20 9B 7A 28 F4 CA 9B B8 03 32 34 08 92 C2 C4 F1 05 10 92 C2 C4 F1 05 18 E6 ED B9 C3 02 20 89 FE BE A4 06 28 89 84 F9 A2 06 48 DE 8C EA E5 0E 58 D9 BD BB A0 09 60 1D 68 92 C2 C4 F1 05 70 00 40 01".hexToBytes())
// DebugLogger.debug("sending group message: " + message.toRichTextElems().contentToString())
val
seq
=
client
.
atomicNextMessageSequenceId
()
///return@buildOutgoingUniPacket
writeProtoBuf
(
MsgSvc
.
PbSendMsgReq
.
serializer
(),
MsgSvc
.
PbSendMsgReq
(
...
...
@@ -317,12 +376,14 @@ internal class MessageSvc {
elems
=
message
.
toRichTextElems
()
)
),
msgSeq
=
seq
,
msgRand
=
Random
.
nextInt
().
absoluteValue
,
msgSeq
=
client
.
atomicNextMessageSequenceId
()
,
msgRand
=
source
.
messageUid
.
toInt
()
,
syncCookie
=
EMPTY_BYTE_ARRAY
,
msgVia
=
1
)
)
message
.
addOrRemove
(
source
)
}
override
suspend
fun
ByteReadPacket
.
decode
(
bot
:
QQAndroidBot
):
Response
{
...
...
mirai-core-qqandroid/src/commonMain/kotlin/net/mamoe/mirai/qqandroid/network/protocol/packet/chat/receive/OnlinePush.kt
View file @
170418b5
...
...
@@ -19,6 +19,7 @@ import net.mamoe.mirai.contact.MemberPermission
import
net.mamoe.mirai.data.MultiPacket
import
net.mamoe.mirai.data.NoPacket
import
net.mamoe.mirai.data.Packet
import
net.mamoe.mirai.event.Event
import
net.mamoe.mirai.event.events.*
import
net.mamoe.mirai.message.GroupMessage
import
net.mamoe.mirai.qqandroid.GroupImpl
...
...
@@ -46,9 +47,18 @@ internal class OnlinePush {
/**
* 接受群消息
*/
internal
object
PbPushGroupMsg
:
IncomingPacketFactory
<
GroupMessage
?
>(
"OnlinePush.PbPushGroupMsg"
)
{
internal
object
PbPushGroupMsg
:
IncomingPacketFactory
<
Packet
?
>(
"OnlinePush.PbPushGroupMsg"
)
{
internal
class
SendGroupMessageReceipt
(
val
messageRandom
:
Int
,
val
sequenceId
:
Int
)
:
Packet
,
Event
{
override
fun
toString
():
String
{
return
"OnlinePush.PbPushGroupMsg.SendGroupMessageReceipt(messageRandom=$messageRandom, sequenceId=$sequenceId)"
}
}
@UseExperimental
(
ExperimentalStdlibApi
::
class
)
override
suspend
fun
ByteReadPacket
.
decode
(
bot
:
QQAndroidBot
,
sequenceId
:
Int
):
GroupMessage
?
{
override
suspend
fun
ByteReadPacket
.
decode
(
bot
:
QQAndroidBot
,
sequenceId
:
Int
):
Packet
?
{
// 00 00 02 E4 0A D5 05 0A 4F 08 A2 FF 8C F0 03 10 DD F1 92 B7 07 18 52 20 00 28 BC 3D 30 8C 82 AB F1 05 38 D2 80 E0 8C 80 80 80 80 02 4A 21 08 E7 C1 AD B8 02 10 01 18 BA 05 22 09 48 69 6D 31 38 38 6D 6F 65 30 06 38 02 42 05 4D 69 72 61 69 50 01 58 01 60 00 88 01 08 12 06 08 01 10 00 18 00 1A F9 04 0A F6 04 0A 26 08 00 10 87 82 AB F1 05 18 B7 B4 BF 30 20 00 28 0C 30 00 38 86 01 40 22 4A 0C E5 BE AE E8 BD AF E9 9B 85 E9 BB 91 12 E6 03 42 E3 03 12 2A 7B 34 45 31 38 35 38 32 32 2D 30 45 37 42 2D 46 38 30 46 2D 43 35 42 31 2D 33 34 34 38 38 33 37 34 44 33 39 43 7D 2E 6A 70 67 22 00 2A 04 03 00 00 00 32 60 15 36 20 39 36 6B 45 31 41 38 35 32 32 39 64 63 36 39 38 34 37 39 37 37 62 20 20 20 20 20 20 35 30 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 7B 34 45 31 38 35 38 32 32 2D 30 45 37 42 2D 46 38 30 46 2D 43 35 42 31 2D 33 34 34 38 38 33 37 34 44 33 39 43 7D 2E 6A 70 67 31 32 31 32 41 38 C6 BB 8A A9 08 40 FB AE 9E C2 09 48 50 50 41 5A 00 60 01 6A 10 4E 18 58 22 0E 7B F8 0F C5 B1 34 48 83 74 D3 9C 72 59 2F 67 63 68 61 74 70 69 63 5F 6E 65 77 2F 31 30 34 30 34 30 30 32 39 30 2F 36 35 35 30 35 37 31 32 37 2D 32 32 33 33 36 33 38 33 34 32 2D 34 45 31 38 35 38 32 32 30 45 37 42 46 38 30 46 43 35 42 31 33 34 34 38 38 33 37 34 44 33 39 43 2F 31 39 38 3F 74 65 72 6D 3D 32 82 01 57 2F 67 63 68 61 74 70 69 63 5F 6E 65 77 2F 31 30 34 30 34 30 30 32 39 30 2F 36 35 35 30 35 37 31 32 37 2D 32 32 33 33 36 33 38 33 34 32 2D 34 45 31 38 35 38 32 32 30 45 37 42 46 38 30 46 43 35 42 31 33 34 34 38 38 33 37 34 44 33 39 43 2F 30 3F 74 65 72 6D 3D 32 B0 01 4D B8 01 2E C8 01 FF 05 D8 01 4D E0 01 2E FA 01 59 2F 67 63 68 61 74 70 69 63 5F 6E 65 77 2F 31 30 34 30 34 30 30 32 39 30 2F 36 35 35 30 35 37 31 32 37 2D 32 32 33 33 36 33 38 33 34 32 2D 34 45 31 38 35 38 32 32 30 45 37 42 46 38 30 46 43 35 42 31 33 34 34 38 38 33 37 34 44 33 39 43 2F 34 30 30 3F 74 65 72 6D 3D 32 80 02 4D 88 02 2E 12 45 AA 02 42 50 03 60 00 68 00 9A 01 39 08 09 20 BF 50 80 01 01 C8 01 00 F0 01 00 F8 01 00 90 02 00 98 03 00 A0 03 20 B0 03 00 C0 03 00 D0 03 00 E8 03 00 8A 04 04 08 02 08 01 90 04 80 80 80 10 B8 04 00 C0 04 00 12 06 4A 04 08 00 40 01 12 14 82 01 11 0A 09 48 69 6D 31 38 38 6D 6F 65 18 06 20 08 28 03 10 8A CA 9D A1 07 1A 00
if
(!
bot
.
firstLoginSucceed
)
return
null
val
pbPushMsg
=
readProtoBuf
(
MsgOnlinePush
.
PbPushMsg
.
serializer
())
...
...
@@ -56,7 +66,7 @@ internal class OnlinePush {
val
extraInfo
:
ImMsgBody
.
ExtraInfo
?
=
pbPushMsg
.
msg
.
msgBody
.
richText
.
elems
.
firstOrNull
{
it
.
extraInfo
!=
null
}
?.
extraInfo
if
(
pbPushMsg
.
msg
.
msgHead
.
fromUin
==
bot
.
uin
)
{
return
null
return
SendGroupMessageReceipt
(
pbPushMsg
.
msg
.
msgBody
.
richText
.
attr
!!
.
random
,
pbPushMsg
.
msg
.
msgHead
.
msgSeq
)
}
val
group
=
bot
.
getGroup
(
pbPushMsg
.
msg
.
msgHead
.
groupInfo
!!
.
groupCode
)
...
...
mirai-core-qqandroid/src/jvmTest/kotlin/androidPacketTests/clientToServer.kt
View file @
170418b5
...
...
@@ -107,6 +107,8 @@ fun main() {
* 顶层方法. TCP 切掉头后直接来这里
*/
fun
ByteReadPacket
.
decodeMultiClientToServerPackets
()
{
DebugLogger
.
enable
()
PacketLogger
.
enable
()
println
(
"=======================处理客户端到服务器======================="
)
var
count
=
0
while
(
remaining
!=
0L
)
{
...
...
mirai-core-qqandroid/src/jvmTest/kotlin/test/ProtoBufDataClassGenerator.kt
View file @
170418b5
...
...
@@ -25,7 +25,7 @@ fun main() {
println
(
File
(
"""
E:\Projects\QQAndroidFF\app\src\main\java\tencent\im\
statsvc\getonlin
e
E:\Projects\QQAndroidFF\app\src\main\java\tencent\im\
msgrevok
e
"""
.
trimIndent
()
)
.
generateUnarrangedClasses
().
toMutableList
().
arrangeClasses
().
joinToString
(
"\n\n"
)
...
...
mirai-core/src/commonMain/kotlin/net.mamoe.mirai/Bot.kt
View file @
170418b5
...
...
@@ -84,7 +84,7 @@ abstract class Bot : CoroutineScope {
*/
@MiraiExperimentalAPI
(
"还未支持"
)
val
nick
:
String
get
()
=
TODO
(
"bot 昵称获取"
)
get
()
=
""
//
TODO("bot 昵称获取")
/**
* 日志记录器
...
...
@@ -175,8 +175,6 @@ abstract class Bot : CoroutineScope {
*/
abstract
suspend
fun
queryGroupMemberList
(
groupUin
:
Long
,
groupCode
:
Long
,
ownerId
:
Long
):
Sequence
<
MemberInfo
>
// TODO 目前还不能构造群对象. 这将在以后支持
// endregion
// region network
...
...
mirai-core/src/commonMain/kotlin/net.mamoe.mirai/contact/Contact.kt
View file @
170418b5
...
...
@@ -18,6 +18,7 @@ import net.mamoe.mirai.event.events.EventCancelledException
import
net.mamoe.mirai.event.events.ImageUploadEvent
import
net.mamoe.mirai.event.events.MessageSendEvent.FriendMessageSendEvent
import
net.mamoe.mirai.event.events.MessageSendEvent.GroupMessageSendEvent
import
net.mamoe.mirai.message.MessageReceipt
import
net.mamoe.mirai.message.data.*
import
net.mamoe.mirai.utils.ExternalImage
import
net.mamoe.mirai.utils.WeakRefProperty
...
...
@@ -40,19 +41,24 @@ interface Contact : CoroutineScope {
*
* 对于 [QQ], `uin` 与 `id` 是相同的意思.
* 对于 [Group], `groupCode` 与 `id` 是相同的意思.
*
* @see QQ.id
* @see Group.id
*/
val
id
:
Long
/**
* 向这个对象发送消息.
* 向这个对象发送消息.
发送成功后 [message] 中会添加 [MessageSource], 此后可以 [引用回复][MessageReceipt.quote](仅群聊)或 [撤回][MessageReceipt.recall] 这条消息.
*
* @see FriendMessageSendEvent 发送好友信息事件, cancellable
* @see GroupMessageSendEvent 发送群消息事件. cancellable
*
* @throws EventCancelledException 当发送消息事件被取消
* @throws IllegalStateException 发送群消息时若 [Bot] 被禁言抛出
*
* @return 消息回执. 可 [引用回复][MessageReceipt.quote](仅群聊)或 [撤回][MessageReceipt.recall] 这条消息.
*/
suspend
fun
sendMessage
(
message
:
MessageChain
)
suspend
fun
sendMessage
(
message
:
MessageChain
)
:
MessageReceipt
<
out
Contact
>
/**
* 上传一个图片以备发送.
...
...
@@ -88,4 +94,4 @@ interface Contact : CoroutineScope {
suspend
inline
fun
Contact
.
sendMessage
(
message
:
Message
)
=
sendMessage
(
message
.
toChain
())
suspend
inline
fun
Contact
.
sendMessage
(
plain
:
String
)
=
sendMessage
(
plain
.
singleChain
())
\ No newline at end of file
suspend
inline
fun
Contact
.
sendMessage
(
plain
:
String
)
=
sendMessage
(
plain
.
toMessage
())
\ No newline at end of file
mirai-core/src/commonMain/kotlin/net.mamoe.mirai/contact/ContactList.kt
View file @
170418b5
...
...
@@ -40,6 +40,15 @@ class ContactList<C : Contact>(@MiraiInternalAPI val delegate: LockFreeLinkedLis
fun
containsAll
(
elements
:
Collection
<
C
>):
Boolean
=
elements
.
all
{
contains
(
it
)
}
fun
isEmpty
():
Boolean
=
delegate
.
isEmpty
()
inline
fun
forEach
(
block
:
(
C
)
->
Unit
)
=
delegate
.
forEach
(
block
)
fun
first
():
C
{
forEach
{
return
it
}
throw
NoSuchElementException
()
}
fun
firstOrNull
():
C
?
{
forEach
{
return
it
}
return
null
}
override
fun
toString
():
String
=
delegate
.
joinToString
(
separator
=
", "
,
prefix
=
"ContactList("
,
postfix
=
")"
)
}
...
...
mirai-core/src/commonMain/kotlin/net.mamoe.mirai/contact/Group.kt
View file @
170418b5
...
...
@@ -11,11 +11,22 @@
package
net.mamoe.mirai.contact
import
kotlinx.coroutines.CoroutineName
import
kotlinx.coroutines.CoroutineScope
import
kotlinx.coroutines.Job
import
kotlinx.coroutines.launch
import
net.mamoe.mirai.Bot
import
net.mamoe.mirai.data.MemberInfo
import
net.mamoe.mirai.event.events.*
import
net.mamoe.mirai.event.events.MessageSendEvent.FriendMessageSendEvent
import
net.mamoe.mirai.event.events.MessageSendEvent.GroupMessageSendEvent
import
net.mamoe.mirai.message.MessageReceipt
import
net.mamoe.mirai.message.data.MessageChain
import
net.mamoe.mirai.message.data.MessageSource
import
net.mamoe.mirai.message.data.quote
import
net.mamoe.mirai.utils.MiraiExperimentalAPI
import
kotlin.coroutines.CoroutineContext
import
kotlin.coroutines.EmptyCoroutineContext
import
kotlin.jvm.JvmName
/**
...
...
@@ -83,10 +94,18 @@ interface Group : Contact, CoroutineScope {
override
val
id
:
Long
/**
* 群主
* 群主.
*
* @return 若机器人是群主, 返回 [botAsMember]. 否则返回相应的成员
*/
val
owner
:
Member
/**
* [Bot] 在群内的 [Member] 实例
*/
@MiraiExperimentalAPI
val
botAsMember
:
Member
/**
* 机器人被禁言还剩余多少秒
*
...
...
@@ -133,6 +152,17 @@ interface Group : Contact, CoroutineScope {
@MiraiExperimentalAPI
(
"还未支持"
)
suspend
fun
quit
():
Boolean
/**
* 撤回这条消息.
*
* [Bot] 撤回自己的消息不需要权限.
* [Bot] 撤回群员的消息需要管理员权限.
*
* @throws PermissionDeniedException 当 [Bot] 无权限操作时
* @see Group.recall (扩展函数) 接受参数 [MessageChain]
*/
suspend
fun
recall
(
source
:
MessageSource
)
/**
* 构造一个 [Member].
* 非特殊情况请不要使用这个函数. 优先使用 [get].
...
...
@@ -142,6 +172,19 @@ interface Group : Contact, CoroutineScope {
@JvmName
(
"newMember"
)
fun
Member
(
memberInfo
:
MemberInfo
):
Member
/**
* 向这个对象发送消息. 发送成功后 [message] 中会添加 [MessageSource], 此后可以 [引用回复][quote] 或 [撤回][recall] 这条消息.
*
* @see FriendMessageSendEvent 发送好友信息事件, cancellable
* @see GroupMessageSendEvent 发送群消息事件. cancellable
*
* @throws EventCancelledException 当发送消息事件被取消
* @throws IllegalStateException 发送群消息时若 [Bot] 被禁言抛出
*
* @return 消息回执. 可进行撤回 ([MessageReceipt.recall])
*/
override
suspend
fun
sendMessage
(
message
:
MessageChain
):
MessageReceipt
<
Group
>
companion
object
{
/**
...
...
@@ -184,7 +227,52 @@ interface Group : Contact, CoroutineScope {
fun
toFullString
():
String
=
"Group(id=${this.id}, name=$name, owner=${owner.id}, members=${members.idContentString})"
}
/**
* 撤回这条消息.
*
* [Bot] 撤回自己的消息不需要权限.
* [Bot] 撤回群员的消息需要管理员权限.
*
* @throws PermissionDeniedException 当 [Bot] 无权限操作时
* @see Group.recall
*/
suspend
inline
fun
Group
.
recall
(
message
:
MessageChain
)
=
this
.
recall
(
message
[
MessageSource
])
/**
* 在一段时间后撤回这条消息.
*
* @param millis 延迟的时间, 单位为毫秒
* @param coroutineContext 额外的 [CoroutineContext]
* @see recall
*/
fun
Group
.
recallIn
(
message
:
MessageSource
,
millis
:
Long
,
coroutineContext
:
CoroutineContext
=
EmptyCoroutineContext
):
Job
=
this
.
launch
(
coroutineContext
+
CoroutineName
(
"MessageRecall"
))
{
kotlinx
.
coroutines
.
delay
(
millis
)
recall
(
message
)
}
/**
* 在一段时间后撤回这条消息.
*
* @param millis 延迟的时间, 单位为毫秒
* @param coroutineContext 额外的 [CoroutineContext]
* @see recall
*/
fun
Group
.
recallIn
(
message
:
MessageChain
,
millis
:
Long
,
coroutineContext
:
CoroutineContext
=
EmptyCoroutineContext
):
Job
=
this
.
launch
(
coroutineContext
+
CoroutineName
(
"MessageRecall"
))
{
kotlinx
.
coroutines
.
delay
(
millis
)
recall
(
message
)
}
/**
* 返回机器人是否正在被禁言
*
* @see Group.botMuteRemaining 剩余禁言时间
*/
val
Group
.
isBotMuted
:
Boolean
get
()
=
this
.
botMuteRemaining
!=
0
mirai-core/src/commonMain/kotlin/net.mamoe.mirai/contact/QQ.kt
View file @
170418b5
...
...
@@ -16,6 +16,12 @@ import net.mamoe.mirai.Bot
import
net.mamoe.mirai.data.FriendNameRemark
import
net.mamoe.mirai.data.PreviousNameList
import
net.mamoe.mirai.data.Profile
import
net.mamoe.mirai.event.events.EventCancelledException
import
net.mamoe.mirai.event.events.MessageSendEvent.FriendMessageSendEvent
import
net.mamoe.mirai.event.events.MessageSendEvent.GroupMessageSendEvent
import
net.mamoe.mirai.message.MessageReceipt
import
net.mamoe.mirai.message.data.MessageChain
import
net.mamoe.mirai.message.data.MessageSource
import
net.mamoe.mirai.utils.MiraiExperimentalAPI
/**
...
...
@@ -68,4 +74,17 @@ interface QQ : Contact, CoroutineScope {
*/
@MiraiExperimentalAPI
(
"还未支持"
)
suspend
fun
queryRemark
():
FriendNameRemark
/**
* 向这个对象发送消息. 发送成功后 [message] 中会添加 [MessageSource], 此后可以 [撤回][recall] 这条消息.
*
* @see FriendMessageSendEvent 发送好友信息事件, cancellable
* @see GroupMessageSendEvent 发送群消息事件. cancellable
*
* @throws EventCancelledException 当发送消息事件被取消
* @throws IllegalStateException 发送群消息时若 [Bot] 被禁言抛出
*
* @return 消息回执. 可进行撤回 ([MessageReceipt.recall])
*/
override
suspend
fun
sendMessage
(
message
:
MessageChain
):
MessageReceipt
<
QQ
>
}
\ No newline at end of file
mirai-core/src/commonMain/kotlin/net.mamoe.mirai/data/GroupInfo.kt
View file @
170418b5
...
...
@@ -62,4 +62,15 @@ interface GroupInfo {
* 机器人被禁言还剩时间, 秒.
*/
val
botMuteRemaining
:
Int
/*
/**
* 机器人的头衔
*/
val botSpecialTitle: String
/**
* 机器人的昵称
*/
val botNameCard: String*/
}
\ No newline at end of file
mirai-core/src/commonMain/kotlin/net.mamoe.mirai/event/
Subscribable
.kt
→
mirai-core/src/commonMain/kotlin/net.mamoe.mirai/event/
Event
.kt
View file @
170418b5
File moved
mirai-core/src/commonMain/kotlin/net.mamoe.mirai/event/linear.kt
0 → 100644
View file @
170418b5
/*
* Copyright 2020 Mamoe Technologies and contributors.
*
* 此源代码的使用受 GNU AFFERO GENERAL PUBLIC LICENSE version 3 许可证的约束, 可以在以下链接找到该许可证.
* Use of this source code is governed by the GNU AGPLv3 license that can be found through the following link.
*
* https://github.com/mamoe/mirai/blob/master/LICENSE
*/
package
net.mamoe.mirai.event
mirai-core/src/commonMain/kotlin/net.mamoe.mirai/event/
MessageSubscriber
s.kt
→
mirai-core/src/commonMain/kotlin/net.mamoe.mirai/event/
subscribeMessage
s.kt
View file @
170418b5
File moved
mirai-core/src/commonMain/kotlin/net.mamoe.mirai/event/
Subscribers
.kt
→
mirai-core/src/commonMain/kotlin/net.mamoe.mirai/event/
subscriber
.kt
View file @
170418b5
File moved
mirai-core/src/commonMain/kotlin/net.mamoe.mirai/message/GroupMessage.kt
View file @
170418b5
...
...
@@ -10,12 +10,11 @@
package
net.mamoe.mirai.message
import
net.mamoe.mirai.Bot
import
net.mamoe.mirai.contact.Group
import
net.mamoe.mirai.contact.Member
import
net.mamoe.mirai.contact.MemberPermission
import
net.mamoe.mirai.contact.*
import
net.mamoe.mirai.event.Event
import
net.mamoe.mirai.message.data.Message
import
net.mamoe.mirai.message.data.MessageChain
import
net.mamoe.mirai.message.data.MessageSource
import
net.mamoe.mirai.utils.getValue
import
net.mamoe.mirai.utils.unsafeWeakRef
import
kotlin.jvm.JvmName
...
...
@@ -60,6 +59,11 @@ class GroupMessage(
@JvmName
(
"reply2"
)
suspend
inline
fun
MessageChain
.
quoteReply
()
=
quoteReply
(
this
)
suspend
inline
fun
MessageChain
.
recall
()
=
group
.
recall
(
this
)
suspend
inline
fun
MessageSource
.
recall
()
=
group
.
recall
(
this
)
inline
fun
MessageSource
.
recallIn
(
delay
:
Long
)
=
group
.
recallIn
(
this
,
delay
)
inline
fun
MessageChain
.
recallIn
(
delay
:
Long
)
=
group
.
recallIn
(
this
,
delay
)
override
fun
toString
():
String
=
"GroupMessage(group=${group.id}, senderName=$senderName, sender=${sender.id}, permission=${permission.name}, message=$message)"
}
\ No newline at end of file
mirai-core/src/commonMain/kotlin/net.mamoe.mirai/message/MessagePacket.kt
View file @
170418b5
...
...
@@ -35,7 +35,7 @@ expect abstract class MessagePacket<TSender : QQ, TSubject : Contact>(bot: Bot)
/**
* 仅内部使用, 请使用 [MessagePacket]
*/
// Tips: 在 IntelliJ 中 (左侧边栏) 打开 `Structure`, 可查看类结构
@Suppress
(
"NOTHING_TO_INLINE"
)
@Suppress
(
"NOTHING_TO_INLINE"
,
"UNCHECKED_CAST"
)
@MiraiInternalAPI
abstract
class
MessagePacketBase
<
TSender
:
QQ
,
TSubject
:
Contact
>(
_bot
:
Bot
)
:
Packet
,
BotEvent
{
/**
...
...
@@ -73,20 +73,19 @@ abstract class MessagePacketBase<TSender : QQ, TSubject : Contact>(_bot: Bot) :
* 对于好友消息事件, 这个方法将会给好友 ([subject]) 发送消息
* 对于群消息事件, 这个方法将会给群 ([subject]) 发送消息
*/
suspend
inline
fun
reply
(
message
:
MessageChain
)
=
subject
.
sendMessage
(
message
)
suspend
inline
fun
reply
(
message
:
MessageChain
)
:
MessageReceipt
<
TSubject
>
=
subject
.
sendMessage
(
message
)
as
MessageReceipt
<
TSubject
>
suspend
inline
fun
reply
(
message
:
Message
)
=
subject
.
sendMessage
(
message
.
toChain
())
suspend
inline
fun
reply
(
plain
:
String
)
=
subject
.
sendMessage
(
plain
.
singleChain
())
suspend
inline
fun
reply
(
message
:
Message
)
:
MessageReceipt
<
TSubject
>
=
subject
.
sendMessage
(
message
.
toChain
())
as
MessageReceipt
<
TSubject
>
suspend
inline
fun
reply
(
plain
:
String
)
:
MessageReceipt
<
TSubject
>
=
subject
.
sendMessage
(
plain
.
toMessage
().
toChain
())
as
MessageReceipt
<
TSubject
>
@JvmName
(
"reply1"
)
suspend
inline
fun
String
.
reply
()
=
reply
(
this
)
suspend
inline
fun
String
.
reply
()
:
MessageReceipt
<
TSubject
>
=
reply
(
this
)
@JvmName
(
"reply1"
)
suspend
inline
fun
Message
.
reply
()
=
reply
(
this
)
suspend
inline
fun
Message
.
reply
()
:
MessageReceipt
<
TSubject
>
=
reply
(
this
)
@JvmName
(
"reply1"
)
suspend
inline
fun
MessageChain
.
reply
()
=
reply
(
this
)
suspend
inline
fun
MessageChain
.
reply
():
MessageReceipt
<
TSubject
>
=
reply
(
this
)
// endregion
// region
...
...
@@ -113,9 +112,9 @@ abstract class MessagePacketBase<TSender : QQ, TSubject : Contact>(_bot: Bot) :
/**
* 创建 @ 这个账号的消息. 当且仅当消息为群消息时可用. 否则将会抛出 [IllegalArgumentException]
*/
inline
fun
QQ
.
at
():
At
=
At
(
this
as
?
Member
?:
error
(
"`QQ.at` can only be used in GroupMessage"
))
fun
QQ
.
at
():
At
=
At
(
this
as
?
Member
?:
error
(
"`QQ.at` can only be used in GroupMessage"
))
inline
fun
At
.
member
():
Member
=
(
this
@MessagePacketBase
as
?
GroupMessage
)
?.
group
?.
get
(
this
.
target
)
?:
error
(
"`At.member` can only be used in GroupMessage"
)
fun
At
.
member
():
Member
=
(
this
@MessagePacketBase
as
?
GroupMessage
)
?.
group
?.
get
(
this
.
target
)
?:
error
(
"`At.member` can only be used in GroupMessage"
)
// endregion
...
...
@@ -135,16 +134,4 @@ abstract class MessagePacketBase<TSender : QQ, TSubject : Contact>(_bot: Bot) :
*/
suspend
inline
fun
Image
.
download
():
ByteReadPacket
=
bot
.
run
{
download
()
}
// endregion
@Deprecated
(
message
=
"这个函数有歧义, 将在不久后删除"
,
replaceWith
=
ReplaceWith
(
"bot.getFriend(this.target)"
))
fun
At
.
qq
():
QQ
=
bot
.
getFriend
(
this
.
target
)
@Deprecated
(
message
=
"这个函数有歧义, 将在不久后删除"
,
replaceWith
=
ReplaceWith
(
"bot.getFriend(this.toLong())"
))
fun
Int
.
qq
():
QQ
=
bot
.
getFriend
(
this
.
coerceAtLeastOrFail
(
0
).
toLong
())
@Deprecated
(
message
=
"这个函数有歧义, 将在不久后删除"
,
replaceWith
=
ReplaceWith
(
"bot.getFriend(this)"
))
fun
Long
.
qq
():
QQ
=
bot
.
getFriend
(
this
.
coerceAtLeastOrFail
(
0
))
@Deprecated
(
message
=
"这个函数有歧义, 将在不久后删除"
,
replaceWith
=
ReplaceWith
(
"bot.getGroup(this)"
))
fun
Long
.
group
():
Group
=
bot
.
getGroup
(
this
)
}
\ No newline at end of file
mirai-core/src/commonMain/kotlin/net.mamoe.mirai/message/MessageReceipt.kt
0 → 100644
View file @
170418b5
/*
* Copyright 2020 Mamoe Technologies and contributors.
*
* 此源代码的使用受 GNU AFFERO GENERAL PUBLIC LICENSE version 3 许可证的约束, 可以在以下链接找到该许可证.
* Use of this source code is governed by the GNU AGPLv3 license that can be found through the following link.
*
* https://github.com/mamoe/mirai/blob/master/LICENSE
*/
package
net.mamoe.mirai.message
import
kotlinx.atomicfu.atomic
import
kotlinx.coroutines.Job
import
net.mamoe.mirai.Bot
import
net.mamoe.mirai.contact.*
import
net.mamoe.mirai.message.data.*
import
net.mamoe.mirai.utils.MiraiExperimentalAPI
import
net.mamoe.mirai.utils.getValue
import
net.mamoe.mirai.utils.unsafeWeakRef
/**
* 发送消息后得到的回执. 可用于撤回.
*
* 此对象持有 [Contact] 的弱引用, [Bot] 离线后将会释放引用, 届时 [target] 将无法访问.
*
* @see Group.sendMessage 发送群消息, 返回回执(此对象)
* @see QQ.sendMessage 发送群消息, 返回回执(此对象)
*/
open
class
MessageReceipt
<
C
:
Contact
>(
val
originalMessage
:
MessageChain
,
target
:
C
)
{
init
{
require
(
target
is
Group
||
target
is
QQ
)
{
"target must be either Group or QQ"
}
}
/**
* 发送目标, 为 [Group] 或 [QQ]
*/
val
target
:
C
by
target
.
unsafeWeakRef
()
private
val
_isRecalled
=
atomic
(
false
)
/**
* 撤回这条消息. [recall] 或 [recallIn] 只能被调用一次.
*
* @see Group.recall
* @throws IllegalStateException 当此消息已经被撤回或正计划撤回时
*/
@UseExperimental
(
MiraiExperimentalAPI
::
class
)
suspend
fun
recall
()
{
@Suppress
(
"BooleanLiteralArgument"
)
if
(
_isRecalled
.
compareAndSet
(
false
,
true
))
{
when
(
val
contact
=
target
)
{
is
Group
->
{
contact
.
recall
(
originalMessage
)
}
is
QQ
->
{
TODO
()
}
else
->
error
(
"Unknown contact type"
)
}
}
else
error
(
"message is already or planned to be recalled"
)
}
/**
* 撤回这条消息. [recall] 或 [recallIn] 只能被调用一次.
*
* @param millis 延迟时间, 单位为毫秒
*
* @throws IllegalStateException 当此消息已经被撤回或正计划撤回时
*/
@UseExperimental
(
MiraiExperimentalAPI
::
class
)
fun
recallIn
(
millis
:
Long
):
Job
{
@Suppress
(
"BooleanLiteralArgument"
)
if
(
_isRecalled
.
compareAndSet
(
false
,
true
))
{
when
(
val
contact
=
target
)
{
is
Group
->
{
return
contact
.
recallIn
(
originalMessage
,
millis
)
}
is
QQ
->
{
TODO
()
}
else
->
error
(
"Unknown contact type"
)
}
}
else
error
(
"message is already or planned to be recalled"
)
}
/**
* 引用这条消息. 仅群消息能被引用
*
* @see MessageChain.quote 引用一条消息
*
* @throws IllegalStateException 当此消息不是群消息时
*/
@MiraiExperimentalAPI
(
"unstable"
)
open
fun
quote
():
MessageChain
{
val
target
=
target
check
(
target
is
Group
)
{
"quote is only available for GroupMessage"
}
return
this
.
originalMessage
.
quote
(
target
.
botAsMember
)
}
/**
* 引用这条消息并回复. 仅群消息能被引用
*
* @see MessageChain.quote 引用一条消息
*
* @throws IllegalStateException 当此消息不是群消息时
*/
@MiraiExperimentalAPI
(
"unstable"
)
suspend
fun
quoteReply
(
message
:
MessageChain
)
{
target
.
sendMessage
(
this
.
quote
()
+
message
)
}
}
@MiraiExperimentalAPI
(
"unstable"
)
suspend
inline
fun
MessageReceipt
<
out
Contact
>.
quoteReply
(
message
:
Message
)
{
return
this
.
quoteReply
(
message
.
toChain
())
}
@MiraiExperimentalAPI
(
"unstable"
)
suspend
inline
fun
MessageReceipt
<
out
Contact
>.
quoteReply
(
message
:
String
)
{
return
this
.
quoteReply
(
message
.
toMessage
().
toChain
())
}
mirai-core/src/commonMain/kotlin/net.mamoe.mirai/message/data/AtAll.kt
View file @
170418b5
...
...
@@ -16,7 +16,9 @@ import kotlin.jvm.JvmMultifileClass
import
kotlin.jvm.JvmName
/**
* "@全体成员"
* "@全体成员".
*
* 非会员每天只能发送 10 次 [AtAll]. 超出部分会被以普通文字看待.
*
* @see At at 单个群成员
*/
...
...
@@ -26,7 +28,7 @@ object AtAll : Message, Message.Key<AtAll> {
// 自动为消息补充 " "
override
fun
followedBy
(
tail
:
Message
):
MessageChain
{
if
(
tail
is
PlainText
&&
tail
.
stringValue
.
startsWith
(
' '
))
{
if
(
tail
is
PlainText
&&
tail
.
stringValue
.
startsWith
(
' '
))
{
return
super
.
followedBy
(
tail
)
}
return
super
.
followedBy
(
PlainText
(
" "
))
+
tail
...
...
mirai-core/src/commonMain/kotlin/net.mamoe.mirai/message/data/MessageChain.kt
View file @
170418b5
...
...
@@ -13,9 +13,6 @@
package
net.mamoe.mirai.message.data
import
net.mamoe.mirai.message.data.NullMessageChain.toString
import
net.mamoe.mirai.utils.MiraiExperimentalAPI
import
kotlin.contracts.ExperimentalContracts
import
kotlin.contracts.contract
import
kotlin.js.JsName
import
kotlin.jvm.JvmMultifileClass
import
kotlin.jvm.JvmName
...
...
@@ -68,6 +65,15 @@ interface MessageChain : Message, MutableList<Message> {
}
}
/**
* 先删除同类型的消息, 再添加 [message]
*/
fun
<
T
:
Message
>
MessageChain
.
addOrRemove
(
message
:
T
)
{
val
clazz
=
message
::
class
this.remove
All
{
clazz
.
isInstance
(
it
)
}
this
.
add
(
message
)
}
/**
* 遍历每一个有内容的消息, 即 [At], [AtAll], [PlainText], [Image], [Face], [XMLMessage]
*/
...
...
@@ -133,37 +139,23 @@ fun MessageChain(vararg messages: Message): MessageChain =
else
MessageChainImpl
(
messages
.
toMutableList
())
/**
* 构造 [MessageChain]
* 构造 [MessageChain] 的快速途径 (无 [Array] 创建)
* 若仅提供一个参数, 请考虑使用 [Message.toChain] 以优化性能
*/
@JvmName
(
"newChain"
)
@JsName
(
"newChain"
)
@Suppress
(
"FunctionName"
)
fun
MessageChain
(
message
s
:
Iterable
<
Message
>
):
MessageChain
=
MessageChainImpl
(
m
essages
.
toMutableList
(
))
fun
MessageChain
(
message
:
Message
):
MessageChain
=
MessageChainImpl
(
m
utableListOf
(
message
))
/**
* 构造单元素的不可修改的 [MessageChain]. 内部类实现为 [SingleMessageChain]
*
* 参数 [delegate] 不能为 [MessageChain] 的实例, 否则将会抛出异常.
* 使用 [Message.toChain] 将帮助提前处理这个问题.
*
* @param delegate 所构造的单元素 [MessageChain] 代表的 [Message]
* @throws IllegalArgumentException 当 [delegate] 为 [MessageChain] 的实例时
*
* @see Message.toChain receiver 模式
* 构造 [MessageChain]
*/
@JvmName
(
"new
SingleMessage
Chain"
)
@JvmName
(
"newChain"
)
@JsName
(
"newChain"
)
@MiraiExperimentalAPI
@UseExperimental
(
ExperimentalContracts
::
class
)
@Suppress
(
"FunctionName"
)
fun
SingleMessageChain
(
delegate
:
Message
):
MessageChain
{
contract
{
returns
()
implies
(
delegate
!
is
MessageChain
)
}
require
(
delegate
!
is
MessageChain
)
{
"delegate for SingleMessageChain should not be any instance of MessageChain"
}
return
SingleMessageChainImpl
(
delegate
)
}
fun
MessageChain
(
messages
:
Iterable
<
Message
>):
MessageChain
=
MessageChainImpl
(
messages
.
toMutableList
())
/**
...
...
@@ -387,97 +379,3 @@ internal inline class MessageChainImpl constructor(
// endregion
}
/**
* 单个成员的不可修改的 [MessageChain].
*
* 在连接时将会把它当做一个普通 [Message] 看待, 但它不能被 [plusAssign]
*/
@PublishedApi
internal
inline
class
SingleMessageChainImpl
(
private
val
delegate
:
Message
)
:
Message
,
MutableList
<
Message
>,
MessageChain
{
// region Message override
override
operator
fun
contains
(
sub
:
String
):
Boolean
=
delegate
.
contains
(
sub
)
override
fun
followedBy
(
tail
:
Message
):
MessageChain
{
require
(
tail
!
is
SingleOnly
)
{
"SingleOnly Message cannot follow another message"
}
return
if
(
tail
is
MessageChain
)
tail
.
apply
{
followedBy
(
delegate
)
}
else
MessageChain
(
delegate
,
tail
)
}
override
fun
plusAssign
(
message
:
Message
)
=
throw
UnsupportedOperationException
(
"SingleMessageChainImpl cannot be plusAssigned"
)
override
fun
toString
():
String
=
delegate
.
toString
()
// endregion
// region MutableList override
override
fun
containsAll
(
elements
:
Collection
<
Message
>):
Boolean
=
elements
.
all
{
it
==
delegate
}
override
operator
fun
get
(
index
:
Int
):
Message
=
if
(
index
==
0
)
delegate
else
throw
NoSuchElementException
()
override
fun
indexOf
(
element
:
Message
):
Int
=
if
(
delegate
==
element
)
0
else
-
1
override
fun
isEmpty
():
Boolean
=
false
override
fun
lastIndexOf
(
element
:
Message
):
Int
=
if
(
delegate
==
element
)
0
else
-
1
override
fun
add
(
element
:
Message
):
Boolean
=
throw
UnsupportedOperationException
()
override
fun
add
(
index
:
Int
,
element
:
Message
)
=
throw
UnsupportedOperationException
()
override
fun
addAll
(
index
:
Int
,
elements
:
Collection
<
Message
>):
Boolean
=
throw
UnsupportedOperationException
()
override
fun
addAll
(
elements
:
Collection
<
Message
>):
Boolean
=
throw
UnsupportedOperationException
()
override
fun
clear
()
=
throw
UnsupportedOperationException
()
override
fun
listIterator
():
MutableListIterator
<
Message
>
=
object
:
MutableListIterator
<
Message
>
{
private
var
hasNext
=
true
override
fun
hasPrevious
():
Boolean
=
!
hasNext
override
fun
nextIndex
():
Int
=
if
(
hasNext
)
0
else
-
1
override
fun
previous
():
Message
=
if
(
hasPrevious
())
{
hasNext
=
true
delegate
}
else
throw
NoSuchElementException
()
override
fun
previousIndex
():
Int
=
if
(!
hasNext
)
0
else
-
1
override
fun
add
(
element
:
Message
)
=
throw
UnsupportedOperationException
()
override
fun
hasNext
():
Boolean
=
hasNext
override
fun
next
():
Message
=
if
(
hasNext
)
{
hasNext
=
false
delegate
}
else
throw
NoSuchElementException
()
override
fun
remove
()
=
throw
UnsupportedOperationException
()
override
fun
set
(
element
:
Message
)
=
throw
UnsupportedOperationException
()
}
override
fun
listIterator
(
index
:
Int
):
MutableListIterator
<
Message
>
=
if
(
index
==
0
)
listIterator
()
else
throw
UnsupportedOperationException
()
override
fun
remove
(
element
:
Message
):
Boolean
=
throw
UnsupportedOperationException
()
override
fun
removeAll
(
elements
:
Collection
<
Message
>):
Boolean
=
throw
UnsupportedOperationException
()
override
fun
removeAt
(
index
:
Int
):
Message
=
throw
UnsupportedOperationException
()
override
fun
retainAll
(
elements
:
Collection
<
Message
>):
Boolean
=
throw
UnsupportedOperationException
()
override
fun
set
(
index
:
Int
,
element
:
Message
):
Message
=
throw
UnsupportedOperationException
()
override
fun
subList
(
fromIndex
:
Int
,
toIndex
:
Int
):
MutableList
<
Message
>
{
return
if
(
fromIndex
==
0
)
when
(
toIndex
)
{
1
->
mutableListOf
<
Message
>(
this
)
0
->
mutableListOf
()
else
->
throw
UnsupportedOperationException
()
}
else
throw
UnsupportedOperationException
()
}
override
fun
iterator
():
MutableIterator
<
Message
>
=
object
:
MutableIterator
<
Message
>
{
private
var
hasNext
=
true
override
fun
hasNext
():
Boolean
=
hasNext
override
fun
next
():
Message
=
if
(
hasNext
)
{
hasNext
=
false
delegate
}
else
throw
NoSuchElementException
()
override
fun
remove
()
=
throw
UnsupportedOperationException
()
}
override
operator
fun
contains
(
element
:
Message
):
Boolean
=
element
==
delegate
override
val
size
:
Int
get
()
=
1
// endregion
}
\ No newline at end of file
mirai-core/src/commonMain/kotlin/net.mamoe.mirai/message/data/MessageSource.kt
View file @
170418b5
...
...
@@ -26,6 +26,18 @@ import kotlin.jvm.JvmName
interface
MessageSource
:
Message
{
companion
object
Key
:
Message
.
Key
<
MessageSource
>
/**
* 序列号. 若是机器人发出去的消息, 请先 [确保 sequenceId 可用][ensureSequenceIdAvailable]
*/
val
sequenceId
:
Int
/**
* 等待 [sequenceId] 获取, 确保其可用.
*
* 若原消息发送失败, 这个方法会等待最多 3 秒随后抛出 [IllegalStateException]
*/
suspend
fun
ensureSequenceIdAvailable
()
/**
* 实际上是个随机数, 但服务器确实是用它当做 uid
*/
...
...
@@ -42,7 +54,7 @@ interface MessageSource : Message {
val
senderId
:
Long
/**
* 群号码
* 群号码
, 为 0 时则来自好友消息
*/
val
groupId
:
Long
...
...
mirai-core/src/commonMain/kotlin/net.mamoe.mirai/message/data/PlainText.kt
View file @
170418b5
...
...
@@ -38,15 +38,4 @@ inline class PlainText(val stringValue: String) : Message {
* 构造 [PlainText]
*/
@Suppress
(
"NOTHING_TO_INLINE"
)
inline
fun
String
.
toMessage
():
PlainText
=
PlainText
(
this
)
/**
* 得到包含作为 [PlainText] 的 [this] 的 [MessageChain].
*
* @return 唯一成员且不可修改的 [SingleMessageChainImpl]
*
* @see SingleMessageChain
* @see SingleMessageChainImpl
*/
@Suppress
(
"NOTHING_TO_INLINE"
)
inline
fun
String
.
singleChain
():
MessageChain
=
SingleMessageChainImpl
(
this
.
toMessage
())
\ No newline at end of file
inline
fun
String
.
toMessage
():
PlainText
=
PlainText
(
this
)
\ No newline at end of file
mirai-core/src/commonMain/kotlin/net.mamoe.mirai/utils/ExternalImage.kt
View file @
170418b5
...
...
@@ -51,9 +51,39 @@ class ExternalImage(
filename
:
String
):
ExternalImage
=
ExternalImage
(
width
,
height
,
md5
,
format
,
data
,
data
.
remaining
,
filename
)
fun
generateUUID
(
md5
:
ByteArray
):
String
{
fun
generateUUID
(
md5
:
ByteArray
):
String
{
return
"${md5[0..3]}-${md5[4..5]}-${md5[6..7]}-${md5[8..9]}-${md5[10..15]}"
}
fun
generateImageId
(
md5
:
ByteArray
,
imageType
:
Int
):
String
{
return
"""{${generateUUID(md5)}}.${determineFormat(imageType)}"""
}
fun
determineImageType
(
format
:
String
):
Int
{
return
when
(
format
)
{
"jpg"
->
1000
"png"
->
1001
"webp"
->
1002
"bmp"
->
1005
"gig"
->
2000
"apng"
->
2001
"sharpp"
->
1004
else
->
1000
// unsupported, just make it jpg
}
}
fun
determineFormat
(
imageType
:
Int
):
String
{
return
when
(
imageType
)
{
1000
->
"jpg"
1001
->
"png"
1002
->
"webp"
1005
->
"bmp"
2000
->
"gig"
2001
->
"apng"
1004
->
"sharpp"
else
->
"jpg"
// unsupported, just make it jpg
}
}
}
val
format
:
String
=
...
...
@@ -73,16 +103,7 @@ class ExternalImage(
* SHARPP: 1004
*/
val
imageType
:
Int
get
()
=
when
(
format
)
{
"jpg"
->
1000
"png"
->
1001
"webp"
->
1002
"bmp"
->
1005
"gig"
->
2000
"apng"
->
2001
"sharpp"
->
1004
else
->
1000
// unsupported, just make it jpg
}
get
()
=
determineImageType
(
format
)
override
fun
toString
():
String
=
"[ExternalImage(${width}x$height $format)]"
...
...
mirai-japt/src/main/java/net/mamoe/mirai/japt/BlockingContact.java
View file @
170418b5
...
...
@@ -9,6 +9,7 @@ import net.mamoe.mirai.event.events.EventCancelledException;
import
net.mamoe.mirai.event.events.ImageUploadEvent
;
import
net.mamoe.mirai.event.events.MessageSendEvent.FriendMessageSendEvent
;
import
net.mamoe.mirai.event.events.MessageSendEvent.GroupMessageSendEvent
;
import
net.mamoe.mirai.message.MessageReceipt
;
import
net.mamoe.mirai.message.data.Image
;
import
net.mamoe.mirai.message.data.Message
;
import
net.mamoe.mirai.message.data.MessageChain
;
...
...
@@ -42,8 +43,7 @@ public interface BlockingContact {
* @see FriendMessageSendEvent 发送好友信息事件, cancellable
* @see GroupMessageSendEvent 发送群消息事件. cancellable
*/
// kotlin bug
void
sendMessage
(
@NotNull
MessageChain
messages
)
throws
EventCancelledException
,
IllegalStateException
;
MessageReceipt
<?
extends
Contact
>
sendMessage
(
@NotNull
MessageChain
messages
)
throws
EventCancelledException
,
IllegalStateException
;
/**
* 向这个对象发送消息.
...
...
@@ -53,7 +53,7 @@ public interface BlockingContact {
* @see FriendMessageSendEvent 发送好友信息事件, cancellable
* @see GroupMessageSendEvent 发送群消息事件. cancellable
*/
void
sendMessage
(
@NotNull
String
message
)
throws
EventCancelledException
,
IllegalStateException
;
MessageReceipt
<?
extends
Contact
>
sendMessage
(
@NotNull
String
message
)
throws
EventCancelledException
,
IllegalStateException
;
/**
* 向这个对象发送消息.
...
...
@@ -63,7 +63,7 @@ public interface BlockingContact {
* @see FriendMessageSendEvent 发送好友信息事件, cancellable
* @see GroupMessageSendEvent 发送群消息事件. cancellable
*/
void
sendMessage
(
@NotNull
Message
message
)
throws
EventCancelledException
,
IllegalStateException
;
MessageReceipt
<?
extends
Contact
>
sendMessage
(
@NotNull
Message
message
)
throws
EventCancelledException
,
IllegalStateException
;
/**
* 上传一个图片以备发送.
...
...
mirai-japt/src/main/java/net/mamoe/mirai/japt/BlockingGroup.java
View file @
170418b5
...
...
@@ -3,6 +3,9 @@ package net.mamoe.mirai.japt;
import
net.mamoe.mirai.contact.*
;
import
net.mamoe.mirai.data.MemberInfo
;
import
net.mamoe.mirai.event.events.*
;
import
net.mamoe.mirai.message.MessageReceipt
;
import
net.mamoe.mirai.message.data.Message
;
import
net.mamoe.mirai.message.data.MessageChain
;
import
net.mamoe.mirai.utils.MiraiExperimentalAPI
;
import
org.jetbrains.annotations.NotNull
;
import
org.jetbrains.annotations.Nullable
;
...
...
@@ -152,6 +155,36 @@ public interface BlockingGroup extends BlockingContact {
@Nullable
BlockingMember
getMemberOrNull
(
long
id
);
/**
* 向这个对象发送消息.
*
* @throws EventCancelledException 当发送消息事件被取消
* @throws IllegalStateException 发送群消息时若 [Bot] 被禁言抛出
* @see MessageSendEvent.FriendMessageSendEvent 发送好友信息事件, cancellable
* @see MessageSendEvent.GroupMessageSendEvent 发送群消息事件. cancellable
*/
MessageReceipt
<
Group
>
sendMessage
(
@NotNull
MessageChain
messages
)
throws
EventCancelledException
,
IllegalStateException
;
/**
* 向这个对象发送消息.
*
* @throws EventCancelledException 当发送消息事件被取消
* @throws IllegalStateException 发送群消息时若 [Bot] 被禁言抛出
* @see MessageSendEvent.FriendMessageSendEvent 发送好友信息事件, cancellable
* @see MessageSendEvent.GroupMessageSendEvent 发送群消息事件. cancellable
*/
MessageReceipt
<
Group
>
sendMessage
(
@NotNull
String
message
)
throws
EventCancelledException
,
IllegalStateException
;
/**
* 向这个对象发送消息.
*
* @throws EventCancelledException 当发送消息事件被取消
* @throws IllegalStateException 发送群消息时若 [Bot] 被禁言抛出
* @see MessageSendEvent.FriendMessageSendEvent 发送好友信息事件, cancellable
* @see MessageSendEvent.GroupMessageSendEvent 发送群消息事件. cancellable
*/
MessageReceipt
<
Group
>
sendMessage
(
@NotNull
Message
message
)
throws
EventCancelledException
,
IllegalStateException
;
/**
* 检查此 id 的群成员是否存在
*/
...
...
mirai-japt/src/main/java/net/mamoe/mirai/japt/BlockingQQ.java
View file @
170418b5
package
net.mamoe.mirai.japt
;
import
net.mamoe.mirai.contact.QQ
;
import
net.mamoe.mirai.data.FriendNameRemark
;
import
net.mamoe.mirai.data.PreviousNameList
;
import
net.mamoe.mirai.data.Profile
;
import
net.mamoe.mirai.event.events.EventCancelledException
;
import
net.mamoe.mirai.event.events.MessageSendEvent
;
import
net.mamoe.mirai.message.MessageReceipt
;
import
net.mamoe.mirai.message.data.Message
;
import
net.mamoe.mirai.message.data.MessageChain
;
import
net.mamoe.mirai.utils.MiraiExperimentalAPI
;
import
org.jetbrains.annotations.NotNull
;
...
...
@@ -47,4 +53,35 @@ public interface BlockingQQ extends BlockingContact {
@MiraiExperimentalAPI
(
message
=
"还未支持"
)
@NotNull
FriendNameRemark
queryRemark
();
/**
* 向这个对象发送消息.
*
* @throws EventCancelledException 当发送消息事件被取消
* @throws IllegalStateException 发送群消息时若 [Bot] 被禁言抛出
* @see MessageSendEvent.FriendMessageSendEvent 发送好友信息事件, cancellable
* @see MessageSendEvent.GroupMessageSendEvent 发送群消息事件. cancellable
*/
MessageReceipt
<
QQ
>
sendMessage
(
@NotNull
MessageChain
messages
)
throws
EventCancelledException
,
IllegalStateException
;
/**
* 向这个对象发送消息.
*
* @throws EventCancelledException 当发送消息事件被取消
* @throws IllegalStateException 发送群消息时若 [Bot] 被禁言抛出
* @see MessageSendEvent.FriendMessageSendEvent 发送好友信息事件, cancellable
* @see MessageSendEvent.GroupMessageSendEvent 发送群消息事件. cancellable
*/
MessageReceipt
<
QQ
>
sendMessage
(
@NotNull
String
message
)
throws
EventCancelledException
,
IllegalStateException
;
/**
* 向这个对象发送消息.
*
* @throws EventCancelledException 当发送消息事件被取消
* @throws IllegalStateException 发送群消息时若 [Bot] 被禁言抛出
* @see MessageSendEvent.FriendMessageSendEvent 发送好友信息事件, cancellable
* @see MessageSendEvent.GroupMessageSendEvent 发送群消息事件. cancellable
*/
MessageReceipt
<
QQ
>
sendMessage
(
@NotNull
Message
message
)
throws
EventCancelledException
,
IllegalStateException
;
}
mirai-japt/src/main/kotlin/net/mamoe/mirai/japt/internal/BlockingContactsImpl.kt
View file @
170418b5
...
...
@@ -24,6 +24,7 @@ import net.mamoe.mirai.japt.BlockingBot
import
net.mamoe.mirai.japt.BlockingGroup
import
net.mamoe.mirai.japt.BlockingMember
import
net.mamoe.mirai.japt.BlockingQQ
import
net.mamoe.mirai.message.MessageReceipt
import
net.mamoe.mirai.message.data.*
import
net.mamoe.mirai.utils.ExternalImage
import
net.mamoe.mirai.utils.MiraiExperimentalAPI
...
...
@@ -35,9 +36,9 @@ internal class BlockingQQImpl(private val delegate: QQ) : BlockingQQ {
override
fun
getId
():
Long
=
delegate
.
id
override
fun
getNick
():
String
=
delegate
.
nick
override
fun
sendMessage
(
messages
:
MessageChain
)
=
runBlocking
{
delegate
.
sendMessage
(
messages
)
}
override
fun
sendMessage
(
message
:
String
)
=
runBlocking
{
delegate
.
sendMessage
(
message
.
toMessage
().
toChain
())
}
override
fun
sendMessage
(
message
:
Message
)
=
runBlocking
{
delegate
.
sendMessage
(
message
.
toChain
())
}
override
fun
sendMessage
(
messages
:
MessageChain
)
:
MessageReceipt
<
QQ
>
=
runBlocking
{
delegate
.
sendMessage
(
messages
)
}
override
fun
sendMessage
(
message
:
String
)
:
MessageReceipt
<
QQ
>
=
runBlocking
{
delegate
.
sendMessage
(
message
.
toMessage
().
toChain
())
}
override
fun
sendMessage
(
message
:
Message
)
:
MessageReceipt
<
QQ
>
=
runBlocking
{
delegate
.
sendMessage
(
message
.
toChain
())
}
override
fun
uploadImage
(
image
:
ExternalImage
):
Image
=
runBlocking
{
delegate
.
uploadImage
(
image
)
}
@MiraiExperimentalAPI
...
...
@@ -51,9 +52,9 @@ internal class BlockingQQImpl(private val delegate: QQ) : BlockingQQ {
}
internal
class
BlockingGroupImpl
(
private
val
delegate
:
Group
)
:
BlockingGroup
{
override
fun
sendMessage
(
messages
:
MessageChain
)
=
runBlocking
{
delegate
.
sendMessage
(
messages
)
}
override
fun
sendMessage
(
message
:
String
)
=
runBlocking
{
delegate
.
sendMessage
(
message
.
toMessage
().
toChain
())
}
override
fun
sendMessage
(
message
:
Message
)
=
runBlocking
{
delegate
.
sendMessage
(
message
.
toChain
())
}
override
fun
sendMessage
(
messages
:
MessageChain
)
:
MessageReceipt
<
Group
>
=
runBlocking
{
delegate
.
sendMessage
(
messages
)
}
override
fun
sendMessage
(
message
:
String
)
:
MessageReceipt
<
Group
>
=
runBlocking
{
delegate
.
sendMessage
(
message
.
toMessage
().
toChain
())
}
override
fun
sendMessage
(
message
:
Message
)
:
MessageReceipt
<
Group
>
=
runBlocking
{
delegate
.
sendMessage
(
message
.
toChain
())
}
override
fun
getOwner
():
BlockingMember
=
delegate
.
owner
.
blocking
()
@MiraiExperimentalAPI
override
fun
newMember
(
memberInfo
:
MemberInfo
):
Member
=
delegate
.
Member
(
memberInfo
)
...
...
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