summaryrefslogtreecommitdiff
path: root/wallee-c2ec/app/src/main/java/ch/bfh/habej2/wallee_c2ec/client/taler/BankIntegrationClient.kt
blob: 55b9b8d7d3fd189dfe8a9d1867749ca8df43a690 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
package ch.bfh.habej2.wallee_c2ec.client.taler

import ch.bfh.habej2.wallee_c2ec.client.taler.model.BankIntegrationConfig
import ch.bfh.habej2.wallee_c2ec.client.taler.model.PaymentNotification
import ch.bfh.habej2.wallee_c2ec.client.taler.model.WithdrawalOperation
import ch.bfh.habej2.wallee_c2ec.client.taler.model.WithdrawalOperationStatus
import ch.bfh.habej2.wallee_c2ec.config.TalerBankIntegrationConfig
import com.squareup.moshi.Moshi
import okhttp3.HttpUrl
import okhttp3.Interceptor
import okhttp3.OkHttpClient
import okhttp3.Request
import okhttp3.Response
import java.util.Optional

class BankIntegrationClientException(
    val status: Int,
    msg: String
): RuntimeException(msg)

class BankIntegrationClient(
    private val config: TalerBankIntegrationConfig
) {

    private val WITHDRAWAL_OP = "withdrawal-operation"

    private val client: OkHttpClient =
        OkHttpClient.Builder()
            .addInterceptor(C2ECBasicAuthInterceptor(config))
            .build()

    private fun baseUrlBuilder() = HttpUrl.Builder()
        .encodedPath(config.bankIntegrationBaseUrl)

    private fun configUrl() = baseUrlBuilder()
        .addPathSegment("config")
        .build()
    private fun withdrawalByWopid(encodedWopid: String) = baseUrlBuilder()
        .addPathSegment(WITHDRAWAL_OP)
        .addPathSegment(encodedWopid)
        .build()

    private fun <T> serializer(clazz: Class<T>) = Moshi.Builder().build().adapter(clazz)

    private fun withdrawalConfirm(encodedWopid: String) = withdrawalByWopid(encodedWopid)
        .newBuilder()
        .addPathSegment("confirm")
        .build()
    private fun withdrawalAbort(encodedWopid: String) = withdrawalByWopid(encodedWopid)
        .newBuilder()
        .addPathSegment("abort")
        .build()

    fun retrieveBankIntegrationConfig(): Optional<BankIntegrationConfig> {

        val req = Request.Builder()
            .get()
            .url(configUrl())
            .build()
        val response = client.newCall(req).execute()
        return parseOrEmpty(response)
    }

    fun retrieveWithdrawalStatus(
        wopid: String,
        longPollMs: Int,
        oldState: WithdrawalOperationStatus = WithdrawalOperationStatus.PENDING
    ): Optional<WithdrawalOperation> {

        val req = Request.Builder()
            .get()
            .url(withdrawalByWopid(wopid)
                .newBuilder()
                .addQueryParameter("long_poll_ms", longPollMs.toString())
                .addQueryParameter("old_state", oldState.value)
                .build()
            )
            .build()
        val response = client.newCall(req).execute()
        return parseOrEmpty(response)
    }

    fun sendPaymentNotification(payment: PaymentNotification) {


        println("sending payment notification...")
    }

    fun abortWithdrawal(wopid: String) {
        println("aborting withdrawal")
    }

    private inline fun <reified T: Any> parseOrEmpty(response: Response): Optional<T> {

        if (response.isSuccessful) {
            if (response.body != null) {
                val content = serializer(T::class.java).fromJson(response.body!!.source())
                if (content != null) {
                    return Optional.of(content)
                }
                return Optional.empty()
            }
            return Optional.empty()
        }
        throw BankIntegrationClientException(response.code, "request unsuccessful")
    }

    private class C2ECBasicAuthInterceptor(
        private val config: TalerBankIntegrationConfig
    ) : Interceptor {

        override fun intercept(chain: Interceptor.Chain): Response {

            val base64EncodedCredentials = java.util.Base64
                .getUrlEncoder()
                .encode("${config.terminalId}:${config.accessToken}".toByteArray())
                .toString()

            return chain.proceed(
                chain.request().newBuilder()
                    .header("Authorization", base64EncodedCredentials)
                    .build()
            )
        }
    }
}