gnunet-svn
[Top][All Lists]
Advanced

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

[libeufin] branch master updated: nexus fetch


From: gnunet
Subject: [libeufin] branch master updated: nexus fetch
Date: Thu, 09 Nov 2023 18:28:27 +0100

This is an automated email from the git hooks/post-receive script.

ms pushed a commit to branch master
in repository libeufin.

The following commit(s) were added to refs/heads/master by this push:
     new 41628115 nexus fetch
41628115 is described below

commit 41628115dcac19c5f1532fdafb06e361a409fa8a
Author: MS <ms@taler.net>
AuthorDate: Thu Nov 9 18:25:24 2023 +0100

    nexus fetch
    
    - fixing the file logger
    - implementing --only-statements flag
    - fixing the SELECTion of non-existent execution_time
---
 .../main/kotlin/tech/libeufin/nexus/Database.kt    |  8 +-
 .../main/kotlin/tech/libeufin/nexus/EbicsFetch.kt  | 96 ++++++++++++++++------
 .../main/kotlin/tech/libeufin/nexus/EbicsSubmit.kt | 22 ++---
 3 files changed, 88 insertions(+), 38 deletions(-)

diff --git a/nexus/src/main/kotlin/tech/libeufin/nexus/Database.kt 
b/nexus/src/main/kotlin/tech/libeufin/nexus/Database.kt
index 78fc2039..cc91b557 100644
--- a/nexus/src/main/kotlin/tech/libeufin/nexus/Database.kt
+++ b/nexus/src/main/kotlin/tech/libeufin/nexus/Database.kt
@@ -319,10 +319,12 @@ class Database(dbConfig: String): java.io.Closeable {
         )
         stmt.executeQuery().use {
             if (!it.next()) return@runConn null
-            val timestamp = 
it.getLong("latest_execution_time").microsToJavaInstant()
-            if (timestamp == null)
+            val timestamp = it.getLong("latest_execution_time")
+            if (timestamp == 0L) return@runConn null
+            val asInstant = timestamp.microsToJavaInstant()
+            if (asInstant == null)
                 throw Exception("Could not convert latest_execution_time to 
Instant")
-            return@runConn timestamp
+            return@runConn asInstant
         }
     }
 
diff --git a/nexus/src/main/kotlin/tech/libeufin/nexus/EbicsFetch.kt 
b/nexus/src/main/kotlin/tech/libeufin/nexus/EbicsFetch.kt
index 86e7ec7b..b08bbede 100644
--- a/nexus/src/main/kotlin/tech/libeufin/nexus/EbicsFetch.kt
+++ b/nexus/src/main/kotlin/tech/libeufin/nexus/EbicsFetch.kt
@@ -7,13 +7,13 @@ import io.ktor.client.*
 import kotlinx.coroutines.runBlocking
 import org.apache.commons.compress.archivers.zip.ZipFile
 import org.apache.commons.compress.utils.SeekableInMemoryByteChannel
-import tech.libeufin.nexus.ebics.EbicsSideError
 import tech.libeufin.nexus.ebics.EbicsSideException
 import tech.libeufin.nexus.ebics.createEbics3DownloadInitialization
 import tech.libeufin.nexus.ebics.doEbicsDownload
 import tech.libeufin.util.ebics_h005.Ebics3Request
 import tech.libeufin.util.getXmlDate
 import tech.libeufin.util.toDbMicros
+import java.io.File
 import java.nio.file.Path
 import java.time.Instant
 import java.time.LocalDate
@@ -217,7 +217,7 @@ fun prepReportRequest(
  *         length is zero.  It returns null, if the bank assigned an
  *         error to the EBICS transaction.
  */
-suspend fun downloadRecords(
+private suspend fun downloadHelper(
     cfg: EbicsSetupConfig,
     bankKeys: BankPublicKeysFile,
     clientKeys: ClientPrivateKeysFile,
@@ -260,29 +260,32 @@ suspend fun downloadRecords(
  * @param content ZIP bytes from the server.
  */
 fun maybeLogFile(cfg: EbicsSetupConfig, content: ByteArray) {
+    // Main dir.
     val maybeLogDir = cfg.config.lookupString(
-        "[neuxs-fetch]",
+        "nexus-fetch",
         "STATEMENT_LOG_DIRECTORY"
     ) ?: return
-    try { Path.of(maybeLogDir).createDirectories() }
+    logger.debug("Logging to $maybeLogDir")
+    // Subdir based on current day.
+    val now = Instant.now()
+    val asUtcDate = LocalDate.ofInstant(now, ZoneId.of("UTC"))
+    val subDir = 
"${asUtcDate.year}-${asUtcDate.monthValue}-${asUtcDate.dayOfMonth}"
+    // Creating the combined dir.
+    val dirs = Path.of(maybeLogDir, subDir)
+    try { dirs.createDirectories() }
     catch (e: Exception) {
-        logger.error("Could not create log directory of path: $maybeLogDir")
+        logger.error("Could not create log directory of path: $dirs") // check 
how dirs stringifies.
         exitProcess(1)
     }
-    val now = Instant.now()
-    val asUtcDate = LocalDate.ofInstant(now, ZoneId.of("UTC"))
+    // Write each ZIP entry in the combined dir.
     content.unzipForEach { fileName, xmlContent ->
-        val f = Path.of(
-            
"${asUtcDate.year}-${asUtcDate.monthValue}-${asUtcDate.dayOfMonth}",
-            "${now.toDbMicros()}_$fileName"
-        ).toFile()
-        val completePath = Path.of(maybeLogDir, f.path)
+        val f  = File(dirs.toString(), "${now.toDbMicros()}_$fileName")
         // Rare: cannot download the same file twice in the same microsecond.
         if (f.exists()) {
-            logger.error("Log file exists already at: $completePath")
+            logger.error("Log file exists already at: ${f.path}")
             exitProcess(1)
         }
-        completePath.toFile().writeText(xmlContent)
+        f.writeText(xmlContent)
     }
 }
 
@@ -305,19 +308,24 @@ fun maybeLogFile(cfg: EbicsSetupConfig, content: 
ByteArray) {
  * @param clientKeys EBICS subscriber private keys.
  * @param bankKeys bank public keys.
  */
-suspend fun fetchHistory(
+private suspend fun fetchDocuments(
     cfg: EbicsSetupConfig,
     db: Database,
     httpClient: HttpClient,
     clientKeys: ClientPrivateKeysFile,
-    bankKeys: BankPublicKeysFile
+    bankKeys: BankPublicKeysFile,
+    whichDocument: SupportedDocument = SupportedDocument.CAMT_054
 ) {
     // maybe get last execution_date.
-    val lastExecutionTime = db.incomingPaymentLastExecTime()
-    // Asking unseen records.
-    val req = if (lastExecutionTime == null) 
prepNotificationRequest(isAppendix = false)
-    else prepNotificationRequest(lastExecutionTime, isAppendix = false)
-    val maybeContent = downloadRecords(
+    val lastExecutionTime: Instant? = db.incomingPaymentLastExecTime()
+    logger.debug("Fetching documents from timestamp: $lastExecutionTime")
+    val req = when(whichDocument) {
+        SupportedDocument.PAIN_002 -> prepAckRequest(startDate = 
lastExecutionTime)
+        SupportedDocument.CAMT_052 -> prepReportRequest(startDate = 
lastExecutionTime)
+        SupportedDocument.CAMT_053 -> prepStatementRequest(startDate = 
lastExecutionTime)
+        SupportedDocument.CAMT_054 -> prepNotificationRequest(startDate = 
lastExecutionTime, isAppendix = false)
+    }
+    val maybeContent = downloadHelper(
         cfg,
         bankKeys,
         clientKeys,
@@ -329,7 +337,13 @@ suspend fun fetchHistory(
     maybeLogFile(cfg, maybeContent)
 }
 
-class EbicsFetch: CliktCommand("Fetches bank records") {
+enum class SupportedDocument {
+    PAIN_002,
+    CAMT_053,
+    CAMT_052,
+    CAMT_054
+}
+class EbicsFetch: CliktCommand("Fetches bank records.  Defaults to camt.054 
notifications") {
     private val configFile by option(
         "--config", "-c",
         help = "set the configuration file"
@@ -340,6 +354,10 @@ class EbicsFetch: CliktCommand("Fetches bank records") {
                 "ignoring the 'frequency' configuration value"
     ).flag(default = false)
 
+    private val onlyStatements by option(
+        help = "Downloads only camt.053 statements"
+    ).flag(default = false)
+
     /**
      * This function collects the main steps of fetching banking records.
      * In this current version, it does not implement long polling, instead
@@ -366,9 +384,19 @@ class EbicsFetch: CliktCommand("Fetches bank records") {
             exitProcess(1)
         }
         val httpClient = HttpClient()
+        val whichDoc = if (onlyStatements) SupportedDocument.CAMT_053 else 
SupportedDocument.CAMT_054
         if (transient) {
             logger.info("Transient mode: fetching once and returning.")
-            runBlocking { fetchHistory(cfg, db, httpClient, clientKeys, 
bankKeys) }
+            runBlocking {
+                fetchDocuments(
+                    cfg,
+                    db,
+                    httpClient,
+                    clientKeys,
+                    bankKeys,
+                    whichDoc
+                )
+            }
             return
         }
         val frequency: NexusFrequency = doOrFail {
@@ -379,14 +407,32 @@ class EbicsFetch: CliktCommand("Fetches bank records") {
         logger.debug("Running with a frequency of ${frequency.fromConfig}")
         if (frequency.inSeconds == 0) {
             logger.warn("Long-polling not implemented, running therefore in 
transient mode")
-            runBlocking { fetchHistory(cfg, db, httpClient, clientKeys, 
bankKeys) }
+            runBlocking {
+                fetchDocuments(
+                    cfg,
+                    db,
+                    httpClient,
+                    clientKeys,
+                    bankKeys,
+                    whichDoc
+                )
+            }
             return
         }
         fixedRateTimer(
             name = "ebics submit period",
             period = (frequency.inSeconds * 1000).toLong(),
             action = {
-                runBlocking { fetchHistory(cfg, db, httpClient, clientKeys, 
bankKeys) }
+                runBlocking {
+                    fetchDocuments(
+                        cfg,
+                        db,
+                        httpClient,
+                        clientKeys,
+                        bankKeys,
+                        whichDoc
+                    )
+                }
             }
         )
     }
diff --git a/nexus/src/main/kotlin/tech/libeufin/nexus/EbicsSubmit.kt 
b/nexus/src/main/kotlin/tech/libeufin/nexus/EbicsSubmit.kt
index 8705c500..ed428643 100644
--- a/nexus/src/main/kotlin/tech/libeufin/nexus/EbicsSubmit.kt
+++ b/nexus/src/main/kotlin/tech/libeufin/nexus/EbicsSubmit.kt
@@ -30,6 +30,7 @@ import tech.libeufin.nexus.ebics.EbicsUploadException
 import tech.libeufin.nexus.ebics.submitPain001
 import tech.libeufin.util.parsePayto
 import tech.libeufin.util.toDbMicros
+import java.io.File
 import java.nio.file.Path
 import java.time.Instant
 import java.time.LocalDate
@@ -137,24 +138,25 @@ private suspend fun submitInitiatedPayment(
         "SUBMISSIONS_LOG_DIRECTORY"
     )
     if (logDir != null) {
-        try { Path.of(logDir).createDirectories() }
+        val now = Instant.now()
+        val asUtcDate = LocalDate.ofInstant(now, ZoneId.of("UTC"))
+        val subDir = 
"${asUtcDate.year}-${asUtcDate.monthValue}-${asUtcDate.dayOfMonth}"
+        val dirs = Path.of(logDir, subDir)
+        try { dirs.createDirectories() }
         catch (e: Exception) {
-            logger.error("Could not create log directory of path: $logDir")
+            logger.error("Could not create log directory of path: $dirs")
             exitProcess(1)
         }
-        val now = Instant.now()
-        val asUtcDate = LocalDate.ofInstant(now, ZoneId.of("UTC"))
-        val f = Path.of(
-            
"${asUtcDate.year}-${asUtcDate.monthValue}-${asUtcDate.dayOfMonth}",
+        val f = File(
+            dirs.toString(),
             
"${now.toDbMicros()}_requestUid_${initiatedPayment.requestUid}_pain.001.xml"
-        ).toFile()
-        val completePath = Path.of(logDir, f.path)
+            )
         // Very rare: same pain.001 should not be submitted twice in the same 
microsecond.
         if (f.exists()) {
-            logger.error("pain.001 log file exists already at: $completePath")
+            logger.error("pain.001 log file exists already at: $f")
             exitProcess(1)
         }
-        completePath.toFile().writeText(xml)
+        f.writeText(xml)
     }
 }
 

-- 
To stop receiving notification emails like this one, please contact
gnunet@gnunet.org.



reply via email to

[Prev in Thread] Current Thread [Next in Thread]