瀏覽代碼

Adapt for server time difference, let `MessageSource.time` refer to server time. Fixes 1519

Him188 4 年之前
父節點
當前提交
238ec52eea

+ 2 - 1
mirai-core-api/src/commonMain/kotlin/message/data/MessageSource.kt

@@ -149,7 +149,8 @@ public sealed class MessageSource : Message, MessageMetadata, ConstrainSingle {
     /**
     /**
      * 发送时间时间戳, 单位为秒.
      * 发送时间时间戳, 单位为秒.
      *
      *
-     * 时间戳可能来自服务器, 也可能来自 mirai, 且无法保证两者时间同步.
+     * 自 2.8.0 起, 时间戳为服务器时区 (UTC+8).
+     * 在 2.8.0 以前, 时间戳可能来自服务器 (UTC+8), 也可能来自 mirai (本地), 且无法保证两者时间同步.
      */
      */
     public abstract val time: Int
     public abstract val time: Int
 
 

+ 30 - 0
mirai-core-utils/src/commonMain/kotlin/Clock.kt

@@ -0,0 +1,30 @@
+/*
+ * Copyright 2019-2021 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/dev/LICENSE
+ */
+
+package net.mamoe.mirai.utils
+
+public interface Clock {
+    public fun currentTimeMillis(): Long
+    public fun currentTimeSeconds(): Long
+
+    public object SystemDefault : Clock {
+        override fun currentTimeMillis(): Long = net.mamoe.mirai.utils.currentTimeMillis()
+        override fun currentTimeSeconds(): Long = net.mamoe.mirai.utils.currentTimeSeconds()
+    }
+}
+
+public fun Clock.adjusted(diffMillis: Long): Clock = AdjustedClock(this, diffMillis)
+
+public class AdjustedClock(
+    private val clock: Clock,
+    private val diffMillis: Long,
+) : Clock {
+    override fun currentTimeMillis(): Long = clock.currentTimeMillis() + diffMillis
+    override fun currentTimeSeconds(): Long = (clock.currentTimeMillis() + diffMillis) / 1000
+}

+ 1 - 0
mirai-core/src/commonMain/kotlin/QQAndroidBot.kt

@@ -232,6 +232,7 @@ internal open class QQAndroidBot constructor(
         return ConcurrentComponentStorage {
         return ConcurrentComponentStorage {
             set(BotClientHolder, BotClientHolderImpl(bot, networkLogger.subLogger("BotClientHolder")))
             set(BotClientHolder, BotClientHolderImpl(bot, networkLogger.subLogger("BotClientHolder")))
             set(SyncController, SyncControllerImpl())
             set(SyncController, SyncControllerImpl())
+            set(ClockHolder, ClockHolder())
         }.withFallback(defaultBotLevelComponents)
         }.withFallback(defaultBotLevelComponents)
     }
     }
 
 

+ 2 - 1
mirai-core/src/commonMain/kotlin/contact/SendMessageHandler.kt

@@ -19,6 +19,7 @@ import net.mamoe.mirai.internal.getMiraiImpl
 import net.mamoe.mirai.internal.message.*
 import net.mamoe.mirai.internal.message.*
 import net.mamoe.mirai.internal.network.Packet
 import net.mamoe.mirai.internal.network.Packet
 import net.mamoe.mirai.internal.network.QQAndroidClient
 import net.mamoe.mirai.internal.network.QQAndroidClient
+import net.mamoe.mirai.internal.network.components.ClockHolder.Companion.clock
 import net.mamoe.mirai.internal.network.components.MessageSvcSyncer
 import net.mamoe.mirai.internal.network.components.MessageSvcSyncer
 import net.mamoe.mirai.internal.network.handler.logger
 import net.mamoe.mirai.internal.network.handler.logger
 import net.mamoe.mirai.internal.network.notice.group.GroupMessageProcessor.SendGroupMessageReceipt
 import net.mamoe.mirai.internal.network.notice.group.GroupMessageProcessor.SendGroupMessageReceipt
@@ -399,7 +400,7 @@ internal open class GroupSendMessageHandler(
             providedSequenceIds = intArrayOf(receipt.sequenceId),
             providedSequenceIds = intArrayOf(receipt.sequenceId),
             sender = bot,
             sender = bot,
             target = contact,
             target = contact,
-            time = currentTimeSeconds().toInt(),
+            time = bot.clock.server.currentTimeSeconds().toInt(),
             originalMessage = finalMessage
             originalMessage = finalMessage
         )
         )
     }
     }

+ 23 - 0
mirai-core/src/commonMain/kotlin/network/components/ClockComponent.kt

