aboutsummaryrefslogtreecommitdiff
path: root/nexus
diff options
context:
space:
mode:
authorAntoine A <>2024-05-03 17:53:27 +0900
committerAntoine A <>2024-05-03 18:14:50 +0900
commit0dc33d16270b91eb0d2e3a78d08e319c5e4423cd (patch)
treeb184a293d074ae08624f898195bfa509a646745a /nexus
parent8f18b1b5c872a6e83d52539e88fafc89d5dba7a9 (diff)
downloadlibeufin-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.kt143
-rw-r--r--nexus/src/main/kotlin/tech/libeufin/nexus/db/PaymentDAO.kt124
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