From a46b61bec3e670422fe8e84db44c07f80272495b Mon Sep 17 00:00:00 2001 From: Antoine A <> Date: Wed, 20 Mar 2024 18:33:45 +0100 Subject: Share duration parsing with libeufin-nexus --- common/src/main/kotlin/TalerConfig.kt | 2 +- common/src/test/kotlin/ConfigTest.kt | 47 ++++++++++++++ .../main/kotlin/tech/libeufin/nexus/EbicsFetch.kt | 18 +++--- .../main/kotlin/tech/libeufin/nexus/EbicsSubmit.kt | 22 +++---- nexus/src/main/kotlin/tech/libeufin/nexus/Main.kt | 74 ---------------------- nexus/src/test/kotlin/ConfigLoading.kt | 43 ------------- 6 files changed, 66 insertions(+), 140 deletions(-) create mode 100644 common/src/test/kotlin/ConfigTest.kt delete mode 100644 nexus/src/test/kotlin/ConfigLoading.kt diff --git a/common/src/main/kotlin/TalerConfig.kt b/common/src/main/kotlin/TalerConfig.kt index edcc2faa..c0148278 100644 --- a/common/src/main/kotlin/TalerConfig.kt +++ b/common/src/main/kotlin/TalerConfig.kt @@ -100,7 +100,7 @@ fun ConfigSource.fromFile(file: Path?): TalerConfig { * @param configSource information about where to load configuration defaults from */ class TalerConfig internal constructor( - val configSource: ConfigSource, + val configSource: ConfigSource ) { private val sectionMap: MutableMap = mutableMapOf() diff --git a/common/src/test/kotlin/ConfigTest.kt b/common/src/test/kotlin/ConfigTest.kt new file mode 100644 index 00000000..cb573501 --- /dev/null +++ b/common/src/test/kotlin/ConfigTest.kt @@ -0,0 +1,47 @@ +/* + * This file is part of LibEuFin. + * Copyright (C) 2024 Taler Systems S.A. + + * LibEuFin is free software; you can redistribute it and/or modify + * it under the terms of the GNU Affero General Public License as + * published by the Free Software Foundation; either version 3, or + * (at your option) any later version. + + * LibEuFin is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY + * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General + * Public License for more details. + + * You should have received a copy of the GNU Affero General Public + * License along with LibEuFin; see the file COPYING. If not, see + * + */ + +import org.junit.Test +import java.time.Duration +import tech.libeufin.common.* +import kotlin.test.* + +class ConfigTest { + @Test + fun timeParsing() { + fun parseTime(raw: String): Duration { + val cfg = TalerConfig(ConfigSource("test", "test", "test")) + cfg.loadFromMem(""" + [test] + time = "$raw" + """, null) + return cfg.requireDuration("test", "time") + } + assertEquals(Duration.ofSeconds(1), parseTime("1s")) + assertEquals(parseTime("1 s"), parseTime("1s")) + assertEquals(Duration.ofMinutes(10), parseTime("10m")) + assertEquals(parseTime("10 m"), parseTime("10m")) + assertEquals(Duration.ofHours(1), parseTime("01h")) + assertEquals( + Duration.ofHours(1).plus(Duration.ofMinutes(10)).plus(Duration.ofSeconds(12)), + parseTime("1h10m12s") + ) + assertEquals(parseTime("1h10m12s"), parseTime("1h10'12\"")) + } +} \ No newline at end of file diff --git a/nexus/src/main/kotlin/tech/libeufin/nexus/EbicsFetch.kt b/nexus/src/main/kotlin/tech/libeufin/nexus/EbicsFetch.kt index 47c021cd..298d84b4 100644 --- a/nexus/src/main/kotlin/tech/libeufin/nexus/EbicsFetch.kt +++ b/nexus/src/main/kotlin/tech/libeufin/nexus/EbicsFetch.kt @@ -32,10 +32,12 @@ import tech.libeufin.nexus.db.* import java.io.IOException import java.io.InputStream import java.time.Instant +import java.time.Duration import java.time.LocalDate import java.time.ZoneId import kotlin.io.* import kotlin.io.path.* +import kotlin.time.toKotlinDuration /** * Necessary data to perform a download. @@ -389,20 +391,16 @@ class EbicsFetch: CliktCommand("Fetches EBICS files") { throw Exception("Failed to fetch documents") } } else { - val configValue = cfg.config.requireString("nexus-fetch", "frequency") - val frequencySeconds = checkFrequency(configValue) - val cfgFrequency: NexusFrequency = NexusFrequency(frequencySeconds, configValue) - logger.debug("Running with a frequency of ${cfgFrequency.fromConfig}") - val frequency: NexusFrequency? = if (cfgFrequency.inSeconds == 0) { + var frequency: Duration = cfg.config.requireDuration("nexus-fetch", "frequency") + val raw = cfg.config.requireString("nexus-fetch", "frequency") + logger.debug("Running with a frequency of $raw") + if (frequency == Duration.ZERO) { logger.warn("Long-polling not implemented, running therefore in transient mode") - null - } else { - cfgFrequency } do { fetchDocuments(db, ctx, docs) - delay(((frequency?.inSeconds ?: 0) * 1000).toLong()) - } while (frequency != null) + delay(frequency.toKotlinDuration()) + } while (frequency != Duration.ZERO) } } } diff --git a/nexus/src/main/kotlin/tech/libeufin/nexus/EbicsSubmit.kt b/nexus/src/main/kotlin/tech/libeufin/nexus/EbicsSubmit.kt index 8366f064..cf206380 100644 --- a/nexus/src/main/kotlin/tech/libeufin/nexus/EbicsSubmit.kt +++ b/nexus/src/main/kotlin/tech/libeufin/nexus/EbicsSubmit.kt @@ -29,6 +29,7 @@ import tech.libeufin.nexus.ebics.* import tech.libeufin.nexus.db.* import java.time.* import java.util.* +import kotlin.time.toKotlinDuration /** * Groups useful parameters to submit pain.001 via EBICS. @@ -156,20 +157,17 @@ class EbicsSubmit : CliktCommand("Submits any initiated payment found in the dat fileLogger = FileLogger(ebicsLog) ) Database(dbCfg.dbConnStr).use { db -> - val frequency = if (transient) { + val frequency: Duration = if (transient) { logger.info("Transient mode: submitting what found and returning.") - null + Duration.ZERO } else { - val configValue = cfg.config.requireString("nexus-submit", "frequency") - val frequencySeconds = checkFrequency(configValue) - val frequency: NexusFrequency = NexusFrequency(frequencySeconds, configValue) - logger.debug("Running with a frequency of ${frequency.fromConfig}") - if (frequency.inSeconds == 0) { + var frequency = cfg.config.requireDuration("nexus-submit", "frequency") + val raw = cfg.config.requireString("nexus-submit", "frequency") + logger.debug("Running with a frequency of $raw") + if (frequency == Duration.ZERO) { logger.warn("Long-polling not implemented, running therefore in transient mode") - null - } else { - frequency } + frequency } do { try { @@ -178,8 +176,8 @@ class EbicsSubmit : CliktCommand("Submits any initiated payment found in the dat throw Exception("Failed to submit payments") } // TODO take submitBatch taken time in the delay - delay(((frequency?.inSeconds ?: 0) * 1000).toLong()) - } while (frequency != null) + delay(frequency.toKotlinDuration()) + } while (frequency != Duration.ZERO) } } } \ No newline at end of file diff --git a/nexus/src/main/kotlin/tech/libeufin/nexus/Main.kt b/nexus/src/main/kotlin/tech/libeufin/nexus/Main.kt index 8a51c766..b9582976 100644 --- a/nexus/src/main/kotlin/tech/libeufin/nexus/Main.kt +++ b/nexus/src/main/kotlin/tech/libeufin/nexus/Main.kt @@ -55,80 +55,6 @@ data class IbanAccountMetadata( val name: String ) -/** - * Contains the frequency of submit or fetch iterations. - */ -data class NexusFrequency( - /** - * Value in seconds of the FREQUENCY configuration - * value, found either under [nexus-fetch] or [nexus-submit] - */ - val inSeconds: Int, - /** - * Copy of the value found in the configuration. Used - * for logging. - */ - val fromConfig: String -) - -/** - * Converts human-readable duration in how many seconds. Supports - * the suffixes 's' (seconds), 'm' (minute), 'h' (hours). A valid - * duration is therefore, for example, Nm, where N is the number of - * minutes. - * - * @param trimmed duration - * @return how many seconds is the duration input, or null if the input - * is not valid. - */ -fun getFrequencyInSeconds(humanFormat: String): Int? { - val trimmed = humanFormat.trim() - if (trimmed.isEmpty()) { - logger.error("Input was empty") - return null - } - val howManySeconds: Int = when (val lastChar = trimmed.last()) { - 's' -> {1} - 'm' -> {60} - 'h' -> {60 * 60} - else -> { - logger.error("Duration symbol not one of s, m, h. '$lastChar' was found instead") - return null - } - } - val maybeNumber = trimmed.dropLast(1) - val howMany = try { - maybeNumber.trimEnd().toInt() - } catch (e: Exception) { - logger.error("Prefix was not a valid input: '$maybeNumber'") - return null - } - if (howMany == 0) return 0 - val ret = howMany * howManySeconds - if (howMany != ret / howManySeconds) { - logger.error("Result overflew") - return null - } - return ret -} - -/** - * Sanity-checks the frequency found in the configuration and - * either returns it or fails the process. Note: the returned - * value is also guaranteed to be non-negative. - * - * @param foundInConfig frequency value as found in the configuration. - * @return the duration in seconds of the value found in the configuration. - */ -fun checkFrequency(foundInConfig: String): Int { - val frequencySeconds = getFrequencyInSeconds(foundInConfig) - ?: throw Exception("Invalid frequency value in config section nexus-submit: $foundInConfig") - if (frequencySeconds < 0) { - throw Exception("Configuration error: cannot operate with a negative submit frequency ($foundInConfig)") - } - return frequencySeconds -} - fun Instant.fmtDate(): String = DateTimeFormatter.ISO_LOCAL_DATE.withZone(ZoneId.of("UTC")).format(this) diff --git a/nexus/src/test/kotlin/ConfigLoading.kt b/nexus/src/test/kotlin/ConfigLoading.kt deleted file mode 100644 index ebdfa381..00000000 --- a/nexus/src/test/kotlin/ConfigLoading.kt +++ /dev/null @@ -1,43 +0,0 @@ -/* - * This file is part of LibEuFin. - * Copyright (C) 2024 Taler Systems S.A. - - * LibEuFin is free software; you can redistribute it and/or modify - * it under the terms of the GNU Affero General Public License as - * published by the Free Software Foundation; either version 3, or - * (at your option) any later version. - - * LibEuFin is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY - * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General - * Public License for more details. - - * You should have received a copy of the GNU Affero General Public - * License along with LibEuFin; see the file COPYING. If not, see - * - */ - -import org.junit.Test -import tech.libeufin.nexus.getFrequencyInSeconds -import kotlin.test.assertEquals -import kotlin.test.assertNull - -class ConfigLoading { - // Checks converting human-readable durations to seconds. - @Test - fun timeParsing() { - assertEquals(1, getFrequencyInSeconds("1s")) - assertEquals(1, getFrequencyInSeconds(" 1 s ")) - assertEquals(10*60, getFrequencyInSeconds("10m")) - assertEquals(10*60, getFrequencyInSeconds("10 m")) - assertEquals(24*60*60, getFrequencyInSeconds("24h")) - assertEquals(24*60*60, getFrequencyInSeconds(" 24h")) - assertEquals(60*60, getFrequencyInSeconds(" 1h ")) - assertEquals(60*60, getFrequencyInSeconds("01h")) - assertNull(getFrequencyInSeconds("1.1s")) - assertNull(getFrequencyInSeconds(" ")) - assertNull(getFrequencyInSeconds("m")) - assertNull(getFrequencyInSeconds("")) - assertNull(getFrequencyInSeconds("0")) - } -} \ No newline at end of file -- cgit v1.2.3