From 05b2bfe0593442c0acca3cb622dfbf0cbd1b5069 Mon Sep 17 00:00:00 2001
From: Him188 <Him188@mamoe.net>
Date: Sat, 17 Apr 2021 13:39:59 +0800
Subject: [PATCH] Rearrange packages

---
 .../src/commonMain/kotlin/AbstractBot.kt      |  19 +--
 .../src/commonMain/kotlin/QQAndroidBot.kt     |  61 ++------
 .../commonMain/kotlin/contact/AbstractUser.kt |   2 +-
 .../commonMain/kotlin/contact/GroupImpl.kt    |   2 +-
 .../kotlin/network/QQAndroidClient.kt         |   3 +-
 .../kotlin/network/handler/NetworkHandler.kt  |  33 +----
 .../{impl => }/NetworkHandlerSupport.kt       |  24 ++--
 .../network/handler/SelectorNetworkHandler.kt | 132 ------------------
 .../components}/AccountSecretsManager.kt      |   4 +-
 .../{ => components}/BdhSessionSyncer.kt      |  62 ++++----
 .../components}/ContactUpdater.kt             |   4 +-
 .../components}/PacketDecoder.kt              |   3 +-
 .../handler/{ => components}/ServerList.kt    |   6 +-
 .../components}/SsoProcessor.kt               |  44 ++----
 .../network/handler/components/package.kt     |  13 ++
 .../{ => handler/context}/AccountSecrets.kt   |   5 +-
 .../network/handler/context/BdhSession.kt     |  21 +++
 .../handler/context/NetworkHandlerContext.kt  |  41 ++++++
 .../handler/context/SsoProcessorContext.kt    |  47 +++++++
 .../context}/SsoSession.kt                    |   5 +-
 .../kotlin/network/handler/context/package.kt |  13 ++
 .../handler/impl/netty/NettyNetworkHandler.kt |  10 +-
 ...ctory.kt => NettyNetworkHandlerFactory.kt} |   2 +-
 ...AbstractKeepAliveNetworkHandlerSelector.kt |  61 ++++++++
 .../ExceptionInSelectorResumeException.kt     |  14 ++
 .../FactoryKeepAliveNetworkHandlerSelector.kt |  27 ++++
 .../selector/NetworkHandlerSelector.kt        |  32 +++++
 .../selector/NoServerAvailableException.kt    |  13 ++
 .../selector/SelectorNetworkHandler.kt        |  48 +++++++
 .../handler/state/CombinedStateObserver.kt    |  54 +++++++
 .../ExceptionInStateObserverException.kt      |  14 ++
 .../handler/state/LoggingStateObserver.kt     |  57 ++++++++
 .../SafeStateObserver.kt}                     |  88 +-----------
 .../network/handler/state/StateObserver.kt    |  51 +++++++
 .../kotlin/network/highway/Highway.kt         |   2 +-
 .../network/protocol/packet/PacketFactory.kt  |   4 +-
 .../network/protocol/packet/chat/MultiMsg.kt  |   2 +-
 .../protocol/packet/login/ConfigPushSvc.kt    |   8 +-
 .../kotlin/network/ServerListTest.kt          |   4 +-
 ...ractKeepAliveNetworkHandlerSelectorTest.kt |   1 +
 .../kotlin/network/handler/testUtils.kt       |  12 +-
 .../commonTest/kotlin/network/sessionUtils.kt |   4 +-
 42 files changed, 625 insertions(+), 427 deletions(-)
 rename mirai-core/src/commonMain/kotlin/network/handler/{impl => }/NetworkHandlerSupport.kt (91%)
 delete mode 100644 mirai-core/src/commonMain/kotlin/network/handler/SelectorNetworkHandler.kt
 rename mirai-core/src/commonMain/kotlin/network/{ => handler/components}/AccountSecretsManager.kt (95%)
 rename mirai-core/src/commonMain/kotlin/network/handler/{ => components}/BdhSessionSyncer.kt (61%)
 rename mirai-core/src/commonMain/kotlin/network/{ => handler/components}/ContactUpdater.kt (98%)
 rename mirai-core/src/commonMain/kotlin/network/{net/protocol => handler/components}/PacketDecoder.kt (98%)
 rename mirai-core/src/commonMain/kotlin/network/handler/{ => components}/ServerList.kt (94%)
 rename mirai-core/src/commonMain/kotlin/network/{net/protocol => handler/components}/SsoProcessor.kt (89%)
 create mode 100644 mirai-core/src/commonMain/kotlin/network/handler/components/package.kt
 rename mirai-core/src/commonMain/kotlin/network/{ => handler/context}/AccountSecrets.kt (92%)
 create mode 100644 mirai-core/src/commonMain/kotlin/network/handler/context/BdhSession.kt
 create mode 100644 mirai-core/src/commonMain/kotlin/network/handler/context/NetworkHandlerContext.kt
 create mode 100644 mirai-core/src/commonMain/kotlin/network/handler/context/SsoProcessorContext.kt
 rename mirai-core/src/commonMain/kotlin/network/{net/protocol => handler/context}/SsoSession.kt (81%)
 create mode 100644 mirai-core/src/commonMain/kotlin/network/handler/context/package.kt
 rename mirai-core/src/commonMain/kotlin/network/handler/impl/netty/{NetyNetworkHandlerFactory.kt => NettyNetworkHandlerFactory.kt} (91%)
 create mode 100644 mirai-core/src/commonMain/kotlin/network/handler/selector/AbstractKeepAliveNetworkHandlerSelector.kt
 create mode 100644 mirai-core/src/commonMain/kotlin/network/handler/selector/ExceptionInSelectorResumeException.kt
 create mode 100644 mirai-core/src/commonMain/kotlin/network/handler/selector/FactoryKeepAliveNetworkHandlerSelector.kt
 create mode 100644 mirai-core/src/commonMain/kotlin/network/handler/selector/NetworkHandlerSelector.kt
 create mode 100644 mirai-core/src/commonMain/kotlin/network/handler/selector/NoServerAvailableException.kt
 create mode 100644 mirai-core/src/commonMain/kotlin/network/handler/selector/SelectorNetworkHandler.kt
 create mode 100644 mirai-core/src/commonMain/kotlin/network/handler/state/CombinedStateObserver.kt
 create mode 100644 mirai-core/src/commonMain/kotlin/network/handler/state/ExceptionInStateObserverException.kt
 create mode 100644 mirai-core/src/commonMain/kotlin/network/handler/state/LoggingStateObserver.kt
 rename mirai-core/src/commonMain/kotlin/network/handler/{impl/StateObserver.kt => state/SafeStateObserver.kt} (53%)
 create mode 100644 mirai-core/src/commonMain/kotlin/network/handler/state/StateObserver.kt

diff --git a/mirai-core/src/commonMain/kotlin/AbstractBot.kt b/mirai-core/src/commonMain/kotlin/AbstractBot.kt
index 3298eee55..30e169ea7 100644
--- a/mirai-core/src/commonMain/kotlin/AbstractBot.kt
+++ b/mirai-core/src/commonMain/kotlin/AbstractBot.kt
@@ -22,15 +22,18 @@ import kotlinx.coroutines.sync.Mutex
 import net.mamoe.mirai.Bot
 import net.mamoe.mirai.Mirai
 import net.mamoe.mirai.contact.*
-import net.mamoe.mirai.event.*
+import net.mamoe.mirai.event.ConcurrencyKind
+import net.mamoe.mirai.event.EventChannel
 import net.mamoe.mirai.event.EventPriority.MONITOR
+import net.mamoe.mirai.event.GlobalEventChannel
+import net.mamoe.mirai.event.Listener
 import net.mamoe.mirai.event.events.BotEvent
 import net.mamoe.mirai.event.events.BotOfflineEvent
 import net.mamoe.mirai.internal.contact.info.FriendInfoImpl
 import net.mamoe.mirai.internal.contact.info.StrangerInfoImpl
 import net.mamoe.mirai.internal.contact.uin
 import net.mamoe.mirai.internal.network.handler.NetworkHandler
-import net.mamoe.mirai.internal.network.handler.ServerList
+import net.mamoe.mirai.internal.network.handler.components.ServerList
 import net.mamoe.mirai.supervisorJob
 import net.mamoe.mirai.utils.*
 import kotlin.coroutines.CoroutineContext
