feat: use KNet for HTTP/3 support

This commit is contained in:
Canny 2022-10-11 16:36:18 +03:00
parent e06b30cd7a
commit dd81b79fac
No known key found for this signature in database
GPG Key ID: 395CCB0AA979F27B
4 changed files with 56 additions and 48 deletions

View File

@ -138,5 +138,7 @@ dependencies {
implementation("org.jetbrains.kotlinx:kotlinx-coroutines-guava:1.6.4") implementation("org.jetbrains.kotlinx:kotlinx-coroutines-guava:1.6.4")
// Networking // Networking
implementation("com.github.niusounds:cronet-engine:0.1.0") implementation("com.vk.knet:core:1.0")
implementation("com.vk.knet:cronet:1.0")
implementation("com.vk.knet:okcronet:1.0")
} }

View File

@ -4,14 +4,15 @@ import android.util.Log
import app.revanced.manager.dto.github.Assets import app.revanced.manager.dto.github.Assets
import app.revanced.manager.preferences.PreferencesManager import app.revanced.manager.preferences.PreferencesManager
import app.revanced.manager.repository.GitHubRepository import app.revanced.manager.repository.GitHubRepository
import io.ktor.client.* import com.vk.knet.core.Knet
import io.ktor.client.request.* import com.vk.knet.core.http.HttpMethod
import io.ktor.client.statement.* import com.vk.knet.core.http.HttpRequest
import io.ktor.util.cio.* import com.vk.knet.cornet.CronetKnetEngine
import io.ktor.utils.io.*
import java.io.File import java.io.File
class API(private val repository: GitHubRepository, private val prefs: PreferencesManager, val client: HttpClient) { class API(private val repository: GitHubRepository, private val prefs: PreferencesManager, cronet: CronetKnetEngine) {
val client = Knet.Build(cronet)
suspend fun findAsset(repo: String, file: String): PatchesAsset { suspend fun findAsset(repo: String, file: String): PatchesAsset {
val asset = repository.fetchAssets().tools.findAsset(repo, file) ?: throw MissingAssetException() val asset = repository.fetchAssets().tools.findAsset(repo, file) ?: throw MissingAssetException()
@ -42,7 +43,7 @@ class API(private val repository: GitHubRepository, private val prefs: Preferenc
} }
} }
suspend fun downloadAsset( fun downloadAsset(
workdir: File, workdir: File,
assets: PatchesAsset assets: PatchesAsset
): Pair<PatchesAsset, File> { ): Pair<PatchesAsset, File> {
@ -55,9 +56,9 @@ class API(private val repository: GitHubRepository, private val prefs: Preferenc
return assets to out return assets to out
} }
Log.d("ReVanced Manager", "Downloading asset ${assets.asset.name}") Log.d("ReVanced Manager", "Downloading asset ${assets.asset.name}")
client.get(assets.asset.downloadUrl) val file = client.execute(HttpRequest(HttpMethod.GET, assets.asset.downloadUrl)).body?.asBytes()
.bodyAsChannel() file?.let { out.writeBytes(it) }
.copyAndClose(out.writeChannel())
return assets to out return assets to out
} }

View File

@ -1,41 +1,42 @@
package app.revanced.manager.di package app.revanced.manager.di
import android.content.Context import android.content.Context
import com.niusounds.ktor.client.engine.cronet.Cronet import com.vk.knet.core.utils.ByteArrayPool
import io.ktor.client.* import com.vk.knet.cornet.CronetKnetEngine
import io.ktor.client.plugins.* import com.vk.knet.cornet.config.CronetCache
import io.ktor.client.plugins.cache.* import com.vk.knet.cornet.config.CronetQuic
import io.ktor.client.plugins.contentnegotiation.* import com.vk.knet.cornet.pool.buffer.CronetNativeByteBufferPool
import io.ktor.serialization.kotlinx.json.*
import kotlinx.serialization.json.Json
import org.koin.android.ext.koin.androidContext import org.koin.android.ext.koin.androidContext
import org.koin.dsl.module import org.koin.dsl.module
import java.util.concurrent.TimeUnit
val httpModule = module { val httpModule = module {
fun provideHttpClient(appContext: Context) = HttpClient( fun client(appContext: Context) = CronetKnetEngine.Build(appContext) {
engine = Cronet.create { client {
context = appContext setCache(CronetCache.Disk(appContext.filesDir, 1024 * 1024 * 10))
config = {
enableBrotli(true) enableHttp2(true)
enableQuic(true) enableQuic(
CronetQuic()
)
useBrotli(true)
connectTimeout(15, TimeUnit.SECONDS)
writeTimeout(15, TimeUnit.SECONDS)
readTimeout(15, TimeUnit.SECONDS)
nativePool(CronetNativeByteBufferPool.DEFAULT)
arrayPool(ByteArrayPool.DEFAULT)
maxConcurrentRequests(50)
maxConcurrentRequestsPerHost(10)
followRedirects(true)
followSslRedirects(true)
} }
} }
) {
BrowserUserAgent()
install(ContentNegotiation) {
json(Json {
encodeDefaults = true
isLenient = true
ignoreUnknownKeys = true
})
}
install(HttpRequestRetry) {
retryOnServerErrors(maxRetries = 5)
}
install(HttpCache)
}
single { single {
provideHttpClient(androidContext()) client(androidContext())
} }
} }

View File

@ -1,24 +1,28 @@
package app.revanced.manager.repository package app.revanced.manager.repository
import app.revanced.manager.dto.github.Tools
import app.revanced.manager.dto.github.Repositories import app.revanced.manager.dto.github.Repositories
import io.ktor.client.* import app.revanced.manager.dto.github.Tools
import io.ktor.client.call.* import com.vk.knet.core.Knet
import io.ktor.client.request.* import com.vk.knet.core.http.HttpMethod
import com.vk.knet.core.http.HttpRequest
import com.vk.knet.cornet.CronetKnetEngine
import kotlinx.coroutines.Dispatchers import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.withContext import kotlinx.coroutines.withContext
import kotlinx.serialization.decodeFromString
import kotlinx.serialization.json.Json
class GitHubRepository(val client: HttpClient) { class GitHubRepository(cronet: CronetKnetEngine) {
val client = Knet.Build(cronet)
suspend fun fetchAssets() = withContext(Dispatchers.IO) { suspend fun fetchAssets() = withContext(Dispatchers.IO) {
client.get("$apiUrl/tools") { val stream = client.execute(HttpRequest(HttpMethod.GET, "$apiUrl/tools")).body!!.asString()
parameter("per_page", 1) Json.decodeFromString(stream) as Tools
}.body() as Tools
} }
suspend fun fetchContributors() = withContext(Dispatchers.IO) { suspend fun fetchContributors() = withContext(Dispatchers.IO) {
client.get("$apiUrl/contributors").body() as Repositories val stream = client.execute(HttpRequest(HttpMethod.GET,"$apiUrl/contributors")).body!!.asString()
Json.decodeFromString(stream) as Repositories
} }
private companion object { private companion object {