@@ -0,0 +1,23 @@
+/*
+ * Copyright 2019-2021 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/dev/LICENSE
+ */
+
+package net.mamoe.mirai.internal.network.components
+
+import net.mamoe.mirai.internal.QQAndroidBot
+import net.mamoe.mirai.internal.network.component.ComponentKey
+import net.mamoe.mirai.utils.Clock
+
+internal class ClockHolder {
+    val local: Clock get() = Clock.SystemDefault
+    var server: Clock = local
+
+    companion object : ComponentKey<ClockHolder> {
+        val QQAndroidBot.clock get() = components[ClockHolder]
+    }
+}

+ 5 - 5
mirai-core/src/commonMain/kotlin/network/protocol/packet/chat/receive/MessageSvc.PbSendMsg.kt

@@ -23,6 +23,7 @@ import net.mamoe.mirai.internal.contact.uin
 import net.mamoe.mirai.internal.message.*
 import net.mamoe.mirai.internal.message.*
 import net.mamoe.mirai.internal.network.Packet
 import net.mamoe.mirai.internal.network.Packet
 import net.mamoe.mirai.internal.network.QQAndroidClient
 import net.mamoe.mirai.internal.network.QQAndroidClient
+import net.mamoe.mirai.internal.network.components.ClockHolder.Companion.clock
 import net.mamoe.mirai.internal.network.components.SyncController.Companion.syncController
 import net.mamoe.mirai.internal.network.components.SyncController.Companion.syncController
 import net.mamoe.mirai.internal.network.components.SyncController.Companion.syncCookie
 import net.mamoe.mirai.internal.network.components.SyncController.Companion.syncCookie
 import net.mamoe.mirai.internal.network.protocol.data.proto.ImMsgBody
 import net.mamoe.mirai.internal.network.protocol.data.proto.ImMsgBody
@@ -35,7 +36,6 @@ import net.mamoe.mirai.internal.network.protocol.packet.buildOutgoingUniPacket
 import net.mamoe.mirai.internal.utils.io.serialization.readProtoBuf
 import net.mamoe.mirai.internal.utils.io.serialization.readProtoBuf
 import net.mamoe.mirai.internal.utils.io.serialization.writeProtoBuf
 import net.mamoe.mirai.internal.utils.io.serialization.writeProtoBuf
 import net.mamoe.mirai.message.data.*
 import net.mamoe.mirai.message.data.*
-import net.mamoe.mirai.utils.currentTimeSeconds
 import net.mamoe.mirai.utils.getRandomUnsignedInt
 import net.mamoe.mirai.utils.getRandomUnsignedInt
 import java.util.concurrent.atomic.AtomicReference
 import java.util.concurrent.atomic.AtomicReference
 import kotlin.contracts.InvocationKind
 import kotlin.contracts.InvocationKind
@@ -215,7 +215,7 @@ internal object MessageSvcPbSendMsg : OutgoingPacketFactory<MessageSvcPbSendMsg.
                         internalIds = randIds.get(),
                         internalIds = randIds.get(),
                         sender = client.bot,
                         sender = client.bot,
                         target = target,
                         target = target,
-                        time = currentTimeSeconds().toInt(),
+                        time = client.bot.clock.server.currentTimeSeconds().toInt(),
                         sequenceIds = sequenceIds.get(),
                         sequenceIds = sequenceIds.get(),
                         originalMessage = message,
                         originalMessage = message,
                     ),
                     ),
@@ -275,7 +275,7 @@ internal object MessageSvcPbSendMsg : OutgoingPacketFactory<MessageSvcPbSendMsg.
                         internalIds = randIds.get(),
                         internalIds = randIds.get(),
                         sender = client.bot,
                         sender = client.bot,
                         target = targetFriend,
                         target = targetFriend,
-                        time = currentTimeSeconds().toInt(),
+                        time = client.bot.clock.server.currentTimeSeconds().toInt(),
                         sequenceIds = sequenceIds.get(),
                         sequenceIds = sequenceIds.get(),
                         originalMessage = message,
                         originalMessage = message,
                     ),
                     ),
@@ -400,7 +400,7 @@ internal object MessageSvcPbSendMsg : OutgoingPacketFactory<MessageSvcPbSendMsg.
                         internalIds = randIds.get(),
                         internalIds = randIds.get(),
                         sender = client.bot,
                         sender = client.bot,
                         target = targetGroup,
                         target = targetGroup,
-                        time = currentTimeSeconds().toInt(),
+                        time = client.bot.clock.server.currentTimeSeconds().toInt(),
                         originalMessage = message, //,
                         originalMessage = message, //,
                         //   sourceMessage = message
                         //   sourceMessage = message
                     ),
                     ),