@@ -169,21 +172,11 @@ internal abstract class AbstractBot constructor(
     // network
     ///////////////////////////////////////////////////////////////////////////
 
-    internal val serverList: MutableList<Pair<String, Int>> = mutableListOf() // TODO: 2021/4/16 remove old
     internal val serverListNew = ServerList() // TODO: 2021/4/16 load server list from cache (add a provider)
     // bot.bdhSyncer.loadServerListFromCache()
 
-    // TODO: 2021/4/14 handle serverList
+    val network: NetworkHandler by lazy { createNetworkHandler(coroutineContext) }
 
-    val network: NetworkHandler by lazy {
-        createNetworkHandler(coroutineContext)
-    }
-
-
-    /**
-     * **Exposed public API**
-     * [AbstractBot.relogin] && [BotNetworkHandler.init]
-     */
     final override suspend fun login() {
         if (!isActive) error("Bot is already closed and cannot relogin. Please create a new Bot instance then do login.")
         network.resumeConnection()
diff --git a/mirai-core/src/commonMain/kotlin/QQAndroidBot.kt b/mirai-core/src/commonMain/kotlin/QQAndroidBot.kt
index d4cd5a2f5..d98b361fd 100644
--- a/mirai-core/src/commonMain/kotlin/QQAndroidBot.kt
+++ b/mirai-core/src/commonMain/kotlin/QQAndroidBot.kt
@@ -19,22 +19,22 @@ import net.mamoe.mirai.internal.contact.OtherClientImpl
 import net.mamoe.mirai.internal.contact.checkIsGroupImpl
 import net.mamoe.mirai.internal.network.*
 import net.mamoe.mirai.internal.network.handler.*
-import net.mamoe.mirai.internal.network.handler.impl.LoggingStateObserver
-import net.mamoe.mirai.internal.network.handler.impl.SafeStateObserver
-import net.mamoe.mirai.internal.network.handler.impl.StateObserver
+import net.mamoe.mirai.internal.network.handler.components.BdhSessionSyncer
+import net.mamoe.mirai.internal.network.handler.components.SsoProcessor
+import net.mamoe.mirai.internal.network.handler.context.NetworkHandlerContextImpl
+import net.mamoe.mirai.internal.network.handler.context.SsoProcessorContextImpl
 import net.mamoe.mirai.internal.network.handler.impl.netty.NettyNetworkHandlerFactory
-import net.mamoe.mirai.internal.network.net.protocol.SsoProcessor
-import net.mamoe.mirai.internal.network.net.protocol.SsoProcessorContextImpl
+import net.mamoe.mirai.internal.network.handler.selector.FactoryKeepAliveNetworkHandlerSelector
+import net.mamoe.mirai.internal.network.handler.selector.SelectorNetworkHandler
+import net.mamoe.mirai.internal.network.handler.state.LoggingStateObserver
+import net.mamoe.mirai.internal.network.handler.state.SafeStateObserver
+import net.mamoe.mirai.internal.network.handler.state.StateObserver
 import net.mamoe.mirai.internal.network.protocol.packet.OutgoingPacket
 import net.mamoe.mirai.internal.network.protocol.packet.OutgoingPacketWithRespType
 import net.mamoe.mirai.internal.network.protocol.packet.login.StatSvc
-import net.mamoe.mirai.internal.network.protocol.packet.login.WtLogin
 import net.mamoe.mirai.internal.utils.ScheduledJob
-import net.mamoe.mirai.internal.utils.crypto.TEA
 import net.mamoe.mirai.internal.utils.friendCacheFile
-import net.mamoe.mirai.internal.utils.io.serialization.toByteArray
 import net.mamoe.mirai.utils.*
-import java.io.File
 import kotlin.contracts.contract
 import kotlin.coroutines.CoroutineContext
 
@@ -71,7 +71,7 @@ internal class QQAndroidBot constructor(
 ) : AbstractBot(configuration, account.id) {
     override val bot: QQAndroidBot get() = this
 
-    val bdhSyncer: BdhSessionSyncer = BdhSessionSyncer(this)
+    val bdhSyncer: BdhSessionSyncer by lazy { BdhSessionSyncer(configuration, serverListNew, network.logger) }
     internal var firstLoginSucceed: Boolean = false
 
     ///////////////////////////////////////////////////////////////////////////
@@ -180,45 +180,4 @@ internal class QQAndroidBot constructor(
             bot.network.context.logger.info { "Saved ${friendListCache.list.size} friends to local cache." }
         }
     }
-
-    ///////////////////////////////////////////////////////////////////////////
-    // Account secrets cache
-    ///////////////////////////////////////////////////////////////////////////
-
-    // We cannot extract these logics until we rewrite the network framework.
-
-    private val cacheDir: File by lazy {
-        configuration.workingDir.resolve(bot.configuration.cacheDir).apply { mkdirs() }
-    }
-    private val accountSecretsFile: File by lazy {
-        cacheDir.resolve("account.secrets")
-    }
-
-    private fun saveSecrets(secrets: AccountSecretsImpl) {
-        if (secrets.wLoginSigInfoField == null) return
-
-        accountSecretsFile.writeBytes(
-            TEA.encrypt(
-                secrets.toByteArray(AccountSecretsImpl.serializer()),
-                account.passwordMd5
-            )
-        )
-
-        network.context.logger.info { "Saved account secrets to local cache for fast login." }
-    }
-
-    init {
-        if (configuration.loginCacheEnabled) {
-            eventChannel.parentScope(this).subscribeAlways<WtLogin.Login.LoginPacketResponse> { event ->
-                if (event is WtLogin.Login.LoginPacketResponse.Success) {
-                    if (client.wLoginSigInfoInitialized) {
-                        saveSecrets(AccountSecretsImpl(client))
-                    }
-                }
-            }
-        }
-    }
-
-    /////////////////////////// accounts secrets end
-
 }
diff --git a/mirai-core/src/commonMain/kotlin/contact/AbstractUser.kt b/mirai-core/src/commonMain/kotlin/contact/AbstractUser.kt
index efa03a2a1..eb4b5acfe 100644
--- a/mirai-core/src/commonMain/kotlin/contact/AbstractUser.kt
+++ b/mirai-core/src/commonMain/kotlin/contact/AbstractUser.kt
@@ -18,7 +18,7 @@ import net.mamoe.mirai.event.events.*
 import net.mamoe.mirai.internal.message.OfflineFriendImage
 import net.mamoe.mirai.internal.message.contextualBugReportException
 import net.mamoe.mirai.internal.message.getImageType
-import net.mamoe.mirai.internal.network.handler.BdhSession
+import net.mamoe.mirai.internal.network.handler.context.BdhSession
 import net.mamoe.mirai.internal.network.highway.ChannelKind
 import net.mamoe.mirai.internal.network.highway.Highway
 import net.mamoe.mirai.internal.network.highway.ResourceKind.PRIVATE_IMAGE
diff --git a/mirai-core/src/commonMain/kotlin/contact/GroupImpl.kt b/mirai-core/src/commonMain/kotlin/contact/GroupImpl.kt
index 379549321..f80538ee2 100644
--- a/mirai-core/src/commonMain/kotlin/contact/GroupImpl.kt
+++ b/mirai-core/src/commonMain/kotlin/contact/GroupImpl.kt
@@ -22,8 +22,8 @@ import net.mamoe.mirai.event.events.*
 import net.mamoe.mirai.internal.QQAndroidBot
 import net.mamoe.mirai.internal.contact.info.MemberInfoImpl
 import net.mamoe.mirai.internal.message.OfflineGroupImage
-import net.mamoe.mirai.internal.network.handler.BdhSession
 import net.mamoe.mirai.internal.network.handler.NetworkHandler
+import net.mamoe.mirai.internal.network.handler.context.BdhSession
 import net.mamoe.mirai.internal.network.highway.ChannelKind
 import net.mamoe.mirai.internal.network.highway.Highway
 import net.mamoe.mirai.internal.network.highway.ResourceKind.GROUP_IMAGE
diff --git a/mirai-core/src/commonMain/kotlin/network/QQAndroidClient.kt b/mirai-core/src/commonMain/kotlin/network/QQAndroidClient.kt
index 3ef9d28ce..7d180ff64 100644
--- a/mirai-core/src/commonMain/kotlin/network/QQAndroidClient.kt
+++ b/mirai-core/src/commonMain/kotlin/network/QQAndroidClient.kt
@@ -19,7 +19,8 @@ import kotlinx.io.core.toByteArray
 import net.mamoe.mirai.data.OnlineStatus
 import net.mamoe.mirai.internal.BotAccount
 import net.mamoe.mirai.internal.QQAndroidBot
-import net.mamoe.mirai.internal.network.net.protocol.SsoSession
+import net.mamoe.mirai.internal.network.handler.context.AccountSecrets
+import net.mamoe.mirai.internal.network.handler.context.SsoSession
 import net.mamoe.mirai.internal.network.protocol.SyncingCacheList
 import net.mamoe.mirai.internal.network.protocol.data.jce.FileStoragePushFSSvcList
 import net.mamoe.mirai.internal.network.protocol.packet.Tlv
diff --git a/mirai-core/src/commonMain/kotlin/network/handler/NetworkHandler.kt b/mirai-core/src/commonMain/kotlin/network/handler/NetworkHandler.kt
index 274063889..fb6a656ac 100644
--- a/mirai-core/src/commonMain/kotlin/network/handler/NetworkHandler.kt
+++ b/mirai-core/src/commonMain/kotlin/network/handler/NetworkHandler.kt
@@ -9,12 +9,9 @@
 
 package net.mamoe.mirai.internal.network.handler
 
-import net.mamoe.mirai.Bot
-import net.mamoe.mirai.internal.QQAndroidBot
 import net.mamoe.mirai.internal.network.Packet
 import net.mamoe.mirai.internal.network.handler.NetworkHandler.State
-import net.mamoe.mirai.internal.network.handler.impl.StateObserver
-import net.mamoe.mirai.internal.network.net.protocol.SsoProcessor
+import net.mamoe.mirai.internal.network.handler.context.NetworkHandlerContext
 import net.mamoe.mirai.internal.network.protocol.packet.OutgoingPacket
 import net.mamoe.mirai.internal.network.protocol.packet.OutgoingPacketWithRespType
 import net.mamoe.mirai.utils.MiraiLogger
@@ -23,34 +20,12 @@ import java.net.InetSocketAddress
 import java.net.SocketAddress
 import java.util.concurrent.CancellationException
 
-/**
- * Immutable context for [NetworkHandler]
- */
-internal interface NetworkHandlerContext {
-    val bot: QQAndroidBot
-    // however migration requires a major change.
-
-    val logger: MiraiLogger
-    val ssoProcessor: SsoProcessor
-
-    val stateObserver: StateObserver?
-}
-
-internal class NetworkHandlerContextImpl(
-    override val bot: QQAndroidBot,
-    override val ssoProcessor: SsoProcessor,
-    override val logger: MiraiLogger,
-    override val stateObserver: StateObserver?,
-) : NetworkHandlerContext {
-    override fun toString(): String {
-        return "NetworkHandlerContextImpl(bot=${bot.id}, stateObserver=$stateObserver)"
-    }
-}
-
 /**
  * Basic interface available to application. Usually wrapped with [SelectorNetworkHandler].
  *
- * A [NetworkHandler] holds no reference to [Bot]s.
+ * Implementation is usually subclass of [NetworkHandlerSupport].
+ *
+ * @see NetworkHandlerSupport
  */
 internal interface NetworkHandler {
     val context: NetworkHandlerContext
diff --git a/mirai-core/src/commonMain/kotlin/network/handler/impl/NetworkHandlerSupport.kt b/mirai-core/src/commonMain/kotlin/network/handler/NetworkHandlerSupport.kt
similarity index 91%
rename from mirai-core/src/commonMain/kotlin/network/handler/impl/NetworkHandlerSupport.kt
rename to mirai-core/src/commonMain/kotlin/network/handler/NetworkHandlerSupport.kt
index 974a4ff62..26db0eaa0 100644
--- a/mirai-core/src/commonMain/kotlin/network/handler/impl/NetworkHandlerSupport.kt
+++ b/mirai-core/src/commonMain/kotlin/network/handler/NetworkHandlerSupport.kt
@@ -7,22 +7,22 @@
  *  https://github.com/mamoe/mirai/blob/master/LICENSE
  */
 
-package net.mamoe.mirai.internal.network.handler.impl
+package net.mamoe.mirai.internal.network.handler
 
 import kotlinx.coroutines.*
 import net.mamoe.mirai.internal.network.Packet
-import net.mamoe.mirai.internal.network.handler.NetworkHandler
-import net.mamoe.mirai.internal.network.handler.NetworkHandlerContext
-import net.mamoe.mirai.internal.network.handler.logger
-import net.mamoe.mirai.internal.network.net.protocol.PacketCodec.PACKET_DEBUG
-import net.mamoe.mirai.internal.network.net.protocol.RawIncomingPacket
+import net.mamoe.mirai.internal.network.handler.components.PacketCodec
+import net.mamoe.mirai.internal.network.handler.components.RawIncomingPacket
+import net.mamoe.mirai.internal.network.handler.context.NetworkHandlerContext
 import net.mamoe.mirai.internal.network.protocol.packet.IncomingPacket
 import net.mamoe.mirai.internal.network.protocol.packet.OutgoingPacket
 import net.mamoe.mirai.utils.*
 import java.util.concurrent.ConcurrentLinkedQueue
 import kotlin.coroutines.CoroutineContext
 
-
+/**
+ * Implements basic logics of [NetworkHandler]
+ */
 internal abstract class NetworkHandlerSupport(
     override val context: NetworkHandlerContext,
     final override val coroutineContext: CoroutineContext = SupervisorJob(),
@@ -95,7 +95,7 @@ internal abstract class NetworkHandlerSupport(
     }
 
     protected val packetLogger: MiraiLogger by lazy {
-        MiraiLogger.create(context.logger.identity + ".debug").withSwitch(PACKET_DEBUG)
+        MiraiLogger.create(context.logger.identity + ".debug").withSwitch(PacketCodec.PACKET_DEBUG)
     }
 
     ///////////////////////////////////////////////////////////////////////////
@@ -173,9 +173,9 @@ internal abstract class NetworkHandlerSupport(
     }
 
     /**
-     * You may need to call [BaseStateImpl.resumeConnection] since state is lazy.
+     * Calculate [new state][new] and set it as the current.
      *
-     * Do not check for instances of [BaseStateImpl]. Instances may be decorated by [StateObserver] for extended functionality.
+     * You may need to call [BaseStateImpl.resumeConnection] to activate the new state, as states are lazy.
      */
     protected inline fun <S : BaseStateImpl> setState(crossinline new: () -> S): S = synchronized(this) {
         // we can add hooks here for debug.
@@ -200,6 +200,4 @@ internal abstract class NetworkHandlerSupport(
     final override suspend fun resumeConnection() {
         _state.resumeConnection()
     }
-}
-
-
+}
\ No newline at end of file
diff --git a/mirai-core/src/commonMain/kotlin/network/handler/SelectorNetworkHandler.kt b/mirai-core/src/commonMain/kotlin/network/handler/SelectorNetworkHandler.kt
deleted file mode 100644
index 1d0d812e6..000000000
--- a/mirai-core/src/commonMain/kotlin/network/handler/SelectorNetworkHandler.kt
+++ /dev/null
@@ -1,132 +0,0 @@
-/*
- * Copyright 2019-2021 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.internal.network.handler
-
-import kotlinx.atomicfu.atomic
-import net.mamoe.mirai.internal.network.handler.NetworkHandler.State
-import net.mamoe.mirai.internal.network.protocol.packet.OutgoingPacket
-import org.jetbrains.annotations.TestOnly
-
-/**
- * A proxy to [NetworkHandler] that delegates calls to instance returned by [NetworkHandlerSelector.awaitResumeInstance].
- *
- * [NetworkHandlerSelector.awaitResumeInstance] is called everytime when an operation in [NetworkHandler] is called.
- *
- * This is useful to implement a delegation of [NetworkHandler]. The functionality of *selection* is provided by the strategy [selector][NetworkHandlerSelector].
- * @see NetworkHandlerSelector
- */
-internal class SelectorNetworkHandler(
-    override val context: NetworkHandlerContext, // impl notes: may consider to move into function member.
-    private val selector: NetworkHandlerSelector<*>,
-) : NetworkHandler {
-    private suspend inline fun instance(): NetworkHandler = selector.awaitResumeInstance()
-
-    override val state: State
-        get() = selector.getResumedInstance()?.state ?: State.INITIALIZED
-
-    override suspend fun resumeConnection() {
-        instance() // the selector will resume connection for us.
-    }
-
-    override suspend fun sendAndExpect(packet: OutgoingPacket, timeout: Long, attempts: Int) =
-        instance().sendAndExpect(packet, timeout, attempts)
-
-    override suspend fun sendWithoutExpect(packet: OutgoingPacket) = instance().sendWithoutExpect(packet)
-    override fun close(cause: Throwable?) {
-        selector.getResumedInstance()?.close(cause)
-    }
-
-    override fun toString(): String = "SelectorNetworkHandler(currentInstance=${selector.getResumedInstance()})"
-}
-
-internal class ExceptionInSelectorResumeException(
-    cause: Throwable
-) : RuntimeException(cause)
-
-/**
- * A lazy stateful selector of [NetworkHandler]. This is used as a director([selector][SelectorNetworkHandler.selector]) to [SelectorNetworkHandler].
- */
-internal interface NetworkHandlerSelector<H : NetworkHandler> {
-    /**
-     * Returns an instance immediately without suspension, or `null` if instance not ready.
-     *
-     * This function should not throw any exception.
-     * @see awaitResumeInstance
-     */
-    fun getResumedInstance(): H?
-
-    /**
-     * Returns an alive [NetworkHandler], or suspends the coroutine until the connection has been made again.
-     *
-     * This function may throw exceptions, which would be propagated to the original caller of [SelectorNetworkHandler.resumeConnection].
-     */
-    suspend fun awaitResumeInstance(): H
-}
-
-/**
- * A lazy stateful implementation of [NetworkHandlerSelector].
- *
- * - Calls [factory.create][NetworkHandlerFactory.create] to create [NetworkHandler]s.
- * - Re-initialize [NetworkHandler] instances if the old one is dead.
- * - Suspends requests when connection is not available.
- *
- * No connection is created until first invocation of [getResumedInstance],
- * and new connections are created only when calling [getResumedInstance] if the old connection was dead.
- */
-// may be replaced with a better name.
-internal abstract class AbstractKeepAliveNetworkHandlerSelector<H : NetworkHandler> : NetworkHandlerSelector<H> {
-    private val current = atomic<H?>(null)
-
-    @TestOnly
-    internal fun setCurrent(h: H) {
-        current.value = h
-    }
-
-    protected abstract fun createInstance(): H
-
-    final override fun getResumedInstance(): H? = current.value
-
-    final override tailrec suspend fun awaitResumeInstance(): H {
-        val current = getResumedInstance()
-        return if (current != null) {
-            when (current.state) {
-                State.CLOSED -> {
-                    this.current.compareAndSet(current, null) // invalidate the instance and try again.
-                    awaitResumeInstance() // will create new instance.
-                }
-                State.CONNECTING,
-                State.CONNECTION_LOST,
-                State.INITIALIZED,
-                State.OK -> {
-                    current.resumeConnection()
-                    return current
-                }
-            }
-        } else {
-            this.current.compareAndSet(current, createInstance())
-            awaitResumeInstance()
-        }
-    }
-}
-
-/**
- * [AbstractKeepAliveNetworkHandlerSelector] implementation delegating [createInstance] to [factory]
- */
-internal class FactoryKeepAliveNetworkHandlerSelector<H : NetworkHandler>(
-    private val factory: NetworkHandlerFactory<H>,
-    private val serverList: ServerList,
-    private val context: NetworkHandlerContext,
-) : AbstractKeepAliveNetworkHandlerSelector<H>() {
-    override fun createInstance(): H =
-        factory.create(context, serverList.pollCurrent()?.toSocketAddress() ?: throw NoServerAvailableException())
-}
-
-internal class NoServerAvailableException :
-    NoSuchElementException("No server available. (Failed to connect to any of the servers)")
\ No newline at end of file
diff --git a/mirai-core/src/commonMain/kotlin/network/AccountSecretsManager.kt b/mirai-core/src/commonMain/kotlin/network/handler/components/AccountSecretsManager.kt
similarity index 95%
rename from mirai-core/src/commonMain/kotlin/network/AccountSecretsManager.kt
rename to mirai-core/src/commonMain/kotlin/network/handler/components/AccountSecretsManager.kt
index 3d4765b97..0603d0fad 100644
--- a/mirai-core/src/commonMain/kotlin/network/AccountSecretsManager.kt
+++ b/mirai-core/src/commonMain/kotlin/network/handler/components/AccountSecretsManager.kt
@@ -7,10 +7,12 @@
  *  https://github.com/mamoe/mirai/blob/master/LICENSE
  */
 
-package net.mamoe.mirai.internal.network
+package net.mamoe.mirai.internal.network.handler.components
 
 import net.mamoe.mirai.Bot
 import net.mamoe.mirai.internal.BotAccount
+import net.mamoe.mirai.internal.network.handler.context.AccountSecrets
+import net.mamoe.mirai.internal.network.handler.context.AccountSecretsImpl
 import net.mamoe.mirai.internal.utils.actualCacheDir
 import net.mamoe.mirai.internal.utils.crypto.TEA
 import net.mamoe.mirai.internal.utils.io.serialization.loadAs
diff --git a/mirai-core/src/commonMain/kotlin/network/handler/BdhSessionSyncer.kt b/mirai-core/src/commonMain/kotlin/network/handler/components/BdhSessionSyncer.kt
similarity index 61%
rename from mirai-core/src/commonMain/kotlin/network/handler/BdhSessionSyncer.kt
rename to mirai-core/src/commonMain/kotlin/network/handler/components/BdhSessionSyncer.kt
index 229e68c85..c78d16c63 100644
--- a/mirai-core/src/commonMain/kotlin/network/handler/BdhSessionSyncer.kt
+++ b/mirai-core/src/commonMain/kotlin/network/handler/components/BdhSessionSyncer.kt
@@ -7,32 +7,28 @@
  *  https://github.com/mamoe/mirai/blob/master/LICENSE
  */
 
-package net.mamoe.mirai.internal.network.handler
+package net.mamoe.mirai.internal.network.handler.components
 
 import kotlinx.coroutines.CompletableDeferred
 import kotlinx.coroutines.ExperimentalCoroutinesApi
 import kotlinx.serialization.KSerializer
-import kotlinx.serialization.Serializable
-import kotlinx.serialization.builtins.ListSerializer
-import net.mamoe.mirai.internal.QQAndroidBot
+import kotlinx.serialization.builtins.SetSerializer
 import net.mamoe.mirai.internal.network.JsonForCache
 import net.mamoe.mirai.internal.network.ProtoBufForCache
+import net.mamoe.mirai.internal.network.handler.context.BdhSession
 import net.mamoe.mirai.internal.utils.actualCacheDir
+import net.mamoe.mirai.utils.BotConfiguration
+import net.mamoe.mirai.utils.MiraiLogger
 import java.io.File
-import java.util.concurrent.CopyOnWriteArraySet
 
-@Serializable
-private data class ServerHostAndPort(
-    val host: String,
-    val port: Int,
-)
-
-private val ServerListSerializer: KSerializer<List<ServerHostAndPort>> =
-    ListSerializer(ServerHostAndPort.serializer())
+private val ServerListSerializer: KSerializer<Set<ServerAddress>> =
+    SetSerializer(ServerAddress.serializer())
 
 @OptIn(ExperimentalCoroutinesApi::class)
 internal class BdhSessionSyncer(
-    private val bot: QQAndroidBot
+    private val configuration: BotConfiguration,
+    private val serverList: ServerList,
+    private val logger: MiraiLogger,
 ) {
     var bdhSession: CompletableDeferred<BdhSession> = CompletableDeferred()
     val hasSession: Boolean
@@ -50,30 +46,29 @@ internal class BdhSessionSyncer(
     }
 
     private val sessionCacheFile: File
-        get() = bot.configuration.actualCacheDir().resolve("session.bin")
+        get() = configuration.actualCacheDir().resolve("session.bin")
     private val serverListCacheFile: File
-        get() = bot.configuration.actualCacheDir().resolve("servers.json")
+        get() = configuration.actualCacheDir().resolve("servers.json")
 
     fun loadServerListFromCache() {
         val serverListCacheFile = this.serverListCacheFile
         if (serverListCacheFile.isFile) {
-            bot.network.logger.verbose("Loading server list from cache.")
+            logger.verbose("Loading server list from cache.")
             kotlin.runCatching {
                 val list = JsonForCache.decodeFromString(ServerListSerializer, serverListCacheFile.readText())
-                bot.serverList.clear()
-                bot.serverList.addAll(list.map { it.host to it.port })
+                serverList.setPreferred(list.map { ServerAddress(it.host, it.port) })
             }.onFailure {
-                bot.network.logger.warning("Error in loading server list from cache", it)
+                logger.warning("Error in loading server list from cache", it)
             }
         } else {
-            bot.network.logger.verbose("No server list cached.")
+            logger.verbose("No server list cached.")
         }
     }
 
     fun loadFromCache() {
         val sessionCacheFile = this.sessionCacheFile
         if (sessionCacheFile.isFile) {
-            bot.network.logger.verbose("Loading BdhSession from cache file")
+            logger.verbose("Loading BdhSession from cache file")
             kotlin.runCatching {
                 overrideSession(
                     ProtoBufForCache.decodeFromByteArray(BdhSession.serializer(), sessionCacheFile.readBytes()),
@@ -81,10 +76,10 @@ internal class BdhSessionSyncer(
                 )
             }.onFailure {
                 kotlin.runCatching { sessionCacheFile.delete() }
-                bot.network.logger.warning("Error in loading BdhSession from cache", it)
+                logger.warning("Error in loading BdhSession from cache", it)
             }
         } else {
-            bot.network.logger.verbose("No BdhSession cache")
+            logger.verbose("No BdhSession cache")
         }
     }
 
@@ -92,16 +87,16 @@ internal class BdhSessionSyncer(
         val serverListCacheFile = this.serverListCacheFile
         serverListCacheFile.parentFile?.mkdirs()
 
-        bot.network.logger.verbose("Saving server list to cache")
+        logger.verbose("Saving server list to cache")
         kotlin.runCatching {
             serverListCacheFile.writeText(
                 JsonForCache.encodeToString(
                     ServerListSerializer,
-                    bot.serverList.map { ServerHostAndPort(it.first, it.second) }
+                    serverList.getPreferred()
                 )
             )
         }.onFailure {
-            bot.network.logger.warning("Error in saving ServerList to cache.", it)
+            logger.warning("Error in saving ServerList to cache.", it)
         }
     }
 
@@ -109,7 +104,7 @@ internal class BdhSessionSyncer(
         val sessionCacheFile = this.sessionCacheFile
         sessionCacheFile.parentFile?.mkdirs()
         if (bdhSession.isCompleted) {
-            bot.network.logger.verbose("Saving bdh session to cache")
+            logger.verbose("Saving bdh session to cache")
             kotlin.runCatching {
                 sessionCacheFile.writeBytes(
                     ProtoBufForCache.encodeToByteArray(
@@ -118,20 +113,13 @@ internal class BdhSessionSyncer(
                     )
                 )
             }.onFailure {
-                bot.network.logger.warning("Error in saving BdhSession to cache.", it)
+                logger.warning("Error in saving BdhSession to cache.", it)
             }
         } else {
             sessionCacheFile.delete()
-            bot.network.logger.verbose("No BdhSession to save to cache")
+            logger.verbose("No BdhSession to save to cache")
         }
 
     }
 }
 
-@Serializable
-internal class BdhSession(
-    val sigSession: ByteArray,
-    val sessionKey: ByteArray,
-    var ssoAddresses: MutableSet<Pair<Int, Int>> = CopyOnWriteArraySet(),
-    var otherAddresses: MutableSet<Pair<Int, Int>> = CopyOnWriteArraySet(),
-)
\ No newline at end of file
diff --git a/mirai-core/src/commonMain/kotlin/network/ContactUpdater.kt b/mirai-core/src/commonMain/kotlin/network/handler/components/ContactUpdater.kt
similarity index 98%
rename from mirai-core/src/commonMain/kotlin/network/ContactUpdater.kt
rename to mirai-core/src/commonMain/kotlin/network/handler/components/ContactUpdater.kt
index 961d162d6..28d0bd686 100644
--- a/mirai-core/src/commonMain/kotlin/network/ContactUpdater.kt
+++ b/mirai-core/src/commonMain/kotlin/network/handler/components/ContactUpdater.kt
@@ -7,7 +7,7 @@
  * https://github.com/mamoe/mirai/blob/master/LICENSE
  */
 
-package net.mamoe.mirai.internal.network
+package net.mamoe.mirai.internal.network.handler.components
 
 import kotlinx.coroutines.CancellationException
 import kotlinx.coroutines.cancel
@@ -27,7 +27,9 @@ import net.mamoe.mirai.internal.contact.info.GroupInfoImpl
 import net.mamoe.mirai.internal.contact.info.MemberInfoImpl
 import net.mamoe.mirai.internal.contact.info.StrangerInfoImpl
 import net.mamoe.mirai.internal.contact.toMiraiFriendInfo
+import net.mamoe.mirai.internal.network.Packet
 import net.mamoe.mirai.internal.network.handler.logger
+import net.mamoe.mirai.internal.network.isValid
 import net.mamoe.mirai.internal.network.protocol.data.jce.StTroopNum
 import net.mamoe.mirai.internal.network.protocol.data.jce.SvcRespRegister
 import net.mamoe.mirai.internal.network.protocol.data.jce.isValid
diff --git a/mirai-core/src/commonMain/kotlin/network/net/protocol/PacketDecoder.kt b/mirai-core/src/commonMain/kotlin/network/handler/components/PacketDecoder.kt
similarity index 98%
rename from mirai-core/src/commonMain/kotlin/network/net/protocol/PacketDecoder.kt
rename to mirai-core/src/commonMain/kotlin/network/handler/components/PacketDecoder.kt
index 8389fdc8b..2e03e8b2a 100644
--- a/mirai-core/src/commonMain/kotlin/network/net/protocol/PacketDecoder.kt
+++ b/mirai-core/src/commonMain/kotlin/network/handler/components/PacketDecoder.kt
@@ -7,10 +7,11 @@
  *  https://github.com/mamoe/mirai/blob/master/LICENSE
  */
 
-package net.mamoe.mirai.internal.network.net.protocol
+package net.mamoe.mirai.internal.network.handler.components
 
 import kotlinx.io.core.*
 import net.mamoe.mirai.internal.QQAndroidBot
+import net.mamoe.mirai.internal.network.handler.context.SsoSession
 import net.mamoe.mirai.internal.network.protocol.packet.*
 import net.mamoe.mirai.internal.utils.crypto.TEA
 import net.mamoe.mirai.internal.utils.crypto.adjustToPublicKey
diff --git a/mirai-core/src/commonMain/kotlin/network/handler/ServerList.kt b/mirai-core/src/commonMain/kotlin/network/handler/components/ServerList.kt
similarity index 94%
rename from mirai-core/src/commonMain/kotlin/network/handler/ServerList.kt
rename to mirai-core/src/commonMain/kotlin/network/handler/components/ServerList.kt
index b78757616..c1a3566a8 100644
--- a/mirai-core/src/commonMain/kotlin/network/handler/ServerList.kt
+++ b/mirai-core/src/commonMain/kotlin/network/handler/components/ServerList.kt
@@ -7,11 +7,13 @@
  *  https://github.com/mamoe/mirai/blob/master/LICENSE
  */
 
-package net.mamoe.mirai.internal.network.handler
+package net.mamoe.mirai.internal.network.handler.components
 
+import kotlinx.serialization.Serializable
 import java.net.InetSocketAddress
 import java.util.*
 
+@Serializable
 internal data class ServerAddress(
     val host: String,
     val port: Int
@@ -42,6 +44,8 @@ internal class ServerList(
         preferred = list.toSet()
     }
 
+    fun getPreferred() = preferred
+
     init {
         refresh()
     }
diff --git a/mirai-core/src/commonMain/kotlin/network/net/protocol/SsoProcessor.kt b/mirai-core/src/commonMain/kotlin/network/handler/components/SsoProcessor.kt
similarity index 89%
rename from mirai-core/src/commonMain/kotlin/network/net/protocol/SsoProcessor.kt
rename to mirai-core/src/commonMain/kotlin/network/handler/components/SsoProcessor.kt
index 0e2827123..97392f45c 100644
--- a/mirai-core/src/commonMain/kotlin/network/net/protocol/SsoProcessor.kt
+++ b/mirai-core/src/commonMain/kotlin/network/handler/components/SsoProcessor.kt
@@ -7,12 +7,15 @@
  *  https://github.com/mamoe/mirai/blob/master/LICENSE
  */
 
-package net.mamoe.mirai.internal.network.net.protocol
+package net.mamoe.mirai.internal.network.handler.components
 
-import net.mamoe.mirai.internal.BotAccount
 import net.mamoe.mirai.internal.QQAndroidBot
-import net.mamoe.mirai.internal.network.*
+import net.mamoe.mirai.internal.network.Packet
+import net.mamoe.mirai.internal.network.QQAndroidClient
 import net.mamoe.mirai.internal.network.handler.NetworkHandler
+import net.mamoe.mirai.internal.network.handler.context.AccountSecretsImpl
+import net.mamoe.mirai.internal.network.handler.context.SsoProcessorContext
+import net.mamoe.mirai.internal.network.handler.context.SsoSession
 import net.mamoe.mirai.internal.network.handler.impl.netty.NettyNetworkHandler
 import net.mamoe.mirai.internal.network.protocol.packet.OutgoingPacketWithRespType
 import net.mamoe.mirai.internal.network.protocol.packet.login.WtLogin.Login.LoginPacketResponse
@@ -23,34 +26,10 @@ import net.mamoe.mirai.internal.network.protocol.packet.login.wtlogin.WtLogin20
 import net.mamoe.mirai.internal.network.protocol.packet.login.wtlogin.WtLogin9
 import net.mamoe.mirai.internal.network.protocol.packet.sendAndExpect
 import net.mamoe.mirai.network.*
-import net.mamoe.mirai.utils.*
 import net.mamoe.mirai.utils.BotConfiguration.MiraiProtocol
-
-/**
- * Provides the information needed by the [SsoProcessor].
- */
-internal interface SsoProcessorContext {
-    val bot: QQAndroidBot
-
-    val account: BotAccount
-    val device: DeviceInfo
-
-    val protocol: MiraiProtocol
-
-    val accountSecretsManager: AccountSecretsManager
-
-    val configuration: BotConfiguration
-}
-
-internal class SsoProcessorContextImpl(
-    override val bot: QQAndroidBot
-) : SsoProcessorContext {
-    override val account: BotAccount get() = bot.account
-    override val device: DeviceInfo = configuration.deviceInfo?.invoke(bot) ?: DeviceInfo.random()
-    override val protocol: MiraiProtocol get() = configuration.protocol
-    override val accountSecretsManager: AccountSecretsManager get() = configuration.createAccountsSecretsManager(bot.logger)
-    override val configuration: BotConfiguration get() = bot.configuration
-}
+import net.mamoe.mirai.utils.LoginSolver
+import net.mamoe.mirai.utils.info
+import net.mamoe.mirai.utils.withExceptionCollector
 
 /**
  * Strategy that performs the process of single sing-on (SSO). (login)
@@ -60,7 +39,7 @@ internal class SsoProcessorContextImpl(
  * Used by [NettyNetworkHandler.StateConnecting].
  */
 internal class SsoProcessor(
-    private val ssoContext: SsoProcessorContext,
+    internal val ssoContext: SsoProcessorContext,
 ) {
     @Volatile
     internal var client = createClient(ssoContext.bot)
@@ -71,7 +50,7 @@ internal class SsoProcessor(
      * Do login. Throws [LoginFailedException] if failed
      */
     @Throws(LoginFailedException::class)
-    suspend fun login(handler: NetworkHandler) = withExceptionCollector<Unit> {
+    suspend fun login(handler: NetworkHandler) = withExceptionCollector {
         if (client.wLoginSigInfoInitialized) {
             kotlin.runCatching {
                 FastLoginImpl(handler).doLogin()
@@ -83,6 +62,7 @@ internal class SsoProcessor(
             client = createClient(ssoContext.bot)
             SlowLoginImpl(handler).doLogin()
         }
+        ssoContext.accountSecretsManager.saveSecrets(ssoContext.account, AccountSecretsImpl(client))
     }
 
     private fun createClient(bot: QQAndroidBot): QQAndroidClient {
diff --git a/mirai-core/src/commonMain/kotlin/network/handler/components/package.kt b/mirai-core/src/commonMain/kotlin/network/handler/components/package.kt
new file mode 100644
index 000000000..531bef7db
--- /dev/null
+++ b/mirai-core/src/commonMain/kotlin/network/handler/components/package.kt
@@ -0,0 +1,13 @@
+/*
+ * Copyright 2019-2021 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.internal.network.handler.components
\ No newline at end of file
diff --git a/mirai-core/src/commonMain/kotlin/network/AccountSecrets.kt b/mirai-core/src/commonMain/kotlin/network/handler/context/AccountSecrets.kt
similarity index 92%
rename from mirai-core/src/commonMain/kotlin/network/AccountSecrets.kt
rename to mirai-core/src/commonMain/kotlin/network/handler/context/AccountSecrets.kt
index a2d4adc4f..1afa04f83 100644
--- a/mirai-core/src/commonMain/kotlin/network/AccountSecrets.kt
+++ b/mirai-core/src/commonMain/kotlin/network/handler/context/AccountSecrets.kt
@@ -7,11 +7,14 @@
  *  https://github.com/mamoe/mirai/blob/master/LICENSE
  */
 
-package net.mamoe.mirai.internal.network
+package net.mamoe.mirai.internal.network.handler.context
 
 import kotlinx.io.core.toByteArray
 import kotlinx.serialization.Serializable
 import net.mamoe.mirai.internal.BotAccount
+import net.mamoe.mirai.internal.network.LoginExtraData
+import net.mamoe.mirai.internal.network.WLoginSigInfo
+import net.mamoe.mirai.internal.network.getRandomByteArray
 import net.mamoe.mirai.internal.network.protocol.packet.login.wtlogin.get_mpasswd
 import net.mamoe.mirai.internal.utils.io.ProtoBuf
 import net.mamoe.mirai.utils.DeviceInfo
diff --git a/mirai-core/src/commonMain/kotlin/network/handler/context/BdhSession.kt b/mirai-core/src/commonMain/kotlin/network/handler/context/BdhSession.kt
new file mode 100644
index 000000000..e811afb91
--- /dev/null
+++ b/mirai-core/src/commonMain/kotlin/network/handler/context/BdhSession.kt
@@ -0,0 +1,21 @@
+/*
+ * Copyright 2019-2021 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.internal.network.handler.context
+
+import kotlinx.serialization.Serializable
+import java.util.concurrent.CopyOnWriteArraySet
+
+@Serializable
+internal class BdhSession(
+    val sigSession: ByteArray,
+    val sessionKey: ByteArray,
+    var ssoAddresses: MutableSet<Pair<Int, Int>> = CopyOnWriteArraySet(),
+    var otherAddresses: MutableSet<Pair<Int, Int>> = CopyOnWriteArraySet(),
+)
\ No newline at end of file
diff --git a/mirai-core/src/commonMain/kotlin/network/handler/context/NetworkHandlerContext.kt b/mirai-core/src/commonMain/kotlin/network/handler/context/NetworkHandlerContext.kt
new file mode 100644
index 000000000..4595faa10
--- /dev/null
+++ b/mirai-core/src/commonMain/kotlin/network/handler/context/NetworkHandlerContext.kt
@@ -0,0 +1,41 @@
+/*
+ * Copyright 2019-2021 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.internal.network.handler.context
+
+import net.mamoe.mirai.internal.QQAndroidBot
+import net.mamoe.mirai.internal.network.handler.NetworkHandler
+import net.mamoe.mirai.internal.network.handler.components.SsoProcessor
+import net.mamoe.mirai.internal.network.handler.state.StateObserver
+import net.mamoe.mirai.utils.MiraiLogger
+
+/**
+ * Immutable context for [NetworkHandler]
+ * @see NetworkHandlerContextImpl
+ */
+internal interface NetworkHandlerContext {
+    val bot: QQAndroidBot
+    // however migration requires a major change.
+
+    val logger: MiraiLogger
+    val ssoProcessor: SsoProcessor
+
+    val stateObserver: StateObserver?
+}
+
+internal class NetworkHandlerContextImpl(
+    override val bot: QQAndroidBot,
+    override val ssoProcessor: SsoProcessor,
+    override val logger: MiraiLogger,
+    override val stateObserver: StateObserver?,
+) : NetworkHandlerContext {
+    override fun toString(): String {
+        return "NetworkHandlerContextImpl(bot=${bot.id}, stateObserver=$stateObserver)"
+    }
+}
diff --git a/mirai-core/src/commonMain/kotlin/network/handler/context/SsoProcessorContext.kt b/mirai-core/src/commonMain/kotlin/network/handler/context/SsoProcessorContext.kt
new file mode 100644
index 000000000..df80e0d7e
--- /dev/null
+++ b/mirai-core/src/commonMain/kotlin/network/handler/context/SsoProcessorContext.kt
@@ -0,0 +1,47 @@
+/*
+ * Copyright 2019-2021 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.internal.network.handler.context
+
+import net.mamoe.mirai.internal.BotAccount
+import net.mamoe.mirai.internal.QQAndroidBot
+import net.mamoe.mirai.internal.network.handler.components.AccountSecretsManager
+import net.mamoe.mirai.internal.network.handler.components.SsoProcessor
+import net.mamoe.mirai.internal.network.handler.components.createAccountsSecretsManager
+import net.mamoe.mirai.utils.BotConfiguration
+import net.mamoe.mirai.utils.DeviceInfo
+
+/**
+ * Provides the information needed by the [SsoProcessor].
+ */
+internal interface SsoProcessorContext {
+    /**
+     * Use other properties instead. Use [bot] only when you cannot find other properties.
+     */
+    val bot: QQAndroidBot
+
+    val account: BotAccount
+    val device: DeviceInfo
+
+    val protocol: BotConfiguration.MiraiProtocol
+
+    val accountSecretsManager: AccountSecretsManager
+
+    val configuration: BotConfiguration
+}
+
+internal class SsoProcessorContextImpl(
+    override val bot: QQAndroidBot
+) : SsoProcessorContext {
+    override val account: BotAccount get() = bot.account
+    override val device: DeviceInfo = configuration.deviceInfo?.invoke(bot) ?: DeviceInfo.random()
+    override val protocol: BotConfiguration.MiraiProtocol get() = configuration.protocol
+    override val accountSecretsManager: AccountSecretsManager get() = configuration.createAccountsSecretsManager(bot.logger)
+    override val configuration: BotConfiguration get() = bot.configuration
+}
diff --git a/mirai-core/src/commonMain/kotlin/network/net/protocol/SsoSession.kt b/mirai-core/src/commonMain/kotlin/network/handler/context/SsoSession.kt
similarity index 81%
rename from mirai-core/src/commonMain/kotlin/network/net/protocol/SsoSession.kt
rename to mirai-core/src/commonMain/kotlin/network/handler/context/SsoSession.kt
index f3e4748fb..458549f50 100644
--- a/mirai-core/src/commonMain/kotlin/network/net/protocol/SsoSession.kt
+++ b/mirai-core/src/commonMain/kotlin/network/handler/context/SsoSession.kt
@@ -7,10 +7,11 @@
  *  https://github.com/mamoe/mirai/blob/master/LICENSE
  */
 
-package net.mamoe.mirai.internal.network.net.protocol
+package net.mamoe.mirai.internal.network.handler.context
 
-import net.mamoe.mirai.internal.network.AccountSecrets
 import net.mamoe.mirai.internal.network.WLoginSigInfo
+import net.mamoe.mirai.internal.network.handler.components.PacketCodec
+import net.mamoe.mirai.internal.network.handler.components.SsoProcessor
 import net.mamoe.mirai.internal.utils.crypto.ECDH
 
 /**
diff --git a/mirai-core/src/commonMain/kotlin/network/handler/context/package.kt b/mirai-core/src/commonMain/kotlin/network/handler/context/package.kt
new file mode 100644
index 000000000..617a3a925
--- /dev/null
+++ b/mirai-core/src/commonMain/kotlin/network/handler/context/package.kt
@@ -0,0 +1,13 @@
+/*
+ * Copyright 2019-2021 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
+ */
+
+/**
+ * 放各种 context
+ */
+package net.mamoe.mirai.internal.network.handler.context
\ No newline at end of file
diff --git a/mirai-core/src/commonMain/kotlin/network/handler/impl/netty/NettyNetworkHandler.kt b/mirai-core/src/commonMain/kotlin/network/handler/impl/netty/NettyNetworkHandler.kt
index b097ba053..997e5c497 100644
--- a/mirai-core/src/commonMain/kotlin/network/handler/impl/netty/NettyNetworkHandler.kt
+++ b/mirai-core/src/commonMain/kotlin/network/handler/impl/netty/NettyNetworkHandler.kt
@@ -23,12 +23,12 @@ import kotlinx.coroutines.channels.sendBlocking
 import kotlinx.coroutines.flow.collect
 import kotlinx.coroutines.flow.consumeAsFlow
 import net.mamoe.mirai.internal.network.handler.NetworkHandler
-import net.mamoe.mirai.internal.network.handler.NetworkHandlerContext
-import net.mamoe.mirai.internal.network.handler.impl.NetworkHandlerSupport
+import net.mamoe.mirai.internal.network.handler.NetworkHandlerSupport
+import net.mamoe.mirai.internal.network.handler.components.PacketCodec
+import net.mamoe.mirai.internal.network.handler.components.RawIncomingPacket
+import net.mamoe.mirai.internal.network.handler.components.SsoProcessor
+import net.mamoe.mirai.internal.network.handler.context.NetworkHandlerContext
 import net.mamoe.mirai.internal.network.handler.logger
-import net.mamoe.mirai.internal.network.net.protocol.PacketCodec
-import net.mamoe.mirai.internal.network.net.protocol.RawIncomingPacket
-import net.mamoe.mirai.internal.network.net.protocol.SsoProcessor
 import net.mamoe.mirai.internal.network.protocol.packet.OutgoingPacket
 import net.mamoe.mirai.utils.childScope
 import net.mamoe.mirai.utils.debug
diff --git a/mirai-core/src/commonMain/kotlin/network/handler/impl/netty/NetyNetworkHandlerFactory.kt b/mirai-core/src/commonMain/kotlin/network/handler/impl/netty/NettyNetworkHandlerFactory.kt
similarity index 91%
rename from mirai-core/src/commonMain/kotlin/network/handler/impl/netty/NetyNetworkHandlerFactory.kt
rename to mirai-core/src/commonMain/kotlin/network/handler/impl/netty/NettyNetworkHandlerFactory.kt
index 0cb2806c9..5914000c5 100644
--- a/mirai-core/src/commonMain/kotlin/network/handler/impl/netty/NetyNetworkHandlerFactory.kt
+++ b/mirai-core/src/commonMain/kotlin/network/handler/impl/netty/NettyNetworkHandlerFactory.kt
@@ -9,8 +9,8 @@
 
 package net.mamoe.mirai.internal.network.handler.impl.netty
 
-import net.mamoe.mirai.internal.network.handler.NetworkHandlerContext
 import net.mamoe.mirai.internal.network.handler.NetworkHandlerFactory
+import net.mamoe.mirai.internal.network.handler.context.NetworkHandlerContext
 import java.net.SocketAddress
 
 internal object NettyNetworkHandlerFactory : NetworkHandlerFactory<NettyNetworkHandler> {
diff --git a/mirai-core/src/commonMain/kotlin/network/handler/selector/AbstractKeepAliveNetworkHandlerSelector.kt b/mirai-core/src/commonMain/kotlin/network/handler/selector/AbstractKeepAliveNetworkHandlerSelector.kt
new file mode 100644
index 000000000..4f872dc8b
--- /dev/null
+++ b/mirai-core/src/commonMain/kotlin/network/handler/selector/AbstractKeepAliveNetworkHandlerSelector.kt
@@ -0,0 +1,61 @@
+/*
+ * Copyright 2019-2021 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.internal.network.handler.selector
+
+import kotlinx.atomicfu.atomic
+import net.mamoe.mirai.internal.network.handler.NetworkHandler
+import net.mamoe.mirai.internal.network.handler.NetworkHandlerFactory
+import org.jetbrains.annotations.TestOnly
+
+/**
+ * A lazy stateful implementation of [NetworkHandlerSelector].
+ *
+ * - Calls [factory.create][NetworkHandlerFactory.create] to create [NetworkHandler]s.
+ * - Re-initialize [NetworkHandler] instances if the old one is dead.
+ * - Suspends requests when connection is not available.
+ *
+ * No connection is created until first invocation of [getResumedInstance],
+ * and new connections are created only when calling [getResumedInstance] if the old connection was dead.
+ */
+// may be replaced with a better name.
+internal abstract class AbstractKeepAliveNetworkHandlerSelector<H : NetworkHandler> : NetworkHandlerSelector<H> {
+    private val current = atomic<H?>(null)
+
+    @TestOnly
+    internal fun setCurrent(h: H) {
+        current.value = h
+    }
+
+    protected abstract fun createInstance(): H
+
+    final override fun getResumedInstance(): H? = current.value
+
+    final override tailrec suspend fun awaitResumeInstance(): H {
+        val current = getResumedInstance()
+        return if (current != null) {
+            when (current.state) {
+                NetworkHandler.State.CLOSED -> {
+                    this.current.compareAndSet(current, null) // invalidate the instance and try again.
+                    awaitResumeInstance() // will create new instance.
+                }
+                NetworkHandler.State.CONNECTING,
+                NetworkHandler.State.CONNECTION_LOST,
+                NetworkHandler.State.INITIALIZED,
+                NetworkHandler.State.OK -> {
+                    current.resumeConnection()
+                    return current
+                }
+            }
+        } else {
+            this.current.compareAndSet(current, createInstance())
+            awaitResumeInstance()
+        }
+    }
+}
\ No newline at end of file
diff --git a/mirai-core/src/commonMain/kotlin/network/handler/selector/ExceptionInSelectorResumeException.kt b/mirai-core/src/commonMain/kotlin/network/handler/selector/ExceptionInSelectorResumeException.kt
new file mode 100644
index 000000000..c82cd959a
--- /dev/null
+++ b/mirai-core/src/commonMain/kotlin/network/handler/selector/ExceptionInSelectorResumeException.kt
@@ -0,0 +1,14 @@
+/*
+ * Copyright 2019-2021 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.internal.network.handler.selector
+
+internal class ExceptionInSelectorResumeException(
+    cause: Throwable
+) : RuntimeException(cause)
\ No newline at end of file
diff --git a/mirai-core/src/commonMain/kotlin/network/handler/selector/FactoryKeepAliveNetworkHandlerSelector.kt b/mirai-core/src/commonMain/kotlin/network/handler/selector/FactoryKeepAliveNetworkHandlerSelector.kt
new file mode 100644
index 000000000..a033a2e98
--- /dev/null
+++ b/mirai-core/src/commonMain/kotlin/network/handler/selector/FactoryKeepAliveNetworkHandlerSelector.kt
@@ -0,0 +1,27 @@
+/*
+ * Copyright 2019-2021 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.internal.network.handler.selector
+
+import net.mamoe.mirai.internal.network.handler.NetworkHandler
+import net.mamoe.mirai.internal.network.handler.NetworkHandlerFactory
+import net.mamoe.mirai.internal.network.handler.components.ServerList
+import net.mamoe.mirai.internal.network.handler.context.NetworkHandlerContext
+
+/**
+ * [AbstractKeepAliveNetworkHandlerSelector] implementation delegating [createInstance] to [factory]
+ */
+internal class FactoryKeepAliveNetworkHandlerSelector<H : NetworkHandler>(
+    private val factory: NetworkHandlerFactory<H>,
+    private val serverList: ServerList,
+    private val context: NetworkHandlerContext,
+) : AbstractKeepAliveNetworkHandlerSelector<H>() {
+    override fun createInstance(): H =
+        factory.create(context, serverList.pollCurrent()?.toSocketAddress() ?: throw NoServerAvailableException())
+}
\ No newline at end of file
diff --git a/mirai-core/src/commonMain/kotlin/network/handler/selector/NetworkHandlerSelector.kt b/mirai-core/src/commonMain/kotlin/network/handler/selector/NetworkHandlerSelector.kt
new file mode 100644
index 000000000..fb3274b08
--- /dev/null
+++ b/mirai-core/src/commonMain/kotlin/network/handler/selector/NetworkHandlerSelector.kt
@@ -0,0 +1,32 @@
+/*
+ * Copyright 2019-2021 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.internal.network.handler.selector
+
+import net.mamoe.mirai.internal.network.handler.NetworkHandler
+
+/**
+ * A lazy stateful selector of [NetworkHandler]. This is used as a director([selector][SelectorNetworkHandler.selector]) to [SelectorNetworkHandler].
+ */
+internal interface NetworkHandlerSelector<H : NetworkHandler> {
+    /**
+     * Returns an instance immediately without suspension, or `null` if instance not ready.
+     *
+     * This function should not throw any exception.
+     * @see awaitResumeInstance
+     */
+    fun getResumedInstance(): H?
+
+    /**
+     * Returns an alive [NetworkHandler], or suspends the coroutine until the connection has been made again.
+     *
+     * This function may throw exceptions, which would be propagated to the original caller of [SelectorNetworkHandler.resumeConnection].
+     */
+    suspend fun awaitResumeInstance(): H
+}
\ No newline at end of file
diff --git a/mirai-core/src/commonMain/kotlin/network/handler/selector/NoServerAvailableException.kt b/mirai-core/src/commonMain/kotlin/network/handler/selector/NoServerAvailableException.kt
new file mode 100644
index 000000000..166eed6f5
--- /dev/null
+++ b/mirai-core/src/commonMain/kotlin/network/handler/selector/NoServerAvailableException.kt
@@ -0,0 +1,13 @@
+/*
+ * Copyright 2019-2021 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.internal.network.handler.selector
+
+internal class NoServerAvailableException :
+    NoSuchElementException("No server available. (Failed to connect to any of the servers)")
\ No newline at end of file
diff --git a/mirai-core/src/commonMain/kotlin/network/handler/selector/SelectorNetworkHandler.kt b/mirai-core/src/commonMain/kotlin/network/handler/selector/SelectorNetworkHandler.kt
new file mode 100644
index 000000000..3df20abca
--- /dev/null
+++ b/mirai-core/src/commonMain/kotlin/network/handler/selector/SelectorNetworkHandler.kt
@@ -0,0 +1,48 @@
+/*
+ * Copyright 2019-2021 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.internal.network.handler.selector
+
+import net.mamoe.mirai.internal.network.handler.NetworkHandler
+import net.mamoe.mirai.internal.network.handler.NetworkHandler.State
+import net.mamoe.mirai.internal.network.handler.context.NetworkHandlerContext
+import net.mamoe.mirai.internal.network.protocol.packet.OutgoingPacket
+
+/**
+ * A proxy to [NetworkHandler] that delegates calls to instance returned by [NetworkHandlerSelector.awaitResumeInstance].
+ *
+ * [NetworkHandlerSelector.awaitResumeInstance] is called everytime when an operation in [NetworkHandler] is called.
+ *
+ * This is useful to implement a delegation of [NetworkHandler]. The functionality of *selection* is provided by the strategy [selector][NetworkHandlerSelector].
+ * @see NetworkHandlerSelector
+ */
+internal class SelectorNetworkHandler(
+    override val context: NetworkHandlerContext, // impl notes: may consider to move into function member.
+    private val selector: NetworkHandlerSelector<*>,
+) : NetworkHandler {
+    private suspend inline fun instance(): NetworkHandler = selector.awaitResumeInstance()
+
+    override val state: State
+        get() = selector.getResumedInstance()?.state ?: State.INITIALIZED
+
+    override suspend fun resumeConnection() {
+        instance() // the selector will resume connection for us.
+    }
+
+    override suspend fun sendAndExpect(packet: OutgoingPacket, timeout: Long, attempts: Int) =
+        instance().sendAndExpect(packet, timeout, attempts)
+
+    override suspend fun sendWithoutExpect(packet: OutgoingPacket) = instance().sendWithoutExpect(packet)
+    override fun close(cause: Throwable?) {
+        selector.getResumedInstance()?.close(cause)
+    }
+
+    override fun toString(): String = "SelectorNetworkHandler(currentInstance=${selector.getResumedInstance()})"
+}
+
diff --git a/mirai-core/src/commonMain/kotlin/network/handler/state/CombinedStateObserver.kt b/mirai-core/src/commonMain/kotlin/network/handler/state/CombinedStateObserver.kt
new file mode 100644
index 000000000..0afe52161
--- /dev/null
+++ b/mirai-core/src/commonMain/kotlin/network/handler/state/CombinedStateObserver.kt
@@ -0,0 +1,54 @@
+/*
+ * Copyright 2019-2021 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.internal.network.handler.state
+
+import net.mamoe.mirai.internal.network.handler.NetworkHandler
+import net.mamoe.mirai.internal.network.handler.NetworkHandlerSupport
+
+internal class CombinedStateObserver(
+    private val first: StateObserver,
+    private val last: StateObserver,
+) : StateObserver {
+    override fun stateChanged(
+        networkHandler: NetworkHandlerSupport,
+        previous: NetworkHandlerSupport.BaseStateImpl,
+        new: NetworkHandlerSupport.BaseStateImpl
+    ) {
+        first.stateChanged(networkHandler, previous, new)
+        last.stateChanged(networkHandler, previous, new)
+    }
+
+    override fun exceptionOnCreatingNewState(
+        networkHandler: NetworkHandlerSupport,
+        previousState: NetworkHandlerSupport.BaseStateImpl,
+        exception: Throwable
+    ) {
+        first.exceptionOnCreatingNewState(networkHandler, previousState, exception)
+        last.exceptionOnCreatingNewState(networkHandler, previousState, exception)
+    }
+
+    override fun beforeStateResume(networkHandler: NetworkHandler, state: NetworkHandlerSupport.BaseStateImpl) {
+        first.beforeStateResume(networkHandler, state)
+        last.beforeStateResume(networkHandler, state)
+    }
+
+    override fun afterStateResume(
+        networkHandler: NetworkHandler,
+        state: NetworkHandlerSupport.BaseStateImpl,
+        result: Result<Unit>
+    ) {
+        first.afterStateResume(networkHandler, state, result)
+        last.afterStateResume(networkHandler, state, result)
+    }
+
+    companion object {
+        operator fun StateObserver.plus(last: StateObserver): StateObserver = CombinedStateObserver(this, last)
+    }
+}
\ No newline at end of file
diff --git a/mirai-core/src/commonMain/kotlin/network/handler/state/ExceptionInStateObserverException.kt b/mirai-core/src/commonMain/kotlin/network/handler/state/ExceptionInStateObserverException.kt
new file mode 100644
index 000000000..d701d7d01
--- /dev/null
+++ b/mirai-core/src/commonMain/kotlin/network/handler/state/ExceptionInStateObserverException.kt
@@ -0,0 +1,14 @@
+/*
+ * Copyright 2019-2021 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.internal.network.handler.state
+
+internal class ExceptionInStateObserverException(
+    override val cause: Throwable
+) : RuntimeException()
\ No newline at end of file
diff --git a/mirai-core/src/commonMain/kotlin/network/handler/state/LoggingStateObserver.kt b/mirai-core/src/commonMain/kotlin/network/handler/state/LoggingStateObserver.kt
new file mode 100644
index 000000000..9e6f8375d
--- /dev/null
+++ b/mirai-core/src/commonMain/kotlin/network/handler/state/LoggingStateObserver.kt
@@ -0,0 +1,57 @@
+/*
+ * Copyright 2019-2021 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.internal.network.handler.state
+
+import net.mamoe.mirai.internal.network.handler.NetworkHandler
+import net.mamoe.mirai.internal.network.handler.NetworkHandlerSupport
+import net.mamoe.mirai.utils.MiraiLogger
+import net.mamoe.mirai.utils.debug
+
+internal class LoggingStateObserver(
+    val logger: MiraiLogger
+) : StateObserver {
+    override fun toString(): String {
+        return "LoggingStateObserver(logger=$logger)"
+    }
+
+    override fun stateChanged(
+        networkHandler: NetworkHandlerSupport,
+        previous: NetworkHandlerSupport.BaseStateImpl,
+        new: NetworkHandlerSupport.BaseStateImpl
+    ) {
+        logger.debug { "State changed: ${previous.correspondingState} -> ${new.correspondingState}" }
+    }
+
+    override fun exceptionOnCreatingNewState(
+        networkHandler: NetworkHandlerSupport,
+        previousState: NetworkHandlerSupport.BaseStateImpl,
+        exception: Throwable
+    ) {
+        logger.debug({ "State changed: ${previousState.correspondingState} -> $exception" }, exception)
+    }
+
+    override fun afterStateResume(
+        networkHandler: NetworkHandler,
+        state: NetworkHandlerSupport.BaseStateImpl,
+        result: Result<Unit>
+    ) {
+        result.fold(
+            onSuccess = {
+                logger.debug { "State resumed: ${state.correspondingState}." }
+            },
+            onFailure = {
+                logger.debug(
+                    { "State resumed: ${state.correspondingState} ${result.exceptionOrNull()}" },
+                    result.exceptionOrNull()
+                )
+            }
+        )
+    }
+}
\ No newline at end of file
diff --git a/mirai-core/src/commonMain/kotlin/network/handler/impl/StateObserver.kt b/mirai-core/src/commonMain/kotlin/network/handler/state/SafeStateObserver.kt
similarity index 53%
rename from mirai-core/src/commonMain/kotlin/network/handler/impl/StateObserver.kt
rename to mirai-core/src/commonMain/kotlin/network/handler/state/SafeStateObserver.kt
index 4de51ea10..1c66832c5 100644
--- a/mirai-core/src/commonMain/kotlin/network/handler/impl/StateObserver.kt
+++ b/mirai-core/src/commonMain/kotlin/network/handler/state/SafeStateObserver.kt
@@ -7,97 +7,13 @@
  *  https://github.com/mamoe/mirai/blob/master/LICENSE
  */
 
-package net.mamoe.mirai.internal.network.handler.impl
+package net.mamoe.mirai.internal.network.handler.state
 
 import net.mamoe.mirai.internal.network.handler.NetworkHandler
+import net.mamoe.mirai.internal.network.handler.NetworkHandlerSupport
 import net.mamoe.mirai.utils.MiraiLogger
-import net.mamoe.mirai.utils.debug
 import net.mamoe.mirai.utils.error
 
-/**
- * Stateless observer of state changes.
- *
- * @see SafeStateObserver
- * @see LoggingStateObserver
- */
-internal interface StateObserver {
-
-    fun stateChanged(
-        networkHandler: NetworkHandlerSupport,
-        previous: NetworkHandlerSupport.BaseStateImpl,
-        new: NetworkHandlerSupport.BaseStateImpl
-    ) {
-    }
-
-    fun exceptionOnCreatingNewState(
-        networkHandler: NetworkHandlerSupport,
-        previousState: NetworkHandlerSupport.BaseStateImpl,
-        exception: Throwable,
-    ) {
-    }
-
-    fun beforeStateResume(
-        networkHandler: NetworkHandler,
-        state: NetworkHandlerSupport.BaseStateImpl,
-    ) {
-
-    }
-
-    fun afterStateResume(
-        networkHandler: NetworkHandler,
-        state: NetworkHandlerSupport.BaseStateImpl,
-        result: Result<Unit>,
-    ) {
-
-    }
-}
-
-internal class LoggingStateObserver(
-    val logger: MiraiLogger
-) : StateObserver {
-    override fun toString(): String {
-        return "LoggingStateObserver(logger=$logger)"
-    }
-
-    override fun stateChanged(
-        networkHandler: NetworkHandlerSupport,
-        previous: NetworkHandlerSupport.BaseStateImpl,
-        new: NetworkHandlerSupport.BaseStateImpl
-    ) {
-        logger.debug { "State changed: ${previous.correspondingState} -> ${new.correspondingState}" }
-    }
-
-    override fun exceptionOnCreatingNewState(
-        networkHandler: NetworkHandlerSupport,
-        previousState: NetworkHandlerSupport.BaseStateImpl,
-        exception: Throwable
-    ) {
-        logger.debug({ "State changed: ${previousState.correspondingState} -> $exception" }, exception)
-    }
-
-    override fun afterStateResume(
-        networkHandler: NetworkHandler,
-        state: NetworkHandlerSupport.BaseStateImpl,
-        result: Result<Unit>
-    ) {
-        result.fold(
-            onSuccess = {
-                logger.debug { "State resumed: ${state.correspondingState}." }
-            },
-            onFailure = {
-                logger.debug(
-                    { "State resumed: ${state.correspondingState} ${result.exceptionOrNull()}" },
-                    result.exceptionOrNull()
-                )
-            }
-        )
-    }
-}
-
-internal class ExceptionInStateObserverException(
-    override val cause: Throwable
-) : RuntimeException()
-
 /**
  * Catches exception then log by [logger]
  */
diff --git a/mirai-core/src/commonMain/kotlin/network/handler/state/StateObserver.kt b/mirai-core/src/commonMain/kotlin/network/handler/state/StateObserver.kt
new file mode 100644
index 000000000..e3e232a76
--- /dev/null
+++ b/mirai-core/src/commonMain/kotlin/network/handler/state/StateObserver.kt
@@ -0,0 +1,51 @@
+/*
+ * Copyright 2019-2021 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.internal.network.handler.state
+
+import net.mamoe.mirai.internal.network.handler.NetworkHandler
+import net.mamoe.mirai.internal.network.handler.NetworkHandlerSupport
+
+/**
+ * Stateless observer of state changes.
+ *
+ * @see SafeStateObserver
+ * @see LoggingStateObserver
+ */
+internal interface StateObserver {
+
+    fun stateChanged(
+        networkHandler: NetworkHandlerSupport,
+        previous: NetworkHandlerSupport.BaseStateImpl,
+        new: NetworkHandlerSupport.BaseStateImpl
+    ) {
+    }
+
+    fun exceptionOnCreatingNewState(
+        networkHandler: NetworkHandlerSupport,
+        previousState: NetworkHandlerSupport.BaseStateImpl,
+        exception: Throwable,
+    ) {
+    }
+
+    fun beforeStateResume(
+        networkHandler: NetworkHandler,
+        state: NetworkHandlerSupport.BaseStateImpl,
+    ) {
+
+    }
+
+    fun afterStateResume(
+        networkHandler: NetworkHandler,
+        state: NetworkHandlerSupport.BaseStateImpl,
+        result: Result<Unit>,
+    ) {
+
+    }
+}
diff --git a/mirai-core/src/commonMain/kotlin/network/highway/Highway.kt b/mirai-core/src/commonMain/kotlin/network/highway/Highway.kt
index 28c65543c..e3d285032 100644
--- a/mirai-core/src/commonMain/kotlin/network/highway/Highway.kt
+++ b/mirai-core/src/commonMain/kotlin/network/highway/Highway.kt
@@ -22,7 +22,7 @@ import kotlinx.io.core.discardExact
 import kotlinx.io.core.writeFully
 import net.mamoe.mirai.internal.QQAndroidBot
 import net.mamoe.mirai.internal.network.QQAndroidClient
-import net.mamoe.mirai.internal.network.handler.BdhSession
+import net.mamoe.mirai.internal.network.handler.context.BdhSession
 import net.mamoe.mirai.internal.network.handler.logger
 import net.mamoe.mirai.internal.network.protocol.data.proto.CSDataHighwayHead
 import net.mamoe.mirai.internal.network.subAppId
diff --git a/mirai-core/src/commonMain/kotlin/network/protocol/packet/PacketFactory.kt b/mirai-core/src/commonMain/kotlin/network/protocol/packet/PacketFactory.kt
index 1d29af0f2..c2d1e5593 100644
--- a/mirai-core/src/commonMain/kotlin/network/protocol/packet/PacketFactory.kt
+++ b/mirai-core/src/commonMain/kotlin/network/protocol/packet/PacketFactory.kt
@@ -13,7 +13,7 @@ import kotlinx.io.core.ByteReadPacket
 import net.mamoe.mirai.event.Event
 import net.mamoe.mirai.internal.QQAndroidBot
 import net.mamoe.mirai.internal.network.Packet
-import net.mamoe.mirai.internal.network.net.protocol.PacketCodec
+import net.mamoe.mirai.internal.network.handler.components.PacketCodec
 import net.mamoe.mirai.internal.network.protocol.packet.chat.*
 import net.mamoe.mirai.internal.network.protocol.packet.chat.image.ImgStore
 import net.mamoe.mirai.internal.network.protocol.packet.chat.image.LongConn
@@ -113,7 +113,7 @@ internal suspend inline fun <P : Packet?> IncomingPacketFactory<P>.decode(
  */
 @Deprecated(
     "Kept for binary compatibility.",
-    ReplaceWith("PacketCodec.PacketLogger", "net.mamoe.mirai.internal.network.net.protocol.PacketCodec"),
+    ReplaceWith("PacketCodec.PacketLogger", "net.mamoe.mirai.internal.network.handler.components.PacketCodec"),
     level = DeprecationLevel.ERROR,
 )
 @PublishedApi
diff --git a/mirai-core/src/commonMain/kotlin/network/protocol/packet/chat/MultiMsg.kt b/mirai-core/src/commonMain/kotlin/network/protocol/packet/chat/MultiMsg.kt
index 51151dd01..e93faa489 100644
--- a/mirai-core/src/commonMain/kotlin/network/protocol/packet/chat/MultiMsg.kt
+++ b/mirai-core/src/commonMain/kotlin/network/protocol/packet/chat/MultiMsg.kt
@@ -19,7 +19,7 @@ import net.mamoe.mirai.internal.message.contextualBugReportException
 import net.mamoe.mirai.internal.message.toRichTextElems
 import net.mamoe.mirai.internal.network.Packet
 import net.mamoe.mirai.internal.network.QQAndroidClient
-import net.mamoe.mirai.internal.network.net.protocol.PacketCodec
+import net.mamoe.mirai.internal.network.handler.components.PacketCodec
 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.MsgTransmit
diff --git a/mirai-core/src/commonMain/kotlin/network/protocol/packet/login/ConfigPushSvc.kt b/mirai-core/src/commonMain/kotlin/network/protocol/packet/login/ConfigPushSvc.kt
index 64a68d8aa..9c0e5520c 100644
--- a/mirai-core/src/commonMain/kotlin/network/protocol/packet/login/ConfigPushSvc.kt
+++ b/mirai-core/src/commonMain/kotlin/network/protocol/packet/login/ConfigPushSvc.kt
@@ -19,7 +19,8 @@ import net.mamoe.mirai.event.events.BotOfflineEvent
 import net.mamoe.mirai.internal.QQAndroidBot
 import net.mamoe.mirai.internal.message.contextualBugReportException
 import net.mamoe.mirai.internal.network.Packet
-import net.mamoe.mirai.internal.network.handler.BdhSession
+import net.mamoe.mirai.internal.network.handler.components.ServerAddress
+import net.mamoe.mirai.internal.network.handler.context.BdhSession
 import net.mamoe.mirai.internal.network.handler.logger
 import net.mamoe.mirai.internal.network.networkType
 import net.mamoe.mirai.internal.network.protocol.data.jce.FileStoragePushFSSvcList
@@ -148,10 +149,7 @@ internal class ConfigPushSvc {
                 bot.network.logger.info { "Server list: ${pushServerList.joinToString()}." }
 
                 if (pushServerList.isNotEmpty()) {
-                    bot.serverList.clear()
-                    pushServerList.shuffled().forEach {
-                        bot.serverList.add(it.host to it.port)
-                    }
+                    bot.serverListNew.setPreferred(pushServerList.shuffled().map { ServerAddress(it.host, it.port) })
                 }
                 bot.bdhSyncer.saveToCache()
                 bot.bdhSyncer.saveServerListToCache()
diff --git a/mirai-core/src/commonTest/kotlin/network/ServerListTest.kt b/mirai-core/src/commonTest/kotlin/network/ServerListTest.kt
index 1b1217925..663a40b96 100644
--- a/mirai-core/src/commonTest/kotlin/network/ServerListTest.kt
+++ b/mirai-core/src/commonTest/kotlin/network/ServerListTest.kt
@@ -9,8 +9,8 @@
 
 package net.mamoe.mirai.internal.network
 
-import net.mamoe.mirai.internal.network.handler.ServerAddress
-import net.mamoe.mirai.internal.network.handler.ServerList
+import net.mamoe.mirai.internal.network.handler.components.ServerAddress
+import net.mamoe.mirai.internal.network.handler.components.ServerList
 import kotlin.test.*
 
 internal class ServerListTest {
diff --git a/mirai-core/src/commonTest/kotlin/network/handler/AbstractKeepAliveNetworkHandlerSelectorTest.kt b/mirai-core/src/commonTest/kotlin/network/handler/AbstractKeepAliveNetworkHandlerSelectorTest.kt
index f288b0409..67cf1352f 100644
--- a/mirai-core/src/commonTest/kotlin/network/handler/AbstractKeepAliveNetworkHandlerSelectorTest.kt
+++ b/mirai-core/src/commonTest/kotlin/network/handler/AbstractKeepAliveNetworkHandlerSelectorTest.kt
@@ -10,6 +10,7 @@
 package net.mamoe.mirai.internal.network.handler
 
 import net.mamoe.mirai.internal.network.handler.NetworkHandler.State
+import net.mamoe.mirai.internal.network.handler.selector.AbstractKeepAliveNetworkHandlerSelector
 import net.mamoe.mirai.internal.test.runBlockingUnit
 import java.util.concurrent.atomic.AtomicInteger
 import kotlin.test.*
diff --git a/mirai-core/src/commonTest/kotlin/network/handler/testUtils.kt b/mirai-core/src/commonTest/kotlin/network/handler/testUtils.kt
index 676f204b9..d51d3f8e7 100644
--- a/mirai-core/src/commonTest/kotlin/network/handler/testUtils.kt
+++ b/mirai-core/src/commonTest/kotlin/network/handler/testUtils.kt
@@ -12,12 +12,12 @@ package net.mamoe.mirai.internal.network.handler
 import kotlinx.coroutines.CompletableDeferred
 import net.mamoe.mirai.internal.MockBot
 import net.mamoe.mirai.internal.QQAndroidBot
-import net.mamoe.mirai.internal.network.handler.impl.LoggingStateObserver
-import net.mamoe.mirai.internal.network.handler.impl.NetworkHandlerSupport
-import net.mamoe.mirai.internal.network.handler.impl.SafeStateObserver
-import net.mamoe.mirai.internal.network.handler.impl.StateObserver
-import net.mamoe.mirai.internal.network.net.protocol.SsoProcessor
-import net.mamoe.mirai.internal.network.net.protocol.SsoProcessorContextImpl
+import net.mamoe.mirai.internal.network.handler.components.SsoProcessor
+import net.mamoe.mirai.internal.network.handler.context.NetworkHandlerContext
+import net.mamoe.mirai.internal.network.handler.context.SsoProcessorContextImpl
+import net.mamoe.mirai.internal.network.handler.state.LoggingStateObserver
+import net.mamoe.mirai.internal.network.handler.state.SafeStateObserver
+import net.mamoe.mirai.internal.network.handler.state.StateObserver
 import net.mamoe.mirai.internal.network.protocol.packet.OutgoingPacket
 import net.mamoe.mirai.utils.MiraiLogger
 import java.util.concurrent.ConcurrentLinkedQueue
diff --git a/mirai-core/src/commonTest/kotlin/network/sessionUtils.kt b/mirai-core/src/commonTest/kotlin/network/sessionUtils.kt
index 3a4e36138..31b753df0 100644
--- a/mirai-core/src/commonTest/kotlin/network/sessionUtils.kt
+++ b/mirai-core/src/commonTest/kotlin/network/sessionUtils.kt
@@ -11,7 +11,9 @@ package net.mamoe.mirai.internal.network
 
 import net.mamoe.mirai.event.events.BotOnlineEvent
 import net.mamoe.mirai.internal.QQAndroidBot
-import net.mamoe.mirai.internal.network.net.protocol.SsoSession
+import net.mamoe.mirai.internal.network.handler.context.AccountSecrets
+import net.mamoe.mirai.internal.network.handler.context.AccountSecretsImpl
+import net.mamoe.mirai.internal.network.handler.context.SsoSession
 import net.mamoe.mirai.internal.utils.crypto.ECDH
 import net.mamoe.mirai.internal.utils.io.serialization.loadAs
 import net.mamoe.mirai.internal.utils.io.serialization.toByteArray