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()
)
}
}
}
|