QQAndroidBot.kt 12 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256
  1. /*
  2. * Copyright 2019-2021 Mamoe Technologies and contributors.
  3. *
  4. * 此源代码的使用受 GNU AFFERO GENERAL PUBLIC LICENSE version 3 许可证的约束, 可以在以下链接找到该许可证.
  5. * Use of this source code is governed by the GNU AGPLv3 license that can be found through the following link.
  6. *
  7. * https://github.com/mamoe/mirai/blob/master/LICENSE
  8. */
  9. @file:Suppress("EXPERIMENTAL_API_USAGE", "INVISIBLE_REFERENCE", "INVISIBLE_MEMBER")
  10. package net.mamoe.mirai.internal
  11. import kotlinx.atomicfu.atomic
  12. import kotlinx.coroutines.isActive
  13. import kotlinx.coroutines.runBlocking
  14. import net.mamoe.mirai.Bot
  15. import net.mamoe.mirai.event.events.BotOfflineEvent
  16. import net.mamoe.mirai.event.events.BotOnlineEvent
  17. import net.mamoe.mirai.event.events.BotReloginEvent
  18. import net.mamoe.mirai.internal.network.component.ComponentStorage
  19. import net.mamoe.mirai.internal.network.component.ComponentStorageDelegate
  20. import net.mamoe.mirai.internal.network.component.ConcurrentComponentStorage
  21. import net.mamoe.mirai.internal.network.component.withFallback
  22. import net.mamoe.mirai.internal.network.components.*
  23. import net.mamoe.mirai.internal.network.handler.NetworkHandler
  24. import net.mamoe.mirai.internal.network.handler.NetworkHandler.State
  25. import net.mamoe.mirai.internal.network.handler.NetworkHandlerContextImpl
  26. import net.mamoe.mirai.internal.network.handler.NetworkHandlerSupport
  27. import net.mamoe.mirai.internal.network.handler.NetworkHandlerSupport.BaseStateImpl
  28. import net.mamoe.mirai.internal.network.handler.selector.KeepAliveNetworkHandlerSelector
  29. import net.mamoe.mirai.internal.network.handler.selector.NetworkException
  30. import net.mamoe.mirai.internal.network.handler.selector.SelectorNetworkHandler
  31. import net.mamoe.mirai.internal.network.handler.state.CombinedStateObserver.Companion.plus
  32. import net.mamoe.mirai.internal.network.handler.state.LoggingStateObserver
  33. import net.mamoe.mirai.internal.network.handler.state.StateChangedObserver
  34. import net.mamoe.mirai.internal.network.handler.state.StateObserver
  35. import net.mamoe.mirai.internal.network.handler.state.safe
  36. import net.mamoe.mirai.internal.network.impl.netty.ForceOfflineException
  37. import net.mamoe.mirai.internal.network.impl.netty.NettyNetworkHandlerFactory
  38. import net.mamoe.mirai.internal.network.protocol.packet.login.StatSvc
  39. import net.mamoe.mirai.internal.network.notice.*
  40. import net.mamoe.mirai.internal.network.notice.decoders.MsgInfoDecoder
  41. import net.mamoe.mirai.internal.utils.subLogger
  42. import net.mamoe.mirai.utils.BotConfiguration
  43. import net.mamoe.mirai.utils.MiraiLogger
  44. import net.mamoe.mirai.utils.lateinitMutableProperty
  45. import kotlin.contracts.contract
  46. internal fun Bot.asQQAndroidBot(): QQAndroidBot {
  47. contract {
  48. returns() implies (this@asQQAndroidBot is QQAndroidBot)
  49. }
  50. return this as QQAndroidBot
  51. }
  52. @Suppress("INVISIBLE_MEMBER", "BooleanLiteralArgument", "OverridingDeprecatedMember")
  53. internal open class QQAndroidBot constructor(
  54. internal val account: BotAccount,
  55. configuration: BotConfiguration,
  56. ) : AbstractBot(configuration, account.id) {
  57. override val bot: QQAndroidBot get() = this
  58. val client get() = components[SsoProcessor].client
  59. override fun close(cause: Throwable?) {
  60. if (!this.isActive) return
  61. runBlocking {
  62. try { // this may not be very good but
  63. components[SsoProcessor].logout(network)
  64. } catch (ignored: Exception) {
  65. }
  66. }
  67. super.close(cause)
  68. }
  69. ///////////////////////////////////////////////////////////////////////////
  70. // network
  71. ///////////////////////////////////////////////////////////////////////////
  72. // also called by tests.
  73. fun ComponentStorage.stateObserverChain(): StateObserver {
  74. val components = this
  75. val eventDispatcher = this[EventDispatcher]
  76. return StateObserver.chainOfNotNull(
  77. components[BotInitProcessor].asObserver(),
  78. object : StateChangedObserver(State.OK) {
  79. private val shouldBroadcastRelogin = atomic(false)
  80. override fun stateChanged0(
  81. networkHandler: NetworkHandlerSupport,
  82. previous: BaseStateImpl,
  83. new: BaseStateImpl,
  84. ) {
  85. eventDispatcher.broadcastAsync(BotOnlineEvent(bot)).thenBroadcast(eventDispatcher) {
  86. if (!shouldBroadcastRelogin.compareAndSet(false, true)) {
  87. BotReloginEvent(bot, new.getCause())
  88. } else null
  89. }
  90. }
  91. override fun toString(): String = "StateChangedObserver(BotOnlineEventBroadcaster)"
  92. },
  93. StateChangedObserver("LastConnectedAddressUpdater", State.OK) {
  94. components[ServerList].run {
  95. lastConnectedIP = getLastPolledIP()
  96. }
  97. },
  98. StateChangedObserver("LastDisconnectedAddressUpdater", State.CLOSED) {
  99. components[ServerList].run {
  100. lastDisconnectedIP = lastConnectedIP
  101. }
  102. },
  103. StateChangedObserver("BotOfflineEventBroadcaster", State.OK, State.CLOSED) { new ->
  104. // logging performed by BotOfflineEventMonitor
  105. val cause = new.getCause()
  106. when {
  107. cause is ForceOfflineException -> {
  108. eventDispatcher.broadcastAsync(BotOfflineEvent.Force(bot, cause.title, cause.message))
  109. }
  110. cause is StatSvc.ReqMSFOffline.MsfOfflineToken -> {
  111. eventDispatcher.broadcastAsync(BotOfflineEvent.MsfOffline(bot, cause))
  112. }
  113. cause is NetworkException && cause.recoverable -> {
  114. eventDispatcher.broadcastAsync(BotOfflineEvent.Dropped(bot, cause))
  115. }
  116. cause is BotClosedByEvent -> {
  117. }
  118. else -> {
  119. // any other unexpected exceptions considered as an error
  120. eventDispatcher.broadcastAsync(BotOfflineEvent.Active(bot, cause))
  121. }
  122. }
  123. },
  124. ).safe(logger.subLogger("StateObserver")) + LoggingStateObserver.createLoggingIfEnabled()
  125. }
  126. private val networkLogger: MiraiLogger by lazy { configuration.networkLoggerSupplier(this) }
  127. final override val components: ComponentStorage get() = network.context
  128. private val defaultBotLevelComponents: ComponentStorage by lateinitMutableProperty {
  129. createBotLevelComponents().apply {
  130. set(StateObserver, stateObserverChain())
  131. }.also { components ->
  132. components[BotOfflineEventMonitor].attachJob(bot, this)
  133. }
  134. }
  135. open fun createBotLevelComponents(): ConcurrentComponentStorage = ConcurrentComponentStorage {
  136. val components = ComponentStorageDelegate { [email protected] }
  137. // There's no need to interrupt a broadcasting event when network handler closed.
  138. set(EventDispatcher, EventDispatcherImpl(bot.coroutineContext, logger.subLogger("EventDispatcher")))
  139. val pipelineLogger = networkLogger.subLogger("NoticeProcessor") // shorten name
  140. set(
  141. NoticeProcessorPipeline,
  142. NoticeProcessorPipelineImpl().apply {
  143. registerProcessor(MsgInfoDecoder(pipelineLogger))
  144. registerProcessor(FriendNoticeProcessor(pipelineLogger))
  145. registerProcessor(GroupListNoticeProcessor(pipelineLogger))
  146. registerProcessor(GroupMessageProcessor())
  147. registerProcessor(PrivateMessageNoticeProcessor())
  148. registerProcessor(OtherClientNoticeProcessor())
  149. registerProcessor(UnconsumedNoticesAlerter(pipelineLogger))
  150. },
  151. )
  152. set(SsoProcessorContext, SsoProcessorContextImpl(bot))
  153. set(SsoProcessor, SsoProcessorImpl(get(SsoProcessorContext)))
  154. set(HeartbeatProcessor, HeartbeatProcessorImpl())
  155. set(HeartbeatScheduler, TimeBasedHeartbeatSchedulerImpl(networkLogger.subLogger("HeartbeatScheduler")))
  156. set(KeyRefreshProcessor, KeyRefreshProcessorImpl(networkLogger.subLogger("KeyRefreshProcessor")))
  157. set(ConfigPushProcessor, ConfigPushProcessorImpl(networkLogger.subLogger("ConfigPushProcessor")))
  158. set(BotOfflineEventMonitor, BotOfflineEventMonitorImpl())
  159. set(BotInitProcessor, BotInitProcessorImpl(bot, components, networkLogger.subLogger("BotInitProcessor")))
  160. set(ContactCacheService, ContactCacheServiceImpl(bot, networkLogger.subLogger("ContactCacheService")))
  161. set(ContactUpdater, ContactUpdaterImpl(bot, components, networkLogger.subLogger("ContactUpdater")))
  162. set(
  163. BdhSessionSyncer,
  164. BdhSessionSyncerImpl(configuration, components, networkLogger.subLogger("BotSessionSyncer")),
  165. )
  166. set(
  167. MessageSvcSyncer,
  168. MessageSvcSyncerImpl(bot, bot.coroutineContext, networkLogger.subLogger("MessageSvcSyncer")),
  169. )
  170. set(
  171. EcdhInitialPublicKeyUpdater,
  172. EcdhInitialPublicKeyUpdaterImpl(bot, networkLogger.subLogger("ECDHInitialPublicKeyUpdater")),
  173. )
  174. set(ServerList, ServerListImpl(networkLogger.subLogger("ServerList")))
  175. set(PacketLoggingStrategy, PacketLoggingStrategyImpl(bot))
  176. set(
  177. PacketHandler,
  178. PacketHandlerChain(
  179. LoggingPacketHandlerAdapter(get(PacketLoggingStrategy), networkLogger),
  180. EventBroadcasterPacketHandler(components),
  181. CallPacketFactoryPacketHandler(bot),
  182. ),
  183. )
  184. set(PacketCodec, PacketCodecImpl())
  185. set(
  186. OtherClientUpdater,
  187. OtherClientUpdaterImpl(bot, components, networkLogger.subLogger("OtherClientUpdater")),
  188. )
  189. set(ConfigPushSyncer, ConfigPushSyncerImpl())
  190. set(
  191. AccountSecretsManager,
  192. configuration.createAccountsSecretsManager(bot.logger.subLogger("AccountSecretsManager")),
  193. )
  194. }
  195. /**
  196. * This would overrides those from [createBotLevelComponents]
  197. */
  198. open fun createNetworkLevelComponents(): ComponentStorage {
  199. return ConcurrentComponentStorage {
  200. set(BotClientHolder, BotClientHolderImpl(bot, networkLogger.subLogger("BotClientHolder")))
  201. set(SyncController, SyncControllerImpl())
  202. }.withFallback(defaultBotLevelComponents)
  203. }
  204. override fun createNetworkHandler(): NetworkHandler {
  205. return SelectorNetworkHandler(
  206. KeepAliveNetworkHandlerSelector(
  207. maxAttempts = configuration.reconnectionRetryTimes.coerceIn(1, Int.MAX_VALUE),
  208. logger = networkLogger.subLogger("Selector")
  209. ) {
  210. val context = NetworkHandlerContextImpl(
  211. bot,
  212. networkLogger,
  213. createNetworkLevelComponents(),
  214. )
  215. NettyNetworkHandlerFactory.create(
  216. context,
  217. context[ServerList].pollAny().toSocketAddress(),
  218. )
  219. },
  220. ) // We can move the factory to configuration but this is not necessary for now.
  221. }
  222. /**
  223. * 获取 获取群公告 所需的 bkn 参数
  224. * */ // TODO: 2021/4/26 extract it after #1141 merged
  225. val bkn: Int
  226. get() = client.wLoginSigInfo.sKey.data
  227. .fold(5381) { acc: Int, b: Byte -> acc + acc.shl(5) + b.toInt() }
  228. .and(Int.MAX_VALUE)
  229. }
  230. internal fun QQAndroidBot.getGroupByUinOrFail(uin: Long) =
  231. getGroupByUin(uin) ?: throw NoSuchElementException("group.uin=$uin")
  232. internal fun QQAndroidBot.getGroupByUin(uin: Long) = groups.firstOrNull { it.uin == uin }