mirror of
https://github.com/mamoe/mirai.git
synced 2025-02-08 22:09:50 +08:00
Merge remote-tracking branch 'origin/master'
# Conflicts: # mirai-core/src/commonMain/kotlin/net.mamoe.mirai/message/data/MessageSource.kt
This commit is contained in:
commit
1c1a37a103
8
.github/ISSUE_TEMPLATE/bug---.md
vendored
8
.github/ISSUE_TEMPLATE/bug---.md
vendored
@ -7,7 +7,7 @@ assignees: ''
|
||||
|
||||
---
|
||||
|
||||
## 问题
|
||||
|
||||
<!--在这里简略描述你遇到的问题-->
|
||||
|
||||
|
||||
@ -17,14 +17,18 @@ assignees: ''
|
||||
<!--如果有控制台报错,请尽量在这里附加全面的日志. (不建议截图)-->
|
||||
|
||||
|
||||
|
||||
```
|
||||
|
||||
|
||||
## 如何复现
|
||||
### 如何复现
|
||||
<!--在这里简略说明如何让这个问题再次发生-->
|
||||
<!--可使用 1. 2. 3. 的列表格式,或其他任意恰当的格式-->
|
||||
|
||||
|
||||
### 版本
|
||||
mirai: `` <!--在``中填写你正在使用的版本号,如0.40.0-->
|
||||
|
||||
|
||||
|
||||
<!--如有必要,你可以在下文继续添加其他信息-->
|
||||
|
@ -18,6 +18,7 @@ buildscript {
|
||||
classpath("org.jetbrains.kotlin:kotlin-gradle-plugin:${Versions.Kotlin.stdlib}")
|
||||
classpath("org.jetbrains.kotlin:kotlin-serialization:${Versions.Kotlin.stdlib}")
|
||||
classpath("org.jetbrains.kotlinx:atomicfu-gradle-plugin:${Versions.Kotlin.atomicFU}")
|
||||
classpath("org.jetbrains.kotlinx:binary-compatibility-validator:${Versions.Kotlin.binaryValidator}")
|
||||
}
|
||||
}
|
||||
|
||||
@ -26,6 +27,10 @@ plugins {
|
||||
// id("com.jfrog.bintray") version Versions.Publishing.bintray apply false
|
||||
}
|
||||
|
||||
// https://github.com/kotlin/binary-compatibility-validator
|
||||
apply(plugin = "binary-compatibility-validator")
|
||||
|
||||
|
||||
project.ext.set("isAndroidSDKAvailable", false)
|
||||
|
||||
// until
|
||||
@ -139,17 +144,20 @@ subprojects {
|
||||
}
|
||||
|
||||
|
||||
fun Project.findLatestFile(): Map.Entry<String, File>? {
|
||||
fun Project.findLatestFile(): Map.Entry<String, File> {
|
||||
return File(projectDir, "build/libs").walk()
|
||||
.filter { it.isFile }
|
||||
.onEach { println("all files=$it") }
|
||||
.filter { it.name.matches(Regex("""${project.name}-([0-9]|\.)*\.jar""")) }
|
||||
.filter { it.name.matches(Regex("""${project.name}-[0-9][0-9]*(\.[0-9]*)*.*\.jar""")) }
|
||||
.onEach { println("matched file: ${it.name}") }
|
||||
.associateBy { it.nameWithoutExtension.substringAfterLast('-') }
|
||||
.onEach { println("versions: $it") }
|
||||
.maxBy {
|
||||
it.key.split('.').foldRightIndexed(0) { index: Int, s: String, acc: Int ->
|
||||
acc + 100.0.pow(2 - index).toInt() * (s.toIntOrNull() ?: 0)
|
||||
.maxBy { (version, file) ->
|
||||
version.split('.').let {
|
||||
if (it.size == 2) it + "0"
|
||||
else it
|
||||
}.reversed().foldIndexed(0) { index: Int, acc: Int, s: String ->
|
||||
acc + 100.0.pow(index).toInt() * (s.toIntOrNull() ?: 0)
|
||||
}
|
||||
}
|
||||
} ?: error("cannot find any file to upload")
|
||||
}
|
@ -18,6 +18,7 @@ object Versions {
|
||||
const val atomicFU = "0.14.2"
|
||||
const val serialization = "0.20.0"
|
||||
const val ktor = "1.3.2"
|
||||
const val binaryValidator = "0.2.3"
|
||||
|
||||
const val io = "0.1.16"
|
||||
const val coroutinesIo = "0.1.16"
|
||||
|
13
gradle/api-validation.gradle
Normal file
13
gradle/api-validation.gradle
Normal file
@ -0,0 +1,13 @@
|
||||
apiValidation {
|
||||
ignoredPackages += [
|
||||
"net.mamoe.mirai.event.internal",
|
||||
"net.mamoe.mirai.utils.internal"
|
||||
]
|
||||
|
||||
ignoredPackages += [
|
||||
"net.mamoe.mirai.qqandroid.contact",
|
||||
"net.mamoe.mirai.qqandroid.message",
|
||||
"net.mamoe.mirai.qqandroid.network",
|
||||
"net.mamoe.mirai.qqandroid.utils"
|
||||
]
|
||||
}
|
@ -504,8 +504,8 @@ internal class MsgSvc : ProtoBuf {
|
||||
|
||||
@Serializable
|
||||
internal class SecretFileHead(
|
||||
@ProtoId(1) @JvmField val secretFileMsg: SubMsgType0xc1.MsgBody? = null,
|
||||
@ProtoId(2) @JvmField val secretFileStatus: SubMsgType0x1a.MsgBody? = null
|
||||
@ProtoId(1) @JvmField val secretFileMsg: SubMsgType0xc1.MsgBody? = null
|
||||
// @ProtoId(2) @JvmField val secretFileStatus: SubMsgType0x1a.MsgBody? = null
|
||||
)
|
||||
|
||||
@Serializable
|
||||
@ -815,6 +815,7 @@ internal class SubMsgType0xc1 {
|
||||
) : ProtoBuf
|
||||
}
|
||||
|
||||
/*
|
||||
@Serializable
|
||||
internal class SubMsgType0x1a {
|
||||
@Serializable
|
||||
@ -830,4 +831,4 @@ internal class SubMsgType0x1a {
|
||||
@ProtoId(9) @JvmField val fromUin: Long = 0L,
|
||||
@ProtoId(10) @JvmField val toUin: Long = 0L
|
||||
) : ProtoBuf
|
||||
}
|
||||
}*/
|
@ -515,6 +515,7 @@ internal class Submsgtype0x129 {
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
internal class Submsgtype0x1a {
|
||||
internal class SubMsgType0x1a : ProtoBuf {
|
||||
@Serializable
|
||||
@ -531,7 +532,7 @@ internal class Submsgtype0x1a {
|
||||
@ProtoId(10) @JvmField val toUin: Long = 0L
|
||||
) : ProtoBuf
|
||||
}
|
||||
}
|
||||
}*/
|
||||
|
||||
|
||||
internal class Submsgtype0x26 {
|
||||
@ -2730,6 +2731,7 @@ internal class Submsgtype0xbe {
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
internal class Submsgtype0xc1 {
|
||||
internal class Submsgtype0xc1 : ProtoBuf {
|
||||
@Serializable
|
||||
@ -2740,7 +2742,7 @@ internal class Submsgtype0xc1 {
|
||||
) : ProtoBuf
|
||||
}
|
||||
}
|
||||
|
||||
*/
|
||||
|
||||
internal class Submsgtype0xc3 {
|
||||
internal class Submsgtype0xc3 : ProtoBuf {
|
||||
|
@ -52,7 +52,7 @@ internal class NewContact {
|
||||
struct.msgSeq,
|
||||
msgAdditional,
|
||||
struct.reqUin,
|
||||
Group.calculateGroupUinByGroupCode(groupCode),
|
||||
groupCode,
|
||||
reqUinNick
|
||||
)
|
||||
}
|
||||
@ -143,7 +143,7 @@ internal class NewContact {
|
||||
bot,
|
||||
struct.msgSeq,
|
||||
actionUin,
|
||||
Group.calculateGroupUinByGroupCode(groupCode),
|
||||
groupCode,
|
||||
groupName,
|
||||
actionUinNick
|
||||
)
|
||||
@ -155,7 +155,7 @@ internal class NewContact {
|
||||
struct.msgSeq,
|
||||
msgAdditional,
|
||||
struct.reqUin,
|
||||
Group.calculateGroupUinByGroupCode(groupCode),
|
||||
groupCode,
|
||||
groupName,
|
||||
reqUinNick
|
||||
)
|
||||
@ -185,7 +185,7 @@ internal class NewContact {
|
||||
true -> 11 // accept
|
||||
false -> 12 // reject
|
||||
},
|
||||
groupCode = Group.calculateGroupCodeByGroupUin(event.groupId),
|
||||
groupCode = event.groupId,
|
||||
msg = "",
|
||||
remark = "",
|
||||
blacklist = blackList
|
||||
|
@ -13,6 +13,7 @@ package net.mamoe.mirai.qqandroid.network.protocol.packet.chat.receive
|
||||
|
||||
import kotlinx.io.core.*
|
||||
import kotlinx.serialization.Serializable
|
||||
import net.mamoe.mirai.Bot
|
||||
import net.mamoe.mirai.LowLevelAPI
|
||||
import net.mamoe.mirai.contact.MemberPermission
|
||||
import net.mamoe.mirai.contact.nameCardOrNick
|
||||
@ -401,13 +402,15 @@ internal class OnlinePush {
|
||||
when {
|
||||
pkg.authorUin == bot.id && operator.id == bot.id -> null
|
||||
else -> {
|
||||
MessageRecallEvent.GroupRecall(bot,
|
||||
MessageRecallEvent.GroupRecall(
|
||||
bot,
|
||||
pkg.authorUin,
|
||||
pkg.seq,
|
||||
pkg.msgRandom,
|
||||
pkg.time,
|
||||
operator,
|
||||
group)
|
||||
group
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -583,6 +586,10 @@ internal class OnlinePush {
|
||||
} ?: emptySequence()
|
||||
}
|
||||
|
||||
fun Submsgtype0x27.SubMsgType0x27.ModCustomFace.transform(bot: QQAndroidBot): Sequence<Packet> =
|
||||
sequenceOf(BotFaceChangedEvent(Bot.getInstance(uin)))
|
||||
|
||||
|
||||
return@lambda528 vProtobuf.loadAs(Submsgtype0x27.SubMsgType0x27.MsgBody.serializer()).msgModInfos.asSequence()
|
||||
.flatMap {
|
||||
when {
|
||||
@ -590,6 +597,7 @@ internal class OnlinePush {
|
||||
it.msgDelFriend != null -> it.msgDelFriend.transform(bot)
|
||||
it.msgModGroupProfile != null -> it.msgModGroupProfile.transform(bot)
|
||||
it.msgModGroupMemberProfile != null -> it.msgModGroupMemberProfile.transform(bot)
|
||||
it.msgModCustomFace != null -> it.msgModCustomFace.transform(bot)
|
||||
else -> {
|
||||
bot.network.logger.debug {
|
||||
"Transformers528 0x27L: new data: ${it._miraiContentToString()}"
|
||||
|
@ -24,6 +24,7 @@ import net.mamoe.mirai.network.closeAndJoin
|
||||
import net.mamoe.mirai.utils.*
|
||||
import net.mamoe.mirai.utils.internal.retryCatching
|
||||
import kotlin.coroutines.CoroutineContext
|
||||
import kotlin.time.Duration
|
||||
import kotlin.time.ExperimentalTime
|
||||
import kotlin.time.measureTime
|
||||
|
||||
@ -138,7 +139,7 @@ abstract class BotImpl<N : BotNetworkHandler> constructor(
|
||||
reconnect()
|
||||
}
|
||||
|
||||
logger.info { "Reconnected successfully in ${time.inMilliseconds} ms" }
|
||||
logger.info { "Reconnected successfully in ${time.asHumanReadable}" }
|
||||
}
|
||||
is BotOfflineEvent.Active -> {
|
||||
val msg = if (event.cause == null) {
|
||||
|
@ -287,7 +287,7 @@ open class MessageSubscribersBuilder<M : MessageEvent, out Ret, R : RR, RR>(
|
||||
@MessageDsl
|
||||
fun atAll(): ListeningFilter = content { message.firstIsInstanceOrNull<AtAll>() != null }
|
||||
|
||||
/** [消息内容][Message.contentToString]包含 [AtAll] */
|
||||
/** [消息内容][Message.contentToString]包含目标为 [target] 的 [At] */
|
||||
@MessageDsl
|
||||
fun at(target: Long): ListeningFilter = content { message.firstIsInstanceOrNull<At>()?.target == target }
|
||||
|
||||
@ -447,4 +447,4 @@ open class MessageSubscribersBuilder<M : MessageEvent, out Ret, R : RR, RR>(
|
||||
@Retention(AnnotationRetention.SOURCE)
|
||||
@Target(AnnotationTarget.FUNCTION, AnnotationTarget.CLASS, AnnotationTarget.TYPE)
|
||||
@DslMarker
|
||||
annotation class MessageDsl
|
||||
annotation class MessageDsl
|
||||
|
@ -88,6 +88,13 @@ data class BotReloginEvent(
|
||||
val cause: Throwable?
|
||||
) : BotEvent, BotActiveEvent, AbstractEvent()
|
||||
|
||||
/**
|
||||
* [Bot] 头像被修改(通过其他客户端修改了Bot的头像)
|
||||
*/
|
||||
data class BotFaceChangedEvent(
|
||||
override val bot: Bot
|
||||
) : BotEvent, Packet, AbstractEvent()
|
||||
|
||||
// endregion
|
||||
|
||||
// region 消息
|
||||
|
@ -15,6 +15,10 @@ package net.mamoe.mirai.utils
|
||||
import kotlin.jvm.JvmMultifileClass
|
||||
import kotlin.jvm.JvmName
|
||||
import kotlin.jvm.JvmSynthetic
|
||||
import kotlin.math.floor
|
||||
import kotlin.time.Duration
|
||||
import kotlin.time.DurationUnit
|
||||
import kotlin.time.ExperimentalTime
|
||||
|
||||
/**
|
||||
* 时间戳
|
||||
@ -76,4 +80,21 @@ inline val Int.weeksToSeconds: Long
|
||||
|
||||
@get:JvmSynthetic
|
||||
inline val Int.monthsToSeconds: Long
|
||||
get() = this * 30.daysToSeconds
|
||||
get() = this * 30.daysToSeconds
|
||||
|
||||
@ExperimentalTime
|
||||
val Duration.asHumanReadable: String
|
||||
get() {
|
||||
val builder = StringBuilder()
|
||||
val days = toInt(DurationUnit.DAYS)
|
||||
val hours = toInt(DurationUnit.HOURS) % 24
|
||||
val minutes = toInt(DurationUnit.MINUTES) % 60
|
||||
val s = floor(toDouble(DurationUnit.SECONDS) % 60 * 1000) / 1000
|
||||
with(builder) {
|
||||
if (days != 0) append("${days}d ")
|
||||
if (hours != 0) append("${hours}h ")
|
||||
if (minutes != 0) append("${minutes}min ")
|
||||
append("${s}s")
|
||||
}
|
||||
return builder.toString()
|
||||
}
|
||||
|
@ -0,0 +1,31 @@
|
||||
/*
|
||||
* 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.utils
|
||||
|
||||
import kotlin.test.Test
|
||||
import kotlin.test.assertTrue
|
||||
import kotlin.time.DurationUnit
|
||||
import kotlin.time.ExperimentalTime
|
||||
import kotlin.time.toDuration
|
||||
|
||||
internal class TimeTest {
|
||||
@ExperimentalTime
|
||||
@Test
|
||||
fun testTimeHumanReadable() {
|
||||
val time0 = 1.toDuration(DurationUnit.DAYS) +
|
||||
20.toDuration(DurationUnit.HOURS) +
|
||||
15.toDuration(DurationUnit.MINUTES) +
|
||||
2057.toDuration(DurationUnit.MILLISECONDS)
|
||||
println(time0.asHumanReadable)
|
||||
assertTrue { time0.asHumanReadable == "1d 20h 15min 2.057s" }
|
||||
val time1 = 1.toDuration(DurationUnit.DAYS) + 59.toDuration(DurationUnit.MINUTES)
|
||||
println(time1.asHumanReadable)
|
||||
assertTrue { time1.asHumanReadable == "1d 59min 0.0s" }
|
||||
}
|
||||
}
|
@ -24,8 +24,8 @@ internal actual class DeferredReusableInput actual constructor(
|
||||
is InputStream -> strategy.newImageCache(input)
|
||||
is ByteArray -> strategy.newImageCache(input)
|
||||
is Input -> strategy.newImageCache(input)
|
||||
is BufferedImage -> strategy.newImageCache(input, extraArg as String)
|
||||
is URL -> strategy.newImageCache(input)
|
||||
is BufferedImage -> strategy.newImageCache(input, extraArg as String)
|
||||
else -> error("Internal error: unsupported DeferredReusableInput.input: ${input::class.qualifiedName}")
|
||||
}.input
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user