summaryrefslogtreecommitdiff
path: root/merchant-lib/src/main/java/net/taler
diff options
context:
space:
mode:
Diffstat (limited to 'merchant-lib/src/main/java/net/taler')
-rw-r--r--merchant-lib/src/main/java/net/taler/merchantlib/MerchantApi.kt48
-rw-r--r--merchant-lib/src/main/java/net/taler/merchantlib/MerchantConfig.kt37
-rw-r--r--merchant-lib/src/main/java/net/taler/merchantlib/PostOrderRequest.kt83
-rw-r--r--merchant-lib/src/main/java/net/taler/merchantlib/Response.kt63
4 files changed, 230 insertions, 1 deletions
diff --git a/merchant-lib/src/main/java/net/taler/merchantlib/MerchantApi.kt b/merchant-lib/src/main/java/net/taler/merchantlib/MerchantApi.kt
index 3406f78..335e42d 100644
--- a/merchant-lib/src/main/java/net/taler/merchantlib/MerchantApi.kt
+++ b/merchant-lib/src/main/java/net/taler/merchantlib/MerchantApi.kt
@@ -21,6 +21,16 @@ import io.ktor.client.engine.okhttp.OkHttp
import io.ktor.client.features.json.JsonFeature
import io.ktor.client.features.json.serializer.KotlinxSerializer
import io.ktor.client.request.get
+import io.ktor.client.request.header
+import io.ktor.client.request.post
+import io.ktor.http.ContentType.Application.Json
+import io.ktor.http.HttpHeaders.Authorization
+import io.ktor.http.contentType
+import kotlinx.serialization.json.Json
+import kotlinx.serialization.json.JsonConfiguration
+import net.taler.common.ContractTerms
+import net.taler.merchantlib.Response.Companion.failure
+import net.taler.merchantlib.Response.Companion.success
class MerchantApi(private val httpClient: HttpClient) {
@@ -30,10 +40,46 @@ class MerchantApi(private val httpClient: HttpClient) {
return httpClient.get("$baseUrl/config")
}
+ suspend fun postOrder(
+ merchantConfig: MerchantConfig,
+ contractTerms: ContractTerms
+ ): Response<PostOrderResponse> = response {
+ httpClient.post(merchantConfig.urlFor("private/orders")) {
+ header(Authorization, "ApiKey ${merchantConfig.apiKey}")
+ contentType(Json)
+ body = PostOrderRequest(contractTerms)
+ } as PostOrderResponse
+ }
+
+ suspend fun checkOrder(
+ merchantConfig: MerchantConfig,
+ orderId: String
+ ): Response<CheckPaymentResponse> = response {
+ httpClient.get(merchantConfig.urlFor("private/orders/$orderId")) {
+ header(Authorization, "ApiKey ${merchantConfig.apiKey}")
+ } as CheckPaymentResponse
+ }
+
+ private suspend fun <T> response(request: suspend () -> T): Response<T> {
+ return try {
+ success(request())
+ } catch (e: Throwable) {
+ failure(e)
+ }
+ }
}
private fun getDefaultHttpClient(): HttpClient = HttpClient(OkHttp) {
install(JsonFeature) {
- serializer = KotlinxSerializer()
+ serializer = getSerializer()
}
}
+
+fun getSerializer() = KotlinxSerializer(
+ Json(
+ JsonConfiguration(
+ encodeDefaults = false,
+ ignoreUnknownKeys = true
+ )
+ )
+)
diff --git a/merchant-lib/src/main/java/net/taler/merchantlib/MerchantConfig.kt b/merchant-lib/src/main/java/net/taler/merchantlib/MerchantConfig.kt
new file mode 100644
index 0000000..71185b9
--- /dev/null
+++ b/merchant-lib/src/main/java/net/taler/merchantlib/MerchantConfig.kt
@@ -0,0 +1,37 @@
+/*
+ * 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.merchantlib
+
+import kotlinx.serialization.SerialName
+import kotlinx.serialization.Serializable
+
+@Serializable
+data class MerchantConfig(
+ @SerialName("base_url")
+ val baseUrl: String,
+ val instance: String,
+ @SerialName("api_key")
+ val apiKey: String
+) {
+ fun urlFor(endpoint: String, params: Map<String, String>? = null): String {
+ val sb = StringBuilder(baseUrl)
+ if (sb.last() != '/') sb.append('/')
+ sb.append("instances/$instance/")
+ sb.append(endpoint)
+ return sb.toString()
+ }
+}
diff --git a/merchant-lib/src/main/java/net/taler/merchantlib/PostOrderRequest.kt b/merchant-lib/src/main/java/net/taler/merchantlib/PostOrderRequest.kt
new file mode 100644
index 0000000..a6e74d6
--- /dev/null
+++ b/merchant-lib/src/main/java/net/taler/merchantlib/PostOrderRequest.kt
@@ -0,0 +1,83 @@
+/*
+ * 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.merchantlib
+
+import kotlinx.serialization.Decoder
+import kotlinx.serialization.Encoder
+import kotlinx.serialization.KSerializer
+import kotlinx.serialization.SerialName
+import kotlinx.serialization.Serializable
+import kotlinx.serialization.Serializer
+import kotlinx.serialization.json.JsonInput
+import kotlinx.serialization.json.JsonObject
+import net.taler.common.ContractTerms
+
+@Serializable
+data class PostOrderRequest(
+ @SerialName("order")
+ val contractTerms: ContractTerms
+
+)
+
+@Serializable
+data class PostOrderResponse(
+ @SerialName("order_id")
+ val orderId: String
+)
+
+@Serializable
+sealed class CheckPaymentResponse {
+ abstract val paid: Boolean
+
+ @Serializer(forClass = CheckPaymentResponse::class)
+ companion object : KSerializer<CheckPaymentResponse> {
+ override fun deserialize(decoder: Decoder): CheckPaymentResponse {
+ val input = decoder as JsonInput
+ val tree = input.decodeJson() as JsonObject
+ val paid = tree.getPrimitive("paid").boolean
+// return if (paid) decoder.json.fromJson(Paid.serializer(), tree)
+// else decoder.json.fromJson(Unpaid.serializer(), tree)
+ // manual parsing due to https://github.com/Kotlin/kotlinx.serialization/issues/576
+ return if (paid) Paid(
+ refunded = tree.getPrimitive("refunded").boolean
+ ) else Unpaid(
+ talerPayUri = tree.getPrimitive("taler_pay_uri").content
+ )
+ }
+
+ override fun serialize(encoder: Encoder, value: CheckPaymentResponse) = when (value) {
+ is Unpaid -> Unpaid.serializer().serialize(encoder, value)
+ is Paid -> Paid.serializer().serialize(encoder, value)
+ }
+ }
+
+ @Serializable
+ data class Unpaid(
+ override val paid: Boolean = false,
+ @SerialName("taler_pay_uri")
+ val talerPayUri: String,
+ @SerialName("already_paid_order_id")
+ val alreadyPaidOrderId: String? = null
+ ) : CheckPaymentResponse()
+
+ @Serializable
+ data class Paid(
+ override val paid: Boolean = true,
+ val refunded: Boolean
+ ) : CheckPaymentResponse()
+
+}
diff --git a/merchant-lib/src/main/java/net/taler/merchantlib/Response.kt b/merchant-lib/src/main/java/net/taler/merchantlib/Response.kt
new file mode 100644
index 0000000..23fa101
--- /dev/null
+++ b/merchant-lib/src/main/java/net/taler/merchantlib/Response.kt
@@ -0,0 +1,63 @@
+/*
+ * 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.merchantlib
+
+import io.ktor.client.call.receive
+import io.ktor.client.features.ClientRequestException
+import kotlinx.serialization.Serializable
+
+class Response<out T> private constructor(
+ private val value: Any?
+) {
+
+ companion object {
+ fun <T> success(value: T): Response<T> =
+ Response(value)
+
+ fun <T> failure(e: Throwable): Response<T> =
+ Response(Failure(e))
+ }
+
+ val isFailure: Boolean get() = value is Failure
+
+ suspend fun handle(onFailure: ((String) -> Any)? = null, onSuccess: ((T) -> Any)? = null) {
+ if (value is Failure) onFailure?.let { it(getFailureString(value)) }
+ else onSuccess?.let {
+ @Suppress("UNCHECKED_CAST")
+ it(value as T)
+ }
+ }
+
+ private suspend fun getFailureString(failure: Failure): String = when (failure.exception) {
+ is ClientRequestException -> getExceptionString(failure.exception)
+ else -> failure.exception.toString()
+ }
+
+ private suspend fun getExceptionString(e: ClientRequestException): String {
+ val error: Error = e.response.receive()
+ return "Error ${error.code}: ${error.hint}"
+ }
+
+ private class Failure(val exception: Throwable)
+
+ @Serializable
+ private class Error(
+ val code: Int?,
+ val hint: String?
+ )
+
+}