mirror of
https://github.com/mamoe/mirai.git
synced 2025-01-27 08:50:15 +08:00
Merge remote-tracking branch 'mirai/dev' into dev
This commit is contained in:
commit
333103eca7
@ -4706,12 +4706,13 @@ public final class net/mamoe/mirai/message/data/MusicKind : java/lang/Enum {
|
||||
public static fun values ()[Lnet/mamoe/mirai/message/data/MusicKind;
|
||||
}
|
||||
|
||||
public final class net/mamoe/mirai/message/data/MusicShare : net/mamoe/mirai/message/data/ConstrainSingle, net/mamoe/mirai/message/data/MessageContent {
|
||||
public final class net/mamoe/mirai/message/data/MusicShare : net/mamoe/mirai/message/code/CodableMessage, net/mamoe/mirai/message/data/ConstrainSingle, net/mamoe/mirai/message/data/MessageContent {
|
||||
public static final field Key Lnet/mamoe/mirai/message/data/MusicShare$Key;
|
||||
public static final field SERIAL_NAME Ljava/lang/String;
|
||||
public synthetic fun <init> (ILnet/mamoe/mirai/message/data/MusicKind;Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;Lkotlinx/serialization/internal/SerializationConstructorMarker;)V
|
||||
public fun <init> (Lnet/mamoe/mirai/message/data/MusicKind;Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;)V
|
||||
public fun <init> (Lnet/mamoe/mirai/message/data/MusicKind;Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;)V
|
||||
public fun appendMiraiCodeTo (Ljava/lang/StringBuilder;)V
|
||||
public final fun component1 ()Lnet/mamoe/mirai/message/data/MusicKind;
|
||||
public final fun component2 ()Ljava/lang/String;
|
||||
public final fun component3 ()Ljava/lang/String;
|
||||
|
@ -104,7 +104,6 @@ allprojects {
|
||||
maven(url = "https://kotlin.bintray.com/kotlinx")
|
||||
google()
|
||||
mavenCentral()
|
||||
maven(url = "https://dl.bintray.com/karlatemp/misc")
|
||||
}
|
||||
|
||||
afterEvaluate {
|
||||
|
@ -12,7 +12,7 @@
|
||||
import org.gradle.api.attributes.Attribute
|
||||
|
||||
object Versions {
|
||||
const val project = "2.5.0-dev-1"
|
||||
const val project = "2.5.0-dev-2"
|
||||
|
||||
const val core = project
|
||||
const val console = project
|
||||
@ -103,4 +103,4 @@ const val yamlkt = "net.mamoe.yamlkt:yamlkt:${Versions.yamlkt}"
|
||||
const val `jetbrains-annotations` = "org.jetbrains:annotations:19.0.0"
|
||||
|
||||
|
||||
const val `caller-finder` = "io.github.karlatemp:caller:1.0.1"
|
||||
const val `caller-finder` = "io.github.karlatemp:caller:1.1.1"
|
||||
|
55
docs/Bots.md
55
docs/Bots.md
@ -68,6 +68,25 @@ workingDir = File("C:/mirai")
|
||||
setWorkingDir(File("C:/mirai"))
|
||||
```
|
||||
|
||||
#### 修改缓存目录
|
||||
|
||||
缓存目录会相对于 `workingDir` 解析。如 `File("cache")` 将会解析为 `workingDir` 内的 `cache` 目录。而 `File("C:/cache")` 将会解析为绝对的 `C:/cache` 目录。
|
||||
|
||||
默认为 `File("cache")`
|
||||
|
||||
要修改缓存目录(自 mirai 2.4.0):
|
||||
```
|
||||
// Kotlin
|
||||
cacheDir = File("cache") // 最终为 workingDir 目录中的 cache 目录
|
||||
cacheDir = File("C:/cache") // 最终为 C:/cache
|
||||
|
||||
// Java
|
||||
setCacheDir(File("cache")) // 最终为 workingDir 目录中的 cache 目录
|
||||
setCacheDir(File("C:/cache")) // 最终为 C:/cache
|
||||
```
|
||||
|
||||
目前缓存目录会存储列表缓存、登录服务器、资源会话秘钥等。这些数据的存储方式有可能变化,请不要修改缓存目录中的文件。
|
||||
|
||||
#### 设备信息
|
||||
Bot 默认使用全随机的设备信息。**在更换账号地点时候使用随机设备信息可能会导致无法登录**,当然,**成功登录时使用的设备信息也可以保存后在新的设备使用**。
|
||||
|
||||
@ -102,7 +121,6 @@ protocol = BotConfiguration.MiraiProtocol.ANDROID_PAD
|
||||
// Java
|
||||
setProtocol(MiraiProtocol.ANDROID_PAD)
|
||||
```
|
||||
|
||||
#### 重定向日志
|
||||
Bot 有两个日志类别,`Bot` 或 `Net`。`Bot` 为通常日志,如收到事件。`Net` 为网络日志,包含收到和发出的每一个包和网络层解析时遇到的错误。
|
||||
|
||||
@ -149,6 +167,34 @@ setLoginSolver(new YourLoginSolver())
|
||||
|
||||
> 要获取更多有关 `LoginSolver` 的信息,查看 [LoginSolver.kt](../mirai-core-api/src/commonMain/kotlin/utils/LoginSolver.kt#L32)
|
||||
|
||||
#### 启用列表缓存
|
||||
Mirai 在启动时会拉取全部好友列表和群成员列表。当账号拥有过多群时登录可能缓慢,开启列表缓存会大幅加速登录过程。
|
||||
|
||||
Mirai 自动根据事件更新列表,并在每次登录时与服务器校验缓存有效性,**但有时候可能发生意外情况导致列表没有同步。如果出现找不到群员或好友等不同步情况,请关闭缓存并[提交 Bug](https://github.com/mamoe/mirai/issues/new?assignees=&labels=question&template=bug.md)**
|
||||
|
||||
要开启列表缓存(自 mirai 2.4.0):
|
||||
```
|
||||
// 开启所有列表缓存
|
||||
enableContactCache()
|
||||
```
|
||||
|
||||
也可以只开启部分缓存:
|
||||
```
|
||||
// Kotlin
|
||||
contactListCache {
|
||||
friendListCacheEnabled = true // 开启好友列表缓存
|
||||
groupMemberListCacheEnabled = true // 开启群成员列表缓存
|
||||
|
||||
saveIntervalMillis = 60_000 // 可选设置有更新时的保存时间间隔, 默认 60 秒
|
||||
}
|
||||
|
||||
// Java
|
||||
contactListCache.setFriendListCacheEnabled(true) // 开启好友列表缓存
|
||||
contactListCache.setGroupMemberListCacheEnabled(true) // 开启群成员列表缓存
|
||||
contactListCache.setSaveIntervalMillis(60000) // 可选设置有更新时的保存时间间隔, 默认 60 秒
|
||||
```
|
||||
|
||||
|
||||
### 获取当前所有 `Bot` 实例
|
||||
|
||||
在登录后 `Bot` 实例会被自动记录。可在 `Bot.instances` 获取到当前**在线**的所有 `Bot` 列表。
|
||||
@ -168,11 +214,14 @@ setLoginSolver(new YourLoginSolver())
|
||||
|
||||
### 常见登录失败原因
|
||||
|
||||
[#993]: https://github.com/mamoe/mirai/discussions/993
|
||||
|
||||
| 错误信息 | 可能的原因 | 可能的解决方案 |
|
||||
|:--------------|:---------------|:----------------------|
|
||||
| 当前版本过低 | 密码错误 | 检查密码 |
|
||||
| 当前上网环境异常 | 设备锁 | 开启或关闭设备锁后重试登录 |
|
||||
| 当前版本过低 | 密码错误 | 检查密码或修改密码到 16 位以内 |
|
||||
| 当前上网环境异常 | 设备锁 | 开启或关闭设备锁 (登录保护) |
|
||||
| 禁止登录 | 需要处理滑块验证码 | [project-mirai/mirai-login-solver-selenium] |
|
||||
| 密码错误 | 密码错误或过长 | 手机协议最大支持 16 位密码 ([#993]). 在官方 PC 客户端登录后修改密码 |
|
||||
|
||||
若以上方案无法解决问题,请尝试 [切换登录协议](#切换登录协议) 和 **[处理滑动验证码](#处理滑动验证码)**。
|
||||
|
||||
|
@ -475,6 +475,7 @@ public open class MessageSubscribersBuilder<M : MessageEvent, out Ret, R : RR, R
|
||||
internal suspend inline fun executeAndReply(m: M, replier: suspend M.(String) -> Any?): RR {
|
||||
when (val message = replier(m, m.message.contentToString())) {
|
||||
is Message -> m.subject.sendMessage(message)
|
||||
null,
|
||||
is Unit -> Unit
|
||||
else -> m.subject.sendMessage(message.toString())
|
||||
}
|
||||
@ -485,6 +486,7 @@ public open class MessageSubscribersBuilder<M : MessageEvent, out Ret, R : RR, R
|
||||
internal suspend inline fun executeAndQuoteReply(m: M, replier: suspend M.(String) -> Any?): RR {
|
||||
when (val message = replier(m, m.message.contentToString())) {
|
||||
is Message -> m.subject.sendMessage(m.message.quote() + message)
|
||||
null,
|
||||
is Unit -> Unit
|
||||
else -> m.subject.sendMessage(m.message.quote() + message.toString())
|
||||
}
|
||||
|
@ -25,13 +25,7 @@ internal fun String.parseMiraiCodeImpl(contact: Contact?): MessageChain = buildM
|
||||
add(PlainText(origin.decodeMiraiCode()))
|
||||
return@forEachMiraiCode
|
||||
}
|
||||
parser.argsRegex.matchEntire(args)
|
||||
?.destructured
|
||||
?.let {
|
||||
parser.runCatching {
|
||||
contact.mapper(it)
|
||||
}.getOrNull()
|
||||
}
|
||||
parser.parse(contact, args)
|
||||
?.let(::add)
|
||||
?: add(PlainText(origin.decodeMiraiCode()))
|
||||
}
|
||||
@ -128,12 +122,76 @@ private object MiraiCodeParsers : Map<String, MiraiCodeParser> by mapOf(
|
||||
"dice" to MiraiCodeParser(Regex("""([1-6])""")) { (value) ->
|
||||
Dice(value.toInt())
|
||||
},
|
||||
"musicshare" to MiraiCodeParser.DynamicParser(7) { args ->
|
||||
val (kind, title, summary, jumpUrl, pictureUrl) = args
|
||||
val musicUrl = args[5]
|
||||
val brief = args[6]
|
||||
|
||||
MusicShare(MusicKind.valueOf(kind), title, summary, jumpUrl, pictureUrl, musicUrl, brief)
|
||||
},
|
||||
)
|
||||
|
||||
private class MiraiCodeParser(
|
||||
val argsRegex: Regex,
|
||||
val mapper: Contact?.(MatchResult.Destructured) -> Message?
|
||||
)
|
||||
|
||||
// Visitable for test
|
||||
internal sealed class MiraiCodeParser {
|
||||
abstract fun parse(contact: Contact?, args: String): Message?
|
||||
class RegexParser(
|
||||
private val argsRegex: Regex,
|
||||
private val mapper: Contact?.(MatchResult.Destructured) -> Message?
|
||||
) : MiraiCodeParser() {
|
||||
override fun parse(contact: Contact?, args: String): Message? =
|
||||
argsRegex.matchEntire(args)
|
||||
?.destructured
|
||||
?.let {
|
||||
runCatching {
|
||||
contact.mapper(it)
|
||||
}.getOrNull()
|
||||
}
|
||||
}
|
||||
|
||||
class DynamicParser(
|
||||
private val minArgs: Int,
|
||||
private val maxArgs: Int = minArgs,
|
||||
private val parser: (Contact?.(args: Array<String>) -> Message?),
|
||||
) : MiraiCodeParser() {
|
||||
override fun parse(contact: Contact?, args: String): Message? {
|
||||
val ranges = mutableListOf<IntRange>()
|
||||
if (args.isNotEmpty()) {
|
||||
var begin = 0
|
||||
var pos = 0
|
||||
val len = args.length
|
||||
while (pos < len) {
|
||||
when (args[pos]) {
|
||||
'\\' -> pos += 2
|
||||
',' -> {
|
||||
ranges.add(begin..pos)
|
||||
pos++
|
||||
begin = pos
|
||||
}
|
||||
else -> pos++
|
||||
}
|
||||
}
|
||||
ranges.add(begin..len)
|
||||
}
|
||||
if (ranges.size < minArgs) return null
|
||||
if (ranges.size > maxArgs) return null
|
||||
@Suppress("RemoveExplicitTypeArguments")
|
||||
val args0 = Array<String>(ranges.size) { index ->
|
||||
val range = ranges[index]
|
||||
args.substring(range.first, range.last).decodeMiraiCode()
|
||||
}
|
||||
runCatching {
|
||||
return parser(contact, args0)
|
||||
}
|
||||
return null
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private fun MiraiCodeParser(
|
||||
argsRegex: Regex,
|
||||
mapper: Contact?.(MatchResult.Destructured) -> Message?
|
||||
): MiraiCodeParser = MiraiCodeParser.RegexParser(argsRegex, mapper)
|
||||
|
||||
internal fun StringBuilder.appendStringAsMiraiCode(value: String): StringBuilder = apply {
|
||||
value.forEach { char ->
|
||||
|
@ -13,6 +13,8 @@ package net.mamoe.mirai.message.data
|
||||
|
||||
import kotlinx.serialization.SerialName
|
||||
import kotlinx.serialization.Serializable
|
||||
import net.mamoe.mirai.message.code.CodableMessage
|
||||
import net.mamoe.mirai.message.code.internal.appendStringAsMiraiCode
|
||||
import net.mamoe.mirai.utils.MiraiExperimentalApi
|
||||
import net.mamoe.mirai.utils.MiraiInternalApi
|
||||
import net.mamoe.mirai.utils.safeCast
|
||||
@ -53,7 +55,7 @@ public data class MusicShare(
|
||||
* 在消息列表显示
|
||||
*/
|
||||
public val brief: String,
|
||||
) : MessageContent, ConstrainSingle {
|
||||
) : MessageContent, ConstrainSingle, CodableMessage {
|
||||
|
||||
public constructor(
|
||||
/**
|
||||
@ -88,6 +90,19 @@ public data class MusicShare(
|
||||
override fun contentToString(): String =
|
||||
brief.takeIf { it.isNotBlank() } ?: "[分享]$title" // empty content is not accepted by `sendMessage`
|
||||
|
||||
override fun appendMiraiCodeTo(builder: StringBuilder) {
|
||||
builder.append("[mirai:musicshare:")
|
||||
.append(kind.name)
|
||||
.append(',').appendStringAsMiraiCode(title)
|
||||
.append(',').appendStringAsMiraiCode(summary)
|
||||
.append(',').appendStringAsMiraiCode(jumpUrl)
|
||||
.append(',').appendStringAsMiraiCode(pictureUrl)
|
||||
.append(',').appendStringAsMiraiCode(musicUrl)
|
||||
.append(',').appendStringAsMiraiCode(brief)
|
||||
.append(']')
|
||||
}
|
||||
|
||||
|
||||
// MusicShare(type=NeteaseCloudMusic, title='ファッション', summary='rinahamu/Yunomi', brief='', url='http://music.163.com/song/1338728297/?userid=324076307', pictureUrl='http://p2.music.126.net/y19E5SadGUmSR8SZxkrNtw==/109951163785855539.jpg', musicUrl='http://music.163.com/song/media/outer/url?id=1338728297&userid=324076307')
|
||||
|
||||
/**
|
||||
|
@ -277,8 +277,8 @@ public open class BotConfiguration { // open for Java
|
||||
*
|
||||
* - 默认打印到标准输出, 通过 [MiraiLogger.create]
|
||||
* - 忽略所有日志: [noBotLog]
|
||||
* - 重定向到一个目录: `networkLoggerSupplier = { DirectoryLogger("Net ${it.id}") }`
|
||||
* - 重定向到一个文件: `networkLoggerSupplier = { SingleFileLogger("Net ${it.id}") }`
|
||||
* - 重定向到一个目录: `botLoggerSupplier = { DirectoryLogger("Bot ${it.id}") }`
|
||||
* - 重定向到一个文件: `botLoggerSupplier = { SingleFileLogger("Bot ${it.id}") }`
|
||||
*
|
||||
* @see MiraiLogger
|
||||
*/
|
||||
|
@ -10,11 +10,27 @@
|
||||
package net.mamoe.mirai.message.code
|
||||
|
||||
import net.mamoe.mirai.message.code.MiraiCode.deserializeMiraiCode
|
||||
import net.mamoe.mirai.message.code.internal.MiraiCodeParser
|
||||
import net.mamoe.mirai.message.data.*
|
||||
import org.junit.jupiter.api.Test
|
||||
import kotlin.test.assertEquals
|
||||
import kotlin.test.assertNotNull
|
||||
|
||||
class TestMiraiCode {
|
||||
@Test
|
||||
fun testDynamicMiraiCodeParser() {
|
||||
fun runTest(args: Int, code: String, parse: (args: Array<String>) -> Unit) {
|
||||
val response = MiraiCodeParser.DynamicParser(args) { args0 -> parse(args0); AtAll }.parse(null, code)
|
||||
assertNotNull(response, "Parser not invoked")
|
||||
}
|
||||
runTest(3, "test,\\,test,\\,\\,test") { (arg1, arg2, arg3) ->
|
||||
assertEquals("test", arg1)
|
||||
assertEquals(",test", arg2)
|
||||
assertEquals(",,test", arg3)
|
||||
}
|
||||
runTest(2, ",") {}
|
||||
}
|
||||
|
||||
@Test
|
||||
fun testCodes() {
|
||||
assertEquals(AtAll.toMessageChain(), "[mirai:atall]".deserializeMiraiCode())
|
||||
@ -46,5 +62,16 @@ class TestMiraiCode {
|
||||
assertEquals(buildMessageChain {
|
||||
+Dice(1)
|
||||
}, "[mirai:dice:1]".deserializeMiraiCode())
|
||||
|
||||
val musicShare = MusicShare(
|
||||
kind = MusicKind.NeteaseCloudMusic,
|
||||
title = "ファッション",
|
||||
summary = "rinahamu/Yunomi",
|
||||
jumpUrl = "http://music.163.com/song/1338728297/?userid=324076307",
|
||||
pictureUrl = "http://p2.music.126.net/y19E5SadGUmSR8SZxkrNtw==/109951163785855539.jpg",
|
||||
musicUrl = "http://music.163.com/song/media/outer/url?id=1338728297&userid=324076307",
|
||||
brief = "",
|
||||
)
|
||||
assertEquals(musicShare.toMessageChain(), musicShare.serializeToMiraiCode().deserializeMiraiCode())
|
||||
}
|
||||
}
|
@ -292,13 +292,12 @@ internal abstract class AbstractBot<N : BotNetworkHandler> constructor(
|
||||
|
||||
// https://github.com/mamoe/mirai/issues/1019
|
||||
kotlin.runCatching {
|
||||
nick
|
||||
bot.nick
|
||||
}.onFailure {
|
||||
throw contextualBugReportException(
|
||||
context = "Bot login",
|
||||
forDebug = it.toString(),
|
||||
e = it,
|
||||
)
|
||||
bot.asQQAndroidBot().nick = MiraiImpl.queryProfile(bot, bot.id).nickname
|
||||
if (bot.nick.isBlank()) {
|
||||
logger.warning { "Unable to fetch nickname of bot." }
|
||||
}
|
||||
}
|
||||
|
||||
logger.info { "Login successful" }
|
||||
|
@ -20,7 +20,6 @@ import kotlinx.coroutines.withContext
|
||||
import kotlinx.io.core.discardExact
|
||||
import kotlinx.io.core.readBytes
|
||||
import kotlinx.serialization.json.*
|
||||
import net.mamoe.kjbb.JvmBlockingBridge
|
||||
import net.mamoe.mirai.*
|
||||
import net.mamoe.mirai.contact.*
|
||||
import net.mamoe.mirai.data.*
|
||||
@ -794,6 +793,9 @@ internal open class MiraiImpl : IMirai, LowLevelApiAccessor {
|
||||
accept = accept,
|
||||
blackList = blackList
|
||||
).sendWithoutExpect()
|
||||
|
||||
if (!accept) return@apply
|
||||
|
||||
@Suppress("INVISIBLE_MEMBER", "INVISIBLE_REFERENCE")
|
||||
bot.friends.delegate.add(newFriend(bot, FriendInfoImpl(fromId, fromNick, "")))
|
||||
}
|
||||
|
@ -156,6 +156,33 @@ private object ReceiveMessageTransformer {
|
||||
}
|
||||
}
|
||||
|
||||
fun MessageChainBuilder.compressContinuousPlainText() {
|
||||
var index = 0
|
||||
val builder = StringBuilder()
|
||||
while (index + 1 < size) {
|
||||
val elm0 = get(index)
|
||||
val elm1 = get(index + 1)
|
||||
if (elm0 is PlainText && elm1 is PlainText) {
|
||||
builder.setLength(0)
|
||||
var end = -1
|
||||
for (i in index until size) {
|
||||
val elm = get(i)
|
||||
if (elm is PlainText) {
|
||||
end = i
|
||||
builder.append(elm.content)
|
||||
} else break
|
||||
}
|
||||
set(index, PlainText(builder.toString()))
|
||||
// do delete
|
||||
val index1 = index + 1
|
||||
repeat(end - index) {
|
||||
removeAt(index1)
|
||||
}
|
||||
}
|
||||
index++
|
||||
}
|
||||
}
|
||||
|
||||
fun MessageChain.cleanupRubbishMessageElements(): MessageChain {
|
||||
var previousLast: SingleMessage? = null
|
||||
var last: SingleMessage? = null
|
||||
@ -215,15 +242,14 @@ private object ReceiveMessageTransformer {
|
||||
}
|
||||
}
|
||||
|
||||
if (element is PlainText) { // 处理分片消息
|
||||
append(element.content)
|
||||
} else {
|
||||
add(element)
|
||||
}
|
||||
append(element)
|
||||
|
||||
previousLast = last
|
||||
last = element
|
||||
}
|
||||
|
||||
// 处理分片信息
|
||||
compressContinuousPlainText()
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -165,6 +165,8 @@ internal open class QQAndroidClient(
|
||||
|
||||
class MessageSvcSyncData {
|
||||
val firstNotify: AtomicBoolean = atomic(true)
|
||||
var latestMsgNewGroupTime: Long = currentTimeSeconds()
|
||||
var latestMsgNewFriendTime: Long = currentTimeSeconds()
|
||||
|
||||
@Volatile
|
||||
var syncCookie: ByteArray? = null
|
||||
@ -180,12 +182,13 @@ internal open class QQAndroidClient(
|
||||
|
||||
val pbGetMessageCacheList = SyncingCacheList<PbGetMessageSyncId>()
|
||||
|
||||
internal data class SystemMsgNewGroupSyncId(
|
||||
internal data class SystemMsgNewSyncId(
|
||||
val sequence: Long,
|
||||
val time: Long
|
||||
)
|
||||
|
||||
val systemMsgNewGroupCacheList = SyncingCacheList<SystemMsgNewGroupSyncId>(10)
|
||||
val systemMsgNewGroupCacheList = SyncingCacheList<SystemMsgNewSyncId>(10)
|
||||
val systemMsgNewFriendCacheList = SyncingCacheList<SystemMsgNewSyncId>(10)
|
||||
|
||||
|
||||
internal data class PbPushTransMsgSyncId(
|
||||
|
@ -19,6 +19,7 @@ import net.mamoe.mirai.event.events.MemberJoinRequestEvent
|
||||
import net.mamoe.mirai.event.events.NewFriendRequestEvent
|
||||
import net.mamoe.mirai.internal.QQAndroidBot
|
||||
import net.mamoe.mirai.internal.message.contextualBugReportException
|
||||
import net.mamoe.mirai.internal.network.MultiPacketByIterable
|
||||
import net.mamoe.mirai.internal.network.Packet
|
||||
import net.mamoe.mirai.internal.network.QQAndroidClient
|
||||
import net.mamoe.mirai.internal.network.protocol.data.proto.Structmsg
|
||||
@ -27,11 +28,12 @@ import net.mamoe.mirai.internal.network.protocol.packet.buildOutgoingUniPacket
|
||||
import net.mamoe.mirai.internal.utils._miraiContentToString
|
||||
import net.mamoe.mirai.internal.utils.io.serialization.loadAs
|
||||
import net.mamoe.mirai.internal.utils.io.serialization.writeProtoBuf
|
||||
import kotlin.math.max
|
||||
|
||||
internal class NewContact {
|
||||
|
||||
internal object SystemMsgNewFriend :
|
||||
OutgoingPacketFactory<NewFriendRequestEvent?>("ProfileService.Pb.ReqSystemMsgNew.Friend") {
|
||||
OutgoingPacketFactory<Packet?>("ProfileService.Pb.ReqSystemMsgNew.Friend") {
|
||||
|
||||
operator fun invoke(client: QQAndroidClient) = buildOutgoingUniPacket(client) {
|
||||
writeProtoBuf(
|
||||
@ -55,18 +57,40 @@ internal class NewContact {
|
||||
}
|
||||
|
||||
|
||||
override suspend fun ByteReadPacket.decode(bot: QQAndroidBot): NewFriendRequestEvent? {
|
||||
override suspend fun ByteReadPacket.decode(bot: QQAndroidBot): Packet? {
|
||||
readBytes().loadAs(Structmsg.RspSystemMsgNew.serializer()).run {
|
||||
val struct = friendmsgs.firstOrNull()// 会有重复且无法过滤, 不要用 map
|
||||
return struct?.msg?.run {
|
||||
NewFriendRequestEvent(
|
||||
bot,
|
||||
struct.msgSeq,
|
||||
msgAdditional,
|
||||
struct.reqUin,
|
||||
groupCode,
|
||||
reqUinNick
|
||||
)
|
||||
return friendmsgs.filter {
|
||||
it.msgTime >= bot.client.syncingController.latestMsgNewFriendTime
|
||||
}.mapNotNull { struct ->
|
||||
if (!bot.client.syncingController.systemMsgNewFriendCacheList.addCache(
|
||||
QQAndroidClient.MessageSvcSyncData.SystemMsgNewSyncId(
|
||||
struct.msgSeq,
|
||||
struct.msgTime
|
||||
)
|
||||
)
|
||||
) { // duplicate
|
||||
return@mapNotNull null
|
||||
}
|
||||
struct.msg?.run {
|
||||
NewFriendRequestEvent(
|
||||
bot,
|
||||
struct.msgSeq,
|
||||
msgAdditional,
|
||||
struct.reqUin,
|
||||
groupCode,
|
||||
reqUinNick
|
||||
)
|
||||
}
|
||||
}.let { packets ->
|
||||
when {
|
||||
packets.isEmpty() -> null
|
||||
packets.size == 1 -> packets[0]
|
||||
else -> MultiPacketByIterable(packets)
|
||||
}
|
||||
}.also {
|
||||
bot.client.syncingController.run {
|
||||
latestMsgNewFriendTime = max(latestMsgNewFriendTime, friendmsgs.maxOfOrNull { it.msgTime } ?: 0)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -143,18 +167,8 @@ internal class NewContact {
|
||||
|
||||
|
||||
override suspend fun ByteReadPacket.decode(bot: QQAndroidBot): Packet? {
|
||||
return readBytes().loadAs(Structmsg.RspSystemMsgNew.serializer()).run {
|
||||
val struct = groupmsgs.firstOrNull() ?: return null // 会有重复且无法过滤, 不要用 map
|
||||
|
||||
if (!bot.client.syncingController.systemMsgNewGroupCacheList.addCache(
|
||||
QQAndroidClient.MessageSvcSyncData.SystemMsgNewGroupSyncId(struct.msgSeq, struct.msgTime)
|
||||
)
|
||||
) { // duplicate
|
||||
return null
|
||||
}
|
||||
|
||||
struct.msg?.run {
|
||||
//this.soutv("SystemMsg")
|
||||
fun handleStruct(struct: Structmsg.StructMsg): Packet? {
|
||||
return struct.msg?.run {
|
||||
when (subType) {
|
||||
1 -> { // 处理被邀请入群 或 处理成员入群申请
|
||||
when (groupMsgType) {
|
||||
@ -232,6 +246,33 @@ internal class NewContact {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return readBytes().loadAs(Structmsg.RspSystemMsgNew.serializer()).run {
|
||||
groupmsgs.filter {
|
||||
it.msgTime >= bot.client.syncingController.latestMsgNewGroupTime
|
||||
}.mapNotNull { struct ->
|
||||
if (!bot.client.syncingController.systemMsgNewGroupCacheList.addCache(
|
||||
QQAndroidClient.MessageSvcSyncData.SystemMsgNewSyncId(
|
||||
struct.msgSeq,
|
||||
struct.msgTime
|
||||
)
|
||||
)
|
||||
) { // duplicate
|
||||
return@mapNotNull null
|
||||
}
|
||||
handleStruct(struct)
|
||||
}.let { packets ->
|
||||
when {
|
||||
packets.isEmpty() -> null
|
||||
packets.size == 1 -> packets[0]
|
||||
else -> MultiPacketByIterable(packets)
|
||||
}
|
||||
}.also {
|
||||
bot.client.syncingController.run {
|
||||
latestMsgNewGroupTime = max(latestMsgNewGroupTime, groupmsgs.maxOfOrNull { it.msgTime } ?: 0)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
internal object Action : OutgoingPacketFactory<Nothing?>("ProfileService.Pb.ReqSystemMsgAction.Group") {
|
||||
|
@ -156,7 +156,11 @@ internal object OnlinePushPbPushGroupMsg : IncomingPacketFactory<Packet?>("Onlin
|
||||
) = when {
|
||||
flags and 16 != 0 -> MemberPermission.ADMINISTRATOR
|
||||
flags and 8 != 0 -> MemberPermission.OWNER
|
||||
flags == 0 || flags == 1 -> MemberPermission.MEMBER
|
||||
(when (flags) {
|
||||
1, 0, 64,
|
||||
-> true
|
||||
else -> false
|
||||
}) -> MemberPermission.MEMBER
|
||||
else -> {
|
||||
bot.logger.warning { "判断群 ${sender.group.id} 的群员 ${sender.id} 的权限失败: ${flags._miraiContentToString()}. 请完整截图或复制此日志并确认其真实权限后发送给 mirai 维护者以帮助解决问题." }
|
||||
sender.permission
|
||||
|
Loading…
Reference in New Issue
Block a user