2
0
Эх сурвалжийг харах

Add Time utils; Remove klock

Him188 6 жил өмнө
parent
commit
03ca3b5fd1

+ 0 - 2
mirai-core/build.gradle.kts

@@ -72,8 +72,6 @@ kotlin {
                 api(kotlinx("coroutines-core-common", coroutinesVersion))
                 api(kotlinx("serialization-runtime-common", serializationVersion))
 
-                api("com.soywiz.korlibs.klock:klock:$klockVersion")
-
                 api(ktor("http-cio", ktorVersion))
                 api(ktor("http", ktorVersion))
                 api(ktor("client-core-jvm", ktorVersion))

+ 1 - 1
mirai-core/src/commonMain/kotlin/net.mamoe.mirai/Bot.kt

@@ -114,7 +114,7 @@ class Bot(val account: BotAccount, val logger: MiraiLogger, context: CoroutineCo
                 logger.info("Reconnected successfully")
                 return@launch
             } else {
-                delay(configuration.reconnectPeriod.millisecondsLong)
+                delay(configuration.reconnectPeriodMillis)
             }
         }
     }

+ 5 - 13
mirai-core/src/commonMain/kotlin/net.mamoe.mirai/contact/Member.kt

@@ -2,8 +2,7 @@
 
 package net.mamoe.mirai.contact
 
-import com.soywiz.klock.MonthSpan
-import com.soywiz.klock.TimeSpan
+import net.mamoe.mirai.utils.*
 import kotlin.time.Duration
 import kotlin.time.ExperimentalTime
 
