libeufin

Integration and sandbox testing for FinTech APIs and data formats
Log | Files | Refs | Submodules | README | LICENSE

commit b2dff673b9a0d31457ed7648bcd24aa50dca730d
parent fcfd5497b88399fa7c6f74e61c868b2e9b947ecf
Author: MS <ms@taler.net>
Date:   Wed,  8 Nov 2023 10:24:40 +0100

nexus fetch: drafting the CLI

Diffstat:
Anexus/src/main/kotlin/tech/libeufin/nexus/EbicsFetch.kt | 92+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Mnexus/src/main/kotlin/tech/libeufin/nexus/EbicsSubmit.kt | 3++-
Mnexus/src/main/kotlin/tech/libeufin/nexus/Main.kt | 2+-
3 files changed, 95 insertions(+), 2 deletions(-)

diff --git a/nexus/src/main/kotlin/tech/libeufin/nexus/EbicsFetch.kt b/nexus/src/main/kotlin/tech/libeufin/nexus/EbicsFetch.kt @@ -0,0 +1,91 @@ +package tech.libeufin.nexus + +import com.github.ajalt.clikt.core.CliktCommand +import com.github.ajalt.clikt.parameters.options.flag +import com.github.ajalt.clikt.parameters.options.option +import io.ktor.client.* +import kotlin.concurrent.fixedRateTimer +import kotlin.system.exitProcess + +/** + * Fetches the banking records via EBICS, calling the CAMT + * parsing logic and finally updating the database accordingly. + * + * @param cfg config handle. + * @param db database connection + * @param httpClient HTTP client handle to reach the bank + * @param clientKeys EBICS subscriber private keys. + * @param bankKeys bank public keys. + */ +fun fetchHistory( + cfg: EbicsSetupConfig, + db: Database, + httpClient: HttpClient, + clientKeys: ClientPrivateKeysFile, + bankKeys: BankPublicKeysFile +) { + throw NotImplementedError() +} + +class EbicsFetch: CliktCommand("Fetches bank records") { + private val configFile by option( + "--config", "-c", + help = "set the configuration file" + ) + private val transient by option( + "--transient", + help = "This flag fetches only once from the bank and returns, " + + "ignoring the 'frequency' configuration value" + ).flag(default = false) + + /** + * This function collects the main steps of fetching banking records. + * In this current version, it does not implement long polling, instead + * it runs transient if FREQUENCY is zero. Transient is also the default + * mode when no flags are passed to the invocation. + * FIXME: reduce code duplication with the submit subcommand. + */ + override fun run() { + val cfg: EbicsSetupConfig = doOrFail { + extractEbicsConfig(configFile) + } + // Fail now if keying is incomplete. + if (!isKeyingComplete(cfg)) exitProcess(1) + val dbCfg = cfg.config.extractDbConfigOrFail() + val db = Database(dbCfg.dbConnStr) + val bankKeys = loadBankKeys(cfg.bankPublicKeysFilename) ?: exitProcess(1) + if (!bankKeys.accepted) { + logger.error("Bank keys are not accepted, yet. Won't fetch any records.") + exitProcess(1) + } + val clientKeys = loadPrivateKeysFromDisk(cfg.clientPrivateKeysFilename) + if (clientKeys == null) { + logger.error("Client private keys not found at: ${cfg.clientPrivateKeysFilename}") + exitProcess(1) + } + val httpClient = HttpClient() + if (transient) { + logger.info("Transient mode: fetching once and returning.") + fetchHistory(cfg, db, httpClient, clientKeys, bankKeys) + return + } + val frequency: NexusFrequency = doOrFail { + val configValue = cfg.config.requireString("nexus-fetch", "frequency") + val frequencySeconds = checkFrequency(configValue) + return@doOrFail NexusFrequency(frequencySeconds, configValue) + } + logger.debug("Running with a frequency of ${frequency.fromConfig}") + if (frequency.inSeconds == 0) { + logger.warn("Long-polling not implemented, running therefore in transient mode") + fetchHistory(cfg, db, httpClient, clientKeys, bankKeys) + return + } + fixedRateTimer( + name = "ebics submit period", + period = (frequency.inSeconds * 1000).toLong(), + action = { + fetchHistory(cfg, db, httpClient, clientKeys, bankKeys) + } + ) + } +} +\ No newline at end of file diff --git a/nexus/src/main/kotlin/tech/libeufin/nexus/EbicsSubmit.kt b/nexus/src/main/kotlin/tech/libeufin/nexus/EbicsSubmit.kt @@ -251,6 +251,7 @@ class EbicsSubmit : CliktCommand("Submits any initiated payment found in the dat * Submits any initiated payment that was not submitted * so far and -- according to the configuration -- returns * or long-polls (currently not implemented) for new payments. + * FIXME: reduce code duplication with the fetch subcommand. */ override fun run() { val cfg: EbicsSetupConfig = doOrFail { @@ -260,7 +261,6 @@ class EbicsSubmit : CliktCommand("Submits any initiated payment found in the dat if (!isKeyingComplete(cfg)) exitProcess(1) val dbCfg = cfg.config.extractDbConfigOrFail() val db = Database(dbCfg.dbConnStr) - val httpClient = HttpClient() val bankKeys = loadBankKeys(cfg.bankPublicKeysFilename) ?: exitProcess(1) if (!bankKeys.accepted) { logger.error("Bank keys are not accepted, yet. Won't submit any payment.") @@ -271,6 +271,7 @@ class EbicsSubmit : CliktCommand("Submits any initiated payment found in the dat logger.error("Client private keys not found at: ${cfg.clientPrivateKeysFilename}") exitProcess(1) } + val httpClient = HttpClient() if (transient) { logger.info("Transient mode: submitting what found and returning.") submitBatch(cfg, db, httpClient, clientKeys, bankKeys) diff --git a/nexus/src/main/kotlin/tech/libeufin/nexus/Main.kt b/nexus/src/main/kotlin/tech/libeufin/nexus/Main.kt @@ -303,7 +303,7 @@ fun TalerConfig.extractDbConfigOrFail(): DatabaseConfig = class LibeufinNexusCommand : CliktCommand() { init { versionOption(getVersion()) - subcommands(EbicsSetup(), DbInit(), EbicsSubmit()) + subcommands(EbicsSetup(), DbInit(), EbicsSubmit(), EbicsFetch()) } override fun run() = Unit }