diff --git a/mirai-core-api/build.gradle.kts b/mirai-core-api/build.gradle.kts index 02a5ff45f..a8204f408 100644 --- a/mirai-core-api/build.gradle.kts +++ b/mirai-core-api/build.gradle.kts @@ -75,8 +75,8 @@ kotlin { api1(`kotlinx-serialization-core`) api1(`kotlinx-serialization-json`) implementation1(`kotlinx-serialization-protobuf`) - api1(`kotlinx-io`) - api1(`kotlinx-coroutines-io`) + api1(`kotlinx-io-jvm`) + api1(`kotlinx-coroutines-io-jvm`) api(`kotlinx-coroutines-core`) implementation1(`kotlinx-atomicfu`) @@ -84,32 +84,21 @@ kotlin { api1(`ktor-client-cio`) api1(`ktor-client-core`) api1(`ktor-network`) + + compileOnly(`log4j-api`) + compileOnly(slf4j) } } if (isAndroidSDKAvailable) { androidMain { dependencies { - api(kotlin("reflect")) - - api1(`kotlinx-io-jvm`) - api1(`kotlinx-coroutines-io-jvm`) - api1(`ktor-client-android`) } } } - val jvmMain by getting { - dependencies { - api(kotlin("reflect")) - compileOnly(`log4j-api`) - compileOnly(slf4j) - - api1(`kotlinx-io-jvm`) - api1(`kotlinx-coroutines-io-jvm`) - } - } + val jvmMain by getting val jvmTest by getting { dependencies { diff --git a/mirai-core-api/src/jvmMain/kotlin/event/JvmMethodListeners.kt b/mirai-core-api/src/commonMain/kotlin/event/JvmMethodListeners.kt similarity index 100% rename from mirai-core-api/src/jvmMain/kotlin/event/JvmMethodListeners.kt rename to mirai-core-api/src/commonMain/kotlin/event/JvmMethodListeners.kt diff --git a/mirai-core-api/src/commonMain/kotlin/event/events/friend.kt b/mirai-core-api/src/commonMain/kotlin/event/events/friend.kt index 10eadb60d..bdc2fbde5 100644 --- a/mirai-core-api/src/commonMain/kotlin/event/events/friend.kt +++ b/mirai-core-api/src/commonMain/kotlin/event/events/friend.kt @@ -20,13 +20,12 @@ import net.mamoe.mirai.contact.Friend import net.mamoe.mirai.contact.Group import net.mamoe.mirai.contact.User import net.mamoe.mirai.event.AbstractEvent -import net.mamoe.mirai.event.internal.MiraiAtomicBoolean import net.mamoe.mirai.internal.network.Packet import net.mamoe.mirai.message.action.Nudge import net.mamoe.mirai.utils.MiraiExperimentalApi import net.mamoe.mirai.utils.SinceMirai import net.mamoe.mirai.utils.internal.runBlocking -import kotlin.jvm.* +import java.util.concurrent.atomic.AtomicBoolean /** @@ -90,7 +89,7 @@ public data class NewFriendRequestEvent internal constructor( public val fromNick: String ) : BotEvent, Packet, AbstractEvent() { @JvmField - internal val responded: MiraiAtomicBoolean = MiraiAtomicBoolean(false) + internal val responded: AtomicBoolean = AtomicBoolean(false) /** * @return 申请人来自的群. 当申请人来自其他途径申请时为 `null` diff --git a/mirai-core-api/src/commonMain/kotlin/event/events/group.kt b/mirai-core-api/src/commonMain/kotlin/event/events/group.kt index cd4437920..7aca731b8 100644 --- a/mirai-core-api/src/commonMain/kotlin/event/events/group.kt +++ b/mirai-core-api/src/commonMain/kotlin/event/events/group.kt @@ -22,12 +22,12 @@ import net.mamoe.mirai.contact.Member import net.mamoe.mirai.contact.MemberPermission import net.mamoe.mirai.event.AbstractEvent import net.mamoe.mirai.event.BroadcastControllable -import net.mamoe.mirai.event.internal.MiraiAtomicBoolean import net.mamoe.mirai.internal.network.Packet import net.mamoe.mirai.message.action.Nudge import net.mamoe.mirai.utils.MiraiExperimentalApi import net.mamoe.mirai.utils.SinceMirai import net.mamoe.mirai.utils.internal.runBlocking +import java.util.concurrent.atomic.AtomicBoolean import kotlin.internal.LowPriorityInOverloadResolution import kotlin.jvm.* @@ -339,7 +339,7 @@ public data class BotInvitedJoinGroupRequestEvent internal constructor( public val invitor: Friend get() = this.bot.getFriend(invitorId) @JvmField - internal val responded: MiraiAtomicBoolean = MiraiAtomicBoolean(false) + internal val responded: AtomicBoolean = AtomicBoolean(false) @JvmSynthetic public suspend fun accept(): Unit = Mirai.acceptInvitedJoinGroupRequest(this) @@ -387,7 +387,7 @@ public data class MemberJoinRequestEvent internal constructor( @JvmField @PublishedApi - internal val responded: MiraiAtomicBoolean = MiraiAtomicBoolean(false) + internal val responded: AtomicBoolean = AtomicBoolean(false) @JvmSynthetic public suspend fun accept(): Unit = Mirai.acceptMemberJoinRequest(this) diff --git a/mirai-core-api/src/commonMain/kotlin/event/internal/InternalEventListeners.kt b/mirai-core-api/src/commonMain/kotlin/event/internal/InternalEventListeners.kt index 4a10e94c9..2f8d07aad 100644 --- a/mirai-core-api/src/commonMain/kotlin/event/internal/InternalEventListeners.kt +++ b/mirai-core-api/src/commonMain/kotlin/event/internal/InternalEventListeners.kt @@ -17,9 +17,9 @@ import net.mamoe.mirai.event.events.BotEvent import net.mamoe.mirai.utils.LockFreeLinkedList import net.mamoe.mirai.utils.MiraiLogger import net.mamoe.mirai.utils.PlannedRemoval +import java.util.* import kotlin.coroutines.CoroutineContext import kotlin.coroutines.coroutineContext -import kotlin.jvm.JvmField import kotlin.reflect.KClass @@ -112,16 +112,21 @@ internal class ListenerRegistry( val type: KClass ) -internal expect object GlobalEventListeners { - operator fun get(priority: Listener.EventPriority): LockFreeLinkedList -} -@PublishedApi -internal expect class MiraiAtomicBoolean(initial: Boolean) { +internal object GlobalEventListeners { + private val ALL_LEVEL_REGISTRIES: Map> - fun compareAndSet(expect: Boolean, update: Boolean): Boolean + init { + val map = + EnumMap>(Listener.EventPriority::class.java) + Listener.EventPriority.values().forEach { + map[it] = LockFreeLinkedList() + } + this.ALL_LEVEL_REGISTRIES = map + } - var value: Boolean + operator fun get(priority: Listener.EventPriority): LockFreeLinkedList = + ALL_LEVEL_REGISTRIES[priority]!! } diff --git a/mirai-core-api/src/jvmMain/kotlin/event/internal/MiraiAtomicBoolean.kt b/mirai-core-api/src/commonMain/kotlin/event/internal/MiraiAtomicBoolean.kt similarity index 78% rename from mirai-core-api/src/jvmMain/kotlin/event/internal/MiraiAtomicBoolean.kt rename to mirai-core-api/src/commonMain/kotlin/event/internal/MiraiAtomicBoolean.kt index 6244a19ab..6e69ff29d 100644 --- a/mirai-core-api/src/jvmMain/kotlin/event/internal/MiraiAtomicBoolean.kt +++ b/mirai-core-api/src/commonMain/kotlin/event/internal/MiraiAtomicBoolean.kt @@ -11,16 +11,18 @@ package net.mamoe.mirai.event.internal import java.util.concurrent.atomic.AtomicBoolean -internal actual class MiraiAtomicBoolean actual constructor(initial: Boolean) { + +@PublishedApi +internal class MiraiAtomicBoolean constructor(initial: Boolean) { private val delegate: AtomicBoolean = AtomicBoolean(initial) - actual fun compareAndSet(expect: Boolean, update: Boolean): Boolean { + fun compareAndSet(expect: Boolean, update: Boolean): Boolean { return delegate.compareAndSet(expect, update) } - actual var value: Boolean + var value: Boolean get() = delegate.get() set(value) { delegate.set(value) } -} +} \ No newline at end of file diff --git a/mirai-core-api/src/commonMain/kotlin/utils/DeviceInfo.kt b/mirai-core-api/src/commonMain/kotlin/utils/DeviceInfo.kt index 5c54d9427..91a7bf39b 100644 --- a/mirai-core-api/src/commonMain/kotlin/utils/DeviceInfo.kt +++ b/mirai-core-api/src/commonMain/kotlin/utils/DeviceInfo.kt @@ -11,13 +11,26 @@ package net.mamoe.mirai.utils import kotlinx.io.core.toByteArray import kotlinx.serialization.Serializable +import kotlinx.serialization.json.Json import kotlinx.serialization.protobuf.ProtoBuf import kotlinx.serialization.protobuf.ProtoNumber import net.mamoe.mirai.utils.internal.getRandomByteArray import net.mamoe.mirai.utils.internal.getRandomIntString import net.mamoe.mirai.utils.internal.getRandomString import net.mamoe.mirai.utils.internal.md5 -import kotlin.jvm.JvmStatic +import java.io.File + +/** + * 加载一个设备信息. 若文件不存在或为空则随机并创建一个设备信息保存. + */ +public fun File.loadAsDeviceInfo(json: Json): DeviceInfo { + if (!this.exists() || this.length() == 0L) { + return DeviceInfo.random().also { + this.writeText(json.encodeToString(DeviceInfo.serializer(), it)) + } + } + return json.decodeFromString(DeviceInfo.serializer(), this.readText()) +} @Serializable public class DeviceInfo( diff --git a/mirai-core-api/src/jvmMain/kotlin/utils/FileLogger.kt b/mirai-core-api/src/commonMain/kotlin/utils/FileLogger.kt similarity index 95% rename from mirai-core-api/src/jvmMain/kotlin/utils/FileLogger.kt rename to mirai-core-api/src/commonMain/kotlin/utils/FileLogger.kt index 322ebcb3d..e77545366 100644 --- a/mirai-core-api/src/jvmMain/kotlin/utils/FileLogger.kt +++ b/mirai-core-api/src/commonMain/kotlin/utils/FileLogger.kt @@ -25,7 +25,7 @@ public class SingleFileLogger @JvmOverloads constructor( identity: String, file: File = File("$identity-$currentDate.log") ) : - PlatformLogger(identity, { file.appendText(it + "\n") }, false) { + PlatformLogger(identity, { file.appendText(it + "\n") }) { init { file.createNewFile() @@ -55,7 +55,7 @@ public class DirectoryLogger @JvmOverloads constructor( } private fun checkOutdated() { - val current = currentTimeMillis + val current = currentTimeMillis() directory.walk().filter(File::isFile).filter { current - it.lastModified() > retain }.forEach { it.delete() } diff --git a/mirai-core-api/src/jvmMain/kotlin/utils/HyperLinkLabel.kt b/mirai-core-api/src/commonMain/kotlin/utils/HyperLinkLabel.kt similarity index 100% rename from mirai-core-api/src/jvmMain/kotlin/utils/HyperLinkLabel.kt rename to mirai-core-api/src/commonMain/kotlin/utils/HyperLinkLabel.kt diff --git a/mirai-core-api/src/jvmMain/kotlin/utils/LoggerAdapters.kt b/mirai-core-api/src/commonMain/kotlin/utils/LoggerAdapters.kt similarity index 100% rename from mirai-core-api/src/jvmMain/kotlin/utils/LoggerAdapters.kt rename to mirai-core-api/src/commonMain/kotlin/utils/LoggerAdapters.kt diff --git a/mirai-core-api/src/commonMain/kotlin/utils/LoginSolver.kt b/mirai-core-api/src/commonMain/kotlin/utils/LoginSolver.kt index 60a763a72..0bb40c24b 100644 --- a/mirai-core-api/src/commonMain/kotlin/utils/LoginSolver.kt +++ b/mirai-core-api/src/commonMain/kotlin/utils/LoginSolver.kt @@ -9,13 +9,29 @@ package net.mamoe.mirai.utils +import kotlinx.coroutines.CoroutineName +import kotlinx.coroutines.Dispatchers +import kotlinx.coroutines.GlobalScope +import kotlinx.coroutines.io.* +import kotlinx.coroutines.io.jvm.nio.copyTo +import kotlinx.coroutines.sync.Mutex +import kotlinx.coroutines.sync.withLock +import kotlinx.coroutines.withContext import net.mamoe.mirai.Bot import net.mamoe.mirai.network.LoginFailedException +import net.mamoe.mirai.network.NoStandardInputForCaptchaException +import utils.SwingSolver +import java.awt.Image +import java.awt.image.BufferedImage +import java.io.File +import java.io.RandomAccessFile +import javax.imageio.ImageIO +import kotlin.coroutines.CoroutineContext /** * 验证码, 设备锁解决器 */ -public expect abstract class LoginSolver { +public abstract class LoginSolver { /** * 处理图片验证码. * 返回 null 以表示无法处理验证码, 将会刷新验证码或重试登录. @@ -46,6 +62,189 @@ public expect abstract class LoginSolver { public abstract suspend fun onSolveUnsafeDeviceLoginVerify(bot: Bot, url: String): String? public companion object { - public val Default: LoginSolver + public val Default: LoginSolver = + DefaultLoginSolver({ readLine() ?: throw NoStandardInputForCaptchaException(null) }) } -} \ No newline at end of file +} + + +/** + * 自动选择 [SwingSolver] 或 [StandardCharImageLoginSolver] + */ +@MiraiExperimentalApi +public class DefaultLoginSolver( + public val input: suspend () -> String, + public val overrideLogger: MiraiLogger? = null +) : LoginSolver() { + private val delegate: LoginSolver + + init { + if (WindowHelperJvm.isDesktopSupported) { + delegate = SwingSolver + } else { + delegate = StandardCharImageLoginSolver(input, overrideLogger) + } + } + + override suspend fun onSolvePicCaptcha(bot: Bot, data: ByteArray): String? { + return delegate.onSolvePicCaptcha(bot, data) + } + + override suspend fun onSolveSliderCaptcha(bot: Bot, url: String): String? { + return delegate.onSolveSliderCaptcha(bot, url) + } + + override suspend fun onSolveUnsafeDeviceLoginVerify(bot: Bot, url: String): String? { + return delegate.onSolveUnsafeDeviceLoginVerify(bot, url) + } +} + +/** + * 使用字符图片展示验证码, 使用 [input] 获取输入, 使用 [overrideLogger] 输出 + */ +@MiraiExperimentalApi +public class StandardCharImageLoginSolver( + input: suspend () -> String, + /** + * 为 `null` 时使用 [Bot.logger] + */ + private val overrideLogger: MiraiLogger? = null +) : LoginSolver() { + private val input: suspend () -> String = suspend { + withContext(Dispatchers.IO) { input() } + } + + override suspend fun onSolvePicCaptcha(bot: Bot, data: ByteArray): String? = loginSolverLock.withLock { + val logger = overrideLogger ?: bot.logger + val tempFile: File = createTempFile(suffix = ".png").apply { deleteOnExit() } + withContext(Dispatchers.IO) { + tempFile.createNewFile() + logger.info("需要图片验证码登录, 验证码为 4 字母") + try { + tempFile.writeChannel().apply { writeFully(data); close() } + logger.info("将会显示字符图片. 若看不清字符图片, 请查看文件 ${tempFile.absolutePath}") + } catch (e: Exception) { + logger.info("无法写出验证码文件(${e.message}), 请尝试查看以上字符图片") + } + + tempFile.inputStream().use { + try { + val img = ImageIO.read(it) + if (img == null) { + logger.info("无法创建字符图片. 请查看文件") + } else { + logger.info("\n" + img.createCharImg()) + } + } catch (throwable: Throwable) { + logger.info("创建字符图片时出错($throwable)。请查看文件") + } + } + } + logger.info("请输入 4 位字母验证码. 若要更换验证码, 请直接回车") + return input().takeUnless { it.isEmpty() || it.length != 4 }.also { + logger.info("正在提交[$it]中...") + } + } + + override suspend fun onSolveSliderCaptcha(bot: Bot, url: String): String = loginSolverLock.withLock { + val logger = overrideLogger ?: bot.logger + logger.info("需要滑动验证码") + logger.info("请在任意浏览器中打开以下链接并完成验证码. ") + logger.info("完成后请输入任意字符 ") + logger.info(url) + return input().also { + logger.info("正在提交中...") + } + } + + override suspend fun onSolveUnsafeDeviceLoginVerify(bot: Bot, url: String): String? = loginSolverLock.withLock { + val logger = overrideLogger ?: bot.logger + logger.info("需要进行账户安全认证") + logger.info("该账户有[设备锁]/[不常用登录地点]/[不常用设备登录]的问题") + logger.info("完成以下账号认证即可成功登录|理论本认证在mirai每个账户中最多出现1次") + logger.info("请将该链接在QQ浏览器中打开并完成认证, 成功后输入任意字符") + logger.info("这步操作将在后续的版本中优化") + logger.info(url) + return input().also { + logger.info("正在提交中...") + } + } +} + +/////////////////////////////// +//////////////// internal +/////////////////////////////// + +internal fun BotConfiguration.getFileBasedDeviceInfoSupplier(filename: String): (Context) -> DeviceInfo { + return { + File(filename).loadAsDeviceInfo(json) + } +} + +// Copied from Ktor CIO +private fun File.writeChannel( + coroutineContext: CoroutineContext = Dispatchers.IO +): ByteWriteChannel = GlobalScope.reader(CoroutineName("file-writer") + coroutineContext, autoFlush = true) { + @Suppress("BlockingMethodInNonBlockingContext") + RandomAccessFile(this@writeChannel, "rw").use { file -> + val copied = channel.copyTo(file.channel) + file.setLength(copied) // truncate tail that could remain from the previously written data + } +}.channel + +private val loginSolverLock = Mutex() + +/** + * @author NaturalHG + */ +private fun BufferedImage.createCharImg(outputWidth: Int = 100, ignoreRate: Double = 0.95): String { + val newHeight = (this.height * (outputWidth.toDouble() / this.width)).toInt() + val tmp = this.getScaledInstance(outputWidth, newHeight, Image.SCALE_SMOOTH) + val image = BufferedImage(outputWidth, newHeight, BufferedImage.TYPE_INT_ARGB) + val g2d = image.createGraphics() + g2d.drawImage(tmp, 0, 0, null) + fun gray(rgb: Int): Int { + val r = rgb and 0xff0000 shr 16 + val g = rgb and 0x00ff00 shr 8 + val b = rgb and 0x0000ff + return (r * 30 + g * 59 + b * 11 + 50) / 100 + } + + fun grayCompare(g1: Int, g2: Int): Boolean = + kotlin.math.min(g1, g2).toDouble() / kotlin.math.max(g1, g2) >= ignoreRate + + val background = gray(image.getRGB(0, 0)) + + return buildString(capacity = height) { + + val lines = mutableListOf() + + var minXPos = outputWidth + var maxXPos = 0 + + for (y in 0 until image.height) { + val builderLine = StringBuilder() + for (x in 0 until image.width) { + val gray = gray(image.getRGB(x, y)) + if (grayCompare(gray, background)) { + builderLine.append(" ") + } else { + builderLine.append("#") + if (x < minXPos) { + minXPos = x + } + if (x > maxXPos) { + maxXPos = x + } + } + } + if (builderLine.toString().isBlank()) { + continue + } + lines.add(builderLine) + } + for (line in lines) { + append(line.substring(minXPos, maxXPos)).append("\n") + } + } +} diff --git a/mirai-core-api/src/commonMain/kotlin/utils/MiraiLogger.kt b/mirai-core-api/src/commonMain/kotlin/utils/MiraiLogger.kt index 8d85d58f5..10c892448 100644 --- a/mirai-core-api/src/commonMain/kotlin/utils/MiraiLogger.kt +++ b/mirai-core-api/src/commonMain/kotlin/utils/MiraiLogger.kt @@ -14,9 +14,6 @@ package net.mamoe.mirai.utils import net.mamoe.mirai.Bot -import kotlin.jvm.JvmMultifileClass -import kotlin.jvm.JvmName -import kotlin.jvm.JvmOverloads /** @@ -229,7 +226,13 @@ public inline fun MiraiLogger.error(lazyMessage: () -> String?, e: Throwable?) { * * @see DefaultLogger */ -public expect open class PlatformLogger @JvmOverloads constructor(identity: String? = "Mirai") : MiraiLoggerPlatformBase +public expect open class PlatformLogger constructor( + identity: String? = "Mirai", + output: (String) -> Unit, // TODO: 2020/11/30 review logs, currently it's just for compile +) : MiraiLoggerPlatformBase { + @JvmOverloads + public constructor(identity: String? = "Mirai") +} /** diff --git a/mirai-core-api/src/commonMain/kotlin/utils/OverFileSizeMaxException.kt b/mirai-core-api/src/commonMain/kotlin/utils/OverFileSizeMaxException.kt index fb1dc9c81..b7d718cb6 100644 --- a/mirai-core-api/src/commonMain/kotlin/utils/OverFileSizeMaxException.kt +++ b/mirai-core-api/src/commonMain/kotlin/utils/OverFileSizeMaxException.kt @@ -12,10 +12,7 @@ package net.mamoe.mirai.utils -import kotlin.jvm.JvmMultifileClass -import kotlin.jvm.JvmName - /** * 图片文件过大 */ // 不要删除多平台结构, 这是 kotlin 的 bug -public expect class OverFileSizeMaxException() : IllegalStateException \ No newline at end of file +public class OverFileSizeMaxException : IllegalStateException() \ No newline at end of file diff --git a/mirai-core-api/src/jvmMain/kotlin/utils/LoginSolver.swing.jvm.kt b/mirai-core-api/src/commonMain/kotlin/utils/SwingSolver.kt similarity index 91% rename from mirai-core-api/src/jvmMain/kotlin/utils/LoginSolver.swing.jvm.kt rename to mirai-core-api/src/commonMain/kotlin/utils/SwingSolver.kt index 9cfd3dd55..db5c229b3 100644 --- a/mirai-core-api/src/jvmMain/kotlin/utils/LoginSolver.swing.jvm.kt +++ b/mirai-core-api/src/commonMain/kotlin/utils/SwingSolver.kt @@ -7,9 +7,13 @@ * https://github.com/mamoe/mirai/blob/master/LICENSE */ -package net.mamoe.mirai.utils +package utils import net.mamoe.mirai.Bot +import net.mamoe.mirai.utils.HyperLinkLabel +import net.mamoe.mirai.utils.LoginSolver +import net.mamoe.mirai.utils.MiraiExperimentalApi +import net.mamoe.mirai.utils.openWindow import java.awt.Desktop import java.net.URI import javax.imageio.ImageIO diff --git a/mirai-core-api/src/commonMain/kotlin/utils/TimeUtils.kt b/mirai-core-api/src/commonMain/kotlin/utils/TimeUtils.kt index 9feaef1c9..a69ff3119 100644 --- a/mirai-core-api/src/commonMain/kotlin/utils/TimeUtils.kt +++ b/mirai-core-api/src/commonMain/kotlin/utils/TimeUtils.kt @@ -12,9 +12,6 @@ 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 @@ -23,11 +20,11 @@ import kotlin.time.ExperimentalTime /** * 时间戳 */ -public expect val currentTimeMillis: Long +public fun currentTimeMillis(): Long = System.currentTimeMillis() @get:JvmSynthetic public inline val currentTimeSeconds: Long - get() = currentTimeMillis / 1000 + get() = currentTimeMillis() / 1000 // 临时使用, 待 Kotlin Duration 稳定后使用 Duration. diff --git a/mirai-core-api/src/jvmMain/kotlin/utils/WindowHelperJvm.kt b/mirai-core-api/src/commonMain/kotlin/utils/WindowHelperJvm.kt similarity index 100% rename from mirai-core-api/src/jvmMain/kotlin/utils/WindowHelperJvm.kt rename to mirai-core-api/src/commonMain/kotlin/utils/WindowHelperJvm.kt diff --git a/mirai-core-api/src/jvmMain/kotlin/utils/internal/DeferredReusableInput.jvm.kt b/mirai-core-api/src/commonMain/kotlin/utils/internal/DeferredReusableInput.jvm.kt similarity index 100% rename from mirai-core-api/src/jvmMain/kotlin/utils/internal/DeferredReusableInput.jvm.kt rename to mirai-core-api/src/commonMain/kotlin/utils/internal/DeferredReusableInput.jvm.kt diff --git a/mirai-core-api/src/commonMain/kotlin/utils/internal/asReusableInput.common.kt b/mirai-core-api/src/commonMain/kotlin/utils/internal/asReusableInput.common.kt deleted file mode 100644 index 22b3baa8b..000000000 --- a/mirai-core-api/src/commonMain/kotlin/utils/internal/asReusableInput.common.kt +++ /dev/null @@ -1,14 +0,0 @@ -/* - * Copyright 2019-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.internal - -internal expect fun ByteArray.asReusableInput(): ReusableInput - -internal fun asReusableInput0(input: ByteArray): ReusableInput = input.asReusableInput() \ No newline at end of file diff --git a/mirai-core-api/src/jvmMain/kotlin/utils/internal/asReusableInput.jvm.kt b/mirai-core-api/src/commonMain/kotlin/utils/internal/asReusableInput.kt similarity index 96% rename from mirai-core-api/src/jvmMain/kotlin/utils/internal/asReusableInput.jvm.kt rename to mirai-core-api/src/commonMain/kotlin/utils/internal/asReusableInput.kt index 8c064468a..f656cd758 100644 --- a/mirai-core-api/src/jvmMain/kotlin/utils/internal/asReusableInput.jvm.kt +++ b/mirai-core-api/src/commonMain/kotlin/utils/internal/asReusableInput.kt @@ -20,9 +20,11 @@ import java.io.ByteArrayInputStream import java.io.File import java.io.InputStream +internal fun asReusableInput0(input: ByteArray): ReusableInput = input.asReusableInput() + internal const val DEFAULT_REUSABLE_INPUT_BUFFER_SIZE = 8192 -internal actual fun ByteArray.asReusableInput(): ReusableInput { +internal fun ByteArray.asReusableInput(): ReusableInput { return object : ReusableInput { override val md5: ByteArray = md5() override val size: Long get() = this@asReusableInput.size.toLongUnsigned() diff --git a/mirai-core-api/src/jvmMain/kotlin/utils/internal/logging/JdkLogger.kt b/mirai-core-api/src/commonMain/kotlin/utils/internal/logging/JdkLogger.kt similarity index 100% rename from mirai-core-api/src/jvmMain/kotlin/utils/internal/logging/JdkLogger.kt rename to mirai-core-api/src/commonMain/kotlin/utils/internal/logging/JdkLogger.kt diff --git a/mirai-core-api/src/jvmMain/kotlin/utils/internal/logging/Log4jLogger.kt b/mirai-core-api/src/commonMain/kotlin/utils/internal/logging/Log4jLogger.kt similarity index 100% rename from mirai-core-api/src/jvmMain/kotlin/utils/internal/logging/Log4jLogger.kt rename to mirai-core-api/src/commonMain/kotlin/utils/internal/logging/Log4jLogger.kt diff --git a/mirai-core-api/src/jvmMain/kotlin/utils/internal/logging/Slf4jLogger.kt b/mirai-core-api/src/commonMain/kotlin/utils/internal/logging/Slf4jLogger.kt similarity index 100% rename from mirai-core-api/src/jvmMain/kotlin/utils/internal/logging/Slf4jLogger.kt rename to mirai-core-api/src/commonMain/kotlin/utils/internal/logging/Slf4jLogger.kt diff --git a/mirai-core-api/src/jvmMain/kotlin/utils/internal/md5.jvm.kt b/mirai-core-api/src/commonMain/kotlin/utils/internal/md5.jvm.kt similarity index 100% rename from mirai-core-api/src/jvmMain/kotlin/utils/internal/md5.jvm.kt rename to mirai-core-api/src/commonMain/kotlin/utils/internal/md5.jvm.kt diff --git a/mirai-core-api/src/jvmMain/kotlin/utils/internal/runBlocking.kt b/mirai-core-api/src/commonMain/kotlin/utils/internal/runBlocking.kt similarity index 100% rename from mirai-core-api/src/jvmMain/kotlin/utils/internal/runBlocking.kt rename to mirai-core-api/src/commonMain/kotlin/utils/internal/runBlocking.kt diff --git a/mirai-core-api/src/jvmMain/kotlin/event/internal/GlobalEventListeners.kt b/mirai-core-api/src/jvmMain/kotlin/event/internal/GlobalEventListeners.kt deleted file mode 100644 index 295b9c130..000000000 --- a/mirai-core-api/src/jvmMain/kotlin/event/internal/GlobalEventListeners.kt +++ /dev/null @@ -1,32 +0,0 @@ -/* - * Copyright 2019-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.event.internal - -import net.mamoe.mirai.event.Listener -import net.mamoe.mirai.utils.LockFreeLinkedList -import java.util.* - - -internal actual object GlobalEventListeners { - private val ALL_LEVEL_REGISTRIES: Map> - - init { - val map = - EnumMap>(Listener.EventPriority::class.java) - Listener.EventPriority.values().forEach { - map[it] = LockFreeLinkedList() - } - this.ALL_LEVEL_REGISTRIES = map - } - - actual operator fun get(priority: Listener.EventPriority): LockFreeLinkedList = - ALL_LEVEL_REGISTRIES[priority]!! - -} diff --git a/mirai-core-api/src/jvmMain/kotlin/utils/DeviceInfoUtils.kt b/mirai-core-api/src/jvmMain/kotlin/utils/DeviceInfoUtils.kt deleted file mode 100644 index bdc2a166b..000000000 --- a/mirai-core-api/src/jvmMain/kotlin/utils/DeviceInfoUtils.kt +++ /dev/null @@ -1,25 +0,0 @@ -/* - * Copyright 2019-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 kotlinx.serialization.json.Json -import java.io.File - -/** - * 加载一个设备信息. 若文件不存在或为空则随机并创建一个设备信息保存. - */ -public fun File.loadAsDeviceInfo(json: Json): DeviceInfo { - if (!this.exists() || this.length() == 0L) { - return DeviceInfo.random().also { - this.writeText(json.encodeToString(DeviceInfo.serializer(), it)) - } - } - return json.decodeFromString(DeviceInfo.serializer(), this.readText()) -} \ No newline at end of file diff --git a/mirai-core-api/src/jvmMain/kotlin/utils/LoginSolver.jvm.kt b/mirai-core-api/src/jvmMain/kotlin/utils/LoginSolver.jvm.kt deleted file mode 100644 index 4800e0431..000000000 --- a/mirai-core-api/src/jvmMain/kotlin/utils/LoginSolver.jvm.kt +++ /dev/null @@ -1,227 +0,0 @@ -/* - * Copyright 2019-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 kotlinx.coroutines.CoroutineName -import kotlinx.coroutines.Dispatchers -import kotlinx.coroutines.GlobalScope -import kotlinx.coroutines.io.ByteWriteChannel -import kotlinx.coroutines.io.close -import kotlinx.coroutines.io.jvm.nio.copyTo -import kotlinx.coroutines.io.reader -import kotlinx.coroutines.io.writeFully -import kotlinx.coroutines.sync.Mutex -import kotlinx.coroutines.sync.withLock -import kotlinx.coroutines.withContext -import kotlinx.io.core.use -import net.mamoe.mirai.Bot -import net.mamoe.mirai.network.NoStandardInputForCaptchaException -import java.awt.Image -import java.awt.image.BufferedImage -import java.io.File -import java.io.RandomAccessFile -import javax.imageio.ImageIO -import kotlin.coroutines.CoroutineContext - -/** - * 自动选择 [SwingSolver] 或 [StandardCharImageLoginSolver] - */ -@MiraiExperimentalApi -public class DefaultLoginSolver( - public val input: suspend () -> String, - public val overrideLogger: MiraiLogger? = null -) : LoginSolver() { - private val delegate: LoginSolver - - init { - if (WindowHelperJvm.isDesktopSupported) { - delegate = SwingSolver - } else { - delegate = StandardCharImageLoginSolver(input, overrideLogger) - } - } - - override suspend fun onSolvePicCaptcha(bot: Bot, data: ByteArray): String? { - return delegate.onSolvePicCaptcha(bot, data) - } - - override suspend fun onSolveSliderCaptcha(bot: Bot, url: String): String? { - return delegate.onSolveSliderCaptcha(bot, url) - } - - override suspend fun onSolveUnsafeDeviceLoginVerify(bot: Bot, url: String): String? { - return delegate.onSolveUnsafeDeviceLoginVerify(bot, url) - } -} - -/** - * 使用字符图片展示验证码, 使用 [input] 获取输入, 使用 [overrideLogger] 输出 - */ -@MiraiExperimentalApi -public class StandardCharImageLoginSolver( - input: suspend () -> String, - /** - * 为 `null` 时使用 [Bot.logger] - */ - private val overrideLogger: MiraiLogger? = null -) : LoginSolver() { - private val input: suspend () -> String = suspend { - withContext(Dispatchers.IO) { input() } - } - - override suspend fun onSolvePicCaptcha(bot: Bot, data: ByteArray): String? = loginSolverLock.withLock { - val logger = overrideLogger ?: bot.logger - val tempFile: File = createTempFile(suffix = ".png").apply { deleteOnExit() } - withContext(Dispatchers.IO) { - tempFile.createNewFile() - logger.info("需要图片验证码登录, 验证码为 4 字母") - try { - tempFile.writeChannel().apply { writeFully(data); close() } - logger.info("将会显示字符图片. 若看不清字符图片, 请查看文件 ${tempFile.absolutePath}") - } catch (e: Exception) { - logger.info("无法写出验证码文件(${e.message}), 请尝试查看以上字符图片") - } - - tempFile.inputStream().use { - try { - val img = ImageIO.read(it) - if (img == null) { - logger.info("无法创建字符图片. 请查看文件") - } else { - logger.info("\n" + img.createCharImg()) - } - } catch (throwable: Throwable) { - logger.info("创建字符图片时出错($throwable)。请查看文件") - } - } - } - logger.info("请输入 4 位字母验证码. 若要更换验证码, 请直接回车") - return input().takeUnless { it.isEmpty() || it.length != 4 }.also { - logger.info("正在提交[$it]中...") - } - } - - override suspend fun onSolveSliderCaptcha(bot: Bot, url: String): String? = loginSolverLock.withLock { - val logger = overrideLogger ?: bot.logger - logger.info("需要滑动验证码") - logger.info("请在任意浏览器中打开以下链接并完成验证码. ") - logger.info("完成后请输入任意字符 ") - logger.info(url) - return input().also { - logger.info("正在提交中...") - } - } - - override suspend fun onSolveUnsafeDeviceLoginVerify(bot: Bot, url: String): String? = loginSolverLock.withLock { - val logger = overrideLogger ?: bot.logger - logger.info("需要进行账户安全认证") - logger.info("该账户有[设备锁]/[不常用登录地点]/[不常用设备登录]的问题") - logger.info("完成以下账号认证即可成功登录|理论本认证在mirai每个账户中最多出现1次") - logger.info("请将该链接在QQ浏览器中打开并完成认证, 成功后输入任意字符") - logger.info("这步操作将在后续的版本中优化") - logger.info(url) - return input().also { - logger.info("正在提交中...") - } - } -} - -/** - * 验证码, 设备锁解决器 - */ -public actual abstract class LoginSolver { - public actual abstract suspend fun onSolvePicCaptcha(bot: Bot, data: ByteArray): String? - public actual abstract suspend fun onSolveSliderCaptcha(bot: Bot, url: String): String? - public actual abstract suspend fun onSolveUnsafeDeviceLoginVerify(bot: Bot, url: String): String? - - public actual companion object { - public actual val Default: LoginSolver = - - DefaultLoginSolver({ readLine() ?: throw NoStandardInputForCaptchaException(null) }) - } -} - -/////////////////////////////// -//////////////// internal -/////////////////////////////// - -internal fun BotConfiguration.getFileBasedDeviceInfoSupplier(filename: String): ((Context) -> DeviceInfo)? { - return { - File(filename).loadAsDeviceInfo(json) - } -} - -// Copied from Ktor CIO -private fun File.writeChannel( - coroutineContext: CoroutineContext = Dispatchers.IO -): ByteWriteChannel = GlobalScope.reader(CoroutineName("file-writer") + coroutineContext, autoFlush = true) { - @Suppress("BlockingMethodInNonBlockingContext") - RandomAccessFile(this@writeChannel, "rw").use { file -> - val copied = channel.copyTo(file.channel) - file.setLength(copied) // truncate tail that could remain from the previously written data - } -}.channel - -private val loginSolverLock = Mutex() - -/** - * @author NaturalHG - */ -private fun BufferedImage.createCharImg(outputWidth: Int = 100, ignoreRate: Double = 0.95): String { - val newHeight = (this.height * (outputWidth.toDouble() / this.width)).toInt() - val tmp = this.getScaledInstance(outputWidth, newHeight, Image.SCALE_SMOOTH) - val image = BufferedImage(outputWidth, newHeight, BufferedImage.TYPE_INT_ARGB) - val g2d = image.createGraphics() - g2d.drawImage(tmp, 0, 0, null) - fun gray(rgb: Int): Int { - val r = rgb and 0xff0000 shr 16 - val g = rgb and 0x00ff00 shr 8 - val b = rgb and 0x0000ff - return (r * 30 + g * 59 + b * 11 + 50) / 100 - } - - fun grayCompare(g1: Int, g2: Int): Boolean = - kotlin.math.min(g1, g2).toDouble() / kotlin.math.max(g1, g2) >= ignoreRate - - val background = gray(image.getRGB(0, 0)) - - return buildString(capacity = height) { - - val lines = mutableListOf() - - var minXPos = outputWidth - var maxXPos = 0 - - for (y in 0 until image.height) { - val builderLine = StringBuilder() - for (x in 0 until image.width) { - val gray = gray(image.getRGB(x, y)) - if (grayCompare(gray, background)) { - builderLine.append(" ") - } else { - builderLine.append("#") - if (x < minXPos) { - minXPos = x - } - if (x > maxXPos) { - maxXPos = x - } - } - } - if (builderLine.toString().isBlank()) { - continue - } - lines.add(builderLine) - } - for (line in lines) { - append(line.substring(minXPos, maxXPos)).append("\n") - } - } -} diff --git a/mirai-core-api/src/jvmMain/kotlin/utils/OverFileSizeMaxException.kt b/mirai-core-api/src/jvmMain/kotlin/utils/OverFileSizeMaxException.kt deleted file mode 100644 index ec4ee5df2..000000000 --- a/mirai-core-api/src/jvmMain/kotlin/utils/OverFileSizeMaxException.kt +++ /dev/null @@ -1,15 +0,0 @@ -/* - * Copyright 2019-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 - -/** - * 图片文件过大 - */ -public actual class OverFileSizeMaxException : IllegalStateException() \ No newline at end of file diff --git a/mirai-core-api/src/jvmMain/kotlin/utils/PlatformLogger.jvm.kt b/mirai-core-api/src/jvmMain/kotlin/utils/PlatformLogger.jvm.kt index 11c0e8bab..9fa379953 100644 --- a/mirai-core-api/src/jvmMain/kotlin/utils/PlatformLogger.jvm.kt +++ b/mirai-core-api/src/jvmMain/kotlin/utils/PlatformLogger.jvm.kt @@ -13,8 +13,6 @@ package net.mamoe.mirai.utils -import java.io.ByteArrayOutputStream -import java.io.PrintStream import java.text.DateFormat import java.text.SimpleDateFormat import java.util.* @@ -44,7 +42,7 @@ import java.util.* * @see SingleFileLogger 使用单一文件记录日志 * @see DirectoryLogger 在一个目录中按日期存放文件记录日志, 自动清理过期日志 */ -public actual open class PlatformLogger @JvmOverloads constructor( +public actual open class PlatformLogger constructor( public override val identity: String? = "Mirai", /** * 日志输出. 不会自动添加换行 @@ -53,6 +51,7 @@ public actual open class PlatformLogger @JvmOverloads constructor( public val isColored: Boolean = true ) : MiraiLoggerPlatformBase() { public actual constructor(identity: String?) : this(identity, ::println) + public actual constructor(identity: String?, output: (String) -> Unit) : this(identity, output, true) /** * 输出一条日志. [message] 末尾可能不带换行符. diff --git a/mirai-core-api/src/jvmMain/kotlin/utils/PlatformUtilsJvm.kt b/mirai-core-api/src/jvmMain/kotlin/utils/PlatformUtilsJvm.kt deleted file mode 100644 index 2ab9a6f58..000000000 --- a/mirai-core-api/src/jvmMain/kotlin/utils/PlatformUtilsJvm.kt +++ /dev/null @@ -1,20 +0,0 @@ -/* - * Copyright 2019-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 - */ - -@file:JvmMultifileClass -@file:JvmName("Utils") -@file:Suppress("EXPERIMENTAL_API_USAGE", "NOTHING_TO_INLINE") - -package net.mamoe.mirai.utils - -/** - * 时间戳 - */ -public actual val currentTimeMillis: Long - get() = System.currentTimeMillis() diff --git a/mirai-core/src/commonMain/kotlin/MiraiImpl.kt b/mirai-core/src/commonMain/kotlin/MiraiImpl.kt index 17555483c..ce3609291 100644 --- a/mirai-core/src/commonMain/kotlin/MiraiImpl.kt +++ b/mirai-core/src/commonMain/kotlin/MiraiImpl.kt @@ -44,7 +44,7 @@ import net.mamoe.mirai.message.data.* import net.mamoe.mirai.utils.BotConfiguration import net.mamoe.mirai.utils.MiraiExperimentalApi import net.mamoe.mirai.utils.currentTimeSeconds -import kotlin.jvm.JvmSynthetic +import java.util.concurrent.atomic.AtomicBoolean import kotlin.math.absoluteValue import kotlin.random.Random @@ -63,7 +63,7 @@ internal open class MiraiImpl : IMirai, LowLevelApiAccessor { @OptIn(LowLevelApi::class) override suspend fun acceptNewFriendRequest(event: NewFriendRequestEvent) { @Suppress("INVISIBLE_REFERENCE", "INVISIBLE_MEMBER") - check(event.responded.compareAndSet(expect = false, update = true)) { + check(event.responded.compareAndSet(false, true)) { "the request $this has already been responded" } @@ -83,7 +83,7 @@ internal open class MiraiImpl : IMirai, LowLevelApiAccessor { override suspend fun rejectNewFriendRequest(event: NewFriendRequestEvent, blackList: Boolean) { @Suppress("INVISIBLE_REFERENCE", "INVISIBLE_MEMBER") - check(event.responded.compareAndSet(expect = false, update = true)) { + check(event.responded.compareAndSet(false, true)) { "the request $event has already been responded" } @@ -105,7 +105,7 @@ internal open class MiraiImpl : IMirai, LowLevelApiAccessor { @Suppress("DuplicatedCode") checkGroupPermission(event.bot, event.group) { event::class.simpleName ?: "" } @Suppress("INVISIBLE_REFERENCE", "INVISIBLE_MEMBER") - check(event.responded.compareAndSet(expect = false, update = true)) { + check(event.responded.compareAndSet(false, true)) { "the request $this has already been responded" } @@ -128,7 +128,7 @@ internal open class MiraiImpl : IMirai, LowLevelApiAccessor { override suspend fun rejectMemberJoinRequest(event: MemberJoinRequestEvent, blackList: Boolean, message: String) { checkGroupPermission(event.bot, event.group) { event::class.simpleName ?: "" } @Suppress("INVISIBLE_REFERENCE", "INVISIBLE_MEMBER") - check(event.responded.compareAndSet(expect = false, update = true)) { + check(event.responded.compareAndSet(false, true)) { "the request $this has already been responded" } @@ -164,7 +164,7 @@ internal open class MiraiImpl : IMirai, LowLevelApiAccessor { override suspend fun ignoreMemberJoinRequest(event: MemberJoinRequestEvent, blackList: Boolean) { checkGroupPermission(event.bot, event.group) { event::class.simpleName ?: "" } @Suppress("INVISIBLE_REFERENCE", "INVISIBLE_MEMBER") - check(event.responded.compareAndSet(expect = false, update = true)) { + check(event.responded.compareAndSet(false, true)) { "the request $this has already been responded" } @@ -188,7 +188,7 @@ internal open class MiraiImpl : IMirai, LowLevelApiAccessor { private suspend fun solveInvitedJoinGroupRequest(event: BotInvitedJoinGroupRequestEvent, accept: Boolean) { @Suppress("INVISIBLE_REFERENCE", "INVISIBLE_MEMBER") - check(event.responded.compareAndSet(expect = false, update = true)) { + check(event.responded.compareAndSet(false, true)) { "the request $this has already been responded" } @@ -260,7 +260,7 @@ internal open class MiraiImpl : IMirai, LowLevelApiAccessor { source.ensureSequenceIdAvailable() @Suppress("BooleanLiteralArgument", "INVISIBLE_REFERENCE", "INVISIBLE_MEMBER") // false positive - check(!source.isRecalledOrPlanned.value && source.isRecalledOrPlanned.compareAndSet(false, true)) { + check(!source.isRecalledOrPlanned.get() && source.isRecalledOrPlanned.compareAndSet(false, true)) { "$source had already been recalled." } @@ -830,8 +830,7 @@ internal open class MiraiImpl : IMirai, LowLevelApiAccessor { override val internalId: Int = internalId @Suppress("INVISIBLE_REFERENCE", "INVISIBLE_MEMBER") - override var isRecalledOrPlanned: net.mamoe.mirai.event.internal.MiraiAtomicBoolean = - net.mamoe.mirai.event.internal.MiraiAtomicBoolean(false) + override var isRecalledOrPlanned: AtomicBoolean = AtomicBoolean(false) override fun toJceData(): ImMsgBody.SourceMsg { return ImMsgBody.SourceMsg( diff --git a/mirai-core/src/commonMain/kotlin/message/incomingSourceImpl.kt b/mirai-core/src/commonMain/kotlin/message/incomingSourceImpl.kt index f7f044c7a..f8c6ac436 100644 --- a/mirai-core/src/commonMain/kotlin/message/incomingSourceImpl.kt +++ b/mirai-core/src/commonMain/kotlin/message/incomingSourceImpl.kt @@ -14,7 +14,6 @@ package net.mamoe.mirai.internal.message import net.mamoe.mirai.Bot import net.mamoe.mirai.contact.Friend import net.mamoe.mirai.contact.Member -import net.mamoe.mirai.event.internal.MiraiAtomicBoolean import net.mamoe.mirai.internal.contact.GroupImpl import net.mamoe.mirai.internal.network.protocol.data.proto.ImMsgBody import net.mamoe.mirai.internal.network.protocol.data.proto.MsgComm @@ -27,6 +26,7 @@ import net.mamoe.mirai.message.data.Message import net.mamoe.mirai.message.data.MessageChain import net.mamoe.mirai.message.data.MessageSource import net.mamoe.mirai.message.data.OnlineMessageSource +import java.util.concurrent.atomic.AtomicBoolean internal interface MessageSourceInternal { val sequenceId: Int @@ -35,7 +35,7 @@ internal interface MessageSourceInternal { @Deprecated("don't use this internally. Use sequenceId or random instead.", level = DeprecationLevel.ERROR) val id: Int - val isRecalledOrPlanned: MiraiAtomicBoolean + val isRecalledOrPlanned: AtomicBoolean fun toJceData(): ImMsgBody.SourceMsg } @@ -67,7 +67,7 @@ internal class MessageSourceFromFriendImpl( val msg: MsgComm.Msg ) : OnlineMessageSource.Incoming.FromFriend(), MessageSourceInternal { override val sequenceId: Int get() = msg.msgHead.msgSeq - override var isRecalledOrPlanned: MiraiAtomicBoolean = MiraiAtomicBoolean(false) + override var isRecalledOrPlanned: AtomicBoolean = AtomicBoolean(false) override val id: Int get() = sequenceId// msg.msgBody.richText.attr!!.random override val internalId: Int get() = msg.msgBody.richText.attr!!.random override val time: Int get() = msg.msgHead.msgTime @@ -121,7 +121,7 @@ internal class MessageSourceFromTempImpl( ) : OnlineMessageSource.Incoming.FromTemp(), MessageSourceInternal { override val sequenceId: Int get() = msg.msgHead.msgSeq override val internalId: Int get() = msg.msgBody.richText.attr!!.random - override var isRecalledOrPlanned: MiraiAtomicBoolean = MiraiAtomicBoolean(false) + override var isRecalledOrPlanned: AtomicBoolean = AtomicBoolean(false) override val id: Int get() = sequenceId// override val time: Int get() = msg.msgHead.msgTime override val originalMessage: MessageChain by lazy { msg.toMessageChain(bot, 0, false) } @@ -135,7 +135,7 @@ internal data class MessageSourceFromGroupImpl( override val bot: Bot, private val msg: MsgComm.Msg ) : OnlineMessageSource.Incoming.FromGroup(), MessageSourceInternal { - override var isRecalledOrPlanned: MiraiAtomicBoolean = MiraiAtomicBoolean(false) + override var isRecalledOrPlanned: AtomicBoolean = AtomicBoolean(false) override val sequenceId: Int get() = msg.msgHead.msgSeq override val internalId: Int get() = msg.msgBody.richText.attr!!.random override val id: Int get() = sequenceId diff --git a/mirai-core/src/commonMain/kotlin/message/offlineSourceImpl.kt b/mirai-core/src/commonMain/kotlin/message/offlineSourceImpl.kt index a1d7eee5c..9b2d3b41c 100644 --- a/mirai-core/src/commonMain/kotlin/message/offlineSourceImpl.kt +++ b/mirai-core/src/commonMain/kotlin/message/offlineSourceImpl.kt @@ -12,7 +12,6 @@ package net.mamoe.mirai.internal.message import net.mamoe.mirai.Bot -import net.mamoe.mirai.event.internal.MiraiAtomicBoolean import net.mamoe.mirai.internal.network.protocol.data.proto.ImMsgBody import net.mamoe.mirai.internal.network.protocol.data.proto.MsgComm import net.mamoe.mirai.internal.network.protocol.data.proto.SourceMsg @@ -20,6 +19,7 @@ import net.mamoe.mirai.internal.network.protocol.packet.EMPTY_BYTE_ARRAY import net.mamoe.mirai.internal.utils.io.serialization.loadAs import net.mamoe.mirai.message.data.MessageChain import net.mamoe.mirai.message.data.OfflineMessageSource +import java.util.concurrent.atomic.AtomicBoolean internal class OfflineMessageSourceImplByMsg( @@ -47,7 +47,7 @@ internal class OfflineMessageSourceImplByMsg( override val sequenceId: Int get() = delegate.msgHead.msgSeq - override var isRecalledOrPlanned: MiraiAtomicBoolean = MiraiAtomicBoolean(false) + override var isRecalledOrPlanned: AtomicBoolean = AtomicBoolean(false) override fun toJceData(): ImMsgBody.SourceMsg { return ImMsgBody.SourceMsg( @@ -72,7 +72,7 @@ internal class OfflineMessageSourceImplBySourceMsg( ) : OfflineMessageSource(), MessageSourceInternal { override val kind: Kind get() = if (delegate.srcMsg == null) Kind.GROUP else Kind.FRIEND - override var isRecalledOrPlanned: MiraiAtomicBoolean = MiraiAtomicBoolean(false) + override var isRecalledOrPlanned: AtomicBoolean = AtomicBoolean(false) override val sequenceId: Int get() = delegate.origSeqs.firstOrNull() ?: error("cannot find sequenceId") override val internalId: Int diff --git a/mirai-core/src/commonMain/kotlin/message/outgoingSourceImpl.kt b/mirai-core/src/commonMain/kotlin/message/outgoingSourceImpl.kt index 0bf142171..ca2f11a3a 100644 --- a/mirai-core/src/commonMain/kotlin/message/outgoingSourceImpl.kt +++ b/mirai-core/src/commonMain/kotlin/message/outgoingSourceImpl.kt @@ -19,7 +19,6 @@ import net.mamoe.mirai.contact.Friend import net.mamoe.mirai.contact.Group import net.mamoe.mirai.contact.Member import net.mamoe.mirai.event.asyncFromEventOrNull -import net.mamoe.mirai.event.internal.MiraiAtomicBoolean import net.mamoe.mirai.internal.network.protocol.data.proto.ImMsgBody import net.mamoe.mirai.internal.network.protocol.data.proto.MsgComm import net.mamoe.mirai.internal.network.protocol.data.proto.SourceMsg @@ -28,6 +27,7 @@ import net.mamoe.mirai.internal.utils.io.serialization.toByteArray import net.mamoe.mirai.message.data.MessageChain import net.mamoe.mirai.message.data.MessageSource import net.mamoe.mirai.message.data.OnlineMessageSource +import java.util.concurrent.atomic.AtomicBoolean private fun T.toJceDataImpl(): ImMsgBody.SourceMsg @@ -81,7 +81,7 @@ internal class MessageSourceToFriendImpl( get() = sender override val id: Int get() = sequenceId - override var isRecalledOrPlanned: MiraiAtomicBoolean = MiraiAtomicBoolean(false) + override var isRecalledOrPlanned: AtomicBoolean = AtomicBoolean(false) private val jceData by lazy { toJceDataImpl() } override fun toJceData(): ImMsgBody.SourceMsg = jceData } @@ -98,7 +98,7 @@ internal class MessageSourceToTempImpl( get() = sender override val id: Int get() = sequenceId - override var isRecalledOrPlanned: MiraiAtomicBoolean = MiraiAtomicBoolean(false) + override var isRecalledOrPlanned: AtomicBoolean = AtomicBoolean(false) private val jceData by lazy { toJceDataImpl() } override fun toJceData(): ImMsgBody.SourceMsg = jceData } @@ -115,7 +115,7 @@ internal class MessageSourceToGroupImpl( get() = sequenceId override val bot: Bot get() = sender - override var isRecalledOrPlanned: MiraiAtomicBoolean = MiraiAtomicBoolean(false) + override var isRecalledOrPlanned: AtomicBoolean = AtomicBoolean(false) private val sequenceIdDeferred: Deferred = coroutineScope.asyncFromEventOrNull( diff --git a/mirai-core/src/commonMain/kotlin/network/protocol/packet/Tlv.kt b/mirai-core/src/commonMain/kotlin/network/protocol/packet/Tlv.kt index 005994fb6..8d75cde56 100644 --- a/mirai-core/src/commonMain/kotlin/network/protocol/packet/Tlv.kt +++ b/mirai-core/src/commonMain/kotlin/network/protocol/packet/Tlv.kt @@ -35,7 +35,7 @@ internal fun BytePacketBuilder.t1(uin: Long, ip: ByteArray) { writeShort(1) // _ip_ver writeInt(Random.nextInt()) writeInt(uin.toInt()) - writeInt(currentTimeMillis.toInt()) + writeInt(currentTimeMillis().toInt()) writeFully(ip) writeShort(0) } shouldEqualsTo 20 @@ -113,7 +113,7 @@ internal fun BytePacketBuilder.t106( writeLong(uin) } - writeInt(currentTimeMillis.toInt()) + writeInt(currentTimeMillis().toInt()) writeFully(ByteArray(4)) // ip // no need to write actual ip writeByte(isSavePassword.toByte()) writeFully(passwordMd5) @@ -555,7 +555,7 @@ internal fun BytePacketBuilder.t400( writeFully(dpwd) writeInt(appId.toInt()) writeInt(subAppId.toInt()) - writeLong(currentTimeMillis) + writeLong(currentTimeMillis()) writeFully(randomSeed) } } diff --git a/mirai-core/src/commonMain/kotlin/utils/AtomicResizeCacheList.kt b/mirai-core/src/commonMain/kotlin/utils/AtomicResizeCacheList.kt index 1c9326f96..45459d4eb 100644 --- a/mirai-core/src/commonMain/kotlin/utils/AtomicResizeCacheList.kt +++ b/mirai-core/src/commonMain/kotlin/utils/AtomicResizeCacheList.kt @@ -14,8 +14,6 @@ import kotlinx.atomicfu.atomic import kotlinx.atomicfu.locks.reentrantLock import kotlinx.atomicfu.locks.withLock import net.mamoe.mirai.utils.currentTimeMillis -import kotlin.jvm.JvmField -import kotlin.jvm.Volatile /** @@ -43,7 +41,7 @@ internal class AtomicResizeCacheList(private val retention: Long) { * No concurrency guaranteed on same [element]. */ private fun add(element: E) { - val currentTime = currentTimeMillis + val currentTime = currentTimeMillis() findAvailable@ while (true) { for (cache in list) { val instant = cache.time.value