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
17af6861
Commit
17af6861
authored
Feb 13, 2020
by
jiahua.liu
Browse files
Options
Browse Files
Download
Plain Diff
Merge remote-tracking branch 'origin/master'
parents
4bb9bc6d
c8f7d53e
Changes
20
Hide whitespace changes
Inline
Side-by-side
Showing
20 changed files
with
225 additions
and
131 deletions
+225
-131
CHANGELOG.md
CHANGELOG.md
+19
-4
README.md
README.md
+4
-4
gradle.properties
gradle.properties
+1
-1
mirai-core-qqandroid/src/commonMain/kotlin/net/mamoe/mirai/qqandroid/message/MessageQQA.kt
...in/kotlin/net/mamoe/mirai/qqandroid/message/MessageQQA.kt
+23
-4
mirai-core-qqandroid/src/commonMain/kotlin/net/mamoe/mirai/qqandroid/network/protocol/packet/PacketFactory.kt
.../mirai/qqandroid/network/protocol/packet/PacketFactory.kt
+6
-31
mirai-core-qqandroid/src/commonMain/kotlin/net/mamoe/mirai/qqandroid/network/protocol/packet/login/WtLogin.kt
.../mirai/qqandroid/network/protocol/packet/login/WtLogin.kt
+9
-5
mirai-core/build.gradle.kts
mirai-core/build.gradle.kts
+6
-6
mirai-core/src/commonMain/kotlin/net.mamoe.mirai/contact/Group.kt
...re/src/commonMain/kotlin/net.mamoe.mirai/contact/Group.kt
+1
-1
mirai-core/src/commonMain/kotlin/net.mamoe.mirai/event/MessageSubscribers.kt
...onMain/kotlin/net.mamoe.mirai/event/MessageSubscribers.kt
+29
-23
mirai-core/src/commonMain/kotlin/net.mamoe.mirai/event/Subscribers.kt
...rc/commonMain/kotlin/net.mamoe.mirai/event/Subscribers.kt
+26
-9
mirai-core/src/commonMain/kotlin/net.mamoe.mirai/event/events/BotEvents.kt
...mmonMain/kotlin/net.mamoe.mirai/event/events/BotEvents.kt
+2
-0
mirai-core/src/commonMain/kotlin/net.mamoe.mirai/event/events/types.kt
...c/commonMain/kotlin/net.mamoe.mirai/event/events/types.kt
+1
-1
mirai-core/src/commonMain/kotlin/net.mamoe.mirai/message/GroupMessage.kt
...commonMain/kotlin/net.mamoe.mirai/message/GroupMessage.kt
+24
-0
mirai-core/src/commonMain/kotlin/net.mamoe.mirai/message/data/At.kt
.../src/commonMain/kotlin/net.mamoe.mirai/message/data/At.kt
+5
-3
mirai-core/src/commonMain/kotlin/net.mamoe.mirai/message/data/AtAll.kt
...c/commonMain/kotlin/net.mamoe.mirai/message/data/AtAll.kt
+28
-0
mirai-core/src/commonMain/kotlin/net.mamoe.mirai/utils/BotConfiguration.kt
...mmonMain/kotlin/net.mamoe.mirai/utils/BotConfiguration.kt
+0
-20
mirai-core/src/commonMain/kotlin/net.mamoe.mirai/utils/io/DebugUtil.kt
...c/commonMain/kotlin/net.mamoe.mirai/utils/io/DebugUtil.kt
+2
-5
mirai-core/src/jvmMain/kotlin/net/mamoe/mirai/utils/PlatformUtilsJvm.kt
.../jvmMain/kotlin/net/mamoe/mirai/utils/PlatformUtilsJvm.kt
+6
-0
mirai-demos/mirai-demo-1/src/main/java/demo/subscribe/SubscribeSamples.kt
...i-demo-1/src/main/java/demo/subscribe/SubscribeSamples.kt
+31
-12
mirai-demos/mirai-demo-gentleman/src/main/kotlin/demo/gentleman/GentleImage.kt
...o-gentleman/src/main/kotlin/demo/gentleman/GentleImage.kt
+2
-2
No files found.
CHANGELOG.md
View file @
17af6861
...
@@ -2,18 +2,33 @@
...
@@ -2,18 +2,33 @@
开发版本. 频繁更新, 不保证高稳定性
开发版本. 频繁更新, 不保证高稳定性
## `0.14.0` 2020/2/13
### mirai-core
-
**支持 at 全体成员: `AtAll`**
### mirai-core-qqandroid
-
**支持 `AtAll` 的发送和解析**
-
**修复某些情况下禁言处理异常**
小优化:
-
在
`GroupMessage`
添加
`quoteReply(Message)`
, 可快速引用消息并回复
-
为
`CoroutineScope.subscribeMessages`
添加返回值. 返回 lambda 的返回值
-
在验证码无法处理时记录更多信息
-
优化
`At`
的空格处理 (自动为
`At`
之后的消息添加空格)
-
删除
`BotConfiguration`
中一些过时的设置
## `0.13.0` 2020/2/12
## `0.13.0` 2020/2/12
### mirai-core
### mirai-core
1.
修改 BotFactory, 添加
`context`
参数.
-
修改 BotFactory, 添加
`context`
参数.
2.
currentTimeMillis 减少不必要对象创建
-
currentTimeMillis 减少不必要对象创建
3.
优化无锁链表性能 (大幅提升
`addAll`
性能)
-
优化无锁链表性能 (大幅提升
`addAll`
性能)
### mirai-core-qqanroid
### mirai-core-qqanroid
安卓协议发布, 基于最新 QQ, 版本
`8.2.0`
安卓协议发布, 基于最新 QQ, 版本
`8.2.0`
支持的功能:
支持的功能:
-
登录: 密码登录. 设备锁支持, 不安全状态支持, 图片验证码支持, 滑动验证码支持.
-
登录: 密码登录. 设备锁支持, 不安全状态支持, 图片验证码支持, 滑动验证码支持.
-
消息: 文字消息, 图片消息(含表情消息), 群员 At.
-
消息: 文字消息, 图片消息(含表情消息), 群员 At
, 引用回复
.
-
列表: 群列表, 群员列表, 好友列表均已稳定.
-
列表: 群列表, 群员列表, 好友列表均已稳定.
-
群操作: 查看和修改群名, 查看和修改群属性(含全体禁言, 坦白说, 自动批准加入, 匿名聊天, 允许成员拉人), 设置和解除成员禁言, 查看和修改成员名片, 踢出成员.
-
群操作: 查看和修改群名, 查看和修改群属性(含全体禁言, 坦白说, 自动批准加入, 匿名聊天, 允许成员拉人), 设置和解除成员禁言, 查看和修改成员名片, 踢出成员.
-
消息事件: 接受群消息和好友消息并解析
-
消息事件: 接受群消息和好友消息并解析
...
...
README.md
View file @
17af6861
...
@@ -53,7 +53,7 @@ repositories{
...
@@ -53,7 +53,7 @@ repositories{
若您需要使用在跨平台项目, 则要对各个目标平台添加不同的依赖,这与 kotlin 相关跨平台库的依赖是类似的。
若您需要使用在跨平台项目, 则要对各个目标平台添加不同的依赖,这与 kotlin 相关跨平台库的依赖是类似的。
**若您只需要使用在单一平台, 则只需要添加一项该平台的依赖. 如只在 JVM 运行则只需要`-jvm`的依赖**
**若您只需要使用在单一平台, 则只需要添加一项该平台的依赖. 如只在 JVM 运行则只需要`-jvm`的依赖**
请将
`VERSION`
替换为最新的版本(如
`0.1
0.6
`
):
请将
`VERSION`
替换为最新的版本(如
`0.1
3.0
`
):
[

](https://bintray.com/him188moe/mirai/mirai-core/)
[

](https://bintray.com/him188moe/mirai/mirai-core/)
**Mirai 目前还处于实验性阶段, 我们无法保证任何稳定性, API 也可能会随时修改.**
**Mirai 目前还处于实验性阶段, 我们无法保证任何稳定性, API 也可能会随时修改.**
...
@@ -64,15 +64,15 @@ Mirai 核心由 API 模块(`mirai-core`)和协议模块组成。
...
@@ -64,15 +64,15 @@ Mirai 核心由 API 模块(`mirai-core`)和协议模块组成。
**common**
**common**
```
kotlin
```
kotlin
implementation
(
"net.mamoe:mirai-core-
timpc
-common:VERSION"
)
implementation
(
"net.mamoe:mirai-core-
qqandroid
-common:VERSION"
)
```
```
**jvm**
**jvm**
```
kotlin
```
kotlin
implementation
(
"net.mamoe:mirai-core-
timpc
-jvm:VERSION"
)
implementation
(
"net.mamoe:mirai-core-
qqandroid
-jvm:VERSION"
)
```
```
**android**
**android**
```
kotlin
```
kotlin
implementation
(
"net.mamoe:mirai-core-
timpc
-android:VERSION"
)
implementation
(
"net.mamoe:mirai-core-
qqandroid
-android:VERSION"
)
```
```
### Performance
### Performance
Android 上, Mirai 运行需使用 80M 内存.
Android 上, Mirai 运行需使用 80M 内存.
...
...
gradle.properties
View file @
17af6861
# style guide
# style guide
kotlin.code.style
=
official
kotlin.code.style
=
official
# config
# config
mirai_version
=
0.1
3
.0
mirai_version
=
0.1
4
.0
kotlin.incremental.multiplatform
=
true
kotlin.incremental.multiplatform
=
true
kotlin.parallel.tasks.in.project
=
true
kotlin.parallel.tasks.in.project
=
true
# kotlin
# kotlin
...
...
mirai-core-qqandroid/src/commonMain/kotlin/net/mamoe/mirai/qqandroid/message/MessageQQA.kt
View file @
17af6861
...
@@ -13,6 +13,7 @@ import kotlinx.io.core.readUInt
...
@@ -13,6 +13,7 @@ import kotlinx.io.core.readUInt
import
net.mamoe.mirai.message.data.*
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.ImMsgBody
import
net.mamoe.mirai.qqandroid.network.protocol.data.proto.MsgComm
import
net.mamoe.mirai.qqandroid.network.protocol.data.proto.MsgComm
import
net.mamoe.mirai.utils.MiraiDebugAPI
import
net.mamoe.mirai.utils.MiraiInternalAPI
import
net.mamoe.mirai.utils.MiraiInternalAPI
import
net.mamoe.mirai.utils.io.discardExact
import
net.mamoe.mirai.utils.io.discardExact
import
net.mamoe.mirai.utils.io.hexToBytes
import
net.mamoe.mirai.utils.io.hexToBytes
...
@@ -184,6 +185,14 @@ notOnlineImage=NotOnlineImage#2050019814 {
...
@@ -184,6 +185,14 @@ notOnlineImage=NotOnlineImage#2050019814 {
pbReserve=08 01 10 00 32 00 42 0E 5B E5 8A A8 E7 94 BB E8 A1 A8 E6 83 85 5D 50 00 78 05
pbReserve=08 01 10 00 32 00 42 0E 5B E5 8A A8 E7 94 BB E8 A1 A8 E6 83 85 5D 50 00 78 05
}
}
*/
*/
private
val
atAllData
=
ImMsgBody
.
Elem
(
text
=
ImMsgBody
.
Text
(
str
=
"@全体成员"
,
attr6Buf
=
"00 01 00 00 00 05 01 00 00 00 00 00 00"
.
hexToBytes
()
)
)
internal
fun
MessageChain
.
toRichTextElems
():
MutableList
<
ImMsgBody
.
Elem
>
{
internal
fun
MessageChain
.
toRichTextElems
():
MutableList
<
ImMsgBody
.
Elem
>
{
val
elements
=
mutableListOf
<
ImMsgBody
.
Elem
>()
val
elements
=
mutableListOf
<
ImMsgBody
.
Elem
>()
...
@@ -203,6 +212,7 @@ internal fun MessageChain.toRichTextElems(): MutableList<ImMsgBody.Elem> {
...
@@ -203,6 +212,7 @@ internal fun MessageChain.toRichTextElems(): MutableList<ImMsgBody.Elem> {
is
CustomFaceFromServer
->
elements
.
add
(
ImMsgBody
.
Elem
(
customFace
=
it
.
delegate
))
is
CustomFaceFromServer
->
elements
.
add
(
ImMsgBody
.
Elem
(
customFace
=
it
.
delegate
))
is
NotOnlineImageFromServer
->
elements
.
add
(
ImMsgBody
.
Elem
(
notOnlineImage
=
it
.
delegate
))
is
NotOnlineImageFromServer
->
elements
.
add
(
ImMsgBody
.
Elem
(
notOnlineImage
=
it
.
delegate
))
is
NotOnlineImageFromFile
->
elements
.
add
(
ImMsgBody
.
Elem
(
notOnlineImage
=
it
.
toJceData
()))
is
NotOnlineImageFromFile
->
elements
.
add
(
ImMsgBody
.
Elem
(
notOnlineImage
=
it
.
toJceData
()))
is
AtAll
->
elements
.
add
(
atAllData
)
is
QuoteReply
,
is
QuoteReply
,
is
MessageSource
->
{
is
MessageSource
->
{
...
@@ -295,7 +305,7 @@ internal fun ImMsgBody.SourceMsg.toMessageChain(): MessageChain {
...
@@ -295,7 +305,7 @@ internal fun ImMsgBody.SourceMsg.toMessageChain(): MessageChain {
}
}
@UseExperimental
(
MiraiInternalAPI
::
class
,
ExperimentalUnsignedTypes
::
class
)
@UseExperimental
(
MiraiInternalAPI
::
class
,
ExperimentalUnsignedTypes
::
class
,
MiraiDebugAPI
::
class
)
internal
fun
List
<
ImMsgBody
.
Elem
>.
joinToMessageChain
(
message
:
MessageChain
)
{
internal
fun
List
<
ImMsgBody
.
Elem
>.
joinToMessageChain
(
message
:
MessageChain
)
{
this
.
forEach
{
this
.
forEach
{
when
{
when
{
...
@@ -306,9 +316,18 @@ internal fun List<ImMsgBody.Elem>.joinToMessageChain(message: MessageChain) {
...
@@ -306,9 +316,18 @@ internal fun List<ImMsgBody.Elem>.joinToMessageChain(message: MessageChain) {
if
(
it
.
text
.
attr6Buf
.
isEmpty
())
{
if
(
it
.
text
.
attr6Buf
.
isEmpty
())
{
message
.
add
(
it
.
text
.
str
.
toMessage
())
message
.
add
(
it
.
text
.
str
.
toMessage
())
}
else
{
}
else
{
//00 01 00 00 00 0A 00 3E 03 3F A2 00 00
//00 01 00 00 00 05 01 00 00 00 00 00 00 all
val
id
=
it
.
text
.
attr6Buf
.
read
{
discardExact
(
7
);
readUInt
().
toLong
()
}
//00 01 00 00 00 0A 00 3E 03 3F A2 00 00 one
message
.
add
(
At
(
id
,
it
.
text
.
str
))
val
id
:
Long
it
.
text
.
attr6Buf
.
read
{
discardExact
(
7
)
id
=
readUInt
().
toLong
()
}
if
(
id
==
0L
){
message
.
add
(
AtAll
)
}
else
{
message
.
add
(
At
(
id
,
it
.
text
.
str
))
}
}
}
}
}
}
}
...
...
mirai-core-qqandroid/src/commonMain/kotlin/net/mamoe/mirai/qqandroid/network/protocol/packet/PacketFactory.kt
View file @
17af6861
...
@@ -175,11 +175,7 @@ internal object KnownPacketFactories {
...
@@ -175,11 +175,7 @@ internal object KnownPacketFactories {
PacketLogger
.
verbose
{
"开始处理一个包"
}
PacketLogger
.
verbose
{
"开始处理一个包"
}
PacketLogger
.
verbose
{
"flag1(0A/0B) = ${flag1.toUByte().toUHexString()}"
}
PacketLogger
.
verbose
{
"flag1(0A/0B) = ${flag1.toUByte().toUHexString()}"
}
// 00 00 05 30
// 00 00 00 0A // flag 1
// 01 // packet type. 02: sso, 01: uni
//
// 00 00 00 00 0E 31 39 39 34 37 30 31 30 32 31 40 3C 63 DC A2 8F FC E7 09 66 62 11 A3 5A B6 AB DC 6E A1 CA CF E2 0A 6F A8 6D 36 64 4E 22 4B A9 8A ED 07 7A 0A 9E F3 C7 7B 72 EF C1 C7 6E 9A 28 27 10 F8 2A 7F 37 49 B6 48 35 52 E9 CF 2A B5 F3 26 90 33 68 9B 5A 04 2A 8B F5 78 13 82 FE 3C 13 C4 F9 38 39 0E 02 4C 3D 91 0A 2A 94 3F 9F A6 52 B9 14 89 C5 D9 57 0F 96 F8 0E 7D 32 81 8E 10 DB C0 CA BE C7 3F EC D0 B1 F0 9D A2 4B 9F B3 8D E0 EB 1F 42 52 EA 5E 9E 76 E2 F4 13 9D 0E 7E 6D 0A E3 56 C3 EE 8A 80 24 DE FB 08 82 FB B7 AF CE 2A 69 16 E3 C3 79 5C C7 CD 44 BA AA 08 A2 51 0B 43 31 69 A1 12 D1 AE 48 15 AE 76 E9 AB BB D2 E0 16 03 EB 2D 47 A4 61 24 65 5E CC C5 03 B3 96 3E 7A 39 90 3D DB 63 56 2B 23 85 CE 5F 9E 04 20 45 31 79 7B BF 78 33 77 34 C1 8E 83 B3 50 88 2A 01 C0 C4 E4 BF 2D 0D B9 37 32 AB E0 BB 82 36 B1 4E 51 4B F7 07 6A 12 3E 79 EA 93 3D BD 06 4E AE 1C 49 82 17 14 00 09 59 40 A6 A9 01 56 1A 23 86 A8 33 B3 9A 70 7B 3A C1 F9 31 03 FD DB 4B 5C 7B F9 BB 43 94 65 A0 1C DA 2B 85 AA AD 7B 79 42 F2 EB 25 5E F0 DA B7 E7 AD 4B 25 02 36 BB 78 5F 83 7F F7 78 F0 99 D2 B5 A3 0C 4A 7F 0E B0 A6 C4 99 F7 9E 0B C6 4D FC F5 8D 6B 5F 35 27 36 D3 DB D0 46 C7 10 76 7D 96 91 48 EA 1C B2 B7 D7 2F D2 88 A8 4C 87 D6 A9 40 33 4C 76 C5 48 3E 32 4D C1 C3 7F 5C D9 B3 22 00 88 BE 04 82 64 A9 73 AA E1 65 1A EF 49 B4 54 74 53 FF 75 B6 E9 57 1B 89 2D 6F 2A 6A CE 23 BF 41 CB 55 B3 A0 53 87 AD A0 22 EE 6B 3F 4A 97 23 36 BF 7E 08 2D 0A 9E 2E 4B F2 2E 00 59 EC F1 21 34 45 75 DB 6B F2 EC 65 24 30 69 50 CC 45 78 00 AF C8 F6 3D 8E 03 60 CF CA A1 88 14 18 82 6F 56 58 D0 BC E0 48 FD AA 86 63 CA C1 01 63 07 16 4A 79 79 17 9D 1F E2 40 4B B6 77 6E 44 84 DE BE 02 4C 33 7A F5 2F 93 21 3E 17 62 38 81 95 E6 84 8B 7C C8 7B E2 23 FB 12 4F E8 42 5F 1D 48 92 84 B1 45 FF 69 97 3C 30 C9 09 E8 84 E8 07 0E 17 D4 A1 CC 35 D6 FE 7B D2 9A 44 8B 17 BF E7 D6 98 1D 98 D7 30 BE 55 19 A9 F4 D6 0D E8 18 80 35 85 B6 AB B9 20 32 C7 ED C6 AD A7 AE 19 48 B7 17 02 B3 45 C3 A2 B9 C9 B7 58 B5 8B 4C AF 52 AD A1 E1 62 45 AB 58 26 67 20 C7 64 AA DA 7E F3 70 8B C2 92 69 E3 3E 3E 6F 39 6F 2B 35 35 0F 00 FC 52 B5 5C 5B 73 FE F6 F5 10 55 36 7C 9A 84 FC A6 23 29 4A 75 49 7C 13 1C CA 54 A2 A2 FA 2A 63 A5 4C 9A B4 27 E8 5F 9F 23 96 B2 E7 AA E6 8B E0 E2 6A 75 8A B2 F4 E4 7E 09 E8 22 70 2A 42 8B E3 DC AD E8 A8 A2 92 71 6B A2 12 78 E1 DA CC 70 57 67 F5 B4 52 F3 B4 4C 17 AB 05 33 DA 6E 47 52 C5 B2 B7 9A D2 A8 BC 44 64 D3 26 1A 6B C6 C5 36 1C 2B 8F BD B7 27 91 3E C0 C2 FC 03 41 FE 02 D3 4B B1 E5 5F 5B 50 05 29 BD 3A 64 85 E3 8C FB 11 F2 1D 94 DB D7 78 AF AD 77 A3 9C D4 39 5D 8B EA DF 9D 08 CA 92 7C 5F D5 17 49 0E FA A1 21 1C 9F C3 88 1A DC E7 D8 82 80 85 86 32 99 15 E4 89 BA 91 2B 4B FB 87 EC 44 B4 D9 83 CC 79 77 A4 A0 D0 50 E3 4F 00 E7 DA DA 79 38 1E D8 04 86 16 CD 25 BE BA 76 E4 8C F9 86 91 69 6E C7 A0 EF 6B 44 2B C9 C3 DC 8D 2D 65 60 7A F4 37 02 D4 8F 38 D0 D5 20 30 DE A5 F5 A8 75 C7 EE 0B 0F 1B 88 C2 8A CC 6F 70 1D E4 D8 4E DD 04 A5 5B B8 04 B1 29 42 08 92 19 78 E2 26 EB 6B 07 49 DE 8A AF A3 41 72 1D E2 3C 62 0F 7E 7B DE A3 0F 71 8C 5D EC E9 96 96 45 A9 39 33 8A 87 C9 93 CE 3B 6D 75 50 21 1F 4C 03 E9 A7 AD 03 0F 5E A9 EE 60 CC EA 05 4F DF E1 B1 13 A6 7D C7 B9 37 58 53 3B 06 1A AD 98 E5 06 D9 74 2A B1 96 75 DE A6 B7 89 25 53 2A A3 07 B6 70 C6 86 1F 59 EB 53 08 57 6E 86 D7 A1 5C DB 26 D7 86 3E 97 BB FD 6A 0A 4C E1 81 B9 4C C1 A0 49 89 57 29 E0 CD 79 6F 0A 46 C1 C6 62 75 49 C6 9A B9 22 75 EE 10 C7 56 E6 D5 DE 4D EC 89 5A 6F AC 60 0F B3 CC 37 9E F2 BE 49 A7 77 3C 05 AE 92 66 C8 BE 16 E5 35 17 24 18 A5 CE B8 BB AE CD 88 DE 01 53 40 84 E0 06 C6 77 96 09 DF D7 76 3B CA C9 B5 B2 91 95 07 54 6F 51 EB 12 58 16 8A AF C3 E3 B9 4A EC 25 A5 D1 19 59 72 F5 E3 4F 7C 40 B2 D0 4E 9F 50 13 FB 86 C3 6A 88 32 5B 67 EC 4F 0E 0B 31 F8 0C 02 6C CE 8D 50 55 A2 B3 57 73 7C 78 D3 43 1F 48 33 51 E7 0A D0 6D 46 71 4A AD 66 50 F9 96 11 4F A5 5B 3C A0 3E 46 D2 CB 3B A1 03 84 9C 8E 4E 2D 83 69 2E 17 9B F8 36 63 F1 93 CA F9 32 57 2B AB 4E 14 A3 5A F1 39 B0 3F 0F 99 CC 9B FB 7E BC 0A AA C9 65 3C C8 B4 B0 1F
val
flag2
=
readByte
().
toInt
()
val
flag2
=
readByte
().
toInt
()
PacketLogger
.
verbose
{
PacketLogger
.
verbose
{
"包类型(flag2) = $flag2. (可能是 ${when (flag2) {
"包类型(flag2) = $flag2. (可能是 ${when (flag2) {
...
@@ -195,19 +191,10 @@ internal object KnownPacketFactories {
...
@@ -195,19 +191,10 @@ internal object KnownPacketFactories {
readString
(
readInt
()
-
4
)
// uinAccount
readString
(
readInt
()
-
4
)
// uinAccount
//debugPrint("remaining")
/* receive
* 00 00 00 0A
* 00
* 00
* 00 00 00 05 30 // uin
*/
ByteArrayPool
.
useInstance
{
data
->
ByteArrayPool
.
useInstance
{
data
->
val
size
=
this
.
readAvailable
(
data
)
val
size
=
this
.
readAvailable
(
data
)
kotlin
.
runCatching
{
kotlin
.
runCatching
{
// 快速解密
when
(
flag2
)
{
when
(
flag2
)
{
2
->
data
.
decryptBy
(
DECRYPTER_16_ZERO
,
size
).
also
{
PacketLogger
.
verbose
{
"成功使用 16 zero 解密"
}
}
2
->
data
.
decryptBy
(
DECRYPTER_16_ZERO
,
size
).
also
{
PacketLogger
.
verbose
{
"成功使用 16 zero 解密"
}
}
1
->
data
.
decryptBy
(
bot
.
client
.
wLoginSigInfo
.
d2Key
,
size
).
also
{
PacketLogger
.
verbose
{
"成功使用 d2Key 解密"
}
}
1
->
data
.
decryptBy
(
bot
.
client
.
wLoginSigInfo
.
d2Key
,
size
).
also
{
PacketLogger
.
verbose
{
"成功使用 d2Key 解密"
}
}
...
@@ -215,20 +202,17 @@ internal object KnownPacketFactories {
...
@@ -215,20 +202,17 @@ internal object KnownPacketFactories {
else
->
error
(
""
)
else
->
error
(
""
)
}
}
}.
getOrElse
{
}.
getOrElse
{
// 慢速解密
PacketLogger
.
verbose
{
"失败, 尝试其他各种key"
}
PacketLogger
.
verbose
{
"失败, 尝试其他各种key"
}
bot
.
client
.
tryDecryptOrNull
(
data
,
size
)
{
it
}
bot
.
client
.
tryDecryptOrNull
(
data
,
size
)
{
it
}
}
?.
toReadPacket
()
?.
let
{
decryptedData
->
}
?.
toReadPacket
()
?.
let
{
decryptedData
->
// 解析外层包装
when
(
flag1
)
{
when
(
flag1
)
{
0
x0A
->
parseSsoFrame
(
bot
,
decryptedData
)
0
x0A
->
parseSsoFrame
(
bot
,
decryptedData
)
0
x0B
->
parseSsoFrame
(
bot
,
decryptedData
)
// 这里可能是 uni?? 但测试时候发现结构跟 sso 一样.
0
x0B
->
parseSsoFrame
(
bot
,
decryptedData
)
// 这里可能是 uni?? 但测试时候发现结构跟 sso 一样.
else
->
error
(
"unknown flag1: ${flag1.toByte().toUHexString()}"
)
else
->
error
(
"unknown flag1: ${flag1.toByte().toUHexString()}"
)
}
}
}
?.
let
{
}
?.
let
{
// 处理内层真实的包
if
(
it
.
packetFactory
==
null
)
{
if
(
it
.
packetFactory
==
null
)
{
bot
.
logger
.
debug
(
"Received commandName: ${it.commandName}"
)
bot
.
network
.
logger
.
debug
(
"Received commandName: ${it.commandName}"
)
PacketLogger
.
warning
{
"找不到 PacketFactory"
}
PacketLogger
.
warning
{
"找不到 PacketFactory"
}
PacketLogger
.
verbose
{
"传递给 PacketFactory 的数据 = ${it.data.useBytes { data, length -> data.toUHexString(length = length) }}"
}
PacketLogger
.
verbose
{
"传递给 PacketFactory 的数据 = ${it.data.useBytes { data, length -> data.toUHexString(length = length) }}"
}
return
return
...
@@ -236,7 +220,7 @@ internal object KnownPacketFactories {
...
@@ -236,7 +220,7 @@ internal object KnownPacketFactories {
it
.
data
.
withUse
{
it
.
data
.
withUse
{
when
(
flag2
)
{
when
(
flag2
)
{
0
,
1
->
//it.data.parseUniResponse(bot, it.packetFactory, it.sequenceId, consumer)
0
,
1
->
when
(
it
.
packetFactory
)
{
when
(
it
.
packetFactory
)
{
is
OutgoingPacketFactory
<
*
>
->
consumer
(
is
OutgoingPacketFactory
<
*
>
->
consumer
(
it
.
packetFactory
as
OutgoingPacketFactory
<
T
>,
it
.
packetFactory
as
OutgoingPacketFactory
<
T
>,
...
@@ -252,13 +236,11 @@ internal object KnownPacketFactories {
...
@@ -252,13 +236,11 @@ internal object KnownPacketFactories {
)
)
}
}
// for oicq response, factory is always OutgoingPacketFactory
2
->
it
.
data
.
parseOicqResponse
(
bot
,
it
.
packetFactory
as
OutgoingPacketFactory
<
T
>,
it
.
sequenceId
,
consumer
)
2
->
it
.
data
.
parseOicqResponse
(
bot
,
it
.
packetFactory
as
OutgoingPacketFactory
<
T
>,
it
.
sequenceId
,
consumer
)
else
->
error
(
"unknown flag2: $flag2. Body to be parsed for inner packet=${it.data.readBytes().toUHexString()}"
)
else
->
error
(
"unknown flag2: $flag2. Body to be parsed for inner packet=${it.data.readBytes().toUHexString()}"
)
}
}
}
}
}
?:
inline
{
}
?:
inline
{
// 无法解析
PacketLogger
.
error
{
"任何key都无法解密: ${data.take(size).toUHexString()}"
}
PacketLogger
.
error
{
"任何key都无法解密: ${data.take(size).toUHexString()}"
}
return
return
}
}
...
@@ -279,21 +261,14 @@ internal object KnownPacketFactories {
...
@@ -279,21 +261,14 @@ internal object KnownPacketFactories {
*/
*/
@UseExperimental
(
ExperimentalUnsignedTypes
::
class
,
MiraiInternalAPI
::
class
)
@UseExperimental
(
ExperimentalUnsignedTypes
::
class
,
MiraiInternalAPI
::
class
)
private
fun
parseSsoFrame
(
bot
:
QQAndroidBot
,
input
:
ByteReadPacket
):
IncomingPacket
{
private
fun
parseSsoFrame
(
bot
:
QQAndroidBot
,
input
:
ByteReadPacket
):
IncomingPacket
{
// * 00 00 00 2F 00 00 94 90 00 00 00 00 00 00 00 04 00 00 00 13 48 65 61 72 74 62 65 61 74 2E 41 6C 69 76 65
// 00 00 00 08
// 59 E7 DF 4F
// 00 00 00 00
//
// 00 00 00 04
val
commandName
:
String
val
commandName
:
String
val
ssoSequenceId
:
Int
val
ssoSequenceId
:
Int
val
dataCompressed
:
Int
val
dataCompressed
:
Int
// head
input
.
readPacket
(
input
.
readInt
()
-
4
).
withUse
{
input
.
readPacket
(
input
.
readInt
()
-
4
).
withUse
{
ssoSequenceId
=
readInt
()
ssoSequenceId
=
readInt
()
PacketLogger
.
verbose
{
"sequenceId = $ssoSequenceId"
}
PacketLogger
.
verbose
{
"sequenceId = $ssoSequenceId"
}
val
returnCode
=
readInt
()
val
returnCode
=
readInt
()
check
(
returnCode
==
0
)
{
"returnCode = $returnCode"
}
check
(
returnCode
==
0
)
{
"returnCode = $returnCode"
}
if
(
PacketLogger
.
isEnabled
)
{
if
(
PacketLogger
.
isEnabled
)
{
val
extraData
=
readBytes
(
readInt
()
-
4
)
val
extraData
=
readBytes
(
readInt
()
-
4
)
PacketLogger
.
verbose
{
"(sso/inner)extraData = ${extraData.toUHexString()}"
}
PacketLogger
.
verbose
{
"(sso/inner)extraData = ${extraData.toUHexString()}"
}
...
@@ -361,7 +336,7 @@ internal object KnownPacketFactories {
...
@@ -361,7 +336,7 @@ internal object KnownPacketFactories {
this
.
discardExact
(
1
)
// const = 0
this
.
discardExact
(
1
)
// const = 0
val
packet
=
when
(
encryptionMethod
)
{
val
packet
=
when
(
encryptionMethod
)
{
4
->
{
// peer public key, ECDH
4
->
{
var
data
=
this
.
decryptBy
(
bot
.
client
.
ecdh
.
keyPair
.
initialShareKey
,
(
this
.
remaining
-
1
).
toInt
())
var
data
=
this
.
decryptBy
(
bot
.
client
.
ecdh
.
keyPair
.
initialShareKey
,
(
this
.
remaining
-
1
).
toInt
())
val
peerShareKey
=
bot
.
client
.
ecdh
.
calculateShareKeyByPeerPublicKey
(
readUShortLVByteArray
().
adjustToPublicKey
())
val
peerShareKey
=
bot
.
client
.
ecdh
.
calculateShareKeyByPeerPublicKey
(
readUShortLVByteArray
().
adjustToPublicKey
())
...
@@ -379,7 +354,7 @@ internal object KnownPacketFactories {
...
@@ -379,7 +354,7 @@ internal object KnownPacketFactories {
byteArrayBuffer
.
decryptBy
(
bot
.
client
.
ecdh
.
keyPair
.
initialShareKey
,
size
)
byteArrayBuffer
.
decryptBy
(
bot
.
client
.
ecdh
.
keyPair
.
initialShareKey
,
size
)
}.
getOrElse
{
}.
getOrElse
{
byteArrayBuffer
.
decryptBy
(
bot
.
client
.
randomKey
,
size
)
byteArrayBuffer
.
decryptBy
(
bot
.
client
.
randomKey
,
size
)
}.
toReadPacket
()
// 这里实际上应该用 privateKey(另一个random出来的key)
}.
toReadPacket
()
}
}
}
else
{
}
else
{
this
.
decryptBy
(
bot
.
client
.
randomKey
,
0
,
(
this
.
remaining
-
1
).
toInt
())
this
.
decryptBy
(
bot
.
client
.
randomKey
,
0
,
(
this
.
remaining
-
1
).
toInt
())
...
...
mirai-core-qqandroid/src/commonMain/kotlin/net/mamoe/mirai/qqandroid/network/protocol/packet/login/Login.kt
→
mirai-core-qqandroid/src/commonMain/kotlin/net/mamoe/mirai/qqandroid/network/protocol/packet/login/
Wt
Login.kt
View file @
17af6861
...
@@ -22,6 +22,7 @@ import net.mamoe.mirai.qqandroid.utils.MacOrAndroidIdChangeFlag
...
@@ -22,6 +22,7 @@ import net.mamoe.mirai.qqandroid.utils.MacOrAndroidIdChangeFlag
import
net.mamoe.mirai.qqandroid.utils.guidFlag
import
net.mamoe.mirai.qqandroid.utils.guidFlag
import
net.mamoe.mirai.utils.MiraiDebugAPI
import
net.mamoe.mirai.utils.MiraiDebugAPI
import
net.mamoe.mirai.utils.MiraiInternalAPI
import
net.mamoe.mirai.utils.MiraiInternalAPI
import
net.mamoe.mirai.utils.cryptor.contentToString
import
net.mamoe.mirai.utils.cryptor.decryptBy
import
net.mamoe.mirai.utils.cryptor.decryptBy
import
net.mamoe.mirai.utils.currentTimeSeconds
import
net.mamoe.mirai.utils.currentTimeSeconds
import
net.mamoe.mirai.utils.io.*
import
net.mamoe.mirai.utils.io.*
...
@@ -359,27 +360,30 @@ internal class WtLogin{
...
@@ -359,27 +360,30 @@ internal class WtLogin{
@UseExperimental
(
MiraiDebugAPI
::
class
)
@UseExperimental
(
MiraiDebugAPI
::
class
)
private
fun
onSolveLoginCaptcha
(
tlvMap
:
TlvMap
,
bot
:
QQAndroidBot
):
LoginPacketResponse
.
Captcha
{
private
fun
onSolveLoginCaptcha
(
tlvMap
:
TlvMap
,
bot
:
QQAndroidBot
):
LoginPacketResponse
.
Captcha
{
// val ret = tlvMap[0x104]?.let { println(it.toUHexString()) }
// val ret = tlvMap[0x104]?.let { println(it.toUHexString()) }
bot
.
client
.
t104
=
tlvMap
.
getOrFail
(
0
x104
)
tlvMap
[
0
x192
]
?.
let
{
tlvMap
[
0
x192
]
?.
let
{
bot
.
client
.
t104
=
tlvMap
.
getOrFail
(
0
x104
)
return
LoginPacketResponse
.
Captcha
.
Slider
(
it
.
encodeToString
())
return
LoginPacketResponse
.
Captcha
.
Slider
(
it
.
encodeToString
())
}
}
tlvMap
[
0
x165
]
?.
let
{
question
->
tlvMap
[
0
x165
]
?.
let
{
question
->
if
(
question
[
18
].
toInt
()
==
0
x36
)
{
if
(
question
[
18
].
toInt
()
==
0
x36
)
{
//图片验证
//图片验证
DebugLogger
.
debug
(
"是一个图片验证码"
)
DebugLogger
.
debug
(
"是一个图片验证码"
)
bot
.
client
.
t104
=
tlvMap
.
getOrFail
(
0
x104
)
val
imageData
=
tlvMap
.
getOrFail
(
0
x105
).
toReadPacket
()
val
imageData
=
tlvMap
.
getOrFail
(
0
x105
).
toReadPacket
()
val
signInfoLength
=
imageData
.
readShort
()
val
signInfoLength
=
imageData
.
readShort
()
imageData
.
discardExact
(
2
)
//image Length
imageData
.
discardExact
(
2
)
//image Length
val
sign
=
imageData
.
readBytes
(
signInfoLength
.
toInt
())
val
sign
=
imageData
.
readBytes
(
signInfoLength
.
toInt
())
val
buffer
=
IoBuffer
.
Pool
.
borrow
()
imageData
.
readFully
(
buffer
)
return
LoginPacketResponse
.
Captcha
.
Picture
(
return
LoginPacketResponse
.
Captcha
.
Picture
(
data
=
imageData
.
readBytes
().
toIoBuffer
()
,
data
=
buffer
,
sign
=
sign
sign
=
sign
)
)
}
else
error
(
"UNKNOWN CAPTCHA QUESTION: $
question"
)
}
else
error
(
"UNKNOWN CAPTCHA QUESTION: $
{question.toUHexString()}, tlvMap="
+
tlvMap
.
contentToString
()
)
}
}
error
(
"UNKNOWN CAPTCHA
"
)
error
(
"UNKNOWN CAPTCHA
, tlvMap="
+
tlvMap
.
contentToString
()
)
}
}
@UseExperimental
(
MiraiDebugAPI
::
class
)
@UseExperimental
(
MiraiDebugAPI
::
class
)
...
...
mirai-core/build.gradle.kts
View file @
17af6861
...
@@ -61,13 +61,13 @@ kotlin {
...
@@ -61,13 +61,13 @@ kotlin {
languageSettings
.
useExperimentalAnnotation
(
"kotlin.Experimental"
)
languageSettings
.
useExperimentalAnnotation
(
"kotlin.Experimental"
)
dependencies
{
dependencies
{
implementation
(
kotlin
(
"stdlib"
,
kotlinVersion
))
api
(
kotlin
(
"stdlib"
,
kotlinVersion
))
implementation
(
kotlin
(
"serialization"
,
kotlinVersion
))
api
(
kotlin
(
"serialization"
,
kotlinVersion
))
implementation
(
"org.jetbrains.kotlinx:atomicfu:$atomicFuVersion"
)
api
(
"org.jetbrains.kotlinx:atomicfu:$atomicFuVersion"
)
implementation
(
kotlinx
(
"io"
,
kotlinXIoVersion
))
api
(
kotlinx
(
"io"
,
kotlinXIoVersion
))
implementation
(
kotlinx
(
"coroutines-io"
,
coroutinesIoVersion
))
api
(
kotlinx
(
"coroutines-io"
,
coroutinesIoVersion
))
implementation
(
kotlinx
(
"coroutines-core"
,
coroutinesVersion
))
api
(
kotlinx
(
"coroutines-core"
,
coroutinesVersion
))
}
}
}
}
commonMain
{
commonMain
{
...
...
mirai-core/src/commonMain/kotlin/net.mamoe.mirai/contact/Group.kt
View file @
17af6861
...
@@ -184,4 +184,4 @@ interface Group : Contact, CoroutineScope {
...
@@ -184,4 +184,4 @@ interface Group : Contact, CoroutineScope {
/**
/**
* 返回机器人是否正在被禁言
* 返回机器人是否正在被禁言
*/
*/
val
Group
.
isBotMuted
:
Boolean
get
()
=
this
.
botMuteRemaining
=
=
0
val
Group
.
isBotMuted
:
Boolean
get
()
=
this
.
botMuteRemaining
!
=
0
mirai-core/src/commonMain/kotlin/net.mamoe.mirai/event/MessageSubscribers.kt
View file @
17af6861
...
@@ -29,20 +29,20 @@ import kotlin.contracts.contract
...
@@ -29,20 +29,20 @@ import kotlin.contracts.contract
*/
*/
@UseExperimental
(
ExperimentalContracts
::
class
)
@UseExperimental
(
ExperimentalContracts
::
class
)
@MessageDsl
@MessageDsl
inline
fun
CoroutineScope
.
subscribeMessages
(
crossinline
listeners
:
MessageSubscribersBuilder
<
MessagePacket
<
*
,
*
>>.()
->
Unit
)
{
inline
fun
<
R
>
CoroutineScope
.
subscribeMessages
(
crossinline
listeners
:
MessageSubscribersBuilder
<
MessagePacket
<
*
,
*
>>.()
->
R
):
R
{
// contract 可帮助 IDE 进行类型推断. 无实际代码作用.
// contract 可帮助 IDE 进行类型推断. 无实际代码作用.
contract
{
contract
{
callsInPlace
(
listeners
,
InvocationKind
.
EXACTLY_ONCE
)
callsInPlace
(
listeners
,
InvocationKind
.
EXACTLY_ONCE
)
}
}
MessageSubscribersBuilder
{
messageListener
:
MessageListener
<
MessagePacket
<
*
,
*
>>
->
return
MessageSubscribersBuilder
{
messageListener
:
MessageListener
<
MessagePacket
<
*
,
*
>>
->
// subscribeAlways 即注册一个监听器. 这个监听器收到消息后就传递给 [listener]
// subscribeAlways 即注册一个监听器. 这个监听器收到消息后就传递给 [listener]
// listener 即为 DSL 里 `contains(...) { }`, `startsWith(...) { }` 的代码块.
// listener 即为 DSL 里 `contains(...) { }`, `startsWith(...) { }` 的代码块.
subscribeAlways
{
subscribeAlways
{
messageListener
.
invoke
(
this
,
this
.
message
.
toString
())
messageListener
.
invoke
(
this
,
this
.
message
.
toString
())
// this.message.toString() 即为 messageListener 中 it 接收到的值
// this.message.toString() 即为 messageListener 中 it 接收到的值
}
}
}.
apply
{
listeners
()
}
}.
run
(
listeners
)
}
}
/**
/**
...
@@ -50,15 +50,15 @@ inline fun CoroutineScope.subscribeMessages(crossinline listeners: MessageSubscr
...
@@ -50,15 +50,15 @@ inline fun CoroutineScope.subscribeMessages(crossinline listeners: MessageSubscr
*/
*/
@UseExperimental
(
ExperimentalContracts
::
class
)
@UseExperimental
(
ExperimentalContracts
::
class
)
@MessageDsl
@MessageDsl
inline
fun
CoroutineScope
.
subscribeGroupMessages
(
crossinline
listeners
:
MessageSubscribersBuilder
<
GroupMessage
>.()
->
Unit
)
{
inline
fun
<
R
>
CoroutineScope
.
subscribeGroupMessages
(
crossinline
listeners
:
MessageSubscribersBuilder
<
GroupMessage
>.()
->
R
):
R
{
contract
{
contract
{
callsInPlace
(
listeners
,
InvocationKind
.
EXACTLY_ONCE
)
callsInPlace
(
listeners
,
InvocationKind
.
EXACTLY_ONCE
)
}
}
MessageSubscribersBuilder
<
GroupMessage
>
{
listener
->
return
MessageSubscribersBuilder
<
GroupMessage
>
{
listener
->
subscribeAlways
{
subscribeAlways
{
listener
(
it
,
this
.
message
.
toString
())
listener
(
this
,
this
.
message
.
toString
())
}
}
}.
apply
{
listeners
()
}
}.
run
(
listeners
)
}
}
/**
/**
...
@@ -66,15 +66,15 @@ inline fun CoroutineScope.subscribeGroupMessages(crossinline listeners: MessageS
...
@@ -66,15 +66,15 @@ inline fun CoroutineScope.subscribeGroupMessages(crossinline listeners: MessageS
*/
*/
@UseExperimental
(
ExperimentalContracts
::
class
)
@UseExperimental
(
ExperimentalContracts
::
class
)
@MessageDsl
@MessageDsl
inline
fun
CoroutineScope
.
subscribeFriendMessages
(
crossinline
listeners
:
MessageSubscribersBuilder
<
FriendMessage
>.()
->
Unit
)
{
inline
fun
<
R
>
CoroutineScope
.
subscribeFriendMessages
(
crossinline
listeners
:
MessageSubscribersBuilder
<
FriendMessage
>.()
->
R
):
R
{
contract
{
contract
{
callsInPlace
(
listeners
,
InvocationKind
.
EXACTLY_ONCE
)
callsInPlace
(
listeners
,
InvocationKind
.
EXACTLY_ONCE
)
}
}
MessageSubscribersBuilder
<
FriendMessage
>
{
listener
->
return
MessageSubscribersBuilder
<
FriendMessage
>
{
listener
->
subscribeAlways
{
subscribeAlways
{
listener
(
it
,
this
.
message
.
toString
())
listener
(
this
,
this
.
message
.
toString
())
}
}
}.
apply
{
listeners
()
}
}.
run
(
listeners
)
}
}
/**
/**
...
@@ -82,15 +82,15 @@ inline fun CoroutineScope.subscribeFriendMessages(crossinline listeners: Message
...
@@ -82,15 +82,15 @@ inline fun CoroutineScope.subscribeFriendMessages(crossinline listeners: Message
*/
*/
@UseExperimental
(
ExperimentalContracts
::
class
)
@UseExperimental
(
ExperimentalContracts
::
class
)
@MessageDsl
@MessageDsl
inline
fun
Bot
.
subscribeMessages
(
crossinline
listeners
:
MessageSubscribersBuilder
<
MessagePacket
<
*
,
*
>>.()
->
Unit
)
{
inline
fun
<
R
>
Bot
.
subscribeMessages
(
crossinline
listeners
:
MessageSubscribersBuilder
<
MessagePacket
<
*
,
*
>>.()
->
R
):
R
{
contract
{
contract
{
callsInPlace
(
listeners
,
InvocationKind
.
EXACTLY_ONCE
)
callsInPlace
(
listeners
,
InvocationKind
.
EXACTLY_ONCE
)
}
}
MessageSubscribersBuilder
<
MessagePacket
<
*
,
*
>>
{
listener
->
return
MessageSubscribersBuilder
<
MessagePacket
<
*
,
*
>>
{
listener
->
this
.
subscribeAlways
{
this
.
subscribeAlways
{
listener
(
it
,
this
.
message
.
toString
())
listener
(
this
,
this
.
message
.
toString
())
}
}
}.
apply
{
listeners
()
}
}.
run
(
listeners
)
}
}
/**
/**
...
@@ -98,15 +98,15 @@ inline fun Bot.subscribeMessages(crossinline listeners: MessageSubscribersBuilde
...
@@ -98,15 +98,15 @@ inline fun Bot.subscribeMessages(crossinline listeners: MessageSubscribersBuilde
*/
*/
@UseExperimental
(
ExperimentalContracts
::
class
)
@UseExperimental
(
ExperimentalContracts
::
class
)
@MessageDsl
@MessageDsl
inline
fun
Bot
.
subscribeGroupMessages
(
crossinline
listeners
:
MessageSubscribersBuilder
<
GroupMessage
>.()
->
Unit
)
{
inline
fun
<
R
>
Bot
.
subscribeGroupMessages
(
crossinline
listeners
:
MessageSubscribersBuilder
<
GroupMessage
>.()
->
R
):
R
{
contract
{
contract
{
callsInPlace
(
listeners
,
InvocationKind
.
EXACTLY_ONCE
)
callsInPlace
(
listeners
,
InvocationKind
.
EXACTLY_ONCE
)
}
}
MessageSubscribersBuilder
<
GroupMessage
>
{
listener
->
return
MessageSubscribersBuilder
<
GroupMessage
>
{
listener
->
this
.
subscribeAlways
{
this
.
subscribeAlways
{
listener
(
it
,
this
.
message
.
toString
())
listener
(
this
,
this
.
message
.
toString
())
}
}
}.
apply
{
listeners
()
}
}.
run
(
listeners
)
}
}
/**
/**
...
@@ -114,15 +114,15 @@ inline fun Bot.subscribeGroupMessages(crossinline listeners: MessageSubscribersB
...
@@ -114,15 +114,15 @@ inline fun Bot.subscribeGroupMessages(crossinline listeners: MessageSubscribersB
*/
*/
@UseExperimental
(
ExperimentalContracts
::
class
)
@UseExperimental
(
ExperimentalContracts
::
class
)
@MessageDsl
@MessageDsl
inline
fun
Bot
.
subscribeFriendMessages
(
crossinline
listeners
:
MessageSubscribersBuilder
<
FriendMessage
>.()
->
Unit
)
{
inline
fun
<
R
>
Bot
.
subscribeFriendMessages
(
crossinline
listeners
:
MessageSubscribersBuilder
<
FriendMessage
>.()
->
R
):
R
{
contract
{
contract
{
callsInPlace
(
listeners
,
InvocationKind
.
EXACTLY_ONCE
)
callsInPlace
(
listeners
,
InvocationKind
.
EXACTLY_ONCE
)
}
}
MessageSubscribersBuilder
<
FriendMessage
>
{
listener
->
return
MessageSubscribersBuilder
<
FriendMessage
>
{
listener
->
this
.
subscribeAlways
{
this
.
subscribeAlways
{
it
.
listener
(
it
.
message
.
toString
())
listener
(
this
,
this
.
message
.
toString
())
}
}
}.
apply
{
listeners
()
}
}.
run
(
listeners
)
}
}
...
@@ -588,6 +588,12 @@ class MessageSubscribersBuilder<T : MessagePacket<*, *>>(
...
@@ -588,6 +588,12 @@ class MessageSubscribersBuilder<T : MessagePacket<*, *>>(
return
content
({
it
.
trim
()
==
toCheck
},
{
reply
(
reply
)
})
return
content
({
it
.
trim
()
==
toCheck
},
{
reply
(
reply
)
})
}
}
@MessageDsl
infix
fun
String
.
reply
(
reply
:
Message
):
Listener
<
T
>
{
val
toCheck
=
this
.
trim
()
return
content
({
it
.
trim
()
==
toCheck
},
{
reply
(
reply
)
})
}
@MessageDsl
@MessageDsl
inline
infix
fun
String
.
reply
(
crossinline
replier
:
@MessageDsl
suspend
T
.(
String
)
->
Any
?):
Listener
<
T
>
{
inline
infix
fun
String
.
reply
(
crossinline
replier
:
@MessageDsl
suspend
T
.(
String
)
->
Any
?):
Listener
<
T
>
{
val
toCheck
=
this
.
trim
()
val
toCheck
=
this
.
trim
()
...
...
mirai-core/src/commonMain/kotlin/net.mamoe.mirai/event/Subscribers.kt
View file @
17af6861
...
@@ -10,11 +10,13 @@
...
@@ -10,11 +10,13 @@
package
net.mamoe.mirai.event
package
net.mamoe.mirai.event
import
kotlinx.coroutines.CompletableJob
import
kotlinx.coroutines.CompletableJob
import
kotlinx.coroutines.CoroutineExceptionHandler
import
kotlinx.coroutines.CoroutineScope
import
kotlinx.coroutines.CoroutineScope
import
kotlinx.coroutines.GlobalScope
import
kotlinx.coroutines.GlobalScope
import
net.mamoe.mirai.Bot
import
net.mamoe.mirai.Bot
import
net.mamoe.mirai.event.internal.Handler
import
net.mamoe.mirai.event.internal.Handler
import
net.mamoe.mirai.event.internal.subscribeInternal
import
net.mamoe.mirai.event.internal.subscribeInternal
import
kotlin.coroutines.CoroutineContext
/*
/*
* 该文件为所有的订阅事件的方法.
* 该文件为所有的订阅事件的方法.
...
@@ -38,6 +40,8 @@ enum class ListeningStatus {
...
@@ -38,6 +40,8 @@ enum class ListeningStatus {
/**
/**
* 事件监听器.
* 事件监听器.
* 由 [subscribe] 等方法返回.
* 由 [subscribe] 等方法返回.
*
* 取消监听: [complete]
*/
*/
interface
Listener
<
in
E
:
Event
>
:
CompletableJob
{
interface
Listener
<
in
E
:
Event
>
:
CompletableJob
{
suspend
fun
onEvent
(
event
:
E
):
ListeningStatus
suspend
fun
onEvent
(
event
:
E
):
ListeningStatus
...
@@ -50,11 +54,10 @@ interface Listener<in E : Event> : CompletableJob {
...
@@ -50,11 +54,10 @@ interface Listener<in E : Event> : CompletableJob {
* 每当 [事件广播][Event.broadcast] 时, [handler] 都会被执行.
* 每当 [事件广播][Event.broadcast] 时, [handler] 都会被执行.
*
*
* 当 [handler] 返回 [ListeningStatus.STOPPED] 时停止监听.
* 当 [handler] 返回 [ListeningStatus.STOPPED] 时停止监听.
* 或 [Listener] complete 时结束.
* 或 [Listener.complete] 后结束.
*
*
*
*
**注意**: 这个函数返回 [Listener], 它是一个 [CompletableJob]. 如果不手动 [CompletableJob.complete], 它将会阻止当前 [CoroutineScope] 结束
.
*
这个函数返回 [Listener], 它是一个 [CompletableJob]. 请注意它除非被 [Listener.complete] 或 [Listener.cancel], 则不会完成
.
* 例
如
:
* 例:
* ```kotlin
* ```kotlin
* runBlocking { // this: CoroutineScope
* runBlocking { // this: CoroutineScope
* subscribe<Event> { /* 一些处理 */
}
// 返回 Listener, 即 CompletableJob
* subscribe<Event> { /* 一些处理 */
}
// 返回 Listener, 即 CompletableJob
...
@@ -70,23 +73,37 @@ interface Listener<in E : Event> : CompletableJob {
...
@@ -70,23 +73,37 @@ interface Listener<in E : Event> : CompletableJob {
*
```
*
```
*
*
*
*
*
要创建一个仅在机器人在线时的监听
,
请在
[
Bot
]
下调用本函数
(
因为
[
Bot
]
也实现
[
CoroutineScope
]):
*
要创建一个仅在
某个
机器人在线时的监听
,
请在
[
Bot
]
下调用本函数
(
因为
[
Bot
]
也实现
[
CoroutineScope
]):
*
``
`kotlin
*
``
`kotlin
*
bot
.
subscribe
<
Subscribe
>
{
/* 一些处理 */
}
*
bot
.
subscribe
<
Subscribe
>
{
/* 一些处理 */
}
*
```
*
```
*
*
*
*
事件处理时的
[
CoroutineContext
]
为调用本函数时的
[
receiver
][
this
]
的
[
CoroutineScope
.
coroutineContext
].
*
因此
:
*
-
事件处理时抛出的异常将会在
[
this
]
的
[
CoroutineExceptionHandler
]
中处理
*
若
[
this
]
没有
[
CoroutineExceptionHandler
],
则在事件广播方的
[
CoroutineExceptionHandler
]
处理
*
若均找不到
,
则会触发
logger
warning
.
*
-
事件处理时抛出异常不会停止监听器
.
*
-
建议在事件处理中
,
即
[
handler
]
里处理异常
,
或在
[
this
]
指定
[
CoroutineExceptionHandler
].
*
*
*
**
注意
:**
事件处理是
`suspend`
的
,
请严格控制
JVM
阻塞方法的使用
.
若致事件处理阻塞
,
则会导致一些逻辑无法进行
.
*
*
// TODO: 2020/2/13 在 bot 下监听时同时筛选对应 bot 实例
*
*
@
see
subscribeMessages
监听消息
DSL
*
@
see
subscribeMessages
监听消息
DSL
*
@
see
subscribeGroupMessages
监听群消息
*
@
see
subscribeGroupMessages
监听群消息
DSL
*
@
see
subscribeFriendMessages
监听好友消息
*
@
see
subscribeFriendMessages
监听好友消息
DSL
*/
*/
inline
fun
<
reified
E
:
Event
>
CoroutineScope
.
subscribe
(
crossinline
handler
:
suspend
E
.(
E
)
->
ListeningStatus
):
Listener
<
E
>
=
inline
fun
<
reified
E
:
Event
>
CoroutineScope
.
subscribe
(
crossinline
handler
:
suspend
E
.(
E
)
->
ListeningStatus
):
Listener
<
E
>
=
E
::
class
.
subscribeInternal
(
Handler
{
it
.
handler
(
it
)
})
E
::
class
.
subscribeInternal
(
Handler
{
it
.
handler
(
it
)
;
})
/**
/**
* 在指定的 [CoroutineScope] 下订阅所有 [E] 及其子类事件.
* 在指定的 [CoroutineScope] 下订阅所有 [E] 及其子类事件.
* 每当 [事件广播][Event.broadcast] 时, [listener] 都会被执行.
* 每当 [事件广播][Event.broadcast] 时, [listener] 都会被执行.
*
*
* 仅当 [Listener
] complete
时结束.
* 仅当 [Listener
.complete] 或 [Listener.cancel]
时结束.
*
*
* @see subscribe 获取更多说明
* @see subscribe 获取更多说明
*/
*/
...
...
mirai-core/src/commonMain/kotlin/net.mamoe.mirai/event/events/BotEvents.kt
View file @
17af6861
...
@@ -29,6 +29,8 @@ class EventCancelledException : RuntimeException {
...
@@ -29,6 +29,8 @@ class EventCancelledException : RuntimeException {
constructor
(
cause
:
Throwable
?)
:
super
(
cause
)
constructor
(
cause
:
Throwable
?)
:
super
(
cause
)
}
}
// note: 若你使用 IntelliJ IDEA, 按 alt + 7 可打开结构
// region Bot 状态
// region Bot 状态
...
...
mirai-core/src/commonMain/kotlin/net.mamoe.mirai/event/events/types.kt
View file @
17af6861
...
@@ -53,7 +53,7 @@ interface GroupMemberEvent : GroupEvent {
...
@@ -53,7 +53,7 @@ interface GroupMemberEvent : GroupEvent {
/**
/**
* 有关
群
的事件
* 有关
好友
的事件
*/
*/
interface
FriendEvent
:
BotEvent
{
interface
FriendEvent
:
BotEvent
{
val
friend
:
QQ
val
friend
:
QQ
...
...
mirai-core/src/commonMain/kotlin/net.mamoe.mirai/message/GroupMessage.kt
View file @
17af6861
...
@@ -14,9 +14,11 @@ import net.mamoe.mirai.contact.Group
...
@@ -14,9 +14,11 @@ import net.mamoe.mirai.contact.Group
import
net.mamoe.mirai.contact.Member
import
net.mamoe.mirai.contact.Member
import
net.mamoe.mirai.contact.MemberPermission
import
net.mamoe.mirai.contact.MemberPermission
import
net.mamoe.mirai.message.data.At
import
net.mamoe.mirai.message.data.At
import
net.mamoe.mirai.message.data.Message
import
net.mamoe.mirai.message.data.MessageChain
import
net.mamoe.mirai.message.data.MessageChain
import
net.mamoe.mirai.utils.getValue
import
net.mamoe.mirai.utils.getValue
import
net.mamoe.mirai.utils.unsafeWeakRef
import
net.mamoe.mirai.utils.unsafeWeakRef
import
kotlin.jvm.JvmName
@Suppress
(
"unused"
,
"NOTHING_TO_INLINE"
)
@Suppress
(
"unused"
,
"NOTHING_TO_INLINE"
)
class
GroupMessage
(
class
GroupMessage
(
...
@@ -37,6 +39,28 @@ class GroupMessage(
...
@@ -37,6 +39,28 @@ class GroupMessage(
inline
fun
At
.
member
():
Member
=
group
[
this
.
target
]
inline
fun
At
.
member
():
Member
=
group
[
this
.
target
]
inline
fun
Long
.
member
():
Member
=
group
[
this
]
inline
fun
Long
.
member
():
Member
=
group
[
this
]
/**
* 给这个消息事件的主体发送引用回复消息
* 对于好友消息事件, 这个方法将会给好友 ([subject]) 发送消息
* 对于群消息事件, 这个方法将会给群 ([subject]) 发送消息
*/
suspend
inline
fun
quoteReply
(
message
:
MessageChain
)
=
reply
(
this
.
message
.
quote
()
+
message
)
suspend
inline
fun
quoteReply
(
message
:
Message
)
=
reply
(
this
.
message
.
quote
()
+
message
)
suspend
inline
fun
quoteReply
(
plain
:
String
)
=
reply
(
this
.
message
.
quote
()
+
plain
)
@JvmName
(
"reply2"
)
suspend
inline
fun
String
.
quoteReply
()
=
quoteReply
(
this
)
@JvmName
(
"reply2"
)
suspend
inline
fun
Message
.
quoteReply
()
=
quoteReply
(
this
)
@JvmName
(
"reply2"
)
suspend
inline
fun
MessageChain
.
quoteReply
()
=
quoteReply
(
this
)
override
fun
toString
():
String
=
override
fun
toString
():
String
=
"GroupMessage(group=${group.id}, senderName=$senderName, sender=${sender.id}, permission=${permission.name}, message=$message)"
"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/data/At.kt
View file @
17af6861
...
@@ -17,6 +17,8 @@ import net.mamoe.mirai.utils.MiraiInternalAPI
...
@@ -17,6 +17,8 @@ import net.mamoe.mirai.utils.MiraiInternalAPI
/**
/**
* At 一个人. 只能发送给一个群.
* At 一个人. 只能发送给一个群.
*
* @see AtAll 全体成员
*/
*/
class
At
@MiraiInternalAPI
constructor
(
val
target
:
Long
,
val
display
:
String
)
:
Message
{
class
At
@MiraiInternalAPI
constructor
(
val
target
:
Long
,
val
display
:
String
)
:
Message
{
@UseExperimental
(
MiraiInternalAPI
::
class
)
@UseExperimental
(
MiraiInternalAPI
::
class
)
...
@@ -33,10 +35,10 @@ class At @MiraiInternalAPI constructor(val target: Long, val display: String) :
...
@@ -33,10 +35,10 @@ class At @MiraiInternalAPI constructor(val target: Long, val display: String) :
// 自动为消息补充 " "
// 自动为消息补充 " "
override
fun
followedBy
(
tail
:
Message
):
MessageChain
{
override
fun
followedBy
(
tail
:
Message
):
MessageChain
{
if
(
tail
is
PlainText
&&
!
tail
.
stringValue
.
startsWith
(
' '
)){
if
(
tail
is
PlainText
&&
tail
.
stringValue
.
startsWith
(
' '
)){
return
super
.
followedBy
(
PlainText
(
" "
))
+
tail
return
super
.
followedBy
(
tail
)
}
}
return
super
.
followedBy
(
tail
)
return
super
.
followedBy
(
PlainText
(
" "
))
+
tail
}
}
}
}
...
...
mirai-core/src/commonMain/kotlin/net.mamoe.mirai/message/data/AtAll.kt
0 → 100644
View file @
17af6861
/*
* 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.data
/**
* "@全体成员"
*
* @see At at 单个群成员
*/
object
AtAll
:
Message
{
override
fun
toString
():
String
=
"@全体成员"
// 自动为消息补充 " "
override
fun
followedBy
(
tail
:
Message
):
MessageChain
{
if
(
tail
is
PlainText
&&
tail
.
stringValue
.
startsWith
(
' '
)){
return
super
.
followedBy
(
tail
)
}
return
super
.
followedBy
(
PlainText
(
" "
))
+
tail
}
}
\ No newline at end of file
mirai-core/src/commonMain/kotlin/net.mamoe.mirai/utils/BotConfiguration.kt
View file @
17af6861
...
@@ -54,16 +54,6 @@ class BotConfiguration {
...
@@ -54,16 +54,6 @@ class BotConfiguration {
*/
*/
var
parentCoroutineContext
:
CoroutineContext
=
EmptyCoroutineContext
var
parentCoroutineContext
:
CoroutineContext
=
EmptyCoroutineContext
/**
* 连接每个服务器的时间
*/
var
touchTimeoutMillis
:
Long
=
1
.
secondsToMillis
/**
* 是否使用随机的设备名.
* 使用随机可以降低被封禁的风险, 但可能导致每次登录都需要输入验证码
* 当一台设备只登录少量账号时, 将此项设置为 `false` 可能更好.
*/
var
randomDeviceName
:
Boolean
=
false
/**
/**
* 心跳周期. 过长会导致被服务器断开连接.
* 心跳周期. 过长会导致被服务器断开连接.
*/
*/
...
@@ -85,20 +75,10 @@ class BotConfiguration {
...
@@ -85,20 +75,10 @@ class BotConfiguration {
* 最多尝试多少次重连
* 最多尝试多少次重连
*/
*/
var
reconnectionRetryTimes
:
Int
=
3
var
reconnectionRetryTimes
:
Int
=
3
/**
* 有验证码要求就失败
*/
var
failOnCaptcha
=
false
/**
/**
* 验证码处理器
* 验证码处理器
*/
*/
var
loginSolver
:
LoginSolver
=
defaultLoginSolver
var
loginSolver
:
LoginSolver
=
defaultLoginSolver
/**
* 登录完成后几秒会收到好友消息的历史记录,
* 这些历史记录不会触发事件.
* 这个选项为是否把这些记录添加到日志
*/
var
logPreviousMessages
:
Boolean
=
false
companion
object
{
companion
object
{
/**
/**
...
...
mirai-core/src/commonMain/kotlin/net.mamoe.mirai/utils/io/DebugUtil.kt
View file @
17af6861
...
@@ -15,10 +15,7 @@ package net.mamoe.mirai.utils.io
...
@@ -15,10 +15,7 @@ package net.mamoe.mirai.utils.io
import
kotlinx.io.core.*
import
kotlinx.io.core.*
import
kotlinx.io.pool.useInstance
import
kotlinx.io.pool.useInstance
import
net.mamoe.mirai.utils.DefaultLogger
import
net.mamoe.mirai.utils.*
import
net.mamoe.mirai.utils.MiraiDebugAPI
import
net.mamoe.mirai.utils.MiraiLogger
import
net.mamoe.mirai.utils.withSwitch
import
kotlin.contracts.ExperimentalContracts
import
kotlin.contracts.ExperimentalContracts
import
kotlin.contracts.InvocationKind
import
kotlin.contracts.InvocationKind
import
kotlin.contracts.contract
import
kotlin.contracts.contract
...
@@ -28,7 +25,7 @@ import kotlin.jvm.JvmName
...
@@ -28,7 +25,7 @@ import kotlin.jvm.JvmName
@MiraiDebugAPI
(
"Unsatble"
)
@MiraiDebugAPI
(
"Unsatble"
)
object
DebugLogger
:
MiraiLogger
by
DefaultLogger
(
"Packet Debug"
).
withSwitch
(
)
val
DebugLogger
:
MiraiLoggerWithSwitch
=
DefaultLogger
(
"Packet Debug"
).
withSwitch
(
false
)
@MiraiDebugAPI
(
"Unstable"
)
@MiraiDebugAPI
(
"Unstable"
)
inline
fun
Throwable
.
logStacktrace
(
message
:
String
?
=
null
)
=
DebugLogger
.
error
(
message
,
this
)
inline
fun
Throwable
.
logStacktrace
(
message
:
String
?
=
null
)
=
DebugLogger
.
error
(
message
,
this
)
...
...
mirai-core/src/jvmMain/kotlin/net/mamoe/mirai/utils/PlatformUtilsJvm.kt
View file @
17af6861
...
@@ -74,3 +74,9 @@ actual fun ByteArray.unzip(offset: Int, length: Int): ByteArray {
...
@@ -74,3 +74,9 @@ actual fun ByteArray.unzip(offset: Int, length: Int): ByteArray {
return
output
.
toByteArray
()
return
output
.
toByteArray
()
}
}
}
}
/**
* 时间戳
*/
actual
val
currentTimeMillis
:
Long
get
()
=
System
.
currentTimeMillis
()
\ No newline at end of file
mirai-demos/mirai-demo-1/src/main/java/demo/subscribe/SubscribeSamples.kt
View file @
17af6861
...
@@ -11,6 +11,7 @@
...
@@ -11,6 +11,7 @@
package
demo.subscribe
package
demo.subscribe
import
kotlinx.coroutines.CompletableJob
import
net.mamoe.mirai.Bot
import
net.mamoe.mirai.Bot
import
net.mamoe.mirai.BotAccount
import
net.mamoe.mirai.BotAccount
import
net.mamoe.mirai.alsoLogin
import
net.mamoe.mirai.alsoLogin
...
@@ -19,6 +20,7 @@ import net.mamoe.mirai.contact.sendMessage
...
@@ -19,6 +20,7 @@ import net.mamoe.mirai.contact.sendMessage
import
net.mamoe.mirai.event.*
import
net.mamoe.mirai.event.*
import
net.mamoe.mirai.message.FriendMessage
import
net.mamoe.mirai.message.FriendMessage
import
net.mamoe.mirai.message.GroupMessage
import
net.mamoe.mirai.message.GroupMessage
import
net.mamoe.mirai.message.data.AtAll
import
net.mamoe.mirai.message.data.Image
import
net.mamoe.mirai.message.data.Image
import
net.mamoe.mirai.message.data.PlainText
import
net.mamoe.mirai.message.data.PlainText
import
net.mamoe.mirai.message.data.firstOrNull
import
net.mamoe.mirai.message.data.firstOrNull
...
@@ -44,12 +46,13 @@ private fun readTestAccount(): BotAccount? {
...
@@ -44,12 +46,13 @@ private fun readTestAccount(): BotAccount? {
@Suppress
(
"UNUSED_VARIABLE"
)
@Suppress
(
"UNUSED_VARIABLE"
)
suspend
fun
main
()
{
suspend
fun
main
()
{
val
bot
=
QQAndroid
.
Bot
(
// JVM 下也可以不写 `
TIMPC
.` 引用顶层函数
val
bot
=
QQAndroid
.
Bot
(
// JVM 下也可以不写 `
QQAndroid
.` 引用顶层函数
1
994701121
,
1
23456789
,
"123456"
"123456"
)
{
)
{
// 覆盖默认的配置
// 覆盖默认的配置
randomDeviceName
=
false
// networkLoggerSupplier = { SilentLogger } // 禁用网络层输出
}.
alsoLogin
()
}.
alsoLogin
()
bot
.
messageDSL
()
bot
.
messageDSL
()
...
@@ -96,7 +99,7 @@ fun Bot.messageDSL() {
...
@@ -96,7 +99,7 @@ fun Bot.messageDSL() {
// it: String (MessageChain.toString)
// it: String (MessageChain.toString)
message
[
Image
].
download
()
// message[Image].download() // 还未支持 download
if
(
this
is
GroupMessage
)
{
if
(
this
is
GroupMessage
)
{
//如果是群消息
//如果是群消息
// group: Group
// group: Group
...
@@ -118,6 +121,7 @@ fun Bot.messageDSL() {
...
@@ -118,6 +121,7 @@ fun Bot.messageDSL() {
// 当收到 "我的qq" 就执行 lambda 并回复 lambda 的返回值 String
// 当收到 "我的qq" 就执行 lambda 并回复 lambda 的返回值 String
"我的qq"
reply
{
sender
.
id
}
"我的qq"
reply
{
sender
.
id
}
"at all"
reply
AtAll
// at 全体成员
// 如果是这个 QQ 号发送的消息(可以是好友消息也可以是群消息)
// 如果是这个 QQ 号发送的消息(可以是好友消息也可以是群消息)
sentBy
(
123456789
)
{
sentBy
(
123456789
)
{
...
@@ -133,12 +137,27 @@ fun Bot.messageDSL() {
...
@@ -133,12 +137,27 @@ fun Bot.messageDSL() {
}
}
// 当消息中包含 "复读" 时
// listener 管理
val
listener
=
(
contains
(
"复读1"
)
or
contains
(
"复读2"
))
{
reply
(
message
)
var
repeaterListener
:
CompletableJob
?
=
null
contains
(
"开启复读"
)
{
repeaterListener
?.
complete
()
bot
.
subscribeGroupMessages
{
repeaterListener
=
contains
(
"复读"
)
{
reply
(
message
)
}
}
}
contains
(
"关闭复读"
)
{
if
(
repeaterListener
?.
complete
()
==
null
)
{
reply
(
"没有开启复读"
)
}
else
{
reply
(
"成功关闭复读"
)
}
}
}
listener
.
complete
()
// 停止监听
// 自定义的 filter, filter 中 it 为转为 String 的消息.
// 自定义的 filter, filter 中 it 为转为 String 的消息.
// 也可以用任何能在处理时使用的变量, 如 subject, sender, message
// 也可以用任何能在处理时使用的变量, 如 subject, sender, message
...
@@ -196,19 +215,19 @@ suspend fun directlySubscribe(bot: Bot) {
...
@@ -196,19 +215,19 @@ suspend fun directlySubscribe(bot: Bot) {
// 在当前协程作用域 (CoroutineScope) 下创建一个子 Job, 监听一个事件.
// 在当前协程作用域 (CoroutineScope) 下创建一个子 Job, 监听一个事件.
//
//
// 手动处理消息
// 手动处理消息
// 使用 Bot 的扩展方法监听, 将在处理事件时得到一个 this: Bot.
// 这样可以调用 Bot 内的一些扩展方法如 UInt.qq():QQ
//
//
// 这个函数返回 Listener, Listener 是一个 CompletableJob. 如果不手动 close 它, 它会一直阻止当前 CoroutineScope 结束.
// subscribeAlways 函数返回 Listener, Listener 是一个 CompletableJob.
//
// 例如:
// 例如:
// ```kotlin
// ```kotlin
// runBlocking {// this: CoroutineScope
// runBlocking {// this: CoroutineScope
//
bot.
subscribeAlways<FriendMessage> {
// subscribeAlways<FriendMessage> {
// }
// }
// }
// }
// ```
// ```
// 则这个 `runBlocking` 永远不会结束, 因为 `subscribeAlways` 在 `runBlocking` 的 `CoroutineScope` 下创建了一个 Job.
// 则这个 `runBlocking` 永远不会结束, 因为 `subscribeAlways` 在 `runBlocking` 的 `CoroutineScope` 下创建了一个 Job.
// 正确的用法为:
// 正确的用法为:
// 在 Bot 的 CoroutineScope 下创建一个监听事件的 Job, 则这个子 Job 会在 Bot 离线后自动完成 (complete).
bot
.
subscribeAlways
<
FriendMessage
>
{
bot
.
subscribeAlways
<
FriendMessage
>
{
// this: FriendMessageEvent
// this: FriendMessageEvent
// event: FriendMessageEvent
// event: FriendMessageEvent
...
...
mirai-demos/mirai-demo-gentleman/src/main/kotlin/demo/gentleman/GentleImage.kt
View file @
17af6861
...
@@ -47,7 +47,7 @@ class GentleImage(val contact: Contact, val keyword: String) {
...
@@ -47,7 +47,7 @@ class GentleImage(val contact: Contact, val keyword: String) {
Jsoup
.
connect
(
"https://api.lolicon.app/setu/?r18=$r18"
+
if
(
keyword
.
isNotBlank
())
"&keyword=$keyword&num=10"
else
""
)
Jsoup
.
connect
(
"https://api.lolicon.app/setu/?r18=$r18"
+
if
(
keyword
.
isNotBlank
())
"&keyword=$keyword&num=10"
else
""
)
.
ignoreContentType
(
true
)
.
ignoreContentType
(
true
)
.
userAgent
(
UserAgent
.
randomUserAgent
)
.
userAgent
(
UserAgent
.
randomUserAgent
)
.
proxy
(
"127.0.0.1"
,
1088
)
//
.proxy("127.0.0.1", 1088)
.
timeout
(
10
_0000
)
.
timeout
(
10
_0000
)
.
get
().
body
().
text
()
.
get
().
body
().
text
()
)
)
...
@@ -60,7 +60,7 @@ class GentleImage(val contact: Contact, val keyword: String) {
...
@@ -60,7 +60,7 @@ class GentleImage(val contact: Contact, val keyword: String) {
.
ignoreContentType
(
true
)
.
ignoreContentType
(
true
)
.
userAgent
(
"Mozilla/5.0 (Macintosh; U; Intel Mac OS X 10_6_7; ja-jp) AppleWebKit/533.20.25 (KHTML, like Gecko) Version/5.0.4 Safari/533.20.27"
)
.
userAgent
(
"Mozilla/5.0 (Macintosh; U; Intel Mac OS X 10_6_7; ja-jp) AppleWebKit/533.20.25 (KHTML, like Gecko) Version/5.0.4 Safari/533.20.27"
)
.
referrer
(
"https://www.pixiv.net/member_illust.php?mode=medium&illust_id=${setu.pid}"
)
.
referrer
(
"https://www.pixiv.net/member_illust.php?mode=medium&illust_id=${setu.pid}"
)
.
proxy
(
"127.0.0.1"
,
1088
)
//
.proxy("127.0.0.1", 1088)
.
ignoreHttpErrors
(
true
)
.
ignoreHttpErrors
(
true
)
.
maxBodySize
(
10000000
)
.
maxBodySize
(
10000000
)
.
execute
().
also
{
check
(
it
.
statusCode
()
==
200
)
{
"Failed to download image"
}
}
.
execute
().
also
{
check
(
it
.
statusCode
()
==
200
)
{
"Failed to download image"
}
}
...
...
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