commit c1a01bf1695fd083cdadda4560eff5cf12aefaf5
parent 0f711b698ee14668bd29d337fe3e07962091a60c
Author: rhunk <101876869+rhunk@users.noreply.github.com>
Date:   Sun, 28 May 2023 23:50:33 +0200

perf(cdndownloader): bolt http resolver

Diffstat:
Mapp/src/main/kotlin/me/rhunk/snapenhance/features/impl/downloader/MediaDownloader.kt | 2+-
Mapp/src/main/kotlin/me/rhunk/snapenhance/util/download/CdnDownloader.kt | 79+++++++++++++++----------------------------------------------------------------
2 files changed, 16 insertions(+), 65 deletions(-)

diff --git a/app/src/main/kotlin/me/rhunk/snapenhance/features/impl/downloader/MediaDownloader.kt b/app/src/main/kotlin/me/rhunk/snapenhance/features/impl/downloader/MediaDownloader.kt @@ -377,7 +377,7 @@ class MediaDownloader : Feature("MediaDownloader", loadParams = FeatureLoadParam //download the message content try { - context.longToast("Querying $urlKey. It might take a while...") + context.shortToast("Querying $urlKey") val downloadedMedia = MediaDownloaderHelper.downloadMediaFromKey(urlKey, canMergeOverlay(), isPreviewMode) { EncryptionUtils.decryptInputStreamFromArroyo(it, contentType, messageReader) }[MediaType.ORIGINAL] ?: throw Exception("Failed to download media for key $urlKey") diff --git a/app/src/main/kotlin/me/rhunk/snapenhance/util/download/CdnDownloader.kt b/app/src/main/kotlin/me/rhunk/snapenhance/util/download/CdnDownloader.kt @@ -1,64 +1,21 @@ package me.rhunk.snapenhance.util.download -import kotlinx.coroutines.Dispatchers -import kotlinx.coroutines.Job -import kotlinx.coroutines.joinAll -import kotlinx.coroutines.launch -import kotlinx.coroutines.runBlocking import me.rhunk.snapenhance.Constants +import me.rhunk.snapenhance.util.protobuf.ProtoWriter import java.io.InputStream import java.net.URL +import java.util.Base64 import javax.net.ssl.HttpsURLConnection object CdnDownloader { - const val BOLT_CDN_U = "https://bolt-gcdn.sc-cdn.net/u/" - const val BOLT_CDN_X = "https://bolt-gcdn.sc-cdn.net/x/" + private const val BOLT_HTTP_RESOLVER_URL = "https://aws.api.snapchat.com/bolt-http" const val CF_ST_CDN_D = "https://cf-st.sc-cdn.net/d/" - const val CF_ST_CDN_F = "https://cf-st.sc-cdn.net/f/" - const val CF_ST_CDN_H = "https://cf-st.sc-cdn.net/h/" - const val CF_ST_CDN_G = "https://cf-st.sc-cdn.net/g/" - const val CF_ST_CDN_O = "https://cf-st.sc-cdn.net/o/" - const val CF_ST_CDN_I = "https://cf-st.sc-cdn.net/i/" - const val CF_ST_CDN_J = "https://cf-st.sc-cdn.net/j/" - const val CF_ST_CDN_C = "https://cf-st.sc-cdn.net/c/" - const val CF_ST_CDN_M = "https://cf-st.sc-cdn.net/m/" - const val CF_ST_CDN_A = "https://cf-st.sc-cdn.net/a/" - const val CF_ST_CDN_AA = "https://cf-st.sc-cdn.net/aa/" - - private val keyCache: MutableMap<String, String> = mutableMapOf() - - fun downloadRemoteContent( - key: String, - vararg endpoints: String - ): InputStream? = runBlocking { - if (keyCache.containsKey(key)) { - return@runBlocking queryRemoteContent( - keyCache[key]!! - ) - } - val jobs = mutableListOf<Job>() - var inputStream: InputStream? = null - - endpoints.forEach { - launch(Dispatchers.IO) { - val url = it + key - queryRemoteContent(url)?.let { result -> - keyCache[key] = url - inputStream = result - jobs.forEach { it.cancel() } - } - }.also { jobs.add(it) } - } - jobs.joinAll() - inputStream - } - private fun queryRemoteContent(url: String): InputStream? { try { val connection = URL(url).openConnection() as HttpsURLConnection connection.requestMethod = "GET" - connection.connectTimeout = 5000 + connection.instanceFollowRedirects = true connection.setRequestProperty("User-Agent", Constants.USER_AGENT) return connection.inputStream } catch (ignored: Throwable) { @@ -66,23 +23,17 @@ object CdnDownloader { return null } - //TODO: automatically detect the correct endpoint fun downloadWithDefaultEndpoints(key: String): InputStream? { - return downloadRemoteContent( - key, - CF_ST_CDN_F, - CF_ST_CDN_H, - BOLT_CDN_U, - BOLT_CDN_X, - CF_ST_CDN_O, - CF_ST_CDN_I, - CF_ST_CDN_C, - CF_ST_CDN_J, - CF_ST_CDN_M, - CF_ST_CDN_A, - CF_ST_CDN_AA, - CF_ST_CDN_G, - CF_ST_CDN_D - ) + val payload = ProtoWriter().apply { + write(2) { + writeString(2, key) + writeBuffer(3, byteArrayOf()) + writeBuffer(3, byteArrayOf()) + writeConstant(6, 6) + writeConstant(10, 4) + writeConstant(12, 1) + } + }.toByteArray() + return queryRemoteContent(BOLT_HTTP_RESOLVER_URL + "/resolve?co=" + Base64.getUrlEncoder().encodeToString(payload)) } }