Commit ae32536e authored by Him188's avatar Him188

Move `BotImpl` and `BotNetworkHandler` to mirai-core-qqandroid.

parent 84c47c9f
......@@ -7,31 +7,30 @@
* https://github.com/mamoe/mirai/blob/master/LICENSE
*/
@file:Suppress("EXPERIMENTAL_API_USAGE", "DEPRECATION_ERROR", "OverridingDeprecatedMember")
@file:Suppress("EXPERIMENTAL_API_USAGE", "DEPRECATION_ERROR", "OverridingDeprecatedMember", "INVISIBLE_REFERENCE", "INVISIBLE_MEMBER")
package net.mamoe.mirai
package net.mamoe.mirai.qqandroid
import kotlinx.coroutines.*
import net.mamoe.mirai.Bot
import net.mamoe.mirai.closeAndJoin
import net.mamoe.mirai.event.Listener
import net.mamoe.mirai.event.broadcast
import net.mamoe.mirai.event.events.BotOfflineEvent
import net.mamoe.mirai.event.events.BotReloginEvent
import net.mamoe.mirai.event.subscribeAlways
import net.mamoe.mirai.network.BotNetworkHandler
import net.mamoe.mirai.network.ForceOfflineException
import net.mamoe.mirai.network.LoginFailedException
import net.mamoe.mirai.network.closeAndJoin
import net.mamoe.mirai.qqandroid.network.BotNetworkHandler
import net.mamoe.mirai.qqandroid.network.closeAndJoin
import net.mamoe.mirai.supervisorJob
import net.mamoe.mirai.utils.*
import net.mamoe.mirai.utils.internal.retryCatching
import kotlin.coroutines.CoroutineContext
import kotlin.time.ExperimentalTime
import kotlin.time.measureTime
/*
* 泛型 N 不需要向外(接口)暴露.
*/
@MiraiInternalAPI
abstract class BotImpl<N : BotNetworkHandler> constructor(
internal abstract class BotImpl<N : BotNetworkHandler> constructor(
context: Context,
val configuration: BotConfiguration
) : Bot(), CoroutineScope {
......@@ -49,44 +48,9 @@ abstract class BotImpl<N : BotNetworkHandler> constructor(
final override val logger: MiraiLogger by lazy { configuration.botLoggerSupplier(this) }
init {
instances.addLast(this.weakRef())
}
companion object {
@PublishedApi
internal val instances: LockFreeLinkedList<WeakRef<Bot>> = LockFreeLinkedList()
fun forEachInstance(block: (Bot) -> Unit) = instances.forEach {
it.get()?.let(block)
}
fun getInstance(qq: Long): Bot {
instances.forEach {
it.get()?.let { bot ->
if (bot.id == qq) {
return bot
}
}
}
throw NoSuchElementException(qq.toString())
}
fun getInstanceOrNull(qq: Long): Bot? {
instances.forEach {
it.get()?.let { bot ->
if (bot.id == qq) {
return bot
}
}
}
return null
}
}
// region network
final override val network: N get() = _network
val network: N get() = _network
@Suppress("PropertyName")
internal lateinit var _network: N
......@@ -160,10 +124,11 @@ abstract class BotImpl<N : BotNetworkHandler> constructor(
logger.info { "Reconnected successfully in ${time.asHumanReadable}" }
}
is BotOfflineEvent.Active -> {
val msg = if (event.cause == null) {
val cause = event.cause
val msg = if (cause == null) {
""
} else {
" with exception: " + event.cause.message
" with exception: " + cause.message
}
bot.logger.info { "Bot is closed manually$msg" }
closeAndJoin(CancellationException(event.toString()))
......@@ -175,6 +140,7 @@ abstract class BotImpl<N : BotNetworkHandler> constructor(
}
}
/**
* **Exposed public API**
* [BotImpl.relogin] && [BotNetworkHandler.init]
......@@ -259,8 +225,6 @@ abstract class BotImpl<N : BotNetworkHandler> constructor(
init {
coroutineContext[Job]!!.invokeOnCompletion { throwable ->
instances.removeIf { it.get()?.id == this.id }
network.close(throwable)
offlineListener.cancel(CancellationException("Bot cancelled", throwable))
......
......@@ -22,7 +22,6 @@ import net.mamoe.mirai.qqandroid.asQQAndroidBot
import net.mamoe.mirai.qqandroid.message.MessageSourceToFriendImpl
import net.mamoe.mirai.qqandroid.message.ensureSequenceIdAvailable
import net.mamoe.mirai.qqandroid.message.firstIsInstanceOrNull
import net.mamoe.mirai.qqandroid.network.QQAndroidBotNetworkHandler
import net.mamoe.mirai.qqandroid.network.protocol.packet.chat.receive.MessageSvcPbSendMsg
import net.mamoe.mirai.utils.verbose
......@@ -33,7 +32,8 @@ internal suspend fun <T : Contact> Friend.sendMessageImpl(generic: T, message: M
}
event.message.firstIsInstanceOrNull<QuoteReply>()?.source?.ensureSequenceIdAvailable()
lateinit var source: MessageSourceToFriendImpl
(bot.network as QQAndroidBotNetworkHandler).run {
val bot = bot.asQQAndroidBot()
bot.network.run {
check(
MessageSvcPbSendMsg.createToFriend(
bot.asQQAndroidBot().client,
......
......@@ -9,7 +9,7 @@
@file:Suppress("EXPERIMENTAL_API_USAGE")
package net.mamoe.mirai.network
package net.mamoe.mirai.qqandroid.network
import kotlinx.coroutines.CancellationException
import kotlinx.coroutines.CompletableJob
......@@ -40,17 +40,8 @@ import net.mamoe.mirai.utils.WeakRefProperty
*
* @suppress 此为**内部 API**, 可能在任意时刻被改动, 且不会给出任何警告.
*/
@MiraiInternalAPI
@Suppress("PropertyName")
abstract class BotNetworkHandler : CoroutineScope {
/*
此为**内部 API**, 可能在任意时刻被改动, 且不会给出任何警告.
此为**内部 API**, 可能在任意时刻被改动, 且不会给出任何警告.
此为**内部 API**, 可能在任意时刻被改动, 且不会给出任何警告.
*/
internal abstract class BotNetworkHandler : CoroutineScope {
/**
* 所属 [Bot]. 为弱引用
*/
......@@ -123,8 +114,7 @@ abstract class BotNetworkHandler : CoroutineScope {
}
}
@MiraiInternalAPI
suspend fun BotNetworkHandler.closeAndJoin(cause: Throwable? = null) {
internal suspend fun BotNetworkHandler.closeAndJoin(cause: Throwable? = null) {
this.close(cause)
this.supervisor.join()
}
\ No newline at end of file
......@@ -24,7 +24,6 @@ import net.mamoe.mirai.event.events.BotOfflineEvent
import net.mamoe.mirai.event.events.BotOnlineEvent
import net.mamoe.mirai.event.events.BotReloginEvent
import net.mamoe.mirai.message.MessageEvent
import net.mamoe.mirai.network.BotNetworkHandler
import net.mamoe.mirai.network.UnsupportedSMSLoginException
import net.mamoe.mirai.network.WrongPasswordException
import net.mamoe.mirai.qqandroid.QQAndroidBot
......@@ -54,7 +53,7 @@ import kotlin.jvm.Volatile
internal class QQAndroidBotNetworkHandler(coroutineContext: CoroutineContext, bot: QQAndroidBot) : BotNetworkHandler() {
override val bot: QQAndroidBot by bot.unsafeWeakRef()
override val supervisor: CompletableJob = SupervisorJob(coroutineContext[Job])
override val logger: MiraiLogger get() = bot.configuration.networkLoggerSupplier(this)
override val logger: MiraiLogger get() = bot.configuration.networkLoggerSupplier(bot)
override val coroutineContext: CoroutineContext = coroutineContext + CoroutineExceptionHandler { _, throwable ->
logger.error("Exception in NetworkHandler", throwable)
......
......@@ -21,7 +21,6 @@ import net.mamoe.mirai.event.events.MemberJoinRequestEvent
import net.mamoe.mirai.event.events.NewFriendRequestEvent
import net.mamoe.mirai.message.MessageReceipt
import net.mamoe.mirai.message.data.*
import net.mamoe.mirai.network.BotNetworkHandler
import net.mamoe.mirai.network.LoginFailedException
import net.mamoe.mirai.utils.*
import kotlin.coroutines.CoroutineContext
......@@ -49,40 +48,56 @@ suspend inline fun <B : Bot> B.alsoLogin(): B = also { login() }
@Suppress("INAPPLICABLE_JVM_NAME", "EXPOSED_SUPER_CLASS")
abstract class Bot : CoroutineScope, LowLevelBotAPIAccessor, BotJavaFriendlyAPI, ContactOrBot {
companion object {
@Suppress("ObjectPropertyName")
internal val _instances: LockFreeLinkedList<WeakRef<Bot>> = LockFreeLinkedList()
/**
* 复制一份此时的 [Bot] 实例列表.
*/
@PlannedRemoval("1.2.0")
@Deprecated("use botInstances instead", replaceWith = ReplaceWith("botInstances"))
@Deprecated(
"use botInstances instead",
replaceWith = ReplaceWith("botInstances"),
level = DeprecationLevel.ERROR
)
@JvmStatic
val instances: List<WeakRef<Bot>>
get() = BotImpl.instances.toList()
get() = _instances.toList()
/**
* 复制一份此时的 [Bot] 实例列表.
*/
@JvmStatic
val botInstances: List<Bot>
get() = BotImpl.instances.asSequence().mapNotNull { it.get() }.toList()
get() = _instances.asSequence().mapNotNull { it.get() }.toList()
/**
* 遍历每一个 [Bot] 实例
*/
@JvmSynthetic
fun forEachInstance(block: (Bot) -> Unit) = BotImpl.forEachInstance(block)
fun forEachInstance(block: (Bot) -> Unit) = _instances.forEach { it.get()?.let(block) }
/**
* 获取一个 [Bot] 实例, 无对应实例时抛出 [NoSuchElementException]
*/
@JvmStatic
@Throws(NoSuchElementException::class)
fun getInstance(qq: Long): Bot = BotImpl.getInstance(qq = qq)
fun getInstance(qq: Long): Bot =
getInstanceOrNull(qq) ?: throw NoSuchElementException(qq.toString())
/**
* 获取一个 [Bot] 实例, 无对应实例时返回 `null`
*/
@JvmStatic
fun getInstanceOrNull(qq: Long): Bot? = BotImpl.getInstanceOrNull(qq = qq)
fun getInstanceOrNull(qq: Long): Bot? =
_instances.asSequence().mapNotNull { it.get() }.firstOrNull { it.id == qq }
}
init {
_instances.addLast(this.weakRef())
supervisorJob.invokeOnCompletion {
_instances.removeIf { it.get()?.id == this.id }
}
}
/**
......@@ -287,13 +302,6 @@ abstract class Bot : CoroutineScope, LowLevelBotAPIAccessor, BotJavaFriendlyAPI,
abstract fun close(cause: Throwable? = null)
final override fun toString(): String = "Bot($id)"
/**
* 网络模块.
* 此为内部 API: 它可能在任意时刻被改动.
*/
@MiraiInternalAPI
abstract val network: BotNetworkHandler
}
/**
......
......@@ -9,7 +9,7 @@
@file:JvmMultifileClass
@file:JvmName("BotEventsKt")
@file:Suppress("FunctionName")
@file:Suppress("FunctionName", "unused")
package net.mamoe.mirai.event.events
......@@ -53,6 +53,7 @@ data class FriendDeleteEvent(
/**
* 一个账号请求添加机器人为好友的事件
*/
@Suppress("DEPRECATION")
data class NewFriendRequestEvent(
override val bot: Bot,
/**
......
......@@ -16,7 +16,6 @@ package net.mamoe.mirai.message.data
import kotlinx.serialization.Serializable
import net.mamoe.mirai.Bot
import net.mamoe.mirai.BotImpl
import net.mamoe.mirai.contact.Contact
import net.mamoe.mirai.contact.Group
import net.mamoe.mirai.utils.ExternalImage
......@@ -188,7 +187,7 @@ suspend fun Image.queryUrl(): String {
@Suppress("DEPRECATION")
return when (this) {
is OnlineImage -> this.originUrl
else -> BotImpl.instances.peekFirst().get()?.queryImageUrl(this)
else -> Bot._instances.peekFirst().get()?.queryImageUrl(this)
?: error("No Bot available to query image url")
}
}
......@@ -243,7 +242,7 @@ interface OfflineImage : Image {
)
@JvmSynthetic
suspend fun OfflineImage.queryUrl(): String {
return BotImpl.instances.peekFirst().get()?.queryImageUrl(this) ?: error("No Bot available to query image url")
return Bot._instances.peekFirst().get()?.queryImageUrl(this) ?: error("No Bot available to query image url")
}
/**
......
package net.mamoe.mirai.qqandroid.network
import net.mamoe.mirai.utils.MiraiInternalAPI
/**
* 从服务器收到的包解析之后的结构化数据.
* 它是一个数据包工厂的处理的返回值.
*
* **InternalAPI**: 这是内部 API, 它随时都有可能被修改
*/
@MiraiInternalAPI
interface Packet {
/**
* 实现这个接口的包将不会被记录到日志中
......
......@@ -13,7 +13,6 @@ package net.mamoe.mirai.utils
import kotlinx.coroutines.Job
import kotlinx.coroutines.SupervisorJob
import net.mamoe.mirai.Bot
import net.mamoe.mirai.network.BotNetworkHandler
import kotlin.coroutines.CoroutineContext
import kotlin.coroutines.EmptyCoroutineContext
import kotlin.coroutines.coroutineContext
......@@ -33,7 +32,7 @@ open class BotConfiguration {
* 网络层日志构造器
* @see noNetworkLog 不显示网络日志
*/
var networkLoggerSupplier: ((BotNetworkHandler) -> MiraiLogger) = { DefaultLogger("Network(${it.bot.id})") }
var networkLoggerSupplier: ((Bot) -> MiraiLogger) = { DefaultLogger("Network(${it.id})") }
/**
* 设备信息覆盖. 默认使用随机的设备信息.
......@@ -105,7 +104,7 @@ open class BotConfiguration {
*/
@ConfigurationDsl
fun noNetworkLog() {
networkLoggerSupplier = { _: BotNetworkHandler -> SilentLogger }
networkLoggerSupplier = { _ -> SilentLogger }
}
/**
......
......@@ -6,6 +6,7 @@ import net.mamoe.mirai.message.MessageReceipt
import net.mamoe.mirai.message.data.Image
import net.mamoe.mirai.message.data.MessageChain
import net.mamoe.mirai.message.data.MessageSource
import net.mamoe.mirai.message.data.queryUrl
import net.mamoe.mirai.network.LoginFailedException
import net.mamoe.mirai.utils.MiraiExperimentalAPI
import net.mamoe.mirai.utils.MiraiInternalAPI
......@@ -29,6 +30,7 @@ internal actual interface BotJavaFriendlyAPI {
*
* @throws LoginFailedException
*/
@Throws(LoginFailedException::class)
@JvmName("login")
fun __loginBlockingForJava__() {
runBlocking { login() }
......@@ -94,7 +96,7 @@ internal actual interface BotJavaFriendlyAPI {
*/
@JvmName("queryImageUrl")
fun __queryImageUrlBlockingForJava__(image: Image): String {
return runBlocking { queryImageUrl(image) }
return runBlocking { image.queryUrl() }
}
/**
......@@ -134,7 +136,7 @@ internal actual interface BotJavaFriendlyAPI {
*/
@JvmName("queryImageUrlAsync")
fun __queryImageUrlAsyncForJava__(image: Image): Future<String> {
return future { queryImageUrl(image) }
return future { image.queryUrl() }
}
}
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment