Automatic switch mirrors on server error
parent
2a35ca6094
commit
99037dd046
@ -0,0 +1,105 @@
|
||||
package org.koitharu.kotatsu.core.network
|
||||
|
||||
import android.content.Context
|
||||
import androidx.collection.ArrayMap
|
||||
import okhttp3.Interceptor
|
||||
import okhttp3.Response
|
||||
import org.koitharu.kotatsu.core.prefs.SourceSettings
|
||||
import org.koitharu.kotatsu.parsers.MangaParser
|
||||
import org.koitharu.kotatsu.parsers.config.ConfigKey
|
||||
import org.koitharu.kotatsu.parsers.model.MangaSource
|
||||
|
||||
class MirrorsInterceptor(
|
||||
private val context: Context,
|
||||
) : Interceptor {
|
||||
|
||||
private val mirrorsMap = ArrayMap<String, Mirrors>()
|
||||
|
||||
override fun intercept(chain: Interceptor.Chain): Response {
|
||||
val response = chain.proceed(chain.request())
|
||||
return if (response.isServerError) {
|
||||
trySwitchMirror(chain) ?: response
|
||||
} else {
|
||||
response
|
||||
}
|
||||
}
|
||||
|
||||
fun register(parser: MangaParser) {
|
||||
val configKeys = ArrayList<ConfigKey<*>>()
|
||||
parser.onCreateConfig(configKeys)
|
||||
for (key in configKeys) {
|
||||
if (key is ConfigKey.Domain) {
|
||||
val mirrors = key.presetValues ?: continue
|
||||
mirrorsMap[parser.getDomain()] = Mirrors(parser.source, mirrors)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private fun trySwitchMirror(chain: Interceptor.Chain): Response? {
|
||||
val url = chain.request().url
|
||||
var mirrors = mirrorsMap[url.host]
|
||||
val domain = if (mirrors != null) {
|
||||
url.host
|
||||
} else {
|
||||
mirrors = mirrorsMap[url.topPrivateDomain()]
|
||||
url.topPrivateDomain()
|
||||
}
|
||||
if (domain == null || mirrors == null) {
|
||||
return null
|
||||
}
|
||||
synchronized(mirrors) {
|
||||
for (mirror in mirrors.mirrors) {
|
||||
val request = chain.request()
|
||||
.newBuilder()
|
||||
.url(url.newBuilder().host(mirror).build())
|
||||
.build()
|
||||
val response = chain.proceed(request)
|
||||
if (!response.isServerError) {
|
||||
switchMirror(domain, mirrors.source, mirror)
|
||||
return response
|
||||
}
|
||||
}
|
||||
return null
|
||||
}
|
||||
}
|
||||
|
||||
private fun switchMirror(oldDomain: String, source: MangaSource, newDomain: String) {
|
||||
val mirrors = mirrorsMap[oldDomain]?.mirrors?.toMutableList()
|
||||
if (mirrors != null) {
|
||||
mirrors.remove(newDomain)
|
||||
mirrors.add(oldDomain)
|
||||
}
|
||||
mirrorsMap[newDomain] = Mirrors(source, (mirrors ?: listOf(oldDomain)).toTypedArray())
|
||||
val settings = SourceSettings(context, source)
|
||||
settings[ConfigKey.Domain(oldDomain, null)] = newDomain
|
||||
}
|
||||
|
||||
private val Response.isServerError: Boolean
|
||||
get() {
|
||||
return code in 500..599
|
||||
}
|
||||
|
||||
private class Mirrors(
|
||||
val source: MangaSource,
|
||||
val mirrors: Array<String>,
|
||||
) {
|
||||
|
||||
override fun equals(other: Any?): Boolean {
|
||||
if (this === other) return true
|
||||
if (javaClass != other?.javaClass) return false
|
||||
|
||||
other as Mirrors
|
||||
|
||||
if (source != other.source) return false
|
||||
if (!mirrors.contentEquals(other.mirrors)) return false
|
||||
|
||||
return true
|
||||
}
|
||||
|
||||
override fun hashCode(): Int {
|
||||
var result = source.hashCode()
|
||||
result = 31 * result + mirrors.contentHashCode()
|
||||
return result
|
||||
}
|
||||
}
|
||||
}
|
||||
Loading…
Reference in New Issue