From 918007df9bde698665212a9ff5480676d7775323 Mon Sep 17 00:00:00 2001
From: Karlatemp <karlatemp@vip.qq.com>
Date: Tue, 2 Feb 2021 22:22:56 +0800
Subject: [PATCH] Fix image uploading; fix #944

---
 .../src/commonMain/kotlin/contact/AbstractUser.kt     | 11 ++++++++++-
 mirai-core/src/commonMain/kotlin/contact/GroupImpl.kt | 11 ++++++++++-
 .../src/commonMain/kotlin/network/highway/Highway.kt  | 10 +++++++++-
 3 files changed, 29 insertions(+), 3 deletions(-)

diff --git a/mirai-core/src/commonMain/kotlin/contact/AbstractUser.kt b/mirai-core/src/commonMain/kotlin/contact/AbstractUser.kt
index 0b9da3e04..2b9609533 100644
--- a/mirai-core/src/commonMain/kotlin/contact/AbstractUser.kt
+++ b/mirai-core/src/commonMain/kotlin/contact/AbstractUser.kt
@@ -18,12 +18,14 @@ 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.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
 import net.mamoe.mirai.internal.network.highway.postImage
 import net.mamoe.mirai.internal.network.highway.tryServers
 import net.mamoe.mirai.internal.network.protocol.data.proto.Cmd0x352
+import net.mamoe.mirai.internal.network.protocol.packet.EMPTY_BYTE_ARRAY
 import net.mamoe.mirai.internal.network.protocol.packet.chat.image.ImgStore
 import net.mamoe.mirai.internal.network.protocol.packet.chat.image.LongConn
 import net.mamoe.mirai.internal.network.protocol.packet.sendAndExpect
@@ -133,7 +135,14 @@ internal abstract class AbstractUser(
                                 resource = resource,
                                 kind = PRIVATE_IMAGE,
                                 commandId = 2,
-                                initialTicket = response.uKey
+                                initialTicket = response.uKey,
+                                fallbackSession = {
+                                    BdhSession(
+                                        EMPTY_BYTE_ARRAY, EMPTY_BYTE_ARRAY,
+                                        ssoAddresses = response.uploadIpList.zip(response.uploadPortList)
+                                            .toMutableSet(),
+                                    )
+                                }
                             )
                         }
                     }
diff --git a/mirai-core/src/commonMain/kotlin/contact/GroupImpl.kt b/mirai-core/src/commonMain/kotlin/contact/GroupImpl.kt
index 980318085..c7039b59f 100644
--- a/mirai-core/src/commonMain/kotlin/contact/GroupImpl.kt
+++ b/mirai-core/src/commonMain/kotlin/contact/GroupImpl.kt
@@ -21,11 +21,13 @@ import net.mamoe.mirai.event.broadcast
 import net.mamoe.mirai.event.events.*
 import net.mamoe.mirai.internal.QQAndroidBot
 import net.mamoe.mirai.internal.message.*
+import net.mamoe.mirai.internal.network.BdhSession
 import net.mamoe.mirai.internal.network.QQAndroidBotNetworkHandler
 import net.mamoe.mirai.internal.network.highway.*
 import net.mamoe.mirai.internal.network.highway.ResourceKind.GROUP_IMAGE
 import net.mamoe.mirai.internal.network.highway.ResourceKind.GROUP_VOICE
 import net.mamoe.mirai.internal.network.protocol.data.proto.Cmd0x388
+import net.mamoe.mirai.internal.network.protocol.packet.EMPTY_BYTE_ARRAY
 import net.mamoe.mirai.internal.network.protocol.packet.chat.TroopEssenceMsgManager
 import net.mamoe.mirai.internal.network.protocol.packet.chat.image.ImgStore
 import net.mamoe.mirai.internal.network.protocol.packet.chat.voice.PttStore
@@ -166,7 +168,14 @@ internal class GroupImpl(
                         resource = resource,
                         kind = GROUP_IMAGE,
                         commandId = 2,
-                        initialTicket = response.uKey
+                        initialTicket = response.uKey,
+                        noBdhAwait = true,
+                        fallbackSession = {
+                            BdhSession(
+                                EMPTY_BYTE_ARRAY, EMPTY_BYTE_ARRAY,
+                                ssoAddresses = response.uploadIpList.zip(response.uploadPortList).toMutableSet(),
+                            )
+                        },
                     )
 
                     return OfflineGroupImage(imageId = resource.calculateResourceId())
diff --git a/mirai-core/src/commonMain/kotlin/network/highway/Highway.kt b/mirai-core/src/commonMain/kotlin/network/highway/Highway.kt
index 799e74f98..2f3db39d3 100644
--- a/mirai-core/src/commonMain/kotlin/network/highway/Highway.kt
+++ b/mirai-core/src/commonMain/kotlin/network/highway/Highway.kt
@@ -21,6 +21,7 @@ import kotlinx.io.core.buildPacket
 import kotlinx.io.core.discardExact
 import kotlinx.io.core.writeFully
 import net.mamoe.mirai.internal.QQAndroidBot
+import net.mamoe.mirai.internal.network.BdhSession
 import net.mamoe.mirai.internal.network.QQAndroidClient
 import net.mamoe.mirai.internal.network.protocol.data.proto.CSDataHighwayHead
 import net.mamoe.mirai.internal.network.protocol.packet.EMPTY_BYTE_ARRAY
@@ -52,8 +53,15 @@ internal object Highway {
         encrypt: Boolean = false,
         initialTicket: ByteArray? = null,
         tryOnce: Boolean = false,
+        noBdhAwait: Boolean = false,
+        fallbackSession: (Throwable) -> BdhSession = { throw IllegalStateException("Failed to get bdh session", it) }
     ): BdhUploadResponse {
-        val bdhSession = bot.client.bdhSession.await() // no need to care about timeout. proceed by bot init
+        val bdhSession = kotlin.runCatching {
+            val deferred = bot.client.bdhSession
+            // no need to care about timeout. proceed by bot init
+            @OptIn(ExperimentalCoroutinesApi::class)
+            if (noBdhAwait) deferred.getCompleted() else deferred.await()
+        }.getOrElse(fallbackSession)
 
         return tryServers(
             bot = bot,