diff --git a/mirai-core-api/src/commonMain/kotlin/utils/BotConfiguration.common.kt b/mirai-core-api/src/commonMain/kotlin/utils/BotConfiguration.kt similarity index 100% rename from mirai-core-api/src/commonMain/kotlin/utils/BotConfiguration.common.kt rename to mirai-core-api/src/commonMain/kotlin/utils/BotConfiguration.kt diff --git a/mirai-core-api/src/commonMain/kotlin/utils/FileCacheStrategy.common.kt b/mirai-core-api/src/commonMain/kotlin/utils/FileCacheStrategy.kt similarity index 100% rename from mirai-core-api/src/commonMain/kotlin/utils/FileCacheStrategy.common.kt rename to mirai-core-api/src/commonMain/kotlin/utils/FileCacheStrategy.kt diff --git a/mirai-core-api/src/commonMain/kotlin/utils/HyperLinkLabel.kt b/mirai-core-api/src/commonMain/kotlin/utils/HyperLinkLabel.kt deleted file mode 100644 index 64b07f3c0..000000000 --- a/mirai-core-api/src/commonMain/kotlin/utils/HyperLinkLabel.kt +++ /dev/null @@ -1,35 +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 java.awt.Desktop -import java.awt.event.MouseAdapter -import java.awt.event.MouseEvent -import java.net.URI -import javax.swing.JLabel - -/** - * 构造方法中url指代用户需要点击的链接, text为显示的提示内容 - */ -internal class HyperLinkLabel constructor(url: String, text: String) : JLabel() { - init { - super.setText("$text") - addMouseListener(object : MouseAdapter() { - - override fun mouseClicked(e: MouseEvent) { - try { - Desktop.getDesktop().browse(URI(url)) - } catch (ex: Exception) { - ex.printStackTrace() - } - } - }) - } -} diff --git a/mirai-core-api/src/commonMain/kotlin/utils/LoggerAdapters.kt b/mirai-core-api/src/commonMain/kotlin/utils/LoggerAdapters.kt index 0d8220e86..d6e1ec022 100644 --- a/mirai-core-api/src/commonMain/kotlin/utils/LoggerAdapters.kt +++ b/mirai-core-api/src/commonMain/kotlin/utils/LoggerAdapters.kt @@ -12,6 +12,7 @@ package net.mamoe.mirai.utils import net.mamoe.mirai.utils.internal.logging.JdkLogger import net.mamoe.mirai.utils.internal.logging.Log4jLogger import net.mamoe.mirai.utils.internal.logging.Slf4jLogger + public object LoggerAdapters { @JvmStatic public fun java.util.logging.Logger.asMiraiLogger(): MiraiLogger { diff --git a/mirai-core-api/src/commonMain/kotlin/utils/SoftRef.kt b/mirai-core-api/src/commonMain/kotlin/utils/SoftRef.kt deleted file mode 100644 index f08882e0f..000000000 --- a/mirai-core-api/src/commonMain/kotlin/utils/SoftRef.kt +++ /dev/null @@ -1,98 +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:Suppress("unused", "NOTHING_TO_INLINE") - -package net.mamoe.mirai.utils - -/* - -/** - * SoftRef that `getValue` for delegation throws an [IllegalStateException] if the referent is released by GC. Therefore it returns notnull value only - */ -class UnsafeSoftRef(private val softRef: SoftRef) { - fun get(): T = softRef.get() ?: error("SoftRef is released") - fun clear() = softRef.clear() -} - -/** - * Provides delegate value. - * - * ```kotlin - * val bot: Bot by param.unsafeSoftRef() - * ``` - */ -@JvmSynthetic -inline operator fun UnsafeSoftRef.getValue(thisRef: Any?, property: KProperty<*>): T = get() - -/** - * Soft Reference. - * On JVM, it is implemented as a typealias referring to `SoftReference` from JDK. - * - * Details: - * On JVM, instances of objects are stored in the JVM Heap and are accessed via references. - * GC(garbage collection) can automatically collect and release the memory used by objects that are not directly referred by any other. - * [SoftRef] will keep the reference until JVM run out of memory. - * - * @see softRef provides a SoftRef - * @see unsafeSoftRef provides a UnsafeSoftRef - */ -expect class SoftRef(referent: T) { - fun get(): T? - fun clear() -} - -/** - * Indicates that the property is delegated by a [SoftRef] - * - * @see softRef - */ -@Target(AnnotationTarget.PROPERTY) -@Retention(AnnotationRetention.SOURCE) -annotation class SoftRefProperty - -/** - * Provides a soft reference to [this] - * The `getValue` for delegation returns [this] when [this] is not released by GC - */ -@JvmSynthetic -inline fun T.softRef(): SoftRef = SoftRef(this) - -/** - * Constructs an unsafe inline delegate for [this] - */ -@JvmSynthetic -inline fun SoftRef.unsafe(): UnsafeSoftRef = UnsafeSoftRef(this) - -/** - * Provides a soft reference to [this]. - * The `getValue` for delegation throws an [IllegalStateException] if the referent is released by GC. Therefore it returns notnull value only - * - * **UNSTABLE API**: It is strongly suggested not to use this api - */ -@JvmSynthetic -inline fun T.unsafeSoftRef(): UnsafeSoftRef = UnsafeSoftRef(this.softRef()) - -/** - * Provides delegate value. - * - * ```kotlin - * val bot: Bot? by param.softRef() - * ``` - */ -@JvmSynthetic -inline operator fun SoftRef.getValue(thisRef: Any?, property: KProperty<*>): T? = this.get() - -/** - * Call the block if the referent is absent - */ -@JvmSynthetic -inline fun SoftRef.ifAbsent(block: (T) -> R): R? = this.get()?.let(block) - - */ \ No newline at end of file diff --git a/mirai-core-api/src/commonMain/kotlin/utils/SwingSolver.kt b/mirai-core-api/src/commonMain/kotlin/utils/SwingSolver.kt index db5c229b3..91a224280 100644 --- a/mirai-core-api/src/commonMain/kotlin/utils/SwingSolver.kt +++ b/mirai-core-api/src/commonMain/kotlin/utils/SwingSolver.kt @@ -9,37 +9,40 @@ 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 -import javax.swing.ImageIcon -import javax.swing.JLabel - /** * @author Karlatemp */ + +import kotlinx.coroutines.CompletableDeferred +import net.mamoe.mirai.Bot +import net.mamoe.mirai.utils.* +import java.awt.BorderLayout +import java.awt.Desktop +import java.awt.Dimension +import java.awt.Toolkit +import java.awt.event.* +import java.awt.image.BufferedImage +import java.net.URI +import javax.imageio.ImageIO +import javax.swing.* + @MiraiExperimentalApi public object SwingSolver : LoginSolver() { - public override suspend fun onSolvePicCaptcha(bot: Bot, data: ByteArray): String? { + public override suspend fun onSolvePicCaptcha(bot: Bot, data: ByteArray): String { return openWindow("Mirai PicCaptcha(${bot.id})") { val image = ImageIO.read(data.inputStream()) JLabel(ImageIcon(image)).append() } } - public override suspend fun onSolveSliderCaptcha(bot: Bot, url: String): String? { + public override suspend fun onSolveSliderCaptcha(bot: Bot, url: String): String { return openWindow("Mirai SliderCaptcha(${bot.id})") { JLabel("需要滑动验证码, 完成后请关闭该窗口").append() Desktop.getDesktop().browse(URI(url)) } } - public override suspend fun onSolveUnsafeDeviceLoginVerify(bot: Bot, url: String): String? { + public override suspend fun onSolveUnsafeDeviceLoginVerify(bot: Bot, url: String): String { return openWindow("Mirai UnsafeDeviceLoginVerify(${bot.id})") { JLabel( """ @@ -53,4 +56,140 @@ public object SwingSolver : LoginSolver() { HyperLinkLabel(url, "设备锁验证").last() } } -} \ No newline at end of file +} + + +// 隔离类代码 +@Suppress("DEPRECATION") +internal object WindowHelperJvm { + internal val isDesktopSupported: Boolean = kotlin.run { + if (System.getProperty("mirai.no-desktop") === null) { + kotlin.runCatching { + Class.forName("java.awt.Desktop") + Class.forName("java.awt.Toolkit") + }.onFailure { return@run false } // Android OS + kotlin.runCatching { + Toolkit.getDefaultToolkit() + }.onFailure { // AWT Error, #270 + return@run false + } + kotlin.runCatching { + Desktop.isDesktopSupported().also { stat -> + if (stat) { + MiraiLogger.info( + """ + Mirai 正在使用桌面环境, + 如果你正在使用SSH, 或无法访问桌面等, + 请将 `mirai.no-desktop` 添加到 JVM 系统属性中 (-Dmirai.no-desktop) + 然后重启 Mirai + """.trimIndent() + ) + MiraiLogger.info( + """ + Mirai using DesktopCaptcha System. + If you are running on SSH, cannot access desktop or more. + Please add `mirai.no-desktop` to JVM properties (-Dmirai.no-desktop) + Then restart mirai + """.trimIndent() + ) + } + } + }.getOrElse { + // Should not happen + MiraiLogger.warning("Exception in checking desktop support.", it) + false + } + } else { + false + } + } +} + +internal class WindowInitializer(private val initializer: WindowInitializer.(JFrame) -> Unit) { + private lateinit var frame0: JFrame + val frame: JFrame get() = frame0 + fun java.awt.Component.append() { + frame.add(this, BorderLayout.NORTH) + } + + fun java.awt.Component.last() { + frame.add(this) + } + + internal fun init(frame: JFrame) { + this.frame0 = frame + initializer(frame) + } +} + +internal val windowIcon: BufferedImage? by lazy { + WindowHelperJvm::class.java.getResourceAsStream("project-mirai.png")?.use { + ImageIO.read(it) + } +} + +internal suspend fun openWindow(title: String = "", initializer: WindowInitializer.(JFrame) -> Unit = {}): String { + return openWindow(title, WindowInitializer(initializer)) +} + +internal suspend fun openWindow(title: String = "", initializer: WindowInitializer = WindowInitializer {}): String { + val frame = JFrame() + frame.iconImage = windowIcon + frame.minimumSize = Dimension(228, 62) // From Windows 10 + val value = JTextField() + val def = CompletableDeferred() + value.addKeyListener(object : KeyListener { + override fun keyTyped(e: KeyEvent?) { + } + + override fun keyPressed(e: KeyEvent?) { + when (e!!.keyCode) { + 27, 10 -> { + def.complete(value.text) + } + } + } + + override fun keyReleased(e: KeyEvent?) { + } + }) + frame.layout = BorderLayout(10, 5) + frame.add(value, BorderLayout.SOUTH) + initializer.init(frame) + + frame.pack() + frame.defaultCloseOperation = JFrame.DISPOSE_ON_CLOSE + frame.addWindowListener(object : WindowAdapter() { + override fun windowClosing(e: WindowEvent?) { + def.complete(value.text) + } + }) + frame.setLocationRelativeTo(null) + frame.title = title + frame.isVisible = true + + return def.await().trim().also { + SwingUtilities.invokeLater { + frame.dispose() + } + } +} + +/** + * 构造方法中url指代用户需要点击的链接, text为显示的提示内容 + */ +internal class HyperLinkLabel constructor(url: String, text: String) : JLabel() { + init { + super.setText("$text") + addMouseListener(object : MouseAdapter() { + + override fun mouseClicked(e: MouseEvent) { + try { + Desktop.getDesktop().browse(URI(url)) + } catch (ex: Exception) { + ex.printStackTrace() + } + } + }) + } +} diff --git a/mirai-core-api/src/commonMain/kotlin/utils/WindowHelperJvm.kt b/mirai-core-api/src/commonMain/kotlin/utils/WindowHelperJvm.kt deleted file mode 100644 index 6b0a6bb01..000000000 --- a/mirai-core-api/src/commonMain/kotlin/utils/WindowHelperJvm.kt +++ /dev/null @@ -1,145 +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 - -/** - * @author Karlatemp - */ - -import kotlinx.coroutines.CompletableDeferred -import java.awt.BorderLayout -import java.awt.Desktop -import java.awt.Dimension -import java.awt.Toolkit -import java.awt.event.KeyEvent -import java.awt.event.KeyListener -import java.awt.event.WindowAdapter -import java.awt.event.WindowEvent -import java.awt.image.BufferedImage -import javax.imageio.ImageIO -import javax.swing.JFrame -import javax.swing.JTextField -import javax.swing.SwingUtilities - -// 隔离类代码 -@Suppress("DEPRECATION") -internal object WindowHelperJvm { - internal val isDesktopSupported: Boolean = kotlin.run { - if (System.getProperty("mirai.no-desktop") === null) { - kotlin.runCatching { - Class.forName("java.awt.Desktop") - Class.forName("java.awt.Toolkit") - }.onFailure { return@run false } // Android OS - kotlin.runCatching { - Toolkit.getDefaultToolkit() - }.onFailure { // AWT Error, #270 - return@run false - } - kotlin.runCatching { - Desktop.isDesktopSupported().also { stat -> - if (stat) { - MiraiLogger.info( - """ - Mirai 正在使用桌面环境, - 如果你正在使用SSH, 或无法访问桌面等, - 请将 `mirai.no-desktop` 添加到 JVM 系统属性中 (-Dmirai.no-desktop) - 然后重启 Mirai - """.trimIndent() - ) - MiraiLogger.info( - """ - Mirai using DesktopCaptcha System. - If you are running on SSH, cannot access desktop or more. - Please add `mirai.no-desktop` to JVM properties (-Dmirai.no-desktop) - Then restart mirai - """.trimIndent() - ) - } - } - }.getOrElse { - // Should not happen - MiraiLogger.warning("Exception in checking desktop support.", it) - false - } - } else { - false - } - } -} - -internal class WindowInitializer(private val initializer: WindowInitializer.(JFrame) -> Unit) { - private lateinit var frame0: JFrame - val frame: JFrame get() = frame0 - fun java.awt.Component.append() { - frame.add(this, BorderLayout.NORTH) - } - - fun java.awt.Component.last() { - frame.add(this) - } - - internal fun init(frame: JFrame) { - this.frame0 = frame - initializer(frame) - } -} - -internal val windowIcon: BufferedImage? by lazy { - WindowHelperJvm::class.java.getResourceAsStream("project-mirai.png")?.use { - ImageIO.read(it) - } -} - -internal suspend fun openWindow(title: String = "", initializer: WindowInitializer.(JFrame) -> Unit = {}): String { - return openWindow(title, WindowInitializer(initializer)) -} - -internal suspend fun openWindow(title: String = "", initializer: WindowInitializer = WindowInitializer {}): String { - val frame = JFrame() - frame.iconImage = windowIcon - frame.minimumSize = Dimension(228, 62) // From Windows 10 - val value = JTextField() - val def = CompletableDeferred() - value.addKeyListener(object : KeyListener { - override fun keyTyped(e: KeyEvent?) { - } - - override fun keyPressed(e: KeyEvent?) { - when (e!!.keyCode) { - 27, 10 -> { - def.complete(value.text) - } - } - } - - override fun keyReleased(e: KeyEvent?) { - } - }) - frame.layout = BorderLayout(10, 5) - frame.add(value, BorderLayout.SOUTH) - initializer.init(frame) - - frame.pack() - frame.defaultCloseOperation = JFrame.DISPOSE_ON_CLOSE - frame.addWindowListener(object : WindowAdapter() { - override fun windowClosing(e: WindowEvent?) { - def.complete(value.text) - } - }) - frame.setLocationRelativeTo(null) - frame.title = title - frame.isVisible = true - - return def.await().trim().also { - SwingUtilities.invokeLater { - frame.dispose() - } - } -} diff --git a/mirai-core/src/commonMain/kotlin/network/QQAndroidBotNetworkHandler.kt b/mirai-core/src/commonMain/kotlin/network/QQAndroidBotNetworkHandler.kt index 456f11eee..831bd5fa4 100644 --- a/mirai-core/src/commonMain/kotlin/network/QQAndroidBotNetworkHandler.kt +++ b/mirai-core/src/commonMain/kotlin/network/QQAndroidBotNetworkHandler.kt @@ -18,7 +18,6 @@ import kotlinx.coroutines.sync.Mutex import kotlinx.coroutines.sync.withLock import kotlinx.io.core.ByteReadPacket import kotlinx.io.core.buildPacket -import kotlinx.io.core.use import net.mamoe.mirai.Mirai import net.mamoe.mirai.event.* import net.mamoe.mirai.event.events.BotOfflineEvent @@ -47,8 +46,6 @@ import net.mamoe.mirai.network.UnsupportedSMSLoginException import net.mamoe.mirai.network.WrongPasswordException import net.mamoe.mirai.utils.* import kotlin.coroutines.CoroutineContext -import kotlin.jvm.JvmField -import kotlin.jvm.Volatile @Suppress("MemberVisibilityCanBePrivate") internal class QQAndroidBotNetworkHandler(coroutineContext: CoroutineContext, bot: QQAndroidBot) : BotNetworkHandler() {