summaryrefslogtreecommitdiff
path: root/cashier/src/main/java/net/taler/cashier/Response.kt
diff options
context:
space:
mode:
authorTorsten Grote <t@grobox.de>2020-08-27 16:42:03 -0300
committerTorsten Grote <t@grobox.de>2020-08-27 16:42:03 -0300
commit53d99e46e6b34d4437f46266cb797a65c0736803 (patch)
tree23f21d022abea280132e3440b3825a71483c7bd2 /cashier/src/main/java/net/taler/cashier/Response.kt
parented3f86481a71517e7bf6ffa46dc8d160b508ec38 (diff)
downloadtaler-android-53d99e46e6b34d4437f46266cb797a65c0736803.tar.gz
taler-android-53d99e46e6b34d4437f46266cb797a65c0736803.tar.bz2
taler-android-53d99e46e6b34d4437f46266cb797a65c0736803.zip
[cashier] don't crash on unexpected network input
Diffstat (limited to 'cashier/src/main/java/net/taler/cashier/Response.kt')
-rw-r--r--cashier/src/main/java/net/taler/cashier/Response.kt86
1 files changed, 86 insertions, 0 deletions
diff --git a/cashier/src/main/java/net/taler/cashier/Response.kt b/cashier/src/main/java/net/taler/cashier/Response.kt
new file mode 100644
index 0000000..0ad39d0
--- /dev/null
+++ b/cashier/src/main/java/net/taler/cashier/Response.kt
@@ -0,0 +1,86 @@
+/*
+ * This file is part of GNU Taler
+ * (C) 2020 Taler Systems S.A.
+ *
+ * GNU Taler is free software; you can redistribute it and/or modify it under the
+ * terms of the GNU General Public License as published by the Free Software
+ * Foundation; either version 3, or (at your option) any later version.
+ *
+ * GNU Taler is distributed in the hope that it will be useful, but WITHOUT ANY
+ * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
+ * A PARTICULAR PURPOSE. See the GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along with
+ * GNU Taler; see the file COPYING. If not, see <http://www.gnu.org/licenses/>
+ */
+
+package net.taler.cashier
+
+import android.content.Context
+import android.util.Log
+import io.ktor.client.call.receive
+import io.ktor.client.features.ResponseException
+import io.ktor.http.HttpStatusCode
+import kotlinx.serialization.Serializable
+import net.taler.common.isOnline
+import java.net.UnknownHostException
+
+class Response<out T> private constructor(
+ private val value: Any?
+) {
+ companion object {
+ suspend fun <T> response(request: suspend () -> T): Response<T> {
+ return try {
+ Response(request())
+ } catch (e: Throwable) {
+ Log.e("HttpClient", "Error getting request", e)
+ Response(getFailure(e))
+ }
+ }
+
+ private suspend fun getFailure(e: Throwable): Failure = when (e) {
+ is ResponseException -> Failure(e, getExceptionString(e), e.response?.status)
+ else -> Failure(e, e.toString())
+ }
+
+ private suspend fun getExceptionString(e: ResponseException): String {
+ val response = e.response ?: return e.toString()
+ return try {
+ Log.e("TEST", "TRY RECEIVE $response")
+ val error: Error = response.receive()
+ "Error ${error.code}: ${error.hint}"
+ } catch (ex: Exception) {
+ "Status code: ${response.status.value}"
+ }
+ }
+ }
+
+ private val isFailure: Boolean get() = value is Failure
+
+ suspend fun onSuccess(block: suspend (result: T) -> Unit): Response<T> {
+ @Suppress("UNCHECKED_CAST")
+ if (!isFailure) block(value as T)
+ return this
+ }
+
+ suspend fun onError(block: suspend (failure: Failure) -> Unit): Response<T> {
+ if (value is Failure) block(value)
+ return this
+ }
+
+ data class Failure(
+ val exception: Throwable,
+ val msg: String,
+ val statusCode: HttpStatusCode? = null
+ ) {
+ fun isOffline(context: Context): Boolean {
+ return exception is UnknownHostException && !context.isOnline()
+ }
+ }
+
+ @Serializable
+ private class Error(
+ val code: Int?,
+ val hint: String?
+ )
+}