Quellcode durchsuchen

Add support to kotlin.time APIs in the rate limit interceptor (#9797)

* Add support to kotlin.time APIs in the rate limit interceptor.

* Add a missing line break in the doc.

* Move the specific host to the same file.

* Add kotlin.time rule to Proguard and remove specific host rule.

* Mark the old version as deprecated and address review.

* Remove unused import.

* Remove yet another unused import.
Alessandro Jean vor 1 Jahr
Ursprung
Commit
9b6567f5e4

+ 1 - 0
app/proguard-rules.pro

@@ -8,6 +8,7 @@
 -keep,allowoptimization class kotlin.** { public protected *; }
 -keep,allowoptimization class kotlinx.coroutines.** { public protected *; }
 -keep,allowoptimization class kotlinx.serialization.** { public protected *; }
+-keep,allowoptimization class kotlin.time.** { public protected *; }
 -keep,allowoptimization class okhttp3.** { public protected *; }
 -keep,allowoptimization class okio.** { public protected *; }
 -keep,allowoptimization class rx.** { public protected *; }

+ 2 - 2
app/src/main/java/eu/kanade/tachiyomi/data/track/anilist/AnilistApi.kt

@@ -27,7 +27,7 @@ import okhttp3.RequestBody.Companion.toRequestBody
 import tachiyomi.core.util.lang.withIOContext
 import uy.kohesive.injekt.injectLazy
 import java.util.Calendar
-import java.util.concurrent.TimeUnit
+import kotlin.time.Duration.Companion.minutes
 
 class AnilistApi(val client: OkHttpClient, interceptor: AnilistInterceptor) {
 
@@ -35,7 +35,7 @@ class AnilistApi(val client: OkHttpClient, interceptor: AnilistInterceptor) {
 
     private val authClient = client.newBuilder()
         .addInterceptor(interceptor)
-        .rateLimit(permits = 85, period = 1, unit = TimeUnit.MINUTES)
+        .rateLimit(permits = 85, period = 1.minutes)
         .build()
 
     suspend fun addLibManga(track: Track): Track {

+ 30 - 7
core/src/main/java/eu/kanade/tachiyomi/network/interceptor/RateLimitInterceptor.kt

@@ -8,10 +8,17 @@ import java.io.IOException
 import java.util.ArrayDeque
 import java.util.concurrent.Semaphore
 import java.util.concurrent.TimeUnit
+import kotlin.time.Duration
+import kotlin.time.Duration.Companion.seconds
+import kotlin.time.toDuration
+import kotlin.time.toDurationUnit
 
 /**
  * An OkHttp interceptor that handles rate limiting.
  *
+ * This uses `java.time` APIs and is the legacy method, kept
+ * for compatibility reasons with existing extensions.
+ *
  * Examples:
  *
  * permits = 5,  period = 1, unit = seconds  =>  5 requests per second
@@ -19,27 +26,43 @@ import java.util.concurrent.TimeUnit
  *
  * @since extension-lib 1.3
  *
- * @param permits {Int}   Number of requests allowed within a period of units.
- * @param period {Long}   The limiting duration. Defaults to 1.
- * @param unit {TimeUnit} The unit of time for the period. Defaults to seconds.
+ * @param permits [Int]   Number of requests allowed within a period of units.
+ * @param period [Long]   The limiting duration. Defaults to 1.
+ * @param unit [TimeUnit] The unit of time for the period. Defaults to seconds.
  */
+@Deprecated("Use the version with kotlin.time APIs instead.")
 fun OkHttpClient.Builder.rateLimit(
     permits: Int,
     period: Long = 1,
     unit: TimeUnit = TimeUnit.SECONDS,
-) = addInterceptor(RateLimitInterceptor(null, permits, period, unit))
+) = addInterceptor(RateLimitInterceptor(null, permits, period.toDuration(unit.toDurationUnit())))
+
+/**
+ * An OkHttp interceptor that handles rate limiting.
+ *
+ * Examples:
+ *
+ * permits = 5,  period = 1.seconds  =>  5 requests per second
+ * permits = 10, period = 2.minutes  =>  10 requests per 2 minutes
+ *
+ * @since extension-lib 1.5
+ *
+ * @param permits [Int]     Number of requests allowed within a period of units.
+ * @param period [Duration] The limiting duration. Defaults to 1.seconds.
+ */
+fun OkHttpClient.Builder.rateLimit(permits: Int, period: Duration = 1.seconds) =
+    addInterceptor(RateLimitInterceptor(null, permits, period))
 
 /** We can probably accept domains or wildcards by comparing with [endsWith], etc. */
 @Suppress("PLATFORM_CLASS_MAPPED_TO_KOTLIN")
 internal class RateLimitInterceptor(
     private val host: String?,
     private val permits: Int,
-    period: Long,
-    unit: TimeUnit,
+    period: Duration,
 ) : Interceptor {
 
     private val requestQueue = ArrayDeque<Long>(permits)
-    private val rateLimitMillis = unit.toMillis(period)
+    private val rateLimitMillis = period.inWholeMilliseconds
     private val fairLock = Semaphore(1, true)
 
     override fun intercept(chain: Interceptor.Chain): Response {

+ 54 - 5
core/src/main/java/eu/kanade/tachiyomi/network/interceptor/SpecificHostRateLimitInterceptor.kt

@@ -1,12 +1,20 @@
 package eu.kanade.tachiyomi.network.interceptor
 
 import okhttp3.HttpUrl
+import okhttp3.HttpUrl.Companion.toHttpUrlOrNull
 import okhttp3.OkHttpClient
 import java.util.concurrent.TimeUnit
+import kotlin.time.Duration
+import kotlin.time.Duration.Companion.seconds
+import kotlin.time.toDuration
+import kotlin.time.toDurationUnit
 
 /**
  * An OkHttp interceptor that handles given url host's rate limiting.
  *
+ * This uses Java Time APIs and is the legacy method, kept
+ * for compatibility reasons with existing extensions.
+ *
  * Examples:
  *
  * httpUrl = "api.manga.com".toHttpUrlOrNull(), permits = 5, period = 1, unit = seconds  =>  5 requests per second to api.manga.com
@@ -14,14 +22,55 @@ import java.util.concurrent.TimeUnit
  *
  * @since extension-lib 1.3
  *
- * @param httpUrl {HttpUrl} The url host that this interceptor should handle. Will get url's host by using HttpUrl.host()
- * @param permits {Int}   Number of requests allowed within a period of units.
- * @param period {Long}   The limiting duration. Defaults to 1.
- * @param unit {TimeUnit} The unit of time for the period. Defaults to seconds.
+ * @param httpUrl [HttpUrl] The url host that this interceptor should handle. Will get url's host by using HttpUrl.host()
+ * @param permits [Int]     Number of requests allowed within a period of units.
+ * @param period [Long]     The limiting duration. Defaults to 1.
+ * @param unit [TimeUnit]   The unit of time for the period. Defaults to seconds.
  */
+@Deprecated("Use the version with kotlin.time APIs instead.")
 fun OkHttpClient.Builder.rateLimitHost(
     httpUrl: HttpUrl,
     permits: Int,
     period: Long = 1,
     unit: TimeUnit = TimeUnit.SECONDS,
-) = addInterceptor(RateLimitInterceptor(httpUrl.host, permits, period, unit))
+) = addInterceptor(RateLimitInterceptor(httpUrl.host, permits, period.toDuration(unit.toDurationUnit())))
+
+/**
+ * An OkHttp interceptor that handles given url host's rate limiting.
+ *
+ * Examples:
+ *
+ * httpUrl = "https://api.manga.com".toHttpUrlOrNull(), permits = 5, period = 1.seconds =>  5 requests per second to api.manga.com
+ * httpUrl = "https://imagecdn.manga.com".toHttpUrlOrNull(), permits = 10, period = 2.minutes  =>  10 requests per 2 minutes to imagecdn.manga.com
+ *
+ * @since extension-lib 1.5
+ *
+ * @param httpUrl [HttpUrl] The url host that this interceptor should handle. Will get url's host by using HttpUrl.host()
+ * @param permits [Int]     Number of requests allowed within a period of units.
+ * @param period [Duration] The limiting duration. Defaults to 1.seconds.
+ */
+fun OkHttpClient.Builder.rateLimitHost(
+    httpUrl: HttpUrl,
+    permits: Int,
+    period: Duration = 1.seconds,
+) = addInterceptor(RateLimitInterceptor(httpUrl.host, permits, period))
+
+/**
+ * An OkHttp interceptor that handles given url host's rate limiting.
+ *
+ * Examples:
+ *
+ * url = "https://api.manga.com", permits = 5, period = 1.seconds =>  5 requests per second to api.manga.com
+ * url = "https://imagecdn.manga.com", permits = 10, period = 2.minutes  =>  10 requests per 2 minutes to imagecdn.manga.com
+ *
+ * @since extension-lib 1.5
+ *
+ * @param url [String]      The url host that this interceptor should handle. Will get url's host by using HttpUrl.host()
+ * @param permits [Int]     Number of requests allowed within a period of units.
+ * @param period [Duration] The limiting duration. Defaults to 1.seconds.
+ */
+fun OkHttpClient.Builder.rateLimitHost(
+    url: String,
+    permits: Int,
+    period: Duration = 1.seconds,
+) = addInterceptor(RateLimitInterceptor(url.toHttpUrlOrNull()?.host, permits, period))