@@ -26,6 +25,10 @@ interface Member : QQ, Contact {
      *
      * @param durationSeconds 持续时间. 精确到秒. 范围区间表示为 `(0s, 30days]`. 超过范围则会抛出异常.
      * @return 若机器人无权限禁言这个群成员, 返回 `false`
+     *
+     * @see Int.minutesToSeconds
+     * @see Int.hoursToSeconds
+     * @see Int.daysToSeconds
      */
     suspend fun mute(durationSeconds: Int): Boolean
 
@@ -42,17 +45,6 @@ suspend inline fun Member.mute(duration: Duration): Boolean {
     return this.mute(duration.inSeconds.toInt())
 }
 
-suspend inline fun Member.mute(duration: TimeSpan): Boolean {
-    require(duration.days <= 30) { "duration must be at most 1 month" }
-    require(duration.microseconds > 0) { "duration must be greater than 0 second" }
-    return this.mute(duration.seconds.toInt())
-}
-
-suspend inline fun Member.mute(duration: MonthSpan): Boolean {
-    require(duration.totalMonths == 1) { "if you pass a MonthSpan, it must be 1 month" }
-    return this.mute(duration.totalMonths * 30 * 24 * 3600)
-}
-
 @ExperimentalUnsignedTypes
 suspend inline fun Member.mute(durationSeconds: UInt): Boolean {
     require(durationSeconds.toInt() <= 30 * 24 * 3600) { "duration must be at most 1 month" }

+ 2 - 2
mirai-core/src/commonMain/kotlin/net.mamoe.mirai/contact/data/Profile.kt

@@ -2,7 +2,7 @@
 
 package net.mamoe.mirai.contact.data
 
-import com.soywiz.klock.Date
+import io.ktor.util.date.GMTDate
 
 /**
  * 个人资料
@@ -17,7 +17,7 @@ data class Profile(
     val zipCode: String?,
     val phone: String?,
     val gender: Gender,
-    val birthday: Date?,
+    val birthday: GMTDate?,
     val personalStatement: String?,// 个人说明
     val school: String?,
     val homepage: String?,

+ 41 - 51
mirai-core/src/commonMain/kotlin/net.mamoe.mirai/network/BotSession.kt

@@ -2,8 +2,6 @@
 
 package net.mamoe.mirai.network
 
-import com.soywiz.klock.TimeSpan
-import com.soywiz.klock.seconds
 import kotlinx.coroutines.*
 import kotlinx.io.core.ByteReadPacket
 import net.mamoe.mirai.*
@@ -26,16 +24,14 @@ import net.mamoe.mirai.utils.assertUnreachable
 import net.mamoe.mirai.utils.getGTK
 import net.mamoe.mirai.utils.internal.PositiveNumbers
 import net.mamoe.mirai.utils.internal.coerceAtLeastOrFail
+import net.mamoe.mirai.utils.secondsToMillis
 import kotlin.coroutines.coroutineContext
 
 /**
  * 构造 [BotSession] 的捷径
  */
 @Suppress("FunctionName", "NOTHING_TO_INLINE")
-internal inline fun TIMBotNetworkHandler.BotSession(
-    sessionKey: SessionKey,
-    socket: DataPacketSocketAdapter
-): BotSession = BotSession(bot, sessionKey, socket, this)
+internal inline fun TIMBotNetworkHandler.BotSession(): BotSession = BotSession(bot)
 
 /**
  * 登录会话. 当登录完成后, 客户端会拿到 sessionKey.
@@ -47,10 +43,7 @@ internal inline fun TIMBotNetworkHandler.BotSession(
  */
 @UseExperimental(MiraiInternalAPI::class)
 expect class BotSession internal constructor(
-    bot: Bot,
-    sessionKey: SessionKey,
-    socket: DataPacketSocketAdapter,
-    NetworkScope: CoroutineScope
+    bot: Bot
 ) : BotSessionBase
 
 /**
@@ -59,11 +52,12 @@ expect class BotSession internal constructor(
 @MiraiInternalAPI
 // cannot be internal because of `public BotSession`
 abstract class BotSessionBase internal constructor(
-    val bot: Bot,
-    internal val sessionKey: SessionKey,
-    val socket: DataPacketSocketAdapter,
-    val NetworkScope: CoroutineScope
+    val bot: Bot
 ) {
+    internal val sessionKey: SessionKey get() = bot.sessionKey
+    val socket: DataPacketSocketAdapter get() = bot.network.socket
+    val NetworkScope: CoroutineScope get() = bot.network
+
     /**
      * Web api 使用
      */
@@ -79,6 +73,29 @@ abstract class BotSessionBase internal constructor(
      */
     val gtk: Int get() = _gtk
 
+    suspend inline fun Int.qq(): QQ = bot.getQQ(this.coerceAtLeastOrFail(0).toUInt())
+    suspend inline fun Long.qq(): QQ = bot.getQQ(this.coerceAtLeastOrFail(0))
+    suspend inline fun UInt.qq(): QQ = bot.getQQ(this)
+
+    suspend inline fun Int.group(): Group = bot.getGroup(this.coerceAtLeastOrFail(0).toUInt())
+    suspend inline fun Long.group(): Group = bot.getGroup(this.coerceAtLeastOrFail(0))
+    suspend inline fun UInt.group(): Group = bot.getGroup(GroupId(this))
+    suspend inline fun GroupId.group(): Group = bot.getGroup(this)
+    suspend inline fun GroupInternalId.group(): Group = bot.getGroup(this)
+
+    suspend fun Image.getLink(): ImageLink = when (this.id) {
+        is ImageId0x06 -> FriendImagePacket.RequestImageLink(bot.qqAccount, bot.sessionKey, id).sendAndExpect<FriendImageLink>()
+        is ImageId0x03 -> GroupImagePacket.RequestImageLink(bot.qqAccount, bot.sessionKey, id).sendAndExpect<GroupImageLink>().requireSuccess()
+        else -> assertUnreachable()
+    }
+
+    suspend inline fun Image.downloadAsByteArray(): ByteArray = getLink().downloadAsByteArray()
+    suspend inline fun Image.download(): ByteReadPacket = getLink().download()
+
+
+
+
+    // region internal
 
     @Suppress("PropertyName")
     internal var _sKey: String = ""
@@ -115,12 +132,11 @@ abstract class BotSessionBase internal constructor(
         noinline handler: suspend (P) -> R
     ): Deferred<R> {
         val deferred: CompletableDeferred<R> = CompletableDeferred(coroutineContext[Job])
-        (bot.network as TIMBotNetworkHandler).addHandler(TemporaryPacketHandler(
-            P::class, deferred, this@BotSessionBase as BotSession, checkSequence, coroutineContext + deferred
-        ).also {
-            it.toSend(this)
-            it.onExpect(handler)
-        })
+        (bot.network as TIMBotNetworkHandler)
+            .addHandler(TemporaryPacketHandler(P::class, deferred, this@BotSessionBase as BotSession, checkSequence, coroutineContext + deferred).also {
+                it.toSend(this)
+                it.onExpect(handler)
+            })
         return deferred
     }
 
@@ -129,45 +145,19 @@ abstract class BotSessionBase internal constructor(
 
     internal suspend inline fun <reified P : Packet, R> OutgoingPacket.sendAndExpect(
         checkSequence: Boolean = true,
-        timeout: TimeSpan = 5.seconds,
+        timeoutMillis: Long = 5.secondsToMillis,
         crossinline mapper: (P) -> R
-    ): R = withTimeout(timeout.millisecondsLong) { sendAndExpectAsync<P, R>(checkSequence) { mapper(it) }.await() }
+    ): R = withTimeout(timeoutMillis) { sendAndExpectAsync<P, R>(checkSequence) { mapper(it) }.await() }
 
     internal suspend inline fun <reified P : Packet> OutgoingPacket.sendAndExpect(
         checkSequence: Boolean = true,
-        timeout: TimeSpan = 5.seconds
-    ): P = withTimeout(timeout.millisecondsLong) { sendAndExpectAsync<P, P>(checkSequence) { it }.await() }
+        timeoutMillist: Long = 5.secondsToMillis
+    ): P = withTimeout(timeoutMillist) { sendAndExpectAsync<P, P>(checkSequence) { it }.await() }
 
     internal suspend inline fun OutgoingPacket.send() =
         (socket as TIMBotNetworkHandler.BotSocketAdapter).sendPacket(this)
 
-
-    suspend inline fun Int.qq(): QQ = bot.getQQ(this.coerceAtLeastOrFail(0).toUInt())
-    suspend inline fun Long.qq(): QQ = bot.getQQ(this.coerceAtLeastOrFail(0))
-    suspend inline fun UInt.qq(): QQ = bot.getQQ(this)
-
-    suspend inline fun Int.group(): Group = bot.getGroup(this.coerceAtLeastOrFail(0).toUInt())
-    suspend inline fun Long.group(): Group = bot.getGroup(this.coerceAtLeastOrFail(0))
-    suspend inline fun UInt.group(): Group = bot.getGroup(GroupId(this))
-    suspend inline fun GroupId.group(): Group = bot.getGroup(this)
-    suspend inline fun GroupInternalId.group(): Group = bot.getGroup(this)
-
-    suspend fun Image.getLink(): ImageLink = when (this.id) {
-        is ImageId0x06 -> FriendImagePacket.RequestImageLink(
-            bot.qqAccount,
-            bot.sessionKey,
-            id
-        ).sendAndExpect<FriendImageLink>()
-        is ImageId0x03 -> GroupImagePacket.RequestImageLink(
-            bot.qqAccount,
-            bot.sessionKey,
-            id
-        ).sendAndExpect<GroupImageLink>().requireSuccess()
-        else -> assertUnreachable()
-    }
-
-    suspend inline fun Image.downloadAsByteArray(): ByteArray = getLink().downloadAsByteArray()
-    suspend inline fun Image.download(): ByteReadPacket = getLink().download()
+    // endregion
 }
 
 

+ 6 - 7
mirai-core/src/commonMain/kotlin/net.mamoe.mirai/network/protocol/tim/TIMBotNetworkHandler.kt

@@ -20,7 +20,6 @@ import net.mamoe.mirai.network.protocol.tim.handler.TemporaryPacketHandler
 import net.mamoe.mirai.network.protocol.tim.packet.*
 import net.mamoe.mirai.network.protocol.tim.packet.login.*
 import net.mamoe.mirai.qqAccount
-import net.mamoe.mirai.utils.MiraiInternalAPI
 import net.mamoe.mirai.utils.OnlineStatus
 import net.mamoe.mirai.utils.currentBotConfiguration
 import net.mamoe.mirai.utils.io.*
@@ -197,7 +196,7 @@ internal class TIMBotNetworkHandler internal constructor(coroutineContext: Corou
             val expect = expectPacket<TouchPacket.TouchResponse>()
             launch { processReceive() }
             launch {
-                if (withTimeoutOrNull(currentBotConfiguration().touchTimeout.millisecondsLong) { expect.join() } == null) {
+                if (withTimeoutOrNull(currentBotConfiguration().touchTimeoutMillis) { expect.join() } == null) {
                     loginResult.complete(LoginResult.TIMEOUT)
                 }
             }
@@ -274,7 +273,7 @@ internal class TIMBotNetworkHandler internal constructor(coroutineContext: Corou
                         bot.logger.error("Caught SendPacketInternalException: ${e.cause?.message}")
                     }
                     val configuration = currentBotConfiguration()
-                    delay(configuration.firstReconnectDelay.millisecondsLong)
+                    delay(configuration.firstReconnectDelayMillis)
                     bot.tryReinitializeNetworkHandler(configuration, e)
                     return@withContext
                 } finally {
@@ -475,22 +474,22 @@ internal class TIMBotNetworkHandler internal constructor(coroutineContext: Corou
                     BotLoginSucceedEvent(bot).broadcast()
 
 
-                    session = BotSession(sessionKey, socket)
+                    session = BotSession()
 
                     val configuration = currentBotConfiguration()
                     heartbeatJob = [email protected] {
                         while (socket.isOpen) {
-                            delay(configuration.heartbeatPeriod.millisecondsLong)
+                            delay(configuration.heartbeatPeriodMillis)
                             with(session) {
                                 class HeartbeatTimeoutException : CancellationException("heartbeat timeout")
 
-                                if (withTimeoutOrNull(configuration.heartbeatTimeout.millisecondsLong) {
+                                if (withTimeoutOrNull(configuration.heartbeatTimeoutMillis) {
                                         // FIXME: 2019/11/26 启动被挤掉线检测
 
                                         HeartbeatPacket(bot.qqAccount, sessionKey).sendAndExpect<HeartbeatPacketResponse>()
                                     } == null) {
                                     bot.logger.warning("Heartbeat timed out")
-                                    delay(configuration.firstReconnectDelay.millisecondsLong)
+                                    delay(configuration.firstReconnectDelayMillis)
                                     bot.tryReinitializeNetworkHandler(configuration, HeartbeatTimeoutException())
                                     return@launch
                                 }

+ 2 - 2
mirai-core/src/commonMain/kotlin/net.mamoe.mirai/network/protocol/tim/packet/action/Profile.kt

@@ -2,7 +2,7 @@
 
 package net.mamoe.mirai.network.protocol.tim.packet.action
 
-import com.soywiz.klock.Date
+import io.ktor.util.date.GMTDate
 import kotlinx.io.core.*
 import net.mamoe.mirai.contact.data.Gender
 import net.mamoe.mirai.contact.data.Profile
@@ -77,7 +77,7 @@ internal object RequestProfileDetailsPacket : SessionPacketFactory<RequestProfil
                 else -> Gender.SECRET // 猜的
                 //else -> error("Cannot determine gender, bad value of 0x4E29u: ${map[0x4729u]!![0].toUHexString()}")
             },
-            birthday = map[0x4E3Fu]?.let { Date(it.toUInt().toInt()) },
+            birthday = map[0x4E3Fu]?.let { GMTDate(it.toUInt().toLong()) },
             personalStatement = map[0x4E33u]?.encodeToString(),
             homepage = map[0x4E2Du]?.encodeToString(),
             company = map[0x5DC8u]?.encodeToString(),

+ 7 - 12
mirai-core/src/commonMain/kotlin/net.mamoe.mirai/network/protocol/tim/packet/event/MemberMute.kt

@@ -2,9 +2,6 @@
 
 package net.mamoe.mirai.network.protocol.tim.packet.event
 
-import com.soywiz.klock.TimeSpan
-import com.soywiz.klock.seconds
-import com.soywiz.klock.toTimeString
 import kotlinx.io.core.ByteReadPacket
 import kotlinx.io.core.discardExact
 import kotlinx.io.core.readUInt
@@ -21,28 +18,28 @@ import net.mamoe.mirai.qqAccount
 @Suppress("unused", "MemberVisibilityCanBePrivate")
 class MemberMuteEvent(
     val member: Member,
-    override val duration: TimeSpan,
+    override val durationSeconds: Int,
     override val operator: Member
 ) : MuteEvent() {
     override val group: Group get() = operator.group
-    override fun toString(): String = "MemberMuteEvent(member=${member.id}, group=${group.id}, operator=${operator.id}, duration=${duration.toTimeString()}"
+    override fun toString(): String = "MemberMuteEvent(member=${member.id}, group=${group.id}, operator=${operator.id}, duration=${durationSeconds}s"
 }
 
 /**
  * 机器人被禁言事件
  */
 class BeingMutedEvent(
-    override val duration: TimeSpan,
+    override val durationSeconds: Int,
     override val operator: Member
 ) : MuteEvent() {
     override val group: Group get() = operator.group
-    override fun toString(): String = "BeingMutedEvent(group=${group.id}, operator=${operator.id}, duration=${duration.toTimeString()}"
+    override fun toString(): String = "BeingMutedEvent(group=${group.id}, operator=${operator.id}, duration=${durationSeconds}s"
 }
 
 sealed class MuteEvent : EventOfMute() {
     abstract override val operator: Member
     abstract override val group: Group
-    abstract val duration: TimeSpan
+    abstract val durationSeconds: Int
 }
 // endregion
 
@@ -124,12 +121,10 @@ internal object MemberMuteEventPacketParserAndHandler : KnownEventParserAndHandl
                 MemberUnmuteEvent(group.getMember(memberQQ), operator)
             }
         } else {
-            val duration = durationSeconds.seconds
-
             if (memberQQ == bot.qqAccount) {
-                BeingMutedEvent(duration, operator)
+                BeingMutedEvent(durationSeconds, operator)
             } else {
-                MemberMuteEvent(group.getMember(memberQQ), duration, operator)
+                MemberMuteEvent(group.getMember(memberQQ), durationSeconds, operator)
             }
         }
     }

+ 5 - 7
mirai-core/src/commonMain/kotlin/net.mamoe.mirai/utils/BotConfiguration.kt

@@ -1,7 +1,5 @@
 package net.mamoe.mirai.utils
 
-import com.soywiz.klock.TimeSpan
-import com.soywiz.klock.seconds
 import kotlinx.io.core.IoBuffer
 import net.mamoe.mirai.Bot
 import net.mamoe.mirai.network.protocol.tim.packet.login.TouchPacket.TouchResponse
@@ -28,7 +26,7 @@ class BotConfiguration : CoroutineContext.Element {
     /**
      * 等待 [TouchResponse] 的时间
      */
-    var touchTimeout: TimeSpan = 2.seconds
+    var touchTimeoutMillis: Long = 2.secondsToMillis
     /**
      * 是否使用随机的设备名.
      * 使用随机可以降低被封禁的风险, 但可能导致每次登录都需要输入验证码
@@ -38,20 +36,20 @@ class BotConfiguration : CoroutineContext.Element {
     /**
      * 心跳周期. 过长会导致被服务器断开连接.
      */
-    var heartbeatPeriod: TimeSpan = 60.seconds
+    var heartbeatPeriodMillis: Long = 60.secondsToMillis
     /**
      * 每次心跳时等待结果的时间.
      * 一旦心跳超时, 整个网络服务将会重启 (将消耗约 1s). 除正在进行的任务 (如图片上传) 会被中断外, 事件和插件均不受影响.
      */
-    var heartbeatTimeout: TimeSpan = 2.seconds
+    var heartbeatTimeoutMillis: Long = 2.secondsToMillis
     /**
      * 心跳失败后的第一次重连前的等待时间.
      */
-    var firstReconnectDelay: TimeSpan = 5.seconds
+    var firstReconnectDelayMillis: Long = 5.secondsToMillis
     /**
      * 重连失败后, 继续尝试的每次等待时间
      */
-    var reconnectPeriod: TimeSpan = 60.seconds
+    var reconnectPeriodMillis: Long = 60.secondsToMillis
     /**
      * 最多尝试多少次重连
      */

+ 2 - 2
mirai-core/src/commonMain/kotlin/net.mamoe.mirai/utils/PlatformUtils.kt

@@ -2,13 +2,13 @@
 
 package net.mamoe.mirai.utils
 
-import com.soywiz.klock.DateTime
 import io.ktor.client.HttpClient
+import io.ktor.util.date.GMTDate
 
 /**
  * 时间戳
  */
-inline val currentTime: Long get() = DateTime.nowUnixLong()
+inline val currentTime: Long get() = GMTDate().timestamp
 
 /**
  * 设备名

+ 33 - 0
mirai-core/src/commonMain/kotlin/net.mamoe.mirai/utils/Time.kt

@@ -0,0 +1,33 @@
+package net.mamoe.mirai.utils
+
+import kotlin.time.seconds
+
+// 临时使用, 待 Kotlin Duration 稳定后使用 Duration.
+// 内联属性, 则将来删除这些 API 将不会导致二进制不兼容.
+
+
+inline val Int.secondsToMillis: Long get() = this * 1000L
+
+inline val Int.minutesToMillis: Long get() = this * 60.secondsToMillis
+
+inline val Int.hoursToMillis: Long get() = this * 60.minutesToMillis
+
+inline val Int.daysToMillis: Long get() = this * 24.hoursToMillis
+
+inline val Int.weeksToMillis: Long get() = this * 7.daysToMillis
+
+inline val Int.monthsToMillis: Long get() = this * 30.daysToMillis
+
+
+
+inline val Int.millisToSeconds: Long get() = (this / 1000).toLong()
+
+inline val Int.minutesToSeconds: Long get() = (this * 60).toLong()
+
+inline val Int.hoursToSeconds: Long get() = this * 60.minutesToSeconds
+
+inline val Int.daysToSeconds: Long get() = this * 24.hoursToSeconds
+
+inline val Int.weeksToSeconds: Long get() = this * 7.daysToSeconds
+
+inline val Int.monthsToSeconds: Long get() = this * 30.daysToSeconds

+ 2 - 5
mirai-core/src/jvmMain/kotlin/net/mamoe/mirai/network/BotSessionJvm.kt

@@ -24,11 +24,8 @@ import javax.imageio.ImageIO
 @UseExperimental(MiraiInternalAPI::class)
 @Suppress("unused")
 actual class BotSession internal actual constructor(
-    bot: Bot,
-    sessionKey: SessionKey,
-    socket: DataPacketSocketAdapter,
-    NetworkScope: CoroutineScope
-) : BotSessionBase(bot, sessionKey, socket, NetworkScope) {
+    bot: Bot
+) : BotSessionBase(bot) {
 
     suspend inline fun Image.downloadAsStream(): InputStream = download().inputStream()
     suspend inline fun Image.downloadAsBufferedImage(): BufferedImage = withContext(IO) { downloadAsStream().use { ImageIO.read(it) } }

+ 2 - 5
mirai-demos/mirai-demo-gentleman/src/main/kotlin/demo/gentleman/Main.kt

@@ -2,8 +2,6 @@
 
 package demo.gentleman
 
-import com.soywiz.klock.months
-import com.soywiz.klock.seconds
 import kotlinx.coroutines.Dispatchers.IO
 import kotlinx.coroutines.GlobalScope
 import kotlinx.coroutines.delay
@@ -14,7 +12,6 @@ import net.mamoe.mirai.BotAccount
 import net.mamoe.mirai.addFriend
 import net.mamoe.mirai.alsoLogin
 import net.mamoe.mirai.contact.MemberPermission
-import net.mamoe.mirai.contact.mute
 import net.mamoe.mirai.event.Subscribable
 import net.mamoe.mirai.event.subscribeAlways
 import net.mamoe.mirai.event.subscribeGroupMessages
@@ -70,12 +67,12 @@ suspend fun main() {
 
         startsWith("mt2months") {
             val at: At by message
-            at.member().mute(1.months)
+            at.member().mute(1)
         }
 
         startsWith("mute") {
             val at: At by message
-            at.member().mute(30.seconds)
+            at.member().mute(30)
         }
 
         startsWith("unmute") {