diff options
author | Antoine A <> | 2024-05-03 17:53:27 +0900 |
---|---|---|
committer | Antoine A <> | 2024-05-03 18:14:50 +0900 |
commit | 0dc33d16270b91eb0d2e3a78d08e319c5e4423cd (patch) | |
tree | b184a293d074ae08624f898195bfa509a646745a /nexus | |
parent | 8f18b1b5c872a6e83d52539e88fafc89d5dba7a9 (diff) | |
download | libeufin-0dc33d16270b91eb0d2e3a78d08e319c5e4423cd.tar.gz libeufin-0dc33d16270b91eb0d2e3a78d08e319c5e4423cd.tar.bz2 libeufin-0dc33d16270b91eb0d2e3a78d08e319c5e4423cd.zip |
nexus: add list cmd
Diffstat (limited to 'nexus')
-rw-r--r-- | nexus/src/main/kotlin/tech/libeufin/nexus/Main.kt | 143 | ||||
-rw-r--r-- | nexus/src/main/kotlin/tech/libeufin/nexus/db/PaymentDAO.kt | 124 |
2 files changed, 257 insertions, 10 deletions
diff --git a/nexus/src/main/kotlin/tech/libeufin/nexus/Main.kt b/nexus/src/main/kotlin/tech/libeufin/nexus/Main.kt index 68c8aa80..bda8affb 100644 --- a/nexus/src/main/kotlin/tech/libeufin/nexus/Main.kt +++ b/nexus/src/main/kotlin/tech/libeufin/nexus/Main.kt @@ -27,14 +27,14 @@ package tech.libeufin.nexus import com.github.ajalt.clikt.core.CliktCommand import com.github.ajalt.clikt.core.subcommands -import com.github.ajalt.clikt.parameters.arguments.argument -import com.github.ajalt.clikt.parameters.arguments.convert -import com.github.ajalt.clikt.parameters.groups.provideDelegate +import com.github.ajalt.clikt.parameters.arguments.* +import com.github.ajalt.clikt.parameters.groups.* import com.github.ajalt.clikt.parameters.options.* -import com.github.ajalt.clikt.parameters.types.path +import com.github.ajalt.clikt.parameters.types.* import kotlinx.serialization.json.Json import kotlinx.serialization.Serializable import kotlin.io.path.* +import kotlin.math.max import io.ktor.server.application.* import org.slf4j.Logger import org.slf4j.event.Level @@ -190,9 +190,142 @@ class FakeIncoming: CliktCommand("Genere a fake incoming payment") { } } +enum class ListKind { + incoming, + outgoing, + initiated; + + fun description(): String = when (this) { + incoming -> "Incoming transactions" + outgoing -> "Outgoing transactions" + initiated -> "Initiated transactions" + } +} + +class ListCmd: CliktCommand("List nexus transactions", name = "list") { + private val common by CommonOption() + private val kind: ListKind by argument( + help = "Which list to print", + helpTags = ListKind.entries.map { Pair(it.name, it.description()) }.toMap() + ).enum<ListKind>() + + override fun run() = cliCmd(logger, common.log) { + val cfg = loadConfig(common.config) + val dbCfg = cfg.dbConfig() + val currency = cfg.requireString("nexus-ebics", "currency") + + Database(dbCfg).use { db -> + fun fmtPayto(payto: String?): String { + if (payto == null) return "" + try { + val parsed = Payto.parse(payto).expectIban() + return buildString { + append(parsed.iban.toString()) + if (parsed.bic != null) append(" ${parsed.bic}") + if (parsed.receiverName != null) append(" ${parsed.receiverName}") + } + } catch (e: Exception) { + return payto + } + } + val (columnNames, rows) = when (kind) { + ListKind.incoming -> { + val txs = db.payment.metadataIncoming() + Pair( + listOf( + "transaction", "id", "reserve_pub", "debtor", "subject" + ), + txs.map { + listOf( + "${it.date} ${it.amount}", + it.id, + it.reservePub?.toString() ?: "", + fmtPayto(it.debtor), + it.subject + ) + } + ) + } + ListKind.outgoing -> { + val txs = db.payment.metadataOutgoing() + Pair( + listOf( + "transaction", "id", "creditor", "subject" + ), + txs.map { + listOf( + "${it.date} ${it.amount}", + it.id, + fmtPayto(it.creditor), + it.subject ?: "" + ) + } + ) + } + ListKind.initiated -> { + val txs = db.payment.metadataInitiated() + Pair( + listOf( + "transaction", "id", "submission", "creditor", "status", "subject" + ), + txs.map { + listOf( + "${it.date} ${it.amount}", + it.id, + "${it.submissionTime} ${it.submissionCounter}", + fmtPayto(it.creditor), + "${it.status} ${it.msg ?: ""}".trim(), + it.subject + ) + } + ) + } + } + val cols: List<Pair<String, Int>> = columnNames.mapIndexed { i, name -> + val maxRow: Int = rows.asSequence().map { it[i].length }.maxOrNull() ?: 0 + Pair(name, max(name.length, maxRow)) + } + val table = buildString { + fun padding(length: Int) { + repeat(length) { append (" ") } + } + var first = true + for ((name, len) in cols) { + if (!first) { + append("|") + } else { + first = false + } + val pad = len - name.length + padding(pad / 2) + append(name) + padding(pad / 2 + if (pad % 2 == 0) { 0 } else { 1 }) + } + append("\n") + for (row in rows) { + var first = true + for ((met, str) in cols.zip(row)) { + if (!first) { + append("|") + } else { + first = false + } + val (name, len) = met + val pad = len - str.length + append(str) + padding(pad) + } + append("\n") + } + } + print(table) + } + } +} + class TestingCmd : CliktCommand("Testing helper commands", name = "testing") { init { - subcommands(FakeIncoming()) + subcommands(FakeIncoming(), ListCmd()) } override fun run() = Unit diff --git a/nexus/src/main/kotlin/tech/libeufin/nexus/db/PaymentDAO.kt b/nexus/src/main/kotlin/tech/libeufin/nexus/db/PaymentDAO.kt index 05548b99..1253e084 100644 --- a/nexus/src/main/kotlin/tech/libeufin/nexus/db/PaymentDAO.kt +++ b/nexus/src/main/kotlin/tech/libeufin/nexus/db/PaymentDAO.kt @@ -19,10 +19,8 @@ package tech.libeufin.nexus.db -import tech.libeufin.common.EddsaPublicKey -import tech.libeufin.common.TalerAmount -import tech.libeufin.common.db.one -import tech.libeufin.common.micros +import tech.libeufin.common.db.* +import tech.libeufin.common.* import tech.libeufin.nexus.IncomingPayment import tech.libeufin.nexus.OutgoingPayment import java.time.Instant @@ -128,4 +126,120 @@ class PaymentDAO(private val db: Database) { } } } -}
\ No newline at end of file + + /** List incoming transaction metadata for debugging */ + suspend fun metadataIncoming(): List<IncomingTxMetadata> = db.conn { conn -> + val stmt = conn.prepareStatement(""" + SELECT + (amount).val as amount_val + ,(amount).frac AS amount_frac + ,wire_transfer_subject + ,execution_time + ,debit_payto_uri + ,bank_id + ,reserve_public_key + FROM incoming_transactions + LEFT OUTER JOIN talerable_incoming_transactions using (incoming_transaction_id) + ORDER BY execution_time + """) + stmt.all { + IncomingTxMetadata( + date = it.getLong("execution_time").asInstant(), + amount = it.getDecimal("amount"), + subject = it.getString("wire_transfer_subject"), + debtor = it.getString("debit_payto_uri"), + id = it.getString("bank_id"), + reservePub = it.getBytes("reserve_public_key")?.run { EddsaPublicKey(this) } + ) + } + } + + /** List outgoing transaction metadata for debugging */ + suspend fun metadataOutgoing(): List<OutgoingTxMetadata> = db.conn { conn -> + val stmt = conn.prepareStatement(""" + SELECT + (amount).val as amount_val + ,(amount).frac AS amount_frac + ,wire_transfer_subject + ,execution_time + ,credit_payto_uri + ,message_id + FROM outgoing_transactions + ORDER BY execution_time + """) + stmt.all { + OutgoingTxMetadata( + date = it.getLong("execution_time").asInstant(), + amount = it.getDecimal("amount"), + subject = it.getString("wire_transfer_subject"), + creditor = it.getString("credit_payto_uri"), + id = it.getString("message_id") + ) + } + } + + /** List initiated transaction metadata for debugging */ + suspend fun metadataInitiated(): List<InitiatedTxMetadata> = db.conn { conn -> + val stmt = conn.prepareStatement(""" + SELECT + (amount).val as amount_val + ,(amount).frac AS amount_frac + ,wire_transfer_subject + ,initiation_time + ,last_submission_time + ,submission_counter + ,credit_payto_uri + ,submitted + ,request_uid + ,failure_message + FROM initiated_outgoing_transactions + ORDER BY initiation_time + """) + stmt.all { + InitiatedTxMetadata( + date = it.getLong("initiation_time").asInstant(), + amount = it.getDecimal("amount"), + subject = it.getString("wire_transfer_subject"), + creditor = it.getString("credit_payto_uri"), + id = it.getString("request_uid"), + status = it.getString("submitted"), + msg = it.getString("failure_message"), + submissionTime = it.getLong("last_submission_time").asInstant(), + submissionCounter = it.getInt("submission_counter") + ) + } + } +} + +/** Incoming transaction metadata for debugging */ +data class IncomingTxMetadata( + val date: Instant, + val amount: DecimalNumber, + val subject: String, + val debtor: String, + val id: String, + val reservePub: EddsaPublicKey? +) + +/** Outgoing transaction metadata for debugging */ +data class OutgoingTxMetadata( + val date: Instant, + val amount: DecimalNumber, + val subject: String?, + val creditor: String?, + val id: String, + // TODO when merged with v11 +) + +/** Initiated metadata for debugging */ +data class InitiatedTxMetadata( + val date: Instant, + val amount: DecimalNumber, + val subject: String, + val creditor: String, + val id: String, + val status: String, + val msg: String?, + val submissionTime: Instant, + val submissionCounter: Int +)
\ No newline at end of file |