From 220d293b7a9d9bba6992068df1e9dd1e321dd679 Mon Sep 17 00:00:00 2001 From: luo123 Date: Fri, 13 Mar 2020 21:06:57 +0800 Subject: [PATCH 1/6] get group announce list --- mirai-core-qqandroid/build.gradle.kts | 6 +++ .../net/mamoe/mirai/qqandroid/ContactImpl.kt | 42 +++++++++++++++++++ .../network/protocol/packet/login/WtLogin.kt | 1 + .../kotlin/net.mamoe.mirai/contact/Group.kt | 11 +++++ .../net.mamoe.mirai/data/GroupAnnouncement.kt | 36 ++++++++++++++++ .../kotlin/net/mamoe/mirai/contact/Group.kt | 9 ++++ 6 files changed, 105 insertions(+) create mode 100644 mirai-core/src/commonMain/kotlin/net.mamoe.mirai/data/GroupAnnouncement.kt diff --git a/mirai-core-qqandroid/build.gradle.kts b/mirai-core-qqandroid/build.gradle.kts index 8179cd718..644956ee7 100644 --- a/mirai-core-qqandroid/build.gradle.kts +++ b/mirai-core-qqandroid/build.gradle.kts @@ -72,6 +72,11 @@ kotlin { api(kotlinx("io", kotlinXIoVersion)) api(kotlinx("coroutines-io", coroutinesIoVersion)) api(kotlinx("coroutines-core", coroutinesVersion)) + + api(ktor("client-core", ktorVersion)) + + implementation(ktor("client-json",ktorVersion)) + implementation(ktor("client-serialization",ktorVersion)) } } commonMain { @@ -110,6 +115,7 @@ kotlin { runtimeOnly(files("build/classes/kotlin/jvm/main")) // classpath is not properly set by IDE api(kotlinx("serialization-runtime", serializationVersion)) //api(kotlinx("serialization-protobuf", serializationVersion)) + } } diff --git a/mirai-core-qqandroid/src/commonMain/kotlin/net/mamoe/mirai/qqandroid/ContactImpl.kt b/mirai-core-qqandroid/src/commonMain/kotlin/net/mamoe/mirai/qqandroid/ContactImpl.kt index d67a04053..55dc4f0ba 100644 --- a/mirai-core-qqandroid/src/commonMain/kotlin/net/mamoe/mirai/qqandroid/ContactImpl.kt +++ b/mirai-core-qqandroid/src/commonMain/kotlin/net/mamoe/mirai/qqandroid/ContactImpl.kt @@ -9,6 +9,12 @@ package net.mamoe.mirai.qqandroid +import io.ktor.client.HttpClient +import io.ktor.client.features.json.JsonFeature +import io.ktor.client.features.json.serializer.KotlinxSerializer +import io.ktor.client.request.* +import io.ktor.client.request.forms.formData +import kotlinx.coroutines.async import kotlinx.coroutines.launch import kotlinx.coroutines.withTimeoutOrNull import kotlinx.io.core.Closeable @@ -35,6 +41,7 @@ import net.mamoe.mirai.qqandroid.network.protocol.packet.chat.image.LongConn import net.mamoe.mirai.qqandroid.network.protocol.packet.chat.receive.MessageSvc import net.mamoe.mirai.qqandroid.utils.toIpV4AddressString import net.mamoe.mirai.utils.* +import net.mamoe.mirai.utils.io.encodeToString import net.mamoe.mirai.utils.io.toUHexString import kotlin.contracts.ExperimentalContracts import kotlin.contracts.contract @@ -559,6 +566,29 @@ internal class GroupImpl( TODO("not implemented") } + @MiraiExperimentalAPI + override suspend fun getAnnouncements(page: Int, amount: Int): GroupAnnouncementList { + val data = bot.network.async { + HttpClient { install(JsonFeature) { serializer = KotlinxSerializer() } }.post { + url("https://web.qun.qq.com/cgi-bin/announce/list_announce") + formData { + append("qid", id) + append("bkn", getBkn()) + append("ft", 23) //好像是一个用来识别应用的参数 + append("s", -page) // 第一页这里的参数应该是-1 + append("n", amount) + append("format", "json") + } + header( + "cookie", + "uin=o${bot.selfQQ.id}; skey=${bot.client.wLoginSigInfo.sKey.data.encodeToString()}; p_uin=o${bot.selfQQ.id};" + ) + } + } + return data.await() + } + + @OptIn(MiraiExperimentalAPI::class) override fun Member(memberInfo: MemberInfo): Member { return MemberImpl( @@ -719,4 +749,16 @@ internal class GroupImpl( if (this::class != other::class) return false return this.id == other.id && this.bot == other.bot } + + /* + * 获取 获取群公告 所需的bkn参数 + * */ + fun getBkn(): Int { + val str = bot.client.wLoginSigInfo.sKey.data.encodeToString() + var magic = 5381 + for (i in str) { + magic += magic.shl(5) + i.toInt() + } + return Int.MAX_VALUE.and(magic) + } } \ No newline at end of file diff --git a/mirai-core-qqandroid/src/commonMain/kotlin/net/mamoe/mirai/qqandroid/network/protocol/packet/login/WtLogin.kt b/mirai-core-qqandroid/src/commonMain/kotlin/net/mamoe/mirai/qqandroid/network/protocol/packet/login/WtLogin.kt index 5b7365394..d15683d68 100644 --- a/mirai-core-qqandroid/src/commonMain/kotlin/net/mamoe/mirai/qqandroid/network/protocol/packet/login/WtLogin.kt +++ b/mirai-core-qqandroid/src/commonMain/kotlin/net/mamoe/mirai/qqandroid/network/protocol/packet/login/WtLogin.kt @@ -602,6 +602,7 @@ internal class WtLogin { userA5 = UserA5(tlvMap119.getOrEmpty(0x10b), creationTime), userA8 = UserA8(tlvMap119.getOrEmpty(0x102), creationTime, expireTime) ) + //bot.network.logger.error(client.wLoginSigInfo.sKey.data.encodeToString()) } } diff --git a/mirai-core/src/commonMain/kotlin/net.mamoe.mirai/contact/Group.kt b/mirai-core/src/commonMain/kotlin/net.mamoe.mirai/contact/Group.kt index 15c7e97d7..88e05cbd6 100644 --- a/mirai-core/src/commonMain/kotlin/net.mamoe.mirai/contact/Group.kt +++ b/mirai-core/src/commonMain/kotlin/net.mamoe.mirai/contact/Group.kt @@ -12,7 +12,11 @@ package net.mamoe.mirai.contact import kotlinx.coroutines.CoroutineScope +import kotlinx.serialization.SerialInfo +import kotlinx.serialization.SerialName +import kotlinx.serialization.Serializable import net.mamoe.mirai.Bot +import net.mamoe.mirai.data.GroupAnnouncementList import net.mamoe.mirai.data.MemberInfo import net.mamoe.mirai.event.events.* import net.mamoe.mirai.event.events.MessageSendEvent.FriendMessageSendEvent @@ -148,6 +152,13 @@ expect abstract class Group() : Contact, CoroutineScope { */ abstract operator fun contains(id: Long): Boolean + /** + * 获取群公告列表 + * + * */ + @MiraiExperimentalAPI + abstract suspend fun getAnnouncements(page: Int = 1, amount: Int = 10):GroupAnnouncementList + /** * 让机器人退出这个群. 机器人必须为非群主才能退出. 否则将会失败 */ diff --git a/mirai-core/src/commonMain/kotlin/net.mamoe.mirai/data/GroupAnnouncement.kt b/mirai-core/src/commonMain/kotlin/net.mamoe.mirai/data/GroupAnnouncement.kt new file mode 100644 index 000000000..9bd272d37 --- /dev/null +++ b/mirai-core/src/commonMain/kotlin/net.mamoe.mirai/data/GroupAnnouncement.kt @@ -0,0 +1,36 @@ +package net.mamoe.mirai.data + +import kotlinx.serialization.SerialName +import kotlinx.serialization.Serializable + +/** + * 群公告数据类 + * + * + */ +@Serializable +data class GroupAnnouncementList( + val feeds: List +) + +@Serializable +data class GroupAnnouncement( + @SerialName("u") val sender: Long, + val msg: GroupAnnouncementMsg, + val settings: GroupAnnouncementSettings +) + +@Serializable +data class GroupAnnouncementMsg( + val text: String, + val text_face: String, + val title: String +) + +@Serializable +data class GroupAnnouncementSettings( + @SerialName("is_show_edit_card") val isShowEditCard: Int, + @SerialName("remind_ts") val remindTs: Int, + @SerialName("tip_window_type") val tipWindowType: Int, + @SerialName("confirm_required") val confirmRequired: Int +) \ No newline at end of file diff --git a/mirai-core/src/jvmMain/kotlin/net/mamoe/mirai/contact/Group.kt b/mirai-core/src/jvmMain/kotlin/net/mamoe/mirai/contact/Group.kt index c1a6d1c21..025754431 100644 --- a/mirai-core/src/jvmMain/kotlin/net/mamoe/mirai/contact/Group.kt +++ b/mirai-core/src/jvmMain/kotlin/net/mamoe/mirai/contact/Group.kt @@ -11,6 +11,7 @@ package net.mamoe.mirai.contact import kotlinx.coroutines.CoroutineScope import net.mamoe.mirai.Bot +import net.mamoe.mirai.data.GroupAnnouncementList import net.mamoe.mirai.data.MemberInfo import net.mamoe.mirai.event.events.* import net.mamoe.mirai.event.events.MessageSendEvent.FriendMessageSendEvent @@ -146,6 +147,14 @@ actual abstract class Group : Contact(), CoroutineScope { */ actual abstract fun getOrNull(id: Long): Member? + + /** + * 获取群公告列表 + * + * */ + @MiraiExperimentalAPI + actual suspend abstract fun getAnnouncements(page: Int, amount: Int ):GroupAnnouncementList + /** * 检查此 id 的群成员是否存在 */ From aa61e9441a0ef962e52c0e26dbabf04f137e4fa2 Mon Sep 17 00:00:00 2001 From: luo123 Date: Fri, 13 Mar 2020 22:33:11 +0800 Subject: [PATCH 2/6] get GroupAnnouncementList is working now --- mirai-core-qqandroid/build.gradle.kts | 5 --- .../net/mamoe/mirai/qqandroid/ContactImpl.kt | 33 ++++++++++++------- .../kotlin/net.mamoe.mirai/contact/Group.kt | 2 +- .../net.mamoe.mirai/data/GroupAnnouncement.kt | 6 +++- .../kotlin/net/mamoe/mirai/contact/Group.kt | 2 +- 5 files changed, 29 insertions(+), 19 deletions(-) diff --git a/mirai-core-qqandroid/build.gradle.kts b/mirai-core-qqandroid/build.gradle.kts index 644956ee7..9793d514e 100644 --- a/mirai-core-qqandroid/build.gradle.kts +++ b/mirai-core-qqandroid/build.gradle.kts @@ -72,11 +72,6 @@ kotlin { api(kotlinx("io", kotlinXIoVersion)) api(kotlinx("coroutines-io", coroutinesIoVersion)) api(kotlinx("coroutines-core", coroutinesVersion)) - - api(ktor("client-core", ktorVersion)) - - implementation(ktor("client-json",ktorVersion)) - implementation(ktor("client-serialization",ktorVersion)) } } commonMain { diff --git a/mirai-core-qqandroid/src/commonMain/kotlin/net/mamoe/mirai/qqandroid/ContactImpl.kt b/mirai-core-qqandroid/src/commonMain/kotlin/net/mamoe/mirai/qqandroid/ContactImpl.kt index 55dc4f0ba..0a31dd4ef 100644 --- a/mirai-core-qqandroid/src/commonMain/kotlin/net/mamoe/mirai/qqandroid/ContactImpl.kt +++ b/mirai-core-qqandroid/src/commonMain/kotlin/net/mamoe/mirai/qqandroid/ContactImpl.kt @@ -10,14 +10,17 @@ package net.mamoe.mirai.qqandroid import io.ktor.client.HttpClient -import io.ktor.client.features.json.JsonFeature -import io.ktor.client.features.json.serializer.KotlinxSerializer import io.ktor.client.request.* +import io.ktor.client.request.forms.MultiPartFormDataContent import io.ktor.client.request.forms.formData import kotlinx.coroutines.async import kotlinx.coroutines.launch import kotlinx.coroutines.withTimeoutOrNull import kotlinx.io.core.Closeable +import kotlinx.serialization.MissingFieldException +import kotlinx.serialization.json.Json +import kotlinx.serialization.json.JsonConfiguration +import kotlinx.serialization.json.int import net.mamoe.mirai.LowLevelAPI import net.mamoe.mirai.contact.* import net.mamoe.mirai.data.* @@ -567,25 +570,33 @@ internal class GroupImpl( } @MiraiExperimentalAPI - override suspend fun getAnnouncements(page: Int, amount: Int): GroupAnnouncementList { + override suspend fun getAnnouncements(page: Int, amount: Int): GroupAnnouncementList? { + val json = Json(JsonConfiguration(ignoreUnknownKeys = true)) val data = bot.network.async { - HttpClient { install(JsonFeature) { serializer = KotlinxSerializer() } }.post { + HttpClient().post { url("https://web.qun.qq.com/cgi-bin/announce/list_announce") - formData { + body = MultiPartFormDataContent(formData { append("qid", id) append("bkn", getBkn()) append("ft", 23) //好像是一个用来识别应用的参数 - append("s", -page) // 第一页这里的参数应该是-1 + append("s", if (page ==1) 0 else -(page*amount+1)) // 第一页这里的参数应该是-1 append("n", amount) + append("ni",if (page ==1) 1 else 0) append("format", "json") + }) + headers { + append( + "cookie", + "uin=o${bot.selfQQ.id}; skey=${bot.client.wLoginSigInfo.sKey.data.encodeToString()}; p_uin=o${bot.selfQQ.id};" + ) } - header( - "cookie", - "uin=o${bot.selfQQ.id}; skey=${bot.client.wLoginSigInfo.sKey.data.encodeToString()}; p_uin=o${bot.selfQQ.id};" - ) } } - return data.await() + + val rep = data.await() + bot.network.logger.error(rep) + + return json.parse(GroupAnnouncementList.serializer(), rep) } diff --git a/mirai-core/src/commonMain/kotlin/net.mamoe.mirai/contact/Group.kt b/mirai-core/src/commonMain/kotlin/net.mamoe.mirai/contact/Group.kt index 88e05cbd6..8d19d83aa 100644 --- a/mirai-core/src/commonMain/kotlin/net.mamoe.mirai/contact/Group.kt +++ b/mirai-core/src/commonMain/kotlin/net.mamoe.mirai/contact/Group.kt @@ -157,7 +157,7 @@ expect abstract class Group() : Contact, CoroutineScope { * * */ @MiraiExperimentalAPI - abstract suspend fun getAnnouncements(page: Int = 1, amount: Int = 10):GroupAnnouncementList + abstract suspend fun getAnnouncements(page: Int = 1, amount: Int = 10):GroupAnnouncementList? /** * 让机器人退出这个群. 机器人必须为非群主才能退出. 否则将会失败 diff --git a/mirai-core/src/commonMain/kotlin/net.mamoe.mirai/data/GroupAnnouncement.kt b/mirai-core/src/commonMain/kotlin/net.mamoe.mirai/data/GroupAnnouncement.kt index 9bd272d37..bc59765d6 100644 --- a/mirai-core/src/commonMain/kotlin/net.mamoe.mirai/data/GroupAnnouncement.kt +++ b/mirai-core/src/commonMain/kotlin/net.mamoe.mirai/data/GroupAnnouncement.kt @@ -5,12 +5,16 @@ import kotlinx.serialization.Serializable /** * 群公告数据类 + * getGroupAnnouncementList时,如果page=1,那么你可以在inst里拿到一些置顶公告 * * */ @Serializable data class GroupAnnouncementList( - val feeds: List + val ec: Int, //状态码 0 是正常的 + @SerialName("em") val msg:String, //信息 + val feeds: List?, //群公告列表 + val inst: List? //置顶列表? ) @Serializable diff --git a/mirai-core/src/jvmMain/kotlin/net/mamoe/mirai/contact/Group.kt b/mirai-core/src/jvmMain/kotlin/net/mamoe/mirai/contact/Group.kt index 025754431..75c9499eb 100644 --- a/mirai-core/src/jvmMain/kotlin/net/mamoe/mirai/contact/Group.kt +++ b/mirai-core/src/jvmMain/kotlin/net/mamoe/mirai/contact/Group.kt @@ -153,7 +153,7 @@ actual abstract class Group : Contact(), CoroutineScope { * * */ @MiraiExperimentalAPI - actual suspend abstract fun getAnnouncements(page: Int, amount: Int ):GroupAnnouncementList + actual suspend abstract fun getAnnouncements(page: Int, amount: Int ):GroupAnnouncementList? /** * 检查此 id 的群成员是否存在 From e57215a6037747fa545ed947a601c3fde39d763d Mon Sep 17 00:00:00 2001 From: luo123 Date: Sat, 14 Mar 2020 00:07:52 +0800 Subject: [PATCH 3/6] send announcement --- .../net/mamoe/mirai/qqandroid/ContactImpl.kt | 49 +++++++++++++++---- .../network/protocol/packet/login/WtLogin.kt | 2 +- .../kotlin/net.mamoe.mirai/contact/Group.kt | 8 +++ .../net.mamoe.mirai/data/GroupAnnouncement.kt | 27 +++++----- .../kotlin/net/mamoe/mirai/contact/Group.kt | 10 +++- 5 files changed, 74 insertions(+), 22 deletions(-) diff --git a/mirai-core-qqandroid/src/commonMain/kotlin/net/mamoe/mirai/qqandroid/ContactImpl.kt b/mirai-core-qqandroid/src/commonMain/kotlin/net/mamoe/mirai/qqandroid/ContactImpl.kt index 0a31dd4ef..dfadae4fe 100644 --- a/mirai-core-qqandroid/src/commonMain/kotlin/net/mamoe/mirai/qqandroid/ContactImpl.kt +++ b/mirai-core-qqandroid/src/commonMain/kotlin/net/mamoe/mirai/qqandroid/ContactImpl.kt @@ -579,9 +579,9 @@ internal class GroupImpl( append("qid", id) append("bkn", getBkn()) append("ft", 23) //好像是一个用来识别应用的参数 - append("s", if (page ==1) 0 else -(page*amount+1)) // 第一页这里的参数应该是-1 + append("s", if (page == 1) 0 else -(page * amount + 1)) // 第一页这里的参数应该是-1 append("n", amount) - append("ni",if (page ==1) 1 else 0) + append("ni", if (page == 1) 1 else 0) append("format", "json") }) headers { @@ -594,12 +594,43 @@ internal class GroupImpl( } val rep = data.await() - bot.network.logger.error(rep) - - return json.parse(GroupAnnouncementList.serializer(), rep) +// bot.network.logger.error(rep) + return json.parse(GroupAnnouncementList.serializer(), rep) } + @MiraiExperimentalAPI + override suspend fun sendAnnouncement(announcement: GroupAnnouncement) { + val json = Json(JsonConfiguration.Stable) + bot.network.launch { + HttpClient().post { + url("https://web.qun.qq.com/cgi-bin/announce/add_qun_notice") + body = MultiPartFormDataContent(formData { + append("qid", id) + append("bkn", getBkn()) + append("text", announcement.msg.text) + append("pinned", announcement.pinned) + append("settings", json.stringify(GroupAnnouncementSettings.serializer(), announcement.settings?:GroupAnnouncementSettings())) + append("format", "json") + }) + headers { + append( + "cookie", + "uin=o${bot.selfQQ.id};" + + " skey=${bot.client.wLoginSigInfo.sKey.data.encodeToString()};" + + " p_uin=o${bot.selfQQ.id};" + + " p_skey=${bot.client.wLoginSigInfo.psKeyMap["qun.qq.com"]?.data?.encodeToString()}; " + ) + } + }.also { + val jsonObj = json.parseJson(it) + if (jsonObj.jsonObject["ec"]?.int ?:1 != 0){ + throw IllegalStateException("Send Announcement fail group:$id msg:${jsonObj.jsonObject["em"]} content:${announcement.msg.text}") + } + } + } + } + @OptIn(MiraiExperimentalAPI::class) override fun Member(memberInfo: MemberInfo): Member { return MemberImpl( @@ -761,10 +792,10 @@ internal class GroupImpl( return this.id == other.id && this.bot == other.bot } - /* - * 获取 获取群公告 所需的bkn参数 - * */ - fun getBkn(): Int { + /** + * 获取 获取群公告 所需的bkn参数 + * */ + private fun getBkn(): Int { val str = bot.client.wLoginSigInfo.sKey.data.encodeToString() var magic = 5381 for (i in str) { diff --git a/mirai-core-qqandroid/src/commonMain/kotlin/net/mamoe/mirai/qqandroid/network/protocol/packet/login/WtLogin.kt b/mirai-core-qqandroid/src/commonMain/kotlin/net/mamoe/mirai/qqandroid/network/protocol/packet/login/WtLogin.kt index d15683d68..ef67b961e 100644 --- a/mirai-core-qqandroid/src/commonMain/kotlin/net/mamoe/mirai/qqandroid/network/protocol/packet/login/WtLogin.kt +++ b/mirai-core-qqandroid/src/commonMain/kotlin/net/mamoe/mirai/qqandroid/network/protocol/packet/login/WtLogin.kt @@ -602,7 +602,7 @@ internal class WtLogin { userA5 = UserA5(tlvMap119.getOrEmpty(0x10b), creationTime), userA8 = UserA8(tlvMap119.getOrEmpty(0x102), creationTime, expireTime) ) - //bot.network.logger.error(client.wLoginSigInfo.sKey.data.encodeToString()) + //bot.network.logger.error(client.wLoginSigInfo.psKeyMap["qun.qq.com"]?.data?.encodeToString()) } } diff --git a/mirai-core/src/commonMain/kotlin/net.mamoe.mirai/contact/Group.kt b/mirai-core/src/commonMain/kotlin/net.mamoe.mirai/contact/Group.kt index 8d19d83aa..dc6005238 100644 --- a/mirai-core/src/commonMain/kotlin/net.mamoe.mirai/contact/Group.kt +++ b/mirai-core/src/commonMain/kotlin/net.mamoe.mirai/contact/Group.kt @@ -16,6 +16,7 @@ import kotlinx.serialization.SerialInfo import kotlinx.serialization.SerialName import kotlinx.serialization.Serializable import net.mamoe.mirai.Bot +import net.mamoe.mirai.data.GroupAnnouncement import net.mamoe.mirai.data.GroupAnnouncementList import net.mamoe.mirai.data.MemberInfo import net.mamoe.mirai.event.events.* @@ -159,6 +160,13 @@ expect abstract class Group() : Contact, CoroutineScope { @MiraiExperimentalAPI abstract suspend fun getAnnouncements(page: Int = 1, amount: Int = 10):GroupAnnouncementList? + /** + * 发送群公告 + * + * */ + @MiraiExperimentalAPI + abstract suspend fun sendAnnouncement(announcement: GroupAnnouncement) + /** * 让机器人退出这个群. 机器人必须为非群主才能退出. 否则将会失败 */ diff --git a/mirai-core/src/commonMain/kotlin/net.mamoe.mirai/data/GroupAnnouncement.kt b/mirai-core/src/commonMain/kotlin/net.mamoe.mirai/data/GroupAnnouncement.kt index bc59765d6..2dfadf8c5 100644 --- a/mirai-core/src/commonMain/kotlin/net.mamoe.mirai/data/GroupAnnouncement.kt +++ b/mirai-core/src/commonMain/kotlin/net.mamoe.mirai/data/GroupAnnouncement.kt @@ -7,34 +7,39 @@ import kotlinx.serialization.Serializable * 群公告数据类 * getGroupAnnouncementList时,如果page=1,那么你可以在inst里拿到一些置顶公告 * + * 发公告时只需要填写text, * */ @Serializable data class GroupAnnouncementList( val ec: Int, //状态码 0 是正常的 - @SerialName("em") val msg:String, //信息 - val feeds: List?, //群公告列表 - val inst: List? //置顶列表? + @SerialName("em") val msg: String, //信息 + val feeds: List? = null, //群公告列表 + val inst: List? = null //置顶列表? ) @Serializable data class GroupAnnouncement( - @SerialName("u") val sender: Long, + @SerialName("u") val sender: Long = 0, val msg: GroupAnnouncementMsg, - val settings: GroupAnnouncementSettings + val settings: GroupAnnouncementSettings? = null, + @SerialName("pubt") val time: Long = 0, + @SerialName("read_num") val readNum: Int = 0, + @SerialName("is_read") val isRead: Int = 0, + val pinned: Int = 0 ) @Serializable data class GroupAnnouncementMsg( val text: String, - val text_face: String, - val title: String + val text_face: String? = null, + val title: String? = null ) @Serializable data class GroupAnnouncementSettings( - @SerialName("is_show_edit_card") val isShowEditCard: Int, - @SerialName("remind_ts") val remindTs: Int, - @SerialName("tip_window_type") val tipWindowType: Int, - @SerialName("confirm_required") val confirmRequired: Int + @SerialName("is_show_edit_card") val isShowEditCard: Int = 0, + @SerialName("remind_ts") val remindTs: Int = 0, + @SerialName("tip_window_type") val tipWindowType: Int = 0, + @SerialName("confirm_required") val confirmRequired: Int = 0 ) \ No newline at end of file diff --git a/mirai-core/src/jvmMain/kotlin/net/mamoe/mirai/contact/Group.kt b/mirai-core/src/jvmMain/kotlin/net/mamoe/mirai/contact/Group.kt index 75c9499eb..2f065bab5 100644 --- a/mirai-core/src/jvmMain/kotlin/net/mamoe/mirai/contact/Group.kt +++ b/mirai-core/src/jvmMain/kotlin/net/mamoe/mirai/contact/Group.kt @@ -11,6 +11,7 @@ package net.mamoe.mirai.contact import kotlinx.coroutines.CoroutineScope import net.mamoe.mirai.Bot +import net.mamoe.mirai.data.GroupAnnouncement import net.mamoe.mirai.data.GroupAnnouncementList import net.mamoe.mirai.data.MemberInfo import net.mamoe.mirai.event.events.* @@ -153,7 +154,14 @@ actual abstract class Group : Contact(), CoroutineScope { * * */ @MiraiExperimentalAPI - actual suspend abstract fun getAnnouncements(page: Int, amount: Int ):GroupAnnouncementList? + actual suspend abstract fun getAnnouncements(page: Int, amount: Int): GroupAnnouncementList? + + + /** + * 发送群公告 + * */ + @MiraiExperimentalAPI + actual suspend abstract fun sendAnnouncement(announcement: GroupAnnouncement) /** * 检查此 id 的群成员是否存在 From 4e7b3b0048ece21df3f212d54f2a38d9c4c80a08 Mon Sep 17 00:00:00 2001 From: luo123 Date: Sat, 14 Mar 2020 00:45:36 +0800 Subject: [PATCH 4/6] delete announcement --- .../net/mamoe/mirai/qqandroid/ContactImpl.kt | 49 ++++++++++++++++--- .../kotlin/net.mamoe.mirai/contact/Group.kt | 13 ++++- .../net.mamoe.mirai/data/GroupAnnouncement.kt | 3 +- .../kotlin/net/mamoe/mirai/contact/Group.kt | 8 ++- 4 files changed, 62 insertions(+), 11 deletions(-) diff --git a/mirai-core-qqandroid/src/commonMain/kotlin/net/mamoe/mirai/qqandroid/ContactImpl.kt b/mirai-core-qqandroid/src/commonMain/kotlin/net/mamoe/mirai/qqandroid/ContactImpl.kt index dfadae4fe..637273e35 100644 --- a/mirai-core-qqandroid/src/commonMain/kotlin/net/mamoe/mirai/qqandroid/ContactImpl.kt +++ b/mirai-core-qqandroid/src/commonMain/kotlin/net/mamoe/mirai/qqandroid/ContactImpl.kt @@ -21,6 +21,7 @@ import kotlinx.serialization.MissingFieldException import kotlinx.serialization.json.Json import kotlinx.serialization.json.JsonConfiguration import kotlinx.serialization.json.int +import kotlinx.serialization.json.long import net.mamoe.mirai.LowLevelAPI import net.mamoe.mirai.contact.* import net.mamoe.mirai.data.* @@ -600,9 +601,9 @@ internal class GroupImpl( @MiraiExperimentalAPI - override suspend fun sendAnnouncement(announcement: GroupAnnouncement) { + override suspend fun sendAnnouncement(announcement: GroupAnnouncement): String { val json = Json(JsonConfiguration.Stable) - bot.network.launch { + val rep = bot.network.async { HttpClient().post { url("https://web.qun.qq.com/cgi-bin/announce/add_qun_notice") body = MultiPartFormDataContent(formData { @@ -610,7 +611,13 @@ internal class GroupImpl( append("bkn", getBkn()) append("text", announcement.msg.text) append("pinned", announcement.pinned) - append("settings", json.stringify(GroupAnnouncementSettings.serializer(), announcement.settings?:GroupAnnouncementSettings())) + append( + "settings", + json.stringify( + GroupAnnouncementSettings.serializer(), + announcement.settings ?: GroupAnnouncementSettings() + ) + ) append("format", "json") }) headers { @@ -622,13 +629,41 @@ internal class GroupImpl( " p_skey=${bot.client.wLoginSigInfo.psKeyMap["qun.qq.com"]?.data?.encodeToString()}; " ) } - }.also { - val jsonObj = json.parseJson(it) - if (jsonObj.jsonObject["ec"]?.int ?:1 != 0){ - throw IllegalStateException("Send Announcement fail group:$id msg:${jsonObj.jsonObject["em"]} content:${announcement.msg.text}") + } + } + val jsonObj = json.parseJson(rep.await()) + return jsonObj.jsonObject["new_fid"]?.primitive?.content + ?: throw throw IllegalStateException("Send Announcement fail group:$id msg:${jsonObj.jsonObject["em"]} content:${announcement.msg.text}") + } + + @MiraiExperimentalAPI + override suspend fun deleteAnnouncement(fid: String) { + val json = Json(JsonConfiguration.Stable) + val rep = bot.network.async { + HttpClient().post { + url("https://web.qun.qq.com/cgi-bin/announce/del_feed") + body = MultiPartFormDataContent(formData { + append("qid", id) + append("bkn", getBkn()) + append("fid", fid) + append("format", "json") + }) + headers { + append( + "cookie", + "uin=o${bot.selfQQ.id};" + + " skey=${bot.client.wLoginSigInfo.sKey.data.encodeToString()};" + + " p_uin=o${bot.selfQQ.id};" + + " p_skey=${bot.client.wLoginSigInfo.psKeyMap["qun.qq.com"]?.data?.encodeToString()}; " + ) } } } + val data = rep.await() + val jsonObj = json.parseJson(data) + if (jsonObj.jsonObject["ec"]?.int ?: 1 != 0){ + throw throw IllegalStateException("delete Announcement fail group:$id msg:${jsonObj.jsonObject["em"]} fid:$fid") + } } @OptIn(MiraiExperimentalAPI::class) diff --git a/mirai-core/src/commonMain/kotlin/net.mamoe.mirai/contact/Group.kt b/mirai-core/src/commonMain/kotlin/net.mamoe.mirai/contact/Group.kt index dc6005238..ff7c690de 100644 --- a/mirai-core/src/commonMain/kotlin/net.mamoe.mirai/contact/Group.kt +++ b/mirai-core/src/commonMain/kotlin/net.mamoe.mirai/contact/Group.kt @@ -158,14 +158,23 @@ expect abstract class Group() : Contact, CoroutineScope { * * */ @MiraiExperimentalAPI - abstract suspend fun getAnnouncements(page: Int = 1, amount: Int = 10):GroupAnnouncementList? + abstract suspend fun getAnnouncements(page: Int = 1, amount: Int = 10): GroupAnnouncementList? /** * 发送群公告 * * */ @MiraiExperimentalAPI - abstract suspend fun sendAnnouncement(announcement: GroupAnnouncement) + abstract suspend fun sendAnnouncement(announcement: GroupAnnouncement): String + + + /** + * 删除群公告 + * fid可以通过发送公告的返回值得到或者获取列表得到 + * */ + + @MiraiExperimentalAPI + abstract suspend fun deleteAnnouncement(fid: String) /** * 让机器人退出这个群. 机器人必须为非群主才能退出. 否则将会失败 diff --git a/mirai-core/src/commonMain/kotlin/net.mamoe.mirai/data/GroupAnnouncement.kt b/mirai-core/src/commonMain/kotlin/net.mamoe.mirai/data/GroupAnnouncement.kt index 2dfadf8c5..ac9cc6311 100644 --- a/mirai-core/src/commonMain/kotlin/net.mamoe.mirai/data/GroupAnnouncement.kt +++ b/mirai-core/src/commonMain/kotlin/net.mamoe.mirai/data/GroupAnnouncement.kt @@ -26,7 +26,8 @@ data class GroupAnnouncement( @SerialName("pubt") val time: Long = 0, @SerialName("read_num") val readNum: Int = 0, @SerialName("is_read") val isRead: Int = 0, - val pinned: Int = 0 + val pinned: Int = 0, + val fid:String? = null //公告的id ) @Serializable diff --git a/mirai-core/src/jvmMain/kotlin/net/mamoe/mirai/contact/Group.kt b/mirai-core/src/jvmMain/kotlin/net/mamoe/mirai/contact/Group.kt index 2f065bab5..8efa42be9 100644 --- a/mirai-core/src/jvmMain/kotlin/net/mamoe/mirai/contact/Group.kt +++ b/mirai-core/src/jvmMain/kotlin/net/mamoe/mirai/contact/Group.kt @@ -156,12 +156,18 @@ actual abstract class Group : Contact(), CoroutineScope { @MiraiExperimentalAPI actual suspend abstract fun getAnnouncements(page: Int, amount: Int): GroupAnnouncementList? + /** + * 删除群公告 + * fid可以通过发送公告的返回值得到或者获取列表得到 + * */ + @MiraiExperimentalAPI + actual abstract suspend fun deleteAnnouncement(fid: String) /** * 发送群公告 * */ @MiraiExperimentalAPI - actual suspend abstract fun sendAnnouncement(announcement: GroupAnnouncement) + actual suspend abstract fun sendAnnouncement(announcement: GroupAnnouncement):String /** * 检查此 id 的群成员是否存在 From 6973488db7c7d5722407eb4d8d1630646250a5cb Mon Sep 17 00:00:00 2001 From: luo123 Date: Sat, 14 Mar 2020 11:01:21 +0800 Subject: [PATCH 5/6] move to lowLevelApi.kt --- .../net/mamoe/mirai/qqandroid/ContactImpl.kt | 108 +----------- .../net/mamoe/mirai/qqandroid/QQAndroidBot.kt | 155 +++++++++++++++++- .../kotlin/net.mamoe.mirai/contact/Group.kt | 21 --- .../net.mamoe.mirai/data/GroupAnnouncement.kt | 2 +- .../kotlin/net.mamoe.mirai/lowLevelApi.kt | 39 ++++- .../kotlin/net/mamoe/mirai/contact/Group.kt | 20 --- 6 files changed, 189 insertions(+), 156 deletions(-) diff --git a/mirai-core-qqandroid/src/commonMain/kotlin/net/mamoe/mirai/qqandroid/ContactImpl.kt b/mirai-core-qqandroid/src/commonMain/kotlin/net/mamoe/mirai/qqandroid/ContactImpl.kt index 637273e35..cfe36b068 100644 --- a/mirai-core-qqandroid/src/commonMain/kotlin/net/mamoe/mirai/qqandroid/ContactImpl.kt +++ b/mirai-core-qqandroid/src/commonMain/kotlin/net/mamoe/mirai/qqandroid/ContactImpl.kt @@ -570,102 +570,6 @@ internal class GroupImpl( TODO("not implemented") } - @MiraiExperimentalAPI - override suspend fun getAnnouncements(page: Int, amount: Int): GroupAnnouncementList? { - val json = Json(JsonConfiguration(ignoreUnknownKeys = true)) - val data = bot.network.async { - HttpClient().post { - url("https://web.qun.qq.com/cgi-bin/announce/list_announce") - body = MultiPartFormDataContent(formData { - append("qid", id) - append("bkn", getBkn()) - append("ft", 23) //好像是一个用来识别应用的参数 - append("s", if (page == 1) 0 else -(page * amount + 1)) // 第一页这里的参数应该是-1 - append("n", amount) - append("ni", if (page == 1) 1 else 0) - append("format", "json") - }) - headers { - append( - "cookie", - "uin=o${bot.selfQQ.id}; skey=${bot.client.wLoginSigInfo.sKey.data.encodeToString()}; p_uin=o${bot.selfQQ.id};" - ) - } - } - } - - val rep = data.await() -// bot.network.logger.error(rep) - return json.parse(GroupAnnouncementList.serializer(), rep) - } - - - @MiraiExperimentalAPI - override suspend fun sendAnnouncement(announcement: GroupAnnouncement): String { - val json = Json(JsonConfiguration.Stable) - val rep = bot.network.async { - HttpClient().post { - url("https://web.qun.qq.com/cgi-bin/announce/add_qun_notice") - body = MultiPartFormDataContent(formData { - append("qid", id) - append("bkn", getBkn()) - append("text", announcement.msg.text) - append("pinned", announcement.pinned) - append( - "settings", - json.stringify( - GroupAnnouncementSettings.serializer(), - announcement.settings ?: GroupAnnouncementSettings() - ) - ) - append("format", "json") - }) - headers { - append( - "cookie", - "uin=o${bot.selfQQ.id};" + - " skey=${bot.client.wLoginSigInfo.sKey.data.encodeToString()};" + - " p_uin=o${bot.selfQQ.id};" + - " p_skey=${bot.client.wLoginSigInfo.psKeyMap["qun.qq.com"]?.data?.encodeToString()}; " - ) - } - } - } - val jsonObj = json.parseJson(rep.await()) - return jsonObj.jsonObject["new_fid"]?.primitive?.content - ?: throw throw IllegalStateException("Send Announcement fail group:$id msg:${jsonObj.jsonObject["em"]} content:${announcement.msg.text}") - } - - @MiraiExperimentalAPI - override suspend fun deleteAnnouncement(fid: String) { - val json = Json(JsonConfiguration.Stable) - val rep = bot.network.async { - HttpClient().post { - url("https://web.qun.qq.com/cgi-bin/announce/del_feed") - body = MultiPartFormDataContent(formData { - append("qid", id) - append("bkn", getBkn()) - append("fid", fid) - append("format", "json") - }) - headers { - append( - "cookie", - "uin=o${bot.selfQQ.id};" + - " skey=${bot.client.wLoginSigInfo.sKey.data.encodeToString()};" + - " p_uin=o${bot.selfQQ.id};" + - " p_skey=${bot.client.wLoginSigInfo.psKeyMap["qun.qq.com"]?.data?.encodeToString()}; " - ) - } - } - } - val data = rep.await() - val jsonObj = json.parseJson(data) - if (jsonObj.jsonObject["ec"]?.int ?: 1 != 0){ - throw throw IllegalStateException("delete Announcement fail group:$id msg:${jsonObj.jsonObject["em"]} fid:$fid") - } - } - @OptIn(MiraiExperimentalAPI::class) override fun Member(memberInfo: MemberInfo): Member { return MemberImpl( @@ -827,15 +731,5 @@ internal class GroupImpl( return this.id == other.id && this.bot == other.bot } - /** - * 获取 获取群公告 所需的bkn参数 - * */ - private fun getBkn(): Int { - val str = bot.client.wLoginSigInfo.sKey.data.encodeToString() - var magic = 5381 - for (i in str) { - magic += magic.shl(5) + i.toInt() - } - return Int.MAX_VALUE.and(magic) - } + } \ No newline at end of file diff --git a/mirai-core-qqandroid/src/commonMain/kotlin/net/mamoe/mirai/qqandroid/QQAndroidBot.kt b/mirai-core-qqandroid/src/commonMain/kotlin/net/mamoe/mirai/qqandroid/QQAndroidBot.kt index b87883f51..c062aa1be 100644 --- a/mirai-core-qqandroid/src/commonMain/kotlin/net/mamoe/mirai/qqandroid/QQAndroidBot.kt +++ b/mirai-core-qqandroid/src/commonMain/kotlin/net/mamoe/mirai/qqandroid/QQAndroidBot.kt @@ -9,18 +9,25 @@ package net.mamoe.mirai.qqandroid +import io.ktor.client.HttpClient +import io.ktor.client.request.forms.MultiPartFormDataContent +import io.ktor.client.request.forms.formData import io.ktor.client.request.get +import io.ktor.client.request.headers +import io.ktor.client.request.post +import io.ktor.client.request.url import io.ktor.client.statement.HttpResponse import kotlinx.coroutines.CoroutineName +import kotlinx.coroutines.async import kotlinx.coroutines.io.ByteReadChannel +import kotlinx.serialization.json.Json +import kotlinx.serialization.json.JsonConfiguration +import kotlinx.serialization.json.int import net.mamoe.mirai.BotAccount import net.mamoe.mirai.BotImpl import net.mamoe.mirai.LowLevelAPI import net.mamoe.mirai.contact.* -import net.mamoe.mirai.data.AddFriendResult -import net.mamoe.mirai.data.FriendInfo -import net.mamoe.mirai.data.GroupInfo -import net.mamoe.mirai.data.MemberInfo +import net.mamoe.mirai.data.* import net.mamoe.mirai.event.broadcast import net.mamoe.mirai.event.events.MessageRecallEvent import net.mamoe.mirai.message.data.* @@ -33,6 +40,7 @@ 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.list.FriendList import net.mamoe.mirai.utils.* +import net.mamoe.mirai.utils.io.encodeToString import kotlin.collections.asSequence import kotlin.coroutines.CoroutineContext @@ -209,6 +217,133 @@ internal abstract class QQAndroidBotBase constructor( } } + + + @OptIn(LowLevelAPI::class) + @MiraiExperimentalAPI + override suspend fun _lowLevelGetAnnouncements(groupId:Long, page: Int, amount: Int): GroupAnnouncementList? { + val json = Json(JsonConfiguration(ignoreUnknownKeys = true)) + val data = network.async { + HttpClient().post { + url("https://web.qun.qq.com/cgi-bin/announce/list_announce") + body = MultiPartFormDataContent(formData { + append("qid", groupId) + append("bkn", getBkn()) + append("ft", 23) //好像是一个用来识别应用的参数 + append("s", if (page == 1) 0 else -(page * amount + 1)) // 第一页这里的参数应该是-1 + append("n", amount) + append("ni", if (page == 1) 1 else 0) + append("format", "json") + }) + headers { + append( + "cookie", + "uin=o${selfQQ.id}; skey=${client.wLoginSigInfo.sKey.data.encodeToString()}; p_uin=o${selfQQ.id};" + ) + } + } + } + + val rep = data.await() +// bot.network.logger.error(rep) + return json.parse(GroupAnnouncementList.serializer(), rep) + } + + @OptIn(LowLevelAPI::class) + @MiraiExperimentalAPI + override suspend fun _lowLevelSendAnnouncement(groupId:Long, announcement: GroupAnnouncement): String { + val json = Json(JsonConfiguration.Stable) + val rep = network.async { + HttpClient().post { + url("https://web.qun.qq.com/cgi-bin/announce/add_qun_notice") + body = MultiPartFormDataContent(formData { + append("qid", groupId) + append("bkn", getBkn()) + append("text", announcement.msg.text) + append("pinned", announcement.pinned) + append( + "settings", + json.stringify( + GroupAnnouncementSettings.serializer(), + announcement.settings ?: GroupAnnouncementSettings() + ) + ) + append("format", "json") + }) + headers { + append( + "cookie", + "uin=o${selfQQ.id};" + + " skey=${client.wLoginSigInfo.sKey.data.encodeToString()};" + + " p_uin=o${selfQQ.id};" + + " p_skey=${client.wLoginSigInfo.psKeyMap["qun.qq.com"]?.data?.encodeToString()}; " + ) + } + } + } + val jsonObj = json.parseJson(rep.await()) + return jsonObj.jsonObject["new_fid"]?.primitive?.content + ?: throw throw IllegalStateException("Send Announcement fail group:$groupId msg:${jsonObj.jsonObject["em"]} content:${announcement.msg.text}") + } + @OptIn(LowLevelAPI::class) + @MiraiExperimentalAPI + override suspend fun _lowLevelDeleteAnnouncement(groupId:Long, fid: String) { + val json = Json(JsonConfiguration.Stable) + val rep = network.async { + HttpClient().post { + url("https://web.qun.qq.com/cgi-bin/announce/del_feed") + body = MultiPartFormDataContent(formData { + append("qid", groupId) + append("bkn", getBkn()) + append("fid", fid) + append("format", "json") + }) + headers { + append( + "cookie", + "uin=o${selfQQ.id};" + + " skey=${client.wLoginSigInfo.sKey.data.encodeToString()};" + + " p_uin=o${selfQQ.id};" + + " p_skey=${client.wLoginSigInfo.psKeyMap["qun.qq.com"]?.data?.encodeToString()}; " + ) + } + } + } + val data = rep.await() + val jsonObj = json.parseJson(data) + if (jsonObj.jsonObject["ec"]?.int ?: 1 != 0){ + throw throw IllegalStateException("delete Announcement fail group:$groupId msg:${jsonObj.jsonObject["em"]} fid:$fid") + } + } + + @OptIn(LowLevelAPI::class) + @MiraiExperimentalAPI + override suspend fun _lowLevelGetAnnouncement(groupId: Long, fid: String): GroupAnnouncement { + val json = Json(JsonConfiguration(ignoreUnknownKeys = true)) + val data = network.async { + HttpClient().post { + url("https://web.qun.qq.com/cgi-bin/announce/get_feed") + body = MultiPartFormDataContent(formData { + append("qid", groupId) + append("bkn", getBkn()) + append("fid", fid) + append("format", "json") + }) + headers { + append( + "cookie", + "uin=o${selfQQ.id}; skey=${client.wLoginSigInfo.sKey.data.encodeToString()}; p_uin=o${selfQQ.id};" + ) + } + } + } + + val rep = data.await() +// bot.network.logger.error(rep) + return json.parse(GroupAnnouncement.serializer(), rep) + + } + override suspend fun queryImageUrl(image: Image): String = when (image) { is OnlineFriendImageImpl -> image.originUrl is OnlineGroupImageImpl -> image.originUrl @@ -224,6 +359,18 @@ internal abstract class QQAndroidBotBase constructor( override suspend fun openChannel(image: Image): ByteReadChannel { return MiraiPlatformUtils.Http.get(queryImageUrl(image)).content.toKotlinByteReadChannel() } + + /** + * 获取 获取群公告 所需的bkn参数 + * */ + private fun getBkn(): Int { + val str = client.wLoginSigInfo.sKey.data.encodeToString() + var magic = 5381 + for (i in str) { + magic += magic.shl(5) + i.toInt() + } + return Int.MAX_VALUE.and(magic) + } } @Suppress("DEPRECATION") diff --git a/mirai-core/src/commonMain/kotlin/net.mamoe.mirai/contact/Group.kt b/mirai-core/src/commonMain/kotlin/net.mamoe.mirai/contact/Group.kt index ff7c690de..c58cf228b 100644 --- a/mirai-core/src/commonMain/kotlin/net.mamoe.mirai/contact/Group.kt +++ b/mirai-core/src/commonMain/kotlin/net.mamoe.mirai/contact/Group.kt @@ -153,28 +153,7 @@ expect abstract class Group() : Contact, CoroutineScope { */ abstract operator fun contains(id: Long): Boolean - /** - * 获取群公告列表 - * - * */ - @MiraiExperimentalAPI - abstract suspend fun getAnnouncements(page: Int = 1, amount: Int = 10): GroupAnnouncementList? - /** - * 发送群公告 - * - * */ - @MiraiExperimentalAPI - abstract suspend fun sendAnnouncement(announcement: GroupAnnouncement): String - - - /** - * 删除群公告 - * fid可以通过发送公告的返回值得到或者获取列表得到 - * */ - - @MiraiExperimentalAPI - abstract suspend fun deleteAnnouncement(fid: String) /** * 让机器人退出这个群. 机器人必须为非群主才能退出. 否则将会失败 diff --git a/mirai-core/src/commonMain/kotlin/net.mamoe.mirai/data/GroupAnnouncement.kt b/mirai-core/src/commonMain/kotlin/net.mamoe.mirai/data/GroupAnnouncement.kt index ac9cc6311..7f39ca05d 100644 --- a/mirai-core/src/commonMain/kotlin/net.mamoe.mirai/data/GroupAnnouncement.kt +++ b/mirai-core/src/commonMain/kotlin/net.mamoe.mirai/data/GroupAnnouncement.kt @@ -7,7 +7,7 @@ import kotlinx.serialization.Serializable * 群公告数据类 * getGroupAnnouncementList时,如果page=1,那么你可以在inst里拿到一些置顶公告 * - * 发公告时只需要填写text, + * 发公告时只需要填写text,其他参数可为默认值 * */ @Serializable diff --git a/mirai-core/src/commonMain/kotlin/net.mamoe.mirai/lowLevelApi.kt b/mirai-core/src/commonMain/kotlin/net.mamoe.mirai/lowLevelApi.kt index 6ea5e0857..ab54eb5f0 100644 --- a/mirai-core/src/commonMain/kotlin/net.mamoe.mirai/lowLevelApi.kt +++ b/mirai-core/src/commonMain/kotlin/net.mamoe.mirai/lowLevelApi.kt @@ -12,9 +12,7 @@ package net.mamoe.mirai import kotlinx.coroutines.Job import net.mamoe.mirai.contact.Group import net.mamoe.mirai.contact.QQ -import net.mamoe.mirai.data.FriendInfo -import net.mamoe.mirai.data.GroupInfo -import net.mamoe.mirai.data.MemberInfo +import net.mamoe.mirai.data.* import net.mamoe.mirai.message.data.MessageSource import net.mamoe.mirai.utils.MiraiExperimentalAPI import net.mamoe.mirai.utils.MiraiInternalAPI @@ -94,6 +92,41 @@ interface LowLevelBotAPIAccessor { */ @LowLevelAPI suspend fun _lowLevelRecallGroupMessage(groupId: Long, messageId: Long) + + /** + * 获取群公告列表 + * @param page 页码 + * */ + @LowLevelAPI + @MiraiExperimentalAPI + suspend fun _lowLevelGetAnnouncements(groupId: Long, page: Int = 1, amount: Int = 10): GroupAnnouncementList? + + /** + * 发送群公告 + * + * @return 公告的fid + * */ + @LowLevelAPI + @MiraiExperimentalAPI + suspend fun _lowLevelSendAnnouncement(groupId: Long, announcement: GroupAnnouncement): String + + + /** + * 删除群公告 + * @param fid [GroupAnnouncement.fid] + * */ + @LowLevelAPI + @MiraiExperimentalAPI + suspend fun _lowLevelDeleteAnnouncement(groupId: Long, fid: String) + + /** + * 获取一条群公告 + * @param fid [GroupAnnouncement.fid] + * */ + @LowLevelAPI + @MiraiExperimentalAPI + suspend fun _lowLevelGetAnnouncement(groupId: Long,fid:String):GroupAnnouncement + } /** diff --git a/mirai-core/src/jvmMain/kotlin/net/mamoe/mirai/contact/Group.kt b/mirai-core/src/jvmMain/kotlin/net/mamoe/mirai/contact/Group.kt index 8efa42be9..fb9ff146f 100644 --- a/mirai-core/src/jvmMain/kotlin/net/mamoe/mirai/contact/Group.kt +++ b/mirai-core/src/jvmMain/kotlin/net/mamoe/mirai/contact/Group.kt @@ -149,26 +149,6 @@ actual abstract class Group : Contact(), CoroutineScope { actual abstract fun getOrNull(id: Long): Member? - /** - * 获取群公告列表 - * - * */ - @MiraiExperimentalAPI - actual suspend abstract fun getAnnouncements(page: Int, amount: Int): GroupAnnouncementList? - - /** - * 删除群公告 - * fid可以通过发送公告的返回值得到或者获取列表得到 - * */ - @MiraiExperimentalAPI - actual abstract suspend fun deleteAnnouncement(fid: String) - - /** - * 发送群公告 - * */ - @MiraiExperimentalAPI - actual suspend abstract fun sendAnnouncement(announcement: GroupAnnouncement):String - /** * 检查此 id 的群成员是否存在 */ From 9ff791e55093f2c6880f75d16ad7b8a018019bb2 Mon Sep 17 00:00:00 2001 From: luo123 Date: Sat, 14 Mar 2020 11:43:43 +0800 Subject: [PATCH 6/6] a little change --- README.md | 1 - .../net/mamoe/mirai/qqandroid/QQAndroidBot.kt | 51 ++++++++++--------- .../kotlin/net.mamoe.mirai/lowLevelApi.kt | 8 +-- 3 files changed, 30 insertions(+), 30 deletions(-) diff --git a/README.md b/README.md index cc467d3ea..766a1c09c 100644 --- a/README.md +++ b/README.md @@ -99,7 +99,6 @@ Demos: [mirai-demos](https://github.com/mamoe/mirai-demos) [](https://github.com/HoshinoTented) [](https://github.com/Cyenoch) - ## 鸣谢 特别感谢 [JetBrains](https://www.jetbrains.com/?from=mirai) 为开源项目提供免费的 [IntelliJ IDEA](https://www.jetbrains.com/idea/?from=mirai) 等 IDE 的授权 diff --git a/mirai-core-qqandroid/src/commonMain/kotlin/net/mamoe/mirai/qqandroid/QQAndroidBot.kt b/mirai-core-qqandroid/src/commonMain/kotlin/net/mamoe/mirai/qqandroid/QQAndroidBot.kt index c062aa1be..fabc9c806 100644 --- a/mirai-core-qqandroid/src/commonMain/kotlin/net/mamoe/mirai/qqandroid/QQAndroidBot.kt +++ b/mirai-core-qqandroid/src/commonMain/kotlin/net/mamoe/mirai/qqandroid/QQAndroidBot.kt @@ -67,6 +67,10 @@ internal abstract class QQAndroidBotBase constructor( internal var firstLoginSucceed: Boolean = false override val uin: Long get() = client.uin + companion object { + val json = Json(JsonConfiguration(ignoreUnknownKeys = true, encodeDefaults = true)) + } + @Deprecated( "use friends instead", level = DeprecationLevel.ERROR, @@ -206,7 +210,7 @@ internal abstract class QQAndroidBotBase constructor( } } - @OptIn(LowLevelAPI::class) + @LowLevelAPI override suspend fun _lowLevelRecallGroupMessage(groupId: Long, messageId: Long) { network.run { val response: PbMessageSvc.PbMsgWithDraw.Response = @@ -218,17 +222,15 @@ internal abstract class QQAndroidBotBase constructor( } - - @OptIn(LowLevelAPI::class) + @LowLevelAPI @MiraiExperimentalAPI - override suspend fun _lowLevelGetAnnouncements(groupId:Long, page: Int, amount: Int): GroupAnnouncementList? { - val json = Json(JsonConfiguration(ignoreUnknownKeys = true)) + override suspend fun _lowLevelGetAnnouncements(groupId: Long, page: Int, amount: Int): GroupAnnouncementList { val data = network.async { HttpClient().post { url("https://web.qun.qq.com/cgi-bin/announce/list_announce") body = MultiPartFormDataContent(formData { append("qid", groupId) - append("bkn", getBkn()) + append("bkn", bkn) append("ft", 23) //好像是一个用来识别应用的参数 append("s", if (page == 1) 0 else -(page * amount + 1)) // 第一页这里的参数应该是-1 append("n", amount) @@ -249,16 +251,15 @@ internal abstract class QQAndroidBotBase constructor( return json.parse(GroupAnnouncementList.serializer(), rep) } - @OptIn(LowLevelAPI::class) + @LowLevelAPI @MiraiExperimentalAPI - override suspend fun _lowLevelSendAnnouncement(groupId:Long, announcement: GroupAnnouncement): String { - val json = Json(JsonConfiguration.Stable) + override suspend fun _lowLevelSendAnnouncement(groupId: Long, announcement: GroupAnnouncement): String { val rep = network.async { HttpClient().post { url("https://web.qun.qq.com/cgi-bin/announce/add_qun_notice") body = MultiPartFormDataContent(formData { append("qid", groupId) - append("bkn", getBkn()) + append("bkn", bkn) append("text", announcement.msg.text) append("pinned", announcement.pinned) append( @@ -285,16 +286,16 @@ internal abstract class QQAndroidBotBase constructor( return jsonObj.jsonObject["new_fid"]?.primitive?.content ?: throw throw IllegalStateException("Send Announcement fail group:$groupId msg:${jsonObj.jsonObject["em"]} content:${announcement.msg.text}") } - @OptIn(LowLevelAPI::class) + + @LowLevelAPI @MiraiExperimentalAPI - override suspend fun _lowLevelDeleteAnnouncement(groupId:Long, fid: String) { - val json = Json(JsonConfiguration.Stable) + override suspend fun _lowLevelDeleteAnnouncement(groupId: Long, fid: String) { val rep = network.async { HttpClient().post { url("https://web.qun.qq.com/cgi-bin/announce/del_feed") body = MultiPartFormDataContent(formData { append("qid", groupId) - append("bkn", getBkn()) + append("bkn", bkn) append("fid", fid) append("format", "json") }) @@ -310,8 +311,8 @@ internal abstract class QQAndroidBotBase constructor( } } val data = rep.await() - val jsonObj = json.parseJson(data) - if (jsonObj.jsonObject["ec"]?.int ?: 1 != 0){ + val jsonObj = json.parseJson(data) + if (jsonObj.jsonObject["ec"]?.int ?: 1 != 0) { throw throw IllegalStateException("delete Announcement fail group:$groupId msg:${jsonObj.jsonObject["em"]} fid:$fid") } } @@ -319,13 +320,12 @@ internal abstract class QQAndroidBotBase constructor( @OptIn(LowLevelAPI::class) @MiraiExperimentalAPI override suspend fun _lowLevelGetAnnouncement(groupId: Long, fid: String): GroupAnnouncement { - val json = Json(JsonConfiguration(ignoreUnknownKeys = true)) val data = network.async { HttpClient().post { url("https://web.qun.qq.com/cgi-bin/announce/get_feed") body = MultiPartFormDataContent(formData { append("qid", groupId) - append("bkn", getBkn()) + append("bkn", bkn) append("fid", fid) append("format", "json") }) @@ -363,14 +363,15 @@ internal abstract class QQAndroidBotBase constructor( /** * 获取 获取群公告 所需的bkn参数 * */ - private fun getBkn(): Int { - val str = client.wLoginSigInfo.sKey.data.encodeToString() - var magic = 5381 - for (i in str) { - magic += magic.shl(5) + i.toInt() + val bkn: Int + get() { + val str = client.wLoginSigInfo.sKey.data.encodeToString() + var magic = 5381 + for (i in str) { + magic += magic.shl(5) + i.toInt() + } + return Int.MAX_VALUE.and(magic) } - return Int.MAX_VALUE.and(magic) - } } @Suppress("DEPRECATION") diff --git a/mirai-core/src/commonMain/kotlin/net.mamoe.mirai/lowLevelApi.kt b/mirai-core/src/commonMain/kotlin/net.mamoe.mirai/lowLevelApi.kt index ab54eb5f0..fa3c6a95f 100644 --- a/mirai-core/src/commonMain/kotlin/net.mamoe.mirai/lowLevelApi.kt +++ b/mirai-core/src/commonMain/kotlin/net.mamoe.mirai/lowLevelApi.kt @@ -99,7 +99,7 @@ interface LowLevelBotAPIAccessor { * */ @LowLevelAPI @MiraiExperimentalAPI - suspend fun _lowLevelGetAnnouncements(groupId: Long, page: Int = 1, amount: Int = 10): GroupAnnouncementList? + suspend fun _lowLevelGetAnnouncements(groupId: Long, page: Int = 1, amount: Int = 10): GroupAnnouncementList /** * 发送群公告 @@ -108,7 +108,7 @@ interface LowLevelBotAPIAccessor { * */ @LowLevelAPI @MiraiExperimentalAPI - suspend fun _lowLevelSendAnnouncement(groupId: Long, announcement: GroupAnnouncement): String + suspend fun _lowLevelSendAnnouncement(groupId: Long, announcement: GroupAnnouncement): String /** @@ -117,7 +117,7 @@ interface LowLevelBotAPIAccessor { * */ @LowLevelAPI @MiraiExperimentalAPI - suspend fun _lowLevelDeleteAnnouncement(groupId: Long, fid: String) + suspend fun _lowLevelDeleteAnnouncement(groupId: Long, fid: String) /** * 获取一条群公告 @@ -125,7 +125,7 @@ interface LowLevelBotAPIAccessor { * */ @LowLevelAPI @MiraiExperimentalAPI - suspend fun _lowLevelGetAnnouncement(groupId: Long,fid:String):GroupAnnouncement + suspend fun _lowLevelGetAnnouncement(groupId: Long, fid: String): GroupAnnouncement }