summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorAntoine A <>2023-10-05 21:53:31 +0000
committerAntoine A <>2023-10-05 21:53:31 +0000
commit0cc10659126adb695eb547295aa125764d3a2c4d (patch)
treec13ed493babbbe91441c08f09635eb009f8993ce
parentdf8fc8bc5eef7d399e37e65b40a035b61cf66975 (diff)
downloadlibeufin-0cc10659126adb695eb547295aa125764d3a2c4d.tar.gz
libeufin-0cc10659126adb695eb547295aa125764d3a2c4d.tar.bz2
libeufin-0cc10659126adb695eb547295aa125764d3a2c4d.zip
Reuse logic between incoming and outgoing history
-rw-r--r--bank/src/main/kotlin/tech/libeufin/bank/BankMessages.kt4
-rw-r--r--bank/src/main/kotlin/tech/libeufin/bank/WireGatewayApiHandlers.kt144
-rw-r--r--bank/src/test/kotlin/TalerApiTest.kt1
3 files changed, 55 insertions, 94 deletions
diff --git a/bank/src/main/kotlin/tech/libeufin/bank/BankMessages.kt b/bank/src/main/kotlin/tech/libeufin/bank/BankMessages.kt
index da35b43e..b8acc5a9 100644
--- a/bank/src/main/kotlin/tech/libeufin/bank/BankMessages.kt
+++ b/bank/src/main/kotlin/tech/libeufin/bank/BankMessages.kt
@@ -669,7 +669,7 @@ data class TWGConfigResponse(
*/
@Serializable
data class IncomingHistory(
- val incoming_transactions: MutableList<IncomingReserveTransaction> = mutableListOf(),
+ val incoming_transactions: List<IncomingReserveTransaction>,
val credit_account: String // Receiver's Payto URI.
)
@@ -691,7 +691,7 @@ data class IncomingReserveTransaction(
*/
@Serializable
data class OutgoingHistory(
- val outgoing_transactions: MutableList<OutgoingTransaction> = mutableListOf(),
+ val outgoing_transactions: List<OutgoingTransaction>,
val debit_account: String // Debitor's Payto URI.
)
diff --git a/bank/src/main/kotlin/tech/libeufin/bank/WireGatewayApiHandlers.kt b/bank/src/main/kotlin/tech/libeufin/bank/WireGatewayApiHandlers.kt
index 19ab200e..4664a55b 100644
--- a/bank/src/main/kotlin/tech/libeufin/bank/WireGatewayApiHandlers.kt
+++ b/bank/src/main/kotlin/tech/libeufin/bank/WireGatewayApiHandlers.kt
@@ -120,122 +120,84 @@ fun Routing.talerWireGatewayHandlers(db: Database, ctx: BankApplicationContext)
return@post
}
- get("/accounts/{USERNAME}/taler-wire-gateway/history/incoming") {
- val username = call.authCheck(TokenScope.readonly, true)
+ suspend fun <T> historyEndpoint(call: ApplicationCall, direction: TransactionDirection, reduce: (List<T>, String) -> Any, map: (BankAccountTransaction) -> T?) {
+ call.authCheck(TokenScope.readonly, true)
val params = getHistoryParams(call.request)
val bankAccount = call.bankAccount()
if (!bankAccount.isTalerExchange) throw forbidden("History is not related to a Taler exchange.")
- val resp = IncomingHistory(credit_account = bankAccount.internalPaytoUri)
var start = params.start
var delta = params.delta
-
- // As we may ignore rows containing incorrect subjects, we may have to run several queries.
+ val items = mutableListOf<T>()
+
while (delta != 0L) {
- val history: List<BankAccountTransaction> = db.bankTransactionGetHistory(
+ val history = db.bankTransactionGetHistory(
start = start,
delta = delta,
bankAccountId = bankAccount.expectRowId(),
- withDirection = TransactionDirection.credit
+ withDirection = direction
)
if (history.isEmpty())
- break;
+ break; // TODO long polling here
history.forEach {
- val reservePub = try {
- EddsaPublicKey(it.subject)
- } catch (e: Exception) {
- logger.debug("Not containing a reserve pub: ${it.subject}")
- null
- }
- if (reservePub == null) {
- // This should usually not happen in the first place,
- // because transactions to the exchange without a valid
- // reserve pub should be bounced.
- logger.warn("exchange account $username contains invalid incoming transaction ${it.expectRowId()}")
- // Skip row
- start = it.expectRowId()
- } else {
- // Register new transacation
- resp.incoming_transactions.add(
- IncomingReserveTransaction(
- row_id = it.expectRowId(),
- amount = it.amount,
- date = TalerProtocolTimestamp(it.transactionDate),
- debit_account = it.debtorPaytoUri,
- reserve_pub = reservePub
- )
- )
- // Advance cursor
- start = it.expectRowId()
+ val item = map(it);
+ // Advance cursor
+ start = it.expectRowId()
+
+ if (item != null) {
+ items.add(item)
+ // Reduce delta
if (delta < 0) delta++ else delta--;
}
}
}
-
- if (resp.incoming_transactions.isEmpty()) {
+
+ if (items.isEmpty()) {
call.respond(HttpStatusCode.NoContent)
} else {
- call.respond(resp)
+ call.respond(reduce(items, bankAccount.internalPaytoUri))
}
}
- get("/accounts/{USERNAME}/taler-wire-gateway/history/outgoing") {
- val username = call.authCheck(TokenScope.readonly, true)
- val params = getHistoryParams(call.request)
- val bankAccount = call.bankAccount()
- if (!bankAccount.isTalerExchange) throw forbidden("History is not related to a Taler exchange.")
-
- val resp = OutgoingHistory(debit_account = bankAccount.internalPaytoUri)
- var start = params.start
- var delta = params.delta
-
- // As we may ignore rows containing incorrect subjects, we may have to run several queries.
- while (delta != 0L) {
- val history: List<BankAccountTransaction> = db.bankTransactionGetHistory(
- start = start,
- delta = delta,
- bankAccountId = bankAccount.expectRowId(),
- withDirection = TransactionDirection.debit
- )
- if (history.isEmpty())
- break;
- history.forEach {
- val metadata = try {
- val split = it.subject.split(" ")
- Pair(ShortHashCode(split[0]), split[1])
- } catch (e: Exception) {
- logger.debug("Not containing metadata: ${it.subject}")
- null
- }
- if (metadata == null) {
- // This should usually not happen in the first place,
- // because transactions from the exchange should be well formed
- logger.warn("exchange account $username contains invalid outgoing transaction ${it.expectRowId()}")
- // Skip row
- start = it.expectRowId()
- } else {
- // Register new transacation
- resp.outgoing_transactions.add(
- OutgoingTransaction(
- row_id = it.expectRowId(),
- date = TalerProtocolTimestamp(it.transactionDate),
- amount = it.amount,
- credit_account = it.creditorPaytoUri,
- wtid = metadata.first,
- exchange_base_url = metadata.second
- )
- )
- // Advance cursor
- start = it.expectRowId()
- if (delta < 0) delta++ else delta--;
- }
+ get("/accounts/{USERNAME}/taler-wire-gateway/history/incoming") {
+ historyEndpoint(call, TransactionDirection.credit, ::IncomingHistory) {
+ try {
+ val reservePub = EddsaPublicKey(it.subject)
+ IncomingReserveTransaction(
+ row_id = it.expectRowId(),
+ amount = it.amount,
+ date = TalerProtocolTimestamp(it.transactionDate),
+ debit_account = it.debtorPaytoUri,
+ reserve_pub = reservePub
+ )
+ } catch (e: Exception) {
+ // This should usually not happen in the first place,
+ // because transactions to the exchange without a valid
+ // reserve pub should be bounced.
+ logger.warn("Invalid incoming transaction ${it.expectRowId()}: ${it.subject}")
+ null
}
}
+ }
- if (resp.outgoing_transactions.isEmpty()) {
- call.respond(HttpStatusCode.NoContent)
- } else {
- call.respond(resp)
+ get("/accounts/{USERNAME}/taler-wire-gateway/history/outgoing") {
+ historyEndpoint(call, TransactionDirection.debit, ::OutgoingHistory) {
+ try {
+ val split = it.subject.split(" ")
+ OutgoingTransaction(
+ row_id = it.expectRowId(),
+ date = TalerProtocolTimestamp(it.transactionDate),
+ amount = it.amount,
+ credit_account = it.creditorPaytoUri,
+ wtid = ShortHashCode(split[0]),
+ exchange_base_url = split[1]
+ )
+ } catch (e: Exception) {
+ // This should usually not happen in the first place,
+ // because transactions from the exchange should be well formed
+ logger.warn("Invalid outgoing transaction ${it.expectRowId()}: ${it.subject}")
+ null
+ }
}
}
diff --git a/bank/src/test/kotlin/TalerApiTest.kt b/bank/src/test/kotlin/TalerApiTest.kt
index 3419a02e..c76fd30e 100644
--- a/bank/src/test/kotlin/TalerApiTest.kt
+++ b/bank/src/test/kotlin/TalerApiTest.kt
@@ -360,7 +360,6 @@ class TalerApiTest {
}
// Testing ranges.
- val mockReservePub = randShortHashCode().encoded
for (i in 1..400)
transfer(db, 2, bankAccountFoo)