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 @@
开发版本. 频繁更新, 不保证高稳定性
## `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
### mirai-core
1.
修改 BotFactory, 添加
`context`
参数.
2.
currentTimeMillis 减少不必要对象创建
3.
优化无锁链表性能 (大幅提升
`addAll`
性能)
-
修改 BotFactory, 添加
`context`
参数.
-
currentTimeMillis 减少不必要对象创建
-
优化无锁链表性能 (大幅提升
`addAll`
性能)
### mirai-core-qqanroid
安卓协议发布, 基于最新 QQ, 版本
`8.2.0`
支持的功能:
-
登录: 密码登录. 设备锁支持, 不安全状态支持, 图片验证码支持, 滑动验证码支持.
-
消息: 文字消息, 图片消息(含表情消息), 群员 At.
-
消息: 文字消息, 图片消息(含表情消息), 群员 At
, 引用回复
.
-
列表: 群列表, 群员列表, 好友列表均已稳定.
-
群操作: 查看和修改群名, 查看和修改群属性(含全体禁言, 坦白说, 自动批准加入, 匿名聊天, 允许成员拉人), 设置和解除成员禁言, 查看和修改成员名片, 踢出成员.
-
消息事件: 接受群消息和好友消息并解析
...
...
README.md
View file @
17af6861
...
...
@@ -53,7 +53,7 @@ repositories{
若您需要使用在跨平台项目, 则要对各个目标平台添加不同的依赖,这与 kotlin 相关跨平台库的依赖是类似的。
**若您只需要使用在单一平台, 则只需要添加一项该平台的依赖. 如只在 JVM 运行则只需要`-jvm`的依赖**
请将
`VERSION`
替换为最新的版本(如
`0.1
0.6
`
):
请将
`VERSION`
替换为最新的版本(如
`0.1
3.0
`
):
[

](https://bintray.com/him188moe/mirai/mirai-core/)
**Mirai 目前还处于实验性阶段, 我们无法保证任何稳定性, API 也可能会随时修改.**
...
...
@@ -64,15 +64,15 @@ Mirai 核心由 API 模块(`mirai-core`)和协议模块组成。
**common**
```
kotlin
implementation
(
"net.mamoe:mirai-core-
timpc
-common:VERSION"
)
implementation
(
"net.mamoe:mirai-core-
qqandroid
-common:VERSION"
)
```
**jvm**
```
kotlin
implementation
(
"net.mamoe:mirai-core-
timpc
-jvm:VERSION"
)
implementation
(
"net.mamoe:mirai-core-
qqandroid
-jvm:VERSION"
)
```
**android**
```
kotlin
implementation
(
"net.mamoe:mirai-core-
timpc
-android:VERSION"
)
implementation
(
"net.mamoe:mirai-core-
qqandroid
-android:VERSION"
)
```
### Performance
Android 上, Mirai 运行需使用 80M 内存.
...
...
gradle.properties
View file @
17af6861
# style guide
kotlin.code.style
=
official
# config
mirai_version
=
0.1
3
.0
mirai_version
=
0.1
4
.0
kotlin.incremental.multiplatform
=
true
kotlin.parallel.tasks.in.project
=
true
# 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
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.MiraiDebugAPI
import
net.mamoe.mirai.utils.MiraiInternalAPI
import
net.mamoe.mirai.utils.io.discardExact
import
net.mamoe.mirai.utils.io.hexToBytes
...
...
@@ -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
}
*/
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
>
{
val
elements
=
mutableListOf
<
ImMsgBody
.
Elem
>()
...
...
@@ -203,6 +212,7 @@ internal fun MessageChain.toRichTextElems(): MutableList<ImMsgBody.Elem> {
is
CustomFaceFromServer
->
elements
.
add
(
ImMsgBody
.
Elem
(
customFace
=
it
.
delegate
))
is
NotOnlineImageFromServer
->
elements
.
add
(
ImMsgBody
.
Elem
(
notOnlineImage
=
it
.
delegate
))
is
NotOnlineImageFromFile
->
elements
.
add
(
ImMsgBody
.
Elem
(
notOnlineImage
=
it
.
toJceData
()))
is
AtAll
->
elements
.
add
(
atAllData
)
is
QuoteReply
,
is
MessageSource
->
{
...
...
@@ -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
)
{
this
.
forEach
{
when
{
...
...
@@ -306,9 +316,18 @@ internal fun List<ImMsgBody.Elem>.joinToMessageChain(message: MessageChain) {
if
(
it
.
text
.
attr6Buf
.
isEmpty
())
{
message
.
add
(
it
.
text
.
str
.
toMessage
())
}
else
{
//00 01 00 00 00 0A 00 3E 03 3F A2 00 00
val
id
=
it
.
text
.
attr6Buf
.
read
{
discardExact
(
7
);
readUInt
().
toLong
()
}
message
.
add
(
At
(
id
,
it
.
text
.
str
))
//00 01 00 00 00 05 01 00 00 00 00 00 00 all
//00 01 00 00 00 0A 00 3E 03 3F A2 00 00 one
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 {
PacketLogger
.
verbose
{
"开始处理一个包"
}
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
()
PacketLogger
.
verbose
{
"包类型(flag2) = $flag2. (可能是 ${when (flag2) {
...
...
@@ -195,19 +191,10 @@ internal object KnownPacketFactories {
readString
(
readInt
()
-
4
)
// uinAccount
//debugPrint("remaining")
/* receive
* 00 00 00 0A
* 00
* 00
* 00 00 00 05 30 // uin
*/
ByteArrayPool
.
useInstance
{
data
->
val
size
=
this
.
readAvailable
(
data
)
kotlin
.
runCatching
{
// 快速解密
when
(
flag2
)
{
2
->
data
.
decryptBy
(
DECRYPTER_16_ZERO
,
size
).
also
{
PacketLogger
.
verbose
{
"成功使用 16 zero 解密"
}
}
1
->
data
.
decryptBy
(
bot
.
client
.
wLoginSigInfo
.
d2Key
,
size
).
also
{
PacketLogger
.
verbose
{
"成功使用 d2Key 解密"
}
}
...
...
@@ -215,20 +202,17 @@ internal object KnownPacketFactories {
else
->
error
(
""
)
}
}.
getOrElse
{
// 慢速解密
PacketLogger
.
verbose
{
"失败, 尝试其他各种key"
}
bot
.
client
.
tryDecryptOrNull
(
data
,
size
)
{
it
}
}
?.
toReadPacket
()
?.
let
{
decryptedData
->
// 解析外层包装
when
(
flag1
)
{
0
x0A
->
parseSsoFrame
(
bot
,
decryptedData
)
0
x0B
->
parseSsoFrame
(
bot
,
decryptedData
)
// 这里可能是 uni?? 但测试时候发现结构跟 sso 一样.
else
->
error
(
"unknown flag1: ${flag1.toByte().toUHexString()}"
)
}
}
?.
let
{
// 处理内层真实的包
if
(
it
.
packetFactory
==
null
)
{
bot
.
logger
.
debug
(
"Received commandName: ${it.commandName}"
)
bot
.
network
.
logger
.
debug
(
"Received commandName: ${it.commandName}"
)
PacketLogger
.
warning
{
"找不到 PacketFactory"
}
PacketLogger
.
verbose
{
"传递给 PacketFactory 的数据 = ${it.data.useBytes { data, length -> data.toUHexString(length = length) }}"
}
return
...
...
@@ -236,7 +220,7 @@ internal object KnownPacketFactories {
it
.
data
.
withUse
{
when
(
flag2
)
{
0
,
1
->
//it.data.parseUniResponse(bot, it.packetFactory, it.sequenceId, consumer)
0
,
1
->
when
(
it
.
packetFactory
)
{
is
OutgoingPacketFactory
<
*
>
->
consumer
(
it
.
packetFactory
as
OutgoingPacketFactory
<
T
>,
...
...
@@ -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
)
else
->
error
(
"unknown flag2: $flag2. Body to be parsed for inner packet=${it.data.readBytes().toUHexString()}"
)
}
}
}
?:
inline
{
// 无法解析
PacketLogger
.
error
{
"任何key都无法解密: ${data.take(size).toUHexString()}"
}
return
}
...
...
@@ -279,21 +261,14 @@ internal object KnownPacketFactories {
*/
@UseExperimental
(
ExperimentalUnsignedTypes
::
class
,
MiraiInternalAPI
::
class
)
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
ssoSequenceId
:
Int
val
dataCompressed
:
Int
// head
input
.
readPacket
(
input
.
readInt
()
-
4
).
withUse
{
ssoSequenceId
=
readInt
()
PacketLogger
.
verbose
{
"sequenceId = $ssoSequenceId"
}
val
returnCode
=
readInt
()
check
(
returnCode
==
0
)
{
"returnCode = $returnCode"
}
check
(
returnCode
==
0
)
{
"returnCode = $returnCode"
}
if
(
PacketLogger
.
isEnabled
)
{
val
extraData
=
readBytes
(
readInt
()
-
4
)
PacketLogger
.
verbose
{
"(sso/inner)extraData = ${extraData.toUHexString()}"
}
...
...
@@ -361,7 +336,7 @@ internal object KnownPacketFactories {
this
.
discardExact
(
1
)
// const = 0
val
packet
=
when
(
encryptionMethod
)
{
4
->
{
// peer public key, ECDH
4
->
{
var
data
=
this
.
decryptBy
(
bot
.
client
.
ecdh
.
keyPair
.
initialShareKey
,
(
this
.
remaining
-
1
).
toInt
())
val
peerShareKey
=
bot
.
client
.
ecdh
.
calculateShareKeyByPeerPublicKey
(
readUShortLVByteArray
().
adjustToPublicKey
())
...
...
@@ -379,7 +354,7 @@ internal object KnownPacketFactories {
byteArrayBuffer
.
decryptBy
(
bot
.
client
.
ecdh
.
keyPair
.
initialShareKey
,
size
)
}.
getOrElse
{
byteArrayBuffer
.
decryptBy
(
bot
.
client
.
randomKey
,
size
)
}.
toReadPacket
()
// 这里实际上应该用 privateKey(另一个random出来的key)
}.
toReadPacket
()
}
}
else
{
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
import
net.mamoe.mirai.qqandroid.utils.guidFlag
import
net.mamoe.mirai.utils.MiraiDebugAPI
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.currentTimeSeconds
import
net.mamoe.mirai.utils.io.*
...
...
@@ -359,27 +360,30 @@ internal class WtLogin{
@UseExperimental
(
MiraiDebugAPI
::
class
)
private
fun
onSolveLoginCaptcha
(
tlvMap
:
TlvMap
,
bot
:
QQAndroidBot
):
LoginPacketResponse
.
Captcha
{
// val ret = tlvMap[0x104]?.let { println(it.toUHexString()) }
bot
.
client
.
t104
=
tlvMap
.
getOrFail
(
0
x104
)
tlvMap
[
0
x192
]
?.
let
{
bot
.
client
.
t104
=
tlvMap
.
getOrFail
(
0
x104
)
return
LoginPacketResponse
.
Captcha
.
Slider
(
it
.
encodeToString
())
}
tlvMap
[
0
x165
]
?.
let
{
question
->
if
(
question
[
18
].
toInt
()
==
0
x36
)
{
//图片验证
DebugLogger
.
debug
(
"是一个图片验证码"
)
bot
.
client
.
t104
=
tlvMap
.
getOrFail
(
0
x104
)
val
imageData
=
tlvMap
.
getOrFail
(
0
x105
).
toReadPacket
()
val
signInfoLength
=
imageData
.
readShort
()
imageData
.
discardExact
(
2
)
//image Length
val
sign
=
imageData
.
readBytes
(
signInfoLength
.
toInt
())
val
buffer
=
IoBuffer
.
Pool
.
borrow
()
imageData
.
readFully
(
buffer
)
return
LoginPacketResponse
.
Captcha
.
Picture
(
data
=
imageData
.
readBytes
().
toIoBuffer
()
,
data
=
buffer
,
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
)
...
...
mirai-core/build.gradle.kts
View file @
17af6861
...
...
@@ -61,13 +61,13 @@ kotlin {
languageSettings
.
useExperimentalAnnotation
(
"kotlin.Experimental"
)
dependencies
{
implementation
(
kotlin
(
"stdlib"
,
kotlinVersion
))
implementation
(
kotlin
(
"serialization"
,
kotlinVersion
))
api
(
kotlin
(
"stdlib"
,
kotlinVersion
))
api
(
kotlin
(
"serialization"
,
kotlinVersion
))
implementation
(
"org.jetbrains.kotlinx:atomicfu:$atomicFuVersion"
)
implementation
(
kotlinx
(
"io"
,
kotlinXIoVersion
))
implementation
(
kotlinx
(
"coroutines-io"
,
coroutinesIoVersion
))
implementation
(
kotlinx
(
"coroutines-core"
,
coroutinesVersion
))
api
(
"org.jetbrains.kotlinx:atomicfu:$atomicFuVersion"
)
api
(
kotlinx
(
"io"
,
kotlinXIoVersion
))
api
(
kotlinx
(
"coroutines-io"
,
coroutinesIoVersion
))
api
(
kotlinx
(
"coroutines-core"
,
coroutinesVersion
))
}
}
commonMain
{
...
...
mirai-core/src/commonMain/kotlin/net.mamoe.mirai/contact/Group.kt
View file @
17af6861
...
...
@@ -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
*/
@UseExperimental
(
ExperimentalContracts
::
class
)
@MessageDsl
inline
fun
CoroutineScope
.
subscribeMessages
(
crossinline
listeners
:
MessageSubscribersBuilder
<
MessagePacket
<
*
,
*
>>.()
->
Unit
)
{
inline
fun
<
R
>
CoroutineScope
.
subscribeMessages
(
crossinline
listeners
:
MessageSubscribersBuilder
<
MessagePacket
<
*
,
*
>>.()
->
R
):
R
{
// contract 可帮助 IDE 进行类型推断. 无实际代码作用.
contract
{
callsInPlace
(
listeners
,
InvocationKind
.
EXACTLY_ONCE
)
}
MessageSubscribersBuilder
{
messageListener
:
MessageListener
<
MessagePacket
<
*
,
*
>>
->
return
MessageSubscribersBuilder
{
messageListener
:
MessageListener
<
MessagePacket
<
*
,
*
>>
->
// subscribeAlways 即注册一个监听器. 这个监听器收到消息后就传递给 [listener]
// listener 即为 DSL 里 `contains(...) { }`, `startsWith(...) { }` 的代码块.
subscribeAlways
{
messageListener
.
invoke
(
this
,
this
.
message
.
toString
())
// this.message.toString() 即为 messageListener 中 it 接收到的值
}
}.
apply
{
listeners
()
}
}.
run
(
listeners
)
}
/**
...
...
@@ -50,15 +50,15 @@ inline fun CoroutineScope.subscribeMessages(crossinline listeners: MessageSubscr
*/
@UseExperimental
(
ExperimentalContracts
::
class
)
@MessageDsl
inline
fun
CoroutineScope
.
subscribeGroupMessages
(
crossinline
listeners
:
MessageSubscribersBuilder
<
GroupMessage
>.()
->
Unit
)
{
inline
fun
<
R
>
CoroutineScope
.
subscribeGroupMessages
(
crossinline
listeners
:
MessageSubscribersBuilder
<
GroupMessage
>.()
->
R
):
R
{
contract
{
callsInPlace
(
listeners
,
InvocationKind
.
EXACTLY_ONCE
)
}
MessageSubscribersBuilder
<
GroupMessage
>
{
listener
->
return
MessageSubscribersBuilder
<
GroupMessage
>
{
listener
->
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
*/
@UseExperimental
(
ExperimentalContracts
::
class
)
@MessageDsl
inline
fun
CoroutineScope
.
subscribeFriendMessages
(
crossinline
listeners
:
MessageSubscribersBuilder
<
FriendMessage
>.()
->
Unit
)
{
inline
fun
<
R
>
CoroutineScope
.
subscribeFriendMessages
(
crossinline
listeners
:
MessageSubscribersBuilder
<
FriendMessage
>.()
->
R
):
R
{
contract
{
callsInPlace
(
listeners
,
InvocationKind
.
EXACTLY_ONCE
)
}
MessageSubscribersBuilder
<
FriendMessage
>
{
listener
->
return
MessageSubscribersBuilder
<
FriendMessage
>
{
listener
->
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
*/
@UseExperimental
(
ExperimentalContracts
::
class
)
@MessageDsl
inline
fun
Bot
.
subscribeMessages
(
crossinline
listeners
:
MessageSubscribersBuilder
<
MessagePacket
<
*
,
*
>>.()
->
Unit
)
{
inline
fun
<
R
>
Bot
.
subscribeMessages
(
crossinline
listeners
:
MessageSubscribersBuilder
<
MessagePacket
<
*
,
*
>>.()
->
R
):
R
{
contract
{
callsInPlace
(
listeners
,
InvocationKind
.
EXACTLY_ONCE
)
}
MessageSubscribersBuilder
<
MessagePacket
<
*
,
*
>>
{
listener
->
return
MessageSubscribersBuilder
<
MessagePacket
<
*
,
*
>>
{
listener
->
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
*/
@UseExperimental
(
ExperimentalContracts
::
class
)
@MessageDsl
inline
fun
Bot
.
subscribeGroupMessages
(
crossinline
listeners
:
MessageSubscribersBuilder
<
GroupMessage
>.()
->
Unit
)
{
inline
fun
<
R
>
Bot
.
subscribeGroupMessages
(
crossinline
listeners
:
MessageSubscribersBuilder
<
GroupMessage
>.()
->
R
):
R
{
contract
{
callsInPlace
(
listeners
,
InvocationKind
.
EXACTLY_ONCE
)
}
MessageSubscribersBuilder
<
GroupMessage
>
{
listener
->
return
MessageSubscribersBuilder
<
GroupMessage
>
{
listener
->
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
*/
@UseExperimental
(
ExperimentalContracts
::
class
)
@MessageDsl
inline
fun
Bot
.
subscribeFriendMessages
(
crossinline
listeners
:
MessageSubscribersBuilder
<
FriendMessage
>.()
->
Unit
)
{
inline
fun
<
R
>
Bot
.
subscribeFriendMessages
(
crossinline
listeners
:
MessageSubscribersBuilder
<
FriendMessage
>.()
->
R
):
R
{
contract
{
callsInPlace
(
listeners
,
InvocationKind
.
EXACTLY_ONCE
)
}
MessageSubscribersBuilder
<
FriendMessage
>
{
listener
->
return
MessageSubscribersBuilder
<
FriendMessage
>
{
listener
->
this
.
subscribeAlways
{
it
.
listener
(
it
.
message
.
toString
())
listener
(
this
,
this
.
message
.
toString
())
}
}.
apply
{
listeners
()
}
}.
run
(
listeners
)
}
...
...
@@ -588,6 +588,12 @@ class MessageSubscribersBuilder<T : MessagePacket<*, *>>(
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
inline
infix
fun
String
.
reply
(
crossinline
replier
:
@MessageDsl
suspend
T
.(
String
)
->
Any
?):
Listener
<
T
>
{
val
toCheck
=
this
.
trim
()
...
...
mirai-core/src/commonMain/kotlin/net.mamoe.mirai/event/Subscribers.kt
View file @
17af6861
...
...
@@ -10,11 +10,13 @@
package
net.mamoe.mirai.event
import
kotlinx.coroutines.CompletableJob
import
kotlinx.coroutines.CoroutineExceptionHandler
import
kotlinx.coroutines.CoroutineScope
import
kotlinx.coroutines.GlobalScope
import
net.mamoe.mirai.Bot
import
net.mamoe.mirai.event.internal.Handler
import
net.mamoe.mirai.event.internal.subscribeInternal
import
kotlin.coroutines.CoroutineContext
/*
* 该文件为所有的订阅事件的方法.
...
...
@@ -38,6 +40,8 @@ enum class ListeningStatus {
/**
* 事件监听器.
* 由 [subscribe] 等方法返回.
*
* 取消监听: [complete]
*/
interface
Listener
<
in
E
:
Event
>
:
CompletableJob
{
suspend
fun
onEvent
(
event
:
E
):
ListeningStatus
...
...
@@ -50,11 +54,10 @@ interface Listener<in E : Event> : CompletableJob {
* 每当 [事件广播][Event.broadcast] 时, [handler] 都会被执行.
*
* 当 [handler] 返回 [ListeningStatus.STOPPED] 时停止监听.
* 或 [Listener] complete 时结束.
*
* 或 [Listener.complete] 后结束.
*
*
**注意**: 这个函数返回 [Listener], 它是一个 [CompletableJob]. 如果不手动 [CompletableJob.complete], 它将会阻止当前 [CoroutineScope] 结束
.
* 例
如
:
*
这个函数返回 [Listener], 它是一个 [CompletableJob]. 请注意它除非被 [Listener.complete] 或 [Listener.cancel], 则不会完成
.
* 例:
* ```kotlin
* runBlocking { // this: CoroutineScope
* subscribe<Event> { /* 一些处理 */
}
// 返回 Listener, 即 CompletableJob
...
...
@@ -70,23 +73,37 @@ interface Listener<in E : Event> : CompletableJob {
*
```
*
*
*
要创建一个仅在机器人在线时的监听
,
请在
[
Bot
]
下调用本函数
(
因为
[
Bot
]
也实现
[
CoroutineScope
]):
*
要创建一个仅在
某个
机器人在线时的监听
,
请在
[
Bot
]
下调用本函数
(
因为
[
Bot
]
也实现
[
CoroutineScope
]):
*
``
`kotlin
*
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
subscribeGroupMessages
监听群消息
*
@
see
subscribeFriendMessages
监听好友消息
*
@
see
subscribeGroupMessages
监听群消息
DSL
*
@
see
subscribeFriendMessages
监听好友消息
DSL
*/
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] 及其子类事件.
* 每当 [事件广播][Event.broadcast] 时, [listener] 都会被执行.
*
* 仅当 [Listener
] complete
时结束.
* 仅当 [Listener
.complete] 或 [Listener.cancel]
时结束.
*
* @see subscribe 获取更多说明
*/
...
...
mirai-core/src/commonMain/kotlin/net.mamoe.mirai/event/events/BotEvents.kt
View file @
17af6861
...
...
@@ -29,6 +29,8 @@ class EventCancelledException : RuntimeException {
constructor
(
cause
:
Throwable
?)
:
super
(
cause
)
}
// note: 若你使用 IntelliJ IDEA, 按 alt + 7 可打开结构
// region Bot 状态
...
...
mirai-core/src/commonMain/kotlin/net.mamoe.mirai/event/events/types.kt
View file @
17af6861
...
...
@@ -53,7 +53,7 @@ interface GroupMemberEvent : GroupEvent {
/**
* 有关
群
的事件
* 有关
好友
的事件
*/
interface
FriendEvent
:
BotEvent
{
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
import
net.mamoe.mirai.contact.Member
import
net.mamoe.mirai.contact.MemberPermission
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.utils.getValue
import
net.mamoe.mirai.utils.unsafeWeakRef
import
kotlin.jvm.JvmName
@Suppress
(
"unused"
,
"NOTHING_TO_INLINE"
)
class
GroupMessage
(
...
...
@@ -37,6 +39,28 @@ class GroupMessage(
inline
fun
At
.
member
():
Member
=
group
[
this
.
target
]
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
=
"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
/**
* At 一个人. 只能发送给一个群.
*
* @see AtAll 全体成员
*/
class
At
@MiraiInternalAPI
constructor
(
val
target
:
Long
,
val
display
:
String
)
:
Message
{
@UseExperimental
(
MiraiInternalAPI
::
class
)
...
...
@@ -33,10 +35,10 @@ class At @MiraiInternalAPI constructor(val target: Long, val display: String) :
// 自动为消息补充 " "
override
fun
followedBy
(
tail
:
Message
):
MessageChain
{
if
(
tail
is
PlainText
&&
!
tail
.
stringValue
.
startsWith
(
' '
)){
return
super
.
followedBy
(
PlainText
(
" "
))
+
tail
if
(
tail
is
PlainText
&&
tail
.
stringValue
.
startsWith
(
' '
)){
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 {
*/
var
parentCoroutineContext
:
CoroutineContext
=
EmptyCoroutineContext
/**
* 连接每个服务器的时间
*/
var
touchTimeoutMillis
:
Long
=
1
.
secondsToMillis
/**
* 是否使用随机的设备名.
* 使用随机可以降低被封禁的风险, 但可能导致每次登录都需要输入验证码
* 当一台设备只登录少量账号时, 将此项设置为 `false` 可能更好.
*/
var
randomDeviceName
:
Boolean
=
false
/**
* 心跳周期. 过长会导致被服务器断开连接.
*/
...
...
@@ -85,20 +75,10 @@ class BotConfiguration {
* 最多尝试多少次重连
*/
var
reconnectionRetryTimes
:
Int
=
3
/**
* 有验证码要求就失败
*/
var
failOnCaptcha
=
false
/**
* 验证码处理器
*/
var
loginSolver
:
LoginSolver
=
defaultLoginSolver
/**
* 登录完成后几秒会收到好友消息的历史记录,
* 这些历史记录不会触发事件.
* 这个选项为是否把这些记录添加到日志
*/
var
logPreviousMessages
:
Boolean
=
false
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
import
kotlinx.io.core.*
import
kotlinx.io.pool.useInstance
import
net.mamoe.mirai.utils.DefaultLogger
import
net.mamoe.mirai.utils.MiraiDebugAPI
import
net.mamoe.mirai.utils.MiraiLogger
import
net.mamoe.mirai.utils.withSwitch
import
net.mamoe.mirai.utils.*
import
kotlin.contracts.ExperimentalContracts
import
kotlin.contracts.InvocationKind
import
kotlin.contracts.contract
...
...
@@ -28,7 +25,7 @@ import kotlin.jvm.JvmName
@MiraiDebugAPI
(
"Unsatble"
)
object
DebugLogger
:
MiraiLogger
by
DefaultLogger
(
"Packet Debug"
).
withSwitch
(
)
val
DebugLogger
:
MiraiLoggerWithSwitch
=
DefaultLogger
(
"Packet Debug"
).
withSwitch
(
false
)
@MiraiDebugAPI
(
"Unstable"
)
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 {
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 @@
package
demo.subscribe
import
kotlinx.coroutines.CompletableJob
import
net.mamoe.mirai.Bot
import
net.mamoe.mirai.BotAccount
import
net.mamoe.mirai.alsoLogin
...
...
@@ -19,6 +20,7 @@ import net.mamoe.mirai.contact.sendMessage
import
net.mamoe.mirai.event.*
import
net.mamoe.mirai.message.FriendMessage
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.PlainText
import
net.mamoe.mirai.message.data.firstOrNull
...
...
@@ -44,12 +46,13 @@ private fun readTestAccount(): BotAccount? {
@Suppress
(
"UNUSED_VARIABLE"
)
suspend
fun
main
()
{
val
bot
=
QQAndroid
.
Bot
(
// JVM 下也可以不写 `
TIMPC
.` 引用顶层函数
1
994701121
,
val
bot
=
QQAndroid
.
Bot
(
// JVM 下也可以不写 `
QQAndroid
.` 引用顶层函数
1
23456789
,
"123456"
)
{
// 覆盖默认的配置
randomDeviceName
=
false
// networkLoggerSupplier = { SilentLogger } // 禁用网络层输出
}.
alsoLogin
()
bot
.
messageDSL
()
...
...
@@ -96,7 +99,7 @@ fun Bot.messageDSL() {
// it: String (MessageChain.toString)
message
[
Image
].
download
()
// message[Image].download() // 还未支持 download
if
(
this
is
GroupMessage
)
{
//如果是群消息
// group: Group
...
...
@@ -118,6 +121,7 @@ fun Bot.messageDSL() {
// 当收到 "我的qq" 就执行 lambda 并回复 lambda 的返回值 String
"我的qq"
reply
{
sender
.
id
}
"at all"
reply
AtAll
// at 全体成员
// 如果是这个 QQ 号发送的消息(可以是好友消息也可以是群消息)
sentBy
(
123456789
)
{
...
...
@@ -133,12 +137,27 @@ fun Bot.messageDSL() {
}
// 当消息中包含 "复读" 时
val
listener
=
(
contains
(
"复读1"
)
or
contains
(
"复读2"
))
{
reply
(
message
)
// listener 管理
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 的消息.
// 也可以用任何能在处理时使用的变量, 如 subject, sender, message
...
...
@@ -196,19 +215,19 @@ suspend fun directlySubscribe(bot: Bot) {
// 在当前协程作用域 (CoroutineScope) 下创建一个子 Job, 监听一个事件.
//
// 手动处理消息
// 使用 Bot 的扩展方法监听, 将在处理事件时得到一个 this: Bot.
// 这样可以调用 Bot 内的一些扩展方法如 UInt.qq():QQ
//
// 这个函数返回 Listener, Listener 是一个 CompletableJob. 如果不手动 close 它, 它会一直阻止当前 CoroutineScope 结束.
// subscribeAlways 函数返回 Listener, Listener 是一个 CompletableJob.
//
// 例如:
// ```kotlin
// runBlocking {// this: CoroutineScope
//
bot.
subscribeAlways<FriendMessage> {
// subscribeAlways<FriendMessage> {
// }
// }
// ```
// 则这个 `runBlocking` 永远不会结束, 因为 `subscribeAlways` 在 `runBlocking` 的 `CoroutineScope` 下创建了一个 Job.
// 正确的用法为:
// 在 Bot 的 CoroutineScope 下创建一个监听事件的 Job, 则这个子 Job 会在 Bot 离线后自动完成 (complete).
bot
.
subscribeAlways
<
FriendMessage
>
{
// this: 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) {
Jsoup
.
connect
(
"https://api.lolicon.app/setu/?r18=$r18"
+
if
(
keyword
.
isNotBlank
())
"&keyword=$keyword&num=10"
else
""
)
.
ignoreContentType
(
true
)
.
userAgent
(
UserAgent
.
randomUserAgent
)
.
proxy
(
"127.0.0.1"
,
1088
)
//
.proxy("127.0.0.1", 1088)
.
timeout
(
10
_0000
)
.
get
().
body
().
text
()
)
...
...
@@ -60,7 +60,7 @@ class GentleImage(val contact: Contact, val keyword: String) {
.
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"
)
.
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
)
.
maxBodySize
(
10000000
)
.
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