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
e9c79429
Commit
e9c79429
authored
Feb 22, 2020
by
jiahua.liu
Browse files
Options
Browse Files
Download
Plain Diff
Merge remote-tracking branch 'origin/master'
parents
5847ac85
7e3ede0d
Changes
64
Hide whitespace changes
Inline
Side-by-side
Showing
64 changed files
with
1517 additions
and
361 deletions
+1517
-361
CHANGELOG.md
CHANGELOG.md
+32
-1
build.gradle
build.gradle
+2
-6
docs/guide_build_for_mirai.md
docs/guide_build_for_mirai.md
+186
-0
docs/guide_getting_started.md
docs/guide_getting_started.md
+4
-2
docs/guide_subscribe_events.md
docs/guide_subscribe_events.md
+116
-0
gradle.properties
gradle.properties
+1
-1
mirai-api-http/EventType_CH.md
mirai-api-http/EventType_CH.md
+0
-0
mirai-api-http/README_CH.md
mirai-api-http/README_CH.md
+3
-3
mirai-api-http/src/main/kotlin/net/mamoe/mirai/api/http/data/StateCode.kt
...rc/main/kotlin/net/mamoe/mirai/api/http/data/StateCode.kt
+2
-1
mirai-api-http/src/main/kotlin/net/mamoe/mirai/api/http/data/common/MessageDTO.kt
...kotlin/net/mamoe/mirai/api/http/data/common/MessageDTO.kt
+12
-7
mirai-api-http/src/main/kotlin/net/mamoe/mirai/api/http/queue/MessageQueue.kt
...ain/kotlin/net/mamoe/mirai/api/http/queue/MessageQueue.kt
+12
-6
mirai-api-http/src/main/kotlin/net/mamoe/mirai/api/http/route/BaseRoute.kt
...c/main/kotlin/net/mamoe/mirai/api/http/route/BaseRoute.kt
+4
-0
mirai-api-http/src/main/kotlin/net/mamoe/mirai/api/http/route/MessageRouteModule.kt
...tlin/net/mamoe/mirai/api/http/route/MessageRouteModule.kt
+20
-3
mirai-console-graphical/src/main/kotlin/net/mamoe/mirai/console/graphical/controller/MiraiGraphicalUIController.kt
...onsole/graphical/controller/MiraiGraphicalUIController.kt
+17
-0
mirai-console-graphical/src/main/kotlin/net/mamoe/mirai/console/graphical/model/PluginModel.kt
...in/net/mamoe/mirai/console/graphical/model/PluginModel.kt
+19
-0
mirai-console-graphical/src/main/kotlin/net/mamoe/mirai/console/graphical/util/JFoenixAdaptor.kt
.../net/mamoe/mirai/console/graphical/util/JFoenixAdaptor.kt
+4
-0
mirai-console-graphical/src/main/kotlin/net/mamoe/mirai/console/graphical/view/PluginsView.kt
...lin/net/mamoe/mirai/console/graphical/view/PluginsView.kt
+22
-0
mirai-console-graphical/src/main/kotlin/net/mamoe/mirai/console/graphical/view/PrimaryView.kt
...lin/net/mamoe/mirai/console/graphical/view/PrimaryView.kt
+16
-5
mirai-console-graphical/src/main/kotlin/net/mamoe/mirai/console/graphical/view/SettingsView.kt
...in/net/mamoe/mirai/console/graphical/view/SettingsView.kt
+23
-0
mirai-core-qqandroid/src/commonMain/kotlin/net/mamoe/mirai/qqandroid/ContactImpl.kt
...ommonMain/kotlin/net/mamoe/mirai/qqandroid/ContactImpl.kt
+77
-23
mirai-core-qqandroid/src/commonMain/kotlin/net/mamoe/mirai/qqandroid/message/MessageSourceFromMsg.kt
...net/mamoe/mirai/qqandroid/message/MessageSourceFromMsg.kt
+18
-7
mirai-core-qqandroid/src/commonMain/kotlin/net/mamoe/mirai/qqandroid/message/messages.kt
...Main/kotlin/net/mamoe/mirai/qqandroid/message/messages.kt
+22
-12
mirai-core-qqandroid/src/commonMain/kotlin/net/mamoe/mirai/qqandroid/network/QQAndroidBotNetworkHandler.kt
...moe/mirai/qqandroid/network/QQAndroidBotNetworkHandler.kt
+16
-19
mirai-core-qqandroid/src/commonMain/kotlin/net/mamoe/mirai/qqandroid/network/protocol/data/proto/MsgRevokeUserDef.kt
...qqandroid/network/protocol/data/proto/MsgRevokeUserDef.kt
+38
-0
mirai-core-qqandroid/src/commonMain/kotlin/net/mamoe/mirai/qqandroid/network/protocol/data/proto/MsgSvc.kt
...moe/mirai/qqandroid/network/protocol/data/proto/MsgSvc.kt
+1
-1
mirai-core-qqandroid/src/commonMain/kotlin/net/mamoe/mirai/qqandroid/network/protocol/packet/PacketFactory.kt
.../mirai/qqandroid/network/protocol/packet/PacketFactory.kt
+3
-1
mirai-core-qqandroid/src/commonMain/kotlin/net/mamoe/mirai/qqandroid/network/protocol/packet/chat/PbMessageSvc.kt
...ai/qqandroid/network/protocol/packet/chat/PbMessageSvc.kt
+91
-0
mirai-core-qqandroid/src/commonMain/kotlin/net/mamoe/mirai/qqandroid/network/protocol/packet/chat/receive/MessageSvc.kt
...ndroid/network/protocol/packet/chat/receive/MessageSvc.kt
+87
-10
mirai-core-qqandroid/src/commonMain/kotlin/net/mamoe/mirai/qqandroid/network/protocol/packet/chat/receive/OnlinePush.kt
...ndroid/network/protocol/packet/chat/receive/OnlinePush.kt
+13
-5
mirai-core-qqandroid/src/jvmTest/kotlin/androidPacketTests/clientToServer.kt
...d/src/jvmTest/kotlin/androidPacketTests/clientToServer.kt
+2
-0
mirai-core-qqandroid/src/jvmTest/kotlin/test/ProtoBufDataClassGenerator.kt
...oid/src/jvmTest/kotlin/test/ProtoBufDataClassGenerator.kt
+1
-1
mirai-core/src/androidMain/kotlin/net/mamoe/mirai/message/MessagePacket.kt
...droidMain/kotlin/net/mamoe/mirai/message/MessagePacket.kt
+1
-2
mirai-core/src/commonMain/kotlin/net.mamoe.mirai/Bot.kt
mirai-core/src/commonMain/kotlin/net.mamoe.mirai/Bot.kt
+1
-3
mirai-core/src/commonMain/kotlin/net.mamoe.mirai/contact/Contact.kt
.../src/commonMain/kotlin/net.mamoe.mirai/contact/Contact.kt
+8
-2
mirai-core/src/commonMain/kotlin/net.mamoe.mirai/contact/ContactList.kt
.../commonMain/kotlin/net.mamoe.mirai/contact/ContactList.kt
+9
-0
mirai-core/src/commonMain/kotlin/net.mamoe.mirai/contact/Group.kt
...re/src/commonMain/kotlin/net.mamoe.mirai/contact/Group.kt
+88
-1
mirai-core/src/commonMain/kotlin/net.mamoe.mirai/contact/Member.kt
...e/src/commonMain/kotlin/net.mamoe.mirai/contact/Member.kt
+3
-0
mirai-core/src/commonMain/kotlin/net.mamoe.mirai/contact/QQ.kt
...-core/src/commonMain/kotlin/net.mamoe.mirai/contact/QQ.kt
+18
-0
mirai-core/src/commonMain/kotlin/net.mamoe.mirai/data/GroupInfo.kt
...e/src/commonMain/kotlin/net.mamoe.mirai/data/GroupInfo.kt
+11
-0
mirai-core/src/commonMain/kotlin/net.mamoe.mirai/event/Event.kt
...core/src/commonMain/kotlin/net.mamoe.mirai/event/Event.kt
+0
-0
mirai-core/src/commonMain/kotlin/net.mamoe.mirai/event/linear.kt
...ore/src/commonMain/kotlin/net.mamoe.mirai/event/linear.kt
+112
-0
mirai-core/src/commonMain/kotlin/net.mamoe.mirai/event/subscribeMessages.kt
...monMain/kotlin/net.mamoe.mirai/event/subscribeMessages.kt
+0
-0
mirai-core/src/commonMain/kotlin/net.mamoe.mirai/event/subscriber.kt
...src/commonMain/kotlin/net.mamoe.mirai/event/subscriber.kt
+3
-0
mirai-core/src/commonMain/kotlin/net.mamoe.mirai/message/FriendMessage.kt
...ommonMain/kotlin/net.mamoe.mirai/message/FriendMessage.kt
+6
-2
mirai-core/src/commonMain/kotlin/net.mamoe.mirai/message/GroupMessage.kt
...commonMain/kotlin/net.mamoe.mirai/message/GroupMessage.kt
+17
-13
mirai-core/src/commonMain/kotlin/net.mamoe.mirai/message/MessagePacket.kt
...ommonMain/kotlin/net.mamoe.mirai/message/MessagePacket.kt
+61
-22
mirai-core/src/commonMain/kotlin/net.mamoe.mirai/message/MessageReceipt.kt
...mmonMain/kotlin/net.mamoe.mirai/message/MessageReceipt.kt
+126
-0
mirai-core/src/commonMain/kotlin/net.mamoe.mirai/message/data/At.kt
.../src/commonMain/kotlin/net.mamoe.mirai/message/data/At.kt
+0
-4
mirai-core/src/commonMain/kotlin/net.mamoe.mirai/message/data/AtAll.kt
...c/commonMain/kotlin/net.mamoe.mirai/message/data/AtAll.kt
+4
-2
mirai-core/src/commonMain/kotlin/net.mamoe.mirai/message/data/Face.kt
...rc/commonMain/kotlin/net.mamoe.mirai/message/data/Face.kt
+0
-4
mirai-core/src/commonMain/kotlin/net.mamoe.mirai/message/data/Image.kt
...c/commonMain/kotlin/net.mamoe.mirai/message/data/Image.kt
+0
-5
mirai-core/src/commonMain/kotlin/net.mamoe.mirai/message/data/MessageChain.kt
...nMain/kotlin/net.mamoe.mirai/message/data/MessageChain.kt
+17
-125
mirai-core/src/commonMain/kotlin/net.mamoe.mirai/message/data/MessageSource.kt
...Main/kotlin/net.mamoe.mirai/message/data/MessageSource.kt
+25
-8
mirai-core/src/commonMain/kotlin/net.mamoe.mirai/message/data/PlainText.kt
...mmonMain/kotlin/net.mamoe.mirai/message/data/PlainText.kt
+1
-19
mirai-core/src/commonMain/kotlin/net.mamoe.mirai/message/data/XML.kt
...src/commonMain/kotlin/net.mamoe.mirai/message/data/XML.kt
+0
-4
mirai-core/src/commonMain/kotlin/net.mamoe.mirai/utils/ExternalImage.kt
.../commonMain/kotlin/net.mamoe.mirai/utils/ExternalImage.kt
+32
-11
mirai-core/src/commonMain/kotlin/net.mamoe.mirai/utils/LockFreeLinkedList.kt
...onMain/kotlin/net.mamoe.mirai/utils/LockFreeLinkedList.kt
+4
-0
mirai-core/src/commonMain/kotlin/net.mamoe.mirai/utils/io/ByteArrayPool.kt
...mmonMain/kotlin/net.mamoe.mirai/utils/io/ByteArrayPool.kt
+1
-1
mirai-core/src/jvmMain/kotlin/net/mamoe/mirai/message/MessagePacket.kt
...c/jvmMain/kotlin/net/mamoe/mirai/message/MessagePacket.kt
+1
-2
mirai-demos/mirai-demo-1/src/main/java/demo/subscribe/SubscribeSamples.kt
...i-demo-1/src/main/java/demo/subscribe/SubscribeSamples.kt
+23
-7
mirai-japt/src/main/java/net/mamoe/mirai/japt/BlockingContact.java
...t/src/main/java/net/mamoe/mirai/japt/BlockingContact.java
+4
-4
mirai-japt/src/main/java/net/mamoe/mirai/japt/BlockingGroup.java
...apt/src/main/java/net/mamoe/mirai/japt/BlockingGroup.java
+33
-0
mirai-japt/src/main/java/net/mamoe/mirai/japt/BlockingQQ.java
...i-japt/src/main/java/net/mamoe/mirai/japt/BlockingQQ.java
+37
-0
mirai-japt/src/main/kotlin/net/mamoe/mirai/japt/internal/BlockingContactsImpl.kt
...lin/net/mamoe/mirai/japt/internal/BlockingContactsImpl.kt
+7
-6
No files found.
CHANGELOG.md
View file @
e9c79429
...
@@ -2,6 +2,37 @@
...
@@ -2,6 +2,37 @@
开发版本. 频繁更新, 不保证高稳定性
开发版本. 频繁更新, 不保证高稳定性
## `0.19.1` 2020/2/21
### mirai-core
-
支持机器人撤回群消息 (含自己发送的消息):
`Group.recall`
,
`MessageReceipt.recall`
-
支持一定时间后自动撤回:
`Group.recallIn`
,
`MessageReceipt.recallIn`
-
`sendMessage`
返回
`MessageReceipt`
以实现撤回功能
-
添加
`MessageChain.addOrRemove`
-
添加
`ContactList.firstOrNull`
,
`ContactList.first`
-
新的异步事件监听方式:
`subscribingGetAsync`
启动一个协程并从一个事件从获取返回值到
`Deferred`
.
-
新的线性事件监听方式:
`subscribingGet`
挂起当前协程并从一个事件从获取返回值.
##### 新的线性消息连续处理: `nextMessage` 挂起当前协程并等待下一条消息:
使用该示例, 发送两条消息, 一条为 "禁言", 另一条包含一个 At
```
kotlin
case
(
"禁言"
)
{
val
value
:
At
=
nextMessage
{
message
.
any
(
At
)
}[
At
]
value
.
member
().
mute
(
10
)
}
```
示例 2:
```
kotlin
case
(
"复读下一条"
)
{
reply
(
nextMessage
().
message
)
}
```
### mirai-core-qqandroid
-
修复一些情况下
`At`
无法发送的问题
-
统一 ImageId: 群消息收到的 ImageId 均为
`{xxxxxxxx-xxxx-xxxx-xxxxxxxxxxxx}.jpg`
形式(固定长度 37)
-
支持成员主动离开事件的解析 (#51)
## `0.18.0` 2020/2/20
## `0.18.0` 2020/2/20
### mirai-core
### mirai-core
...
@@ -212,7 +243,7 @@ TIMPC
...
@@ -212,7 +243,7 @@ TIMPC
## `0.10.0` *2019/12/23*
## `0.10.0` *2019/12/23*
**事件优化**
**事件优化**
更快的监听过程
更快的监听过程
现在监听不再是
`suspend`
, 而必须显式指定
`CoroutineScope`
. 详见
[
`Subscribers.kt`
](
mirai-core/src/commonMain/kotlin/net.mamoe.mirai/event/Subscribers.kt#L69
)
现在监听不再是
`suspend`
, 而必须显式指定
`CoroutineScope`
. 详见
`Subscribers.kt`
删除原本的 bot.subscribe 等监听模式.
删除原本的 bot.subscribe 等监听模式.
**其他**
**其他**
...
...
build.gradle
View file @
e9c79429
buildscript
{
buildscript
{
repositories
{
repositories
{
mavenLocal
()
mavenLocal
()
maven
{
url
"https://mirrors.huaweicloud.com/repository/maven"
}
jcenter
()
jcenter
()
mavenCentral
()
mavenCentral
()
google
()
google
()
...
@@ -9,7 +10,6 @@ buildscript {
...
@@ -9,7 +10,6 @@ buildscript {
}
}
dependencies
{
dependencies
{
// Do try to waste your time.
classpath
'com.android.tools.build:gradle:3.5.3'
classpath
'com.android.tools.build:gradle:3.5.3'
classpath
"org.jetbrains.kotlin:kotlin-gradle-plugin:$kotlinVersion"
classpath
"org.jetbrains.kotlin:kotlin-gradle-plugin:$kotlinVersion"
classpath
(
"com.github.jengelman.gradle.plugins:shadow:5.2.0"
)
classpath
(
"com.github.jengelman.gradle.plugins:shadow:5.2.0"
)
...
@@ -32,14 +32,10 @@ allprojects {
...
@@ -32,14 +32,10 @@ allprojects {
group
=
"net.mamoe"
group
=
"net.mamoe"
version
=
getProperty
(
"mirai_version"
)
version
=
getProperty
(
"mirai_version"
)
// tasks.withType(KotlinCompile).all { task ->
// task.kotlinOptions{
// jvmTarget = '1.6'
// }
// }
repositories
{
repositories
{
mavenLocal
()
mavenLocal
()
maven
{
url
"https://mirrors.huaweicloud.com/repository/maven"
}
jcenter
()
jcenter
()
mavenCentral
()
mavenCentral
()
google
()
google
()
...
...
docs/guide_build_for_mirai.md
0 → 100644
View file @
e9c79429
# Mirai Guide - Build For Mirai
由于Mirai项目在快速推进中,因此内容时有变动,本文档的最后更新日期为
```2020-02-22```
,对应版本
```0.19.1```
本页面采用Kotlin作为开发语言,
**若你希望使用 Java 开发**
, 请参阅:
[
mirai-japt
](
mirai-japt/README.md
)
本页面是
[
Mirai Guide - Subscribe Events
](
/docs/guide_subscribe_events.md
)
的后续Guide
## build.gradle
我们首先来看一下完整的
```build.gradle```
文件
```
groovy
plugins
{
id
'java'
id
'org.jetbrains.kotlin.jvm'
version
'1.3.61'
}
group
'test'
version
'1.0-SNAPSHOT'
sourceCompatibility
=
1.8
repositories
{
mavenCentral
()
jcenter
()
}
dependencies
{
implementation
'net.mamoe:mirai-core-qqandroid-jvm:0.19.1'
implementation
"org.jetbrains.kotlin:kotlin-stdlib-jdk8"
testCompile
group:
'junit'
,
name:
'junit'
,
version:
'4.12'
}
compileKotlin
{
kotlinOptions
.
jvmTarget
=
"1.8"
}
compileTestKotlin
{
kotlinOptions
.
jvmTarget
=
"1.8"
}
```
使用gradle直接打包,不会将依赖也打包进去
因此,我们引入一些插件进行打包
### ShadowJar
shadowJar支持将依赖也打包到Jar内,下面介绍用法。
#### 1.buildscript
首先声明buildScript
```
groovy
buildscript
{
repositories
{
jcenter
()
}
dependencies
{
classpath
'com.github.jengelman.gradle.plugins:shadow:5.2.0'
}
}
```
在plugin前加入以上语句
#### 2.在plugins中进行插件的使用
将原本的plugins
```
groovy
plugins
{
id
'java'
id
'org.jetbrains.kotlin.jvm'
version
'1.3.61'
}
```
覆盖为
```
groovy
plugins
{
id
'java'
id
'org.jetbrains.kotlin.jvm'
version
'1.3.61'
id
'com.github.johnrengelman.shadow'
version
'5.2.0'
//使用shadow对依赖进行打包
}
apply
plugin:
'com.github.johnrengelman.shadow'
apply
plugin:
'java'
```
#### 3.添加shadowJar
在文件底部添加
```
groovy
shadowJar
{
// 生成包的命名规则: baseName-version-classifier.jar
manifest
{
attributes
(
'Main-Class'
:
'net.mamoe.mirai.simpleloader.MyLoaderKt'
//入口点
)
}
// 将 build.gradle 打入到 jar 中, 方便查看依赖包版本
from
(
"./"
){
include
'build.gradle'
}
}
```
#### 4.运行build
在IDEA中点击
```ShadowJar```
左侧的run按钮(绿色小三角),build完成后在
```build\libs```
中找到jar
至此,build.gradle内的内容是
```
groovy
buildscript
{
repositories
{
jcenter
()
}
dependencies
{
classpath
'com.github.jengelman.gradle.plugins:shadow:5.2.0'
}
}
plugins
{
id
'java'
id
'org.jetbrains.kotlin.jvm'
version
'1.3.61'
id
'com.github.johnrengelman.shadow'
version
'5.2.0'
//使用shadow对依赖进行打包
}
apply
plugin:
'com.github.johnrengelman.shadow'
apply
plugin:
'java'
group
'test'
version
'1.0-SNAPSHOT'
sourceCompatibility
=
1.8
repositories
{
mavenCentral
()
jcenter
()
}
dependencies
{
implementation
'net.mamoe:mirai-core-qqandroid-jvm:0.19.1'
implementation
"org.jetbrains.kotlin:kotlin-stdlib-jdk8"
testCompile
group:
'junit'
,
name:
'junit'
,
version:
'4.12'
}
compileKotlin
{
kotlinOptions
.
jvmTarget
=
"1.8"
}
compileTestKotlin
{
kotlinOptions
.
jvmTarget
=
"1.8"
}
shadowJar
{
// 生成包的命名规则: baseName-version-classifier.jar
manifest
{
attributes
(
'Main-Class'
:
'net.mamoe.mirai.simpleloader.MyLoaderKt'
)
}
// 将 build.gradle 打入到 jar 中, 方便查看依赖包版本
from
(
"./"
){
include
'build.gradle'
}
}
```
docs/guide_getting_started.md
View file @
e9c79429
...
@@ -26,6 +26,8 @@ JDK要求6以上
...
@@ -26,6 +26,8 @@ JDK要求6以上
### 2 新建Gradle项目
### 2 新建Gradle项目
*
使用gradle项目可能需要代理,在IDEA的
```settings```
->
```proxy settings```
中可以设置
-
在
```File->new project```
中选择
```Gradle```
-
在
```File->new project```
中选择
```Gradle```
-
在面板中的
```Additional Libraries and Frameworks```
中勾选
```Java```
以及
```Kotlin/JVM```
-
在面板中的
```Additional Libraries and Frameworks```
中勾选
```Java```
以及
```Kotlin/JVM```
-
点击
```next```
,填入
```GroupId```
与
```ArtifactId```
(对于测试项目来说,可随意填写)
-
点击
```next```
,填入
```GroupId```
与
```ArtifactId```
(对于测试项目来说,可随意填写)
...
@@ -69,7 +71,7 @@ JDK要求6以上
...
@@ -69,7 +71,7 @@ JDK要求6以上
### 4 Try Bot
### 4 Try Bot
-
在src/main文件夹下新建文件夹,命名为
```kotlin```
-
在src/main文件夹下新建文件夹,命名为
```kotlin```
-
在
```kotlin```
下新建包(在
```kotlin```
文件夹上右键-
```New```
-
```Package
s
```
) 包名为
```net.mamoe.mirai.simpleloader```
-
在
```kotlin```
下新建包(在
```kotlin```
文件夹上右键-
```New```
-
```Package```
) 包名为
```net.mamoe.mirai.simpleloader```
-
在包下新建kotlin文件
```MyLoader.kt```
-
在包下新建kotlin文件
```MyLoader.kt```
...
@@ -103,9 +105,9 @@ suspend fun main() {
...
@@ -103,9 +105,9 @@ suspend fun main() {
-
本例的功能中,在任意群内任意成员发送包含“舔”字或“刘老板”字样的消息,MiraiBot会回复“刘老板太强了”
-
本例的功能中,在任意群内任意成员发送包含“舔”字或“刘老板”字样的消息,MiraiBot会回复“刘老板太强了”
至此,简单的入门已经结束,下面可根据不同的需求参阅wiki进行功能的添加。
至此,简单的入门已经结束,下面可根据不同的需求参阅wiki进行功能的添加。
下面,可以尝试对不同事件进行监听
[
Mirai Guide - Subscribe Events
](
/docs/guide_subscribe_events.md
)
### 此外,还可以使用Maven作为包管理工具
### 此外,还可以使用Maven作为包管理工具
本项目推荐使用gradle,因此不提供详细入门指导
本项目推荐使用gradle,因此不提供详细入门指导
...
...
docs/guide_subscribe_events.md
0 → 100644
View file @
e9c79429
# Mirai Guide - Subscribe Events
由于Mirai项目在快速推进中,因此内容时有变动,本文档的最后更新日期为
```2020-02-21```
,对应版本
```0.17.0```
本页面采用Kotlin作为开发语言,
**若你希望使用 Java 开发**
, 请参阅:
[
mirai-japt
](
mirai-japt/README.md
)
本页面是
[
Mirai Guide - Getting Started
](
/docs/guide_getting_started.md
)
的后续Guide
## 消息事件-Message Event
首先我们来回顾上一个Guide的源码
```
kotlin
suspend
fun
main
()
{
val
qqId
=
10000L
//Bot的QQ号,需为Long类型,在结尾处添加大写L
val
password
=
"your_password"
//Bot的密码
val
miraiBot
=
Bot
(
qqId
,
password
).
alsoLogin
()
//新建Bot并登录
miraiBot
.
subscribeMessages
{
"你好"
reply
"你好!"
case
(
"at me"
)
{
reply
(
sender
.
at
()
+
" 给爷爬 "
)
}
(
contains
(
"舔"
)
or
contains
(
"刘老板"
))
{
"刘老板太强了"
.
reply
()
}
}
miraiBot
.
join
()
// 等待 Bot 离线, 避免主线程退出
}
```
在本例中,
```miraiBot```
是一个Bot对象,让其登录,然后对
```Message Event```
进行了监听。
对于
``````Message Event``````
,
```Mirai```
提供了较其他Event更强大的
[
MessageSubscribersBuilder
](
https://github.com/mamoe/mirai/wiki/mirai-core/src/commonMain/kotlin/net.mamoe.mirai/event/MessageSubscribers.kt#L140
)
,本例也采用了
[
MessageSubscribersBuilder
](
https://github.com/mamoe/mirai/wiki/mirai-core/src/commonMain/kotlin/net.mamoe.mirai/event/MessageSubscribers.kt#L140
)
。其他具体使用方法可以参考
[
Wiki:Message Event
](
https://github.com/mamoe/mirai/wiki/Development-Guide---Kotlin#Message-Event
)
部分。
## 事件-Event
上一节中提到的
```Message Event```
仅仅是众多
```Event```
的这一种,其他
```Event```
有群员加入群,离开群,私聊等等...
具体doc暂不提供,现可翻阅源码
[
**BotEvents.kt**
](
https://github.com/mamoe/mirai/blob/master/mirai-core/src/commonMain/kotlin/net.mamoe.mirai/event/events/BotEvents.kt
)
,查看注释。当前事件仍在扩充中,可能有一定不足。
下面我们开始示例对一些事件进行监听。
## 尝试监听事件-Try Subscribing Events
### 监听加群事件
在代码中的
```miraiBot.join()```
前添加
```
kotlin
miraiBot
.
subscribeAlways
<
MemberJoinEvent
>
{
it
.
group
.
sendMessage
(
"欢迎 ${it.member.nameCardOrNick} 加入本群!"
)
}
```
本段语句监听了加入群的事件。
### 监听禁言事件
在代码中添加
```
kotlin
miraiBot
.
subscribeAlways
<
MemberMuteEvent
>
(){
it
.
group
.
sendMessage
(
"恭喜老哥 ${it.member.nameCardOrNick} 喜提禁言套餐一份"
)
}
```
在被禁言后,Bot将发送恭喜语句。
### 添加后的可执行代码
至此,当前的代码为
```
kotlin
package
net.mamoe.mirai.simpleloader
import
kotlinx.coroutines.*
import
net.mamoe.mirai.Bot
import
net.mamoe.mirai.alsoLogin
import
net.mamoe.mirai.event.subscribeMessages
import
net.mamoe.mirai.contact.nameCardOrNick
import
net.mamoe.mirai.contact.sendMessage
import
net.mamoe.mirai.event.events.MemberJoinEvent
import
net.mamoe.mirai.event.events.MemberMuteEvent
import
net.mamoe.mirai.event.subscribeAlways
suspend
fun
main
()
{
val
qqId
=
10000L
//Bot的QQ号,需为Long类型,在结尾处添加大写L
val
password
=
"your_password"
//Bot的密码
val
miraiBot
=
Bot
(
qqId
,
password
).
alsoLogin
()
//新建Bot并登录
miraiBot
.
subscribeMessages
{
"你好"
reply
"你好!"
case
(
"at me"
)
{
reply
(
sender
.
at
()
+
" 给爷爬 "
)
}
(
contains
(
"舔"
)
or
contains
(
"刘老板"
))
{
"刘老板太强了"
.
reply
()
}
}
miraiBot
.
subscribeAlways
<
MemberJoinEvent
>
{
it
.
group
.
sendMessage
(
"欢迎 ${it.member.nameCardOrNick} 加入本群!"
)
}
miraiBot
.
subscribeAlways
<
MemberMuteEvent
>
(){
it
.
group
.
sendMessage
(
"恭喜老哥 ${it.member.nameCardOrNick} 喜提禁言套餐一份"
)
}
miraiBot
.
join
()
// 等待 Bot 离线, 避免主线程退出
}
```
下面可以参阅
[
Mirai Guide - Build For Mirai
](
/docs/guide_build_for_mirai.md
)
,对你的Mirai应用进行打包
gradle.properties
View file @
e9c79429
# style guide
# style guide
kotlin.code.style
=
official
kotlin.code.style
=
official
# config
# config
mirai_version
=
0.1
8.0
mirai_version
=
0.1
9.1
mirai_japt_version
=
1.0.1
mirai_japt_version
=
1.0.1
kotlin.incremental.multiplatform
=
true
kotlin.incremental.multiplatform
=
true
kotlin.parallel.tasks.in.project
=
true
kotlin.parallel.tasks.in.project
=
true
...
...
mirai-api-http/EventType_C
N
.md
→
mirai-api-http/EventType_C
H
.md
View file @
e9c79429
File moved
mirai-api-http/README_CH.md
View file @
e9c79429
...
@@ -408,7 +408,7 @@ Content-Type:multipart/form-data
...
@@ -408,7 +408,7 @@ Content-Type:multipart/form-data
### 事件类型一览
### 事件类型一览
[
事件类型一览
](
./EventType_CN
.md
)
[
事件类型一览
](
EventType_CH
.md
)
> 事件为Bot被动接收的信息,无法主动构建
> 事件为Bot被动接收的信息,无法主动构建
...
@@ -430,13 +430,13 @@ Content-Type:multipart/form-data
...
@@ -430,13 +430,13 @@ Content-Type:multipart/form-data
```
json5
```
json5
{
{
"type": "Source",
"type": "Source",
"
u
id": 123456
"id": 123456
}
}
```
```
| 名字 | 类型 | 说明 |
| 名字 | 类型 | 说明 |
| ---- | ---- | ------------------------------------------------------------ |
| ---- | ---- | ------------------------------------------------------------ |
|
uid
| Long | 消息的识别号,用于引用回复(Source类型只在群消息中返回,且永远为chain的第一个元素) |
|
id
| Long | 消息的识别号,用于引用回复(Source类型只在群消息中返回,且永远为chain的第一个元素) |
#### At
#### At
...
...
mirai-api-http/src/main/kotlin/net/mamoe/mirai/api/http/data/StateCode.kt
View file @
e9c79429
package
net.mamoe.mirai.api.http.data
package
net.mamoe.mirai.api.http.data
import
kotlinx.serialization.Serializable
import
kotlinx.serialization.Serializable
import
net.mamoe.mirai.api.http.data.common.DTO
@Serializable
@Serializable
open
class
StateCode
(
val
code
:
Int
,
var
msg
:
String
)
{
open
class
StateCode
(
val
code
:
Int
,
var
msg
:
String
)
:
DTO
{
object
Success
:
StateCode
(
0
,
"success"
)
// 成功
object
Success
:
StateCode
(
0
,
"success"
)
// 成功
object
NoBot
:
StateCode
(
2
,
"指定Bot不存在"
)
object
NoBot
:
StateCode
(
2
,
"指定Bot不存在"
)
object
IllegalSession
:
StateCode
(
3
,
"Session失效或不存在"
)
object
IllegalSession
:
StateCode
(
3
,
"Session失效或不存在"
)
...
...
mirai-api-http/src/main/kotlin/net/mamoe/mirai/api/http/data/common/MessageDTO.kt
View file @
e9c79429
...
@@ -36,7 +36,7 @@ data class GroupMessagePacketDTO(val sender: MemberDTO) : MessagePacketDTO()
...
@@ -36,7 +36,7 @@ data class GroupMessagePacketDTO(val sender: MemberDTO) : MessagePacketDTO()
// Message
// Message
@Serializable
@Serializable
@SerialName
(
"Source"
)
@SerialName
(
"Source"
)
data class
MessageSourceDTO
(
val
u
id
:
Long
)
:
MessageDTO
()
data class
MessageSourceDTO
(
val
id
:
Long
)
:
MessageDTO
()
@Serializable
@Serializable
@SerialName
(
"At"
)
@SerialName
(
"At"
)
...
@@ -64,7 +64,7 @@ data class XmlDTO(val xml: String) : MessageDTO()
...
@@ -64,7 +64,7 @@ data class XmlDTO(val xml: String) : MessageDTO()
@Serializable
@Serializable
@SerialName
(
"Unknown"
)
@SerialName
(
"Unknown"
)
data class
UnknownMessageDTO
(
val
text
:
String
)
:
MessageDTO
()
object
UnknownMessageDTO
:
MessageDTO
()
/*
/*
* Abstract Class
* Abstract Class
...
@@ -88,24 +88,29 @@ fun MessagePacket<*, *>.toDTO() = when (this) {
...
@@ -88,24 +88,29 @@ fun MessagePacket<*, *>.toDTO() = when (this) {
is
GroupMessage
->
GroupMessagePacketDTO
(
MemberDTO
(
sender
))
is
GroupMessage
->
GroupMessagePacketDTO
(
MemberDTO
(
sender
))
else
->
IgnoreEventDTO
else
->
IgnoreEventDTO
}.
apply
{
}.
apply
{
if
(
this
is
MessagePacketDTO
)
{
if
(
this
is
MessagePacketDTO
)
{
messageChain
=
message
.
toDTOChain
()
}
messageChain
=
mutableListOf
<
MessageDTO
>().
also
{
ls
->
message
.
foreachContent
{
ls
.
add
(
it
.
toDTO
())
}
}
// else: `this` is bot event
}
}
fun
MessageChain
.
toDTOChain
()
=
mutableListOf
(
this
[
MessageSource
].
toDTO
()).
apply
{
foreachContent
{
content
->
content
.
toDTO
().
takeUnless
{
it
==
UnknownMessageDTO
}
?.
let
(
::
add
)
}
}
}
fun
MessageChainDTO
.
toMessageChain
(
contact
:
Contact
)
=
fun
MessageChainDTO
.
toMessageChain
(
contact
:
Contact
)
=
MessageChain
().
apply
{
this
@
toMessageChain
.
forEach
{
add
(
it
.
toMessage
(
contact
))
}
}
MessageChain
().
apply
{
this
@
toMessageChain
.
forEach
{
add
(
it
.
toMessage
(
contact
))
}
}
internal
fun
MessageSource
.
calMessageId
()
=
(
messageUid
.
toLong
()
shl
32
)
or
(
sequenceId
.
toLong
()
and
0
xFFFFFFFF
)
@UseExperimental
(
ExperimentalUnsignedTypes
::
class
)
@UseExperimental
(
ExperimentalUnsignedTypes
::
class
)
fun
Message
.
toDTO
()
=
when
(
this
)
{
fun
Message
.
toDTO
()
=
when
(
this
)
{
is
MessageSource
->
MessageSourceDTO
(
messageUid
)
is
MessageSource
->
MessageSourceDTO
(
calMessageId
()
)
is
At
->
AtDTO
(
target
,
display
)
is
At
->
AtDTO
(
target
,
display
)
is
AtAll
->
AtAllDTO
(
0L
)
is
AtAll
->
AtAllDTO
(
0L
)
is
Face
->
FaceDTO
(
id
)
is
Face
->
FaceDTO
(
id
)
is
PlainText
->
PlainDTO
(
stringValue
)
is
PlainText
->
PlainDTO
(
stringValue
)
is
Image
->
ImageDTO
(
imageId
)
is
Image
->
ImageDTO
(
imageId
)
is
XMLMessage
->
XmlDTO
(
stringValue
)
is
XMLMessage
->
XmlDTO
(
stringValue
)
else
->
UnknownMessageDTO
(
"未知消息类型"
)
else
->
UnknownMessageDTO
}
}
@UseExperimental
(
ExperimentalUnsignedTypes
::
class
,
MiraiInternalAPI
::
class
)
@UseExperimental
(
ExperimentalUnsignedTypes
::
class
,
MiraiInternalAPI
::
class
)
...
...
mirai-api-http/src/main/kotlin/net/mamoe/mirai/api/http/queue/MessageQueue.kt
View file @
e9c79429
...
@@ -11,20 +11,22 @@ package net.mamoe.mirai.api.http.queue
...
@@ -11,20 +11,22 @@ package net.mamoe.mirai.api.http.queue
import
net.mamoe.mirai.api.http.data.common.EventDTO
import
net.mamoe.mirai.api.http.data.common.EventDTO
import
net.mamoe.mirai.api.http.data.common.IgnoreEventDTO
import
net.mamoe.mirai.api.http.data.common.IgnoreEventDTO
import
net.mamoe.mirai.api.http.data.common.calMessageId
import
net.mamoe.mirai.api.http.data.common.toDTO
import
net.mamoe.mirai.api.http.data.common.toDTO
import
net.mamoe.mirai.event.events.BotEvent
import
net.mamoe.mirai.event.events.BotEvent
import
net.mamoe.mirai.message.GroupMessage
import
net.mamoe.mirai.message.GroupMessage
import
net.mamoe.mirai.message.data.MessageSource
import
net.mamoe.mirai.message.data.MessageSource
import
java.util.concurrent.ConcurrentHashMap
import
net.mamoe.mirai.utils.firstKey
import
java.util.concurrent.ConcurrentLinkedDeque
import
java.util.concurrent.ConcurrentLinkedDeque
class
MessageQueue
:
ConcurrentLinkedDeque
<
BotEvent
>()
{
class
MessageQueue
:
ConcurrentLinkedDeque
<
BotEvent
>()
{
val
quoteCache
=
ConcurrentHashMap
<
Long
,
GroupMessage
>()
val
quoteCacheSize
=
4096
val
quoteCache
=
LinkedHashMap
<
Long
,
GroupMessage
>()
fun
fetch
(
size
:
Int
):
List
<
EventDTO
>
{
fun
fetch
(
size
:
Int
):
List
<
EventDTO
>
{
var
count
=
size
var
count
=
size
quoteCache
.
clear
()
val
ret
=
ArrayList
<
EventDTO
>(
count
)
val
ret
=
ArrayList
<
EventDTO
>(
count
)
while
(!
this
.
isEmpty
()
&&
count
>
0
)
{
while
(!
this
.
isEmpty
()
&&
count
>
0
)
{
val
event
=
pop
()
val
event
=
pop
()
...
@@ -36,14 +38,18 @@ class MessageQueue : ConcurrentLinkedDeque<BotEvent>() {
...
@@ -36,14 +38,18 @@ class MessageQueue : ConcurrentLinkedDeque<BotEvent>() {
}
}
}
}
// TODO: 等FriendMessage支持quote
if
(
event
is
GroupMessage
)
{
if
(
event
is
GroupMessage
)
{
addCache
(
event
)
add
Quote
Cache
(
event
)
}
}
}
}
return
ret
return
ret
}
}
private
fun
addCache
(
msg
:
GroupMessage
)
{
private
fun
addQuoteCache
(
msg
:
GroupMessage
)
{
quoteCache
[
msg
.
message
[
MessageSource
].
messageUid
]
=
msg
quoteCache
[
msg
.
message
[
MessageSource
].
calMessageId
()]
=
msg
if
(
quoteCache
.
size
>
quoteCacheSize
)
{
quoteCache
.
remove
(
quoteCache
.
firstKey
())
}
}
}
}
}
\ No newline at end of file
mirai-api-http/src/main/kotlin/net/mamoe/mirai/api/http/route/BaseRoute.kt
View file @
e9c79429
...
@@ -21,6 +21,7 @@ import io.ktor.http.HttpStatusCode
...
@@ -21,6 +21,7 @@ import io.ktor.http.HttpStatusCode
import
io.ktor.http.content.PartData
import
io.ktor.http.content.PartData
import
io.ktor.request.receive
import
io.ktor.request.receive
import
io.ktor.response.defaultTextContentType
import
io.ktor.response.defaultTextContentType
import
io.ktor.response.respond
import
io.ktor.response.respondText
import
io.ktor.response.respondText
import
io.ktor.routing.Route
import
io.ktor.routing.Route
import
io.ktor.routing.route
import
io.ktor.routing.route
...
@@ -141,6 +142,9 @@ internal inline fun Route.intercept(crossinline blk: suspend PipelineContext<Uni
...
@@ -141,6 +142,9 @@ internal inline fun Route.intercept(crossinline blk: suspend PipelineContext<Uni
call
.
respondStateCode
(
StateCode
.
PermissionDenied
)
call
.
respondStateCode
(
StateCode
.
PermissionDenied
)
}
catch
(
e
:
IllegalAccessException
)
{
}
catch
(
e
:
IllegalAccessException
)
{
call
.
respondStateCode
(
StateCode
(
400
,
e
.
message
),
HttpStatusCode
.
BadRequest
)
call
.
respondStateCode
(
StateCode
(
400
,
e
.
message
),
HttpStatusCode
.
BadRequest
)
}
catch
(
e
:
Throwable
)
{
e
.
printStackTrace
()
call
.
respond
(
HttpStatusCode
.
InternalServerError
,
e
.
message
!!
)
}
}
}
}
...
...
mirai-api-http/src/main/kotlin/net/mamoe/mirai/api/http/route/
Send
MessageRouteModule.kt
→
mirai-api-http/src/main/kotlin/net/mamoe/mirai/api/http/route/MessageRouteModule.kt
View file @
e9c79429
...
@@ -11,19 +11,21 @@ package net.mamoe.mirai.api.http.route
...
@@ -11,19 +11,21 @@ package net.mamoe.mirai.api.http.route
import
io.ktor.application.Application
import
io.ktor.application.Application
import
io.ktor.application.call
import
io.ktor.application.call
import
io.ktor.http.HttpStatusCode
import
io.ktor.http.content.readAllParts
import
io.ktor.http.content.readAllParts
import
io.ktor.http.content.streamProvider
import
io.ktor.http.content.streamProvider
import
io.ktor.request.receiveMultipart
import
io.ktor.request.receiveMultipart
import
io.ktor.response.respond
import
io.ktor.response.respondText
import
io.ktor.response.respondText
import
io.ktor.routing.post
import
io.ktor.routing.post
import
io.ktor.routing.routing
import
io.ktor.routing.routing
import
kotlinx.serialization.Serializable
import
kotlinx.serialization.Serializable
import
kotlinx.serialization.Transient
import
net.mamoe.mirai.api.http.AuthedSession
import
net.mamoe.mirai.api.http.AuthedSession
import
net.mamoe.mirai.api.http.SessionManager
import
net.mamoe.mirai.api.http.SessionManager
import
net.mamoe.mirai.api.http.data.*
import
net.mamoe.mirai.api.http.data.*
import
net.mamoe.mirai.api.http.data.common.MessageChainDTO
import
net.mamoe.mirai.api.http.data.common.MessageChainDTO
import
net.mamoe.mirai.api.http.data.common.VerifyDTO
import
net.mamoe.mirai.api.http.data.common.VerifyDTO
import
net.mamoe.mirai.api.http.data.common.toDTO
import
net.mamoe.mirai.api.http.data.common.toMessageChain
import
net.mamoe.mirai.api.http.data.common.toMessageChain
import
net.mamoe.mirai.api.http.util.toJson
import
net.mamoe.mirai.api.http.util.toJson
import
net.mamoe.mirai.contact.toList
import
net.mamoe.mirai.contact.toList
...
@@ -45,14 +47,12 @@ fun Application.messageModule() {
...
@@ -45,14 +47,12 @@ fun Application.messageModule() {
it
.
session
.
bot
.
getFriend
(
it
.
target
).
apply
{
it
.
session
.
bot
.
getFriend
(
it
.
target
).
apply
{
sendMessage
(
it
.
messageChain
.
toMessageChain
(
this
))
// this aka QQ
sendMessage
(
it
.
messageChain
.
toMessageChain
(
this
))
// this aka QQ
}
}
call
.
respondStateCode
(
StateCode
.
Success
)
}
}
miraiVerify
<
SendDTO
>(
"/sendGroupMessage"
)
{
miraiVerify
<
SendDTO
>(
"/sendGroupMessage"
)
{
it
.
session
.
bot
.
getGroup
(
it
.
target
).
apply
{
it
.
session
.
bot
.
getGroup
(
it
.
target
).
apply
{
sendMessage
(
it
.
messageChain
.
toMessageChain
(
this
))
// this aka Group
sendMessage
(
it
.
messageChain
.
toMessageChain
(
this
))
// this aka Group
}
}
call
.
respondStateCode
(
StateCode
.
Success
)
}
}
miraiVerify
<
SendDTO
>(
"/quoteMessage"
)
{
miraiVerify
<
SendDTO
>(
"/quoteMessage"
)
{
...
@@ -100,6 +100,11 @@ fun Application.messageModule() {
...
@@ -100,6 +100,11 @@ fun Application.messageModule() {
}
?:
throw
IllegalAccessException
(
"图片上传错误"
)
}
?:
throw
IllegalAccessException
(
"图片上传错误"
)
}
?:
throw
IllegalAccessException
(
"未知错误"
)
}
?:
throw
IllegalAccessException
(
"未知错误"
)
}
}
miraiVerify
<
RecallDTO
>(
"recall"
)
{
// TODO
call
.
respond
(
HttpStatusCode
.
NotFound
,
"未完成"
)
}
}
}
}
}
...
@@ -119,3 +124,15 @@ private data class SendImageDTO(
...
@@ -119,3 +124,15 @@ private data class SendImageDTO(
val
urls
:
List
<
String
>
val
urls
:
List
<
String
>
)
:
VerifyDTO
()
)
:
VerifyDTO
()
@Serializable
private
class
SendRetDTO
(
val
messageId
:
Long
,
@Transient
val
stateCode
:
StateCode
=
Success
)
:
StateCode
(
stateCode
.
code
,
stateCode
.
msg
)
@Serializable
private
data class
RecallDTO
(
override
val
sessionKey
:
String
,
val
target
:
Long
,
val
sender
:
Long
)
:
VerifyDTO
()
mirai-console-graphical/src/main/kotlin/net/mamoe/mirai/console/graphical/controller/MiraiGraphicalUIController.kt
View file @
e9c79429
package
net.mamoe.mirai.console.graphical.controller
package
net.mamoe.mirai.console.graphical.controller
import
javafx.application.Platform
import
javafx.application.Platform
import
javafx.collections.ObservableList
import
javafx.stage.Modality
import
javafx.stage.Modality
import
kotlinx.io.core.IoBuffer
import
kotlinx.io.core.IoBuffer
import
net.mamoe.mirai.Bot
import
net.mamoe.mirai.Bot
...
@@ -8,6 +9,7 @@ import net.mamoe.mirai.console.MiraiConsole
...
@@ -8,6 +9,7 @@ import net.mamoe.mirai.console.MiraiConsole
import
net.mamoe.mirai.console.MiraiConsoleUI
import
net.mamoe.mirai.console.MiraiConsoleUI
import
net.mamoe.mirai.console.graphical.model.BotModel
import
net.mamoe.mirai.console.graphical.model.BotModel
import
net.mamoe.mirai.console.graphical.model.ConsoleInfo
import
net.mamoe.mirai.console.graphical.model.ConsoleInfo
import
net.mamoe.mirai.console.graphical.model.PluginModel
import
net.mamoe.mirai.console.graphical.model.VerificationCodeModel
import
net.mamoe.mirai.console.graphical.model.VerificationCodeModel
import
net.mamoe.mirai.console.graphical.view.VerificationCodeFragment
import
net.mamoe.mirai.console.graphical.view.VerificationCodeFragment
import
net.mamoe.mirai.utils.LoginSolver
import
net.mamoe.mirai.utils.LoginSolver
...
@@ -21,13 +23,21 @@ class MiraiGraphicalUIController : Controller(), MiraiConsoleUI {
...
@@ -21,13 +23,21 @@ class MiraiGraphicalUIController : Controller(), MiraiConsoleUI {
private
val
loginSolver
=
GraphicalLoginSolver
()
private
val
loginSolver
=
GraphicalLoginSolver
()
private
val
cache
=
mutableMapOf
<
Long
,
BotModel
>()
private
val
cache
=
mutableMapOf
<
Long
,
BotModel
>()
val
mainLog
=
observableListOf
<
String
>()
val
mainLog
=
observableListOf
<
String
>()
val
botList
=
observableListOf
<
BotModel
>()
val
botList
=
observableListOf
<
BotModel
>()
val
pluginList
:
ObservableList
<
PluginModel
>
by
lazy
(
::
getPluginsFromConsole
)
val
consoleConfig
:
Map
<
String
,
Any
>
by
lazy
(
::
getConfigFromConsole
)
val
consoleInfo
=
ConsoleInfo
()
val
consoleInfo
=
ConsoleInfo
()
suspend
fun
login
(
qq
:
String
,
psd
:
String
)
{
suspend
fun
login
(
qq
:
String
,
psd
:
String
)
{
MiraiConsole
.
CommandListener
.
commandChannel
.
send
(
"/login $qq $psd"
)
MiraiConsole
.
CommandListener
.
commandChannel
.
send
(
"/login $qq $psd"
)
}
}
suspend
fun
sendCommand
(
command
:
String
)
=
MiraiConsole
.
CommandListener
.
commandChannel
.
send
(
command
)
override
fun
pushLog
(
identity
:
Long
,
message
:
String
)
=
Platform
.
runLater
{
override
fun
pushLog
(
identity
:
Long
,
message
:
String
)
=
Platform
.
runLater
{
when
(
identity
)
{
when
(
identity
)
{
0L
->
mainLog
.
add
(
message
)
0L
->
mainLog
.
add
(
message
)
...
@@ -68,6 +78,13 @@ class MiraiGraphicalUIController : Controller(), MiraiConsoleUI {
...
@@ -68,6 +78,13 @@ class MiraiGraphicalUIController : Controller(), MiraiConsoleUI {
}
}
override
fun
createLoginSolver
():
LoginSolver
=
loginSolver
override
fun
createLoginSolver
():
LoginSolver
=
loginSolver
private
fun
getPluginsFromConsole
():
ObservableList
<
PluginModel
>
{
// TODO
return
observableListOf
<
PluginModel
>()
}
private
fun
getConfigFromConsole
()
=
MiraiConsole
.
MiraiProperties
.
config
.
asMap
()
}
}
class
GraphicalLoginSolver
:
LoginSolver
()
{
class
GraphicalLoginSolver
:
LoginSolver
()
{
...
...
mirai-console-graphical/src/main/kotlin/net/mamoe/mirai/console/graphical/model/PluginModel.kt
0 → 100644
View file @
e9c79429
package
net.mamoe.mirai.console.graphical.model
import
com.jfoenix.controls.datamodels.treetable.RecursiveTreeObject
import
javafx.beans.property.SimpleBooleanProperty
import
javafx.beans.property.SimpleStringProperty
import
tornadofx.getValue
import
tornadofx.setValue
class
PluginModel
:
RecursiveTreeObject
<
PluginModel
>()
{
val
nameProperty
=
SimpleStringProperty
(
this
,
"nameProperty"
)
val
name
by
nameProperty
val
descriptionProperty
=
SimpleStringProperty
(
this
,
"descriptionProperty"
)
val
description
by
descriptionProperty
val
enabledProperty
=
SimpleBooleanProperty
(
this
,
"enabledProperty"
)
var
enabled
by
enabledProperty
}
\ No newline at end of file
mirai-console-graphical/src/main/kotlin/net/mamoe/mirai/console/graphical/util/JFoenixAdaptor.kt
View file @
e9c79429
package
net.mamoe.mirai.console.graphical.util
package
net.mamoe.mirai.console.graphical.util
import
com.jfoenix.controls.*
import
com.jfoenix.controls.*
import
com.jfoenix.controls.datamodels.treetable.RecursiveTreeObject
import
javafx.beans.value.ObservableValue
import
javafx.beans.value.ObservableValue
import
javafx.collections.ObservableList
import
javafx.collections.ObservableList
import
javafx.event.EventTarget
import
javafx.event.EventTarget
...
@@ -42,3 +43,6 @@ internal fun <T> EventTarget.jfxListView(values: ObservableList<T>? = null, op:
...
@@ -42,3 +43,6 @@ internal fun <T> EventTarget.jfxListView(values: ObservableList<T>? = null, op:
else
it
.
items
=
values
else
it
.
items
=
values
}
}
}
}
fun
<
T
:
RecursiveTreeObject
<
T
>
?
>
EventTarget
.
jfxTreeTableView
(
items
:
ObservableList
<
T
>?
=
null
,
op
:
JFXTreeTableView
<
T
>.()
->
Unit
=
{})
=
JFXTreeTableView
<
T
>(
RecursiveTreeItem
(
items
,
RecursiveTreeObject
<
T
>
::
getChildren
)).
attachTo
(
this
,
op
)
\ No newline at end of file
mirai-console-graphical/src/main/kotlin/net/mamoe/mirai/console/graphical/view/PluginsView.kt
0 → 100644
View file @
e9c79429
package
net.mamoe.mirai.console.graphical.view
import
com.jfoenix.controls.JFXTreeTableColumn
import
net.mamoe.mirai.console.graphical.controller.MiraiGraphicalUIController
import
net.mamoe.mirai.console.graphical.model.PluginModel
import
net.mamoe.mirai.console.graphical.util.jfxTreeTableView
import
tornadofx.View
class
PluginsView
:
View
()
{
private
val
controller
=
find
<
MiraiGraphicalUIController
>()
val
plugins
=
controller
.
pluginList
override
val
root
=
jfxTreeTableView
(
plugins
)
{
columns
.
addAll
(
JFXTreeTableColumn
<
PluginModel
,
String
>(
"插件名"
).
apply
{
},
JFXTreeTableColumn
<
PluginModel
,
String
>(
"版本"
).
apply
{
},
JFXTreeTableColumn
<
PluginModel
,
String
>(
"作者"
).
apply
{
},
JFXTreeTableColumn
<
PluginModel
,
String
>(
"介绍"
).
apply
{
}
)
}
}
\ No newline at end of file
mirai-console-graphical/src/main/kotlin/net/mamoe/mirai/console/graphical/view/PrimaryView.kt
View file @
e9c79429
...
@@ -5,6 +5,8 @@ import javafx.collections.ObservableList
...
@@ -5,6 +5,8 @@ import javafx.collections.ObservableList
import
javafx.scene.control.Tab
import
javafx.scene.control.Tab
import
javafx.scene.control.TabPane
import
javafx.scene.control.TabPane
import
javafx.scene.image.Image
import
javafx.scene.image.Image
import
javafx.scene.input.KeyCode
import
kotlinx.coroutines.runBlocking
import
net.mamoe.mirai.console.graphical.controller.MiraiGraphicalUIController
import
net.mamoe.mirai.console.graphical.controller.MiraiGraphicalUIController
import
net.mamoe.mirai.console.graphical.model.BotModel
import
net.mamoe.mirai.console.graphical.model.BotModel
import
net.mamoe.mirai.console.graphical.util.jfxListView
import
net.mamoe.mirai.console.graphical.util.jfxListView
...
@@ -52,17 +54,26 @@ class PrimaryView : View() {
...
@@ -52,17 +54,26 @@ class PrimaryView : View() {
}
}
}
}
}
}
// command input
textfield
{
setOnKeyPressed
{
if
(
it
.
code
==
KeyCode
.
ENTER
)
{
runAsync
{
runBlocking
{
controller
.
sendCommand
(
text
)
}
}.
ui
{
text
=
""
}
}
}
}
}
}
center
=
jfxTabPane
{
center
=
jfxTabPane
{
tab
(
"Login"
)
{
tab
(
"Login"
).
content
=
find
<
LoginView
>().
root
this
+=
find
<
LoginView
>().
root
}
tab
(
"Plugin
"
)
tab
(
"Plugin
s"
).
content
=
find
<
PluginsView
>().
root
tab
(
"Settings"
)
tab
(
"Settings"
)
.
content
=
find
<
SettingsView
>().
root
logTab
(
"Main"
,
controller
.
mainLog
)
logTab
(
"Main"
,
controller
.
mainLog
)
}
}
...
...
mirai-console-graphical/src/main/kotlin/net/mamoe/mirai/console/graphical/view/SettingsView.kt
0 → 100644
View file @
e9c79429
package
net.mamoe.mirai.console.graphical.view
import
net.mamoe.mirai.console.graphical.controller.MiraiGraphicalUIController
import
net.mamoe.mirai.console.graphical.util.jfxTextfield
import
tornadofx.View
import
tornadofx.field
import
tornadofx.fieldset
import
tornadofx.form
class
SettingsView
:
View
()
{
private
val
controller
=
find
<
MiraiGraphicalUIController
>()
override
val
root
=
form
{
controller
.
consoleConfig
.
forEach
{
fieldset
{
field
(
it
.
key
)
{
jfxTextfield
(
it
.
value
.
toString
())
{
isEditable
=
false
}
}
}
}
}
}
\ No newline at end of file
mirai-core-qqandroid/src/commonMain/kotlin/net/mamoe/mirai/qqandroid/ContactImpl.kt
View file @
e9c79429
...
@@ -16,14 +16,13 @@ import net.mamoe.mirai.event.broadcast
...
@@ -16,14 +16,13 @@ import net.mamoe.mirai.event.broadcast
import
net.mamoe.mirai.event.events.*
import
net.mamoe.mirai.event.events.*
import
net.mamoe.mirai.event.events.MessageSendEvent.FriendMessageSendEvent
import
net.mamoe.mirai.event.events.MessageSendEvent.FriendMessageSendEvent
import
net.mamoe.mirai.event.events.MessageSendEvent.GroupMessageSendEvent
import
net.mamoe.mirai.event.events.MessageSendEvent.GroupMessageSendEvent
import
net.mamoe.mirai.message.data.CustomFaceFromFile
import
net.mamoe.mirai.message.MessageReceipt
import
net.mamoe.mirai.message.data.Image
import
net.mamoe.mirai.message.data.*
import
net.mamoe.mirai.message.data.MessageChain
import
net.mamoe.mirai.message.data.NotOnlineImageFromFile
import
net.mamoe.mirai.qqandroid.network.highway.HighwayHelper
import
net.mamoe.mirai.qqandroid.network.highway.HighwayHelper
import
net.mamoe.mirai.qqandroid.network.highway.postImage
import
net.mamoe.mirai.qqandroid.network.highway.postImage
import
net.mamoe.mirai.qqandroid.network.protocol.data.jce.StTroopMemberInfo
import
net.mamoe.mirai.qqandroid.network.protocol.data.jce.StTroopMemberInfo
import
net.mamoe.mirai.qqandroid.network.protocol.data.proto.Cmd0x352
import
net.mamoe.mirai.qqandroid.network.protocol.data.proto.Cmd0x352
import
net.mamoe.mirai.qqandroid.network.protocol.packet.chat.PbMessageSvc
import
net.mamoe.mirai.qqandroid.network.protocol.packet.chat.TroopManagement
import
net.mamoe.mirai.qqandroid.network.protocol.packet.chat.TroopManagement
import
net.mamoe.mirai.qqandroid.network.protocol.packet.chat.image.ImgStore
import
net.mamoe.mirai.qqandroid.network.protocol.packet.chat.image.ImgStore
import
net.mamoe.mirai.qqandroid.network.protocol.packet.chat.image.LongConn
import
net.mamoe.mirai.qqandroid.network.protocol.packet.chat.image.LongConn
...
@@ -66,20 +65,22 @@ internal class QQImpl(
...
@@ -66,20 +65,22 @@ internal class QQImpl(
override
val
nick
:
String
override
val
nick
:
String
get
()
=
friendInfo
.
nick
get
()
=
friendInfo
.
nick
override
suspend
fun
sendMessage
(
message
:
MessageChain
)
{
override
suspend
fun
sendMessage
(
message
:
MessageChain
)
:
MessageReceipt
<
QQ
>
{
val
event
=
FriendMessageSendEvent
(
this
,
message
).
broadcast
()
val
event
=
FriendMessageSendEvent
(
this
,
message
).
broadcast
()
if
(
event
.
isCancelled
)
{
if
(
event
.
isCancelled
)
{
throw
EventCancelledException
(
"cancelled by FriendMessageSendEvent"
)
throw
EventCancelledException
(
"cancelled by FriendMessageSendEvent"
)
}
}
lateinit
var
source
:
MessageSource
bot
.
network
.
run
{
bot
.
network
.
run
{
check
(
check
(
MessageSvc
.
PbSendMsg
.
ToFriend
(
MessageSvc
.
PbSendMsg
.
ToFriend
(
bot
.
client
,
bot
.
client
,
id
,
id
,
event
.
message
event
.
message
).
sendAndExpect
<
MessageSvc
.
PbSendMsg
.
Response
>()
is
MessageSvc
.
PbSendMsg
.
Response
.
SUCCESS
)
{
source
=
it
}
.
sendAndExpect
<
MessageSvc
.
PbSendMsg
.
Response
>()
is
MessageSvc
.
PbSendMsg
.
Response
.
SUCCESS
)
{
"send message failed"
}
)
{
"send message failed"
}
}
}
return
MessageReceipt
(
message
,
source
,
this
)
}
}
override
suspend
fun
uploadImage
(
image
:
ExternalImage
):
Image
=
try
{
override
suspend
fun
uploadImage
(
image
:
ExternalImage
):
Image
=
try
{
...
@@ -166,7 +167,7 @@ internal class QQImpl(
...
@@ -166,7 +167,7 @@ internal class QQImpl(
}
}
@Suppress
(
"MemberVisibilityCanBePrivate"
,
"DELEGATED_MEMBER_HIDES_SUPERTYPE_OVERRIDE"
)
@Suppress
(
"MemberVisibilityCanBePrivate"
)
internal
class
MemberImpl
(
internal
class
MemberImpl
(
qq
:
QQImpl
,
qq
:
QQImpl
,
group
:
GroupImpl
,
group
:
GroupImpl
,
...
@@ -286,26 +287,39 @@ internal class MemberImpl(
...
@@ -286,26 +287,39 @@ internal class MemberImpl(
}
}
}
}
override
fun
hashCode
():
Int
{
var
result
=
bot
.
hashCode
()
result
=
31
*
result
+
id
.
hashCode
()
return
result
}
@Suppress
(
"DuplicatedCode"
)
override
fun
equals
(
other
:
Any
?):
Boolean
{
// 不要删除. trust me
if
(
this
===
other
)
return
true
if
(
other
!
is
Contact
)
return
false
if
(
this
::
class
!= other::class) return false
return this.id == other.id && this.bot == other.bot
}
override fun to
String
():
String
{
override fun to
String
():
String
{
return
"Member($id)"
return
"Member($id)"
}
}
}
}
internal
class
MemberInfoImpl
(
internal
class
MemberInfoImpl
(
private
val
jceInfo
:
StTroopMemberInfo
,
jceInfo
:
StTroopMemberInfo
,
private
val
groupOwnerId
:
Long
groupOwnerId
:
Long
)
:
MemberInfo
{
)
:
MemberInfo
{
override
val
uin
:
Long
get
()
=
jceInfo
.
memberUin
override
val
uin
:
Long
=
jceInfo
.
memberUin
override
val
nameCard
:
String
get
()
=
jceInfo
.
sName
?:
""
override
val
nameCard
:
String
=
jceInfo
.
sName
?:
""
override
val
nick
:
String
get
()
=
jceInfo
.
nick
override
val
nick
:
String
=
jceInfo
.
nick
override
val
permission
:
MemberPermission
override
val
permission
:
MemberPermission
=
when
{
get
()
=
when
{
jceInfo
.
memberUin
==
groupOwnerId
->
MemberPermission
.
OWNER
jceInfo
.
memberUin
==
groupOwnerId
->
MemberPermission
.
OWNER
jceInfo
.
dwFlag
==
1L
->
MemberPermission
.
ADMINISTRATOR
jceInfo
.
dwFlag
==
1L
->
MemberPermission
.
ADMINISTRATOR
else
->
MemberPermission
.
MEMBER
else
->
MemberPermission
.
MEMBER
}
}
override
val
specialTitle
:
String
=
jceInfo
.
sSpecialTitle
?:
""
override
val
specialTitle
:
String
get
()
=
jceInfo
.
sSpecialTitle
?:
""
override
val
muteTimestamp
:
Int
=
jceInfo
.
dwShutupTimestap
?.
toInt
()
?:
0
override
val
muteTimestamp
:
Int
get
()
=
jceInfo
.
dwShutupTimestap
?.
toInt
()
?:
0
}
}
/**
/**
...
@@ -325,6 +339,24 @@ internal class GroupImpl(
...
@@ -325,6 +339,24 @@ internal class GroupImpl(
override
lateinit
var
owner
:
Member
override
lateinit
var
owner
:
Member
@UseExperimental
(
MiraiExperimentalAPI
::
class
)
override
val
botAsMember
:
Member
by
lazy
{
Member
(
object
:
MemberInfo
{
override
val
nameCard
:
String
get
()
=
bot
.
nick
// TODO: 2020/2/21 机器人在群内的昵称获取
override
val
permission
:
MemberPermission
get
()
=
botPermission
override
val
specialTitle
:
String
get
()
=
""
// TODO: 2020/2/21 获取机器人在群里的头衔
override
val
muteTimestamp
:
Int
get
()
=
botMuteRemaining
override
val
uin
:
Long
get
()
=
bot
.
uin
override
val
nick
:
String
get
()
=
bot
.
nick
})
}
@UseExperimental
(
MiraiExperimentalAPI
::
class
)
@UseExperimental
(
MiraiExperimentalAPI
::
class
)
override
lateinit
var
botPermission
:
MemberPermission
override
lateinit
var
botPermission
:
MemberPermission
...
@@ -340,6 +372,9 @@ internal class GroupImpl(
...
@@ -340,6 +372,9 @@ internal class GroupImpl(
override
val
members
:
ContactList
<
Member
>
=
ContactList
(
members
.
mapNotNull
{
override
val
members
:
ContactList
<
Member
>
=
ContactList
(
members
.
mapNotNull
{
if
(
it
.
uin
==
bot
.
uin
)
{
if
(
it
.
uin
==
bot
.
uin
)
{
botPermission
=
it
.
permission
botPermission
=
it
.
permission
if
(
it
.
permission
==
MemberPermission
.
OWNER
)
{
owner
=
botAsMember
}
null
null
}
else
Member
(
it
).
also
{
member
->
}
else
Member
(
it
).
also
{
member
->
if
(
member
.
permission
==
MemberPermission
.
OWNER
)
{
if
(
member
.
permission
==
MemberPermission
.
OWNER
)
{
...
@@ -475,6 +510,20 @@ internal class GroupImpl(
...
@@ -475,6 +510,20 @@ internal class GroupImpl(
TODO
(
"not implemented"
)
TODO
(
"not implemented"
)
}
}
override
suspend
fun
recall
(
source
:
MessageSource
)
{
if
(
source
.
senderId
!=
bot
.
uin
)
{
checkBotPermissionOperator
()
}
source
.
ensureSequenceIdAvailable
()
bot
.
network
.
run
{
val
response
=
PbMessageSvc
.
PbMsgWithDraw
.
Group
(
bot
.
client
,
this
@GroupImpl
.
id
,
source
.
sequenceId
,
source
.
messageUid
.
toInt
())
.
sendAndExpect
<
PbMessageSvc
.
PbMsgWithDraw
.
Response
>()
check
(
response
is
PbMessageSvc
.
PbMsgWithDraw
.
Response
.
Success
)
{
"Failed to recall message #${source.sequenceId}: $response"
}
}
}
@UseExperimental
(
MiraiExperimentalAPI
::
class
)
@UseExperimental
(
MiraiExperimentalAPI
::
class
)
override
fun
Member
(
memberInfo
:
MemberInfo
):
Member
{
override
fun
Member
(
memberInfo
:
MemberInfo
):
Member
{
return
MemberImpl
(
return
MemberImpl
(
...
@@ -498,22 +547,27 @@ internal class GroupImpl(
...
@@ -498,22 +547,27 @@ internal class GroupImpl(
return
members
.
delegate
.
filteringGetOrNull
{
it
.
id
==
id
}
return
members
.
delegate
.
filteringGetOrNull
{
it
.
id
==
id
}
}
}
override
suspend
fun
sendMessage
(
message
:
MessageChain
)
{
override
suspend
fun
sendMessage
(
message
:
MessageChain
)
:
MessageReceipt
<
Group
>
{
check
(!
isBotMuted
)
{
"bot is muted. Remaining seconds=$botMuteRemaining"
}
check
(!
isBotMuted
)
{
"bot is muted. Remaining seconds=$botMuteRemaining"
}
val
event
=
GroupMessageSendEvent
(
this
,
message
).
broadcast
()
val
event
=
GroupMessageSendEvent
(
this
,
message
).
broadcast
()
if
(
event
.
isCancelled
)
{
if
(
event
.
isCancelled
)
{
throw
EventCancelledException
(
"cancelled by FriendMessageSendEvent"
)
throw
EventCancelledException
(
"cancelled by FriendMessageSendEvent"
)
}
}
lateinit
var
source
:
MessageSvc
.
PbSendMsg
.
MessageSourceFromSend
bot
.
network
.
run
{
bot
.
network
.
run
{
val
response
=
MessageSvc
.
PbSendMsg
.
ToGroup
(
val
response
:
MessageSvc
.
PbSendMsg
.
Response
=
MessageSvc
.
PbSendMsg
.
ToGroup
(
bot
.
client
,
bot
.
client
,
id
,
id
,
event
.
message
event
.
message
)
.
sendAndExpect
<
MessageSvc
.
PbSendMsg
.
Response
>
()
)
{
source
=
it
}.
sendAndExpect
()
check
(
check
(
response
is
MessageSvc
.
PbSendMsg
.
Response
.
SUCCESS
response
is
MessageSvc
.
PbSendMsg
.
Response
.
SUCCESS
)
{
"send message failed: $response"
}
)
{
"send message failed: $response"
}
}
}
source
.
startWaitingSequenceId
(
this
)
return
MessageReceipt
(
message
,
source
,
this
)
}
}
override
suspend
fun
uploadImage
(
image
:
ExternalImage
):
Image
=
try
{
override
suspend
fun
uploadImage
(
image
:
ExternalImage
):
Image
=
try
{
...
...
mirai-core-qqandroid/src/commonMain/kotlin/net/mamoe/mirai/qqandroid/message/MessageSourceFromMsg.kt
View file @
e9c79429
...
@@ -10,7 +10,6 @@
...
@@ -10,7 +10,6 @@
package
net.mamoe.mirai.qqandroid.message
package
net.mamoe.mirai.qqandroid.message
import
net.mamoe.mirai.contact.Group
import
net.mamoe.mirai.contact.Group
import
net.mamoe.mirai.message.data.MessageChain
import
net.mamoe.mirai.message.data.MessageSource
import
net.mamoe.mirai.message.data.MessageSource
import
net.mamoe.mirai.qqandroid.io.serialization.loadAs
import
net.mamoe.mirai.qqandroid.io.serialization.loadAs
import
net.mamoe.mirai.qqandroid.io.serialization.toByteArray
import
net.mamoe.mirai.qqandroid.io.serialization.toByteArray
...
@@ -22,8 +21,14 @@ internal inline class MessageSourceFromServer(
...
@@ -22,8 +21,14 @@ internal inline class MessageSourceFromServer(
val
delegate
:
ImMsgBody
.
SourceMsg
val
delegate
:
ImMsgBody
.
SourceMsg
)
:
MessageSource
{
)
:
MessageSource
{
override
val
time
:
Long
get
()
=
delegate
.
time
.
toLong
()
and
0
xFFFFFFFF
override
val
time
:
Long
get
()
=
delegate
.
time
.
toLong
()
and
0
xFFFFFFFF
override
val
messageUid
:
Long
get
()
=
delegate
.
pbReserve
.
loadAs
(
SourceMsg
.
ResvAttr
.
serializer
()).
origUids
!!
override
val
sequenceId
:
Int
get
()
=
delegate
.
origSeqs
?.
firstOrNull
()
?:
error
(
"cannot find sequenceId from ImMsgBody.SourceMsg"
)
override
val
sourceMessage
:
MessageChain
get
()
=
delegate
.
toMessageChain
()
override
suspend
fun
ensureSequenceIdAvailable
()
{
// nothing to do
}
override
val
messageUid
:
Int
get
()
=
delegate
.
pbReserve
.
loadAs
(
SourceMsg
.
ResvAttr
.
serializer
()).
origUids
!!
.
toInt
()
// override val sourceMessage: MessageChain get() = delegate.toMessageChain()
override
val
senderId
:
Long
get
()
=
delegate
.
senderUin
override
val
senderId
:
Long
get
()
=
delegate
.
senderUin
override
val
groupId
:
Long
get
()
=
Group
.
calculateGroupCodeByGroupUin
(
delegate
.
toUin
)
override
val
groupId
:
Long
get
()
=
Group
.
calculateGroupCodeByGroupUin
(
delegate
.
toUin
)
...
@@ -34,8 +39,13 @@ internal inline class MessageSourceFromMsg(
...
@@ -34,8 +39,13 @@ internal inline class MessageSourceFromMsg(
val
delegate
:
MsgComm
.
Msg
val
delegate
:
MsgComm
.
Msg
)
:
MessageSource
{
)
:
MessageSource
{
override
val
time
:
Long
get
()
=
delegate
.
msgHead
.
msgTime
.
toLong
()
and
0
xFFFFFFFF
override
val
time
:
Long
get
()
=
delegate
.
msgHead
.
msgTime
.
toLong
()
and
0
xFFFFFFFF
override
val
messageUid
:
Long
get
()
=
delegate
.
msgBody
.
richText
.
attr
!!
.
random
.
toLong
()
override
val
sequenceId
:
Int
get
()
=
delegate
.
msgHead
.
msgSeq
override
val
sourceMessage
:
MessageChain
get
()
=
delegate
.
toMessageChain
()
override
suspend
fun
ensureSequenceIdAvailable
()
{
// nothing to do
}
override
val
messageUid
:
Int
get
()
=
delegate
.
msgBody
.
richText
.
attr
!!
.
random
// override val sourceMessage: MessageChain get() = delegate.toMessageChain()
override
val
senderId
:
Long
get
()
=
delegate
.
msgHead
.
fromUin
override
val
senderId
:
Long
get
()
=
delegate
.
msgHead
.
fromUin
override
val
groupId
:
Long
get
()
=
delegate
.
msgHead
.
groupInfo
!!
.
groupCode
override
val
groupId
:
Long
get
()
=
delegate
.
msgHead
.
groupInfo
!!
.
groupCode
...
@@ -52,7 +62,7 @@ internal inline class MessageSourceFromMsg(
...
@@ -52,7 +62,7 @@ internal inline class MessageSourceFromMsg(
type
=
0
,
type
=
0
,
time
=
delegate
.
msgHead
.
msgTime
,
time
=
delegate
.
msgHead
.
msgTime
,
pbReserve
=
SourceMsg
.
ResvAttr
(
pbReserve
=
SourceMsg
.
ResvAttr
(
origUids
=
messageUid
origUids
=
messageUid
.
toLong
()
and
0
xffFFffFF
).
toByteArray
(
SourceMsg
.
ResvAttr
.
serializer
()),
).
toByteArray
(
SourceMsg
.
ResvAttr
.
serializer
()),
srcMsg
=
MsgComm
.
Msg
(
srcMsg
=
MsgComm
.
Msg
(
msgHead
=
MsgComm
.
MsgHead
(
msgHead
=
MsgComm
.
MsgHead
(
...
@@ -62,7 +72,8 @@ internal inline class MessageSourceFromMsg(
...
@@ -62,7 +72,8 @@ internal inline class MessageSourceFromMsg(
c2cCmd
=
delegate
.
msgHead
.
c2cCmd
,
c2cCmd
=
delegate
.
msgHead
.
c2cCmd
,
msgSeq
=
delegate
.
msgHead
.
msgSeq
,
msgSeq
=
delegate
.
msgHead
.
msgSeq
,
msgTime
=
delegate
.
msgHead
.
msgTime
,
msgTime
=
delegate
.
msgHead
.
msgTime
,
msgUid
=
messageUid
,
// ok
msgUid
=
messageUid
.
toLong
()
and
0
xffFFffFF
,
// ok
groupInfo
=
MsgComm
.
GroupInfo
(
groupCode
=
delegate
.
msgHead
.
groupInfo
.
groupCode
),
groupInfo
=
MsgComm
.
GroupInfo
(
groupCode
=
delegate
.
msgHead
.
groupInfo
.
groupCode
),
isSrcMsg
=
true
isSrcMsg
=
true
),
),
...
...
mirai-core-qqandroid/src/commonMain/kotlin/net/mamoe/mirai/qqandroid/message/messages.kt
View file @
e9c79429
...
@@ -15,6 +15,7 @@ import kotlinx.io.core.readUInt
...
@@ -15,6 +15,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.ExternalImage
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.io.discardExact
import
net.mamoe.mirai.utils.io.discardExact
...
@@ -27,12 +28,13 @@ internal fun At.toJceData(): ImMsgBody.Text {
...
@@ -27,12 +28,13 @@ internal fun At.toJceData(): ImMsgBody.Text {
return
ImMsgBody
.
Text
(
return
ImMsgBody
.
Text
(
str
=
text
,
str
=
text
,
attr6Buf
=
buildPacket
{
attr6Buf
=
buildPacket
{
writeShort
(
1
)
// MessageForText$AtTroopMemberInfo
writeShort
(
0
)
writeShort
(
1
)
// const
writeShort
(
text
.
length
.
toShort
())
writeShort
(
0
)
// startPos
writeByte
(
1
)
writeShort
(
text
.
length
.
toShort
())
// textLen
writeInt
(
target
.
toInt
())
writeByte
(
0
)
// flag, may=1
writeShort
(
0
)
writeInt
(
target
.
toInt
())
// uin
writeShort
(
0
)
// const
}.
readBytes
()
}.
readBytes
()
)
)
}
}
...
@@ -206,7 +208,15 @@ notOnlineImage=NotOnlineImage#2050019814 {
...
@@ -206,7 +208,15 @@ notOnlineImage=NotOnlineImage#2050019814 {
private
val
atAllData
=
ImMsgBody
.
Elem
(
private
val
atAllData
=
ImMsgBody
.
Elem
(
text
=
ImMsgBody
.
Text
(
text
=
ImMsgBody
.
Text
(
str
=
"@全体成员"
,
str
=
"@全体成员"
,
attr6Buf
=
"00 01 00 00 00 05 01 00 00 00 00 00 00"
.
hexToBytes
()
attr6Buf
=
buildPacket
{
// MessageForText$AtTroopMemberInfo
writeShort
(
1
)
// const
writeShort
(
0
)
// startPos
writeShort
(
"@全体成员"
.
length
.
toShort
())
// textLen
writeByte
(
1
)
// flag, may=1
writeInt
(
0
)
// uin
writeShort
(
0
)
// const
}.
readBytes
()
)
)
)
)
...
@@ -224,7 +234,7 @@ internal fun MessageChain.toRichTextElems(): MutableList<ImMsgBody.Elem> {
...
@@ -224,7 +234,7 @@ internal fun MessageChain.toRichTextElems(): MutableList<ImMsgBody.Elem> {
this
.
forEach
{
this
.
forEach
{
when
(
it
)
{
when
(
it
)
{
is
PlainText
->
elements
.
add
(
ImMsgBody
.
Elem
(
text
=
ImMsgBody
.
Text
(
str
=
it
.
stringValue
)))
is
PlainText
->
elements
.
add
(
ImMsgBody
.
Elem
(
text
=
ImMsgBody
.
Text
(
str
=
it
.
stringValue
)))
is
At
->
elements
.
add
(
ImMsgBody
.
Elem
(
text
=
it
.
toJceData
()))
is
At
->
elements
.
add
(
ImMsgBody
.
Elem
(
text
=
it
.
toJceData
()))
.
also
{
elements
.
add
(
ImMsgBody
.
Elem
(
text
=
ImMsgBody
.
Text
(
str
=
" "
)))
}
is
CustomFaceFromFile
->
elements
.
add
(
ImMsgBody
.
Elem
(
customFace
=
it
.
toJceData
()))
is
CustomFaceFromFile
->
elements
.
add
(
ImMsgBody
.
Elem
(
customFace
=
it
.
toJceData
()))
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
))
...
@@ -249,7 +259,7 @@ internal fun MessageChain.toRichTextElems(): MutableList<ImMsgBody.Elem> {
...
@@ -249,7 +259,7 @@ internal fun MessageChain.toRichTextElems(): MutableList<ImMsgBody.Elem> {
internal
class
CustomFaceFromServer
(
internal
class
CustomFaceFromServer
(
internal
val
delegate
:
ImMsgBody
.
CustomFace
internal
val
delegate
:
ImMsgBody
.
CustomFace
)
:
CustomFace
()
{
)
:
CustomFace
()
{
override
val
filepath
:
String
get
()
=
delegate
.
filePath
override
val
filepath
:
String
=
delegate
.
filePath
override
val
fileId
:
Int
get
()
=
delegate
.
fileId
override
val
fileId
:
Int
get
()
=
delegate
.
fileId
override
val
serverIp
:
Int
get
()
=
delegate
.
serverIp
override
val
serverIp
:
Int
get
()
=
delegate
.
serverIp
override
val
serverPort
:
Int
get
()
=
delegate
.
serverPort
override
val
serverPort
:
Int
get
()
=
delegate
.
serverPort
...
@@ -265,14 +275,14 @@ internal class CustomFaceFromServer(
...
@@ -265,14 +275,14 @@ internal class CustomFaceFromServer(
override
val
size
:
Int
get
()
=
delegate
.
size
override
val
size
:
Int
get
()
=
delegate
.
size
override
val
original
:
Int
get
()
=
delegate
.
origin
override
val
original
:
Int
get
()
=
delegate
.
origin
override
val
pbReserve
:
ByteArray
get
()
=
delegate
.
pbReserve
override
val
pbReserve
:
ByteArray
get
()
=
delegate
.
pbReserve
override
val
imageId
:
String
get
()
=
delegate
.
filePath
override
val
imageId
:
String
=
ExternalImage
.
generateImageId
(
delegate
.
md5
,
imageType
)
override
fun
equals
(
other
:
Any
?):
Boolean
{
override
fun
equals
(
other
:
Any
?):
Boolean
{
return
other
is
CustomFaceFromServer
&&
other
.
filepath
==
this
.
filepath
&&
other
.
md5
.
contentEquals
(
this
.
md5
)
return
other
is
CustomFaceFromServer
&&
other
.
filepath
==
this
.
filepath
&&
other
.
md5
.
contentEquals
(
this
.
md5
)
}
}
override
fun
hashCode
():
Int
{
override
fun
hashCode
():
Int
{
return
filepath
.
hashCode
()
+
31
*
md5
.
hashCode
()
return
imageId
.
hashCode
()
+
31
*
md5
.
hashCode
()
}
}
}
}
...
@@ -296,7 +306,7 @@ internal class NotOnlineImageFromServer(
...
@@ -296,7 +306,7 @@ internal class NotOnlineImageFromServer(
}
}
override
fun
hashCode
():
Int
{
override
fun
hashCode
():
Int
{
return
resourc
eId
.
hashCode
()
+
31
*
md5
.
hashCode
()
return
imag
eId
.
hashCode
()
+
31
*
md5
.
hashCode
()
}
}
}
}
...
...
mirai-core-qqandroid/src/commonMain/kotlin/net/mamoe/mirai/qqandroid/network/QQAndroidBotNetworkHandler.kt
View file @
e9c79429
...
@@ -374,12 +374,12 @@ internal class QQAndroidBotNetworkHandler(bot: QQAndroidBot) : BotNetworkHandler
...
@@ -374,12 +374,12 @@ internal class QQAndroidBotNetworkHandler(bot: QQAndroidBot) : BotNetworkHandler
// with generic type, less mistakes
// with generic type, less mistakes
private
suspend
fun
<
P
:
Packet
?
>
generifiedParsePacket
(
input
:
Input
)
{
private
suspend
fun
<
P
:
Packet
?
>
generifiedParsePacket
(
input
:
Input
)
{
KnownPacketFactories
.
parseIncomingPacket
(
bot
,
input
)
{
packetFactory
:
PacketFactory
<
P
>,
packet
:
P
,
commandName
:
String
,
sequenceId
:
Int
->
KnownPacketFactories
.
parseIncomingPacket
(
bot
,
input
)
{
packetFactory
:
PacketFactory
<
P
>,
packet
:
P
,
commandName
:
String
,
sequenceId
:
Int
->
handlePacket
(
packetFactory
,
packet
,
commandName
,
sequenceId
)
if
(
packet
is
MultiPacket
<
*
>)
{
if
(
packet
is
MultiPacket
<
*
>)
{
packet
.
forEach
{
packet
.
forEach
{
handlePacket
(
null
,
it
,
commandName
,
sequenceId
)
handlePacket
(
null
,
it
,
commandName
,
sequenceId
)
}
}
}
}
handlePacket
(
packetFactory
,
packet
,
commandName
,
sequenceId
)
}
}
}
}
...
@@ -388,19 +388,31 @@ internal class QQAndroidBotNetworkHandler(bot: QQAndroidBot) : BotNetworkHandler
...
@@ -388,19 +388,31 @@ internal class QQAndroidBotNetworkHandler(bot: QQAndroidBot) : BotNetworkHandler
*/
*/
suspend
fun
<
P
:
Packet
?
>
handlePacket
(
packetFactory
:
PacketFactory
<
P
>?,
packet
:
P
,
commandName
:
String
,
sequenceId
:
Int
)
{
suspend
fun
<
P
:
Packet
?
>
handlePacket
(
packetFactory
:
PacketFactory
<
P
>?,
packet
:
P
,
commandName
:
String
,
sequenceId
:
Int
)
{
// highest priority: pass to listeners (attached by sendAndExpect).
// highest priority: pass to listeners (attached by sendAndExpect).
if
(
packet
!=
null
&&
(
bot
.
logger
.
isEnabled
||
logger
.
isEnabled
))
{
val
logMessage
=
"Received: ${packet.toString().replace("
\
n
", """
\
n
""").replace("
\
r
", "")}"
if
(
packet
is
Event
)
{
bot
.
logger
.
verbose
(
logMessage
)
}
else
logger
.
verbose
(
logMessage
)
}
packetListeners
.
forEach
{
listener
->
packetListeners
.
forEach
{
listener
->
if
(
listener
.
filter
(
commandName
,
sequenceId
)
&&
packetListeners
.
remove
(
listener
))
{
if
(
listener
.
filter
(
commandName
,
sequenceId
)
&&
packetListeners
.
remove
(
listener
))
{
listener
.
complete
(
packet
)
listener
.
complete
(
packet
)
}
}
}
}
// check top-level cancelling
packetFactory
?.
run
{
when
(
this
)
{
is
OutgoingPacketFactory
<
P
>
->
bot
.
handle
(
packet
)
is
IncomingPacketFactory
<
P
>
->
bot
.
handle
(
packet
,
sequenceId
)
?.
sendWithoutExpect
()
}
}
if
(
packet
!=
null
&&
PacketReceivedEvent
(
packet
).
broadcast
().
isCancelled
)
{
if
(
packet
!=
null
&&
PacketReceivedEvent
(
packet
).
broadcast
().
isCancelled
)
{
return
return
}
}
// broadcast
if
(
packet
is
Event
)
{
if
(
packet
is
Event
)
{
if
(
packet
is
BroadcastControllable
)
{
if
(
packet
is
BroadcastControllable
)
{
if
(
packet
.
shouldBroadcast
)
packet
.
broadcast
()
if
(
packet
.
shouldBroadcast
)
packet
.
broadcast
()
...
@@ -410,21 +422,6 @@ internal class QQAndroidBotNetworkHandler(bot: QQAndroidBot) : BotNetworkHandler
...
@@ -410,21 +422,6 @@ internal class QQAndroidBotNetworkHandler(bot: QQAndroidBot) : BotNetworkHandler
if
(
packet
is
CancellableEvent
&&
packet
.
isCancelled
)
return
if
(
packet
is
CancellableEvent
&&
packet
.
isCancelled
)
return
}
}
if
(
packet
!=
null
&&
(
bot
.
logger
.
isEnabled
||
logger
.
isEnabled
))
{
val
logMessage
=
"Received: ${packet.toString().replace("
\
n
", """
\
n
""").replace("
\
r
", "")}"
if
(
packet
is
Event
)
{
bot
.
logger
.
verbose
(
logMessage
)
}
else
logger
.
verbose
(
logMessage
)
}
packetFactory
?.
run
{
when
(
this
)
{
is
OutgoingPacketFactory
<
P
>
->
bot
.
handle
(
packet
)
is
IncomingPacketFactory
<
P
>
->
bot
.
handle
(
packet
,
sequenceId
)
?.
sendWithoutExpect
()
}
}
}
}
/**
/**
...
...
mirai-core-qqandroid/src/commonMain/kotlin/net/mamoe/mirai/qqandroid/network/protocol/data/proto/MsgRevokeUserDef.kt
0 → 100644
View file @
e9c79429
/*
* Copyright 2020 Mamoe Technologies and contributors.
*
* 此源代码的使用受 GNU AFFERO GENERAL PUBLIC LICENSE version 3 许可证的约束, 可以在以下链接找到该许可证.
* Use of this source code is governed by the GNU AGPLv3 license that can be found through the following link.
*
* https://github.com/mamoe/mirai/blob/master/LICENSE
*/
package
net.mamoe.mirai.qqandroid.network.protocol.data.proto
import
kotlinx.serialization.SerialId
import
kotlinx.serialization.Serializable
import
net.mamoe.mirai.qqandroid.io.ProtoBuf
class
MsgRevokeUserDef
:
ProtoBuf
{
@Serializable
class
MsgInfoUserDef
(
@SerialId
(
1
)
val
longMessageFlag
:
Int
=
0
,
@SerialId
(
2
)
val
longMsgInfo
:
List
<
MsgInfoDef
>?
=
null
,
@SerialId
(
3
)
val
fileUuid
:
List
<
String
>
=
listOf
()
)
:
ProtoBuf
{
@Serializable
class
MsgInfoDef
(
@SerialId
(
1
)
val
msgSeq
:
Int
=
0
,
@SerialId
(
2
)
val
longMsgId
:
Int
=
0
,
@SerialId
(
3
)
val
longMsgNum
:
Int
=
0
,
@SerialId
(
4
)
val
longMsgIndex
:
Int
=
0
)
:
ProtoBuf
}
@Serializable
class
UinTypeUserDef
(
@SerialId
(
1
)
val
fromUinType
:
Int
=
0
,
@SerialId
(
2
)
val
fromGroupCode
:
Long
=
0L
,
@SerialId
(
3
)
val
fileUuid
:
List
<
String
>
=
listOf
()
)
:
ProtoBuf
}
\ No newline at end of file
mirai-core-qqandroid/src/commonMain/kotlin/net/mamoe/mirai/qqandroid/network/protocol/data/proto/MsgSvc.kt
View file @
e9c79429
...
@@ -26,7 +26,7 @@ internal class MsgSvc : ProtoBuf {
...
@@ -26,7 +26,7 @@ internal class MsgSvc : ProtoBuf {
internal
class
PbGetMsgResp
(
internal
class
PbGetMsgResp
(
@SerialId
(
1
)
val
result
:
Int
=
0
,
@SerialId
(
1
)
val
result
:
Int
=
0
,
@SerialId
(
2
)
val
errmsg
:
String
=
""
,
@SerialId
(
2
)
val
errmsg
:
String
=
""
,
@SerialId
(
3
)
val
syncCookie
:
ByteArray
=
EMPTY_BYTE_ARRAY
,
@SerialId
(
3
)
val
syncCookie
:
ByteArray
?
=
EMPTY_BYTE_ARRAY
,
@SerialId
(
4
)
val
syncFlag
:
SyncFlag
,
@SerialId
(
4
)
val
syncFlag
:
SyncFlag
,
@SerialId
(
5
)
val
uinPairMsgs
:
List
<
MsgComm
.
UinPairMsg
>?
=
null
,
@SerialId
(
5
)
val
uinPairMsgs
:
List
<
MsgComm
.
UinPairMsg
>?
=
null
,
@SerialId
(
6
)
val
bindUin
:
Long
=
0L
,
@SerialId
(
6
)
val
bindUin
:
Long
=
0L
,
...
...
mirai-core-qqandroid/src/commonMain/kotlin/net/mamoe/mirai/qqandroid/network/protocol/packet/PacketFactory.kt
View file @
e9c79429
...
@@ -14,6 +14,7 @@ import kotlinx.io.pool.useInstance
...
@@ -14,6 +14,7 @@ import kotlinx.io.pool.useInstance
import
net.mamoe.mirai.data.Packet
import
net.mamoe.mirai.data.Packet
import
net.mamoe.mirai.event.Event
import
net.mamoe.mirai.event.Event
import
net.mamoe.mirai.qqandroid.QQAndroidBot
import
net.mamoe.mirai.qqandroid.QQAndroidBot
import
net.mamoe.mirai.qqandroid.network.protocol.packet.chat.PbMessageSvc
import
net.mamoe.mirai.qqandroid.network.protocol.packet.chat.TroopManagement
import
net.mamoe.mirai.qqandroid.network.protocol.packet.chat.TroopManagement
import
net.mamoe.mirai.qqandroid.network.protocol.packet.chat.image.ImgStore
import
net.mamoe.mirai.qqandroid.network.protocol.packet.chat.image.ImgStore
import
net.mamoe.mirai.qqandroid.network.protocol.packet.chat.image.LongConn
import
net.mamoe.mirai.qqandroid.network.protocol.packet.chat.image.LongConn
...
@@ -138,7 +139,8 @@ internal object KnownPacketFactories {
...
@@ -138,7 +139,8 @@ internal object KnownPacketFactories {
TroopManagement
.
GetGroupInfo
,
TroopManagement
.
GetGroupInfo
,
TroopManagement
.
EditGroupNametag
,
TroopManagement
.
EditGroupNametag
,
TroopManagement
.
Kick
,
TroopManagement
.
Kick
,
Heartbeat
.
Alive
Heartbeat
.
Alive
,
PbMessageSvc
.
PbMsgWithDraw
)
)
object
IncomingFactories
:
List
<
IncomingPacketFactory
<
*
>>
by
mutableListOf
(
object
IncomingFactories
:
List
<
IncomingPacketFactory
<
*
>>
by
mutableListOf
(
...
...
mirai-core-qqandroid/src/commonMain/kotlin/net/mamoe/mirai/qqandroid/network/protocol/packet/chat/PbMessageSvc.kt
0 → 100644
View file @
e9c79429
/*
* Copyright 2020 Mamoe Technologies and contributors.
*
* 此源代码的使用受 GNU AFFERO GENERAL PUBLIC LICENSE version 3 许可证的约束, 可以在以下链接找到该许可证.
* Use of this source code is governed by the GNU AGPLv3 license that can be found through the following link.
*
* https://github.com/mamoe/mirai/blob/master/LICENSE
*/
package
net.mamoe.mirai.qqandroid.network.protocol.packet.chat
import
kotlinx.io.core.ByteReadPacket
import
net.mamoe.mirai.data.Packet
import
net.mamoe.mirai.qqandroid.QQAndroidBot
import
net.mamoe.mirai.qqandroid.io.serialization.readProtoBuf
import
net.mamoe.mirai.qqandroid.io.serialization.toByteArray
import
net.mamoe.mirai.qqandroid.io.serialization.writeProtoBuf
import
net.mamoe.mirai.qqandroid.network.QQAndroidClient
import
net.mamoe.mirai.qqandroid.network.protocol.data.proto.MsgRevokeUserDef
import
net.mamoe.mirai.qqandroid.network.protocol.data.proto.MsgSvc
import
net.mamoe.mirai.qqandroid.network.protocol.packet.OutgoingPacket
import
net.mamoe.mirai.qqandroid.network.protocol.packet.OutgoingPacketFactory
import
net.mamoe.mirai.qqandroid.network.protocol.packet.buildOutgoingUniPacket
internal
class
PbMessageSvc
{
object
PbMsgWithDraw
:
OutgoingPacketFactory
<
PbMsgWithDraw
.
Response
>(
"PbMessageSvc.PbMsgWithDraw"
)
{
sealed
class
Response
:
Packet
{
object
Success
:
Response
()
{
override
fun
toString
():
String
{
return
"PbMessageSvc.PbMsgWithDraw.Response.Success"
}
}
data class
Failed
(
val
result
:
Int
,
val
errorMessage
:
String
)
:
Response
()
}
// 12 1A 08 01 10 00 18 E7 C1 AD B8 02 22 0A 08 BF BA 03 10 BF 81 CB B7 03 2A 02 08 00
fun
Group
(
client
:
QQAndroidClient
,
groupCode
:
Long
,
messageSequenceId
:
Int
,
// 56639
messageRandom
:
Int
,
// 921878719
messageType
:
Int
=
0
):
OutgoingPacket
=
buildOutgoingUniPacket
(
client
)
{
writeProtoBuf
(
MsgSvc
.
PbMsgWithDrawReq
.
serializer
(),
MsgSvc
.
PbMsgWithDrawReq
(
groupWithDraw
=
listOf
(
MsgSvc
.
PbGroupMsgWithDrawReq
(
subCmd
=
1
,
groupType
=
0
,
// 普通群
groupCode
=
groupCode
,
msgList
=
listOf
(
MsgSvc
.
PbGroupMsgWithDrawReq
.
MessageInfo
(
msgSeq
=
messageSequenceId
,
msgRandom
=
messageRandom
,
msgType
=
messageType
)
),
userdef
=
MsgRevokeUserDef
.
MsgInfoUserDef
(
longMessageFlag
=
0
).
toByteArray
(
MsgRevokeUserDef
.
MsgInfoUserDef
.
serializer
())
)
)
)
)
}
override
suspend
fun
ByteReadPacket
.
decode
(
bot
:
QQAndroidBot
):
Response
{
val
resp
=
readProtoBuf
(
MsgSvc
.
PbMsgWithDrawResp
.
serializer
())
resp
.
groupWithDraw
?.
firstOrNull
()
?.
let
{
if
(
it
.
result
!=
0
)
{
return
Response
.
Failed
(
it
.
result
,
it
.
errmsg
)
}
return
Response
.
Success
}
resp
.
c2cWithDraw
?.
firstOrNull
()
?.
let
{
if
(
it
.
result
!=
0
)
{
return
Response
.
Failed
(
it
.
result
,
it
.
errmsg
)
}
return
Response
.
Success
}
return
Response
.
Failed
(-
1
,
"No response"
)
}
}
}
\ No newline at end of file
mirai-core-qqandroid/src/commonMain/kotlin/net/mamoe/mirai/qqandroid/network/protocol/packet/chat/receive/MessageSvc.kt
View file @
e9c79429
...
@@ -9,8 +9,11 @@
...
@@ -9,8 +9,11 @@
package
net.mamoe.mirai.qqandroid.network.protocol.packet.chat.receive
package
net.mamoe.mirai.qqandroid.network.protocol.packet.chat.receive
import
kotlinx.coroutines.Deferred
import
kotlinx.coroutines.ExperimentalCoroutinesApi
import
kotlinx.io.core.ByteReadPacket
import
kotlinx.io.core.ByteReadPacket
import
kotlinx.io.core.discardExact
import
kotlinx.io.core.discardExact
import
net.mamoe.mirai.contact.Contact
import
net.mamoe.mirai.contact.Group
import
net.mamoe.mirai.contact.Group
import
net.mamoe.mirai.contact.MemberPermission
import
net.mamoe.mirai.contact.MemberPermission
import
net.mamoe.mirai.data.MemberInfo
import
net.mamoe.mirai.data.MemberInfo
...
@@ -19,8 +22,11 @@ import net.mamoe.mirai.data.Packet
...
@@ -19,8 +22,11 @@ import net.mamoe.mirai.data.Packet
import
net.mamoe.mirai.event.events.BotJoinGroupEvent
import
net.mamoe.mirai.event.events.BotJoinGroupEvent
import
net.mamoe.mirai.event.events.BotOfflineEvent
import
net.mamoe.mirai.event.events.BotOfflineEvent
import
net.mamoe.mirai.event.events.MemberJoinEvent
import
net.mamoe.mirai.event.events.MemberJoinEvent
import
net.mamoe.mirai.event.subscribingGetAsync
import
net.mamoe.mirai.message.FriendMessage
import
net.mamoe.mirai.message.FriendMessage
import
net.mamoe.mirai.message.data.MessageChain
import
net.mamoe.mirai.message.data.MessageChain
import
net.mamoe.mirai.message.data.MessageSource
import
net.mamoe.mirai.message.data.addOrRemove
import
net.mamoe.mirai.qqandroid.GroupImpl
import
net.mamoe.mirai.qqandroid.GroupImpl
import
net.mamoe.mirai.qqandroid.QQAndroidBot
import
net.mamoe.mirai.qqandroid.QQAndroidBot
import
net.mamoe.mirai.qqandroid.io.serialization.decodeUniPacket
import
net.mamoe.mirai.qqandroid.io.serialization.decodeUniPacket
...
@@ -256,22 +262,73 @@ internal class MessageSvc {
...
@@ -256,22 +262,73 @@ internal class MessageSvc {
override
fun
toString
():
String
=
"MessageSvc.PbSendMsg.Response.SUCCESS"
override
fun
toString
():
String
=
"MessageSvc.PbSendMsg.Response.SUCCESS"
}
}
/**
* 121: 被限制? 个别号才不能发
*/
data class
Failed
(
val
resultType
:
Int
,
val
errorCode
:
Int
,
val
errorMessage
:
String
)
:
Response
()
{
data class
Failed
(
val
resultType
:
Int
,
val
errorCode
:
Int
,
val
errorMessage
:
String
)
:
Response
()
{
override
fun
toString
():
String
=
override
fun
toString
():
String
=
"MessageSvc.PbSendMsg.Response.Failed(resultType=$resultType, errorCode=$errorCode, errorMessage=$errorMessage)"
"MessageSvc.PbSendMsg.Response.Failed(resultType=$resultType, errorCode=$errorCode, errorMessage=$errorMessage)"
}
}
}
}
internal
class
MessageSourceFromSend
(
override
val
messageUid
:
Int
,
override
val
time
:
Long
,
override
val
senderId
:
Long
,
override
val
groupId
:
Long
// ,
// override val sourceMessage: MessageChain
)
:
MessageSource
{
private
lateinit
var
sequenceIdDeferred
:
Deferred
<
Int
>
@UseExperimental
(
MiraiExperimentalAPI
::
class
)
fun
startWaitingSequenceId
(
contact
:
Contact
)
{
sequenceIdDeferred
=
contact
.
subscribingGetAsync
<
OnlinePush
.
PbPushGroupMsg
.
SendGroupMessageReceipt
,
Int
>
{
if
(
it
.
messageRandom
==
messageUid
)
{
it
.
sequenceId
}
else
null
}
}
@UseExperimental
(
ExperimentalCoroutinesApi
::
class
)
override
val
sequenceId
:
Int
get
()
=
sequenceIdDeferred
.
getCompleted
()
override
suspend
fun
ensureSequenceIdAvailable
()
{
sequenceIdDeferred
.
join
()
}
override
fun
toString
():
String
{
return
""
}
}
inline
fun
ToFriend
(
client
:
QQAndroidClient
,
toUin
:
Long
,
message
:
MessageChain
,
crossinline
sourceCallback
:
(
MessageSource
)
->
Unit
):
OutgoingPacket
{
val
source
=
MessageSourceFromSend
(
messageUid
=
Random
.
nextInt
().
absoluteValue
,
senderId
=
client
.
uin
,
time
=
currentTimeSeconds
+
client
.
timeDifference
,
groupId
=
0
//
// sourceMessage = message
)
sourceCallback
(
source
)
return
ToFriend
(
client
,
toUin
,
message
,
source
)
}
/**
/**
* 发送好友消息
* 发送好友消息
*/
*/
@Suppress
(
"FunctionName"
)
@Suppress
(
"FunctionName"
)
fun
ToFriend
(
private
fun
ToFriend
(
client
:
QQAndroidClient
,
client
:
QQAndroidClient
,
toUin
:
Long
,
toUin
:
Long
,
message
:
MessageChain
message
:
MessageChain
,
source
:
MessageSource
):
OutgoingPacket
=
buildOutgoingUniPacket
(
client
)
{
):
OutgoingPacket
=
buildOutgoingUniPacket
(
client
)
{
///writeFully("0A 08 0A 06 08 89 FC A6 8C 0B 12 06 08 01 10 00 18 00 1A 1F 0A 1D 12 08 0A 06 0A 04 F0 9F 92 A9 12 11 AA 02 0E 88 01 00 9A 01 08 78 00 F8 01 00 C8 02 00 20 9B 7A 28 F4 CA 9B B8 03 32 34 08 92 C2 C4 F1 05 10 92 C2 C4 F1 05 18 E6 ED B9 C3 02 20 89 FE BE A4 06 28 89 84 F9 A2 06 48 DE 8C EA E5 0E 58 D9 BD BB A0 09 60 1D 68 92 C2 C4 F1 05 70 00 40 01".hexToBytes())
///writeFully("0A 08 0A 06 08 89 FC A6 8C 0B 12 06 08 01 10 00 18 00 1A 1F 0A 1D 12 08 0A 06 0A 04 F0 9F 92 A9 12 11 AA 02 0E 88 01 00 9A 01 08 78 00 F8 01 00 C8 02 00 20 9B 7A 28 F4 CA 9B B8 03 32 34 08 92 C2 C4 F1 05 10 92 C2 C4 F1 05 18 E6 ED B9 C3 02 20 89 FE BE A4 06 28 89 84 F9 A2 06 48 DE 8C EA E5 0E 58 D9 BD BB A0 09 60 1D 68 92 C2 C4 F1 05 70 00 40 01".hexToBytes())
///return@buildOutgoingUniPacket
///return@buildOutgoingUniPacket
...
@@ -285,13 +342,32 @@ internal class MessageSvc {
...
@@ -285,13 +342,32 @@ internal class MessageSvc {
)
)
),
),
msgSeq
=
client
.
atomicNextMessageSequenceId
(),
msgSeq
=
client
.
atomicNextMessageSequenceId
(),
msgRand
=
Random
.
nextInt
().
absoluteValue
,
msgRand
=
source
.
messageUid
,
syncCookie
=
SyncCookie
(
time
=
currentTimeSeconds
).
toByteArray
(
SyncCookie
.
serializer
())
syncCookie
=
SyncCookie
(
time
=
source
.
time
).
toByteArray
(
SyncCookie
.
serializer
())
// msgVia = 1
// msgVia = 1
)
)
)
)
}
}
inline
fun
ToGroup
(
client
:
QQAndroidClient
,
groupCode
:
Long
,
message
:
MessageChain
,
sourceCallback
:
(
MessageSourceFromSend
)
->
Unit
):
OutgoingPacket
{
val
source
=
MessageSourceFromSend
(
messageUid
=
Random
.
nextInt
().
absoluteValue
,
senderId
=
client
.
uin
,
time
=
currentTimeSeconds
+
client
.
timeDifference
,
groupId
=
groupCode
//,
// sourceMessage = message
)
sourceCallback
(
source
)
return
ToGroup
(
client
,
groupCode
,
message
,
source
)
}
/**
/**
* 发送群消息
* 发送群消息
*/
*/
...
@@ -299,14 +375,13 @@ internal class MessageSvc {
...
@@ -299,14 +375,13 @@ internal class MessageSvc {
fun
ToGroup
(
fun
ToGroup
(
client
:
QQAndroidClient
,
client
:
QQAndroidClient
,
groupCode
:
Long
,
groupCode
:
Long
,
message
:
MessageChain
message
:
MessageChain
,
source
:
MessageSource
):
OutgoingPacket
=
buildOutgoingUniPacket
(
client
)
{
):
OutgoingPacket
=
buildOutgoingUniPacket
(
client
)
{
///writeFully("0A 08 0A 06 08 89 FC A6 8C 0B 12 06 08 01 10 00 18 00 1A 1F 0A 1D 12 08 0A 06 0A 04 F0 9F 92 A9 12 11 AA 02 0E 88 01 00 9A 01 08 78 00 F8 01 00 C8 02 00 20 9B 7A 28 F4 CA 9B B8 03 32 34 08 92 C2 C4 F1 05 10 92 C2 C4 F1 05 18 E6 ED B9 C3 02 20 89 FE BE A4 06 28 89 84 F9 A2 06 48 DE 8C EA E5 0E 58 D9 BD BB A0 09 60 1D 68 92 C2 C4 F1 05 70 00 40 01".hexToBytes())
///writeFully("0A 08 0A 06 08 89 FC A6 8C 0B 12 06 08 01 10 00 18 00 1A 1F 0A 1D 12 08 0A 06 0A 04 F0 9F 92 A9 12 11 AA 02 0E 88 01 00 9A 01 08 78 00 F8 01 00 C8 02 00 20 9B 7A 28 F4 CA 9B B8 03 32 34 08 92 C2 C4 F1 05 10 92 C2 C4 F1 05 18 E6 ED B9 C3 02 20 89 FE BE A4 06 28 89 84 F9 A2 06 48 DE 8C EA E5 0E 58 D9 BD BB A0 09 60 1D 68 92 C2 C4 F1 05 70 00 40 01".hexToBytes())
// DebugLogger.debug("sending group message: " + message.toRichTextElems().contentToString())
// DebugLogger.debug("sending group message: " + message.toRichTextElems().contentToString())
val
seq
=
client
.
atomicNextMessageSequenceId
()
///return@buildOutgoingUniPacket
///return@buildOutgoingUniPacket
writeProtoBuf
(
writeProtoBuf
(
MsgSvc
.
PbSendMsgReq
.
serializer
(),
MsgSvc
.
PbSendMsgReq
(
MsgSvc
.
PbSendMsgReq
.
serializer
(),
MsgSvc
.
PbSendMsgReq
(
...
@@ -317,12 +392,14 @@ internal class MessageSvc {
...
@@ -317,12 +392,14 @@ internal class MessageSvc {
elems
=
message
.
toRichTextElems
()
elems
=
message
.
toRichTextElems
()
)
)
),
),
msgSeq
=
seq
,
msgSeq
=
client
.
atomicNextMessageSequenceId
()
,
msgRand
=
Random
.
nextInt
().
absoluteValue
,
msgRand
=
source
.
messageUid
,
syncCookie
=
EMPTY_BYTE_ARRAY
,
syncCookie
=
EMPTY_BYTE_ARRAY
,
msgVia
=
1
msgVia
=
1
)
)
)
)
message
.
addOrRemove
(
source
)
}
}
override
suspend
fun
ByteReadPacket
.
decode
(
bot
:
QQAndroidBot
):
Response
{
override
suspend
fun
ByteReadPacket
.
decode
(
bot
:
QQAndroidBot
):
Response
{
...
...
mirai-core-qqandroid/src/commonMain/kotlin/net/mamoe/mirai/qqandroid/network/protocol/packet/chat/receive/OnlinePush.kt
View file @
e9c79429
...
@@ -19,6 +19,7 @@ import net.mamoe.mirai.contact.MemberPermission
...
@@ -19,6 +19,7 @@ import net.mamoe.mirai.contact.MemberPermission
import
net.mamoe.mirai.data.MultiPacket
import
net.mamoe.mirai.data.MultiPacket
import
net.mamoe.mirai.data.NoPacket
import
net.mamoe.mirai.data.NoPacket
import
net.mamoe.mirai.data.Packet
import
net.mamoe.mirai.data.Packet
import
net.mamoe.mirai.event.Event
import
net.mamoe.mirai.event.events.*
import
net.mamoe.mirai.event.events.*
import
net.mamoe.mirai.message.GroupMessage
import
net.mamoe.mirai.message.GroupMessage
import
net.mamoe.mirai.qqandroid.GroupImpl
import
net.mamoe.mirai.qqandroid.GroupImpl
...
@@ -46,9 +47,18 @@ internal class OnlinePush {
...
@@ -46,9 +47,18 @@ internal class OnlinePush {
/**
/**
* 接受群消息
* 接受群消息
*/
*/
internal
object
PbPushGroupMsg
:
IncomingPacketFactory
<
GroupMessage
?
>(
"OnlinePush.PbPushGroupMsg"
)
{
internal
object
PbPushGroupMsg
:
IncomingPacketFactory
<
Packet
?
>(
"OnlinePush.PbPushGroupMsg"
)
{
internal
class
SendGroupMessageReceipt
(
val
messageRandom
:
Int
,
val
sequenceId
:
Int
)
:
Packet
,
Event
{
override
fun
toString
():
String
{
return
"OnlinePush.PbPushGroupMsg.SendGroupMessageReceipt(messageRandom=$messageRandom, sequenceId=$sequenceId)"
}
}
@UseExperimental
(
ExperimentalStdlibApi
::
class
)
@UseExperimental
(
ExperimentalStdlibApi
::
class
)
override
suspend
fun
ByteReadPacket
.
decode
(
bot
:
QQAndroidBot
,
sequenceId
:
Int
):
GroupMessage
?
{
override
suspend
fun
ByteReadPacket
.
decode
(
bot
:
QQAndroidBot
,
sequenceId
:
Int
):
Packet
?
{
// 00 00 02 E4 0A D5 05 0A 4F 08 A2 FF 8C F0 03 10 DD F1 92 B7 07 18 52 20 00 28 BC 3D 30 8C 82 AB F1 05 38 D2 80 E0 8C 80 80 80 80 02 4A 21 08 E7 C1 AD B8 02 10 01 18 BA 05 22 09 48 69 6D 31 38 38 6D 6F 65 30 06 38 02 42 05 4D 69 72 61 69 50 01 58 01 60 00 88 01 08 12 06 08 01 10 00 18 00 1A F9 04 0A F6 04 0A 26 08 00 10 87 82 AB F1 05 18 B7 B4 BF 30 20 00 28 0C 30 00 38 86 01 40 22 4A 0C E5 BE AE E8 BD AF E9 9B 85 E9 BB 91 12 E6 03 42 E3 03 12 2A 7B 34 45 31 38 35 38 32 32 2D 30 45 37 42 2D 46 38 30 46 2D 43 35 42 31 2D 33 34 34 38 38 33 37 34 44 33 39 43 7D 2E 6A 70 67 22 00 2A 04 03 00 00 00 32 60 15 36 20 39 36 6B 45 31 41 38 35 32 32 39 64 63 36 39 38 34 37 39 37 37 62 20 20 20 20 20 20 35 30 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 7B 34 45 31 38 35 38 32 32 2D 30 45 37 42 2D 46 38 30 46 2D 43 35 42 31 2D 33 34 34 38 38 33 37 34 44 33 39 43 7D 2E 6A 70 67 31 32 31 32 41 38 C6 BB 8A A9 08 40 FB AE 9E C2 09 48 50 50 41 5A 00 60 01 6A 10 4E 18 58 22 0E 7B F8 0F C5 B1 34 48 83 74 D3 9C 72 59 2F 67 63 68 61 74 70 69 63 5F 6E 65 77 2F 31 30 34 30 34 30 30 32 39 30 2F 36 35 35 30 35 37 31 32 37 2D 32 32 33 33 36 33 38 33 34 32 2D 34 45 31 38 35 38 32 32 30 45 37 42 46 38 30 46 43 35 42 31 33 34 34 38 38 33 37 34 44 33 39 43 2F 31 39 38 3F 74 65 72 6D 3D 32 82 01 57 2F 67 63 68 61 74 70 69 63 5F 6E 65 77 2F 31 30 34 30 34 30 30 32 39 30 2F 36 35 35 30 35 37 31 32 37 2D 32 32 33 33 36 33 38 33 34 32 2D 34 45 31 38 35 38 32 32 30 45 37 42 46 38 30 46 43 35 42 31 33 34 34 38 38 33 37 34 44 33 39 43 2F 30 3F 74 65 72 6D 3D 32 B0 01 4D B8 01 2E C8 01 FF 05 D8 01 4D E0 01 2E FA 01 59 2F 67 63 68 61 74 70 69 63 5F 6E 65 77 2F 31 30 34 30 34 30 30 32 39 30 2F 36 35 35 30 35 37 31 32 37 2D 32 32 33 33 36 33 38 33 34 32 2D 34 45 31 38 35 38 32 32 30 45 37 42 46 38 30 46 43 35 42 31 33 34 34 38 38 33 37 34 44 33 39 43 2F 34 30 30 3F 74 65 72 6D 3D 32 80 02 4D 88 02 2E 12 45 AA 02 42 50 03 60 00 68 00 9A 01 39 08 09 20 BF 50 80 01 01 C8 01 00 F0 01 00 F8 01 00 90 02 00 98 03 00 A0 03 20 B0 03 00 C0 03 00 D0 03 00 E8 03 00 8A 04 04 08 02 08 01 90 04 80 80 80 10 B8 04 00 C0 04 00 12 06 4A 04 08 00 40 01 12 14 82 01 11 0A 09 48 69 6D 31 38 38 6D 6F 65 18 06 20 08 28 03 10 8A CA 9D A1 07 1A 00
// 00 00 02 E4 0A D5 05 0A 4F 08 A2 FF 8C F0 03 10 DD F1 92 B7 07 18 52 20 00 28 BC 3D 30 8C 82 AB F1 05 38 D2 80 E0 8C 80 80 80 80 02 4A 21 08 E7 C1 AD B8 02 10 01 18 BA 05 22 09 48 69 6D 31 38 38 6D 6F 65 30 06 38 02 42 05 4D 69 72 61 69 50 01 58 01 60 00 88 01 08 12 06 08 01 10 00 18 00 1A F9 04 0A F6 04 0A 26 08 00 10 87 82 AB F1 05 18 B7 B4 BF 30 20 00 28 0C 30 00 38 86 01 40 22 4A 0C E5 BE AE E8 BD AF E9 9B 85 E9 BB 91 12 E6 03 42 E3 03 12 2A 7B 34 45 31 38 35 38 32 32 2D 30 45 37 42 2D 46 38 30 46 2D 43 35 42 31 2D 33 34 34 38 38 33 37 34 44 33 39 43 7D 2E 6A 70 67 22 00 2A 04 03 00 00 00 32 60 15 36 20 39 36 6B 45 31 41 38 35 32 32 39 64 63 36 39 38 34 37 39 37 37 62 20 20 20 20 20 20 35 30 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 7B 34 45 31 38 35 38 32 32 2D 30 45 37 42 2D 46 38 30 46 2D 43 35 42 31 2D 33 34 34 38 38 33 37 34 44 33 39 43 7D 2E 6A 70 67 31 32 31 32 41 38 C6 BB 8A A9 08 40 FB AE 9E C2 09 48 50 50 41 5A 00 60 01 6A 10 4E 18 58 22 0E 7B F8 0F C5 B1 34 48 83 74 D3 9C 72 59 2F 67 63 68 61 74 70 69 63 5F 6E 65 77 2F 31 30 34 30 34 30 30 32 39 30 2F 36 35 35 30 35 37 31 32 37 2D 32 32 33 33 36 33 38 33 34 32 2D 34 45 31 38 35 38 32 32 30 45 37 42 46 38 30 46 43 35 42 31 33 34 34 38 38 33 37 34 44 33 39 43 2F 31 39 38 3F 74 65 72 6D 3D 32 82 01 57 2F 67 63 68 61 74 70 69 63 5F 6E 65 77 2F 31 30 34 30 34 30 30 32 39 30 2F 36 35 35 30 35 37 31 32 37 2D 32 32 33 33 36 33 38 33 34 32 2D 34 45 31 38 35 38 32 32 30 45 37 42 46 38 30 46 43 35 42 31 33 34 34 38 38 33 37 34 44 33 39 43 2F 30 3F 74 65 72 6D 3D 32 B0 01 4D B8 01 2E C8 01 FF 05 D8 01 4D E0 01 2E FA 01 59 2F 67 63 68 61 74 70 69 63 5F 6E 65 77 2F 31 30 34 30 34 30 30 32 39 30 2F 36 35 35 30 35 37 31 32 37 2D 32 32 33 33 36 33 38 33 34 32 2D 34 45 31 38 35 38 32 32 30 45 37 42 46 38 30 46 43 35 42 31 33 34 34 38 38 33 37 34 44 33 39 43 2F 34 30 30 3F 74 65 72 6D 3D 32 80 02 4D 88 02 2E 12 45 AA 02 42 50 03 60 00 68 00 9A 01 39 08 09 20 BF 50 80 01 01 C8 01 00 F0 01 00 F8 01 00 90 02 00 98 03 00 A0 03 20 B0 03 00 C0 03 00 D0 03 00 E8 03 00 8A 04 04 08 02 08 01 90 04 80 80 80 10 B8 04 00 C0 04 00 12 06 4A 04 08 00 40 01 12 14 82 01 11 0A 09 48 69 6D 31 38 38 6D 6F 65 18 06 20 08 28 03 10 8A CA 9D A1 07 1A 00
if
(!
bot
.
firstLoginSucceed
)
return
null
if
(!
bot
.
firstLoginSucceed
)
return
null
val
pbPushMsg
=
readProtoBuf
(
MsgOnlinePush
.
PbPushMsg
.
serializer
())
val
pbPushMsg
=
readProtoBuf
(
MsgOnlinePush
.
PbPushMsg
.
serializer
())
...
@@ -56,7 +66,7 @@ internal class OnlinePush {
...
@@ -56,7 +66,7 @@ internal class OnlinePush {
val
extraInfo
:
ImMsgBody
.
ExtraInfo
?
=
pbPushMsg
.
msg
.
msgBody
.
richText
.
elems
.
firstOrNull
{
it
.
extraInfo
!=
null
}
?.
extraInfo
val
extraInfo
:
ImMsgBody
.
ExtraInfo
?
=
pbPushMsg
.
msg
.
msgBody
.
richText
.
elems
.
firstOrNull
{
it
.
extraInfo
!=
null
}
?.
extraInfo
if
(
pbPushMsg
.
msg
.
msgHead
.
fromUin
==
bot
.
uin
)
{
if
(
pbPushMsg
.
msg
.
msgHead
.
fromUin
==
bot
.
uin
)
{
return
null
return
SendGroupMessageReceipt
(
pbPushMsg
.
msg
.
msgBody
.
richText
.
attr
!!
.
random
,
pbPushMsg
.
msg
.
msgHead
.
msgSeq
)
}
}
val
group
=
bot
.
getGroup
(
pbPushMsg
.
msg
.
msgHead
.
groupInfo
!!
.
groupCode
)
val
group
=
bot
.
getGroup
(
pbPushMsg
.
msg
.
msgHead
.
groupInfo
!!
.
groupCode
)
...
@@ -64,8 +74,6 @@ internal class OnlinePush {
...
@@ -64,8 +74,6 @@ internal class OnlinePush {
// println(pbPushMsg.msg.msgBody.richText.contentToString())
// println(pbPushMsg.msg.msgBody.richText.contentToString())
val
flags
=
extraInfo
?.
flags
?:
0
val
flags
=
extraInfo
?.
flags
?:
0
return
GroupMessage
(
return
GroupMessage
(
bot
=
bot
,
group
=
group
,
senderName
=
pbPushMsg
.
msg
.
msgHead
.
groupInfo
.
groupCard
,
senderName
=
pbPushMsg
.
msg
.
msgHead
.
groupInfo
.
groupCard
,
sender
=
group
[
pbPushMsg
.
msg
.
msgHead
.
fromUin
],
sender
=
group
[
pbPushMsg
.
msg
.
msgHead
.
fromUin
],
message
=
pbPushMsg
.
msg
.
toMessageChain
(),
message
=
pbPushMsg
.
msg
.
toMessageChain
(),
...
...
mirai-core-qqandroid/src/jvmTest/kotlin/androidPacketTests/clientToServer.kt
View file @
e9c79429
...
@@ -107,6 +107,8 @@ fun main() {
...
@@ -107,6 +107,8 @@ fun main() {
* 顶层方法. TCP 切掉头后直接来这里
* 顶层方法. TCP 切掉头后直接来这里
*/
*/
fun
ByteReadPacket
.
decodeMultiClientToServerPackets
()
{
fun
ByteReadPacket
.
decodeMultiClientToServerPackets
()
{
DebugLogger
.
enable
()
PacketLogger
.
enable
()
println
(
"=======================处理客户端到服务器======================="
)
println
(
"=======================处理客户端到服务器======================="
)
var
count
=
0
var
count
=
0
while
(
remaining
!=
0L
)
{
while
(
remaining
!=
0L
)
{
...
...
mirai-core-qqandroid/src/jvmTest/kotlin/test/ProtoBufDataClassGenerator.kt
View file @
e9c79429
...
@@ -25,7 +25,7 @@ fun main() {
...
@@ -25,7 +25,7 @@ fun main() {
println
(
println
(
File
(
File
(
"""
"""
E:\Projects\QQAndroidFF\app\src\main\java\tencent\im\
statsvc\getonlin
e
E:\Projects\QQAndroidFF\app\src\main\java\tencent\im\
msgrevok
e
"""
.
trimIndent
()
"""
.
trimIndent
()
)
)
.
generateUnarrangedClasses
().
toMutableList
().
arrangeClasses
().
joinToString
(
"\n\n"
)
.
generateUnarrangedClasses
().
toMutableList
().
arrangeClasses
().
joinToString
(
"\n\n"
)
...
...
mirai-core/src/androidMain/kotlin/net/mamoe/mirai/message/MessagePacket.kt
View file @
e9c79429
...
@@ -9,7 +9,6 @@
...
@@ -9,7 +9,6 @@
package
net.mamoe.mirai.message
package
net.mamoe.mirai.message
import
net.mamoe.mirai.Bot
import
net.mamoe.mirai.contact.Contact
import
net.mamoe.mirai.contact.Contact
import
net.mamoe.mirai.contact.QQ
import
net.mamoe.mirai.contact.QQ
import
net.mamoe.mirai.utils.MiraiInternalAPI
import
net.mamoe.mirai.utils.MiraiInternalAPI
...
@@ -18,7 +17,7 @@ import net.mamoe.mirai.utils.MiraiInternalAPI
...
@@ -18,7 +17,7 @@ import net.mamoe.mirai.utils.MiraiInternalAPI
* 平台相关扩展
* 平台相关扩展
*/
*/
@UseExperimental
(
MiraiInternalAPI
::
class
)
@UseExperimental
(
MiraiInternalAPI
::
class
)
actual
abstract
class
MessagePacket
<
TSender
:
QQ
,
TSubject
:
Contact
>
actual
constructor
(
bot
:
Bot
)
:
MessagePacketBase
<
TSender
,
TSubject
>(
bot
)
{
actual
abstract
class
MessagePacket
<
TSender
:
QQ
,
TSubject
:
Contact
>
actual
constructor
(
)
:
MessagePacketBase
<
TSender
,
TSubject
>(
)
{
// suspend inline fun uploadImage(image: Bitmap): Image = subject.uploadImage(image)
// suspend inline fun uploadImage(image: Bitmap): Image = subject.uploadImage(image)
//suspend inline fun uploadImage(image: URL): Image = subject.uploadImage(image)
//suspend inline fun uploadImage(image: URL): Image = subject.uploadImage(image)
//suspend inline fun uploadImage(image: Input): Image = subject.uploadImage(image)
//suspend inline fun uploadImage(image: Input): Image = subject.uploadImage(image)
...
...
mirai-core/src/commonMain/kotlin/net.mamoe.mirai/Bot.kt
View file @
e9c79429
...
@@ -84,7 +84,7 @@ abstract class Bot : CoroutineScope {
...
@@ -84,7 +84,7 @@ abstract class Bot : CoroutineScope {
*/
*/
@MiraiExperimentalAPI
(
"还未支持"
)
@MiraiExperimentalAPI
(
"还未支持"
)
val
nick
:
String
val
nick
:
String
get
()
=
TODO
(
"bot 昵称获取"
)
get
()
=
""
//
TODO("bot 昵称获取")
/**
/**
* 日志记录器
* 日志记录器
...
@@ -175,8 +175,6 @@ abstract class Bot : CoroutineScope {
...
@@ -175,8 +175,6 @@ abstract class Bot : CoroutineScope {
*/
*/
abstract
suspend
fun
queryGroupMemberList
(
groupUin
:
Long
,
groupCode
:
Long
,
ownerId
:
Long
):
Sequence
<
MemberInfo
>
abstract
suspend
fun
queryGroupMemberList
(
groupUin
:
Long
,
groupCode
:
Long
,
ownerId
:
Long
):
Sequence
<
MemberInfo
>
// TODO 目前还不能构造群对象. 这将在以后支持
// endregion
// endregion
// region network
// region network
...
...
mirai-core/src/commonMain/kotlin/net.mamoe.mirai/contact/Contact.kt
View file @
e9c79429
...
@@ -18,6 +18,7 @@ import net.mamoe.mirai.event.events.EventCancelledException
...
@@ -18,6 +18,7 @@ import net.mamoe.mirai.event.events.EventCancelledException
import
net.mamoe.mirai.event.events.ImageUploadEvent
import
net.mamoe.mirai.event.events.ImageUploadEvent
import
net.mamoe.mirai.event.events.MessageSendEvent.FriendMessageSendEvent
import
net.mamoe.mirai.event.events.MessageSendEvent.FriendMessageSendEvent
import
net.mamoe.mirai.event.events.MessageSendEvent.GroupMessageSendEvent
import
net.mamoe.mirai.event.events.MessageSendEvent.GroupMessageSendEvent
import
net.mamoe.mirai.message.MessageReceipt
import
net.mamoe.mirai.message.data.*
import
net.mamoe.mirai.message.data.*
import
net.mamoe.mirai.utils.ExternalImage
import
net.mamoe.mirai.utils.ExternalImage
import
net.mamoe.mirai.utils.WeakRefProperty
import
net.mamoe.mirai.utils.WeakRefProperty
...
@@ -40,6 +41,9 @@ interface Contact : CoroutineScope {
...
@@ -40,6 +41,9 @@ interface Contact : CoroutineScope {
*
*
* 对于 [QQ], `uin` 与 `id` 是相同的意思.
* 对于 [QQ], `uin` 与 `id` 是相同的意思.
* 对于 [Group], `groupCode` 与 `id` 是相同的意思.
* 对于 [Group], `groupCode` 与 `id` 是相同的意思.
*
* @see QQ.id
* @see Group.id
*/
*/
val
id
:
Long
val
id
:
Long
...
@@ -51,8 +55,10 @@ interface Contact : CoroutineScope {
...
@@ -51,8 +55,10 @@ interface Contact : CoroutineScope {
*
*
* @throws EventCancelledException 当发送消息事件被取消
* @throws EventCancelledException 当发送消息事件被取消
* @throws IllegalStateException 发送群消息时若 [Bot] 被禁言抛出
* @throws IllegalStateException 发送群消息时若 [Bot] 被禁言抛出
*
* @return 消息回执. 可 [引用回复][MessageReceipt.quote](仅群聊)或 [撤回][MessageReceipt.recall] 这条消息.
*/
*/
suspend
fun
sendMessage
(
message
:
MessageChain
)
suspend
fun
sendMessage
(
message
:
MessageChain
)
:
MessageReceipt
<
out
Contact
>
/**
/**
* 上传一个图片以备发送.
* 上传一个图片以备发送.
...
@@ -88,4 +94,4 @@ interface Contact : CoroutineScope {
...
@@ -88,4 +94,4 @@ interface Contact : CoroutineScope {
suspend
inline
fun
Contact
.
sendMessage
(
message
:
Message
)
=
sendMessage
(
message
.
toChain
())
suspend
inline
fun
Contact
.
sendMessage
(
message
:
Message
)
=
sendMessage
(
message
.
toChain
())
suspend
inline
fun
Contact
.
sendMessage
(
plain
:
String
)
=
sendMessage
(
plain
.
singleChain
())
suspend
inline
fun
Contact
.
sendMessage
(
plain
:
String
)
=
sendMessage
(
plain
.
toMessage
())
\ No newline at end of file
\ No newline at end of file
mirai-core/src/commonMain/kotlin/net.mamoe.mirai/contact/ContactList.kt
View file @
e9c79429
...
@@ -40,6 +40,15 @@ class ContactList<C : Contact>(@MiraiInternalAPI val delegate: LockFreeLinkedLis
...
@@ -40,6 +40,15 @@ class ContactList<C : Contact>(@MiraiInternalAPI val delegate: LockFreeLinkedLis
fun
containsAll
(
elements
:
Collection
<
C
>):
Boolean
=
elements
.
all
{
contains
(
it
)
}
fun
containsAll
(
elements
:
Collection
<
C
>):
Boolean
=
elements
.
all
{
contains
(
it
)
}
fun
isEmpty
():
Boolean
=
delegate
.
isEmpty
()
fun
isEmpty
():
Boolean
=
delegate
.
isEmpty
()
inline
fun
forEach
(
block
:
(
C
)
->
Unit
)
=
delegate
.
forEach
(
block
)
inline
fun
forEach
(
block
:
(
C
)
->
Unit
)
=
delegate
.
forEach
(
block
)
fun
first
():
C
{
forEach
{
return
it
}
throw
NoSuchElementException
()
}
fun
firstOrNull
():
C
?
{
forEach
{
return
it
}
return
null
}
override
fun
toString
():
String
=
delegate
.
joinToString
(
separator
=
", "
,
prefix
=
"ContactList("
,
postfix
=
")"
)
override
fun
toString
():
String
=
delegate
.
joinToString
(
separator
=
", "
,
prefix
=
"ContactList("
,
postfix
=
")"
)
}
}
...
...
mirai-core/src/commonMain/kotlin/net.mamoe.mirai/contact/Group.kt
View file @
e9c79429
...
@@ -11,11 +11,21 @@
...
@@ -11,11 +11,21 @@
package
net.mamoe.mirai.contact
package
net.mamoe.mirai.contact
import
kotlinx.coroutines.CoroutineName
import
kotlinx.coroutines.CoroutineScope
import
kotlinx.coroutines.CoroutineScope
import
kotlinx.coroutines.Job
import
kotlinx.coroutines.launch
import
net.mamoe.mirai.Bot
import
net.mamoe.mirai.Bot
import
net.mamoe.mirai.data.MemberInfo
import
net.mamoe.mirai.data.MemberInfo
import
net.mamoe.mirai.event.events.*
import
net.mamoe.mirai.event.events.*
import
net.mamoe.mirai.event.events.MessageSendEvent.FriendMessageSendEvent
import
net.mamoe.mirai.event.events.MessageSendEvent.GroupMessageSendEvent
import
net.mamoe.mirai.message.MessageReceipt
import
net.mamoe.mirai.message.data.MessageChain
import
net.mamoe.mirai.message.data.MessageSource
import
net.mamoe.mirai.utils.MiraiExperimentalAPI
import
net.mamoe.mirai.utils.MiraiExperimentalAPI
import
kotlin.coroutines.CoroutineContext
import
kotlin.coroutines.EmptyCoroutineContext
import
kotlin.jvm.JvmName
import
kotlin.jvm.JvmName
/**
/**
...
@@ -83,10 +93,18 @@ interface Group : Contact, CoroutineScope {
...
@@ -83,10 +93,18 @@ interface Group : Contact, CoroutineScope {
override
val
id
:
Long
override
val
id
:
Long
/**
/**
* 群主
* 群主.
*
* @return 若机器人是群主, 返回 [botAsMember]. 否则返回相应的成员
*/
*/
val
owner
:
Member
val
owner
:
Member
/**
* [Bot] 在群内的 [Member] 实例
*/
@MiraiExperimentalAPI
val
botAsMember
:
Member
/**
/**
* 机器人被禁言还剩余多少秒
* 机器人被禁言还剩余多少秒
*
*
...
@@ -133,6 +151,17 @@ interface Group : Contact, CoroutineScope {
...
@@ -133,6 +151,17 @@ interface Group : Contact, CoroutineScope {
@MiraiExperimentalAPI
(
"还未支持"
)
@MiraiExperimentalAPI
(
"还未支持"
)
suspend
fun
quit
():
Boolean
suspend
fun
quit
():
Boolean
/**
* 撤回这条消息.
*
* [Bot] 撤回自己的消息不需要权限.
* [Bot] 撤回群员的消息需要管理员权限.
*
* @throws PermissionDeniedException 当 [Bot] 无权限操作时
* @see Group.recall (扩展函数) 接受参数 [MessageChain]
*/
suspend
fun
recall
(
source
:
MessageSource
)
/**
/**
* 构造一个 [Member].
* 构造一个 [Member].
* 非特殊情况请不要使用这个函数. 优先使用 [get].
* 非特殊情况请不要使用这个函数. 优先使用 [get].
...
@@ -142,6 +171,19 @@ interface Group : Contact, CoroutineScope {
...
@@ -142,6 +171,19 @@ interface Group : Contact, CoroutineScope {
@JvmName
(
"newMember"
)
@JvmName
(
"newMember"
)
fun
Member
(
memberInfo
:
MemberInfo
):
Member
fun
Member
(
memberInfo
:
MemberInfo
):
Member
/**
* 向这个对象发送消息.
*
* @see FriendMessageSendEvent 发送好友信息事件, cancellable
* @see GroupMessageSendEvent 发送群消息事件. cancellable
*
* @throws EventCancelledException 当发送消息事件被取消
* @throws IllegalStateException 发送群消息时若 [Bot] 被禁言抛出
*
* @return 消息回执. 可进行撤回 ([MessageReceipt.recall])
*/
override
suspend
fun
sendMessage
(
message
:
MessageChain
):
MessageReceipt
<
Group
>
companion
object
{
companion
object
{
/**
/**
...
@@ -184,7 +226,52 @@ interface Group : Contact, CoroutineScope {
...
@@ -184,7 +226,52 @@ interface Group : Contact, CoroutineScope {
fun
toFullString
():
String
=
"Group(id=${this.id}, name=$name, owner=${owner.id}, members=${members.idContentString})"
fun
toFullString
():
String
=
"Group(id=${this.id}, name=$name, owner=${owner.id}, members=${members.idContentString})"
}
}
/**
* 撤回这条消息.
*
* [Bot] 撤回自己的消息不需要权限.
* [Bot] 撤回群员的消息需要管理员权限.
*
* @throws PermissionDeniedException 当 [Bot] 无权限操作时
* @see Group.recall
*/
suspend
inline
fun
Group
.
recall
(
message
:
MessageChain
)
=
this
.
recall
(
message
[
MessageSource
])
/**
* 在一段时间后撤回这条消息.
*
* @param millis 延迟的时间, 单位为毫秒
* @param coroutineContext 额外的 [CoroutineContext]
* @see recall
*/
fun
Group
.
recallIn
(
message
:
MessageSource
,
millis
:
Long
,
coroutineContext
:
CoroutineContext
=
EmptyCoroutineContext
):
Job
=
this
.
launch
(
coroutineContext
+
CoroutineName
(
"MessageRecall"
))
{
kotlinx
.
coroutines
.
delay
(
millis
)
recall
(
message
)
}
/**
* 在一段时间后撤回这条消息.
*
* @param millis 延迟的时间, 单位为毫秒
* @param coroutineContext 额外的 [CoroutineContext]
* @see recall
*/
fun
Group
.
recallIn
(
message
:
MessageChain
,
millis
:
Long
,
coroutineContext
:
CoroutineContext
=
EmptyCoroutineContext
):
Job
=
this
.
launch
(
coroutineContext
+
CoroutineName
(
"MessageRecall"
))
{
kotlinx
.
coroutines
.
delay
(
millis
)
recall
(
message
)
}
/**
/**
* 返回机器人是否正在被禁言
* 返回机器人是否正在被禁言
*
* @see Group.botMuteRemaining 剩余禁言时间
*/
*/
val
Group
.
isBotMuted
:
Boolean
get
()
=
this
.
botMuteRemaining
!=
0
val
Group
.
isBotMuted
:
Boolean
get
()
=
this
.
botMuteRemaining
!=
0
mirai-core/src/commonMain/kotlin/net.mamoe.mirai/contact/Member.kt
View file @
e9c79429
...
@@ -72,6 +72,9 @@ interface Member : QQ, Contact {
...
@@ -72,6 +72,9 @@ interface Member : QQ, Contact {
/**
/**
* 禁言.
* 禁言.
*
*
* QQ 中最小操作和显示的时间都是一分钟.
* 机器人可以实现精确到秒, 会被客户端显示为 1 分钟但不影响实际禁言时间.
*
* 管理员可禁言成员, 群主可禁言管理员和群员.
* 管理员可禁言成员, 群主可禁言管理员和群员.
*
*
* @param durationSeconds 持续时间. 精确到秒. 范围区间表示为 `(0s, 30days]`. 超过范围则会抛出异常.
* @param durationSeconds 持续时间. 精确到秒. 范围区间表示为 `(0s, 30days]`. 超过范围则会抛出异常.
...
...
mirai-core/src/commonMain/kotlin/net.mamoe.mirai/contact/QQ.kt
View file @
e9c79429
...
@@ -16,6 +16,11 @@ import net.mamoe.mirai.Bot
...
@@ -16,6 +16,11 @@ import net.mamoe.mirai.Bot
import
net.mamoe.mirai.data.FriendNameRemark
import
net.mamoe.mirai.data.FriendNameRemark
import
net.mamoe.mirai.data.PreviousNameList
import
net.mamoe.mirai.data.PreviousNameList
import
net.mamoe.mirai.data.Profile
import
net.mamoe.mirai.data.Profile
import
net.mamoe.mirai.event.events.EventCancelledException
import
net.mamoe.mirai.event.events.MessageSendEvent.FriendMessageSendEvent
import
net.mamoe.mirai.event.events.MessageSendEvent.GroupMessageSendEvent
import
net.mamoe.mirai.message.MessageReceipt
import
net.mamoe.mirai.message.data.MessageChain
import
net.mamoe.mirai.utils.MiraiExperimentalAPI
import
net.mamoe.mirai.utils.MiraiExperimentalAPI
/**
/**
...
@@ -68,4 +73,17 @@ interface QQ : Contact, CoroutineScope {
...
@@ -68,4 +73,17 @@ interface QQ : Contact, CoroutineScope {
*/
*/
@MiraiExperimentalAPI
(
"还未支持"
)
@MiraiExperimentalAPI
(
"还未支持"
)
suspend
fun
queryRemark
():
FriendNameRemark
suspend
fun
queryRemark
():
FriendNameRemark
/**
* 向这个对象发送消息.
*
* @see FriendMessageSendEvent 发送好友信息事件, cancellable
* @see GroupMessageSendEvent 发送群消息事件. cancellable
*
* @throws EventCancelledException 当发送消息事件被取消
* @throws IllegalStateException 发送群消息时若 [Bot] 被禁言抛出
*
* @return 消息回执. 可进行撤回 ([MessageReceipt.recall])
*/
override
suspend
fun
sendMessage
(
message
:
MessageChain
):
MessageReceipt
<
QQ
>
}
}
\ No newline at end of file
mirai-core/src/commonMain/kotlin/net.mamoe.mirai/data/GroupInfo.kt
View file @
e9c79429
...
@@ -62,4 +62,15 @@ interface GroupInfo {
...
@@ -62,4 +62,15 @@ interface GroupInfo {
* 机器人被禁言还剩时间, 秒.
* 机器人被禁言还剩时间, 秒.
*/
*/
val
botMuteRemaining
:
Int
val
botMuteRemaining
:
Int
/*
/**
* 机器人的头衔
*/
val botSpecialTitle: String
/**
* 机器人的昵称
*/
val botNameCard: String*/
}
}
\ No newline at end of file
mirai-core/src/commonMain/kotlin/net.mamoe.mirai/event/
Subscribable
.kt
→
mirai-core/src/commonMain/kotlin/net.mamoe.mirai/event/
Event
.kt
View file @
e9c79429
File moved
mirai-core/src/commonMain/kotlin/net.mamoe.mirai/event/linear.kt
0 → 100644
View file @
e9c79429
/*
* Copyright 2020 Mamoe Technologies and contributors.
*
* 此源代码的使用受 GNU AFFERO GENERAL PUBLIC LICENSE version 3 许可证的约束, 可以在以下链接找到该许可证.
* Use of this source code is governed by the GNU AGPLv3 license that can be found through the following link.
*
* https://github.com/mamoe/mirai/blob/master/LICENSE
*/
package
net.mamoe.mirai.event
import
kotlinx.coroutines.*
import
net.mamoe.mirai.utils.MiraiExperimentalAPI
import
kotlin.coroutines.CoroutineContext
import
kotlin.coroutines.EmptyCoroutineContext
/**
* 挂起当前协程, 监听这个事件, 并尝试从这个事件中获取一个值.
*
* 若 [filter] 抛出了一个异常, 本函数会立即抛出这个异常.
*
* @param timeoutMillis 超时. 单位为毫秒. `-1` 为不限制
* @param filter 过滤器. 返回非 null 则代表得到了需要的值. [subscribingGet] 会返回这个值
*
* @see subscribingGetAsync 本函数的异步版本
*/
@MiraiExperimentalAPI
suspend
inline
fun
<
reified
E
:
Event
,
R
:
Any
>
subscribingGet
(
timeoutMillis
:
Long
=
-
1
,
noinline
filter
:
E
.(
E
)
->
R
?
// 不要 crossinline: crossinline 后 stacktrace 会不正常
):
R
{
require
(
timeoutMillis
==
-
1L
||
timeoutMillis
>
0
)
{
"timeoutMillis must be -1 or > 0"
}
return
subscribingGetOrNull
(
timeoutMillis
,
filter
)
?:
error
(
"timeout subscribingGet"
)
}
/**
* 挂起当前协程, 监听这个事件, 并尝试从这个事件中获取一个值.
*
* 若 [filter] 抛出了一个异常, 本函数会立即抛出这个异常.
*
* @param timeoutMillis 超时. 单位为毫秒. `-1` 为不限制
* @param filter 过滤器. 返回非 null 则代表得到了需要的值. [subscribingGet] 会返回这个值
*
* @see subscribingGetAsync 本函数的异步版本
*/
@MiraiExperimentalAPI
suspend
inline
fun
<
reified
E
:
Event
,
R
:
Any
>
subscribingGetOrNull
(
timeoutMillis
:
Long
=
-
1
,
noinline
filter
:
E
.(
E
)
->
R
?
// 不要 crossinline: crossinline 后 stacktrace 会不正常
):
R
?
{
require
(
timeoutMillis
==
-
1L
||
timeoutMillis
>
0
)
{
"timeoutMillis must be -1 or > 0"
}
var
result
:
R
?
=
null
var
resultThrowable
:
Throwable
?
=
null
if
(
timeoutMillis
==
-
1L
)
{
@Suppress
(
"DuplicatedCode"
)
// for better performance
coroutineScope
{
var
listener
:
Listener
<
E
>?
=
null
listener
=
this
.
subscribe
{
val
value
=
try
{
filter
.
invoke
(
this
,
it
)
}
catch
(
e
:
Exception
)
{
resultThrowable
=
e
return
@
subscribe
ListeningStatus
.
STOPPED
.
also
{
listener
!!
.
complete
()
}
}
if
(
value
!=
null
)
{
result
=
value
return
@
subscribe
ListeningStatus
.
STOPPED
.
also
{
listener
!!
.
complete
()
}
}
else
return
@
subscribe
ListeningStatus
.
LISTENING
}
}
}
else
{
withTimeoutOrNull
(
timeoutMillis
)
{
var
listener
:
Listener
<
E
>?
=
null
@Suppress
(
"DuplicatedCode"
)
// for better performance
listener
=
this
.
subscribe
{
val
value
=
try
{
filter
.
invoke
(
this
,
it
)
}
catch
(
e
:
Exception
)
{
resultThrowable
=
e
return
@
subscribe
ListeningStatus
.
STOPPED
.
also
{
listener
!!
.
complete
()
}
}
if
(
value
!=
null
)
{
result
=
value
return
@
subscribe
ListeningStatus
.
STOPPED
.
also
{
listener
!!
.
complete
()
}
}
else
return
@
subscribe
ListeningStatus
.
LISTENING
}
}
}
resultThrowable
?.
let
{
throw
it
}
return
result
}
/**
* 异步监听这个事件, 并尝试从这个事件中获取一个值.
*
* 若 [filter] 抛出了一个异常, [Deferred.await] 会抛出这个异常或.
*
* @param timeoutMillis 超时. 单位为毫秒. `-1` 为不限制
* @param coroutineContext 额外的 [CoroutineContext]
* @param filter 过滤器. 返回非 null 则代表得到了需要的值. [subscribingGet] 会返回这个值
*/
@MiraiExperimentalAPI
inline
fun
<
reified
E
:
Event
,
R
:
Any
>
CoroutineScope
.
subscribingGetAsync
(
coroutineContext
:
CoroutineContext
=
EmptyCoroutineContext
,
timeoutMillis
:
Long
=
-
1
,
noinline
filter
:
E
.(
E
)
->
R
?
// 不要 crossinline: crossinline 后 stacktrace 会不正常
):
Deferred
<
R
>
=
this
.
async
(
coroutineContext
)
{
subscribingGet
(
timeoutMillis
,
filter
)
}
\ No newline at end of file
mirai-core/src/commonMain/kotlin/net.mamoe.mirai/event/
MessageSubscriber
s.kt
→
mirai-core/src/commonMain/kotlin/net.mamoe.mirai/event/
subscribeMessage
s.kt
View file @
e9c79429
File moved
mirai-core/src/commonMain/kotlin/net.mamoe.mirai/event/
Subscribers
.kt
→
mirai-core/src/commonMain/kotlin/net.mamoe.mirai/event/
subscriber
.kt
View file @
e9c79429
...
@@ -101,6 +101,9 @@ interface Listener<in E : Event> : CompletableJob {
...
@@ -101,6 +101,9 @@ interface Listener<in E : Event> : CompletableJob {
*
*
*
@
param
coroutineContext
给事件监听协程的额外的
[
CoroutineContext
]
*
@
param
coroutineContext
给事件监听协程的额外的
[
CoroutineContext
]
*
*
*
@
see
subscribingGet
监听一个事件
,
并尝试从这个事件中获取一个值
.
*
@
see
subscribingGetAsync
异步监听一个事件
,
并尝试从这个事件中获取一个值
.
*
*
@
see
subscribeAlways
一直监听
*
@
see
subscribeAlways
一直监听
*
@
see
subscribeOnce
只监听一次
*
@
see
subscribeOnce
只监听一次
*
*
...
...
mirai-core/src/commonMain/kotlin/net.mamoe.mirai/message/FriendMessage.kt
View file @
e9c79429
...
@@ -13,12 +13,16 @@ import net.mamoe.mirai.Bot
...
@@ -13,12 +13,16 @@ import net.mamoe.mirai.Bot
import
net.mamoe.mirai.contact.QQ
import
net.mamoe.mirai.contact.QQ
import
net.mamoe.mirai.event.BroadcastControllable
import
net.mamoe.mirai.event.BroadcastControllable
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.unsafeWeakRef
class
FriendMessage
(
class
FriendMessage
(
bot
:
Bot
,
bot
:
Bot
,
override
val
sender
:
QQ
,
sender
:
QQ
,
override
val
message
:
MessageChain
override
val
message
:
MessageChain
)
:
MessagePacket
<
QQ
,
QQ
>(
bot
),
BroadcastControllable
{
)
:
MessagePacket
<
QQ
,
QQ
>(),
BroadcastControllable
{
override
val
sender
:
QQ
by
sender
.
unsafeWeakRef
()
override
val
bot
:
Bot
get
()
=
sender
.
bot
override
val
subject
:
QQ
get
()
=
sender
override
val
subject
:
QQ
get
()
=
sender
override
fun
toString
():
String
=
"FriendMessage(sender=${sender.id}, message=$message)"
override
fun
toString
():
String
=
"FriendMessage(sender=${sender.id}, message=$message)"
...
...
mirai-core/src/commonMain/kotlin/net.mamoe.mirai/message/GroupMessage.kt
View file @
e9c79429
...
@@ -9,21 +9,19 @@
...
@@ -9,21 +9,19 @@
package
net.mamoe.mirai.message
package
net.mamoe.mirai.message
import
kotlinx.coroutines.Job
import
net.mamoe.mirai.Bot
import
net.mamoe.mirai.Bot
import
net.mamoe.mirai.contact.Group
import
net.mamoe.mirai.contact.*
import
net.mamoe.mirai.contact.Member
import
net.mamoe.mirai.contact.MemberPermission
import
net.mamoe.mirai.event.Event
import
net.mamoe.mirai.event.Event
import
net.mamoe.mirai.message.data.Message
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.message.data.MessageSource
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
import
kotlin.jvm.JvmName
@Suppress
(
"unused"
,
"NOTHING_TO_INLINE"
)
@Suppress
(
"unused"
,
"NOTHING_TO_INLINE"
)
class
GroupMessage
(
class
GroupMessage
(
bot
:
Bot
,
group
:
Group
,
val
senderName
:
String
,
val
senderName
:
String
,
/**
/**
* 发送方权限.
* 发送方权限.
...
@@ -31,9 +29,10 @@ class GroupMessage(
...
@@ -31,9 +29,10 @@ class GroupMessage(
val
permission
:
MemberPermission
,
val
permission
:
MemberPermission
,
sender
:
Member
,
sender
:
Member
,
override
val
message
:
MessageChain
override
val
message
:
MessageChain
)
:
MessagePacket
<
Member
,
Group
>(
bot
),
Event
{
)
:
MessagePacket
<
Member
,
Group
>(),
Event
{
val
group
:
Group
by
group
.
unsafeWeakRef
()
override
val
sender
:
Member
by
sender
.
unsafeWeakRef
()
override
val
sender
:
Member
by
sender
.
unsafeWeakRef
()
val
group
:
Group
get
()
=
sender
.
group
override
val
bot
:
Bot
get
()
=
sender
.
bot
override
val
subject
:
Group
get
()
=
group
override
val
subject
:
Group
get
()
=
group
...
@@ -45,20 +44,25 @@ class GroupMessage(
...
@@ -45,20 +44,25 @@ class GroupMessage(
* 对于好友消息事件, 这个方法将会给好友 ([subject]) 发送消息
* 对于好友消息事件, 这个方法将会给好友 ([subject]) 发送消息
* 对于群消息事件, 这个方法将会给群 ([subject]) 发送消息
* 对于群消息事件, 这个方法将会给群 ([subject]) 发送消息
*/
*/
suspend
inline
fun
quoteReply
(
message
:
MessageChain
)
=
reply
(
this
.
message
.
quote
()
+
message
)
suspend
inline
fun
quoteReply
(
message
:
MessageChain
)
:
MessageReceipt
<
Group
>
=
reply
(
this
.
message
.
quote
()
+
message
)
suspend
inline
fun
quoteReply
(
message
:
Message
)
=
reply
(
this
.
message
.
quote
()
+
message
)
suspend
inline
fun
quoteReply
(
message
:
Message
)
:
MessageReceipt
<
Group
>
=
reply
(
this
.
message
.
quote
()
+
message
)
suspend
inline
fun
quoteReply
(
plain
:
String
)
=
reply
(
this
.
message
.
quote
()
+
plain
)
suspend
inline
fun
quoteReply
(
plain
:
String
)
:
MessageReceipt
<
Group
>
=
reply
(
this
.
message
.
quote
()
+
plain
)
@JvmName
(
"reply2"
)
@JvmName
(
"reply2"
)
suspend
inline
fun
String
.
quoteReply
()
=
quoteReply
(
this
)
suspend
inline
fun
String
.
quoteReply
()
:
MessageReceipt
<
Group
>
=
quoteReply
(
this
)
@JvmName
(
"reply2"
)
@JvmName
(
"reply2"
)
suspend
inline
fun
Message
.
quoteReply
()
=
quoteReply
(
this
)
suspend
inline
fun
Message
.
quoteReply
()
:
MessageReceipt
<
Group
>
=
quoteReply
(
this
)
@JvmName
(
"reply2"
)
@JvmName
(
"reply2"
)
suspend
inline
fun
MessageChain
.
quoteReply
()
=
quoteReply
(
this
)
suspend
inline
fun
MessageChain
.
quoteReply
():
MessageReceipt
<
Group
>
=
quoteReply
(
this
)
suspend
inline
fun
MessageChain
.
recall
()
=
group
.
recall
(
this
)
suspend
inline
fun
MessageSource
.
recall
()
=
group
.
recall
(
this
)
inline
fun
MessageSource
.
recallIn
(
delay
:
Long
):
Job
=
group
.
recallIn
(
this
,
delay
)
inline
fun
MessageChain
.
recallIn
(
delay
:
Long
):
Job
=
group
.
recallIn
(
this
,
delay
)
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)"
...
...
mirai-core/src/commonMain/kotlin/net.mamoe.mirai/message/MessagePacket.kt
View file @
e9c79429
...
@@ -21,6 +21,8 @@ import net.mamoe.mirai.contact.Member
...
@@ -21,6 +21,8 @@ import net.mamoe.mirai.contact.Member
import
net.mamoe.mirai.contact.QQ
import
net.mamoe.mirai.contact.QQ
import
net.mamoe.mirai.data.Packet
import
net.mamoe.mirai.data.Packet
import
net.mamoe.mirai.event.events.BotEvent
import
net.mamoe.mirai.event.events.BotEvent
import
net.mamoe.mirai.event.subscribingGet
import
net.mamoe.mirai.event.subscribingGetAsync
import
net.mamoe.mirai.message.data.*
import
net.mamoe.mirai.message.data.*
import
net.mamoe.mirai.utils.*
import
net.mamoe.mirai.utils.*
import
kotlin.jvm.JvmName
import
kotlin.jvm.JvmName
...
@@ -30,18 +32,19 @@ import kotlin.jvm.JvmName
...
@@ -30,18 +32,19 @@ import kotlin.jvm.JvmName
* 请查看各平台的 `actual` 实现的说明.
* 请查看各平台的 `actual` 实现的说明.
*/
*/
@UseExperimental
(
MiraiInternalAPI
::
class
)
@UseExperimental
(
MiraiInternalAPI
::
class
)
expect
abstract
class
MessagePacket
<
TSender
:
QQ
,
TSubject
:
Contact
>(
bot
:
Bot
)
:
MessagePacketBase
<
TSender
,
TSubject
>
expect
abstract
class
MessagePacket
<
TSender
:
QQ
,
TSubject
:
Contact
>()
:
MessagePacketBase
<
TSender
,
TSubject
>
/**
/**
* 仅内部使用, 请使用 [MessagePacket]
* 仅内部使用, 请使用 [MessagePacket]
*/
// Tips: 在 IntelliJ 中 (左侧边栏) 打开 `Structure`, 可查看类结构
*/
// Tips: 在 IntelliJ 中 (左侧边栏) 打开 `Structure`, 可查看类结构
@Suppress
(
"NOTHING_TO_INLINE"
)
@Suppress
(
"NOTHING_TO_INLINE"
,
"UNCHECKED_CAST"
)
@MiraiInternalAPI
@MiraiInternalAPI
abstract
class
MessagePacketBase
<
TSender
:
QQ
,
TSubject
:
Contact
>
(
_bot
:
Bot
)
:
Packet
,
BotEvent
{
abstract
class
MessagePacketBase
<
TSender
:
QQ
,
TSubject
:
Contact
>
:
Packet
,
BotEvent
{
/**
/**
* 接受到这条消息的
* 接受到这条消息的
*/
*/
override
val
bot
:
Bot
by
_bot
.
unsafeWeakRef
()
@WeakRefProperty
abstract
override
val
bot
:
Bot
/**
/**
* 消息事件主体.
* 消息事件主体.
...
@@ -51,6 +54,7 @@ abstract class MessagePacketBase<TSender : QQ, TSubject : Contact>(_bot: Bot) :
...
@@ -51,6 +54,7 @@ abstract class MessagePacketBase<TSender : QQ, TSubject : Contact>(_bot: Bot) :
*
*
* 在回复消息时, 可通过 [subject] 作为回复对象
* 在回复消息时, 可通过 [subject] 作为回复对象
*/
*/
@WeakRefProperty
abstract
val
subject
:
TSubject
abstract
val
subject
:
TSubject
/**
/**
...
@@ -58,6 +62,7 @@ abstract class MessagePacketBase<TSender : QQ, TSubject : Contact>(_bot: Bot) :
...
@@ -58,6 +62,7 @@ abstract class MessagePacketBase<TSender : QQ, TSubject : Contact>(_bot: Bot) :
*
*
* 在好友消息时为 [QQ] 的实例, 在群消息时为 [Member] 的实例
* 在好友消息时为 [QQ] 的实例, 在群消息时为 [Member] 的实例
*/
*/
@WeakRefProperty
abstract
val
sender
:
TSender
abstract
val
sender
:
TSender
/**
/**
...
@@ -73,20 +78,19 @@ abstract class MessagePacketBase<TSender : QQ, TSubject : Contact>(_bot: Bot) :
...
@@ -73,20 +78,19 @@ abstract class MessagePacketBase<TSender : QQ, TSubject : Contact>(_bot: Bot) :
* 对于好友消息事件, 这个方法将会给好友 ([subject]) 发送消息
* 对于好友消息事件, 这个方法将会给好友 ([subject]) 发送消息
* 对于群消息事件, 这个方法将会给群 ([subject]) 发送消息
* 对于群消息事件, 这个方法将会给群 ([subject]) 发送消息
*/
*/
suspend
inline
fun
reply
(
message
:
MessageChain
)
=
subject
.
sendMessage
(
message
)
suspend
inline
fun
reply
(
message
:
MessageChain
)
:
MessageReceipt
<
TSubject
>
=
subject
.
sendMessage
(
message
)
as
MessageReceipt
<
TSubject
>
suspend
inline
fun
reply
(
message
:
Message
)
=
subject
.
sendMessage
(
message
.
toChain
())
suspend
inline
fun
reply
(
message
:
Message
)
:
MessageReceipt
<
TSubject
>
=
subject
.
sendMessage
(
message
.
toChain
())
as
MessageReceipt
<
TSubject
>
suspend
inline
fun
reply
(
plain
:
String
)
=
subject
.
sendMessage
(
plain
.
singleChain
())
suspend
inline
fun
reply
(
plain
:
String
)
:
MessageReceipt
<
TSubject
>
=
subject
.
sendMessage
(
plain
.
toMessage
().
toChain
())
as
MessageReceipt
<
TSubject
>
@JvmName
(
"reply1"
)
@JvmName
(
"reply1"
)
suspend
inline
fun
String
.
reply
()
=
reply
(
this
)
suspend
inline
fun
String
.
reply
()
:
MessageReceipt
<
TSubject
>
=
reply
(
this
)
@JvmName
(
"reply1"
)
@JvmName
(
"reply1"
)
suspend
inline
fun
Message
.
reply
()
=
reply
(
this
)
suspend
inline
fun
Message
.
reply
()
:
MessageReceipt
<
TSubject
>
=
reply
(
this
)
@JvmName
(
"reply1"
)
@JvmName
(
"reply1"
)
suspend
inline
fun
MessageChain
.
reply
()
=
reply
(
this
)
suspend
inline
fun
MessageChain
.
reply
():
MessageReceipt
<
TSubject
>
=
reply
(
this
)
// endregion
// endregion
// region
// region
...
@@ -110,12 +114,16 @@ abstract class MessagePacketBase<TSender : QQ, TSubject : Contact>(_bot: Bot) :
...
@@ -110,12 +114,16 @@ abstract class MessagePacketBase<TSender : QQ, TSubject : Contact>(_bot: Bot) :
suspend
inline
fun
String
.
send
()
=
this
.
toMessage
().
sendTo
(
subject
)
suspend
inline
fun
String
.
send
()
=
this
.
toMessage
().
sendTo
(
subject
)
// endregion
// endregion
operator
fun
<
M
:
Message
>
get
(
at
:
Message
.
Key
<
M
>):
M
{
return
this
.
message
[
at
]
}
/**
/**
* 创建 @ 这个账号的消息. 当且仅当消息为群消息时可用. 否则将会抛出 [IllegalArgumentException]
* 创建 @ 这个账号的消息. 当且仅当消息为群消息时可用. 否则将会抛出 [IllegalArgumentException]
*/
*/
inline
fun
QQ
.
at
():
At
=
At
(
this
as
?
Member
?:
error
(
"`QQ.at` can only be used in GroupMessage"
))
fun
QQ
.
at
():
At
=
At
(
this
as
?
Member
?:
error
(
"`QQ.at` can only be used in GroupMessage"
))
inline
fun
At
.
member
():
Member
=
(
this
@MessagePacketBase
as
?
GroupMessage
)
?.
group
?.
get
(
this
.
target
)
?:
error
(
"`At.member` can only be used in GroupMessage"
)
fun
At
.
member
():
Member
=
(
this
@MessagePacketBase
as
?
GroupMessage
)
?.
group
?.
get
(
this
.
target
)
?:
error
(
"`At.member` can only be used in GroupMessage"
)
// endregion
// endregion
...
@@ -135,16 +143,47 @@ abstract class MessagePacketBase<TSender : QQ, TSubject : Contact>(_bot: Bot) :
...
@@ -135,16 +143,47 @@ abstract class MessagePacketBase<TSender : QQ, TSubject : Contact>(_bot: Bot) :
*/
*/
suspend
inline
fun
Image
.
download
():
ByteReadPacket
=
bot
.
run
{
download
()
}
suspend
inline
fun
Image
.
download
():
ByteReadPacket
=
bot
.
run
{
download
()
}
// endregion
// endregion
}
@Deprecated
(
message
=
"这个函数有歧义, 将在不久后删除"
,
replaceWith
=
ReplaceWith
(
"bot.getFriend(this.target)"
))
/**
fun
At
.
qq
():
QQ
=
bot
.
getFriend
(
this
.
target
)
* 判断两个 [MessagePacket] 的 [MessagePacket.sender] 和 [MessagePacket.subject] 是否相同
*/
@Deprecated
(
message
=
"这个函数有歧义, 将在不久后删除"
,
replaceWith
=
ReplaceWith
(
"bot.getFriend(this.toLong())"
))
fun
MessagePacket
<*,
*>.
isContextIdenticalWith
(
another
:
MessagePacket
<
*
,
*
>):
Boolean
{
fun
Int
.
qq
():
QQ
=
bot
.
getFriend
(
this
.
coerceAtLeastOrFail
(
0
).
toLong
())
return
this
.
sender
==
another
.
sender
&&
this
.
subject
==
another
.
subject
}
@Deprecated
(
message
=
"这个函数有歧义, 将在不久后删除"
,
replaceWith
=
ReplaceWith
(
"bot.getFriend(this)"
))
/**
fun
Long
.
qq
():
QQ
=
bot
.
getFriend
(
this
.
coerceAtLeastOrFail
(
0
))
* 挂起当前协程, 等待下一条 [MessagePacket.sender] 和 [MessagePacket.subject] 与 [P] 相同且通过 [筛选][filter] 的 [MessagePacket]
*
* 若 [filter] 抛出了一个异常, 本函数会立即抛出这个异常.
*
* @param timeoutMillis 超时. 单位为毫秒. `-1` 为不限制
* @param filter 过滤器. 返回非 null 则代表得到了需要的值. [subscribingGet] 会返回这个值
*
* @see subscribingGetAsync 本函数的异步版本
*/
suspend
inline
fun
<
reified
P
:
MessagePacket
<
*
,
*
>>
P
.
nextMessage
(
timeoutMillis
:
Long
=
-
1
,
crossinline
filter
:
P
.(
P
)
->
Boolean
):
MessageChain
{
return
subscribingGet
<
P
,
P
>(
timeoutMillis
)
{
takeIf
{
this
.
isContextIdenticalWith
(
this
@
nextMessage
)
}
?.
takeIf
{
filter
(
it
,
it
)
}
}.
message
}
@Deprecated
(
message
=
"这个函数有歧义, 将在不久后删除"
,
replaceWith
=
ReplaceWith
(
"bot.getGroup(this)"
))
/**
fun
Long
.
group
():
Group
=
bot
.
getGroup
(
this
)
* 挂起当前协程, 等待下一条 [MessagePacket.sender] 和 [MessagePacket.subject] 与 [P] 相同的 [MessagePacket]
*
* 若 [filter] 抛出了一个异常, 本函数会立即抛出这个异常.
*
* @param timeoutMillis 超时. 单位为毫秒. `-1` 为不限制
*
* @see subscribingGetAsync 本函数的异步版本
*/
suspend
inline
fun
<
reified
P
:
MessagePacket
<
*
,
*
>>
P
.
nextMessage
(
timeoutMillis
:
Long
=
-
1
):
MessageChain
{
return
subscribingGet
<
P
,
P
>(
timeoutMillis
)
{
takeIf
{
this
.
isContextIdenticalWith
(
this
@
nextMessage
)
}
}.
message
}
}
\ No newline at end of file
mirai-core/src/commonMain/kotlin/net.mamoe.mirai/message/MessageReceipt.kt
0 → 100644
View file @
e9c79429
/*
* Copyright 2020 Mamoe Technologies and contributors.
*
* 此源代码的使用受 GNU AFFERO GENERAL PUBLIC LICENSE version 3 许可证的约束, 可以在以下链接找到该许可证.
* Use of this source code is governed by the GNU AGPLv3 license that can be found through the following link.
*
* https://github.com/mamoe/mirai/blob/master/LICENSE
*/
package
net.mamoe.mirai.message
import
kotlinx.atomicfu.atomic
import
kotlinx.coroutines.Job
import
net.mamoe.mirai.Bot
import
net.mamoe.mirai.contact.*
import
net.mamoe.mirai.message.data.*
import
net.mamoe.mirai.utils.MiraiExperimentalAPI
import
net.mamoe.mirai.utils.getValue
import
net.mamoe.mirai.utils.unsafeWeakRef
/**
* 发送消息后得到的回执. 可用于撤回.
*
* 此对象持有 [Contact] 的弱引用, [Bot] 离线后将会释放引用, 届时 [target] 将无法访问.
*
* @see Group.sendMessage 发送群消息, 返回回执(此对象)
* @see QQ.sendMessage 发送群消息, 返回回执(此对象)
*/
open
class
MessageReceipt
<
C
:
Contact
>(
val
originalMessage
:
MessageChain
,
private
val
source
:
MessageSource
,
target
:
C
)
{
init
{
require
(
target
is
Group
||
target
is
QQ
)
{
"target must be either Group or QQ"
}
}
/**
* 发送目标, 为 [Group] 或 [QQ]
*/
val
target
:
C
by
target
.
unsafeWeakRef
()
private
val
_isRecalled
=
atomic
(
false
)
/**
* 撤回这条消息. [recall] 或 [recallIn] 只能被调用一次.
*
* @see Group.recall
* @throws IllegalStateException 当此消息已经被撤回或正计划撤回时
*/
@UseExperimental
(
MiraiExperimentalAPI
::
class
)
suspend
fun
recall
()
{
@Suppress
(
"BooleanLiteralArgument"
)
if
(
_isRecalled
.
compareAndSet
(
false
,
true
))
{
when
(
val
contact
=
target
)
{
is
Group
->
{
contact
.
recall
(
source
)
}
is
QQ
->
{
TODO
()
}
else
->
error
(
"Unknown contact type"
)
}
}
else
error
(
"message is already or planned to be recalled"
)
}
/**
* 撤回这条消息. [recall] 或 [recallIn] 只能被调用一次.
*
* @param millis 延迟时间, 单位为毫秒
*
* @throws IllegalStateException 当此消息已经被撤回或正计划撤回时
*/
@UseExperimental
(
MiraiExperimentalAPI
::
class
)
fun
recallIn
(
millis
:
Long
):
Job
{
@Suppress
(
"BooleanLiteralArgument"
)
if
(
_isRecalled
.
compareAndSet
(
false
,
true
))
{
when
(
val
contact
=
target
)
{
is
Group
->
{
return
contact
.
recallIn
(
source
,
millis
)
}
is
QQ
->
{
TODO
()
}
else
->
error
(
"Unknown contact type"
)
}
}
else
error
(
"message is already or planned to be recalled"
)
}
/**
* 引用这条消息. 仅群消息能被引用
*
* @see MessageChain.quote 引用一条消息
*
* @throws IllegalStateException 当此消息不是群消息时
*/
@MiraiExperimentalAPI
(
"unstable"
)
open
fun
quote
():
MessageChain
{
val
target
=
target
check
(
target
is
Group
)
{
"quote is only available for GroupMessage"
}
return
this
.
source
.
quote
(
target
.
botAsMember
)
}
/**
* 引用这条消息并回复. 仅群消息能被引用
*
* @see MessageChain.quote 引用一条消息
*
* @throws IllegalStateException 当此消息不是群消息时
*/
@MiraiExperimentalAPI
(
"unstable"
)
suspend
fun
quoteReply
(
message
:
MessageChain
)
{
target
.
sendMessage
(
this
.
quote
()
+
message
)
}
}
@MiraiExperimentalAPI
(
"unstable"
)
suspend
inline
fun
MessageReceipt
<
out
Contact
>.
quoteReply
(
message
:
Message
)
{
return
this
.
quoteReply
(
message
.
toChain
())
}
@MiraiExperimentalAPI
(
"unstable"
)
suspend
inline
fun
MessageReceipt
<
out
Contact
>.
quoteReply
(
message
:
String
)
{
return
this
.
quoteReply
(
message
.
toMessage
().
toChain
())
}
mirai-core/src/commonMain/kotlin/net.mamoe.mirai/message/data/At.kt
View file @
e9c79429
...
@@ -34,10 +34,6 @@ class At @MiraiInternalAPI constructor(val target: Long, val display: String) :
...
@@ -34,10 +34,6 @@ class At @MiraiInternalAPI constructor(val target: Long, val display: String) :
companion
object
Key
:
Message
.
Key
<
At
>
companion
object
Key
:
Message
.
Key
<
At
>
override
fun
eq
(
other
:
Message
):
Boolean
{
return
other
is
At
&&
other
.
target
==
this
.
target
}
// 自动为消息补充 " "
// 自动为消息补充 " "
override
fun
followedBy
(
tail
:
Message
):
MessageChain
{
override
fun
followedBy
(
tail
:
Message
):
MessageChain
{
...
...
mirai-core/src/commonMain/kotlin/net.mamoe.mirai/message/data/AtAll.kt
View file @
e9c79429
...
@@ -16,7 +16,9 @@ import kotlin.jvm.JvmMultifileClass
...
@@ -16,7 +16,9 @@ import kotlin.jvm.JvmMultifileClass
import
kotlin.jvm.JvmName
import
kotlin.jvm.JvmName
/**
/**
* "@全体成员"
* "@全体成员".
*
* 非会员每天只能发送 10 次 [AtAll]. 超出部分会被以普通文字看待.
*
*
* @see At at 单个群成员
* @see At at 单个群成员
*/
*/
...
@@ -26,7 +28,7 @@ object AtAll : Message, Message.Key<AtAll> {
...
@@ -26,7 +28,7 @@ object AtAll : Message, Message.Key<AtAll> {
// 自动为消息补充 " "
// 自动为消息补充 " "
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
(
tail
)
return
super
.
followedBy
(
tail
)
}
}
return
super
.
followedBy
(
PlainText
(
" "
))
+
tail
return
super
.
followedBy
(
PlainText
(
" "
))
+
tail
...
...
mirai-core/src/commonMain/kotlin/net.mamoe.mirai/message/data/Face.kt
View file @
e9c79429
...
@@ -167,8 +167,4 @@ class Face(val id: Int) : Message {
...
@@ -167,8 +167,4 @@ class Face(val id: Int) : Message {
const
val
shouqiang
:
Int
=
169
const
val
shouqiang
:
Int
=
169
const
val
qingwa
:
Int
=
170
const
val
qingwa
:
Int
=
170
}
}
override
fun
eq
(
other
:
Message
):
Boolean
{
return
other
is
Face
&&
other
.
id
==
this
.
id
}
}
}
\ No newline at end of file
mirai-core/src/commonMain/kotlin/net.mamoe.mirai/message/data/Image.kt
View file @
e9c79429
...
@@ -49,11 +49,6 @@ sealed class Image : Message {
...
@@ -49,11 +49,6 @@ sealed class Image : Message {
final
override
fun
toString
():
String
{
final
override
fun
toString
():
String
{
return
"[mirai:$imageId]"
return
"[mirai:$imageId]"
}
}
final
override
fun
eq
(
other
:
Message
):
Boolean
{
return
if
(
other
is
Image
)
return
other
.
imageId
==
this
.
imageId
else
this
.
toString
()
==
other
.
toString
()
}
}
}
abstract
class
CustomFace
:
Image
()
{
abstract
class
CustomFace
:
Image
()
{
...
...
mirai-core/src/commonMain/kotlin/net.mamoe.mirai/message/data/MessageChain.kt
View file @
e9c79429
...
@@ -13,9 +13,6 @@
...
@@ -13,9 +13,6 @@
package
net.mamoe.mirai.message.data
package
net.mamoe.mirai.message.data
import
net.mamoe.mirai.message.data.NullMessageChain.toString
import
net.mamoe.mirai.message.data.NullMessageChain.toString
import
net.mamoe.mirai.utils.MiraiExperimentalAPI
import
kotlin.contracts.ExperimentalContracts
import
kotlin.contracts.contract
import
kotlin.js.JsName
import
kotlin.js.JsName
import
kotlin.jvm.JvmMultifileClass
import
kotlin.jvm.JvmMultifileClass
import
kotlin.jvm.JvmName
import
kotlin.jvm.JvmName
...
@@ -60,12 +57,15 @@ interface MessageChain : Message, MutableList<Message> {
...
@@ -60,12 +57,15 @@ interface MessageChain : Message, MutableList<Message> {
* @param key 由各个类型消息的伴生对象持有. 如 [PlainText.Key]
* @param key 由各个类型消息的伴生对象持有. 如 [PlainText.Key]
*/
*/
operator
fun
<
M
:
Message
>
get
(
key
:
Message
.
Key
<
M
>):
M
=
first
(
key
)
operator
fun
<
M
:
Message
>
get
(
key
:
Message
.
Key
<
M
>):
M
=
first
(
key
)
}
override
fun
eq
(
other
:
Message
):
Boolean
{
/**
if
(
other
is
MessageChain
&&
other
.
size
!=
this
.
size
)
* 先删除同类型的消息, 再添加 [message]
return
false
*/
return
this
.
toString
()
==
other
.
toString
()
fun
<
T
:
Message
>
MessageChain
.
addOrRemove
(
message
:
T
)
{
}
val
clazz
=
message
::
class
this.remove
All
{
clazz
.
isInstance
(
it
)
}
this
.
add
(
message
)
}
}
/**
/**
...
@@ -133,37 +133,23 @@ fun MessageChain(vararg messages: Message): MessageChain =
...
@@ -133,37 +133,23 @@ fun MessageChain(vararg messages: Message): MessageChain =
else
MessageChainImpl
(
messages
.
toMutableList
())
else
MessageChainImpl
(
messages
.
toMutableList
())
/**
/**
* 构造 [MessageChain]
* 构造 [MessageChain] 的快速途径 (无 [Array] 创建)
* 若仅提供一个参数, 请考虑使用 [Message.toChain] 以优化性能
*/
*/
@JvmName
(
"newChain"
)
@JvmName
(
"newChain"
)
@JsName
(
"newChain"
)
@JsName
(
"newChain"
)
@Suppress
(
"FunctionName"
)
@Suppress
(
"FunctionName"
)
fun
MessageChain
(
message
s
:
Iterable
<
Message
>
):
MessageChain
=
fun
MessageChain
(
message
:
Message
):
MessageChain
=
MessageChainImpl
(
m
essages
.
toMutableList
(
))
MessageChainImpl
(
m
utableListOf
(
message
))
/**
/**
* 构造单元素的不可修改的 [MessageChain]. 内部类实现为 [SingleMessageChain]
* 构造 [MessageChain]
*
* 参数 [delegate] 不能为 [MessageChain] 的实例, 否则将会抛出异常.
* 使用 [Message.toChain] 将帮助提前处理这个问题.
*
* @param delegate 所构造的单元素 [MessageChain] 代表的 [Message]
* @throws IllegalArgumentException 当 [delegate] 为 [MessageChain] 的实例时
*
* @see Message.toChain receiver 模式
*/
*/
@JvmName
(
"new
SingleMessage
Chain"
)
@JvmName
(
"newChain"
)
@JsName
(
"newChain"
)
@JsName
(
"newChain"
)
@MiraiExperimentalAPI
@UseExperimental
(
ExperimentalContracts
::
class
)
@Suppress
(
"FunctionName"
)
@Suppress
(
"FunctionName"
)
fun
SingleMessageChain
(
delegate
:
Message
):
MessageChain
{
fun
MessageChain
(
messages
:
Iterable
<
Message
>):
MessageChain
=
contract
{
MessageChainImpl
(
messages
.
toMutableList
())
returns
()
implies
(
delegate
!
is
MessageChain
)
}
require
(
delegate
!
is
MessageChain
)
{
"delegate for SingleMessageChain should not be any instance of MessageChain"
}
return
SingleMessageChainImpl
(
delegate
)
}
/**
/**
...
@@ -217,7 +203,7 @@ fun <M : Message> MessageChain.firstOrNull(key: Message.Key<M>): M? = when (key)
...
@@ -217,7 +203,7 @@ fun <M : Message> MessageChain.firstOrNull(key: Message.Key<M>): M? = when (key)
* @throws [NoSuchElementException] 如果找不到该类型的实例
* @throws [NoSuchElementException] 如果找不到该类型的实例
*/
*/
@Suppress
(
"UNCHECKED_CAST"
)
@Suppress
(
"UNCHECKED_CAST"
)
fun
<
M
:
Message
>
MessageChain
.
first
(
key
:
Message
.
Key
<
M
>):
M
=
firstOrNull
(
key
)
?:
error
(
"unknown key
: $key"
)
fun
<
M
:
Message
>
MessageChain
.
first
(
key
:
Message
.
Key
<
M
>):
M
=
firstOrNull
(
key
)
?:
throw
NoSuchElementException
(
"no such element
: $key"
)
/**
/**
* 获取第一个 [M] 类型的 [Message] 实例
* 获取第一个 [M] 类型的 [Message] 实例
...
@@ -387,97 +373,3 @@ internal inline class MessageChainImpl constructor(
...
@@ -387,97 +373,3 @@ internal inline class MessageChainImpl constructor(
// endregion
// endregion
}
}
/**
* 单个成员的不可修改的 [MessageChain].
*
* 在连接时将会把它当做一个普通 [Message] 看待, 但它不能被 [plusAssign]
*/
@PublishedApi
internal
inline
class
SingleMessageChainImpl
(
private
val
delegate
:
Message
)
:
Message
,
MutableList
<
Message
>,
MessageChain
{
// region Message override
override
operator
fun
contains
(
sub
:
String
):
Boolean
=
delegate
.
contains
(
sub
)
override
fun
followedBy
(
tail
:
Message
):
MessageChain
{
require
(
tail
!
is
SingleOnly
)
{
"SingleOnly Message cannot follow another message"
}
return
if
(
tail
is
MessageChain
)
tail
.
apply
{
followedBy
(
delegate
)
}
else
MessageChain
(
delegate
,
tail
)
}
override
fun
plusAssign
(
message
:
Message
)
=
throw
UnsupportedOperationException
(
"SingleMessageChainImpl cannot be plusAssigned"
)
override
fun
toString
():
String
=
delegate
.
toString
()
// endregion
// region MutableList override
override
fun
containsAll
(
elements
:
Collection
<
Message
>):
Boolean
=
elements
.
all
{
it
==
delegate
}
override
operator
fun
get
(
index
:
Int
):
Message
=
if
(
index
==
0
)
delegate
else
throw
NoSuchElementException
()
override
fun
indexOf
(
element
:
Message
):
Int
=
if
(
delegate
==
element
)
0
else
-
1
override
fun
isEmpty
():
Boolean
=
false
override
fun
lastIndexOf
(
element
:
Message
):
Int
=
if
(
delegate
==
element
)
0
else
-
1
override
fun
add
(
element
:
Message
):
Boolean
=
throw
UnsupportedOperationException
()
override
fun
add
(
index
:
Int
,
element
:
Message
)
=
throw
UnsupportedOperationException
()
override
fun
addAll
(
index
:
Int
,
elements
:
Collection
<
Message
>):
Boolean
=
throw
UnsupportedOperationException
()
override
fun
addAll
(
elements
:
Collection
<
Message
>):
Boolean
=
throw
UnsupportedOperationException
()
override
fun
clear
()
=
throw
UnsupportedOperationException
()
override
fun
listIterator
():
MutableListIterator
<
Message
>
=
object
:
MutableListIterator
<
Message
>
{
private
var
hasNext
=
true
override
fun
hasPrevious
():
Boolean
=
!
hasNext
override
fun
nextIndex
():
Int
=
if
(
hasNext
)
0
else
-
1
override
fun
previous
():
Message
=
if
(
hasPrevious
())
{
hasNext
=
true
delegate
}
else
throw
NoSuchElementException
()
override
fun
previousIndex
():
Int
=
if
(!
hasNext
)
0
else
-
1
override
fun
add
(
element
:
Message
)
=
throw
UnsupportedOperationException
()
override
fun
hasNext
():
Boolean
=
hasNext
override
fun
next
():
Message
=
if
(
hasNext
)
{
hasNext
=
false
delegate
}
else
throw
NoSuchElementException
()
override
fun
remove
()
=
throw
UnsupportedOperationException
()
override
fun
set
(
element
:
Message
)
=
throw
UnsupportedOperationException
()
}
override
fun
listIterator
(
index
:
Int
):
MutableListIterator
<
Message
>
=
if
(
index
==
0
)
listIterator
()
else
throw
UnsupportedOperationException
()
override
fun
remove
(
element
:
Message
):
Boolean
=
throw
UnsupportedOperationException
()
override
fun
removeAll
(
elements
:
Collection
<
Message
>):
Boolean
=
throw
UnsupportedOperationException
()
override
fun
removeAt
(
index
:
Int
):
Message
=
throw
UnsupportedOperationException
()
override
fun
retainAll
(
elements
:
Collection
<
Message
>):
Boolean
=
throw
UnsupportedOperationException
()
override
fun
set
(
index
:
Int
,
element
:
Message
):
Message
=
throw
UnsupportedOperationException
()
override
fun
subList
(
fromIndex
:
Int
,
toIndex
:
Int
):
MutableList
<
Message
>
{
return
if
(
fromIndex
==
0
)
when
(
toIndex
)
{
1
->
mutableListOf
<
Message
>(
this
)
0
->
mutableListOf
()
else
->
throw
UnsupportedOperationException
()
}
else
throw
UnsupportedOperationException
()
}
override
fun
iterator
():
MutableIterator
<
Message
>
=
object
:
MutableIterator
<
Message
>
{
private
var
hasNext
=
true
override
fun
hasNext
():
Boolean
=
hasNext
override
fun
next
():
Message
=
if
(
hasNext
)
{
hasNext
=
false
delegate
}
else
throw
NoSuchElementException
()
override
fun
remove
()
=
throw
UnsupportedOperationException
()
}
override
operator
fun
contains
(
element
:
Message
):
Boolean
=
element
==
delegate
override
val
size
:
Int
get
()
=
1
// endregion
}
\ No newline at end of file
mirai-core/src/commonMain/kotlin/net.mamoe.mirai/message/data/MessageSource.kt
View file @
e9c79429
...
@@ -26,10 +26,22 @@ import kotlin.jvm.JvmName
...
@@ -26,10 +26,22 @@ import kotlin.jvm.JvmName
interface
MessageSource
:
Message
{
interface
MessageSource
:
Message
{
companion
object
Key
:
Message
.
Key
<
MessageSource
>
companion
object
Key
:
Message
.
Key
<
MessageSource
>
/**
* 序列号. 若是机器人发出去的消息, 请先 [确保 sequenceId 可用][ensureSequenceIdAvailable]
*/
val
sequenceId
:
Int
/**
* 等待 [sequenceId] 获取, 确保其可用.
*
* 若原消息发送失败, 这个方法会等待最多 3 秒随后抛出 [IllegalStateException]
*/
suspend
fun
ensureSequenceIdAvailable
()
/**
/**
* 实际上是个随机数, 但服务器确实是用它当做 uid
* 实际上是个随机数, 但服务器确实是用它当做 uid
*/
*/
val
messageUid
:
Long
val
messageUid
:
Int
/**
/**
* 发送时间, 单位为秒
* 发送时间, 单位为秒
...
@@ -42,17 +54,22 @@ interface MessageSource : Message {
...
@@ -42,17 +54,22 @@ interface MessageSource : Message {
val
senderId
:
Long
val
senderId
:
Long
/**
/**
* 群号码
* 群号码
, 为 0 时则来自好友消息
*/
*/
val
groupId
:
Long
val
groupId
:
Long
/**
* 原消息内容
*/
val
sourceMessage
:
MessageChain
/**
/**
* 固定返回空字符串 ("")
* 固定返回空字符串 ("")
*/
*/
override
fun
toString
():
String
override
fun
toString
():
String
}
}
\ No newline at end of file
/**
* 消息唯一标识符. 实际上是个随机数, 但服务器确实是用它当做 uid
*/
val
MessageChain
.
messageUid
get
()
=
this
[
MessageSource
].
messageUid
/**
* 消息序列号, 可能来自服务器也可以发送时赋值, 不唯一.
*/
val
MessageChain
.
sequenceId
get
()
=
this
[
MessageSource
].
sequenceId
\ No newline at end of file
mirai-core/src/commonMain/kotlin/net.mamoe.mirai/message/data/PlainText.kt
View file @
e9c79429
...
@@ -25,28 +25,10 @@ inline class PlainText(val stringValue: String) : Message {
...
@@ -25,28 +25,10 @@ inline class PlainText(val stringValue: String) : Message {
override
fun
toString
():
String
=
stringValue
override
fun
toString
():
String
=
stringValue
companion
object
Key
:
Message
.
Key
<
PlainText
>
companion
object
Key
:
Message
.
Key
<
PlainText
>
override
fun
eq
(
other
:
Message
):
Boolean
{
if
(
other
is
MessageChain
)
{
return
other
eq
this
.
toString
()
}
return
other
is
PlainText
&&
other
.
stringValue
==
this
.
stringValue
}
}
}
/**
/**
* 构造 [PlainText]
* 构造 [PlainText]
*/
*/
@Suppress
(
"NOTHING_TO_INLINE"
)
@Suppress
(
"NOTHING_TO_INLINE"
)
inline
fun
String
.
toMessage
():
PlainText
=
PlainText
(
this
)
inline
fun
String
.
toMessage
():
PlainText
=
PlainText
(
this
)
\ No newline at end of file
/**
* 得到包含作为 [PlainText] 的 [this] 的 [MessageChain].
*
* @return 唯一成员且不可修改的 [SingleMessageChainImpl]
*
* @see SingleMessageChain
* @see SingleMessageChainImpl
*/
@Suppress
(
"NOTHING_TO_INLINE"
)
inline
fun
String
.
singleChain
():
MessageChain
=
SingleMessageChainImpl
(
this
.
toMessage
())
\ No newline at end of file
mirai-core/src/commonMain/kotlin/net.mamoe.mirai/message/data/XML.kt
View file @
e9c79429
...
@@ -27,10 +27,6 @@ inline class XMLMessage(val stringValue: String) : Message,
...
@@ -27,10 +27,6 @@ inline class XMLMessage(val stringValue: String) : Message,
SingleOnly
{
SingleOnly
{
override
fun
followedBy
(
tail
:
Message
):
Nothing
=
error
(
"XMLMessage Message cannot be followed"
)
override
fun
followedBy
(
tail
:
Message
):
Nothing
=
error
(
"XMLMessage Message cannot be followed"
)
override
fun
toString
():
String
=
stringValue
override
fun
toString
():
String
=
stringValue
override
fun
eq
(
other
:
Message
):
Boolean
{
return
other
is
XMLMessage
&&
other
.
stringValue
==
this
.
stringValue
}
}
}
/**
/**
...
...
mirai-core/src/commonMain/kotlin/net.mamoe.mirai/utils/ExternalImage.kt
View file @
e9c79429
...
@@ -51,9 +51,39 @@ class ExternalImage(
...
@@ -51,9 +51,39 @@ class ExternalImage(
filename
:
String
filename
:
String
):
ExternalImage
=
ExternalImage
(
width
,
height
,
md5
,
format
,
data
,
data
.
remaining
,
filename
)
):
ExternalImage
=
ExternalImage
(
width
,
height
,
md5
,
format
,
data
,
data
.
remaining
,
filename
)
fun
generateUUID
(
md5
:
ByteArray
):
String
{
fun
generateUUID
(
md5
:
ByteArray
):
String
{
return
"${md5[0..3]}-${md5[4..5]}-${md5[6..7]}-${md5[8..9]}-${md5[10..15]}"
return
"${md5[0..3]}-${md5[4..5]}-${md5[6..7]}-${md5[8..9]}-${md5[10..15]}"
}
}
fun
generateImageId
(
md5
:
ByteArray
,
imageType
:
Int
):
String
{
return
"""{${generateUUID(md5)}}.${determineFormat(imageType)}"""
}
fun
determineImageType
(
format
:
String
):
Int
{
return
when
(
format
)
{
"jpg"
->
1000
"png"
->
1001
"webp"
->
1002
"bmp"
->
1005
"gig"
->
2000
"apng"
->
2001
"sharpp"
->
1004
else
->
1000
// unsupported, just make it jpg
}
}
fun
determineFormat
(
imageType
:
Int
):
String
{
return
when
(
imageType
)
{
1000
->
"jpg"
1001
->
"png"
1002
->
"webp"
1005
->
"bmp"
2000
->
"gig"
2001
->
"apng"
1004
->
"sharpp"
else
->
"jpg"
// unsupported, just make it jpg
}
}
}
}
val
format
:
String
=
val
format
:
String
=
...
@@ -73,16 +103,7 @@ class ExternalImage(
...
@@ -73,16 +103,7 @@ class ExternalImage(
* SHARPP: 1004
* SHARPP: 1004
*/
*/
val
imageType
:
Int
val
imageType
:
Int
get
()
=
when
(
format
)
{
get
()
=
determineImageType
(
format
)
"jpg"
->
1000
"png"
->
1001
"webp"
->
1002
"bmp"
->
1005
"gig"
->
2000
"apng"
->
2001
"sharpp"
->
1004
else
->
1000
// unsupported, just make it jpg
}
override
fun
toString
():
String
=
"[ExternalImage(${width}x$height $format)]"
override
fun
toString
():
String
=
"[ExternalImage(${width}x$height $format)]"
...
...
mirai-core/src/commonMain/kotlin/net.mamoe.mirai/utils/LockFreeLinkedList.kt
View file @
e9c79429
...
@@ -68,6 +68,10 @@ fun <E> LockFreeLinkedList<E>.asSequence(): Sequence<E> {
...
@@ -68,6 +68,10 @@ fun <E> LockFreeLinkedList<E>.asSequence(): Sequence<E> {
}
}
}
}
operator
fun
<
E
>
LockFreeLinkedList
<
E
>.
iterator
():
Iterator
<
E
>
{
return
asSequence
().
iterator
()
}
/**
/**
* 构建链表结构然后转为 [LockFreeLinkedList]
* 构建链表结构然后转为 [LockFreeLinkedList]
*/
*/
...
...
mirai-core/src/commonMain/kotlin/net.mamoe.mirai/utils/io/ByteArrayPool.kt
View file @
e9c79429
...
@@ -13,7 +13,7 @@ import kotlinx.io.pool.DefaultPool
...
@@ -13,7 +13,7 @@ import kotlinx.io.pool.DefaultPool
import
kotlinx.io.pool.ObjectPool
import
kotlinx.io.pool.ObjectPool
internal
const
val
DEFAULT_BYTE_ARRAY_POOL_SIZE
=
256
internal
const
val
DEFAULT_BYTE_ARRAY_POOL_SIZE
=
256
internal
const
val
DEFAULT_BYTE_ARRAY_SIZE
=
81920
internal
const
val
DEFAULT_BYTE_ARRAY_SIZE
=
81920
/
2
val
ByteArrayPool
:
ObjectPool
<
ByteArray
>
=
ByteArrayPoolImpl
val
ByteArrayPool
:
ObjectPool
<
ByteArray
>
=
ByteArrayPoolImpl
...
...
mirai-core/src/jvmMain/kotlin/net/mamoe/mirai/message/MessagePacket.kt
View file @
e9c79429
...
@@ -16,7 +16,6 @@ import kotlinx.coroutines.withContext
...
@@ -16,7 +16,6 @@ import kotlinx.coroutines.withContext
import
kotlinx.io.core.Input
import
kotlinx.io.core.Input
import
kotlinx.io.core.use
import
kotlinx.io.core.use
import
kotlinx.io.streams.inputStream
import
kotlinx.io.streams.inputStream
import
net.mamoe.mirai.Bot
import
net.mamoe.mirai.contact.Contact
import
net.mamoe.mirai.contact.Contact
import
net.mamoe.mirai.contact.QQ
import
net.mamoe.mirai.contact.QQ
import
net.mamoe.mirai.message.data.Image
import
net.mamoe.mirai.message.data.Image
...
@@ -35,7 +34,7 @@ import javax.imageio.ImageIO
...
@@ -35,7 +34,7 @@ import javax.imageio.ImageIO
* JVM 平台相关扩展
* JVM 平台相关扩展
*/
*/
@UseExperimental
(
MiraiInternalAPI
::
class
)
@UseExperimental
(
MiraiInternalAPI
::
class
)
actual
abstract
class
MessagePacket
<
TSender
:
QQ
,
TSubject
:
Contact
>
actual
constructor
(
bot
:
Bot
)
:
MessagePacketBase
<
TSender
,
TSubject
>(
bot
)
{
actual
abstract
class
MessagePacket
<
TSender
:
QQ
,
TSubject
:
Contact
>
actual
constructor
(
)
:
MessagePacketBase
<
TSender
,
TSubject
>(
)
{
// region 上传图片
// region 上传图片
suspend
inline
fun
uploadImage
(
image
:
BufferedImage
):
Image
=
subject
.
uploadImage
(
image
)
suspend
inline
fun
uploadImage
(
image
:
BufferedImage
):
Image
=
subject
.
uploadImage
(
image
)
...
...
mirai-demos/mirai-demo-1/src/main/java/demo/subscribe/SubscribeSamples.kt
View file @
e9c79429
...
@@ -16,17 +16,14 @@ import net.mamoe.mirai.Bot
...
@@ -16,17 +16,14 @@ 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
import
net.mamoe.mirai.contact.QQ
import
net.mamoe.mirai.contact.QQ
import
net.mamoe.mirai.contact.isOperator
import
net.mamoe.mirai.contact.sendMessage
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.*
import
net.mamoe.mirai.message.data.Image
import
net.mamoe.mirai.message.nextMessage
import
net.mamoe.mirai.message.data.PlainText
import
net.mamoe.mirai.message.data.firstOrNull
import
net.mamoe.mirai.message.sendAsImageTo
import
net.mamoe.mirai.message.sendAsImageTo
import
net.mamoe.mirai.qqandroid.Bot
import
net.mamoe.mirai.qqandroid.QQAndroid
import
net.mamoe.mirai.utils.FileBasedDeviceInfo
import
net.mamoe.mirai.utils.FileBasedDeviceInfo
import
net.mamoe.mirai.utils.MiraiInternalAPI
import
net.mamoe.mirai.utils.MiraiInternalAPI
import
java.io.File
import
java.io.File
...
@@ -49,7 +46,7 @@ private fun readTestAccount(): BotAccount? {
...
@@ -49,7 +46,7 @@ private fun readTestAccount(): BotAccount? {
@Suppress
(
"UNUSED_VARIABLE"
)
@Suppress
(
"UNUSED_VARIABLE"
)
suspend
fun
main
()
{
suspend
fun
main
()
{
val
bot
=
QQAndroid
.
Bot
(
// JVM 下也可以不写 `QQAndroid.` 引用顶层函数
val
bot
=
Bot
(
// JVM 下也可以不写 `QQAndroid.` 引用顶层函数
123456789
,
123456789
,
"123456"
"123456"
)
{
)
{
...
@@ -207,6 +204,25 @@ fun Bot.messageDSL() {
...
@@ -207,6 +204,25 @@ fun Bot.messageDSL() {
// sender: QQ
// sender: QQ
// it: String (来自 MessageChain.toString)
// it: String (来自 MessageChain.toString)
// group: Group
// group: Group
case
(
"recall"
)
{
reply
(
"😎"
).
recallIn
(
3000
)
// 3 秒后自动撤回这条消息
}
case
(
"禁言"
)
{
// 挂起当前协程, 等待下一条满足条件的消息.
// 发送 "禁言" 后需要再发送一条消息 at 一个人.
val
value
:
At
=
nextMessage
{
message
.
any
(
At
)
}[
At
]
value
.
member
().
mute
(
10
)
}
startsWith
(
"群名="
)
{
if
(!
sender
.
isOperator
())
{
sender
.
mute
(
5
)
return
@
startsWith
}
group
.
name
=
it
}
}
}
}
}
...
...
mirai-japt/src/main/java/net/mamoe/mirai/japt/BlockingContact.java
View file @
e9c79429
...
@@ -9,6 +9,7 @@ import net.mamoe.mirai.event.events.EventCancelledException;
...
@@ -9,6 +9,7 @@ import net.mamoe.mirai.event.events.EventCancelledException;
import
net.mamoe.mirai.event.events.ImageUploadEvent
;
import
net.mamoe.mirai.event.events.ImageUploadEvent
;
import
net.mamoe.mirai.event.events.MessageSendEvent.FriendMessageSendEvent
;
import
net.mamoe.mirai.event.events.MessageSendEvent.FriendMessageSendEvent
;
import
net.mamoe.mirai.event.events.MessageSendEvent.GroupMessageSendEvent
;
import
net.mamoe.mirai.event.events.MessageSendEvent.GroupMessageSendEvent
;
import
net.mamoe.mirai.message.MessageReceipt
;
import
net.mamoe.mirai.message.data.Image
;
import
net.mamoe.mirai.message.data.Image
;
import
net.mamoe.mirai.message.data.Message
;
import
net.mamoe.mirai.message.data.Message
;
import
net.mamoe.mirai.message.data.MessageChain
;
import
net.mamoe.mirai.message.data.MessageChain
;
...
@@ -42,8 +43,7 @@ public interface BlockingContact {
...
@@ -42,8 +43,7 @@ public interface BlockingContact {
* @see FriendMessageSendEvent 发送好友信息事件, cancellable
* @see FriendMessageSendEvent 发送好友信息事件, cancellable
* @see GroupMessageSendEvent 发送群消息事件. cancellable
* @see GroupMessageSendEvent 发送群消息事件. cancellable
*/
*/
// kotlin bug
MessageReceipt
<?
extends
Contact
>
sendMessage
(
@NotNull
MessageChain
messages
)
throws
EventCancelledException
,
IllegalStateException
;
void
sendMessage
(
@NotNull
MessageChain
messages
)
throws
EventCancelledException
,
IllegalStateException
;
/**
/**
* 向这个对象发送消息.
* 向这个对象发送消息.
...
@@ -53,7 +53,7 @@ public interface BlockingContact {
...
@@ -53,7 +53,7 @@ public interface BlockingContact {
* @see FriendMessageSendEvent 发送好友信息事件, cancellable
* @see FriendMessageSendEvent 发送好友信息事件, cancellable
* @see GroupMessageSendEvent 发送群消息事件. cancellable
* @see GroupMessageSendEvent 发送群消息事件. cancellable
*/
*/
void
sendMessage
(
@NotNull
String
message
)
throws
EventCancelledException
,
IllegalStateException
;
MessageReceipt
<?
extends
Contact
>
sendMessage
(
@NotNull
String
message
)
throws
EventCancelledException
,
IllegalStateException
;
/**
/**
* 向这个对象发送消息.
* 向这个对象发送消息.
...
@@ -63,7 +63,7 @@ public interface BlockingContact {
...
@@ -63,7 +63,7 @@ public interface BlockingContact {
* @see FriendMessageSendEvent 发送好友信息事件, cancellable
* @see FriendMessageSendEvent 发送好友信息事件, cancellable
* @see GroupMessageSendEvent 发送群消息事件. cancellable
* @see GroupMessageSendEvent 发送群消息事件. cancellable
*/
*/
void
sendMessage
(
@NotNull
Message
message
)
throws
EventCancelledException
,
IllegalStateException
;
MessageReceipt
<?
extends
Contact
>
sendMessage
(
@NotNull
Message
message
)
throws
EventCancelledException
,
IllegalStateException
;
/**
/**
* 上传一个图片以备发送.
* 上传一个图片以备发送.
...
...
mirai-japt/src/main/java/net/mamoe/mirai/japt/BlockingGroup.java
View file @
e9c79429
...
@@ -3,6 +3,9 @@ package net.mamoe.mirai.japt;
...
@@ -3,6 +3,9 @@ package net.mamoe.mirai.japt;
import
net.mamoe.mirai.contact.*
;
import
net.mamoe.mirai.contact.*
;
import
net.mamoe.mirai.data.MemberInfo
;
import
net.mamoe.mirai.data.MemberInfo
;
import
net.mamoe.mirai.event.events.*
;
import
net.mamoe.mirai.event.events.*
;
import
net.mamoe.mirai.message.MessageReceipt
;
import
net.mamoe.mirai.message.data.Message
;
import
net.mamoe.mirai.message.data.MessageChain
;
import
net.mamoe.mirai.utils.MiraiExperimentalAPI
;
import
net.mamoe.mirai.utils.MiraiExperimentalAPI
;
import
org.jetbrains.annotations.NotNull
;
import
org.jetbrains.annotations.NotNull
;
import
org.jetbrains.annotations.Nullable
;
import
org.jetbrains.annotations.Nullable
;
...
@@ -152,6 +155,36 @@ public interface BlockingGroup extends BlockingContact {
...
@@ -152,6 +155,36 @@ public interface BlockingGroup extends BlockingContact {
@Nullable
@Nullable
BlockingMember
getMemberOrNull
(
long
id
);
BlockingMember
getMemberOrNull
(
long
id
);
/**
* 向这个对象发送消息.
*
* @throws EventCancelledException 当发送消息事件被取消
* @throws IllegalStateException 发送群消息时若 [Bot] 被禁言抛出
* @see MessageSendEvent.FriendMessageSendEvent 发送好友信息事件, cancellable
* @see MessageSendEvent.GroupMessageSendEvent 发送群消息事件. cancellable
*/
MessageReceipt
<
Group
>
sendMessage
(
@NotNull
MessageChain
messages
)
throws
EventCancelledException
,
IllegalStateException
;
/**
* 向这个对象发送消息.
*
* @throws EventCancelledException 当发送消息事件被取消
* @throws IllegalStateException 发送群消息时若 [Bot] 被禁言抛出
* @see MessageSendEvent.FriendMessageSendEvent 发送好友信息事件, cancellable
* @see MessageSendEvent.GroupMessageSendEvent 发送群消息事件. cancellable
*/
MessageReceipt
<
Group
>
sendMessage
(
@NotNull
String
message
)
throws
EventCancelledException
,
IllegalStateException
;
/**
* 向这个对象发送消息.
*
* @throws EventCancelledException 当发送消息事件被取消
* @throws IllegalStateException 发送群消息时若 [Bot] 被禁言抛出
* @see MessageSendEvent.FriendMessageSendEvent 发送好友信息事件, cancellable
* @see MessageSendEvent.GroupMessageSendEvent 发送群消息事件. cancellable
*/
MessageReceipt
<
Group
>
sendMessage
(
@NotNull
Message
message
)
throws
EventCancelledException
,
IllegalStateException
;
/**
/**
* 检查此 id 的群成员是否存在
* 检查此 id 的群成员是否存在
*/
*/
...
...
mirai-japt/src/main/java/net/mamoe/mirai/japt/BlockingQQ.java
View file @
e9c79429
package
net.mamoe.mirai.japt
;
package
net.mamoe.mirai.japt
;
import
net.mamoe.mirai.contact.QQ
;
import
net.mamoe.mirai.data.FriendNameRemark
;
import
net.mamoe.mirai.data.FriendNameRemark
;
import
net.mamoe.mirai.data.PreviousNameList
;
import
net.mamoe.mirai.data.PreviousNameList
;
import
net.mamoe.mirai.data.Profile
;
import
net.mamoe.mirai.data.Profile
;
import
net.mamoe.mirai.event.events.EventCancelledException
;
import
net.mamoe.mirai.event.events.MessageSendEvent
;
import
net.mamoe.mirai.message.MessageReceipt
;
import
net.mamoe.mirai.message.data.Message
;
import
net.mamoe.mirai.message.data.MessageChain
;
import
net.mamoe.mirai.utils.MiraiExperimentalAPI
;
import
net.mamoe.mirai.utils.MiraiExperimentalAPI
;
import
org.jetbrains.annotations.NotNull
;
import
org.jetbrains.annotations.NotNull
;
...
@@ -47,4 +53,35 @@ public interface BlockingQQ extends BlockingContact {
...
@@ -47,4 +53,35 @@ public interface BlockingQQ extends BlockingContact {
@MiraiExperimentalAPI
(
message
=
"还未支持"
)
@MiraiExperimentalAPI
(
message
=
"还未支持"
)
@NotNull
@NotNull
FriendNameRemark
queryRemark
();
FriendNameRemark
queryRemark
();
/**
* 向这个对象发送消息.
*
* @throws EventCancelledException 当发送消息事件被取消
* @throws IllegalStateException 发送群消息时若 [Bot] 被禁言抛出
* @see MessageSendEvent.FriendMessageSendEvent 发送好友信息事件, cancellable
* @see MessageSendEvent.GroupMessageSendEvent 发送群消息事件. cancellable
*/
MessageReceipt
<
QQ
>
sendMessage
(
@NotNull
MessageChain
messages
)
throws
EventCancelledException
,
IllegalStateException
;
/**
* 向这个对象发送消息.
*
* @throws EventCancelledException 当发送消息事件被取消
* @throws IllegalStateException 发送群消息时若 [Bot] 被禁言抛出
* @see MessageSendEvent.FriendMessageSendEvent 发送好友信息事件, cancellable
* @see MessageSendEvent.GroupMessageSendEvent 发送群消息事件. cancellable
*/
MessageReceipt
<
QQ
>
sendMessage
(
@NotNull
String
message
)
throws
EventCancelledException
,
IllegalStateException
;
/**
* 向这个对象发送消息.
*
* @throws EventCancelledException 当发送消息事件被取消
* @throws IllegalStateException 发送群消息时若 [Bot] 被禁言抛出
* @see MessageSendEvent.FriendMessageSendEvent 发送好友信息事件, cancellable
* @see MessageSendEvent.GroupMessageSendEvent 发送群消息事件. cancellable
*/
MessageReceipt
<
QQ
>
sendMessage
(
@NotNull
Message
message
)
throws
EventCancelledException
,
IllegalStateException
;
}
}
mirai-japt/src/main/kotlin/net/mamoe/mirai/japt/internal/BlockingContactsImpl.kt
View file @
e9c79429
...
@@ -24,6 +24,7 @@ import net.mamoe.mirai.japt.BlockingBot
...
@@ -24,6 +24,7 @@ import net.mamoe.mirai.japt.BlockingBot
import
net.mamoe.mirai.japt.BlockingGroup
import
net.mamoe.mirai.japt.BlockingGroup
import
net.mamoe.mirai.japt.BlockingMember
import
net.mamoe.mirai.japt.BlockingMember
import
net.mamoe.mirai.japt.BlockingQQ
import
net.mamoe.mirai.japt.BlockingQQ
import
net.mamoe.mirai.message.MessageReceipt
import
net.mamoe.mirai.message.data.*
import
net.mamoe.mirai.message.data.*
import
net.mamoe.mirai.utils.ExternalImage
import
net.mamoe.mirai.utils.ExternalImage
import
net.mamoe.mirai.utils.MiraiExperimentalAPI
import
net.mamoe.mirai.utils.MiraiExperimentalAPI
...
@@ -35,9 +36,9 @@ internal class BlockingQQImpl(private val delegate: QQ) : BlockingQQ {
...
@@ -35,9 +36,9 @@ internal class BlockingQQImpl(private val delegate: QQ) : BlockingQQ {
override
fun
getId
():
Long
=
delegate
.
id
override
fun
getId
():
Long
=
delegate
.
id
override
fun
getNick
():
String
=
delegate
.
nick
override
fun
getNick
():
String
=
delegate
.
nick
override
fun
sendMessage
(
messages
:
MessageChain
)
=
runBlocking
{
delegate
.
sendMessage
(
messages
)
}
override
fun
sendMessage
(
messages
:
MessageChain
)
:
MessageReceipt
<
QQ
>
=
runBlocking
{
delegate
.
sendMessage
(
messages
)
}
override
fun
sendMessage
(
message
:
String
)
=
runBlocking
{
delegate
.
sendMessage
(
message
.
toMessage
().
toChain
())
}
override
fun
sendMessage
(
message
:
String
)
:
MessageReceipt
<
QQ
>
=
runBlocking
{
delegate
.
sendMessage
(
message
.
toMessage
().
toChain
())
}
override
fun
sendMessage
(
message
:
Message
)
=
runBlocking
{
delegate
.
sendMessage
(
message
.
toChain
())
}
override
fun
sendMessage
(
message
:
Message
)
:
MessageReceipt
<
QQ
>
=
runBlocking
{
delegate
.
sendMessage
(
message
.
toChain
())
}
override
fun
uploadImage
(
image
:
ExternalImage
):
Image
=
runBlocking
{
delegate
.
uploadImage
(
image
)
}
override
fun
uploadImage
(
image
:
ExternalImage
):
Image
=
runBlocking
{
delegate
.
uploadImage
(
image
)
}
@MiraiExperimentalAPI
@MiraiExperimentalAPI
...
@@ -51,9 +52,9 @@ internal class BlockingQQImpl(private val delegate: QQ) : BlockingQQ {
...
@@ -51,9 +52,9 @@ internal class BlockingQQImpl(private val delegate: QQ) : BlockingQQ {
}
}
internal
class
BlockingGroupImpl
(
private
val
delegate
:
Group
)
:
BlockingGroup
{
internal
class
BlockingGroupImpl
(
private
val
delegate
:
Group
)
:
BlockingGroup
{
override
fun
sendMessage
(
messages
:
MessageChain
)
=
runBlocking
{
delegate
.
sendMessage
(
messages
)
}
override
fun
sendMessage
(
messages
:
MessageChain
)
:
MessageReceipt
<
Group
>
=
runBlocking
{
delegate
.
sendMessage
(
messages
)
}
override
fun
sendMessage
(
message
:
String
)
=
runBlocking
{
delegate
.
sendMessage
(
message
.
toMessage
().
toChain
())
}
override
fun
sendMessage
(
message
:
String
)
:
MessageReceipt
<
Group
>
=
runBlocking
{
delegate
.
sendMessage
(
message
.
toMessage
().
toChain
())
}
override
fun
sendMessage
(
message
:
Message
)
=
runBlocking
{
delegate
.
sendMessage
(
message
.
toChain
())
}
override
fun
sendMessage
(
message
:
Message
)
:
MessageReceipt
<
Group
>
=
runBlocking
{
delegate
.
sendMessage
(
message
.
toChain
())
}
override
fun
getOwner
():
BlockingMember
=
delegate
.
owner
.
blocking
()
override
fun
getOwner
():
BlockingMember
=
delegate
.
owner
.
blocking
()
@MiraiExperimentalAPI
@MiraiExperimentalAPI
override
fun
newMember
(
memberInfo
:
MemberInfo
):
Member
=
delegate
.
Member
(
memberInfo
)
override
fun
newMember
(
memberInfo
:
MemberInfo
):
Member
=
delegate
.
Member
(
memberInfo
)
...
...
Write
Preview
Markdown
is supported
0%
Try again
or
attach a new file
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment