Refactor code structure for improved readability and maintainability
This commit is contained in:
@@ -15,7 +15,15 @@ import java.io.File
|
||||
import java.io.IOException
|
||||
import java.util.concurrent.TimeUnit
|
||||
|
||||
class ApiException(message: String, val offline: Boolean = false) : Exception(message)
|
||||
/**
|
||||
* An error ready to show. [code] is the server's machine-readable reason (server/errors.js);
|
||||
* [offline] means the data could not be fetched — no network, or the university's catalog
|
||||
* is down — so a saved copy stays on screen and "Повторить" makes sense.
|
||||
*/
|
||||
class ApiException(message: String, val offline: Boolean = false, val code: String? = null) : Exception(message)
|
||||
|
||||
/** Server codes after which trying again later can help. */
|
||||
private val SOURCE_DOWN = setOf("source_unavailable", "source_timeout", "busy")
|
||||
|
||||
val json = Json {
|
||||
ignoreUnknownKeys = true
|
||||
@@ -44,14 +52,20 @@ class Api(baseUrl: String, cacheDir: File? = null) {
|
||||
client.newCall(Request.Builder().url(url).build()).execute().use { response ->
|
||||
val text = response.body?.string().orEmpty()
|
||||
if (!response.isSuccessful) {
|
||||
val message = runCatching {
|
||||
json.parseToJsonElement(text).jsonObject["error"]?.jsonPrimitive?.content
|
||||
}.getOrNull()
|
||||
// The server's catch-all 404 means it runs an older version without this endpoint.
|
||||
if (response.code == 404 && path.startsWith("api/") && message == "Адрес не найден.") throw ApiException(
|
||||
val body = runCatching { json.parseToJsonElement(text).jsonObject }.getOrNull()
|
||||
val message = body?.get("error")?.jsonPrimitive?.content
|
||||
// Servers before API version 5 send no code; their catch-all 404 has this text.
|
||||
val code = body?.get("code")?.jsonPrimitive?.content
|
||||
?: if (response.code == 404 && message == "Адрес не найден.") "unknown_endpoint" else null
|
||||
if (code == "unknown_endpoint") throw ApiException(
|
||||
"Сервер расписания не знает запрос /$path — на нём старая версия. Обновите сервер.",
|
||||
code = code,
|
||||
)
|
||||
throw ApiException(
|
||||
message ?: "Сервер ответил ошибкой ${response.code}.",
|
||||
offline = code in SOURCE_DOWN,
|
||||
code = code,
|
||||
)
|
||||
throw ApiException(message ?: "Сервер ответил ошибкой ${response.code}.")
|
||||
}
|
||||
text
|
||||
}
|
||||
@@ -70,12 +84,12 @@ class Api(baseUrl: String, cacheDir: File? = null) {
|
||||
return call()
|
||||
} catch (e: IOException) {
|
||||
android.util.Log.w("Api", "GET $url failed (attempt ${attempt + 1})", e)
|
||||
if (attempt == RETRIES - 1) throw ApiException(OFFLINE, offline = true)
|
||||
if (attempt == RETRIES - 1) throw ApiException(OFFLINE, offline = true, code = "offline")
|
||||
delay(wait)
|
||||
wait *= 3
|
||||
}
|
||||
}
|
||||
throw ApiException(OFFLINE, offline = true)
|
||||
throw ApiException(OFFLINE, offline = true, code = "offline")
|
||||
}
|
||||
|
||||
private companion object {
|
||||
|
||||
Reference in New Issue
Block a user