@@ -14,11 +14,13 @@ import kotlinx.coroutines.*
14
14
import kotlinx.coroutines.channels.Channel
15
15
import kotlinx.coroutines.channels.onFailure
16
16
import net.mamoe.mirai.internal.network.components.*
17
+ import net.mamoe.mirai.internal.network.handler.NetworkHandler.Companion.runUnwrapCancellationException
17
18
import net.mamoe.mirai.internal.network.handler.selector.NetworkException
18
19
import net.mamoe.mirai.internal.network.handler.selector.NetworkHandlerSelector
19
20
import net.mamoe.mirai.internal.network.handler.state.StateObserver
20
21
import net.mamoe.mirai.internal.network.impl.HeartbeatFailedException
21
22
import net.mamoe.mirai.internal.network.protocol.packet.OutgoingPacket
23
+ import net.mamoe.mirai.network.LoginFailedException
22
24
import net.mamoe.mirai.utils.*
23
25
import kotlin.coroutines.CoroutineContext
24
26
@@ -171,14 +173,14 @@ internal abstract class CommonNetworkHandler<Conn>(
171
173
// /////////////////////////////////////////////////////////////////////////
172
174
173
175
override fun close (cause : Throwable ? ) {
174
- super .close(cause) // cancel coroutine scope
175
176
if (state == NetworkHandler .State .CLOSED ) return // quick check if already closed
176
177
if (setState { StateClosed (cause) } == null ) return // atomic check
178
+ super .close(cause) // cancel coroutine scope
177
179
}
178
180
179
181
init {
180
182
coroutineContext.job.invokeOnCompletion { e ->
181
- close(e?.unwrapCancellationException() )
183
+ close(e)
182
184
}
183
185
}
184
186
@@ -231,7 +233,6 @@ internal abstract class CommonNetworkHandler<Conn>(
231
233
) : CommonState(NetworkHandler .State .CONNECTING ) {
232
234
private lateinit var connection: Deferred <Conn >
233
235
234
- @Suppress(" JoinDeclarationAndAssignment" )
235
236
private lateinit var connectResult: Deferred <Unit >
236
237
237
238
override fun startState () {
@@ -241,18 +242,27 @@ internal abstract class CommonNetworkHandler<Conn>(
241
242
242
243
connectResult = async {
243
244
connection.join()
244
- context[SsoProcessor ].login(this @CommonNetworkHandler)
245
+ try {
246
+ context[SsoProcessor ].login(this @CommonNetworkHandler)
247
+ } catch (e: LoginFailedException ) {
248
+ throw LoginFailedExceptionAsNetworkException (e)
249
+ }
245
250
}
246
251
connectResult.invokeOnCompletion { error ->
247
252
if (error == null ) {
248
- this @CommonNetworkHandler.launch { resumeConnection() }
253
+ this @CommonNetworkHandler.launch { resumeConnection() } // go to next state.
249
254
} else {
250
255
// failed in SSO stage
251
256
context[SsoProcessor ].firstLoginResult.compareAndSet(null , FirstLoginResult .OTHER_FAILURE )
252
257
253
- if (error is StateSwitchingException && error.new is CommonNetworkHandler <* >.StateConnecting ) {
254
- return @invokeOnCompletion // state already switched, so do not do it again.
258
+ if (error is CancellationException ) {
259
+ // CancellationException is either caused by parent cancellation or manual `connectResult.cancel`.
260
+ // The later should not happen, so it's definitely due to the parent cancellation.
261
+ // It means that the super scope, the NetworkHandler is closed.
262
+ // If we don't `return` here, state will be set to StateClosed with CancellationException, which isn't the real cause.
263
+ return @invokeOnCompletion
255
264
}
265
+
256
266
setState {
257
267
// logon failure closes the network handler.
258
268
StateClosed (collectiveExceptions.collectGet(error))
@@ -304,25 +314,21 @@ internal abstract class CommonNetworkHandler<Conn>(
304
314
return true
305
315
}
306
316
307
- private val configPush = this @CommonNetworkHandler.launch(CoroutineName (" ConfigPush sync" )) {
308
- context[ConfigPushProcessor ].syncConfigPush(this @CommonNetworkHandler)
309
- }
317
+ // Yes, nothing to do in this state.
310
318
311
319
override suspend fun resumeConnection0 (): Unit = runUnwrapCancellationException {
312
320
(coroutineContext.job as CompletableJob ).run {
313
321
complete()
314
322
join()
315
323
}
316
- joinCompleted(configPush) // throw exception
317
- setState { StateOK (connection, configPush) }
324
+ setState { StateOK (connection) }
318
325
} // noop
319
326
320
327
override fun toString (): String = " StateLoading"
321
328
}
322
329
323
330
protected inner class StateOK (
324
331
private val connection : Conn ,
325
- private val configPush : Job ,
326
332
) : CommonState(NetworkHandler .State .OK ) {
327
333
override fun startState () {
328
334
coroutineContext.job.invokeOnCompletion { err ->
@@ -346,6 +352,11 @@ internal abstract class CommonNetworkHandler<Conn>(
346
352
context[KeyRefreshProcessor ].keyRefreshLoop(this @CommonNetworkHandler)
347
353
}
348
354
355
+ private val configPush = this @CommonNetworkHandler.launch(CoroutineName (" ConfigPush sync" )) {
356
+ context[ConfigPushProcessor ].syncConfigPush(this @CommonNetworkHandler)
357
+ }
358
+
359
+
349
360
override suspend fun sendPacketImpl (packet : OutgoingPacket ): Boolean {
350
361
connection.writeAndFlushOrCloseAsync(packet)
351
362
return true
0 commit comments