@@ -488,7 +488,7 @@ internal inline fun MessageSvcPbSendMsg.createToTemp(
         internalIds = intArrayOf(Random.nextInt().absoluteValue),
         internalIds = intArrayOf(Random.nextInt().absoluteValue),
         sender = client.bot,
         sender = client.bot,
         target = member,
         target = member,
-        time = currentTimeSeconds().toInt(),
+        time = client.bot.clock.server.currentTimeSeconds().toInt(),
         sequenceIds = intArrayOf(client.atomicNextMessageSequenceId()),
         sequenceIds = intArrayOf(client.atomicNextMessageSequenceId()),
         originalMessage = message,
         originalMessage = message,
     )
     )

+ 12 - 6
mirai-core/src/commonMain/kotlin/network/protocol/packet/login/StatSvc.kt

@@ -27,9 +27,12 @@ import net.mamoe.mirai.internal.contact.appId
 import net.mamoe.mirai.internal.contact.createOtherClient
 import net.mamoe.mirai.internal.contact.createOtherClient
 import net.mamoe.mirai.internal.message.contextualBugReportException
 import net.mamoe.mirai.internal.message.contextualBugReportException
 import net.mamoe.mirai.internal.network.*
 import net.mamoe.mirai.internal.network.*
+import net.mamoe.mirai.internal.network.components.ClockHolder
 import net.mamoe.mirai.internal.network.components.ContactCacheService
 import net.mamoe.mirai.internal.network.components.ContactCacheService
 import net.mamoe.mirai.internal.network.components.ContactUpdater
 import net.mamoe.mirai.internal.network.components.ContactUpdater
 import net.mamoe.mirai.internal.network.components.ServerList
 import net.mamoe.mirai.internal.network.components.ServerList
+import net.mamoe.mirai.internal.network.getRandomByteArray
+import net.mamoe.mirai.internal.network.handler.logger
 import net.mamoe.mirai.internal.network.handler.selector.NetworkException
 import net.mamoe.mirai.internal.network.handler.selector.NetworkException
 import net.mamoe.mirai.internal.network.impl.netty.HeartbeatFailedException
 import net.mamoe.mirai.internal.network.impl.netty.HeartbeatFailedException
 import net.mamoe.mirai.internal.network.protocol.data.jce.*
 import net.mamoe.mirai.internal.network.protocol.data.jce.*
@@ -41,10 +44,7 @@ import net.mamoe.mirai.internal.utils.NetworkType
 import net.mamoe.mirai.internal.utils._miraiContentToString
 import net.mamoe.mirai.internal.utils._miraiContentToString
 import net.mamoe.mirai.internal.utils.io.serialization.*
 import net.mamoe.mirai.internal.utils.io.serialization.*
 import net.mamoe.mirai.internal.utils.toIpV4Long
 import net.mamoe.mirai.internal.utils.toIpV4Long
-import net.mamoe.mirai.utils.BotConfiguration
-import net.mamoe.mirai.utils.currentTimeMillis
-import net.mamoe.mirai.utils.encodeToString
-import net.mamoe.mirai.utils.toReadPacket
+import net.mamoe.mirai.utils.*
 
 
 @Suppress("EnumEntryName", "unused")
 @Suppress("EnumEntryName", "unused")
 internal enum class RegPushReason {
 internal enum class RegPushReason {
@@ -150,11 +150,17 @@ internal class StatSvc {
 
 
         override suspend fun ByteReadPacket.decode(bot: QQAndroidBot): Response {
         override suspend fun ByteReadPacket.decode(bot: QQAndroidBot): Response {
             val packet = readUniPacket(SvcRespRegister.serializer())
             val packet = readUniPacket(SvcRespRegister.serializer())
-            packet.iHelloInterval.let {
+            return Response(packet)
+        }
+
+        override suspend fun QQAndroidBot.handle(packet: Response) {
+            packet.origin.iHelloInterval.let {
                 bot.configuration.statHeartbeatPeriodMillis = it.times(1000).toLong()
                 bot.configuration.statHeartbeatPeriodMillis = it.times(1000).toLong()
             }
             }
 
 
-            return Response(packet)
+            val diffMillis = packet.origin.serverTime - currentTimeMillis()
+            bot.components[ClockHolder].server = Clock.SystemDefault.adjusted(diffMillis)
+            bot.network.logger.info { "Server time updated, diff: ${diffMillis}ms=${diffMillis.millisToHumanReadableString()}" }
         }
         }
 
 
         fun online(
         fun online(