diff --git a/src/main/kotlin/net/thauvin/erik/mobibot/modules/CryptoPrices.kt b/src/main/kotlin/net/thauvin/erik/mobibot/modules/CryptoPrices.kt index e288286..6a9ffe0 100644 --- a/src/main/kotlin/net/thauvin/erik/mobibot/modules/CryptoPrices.kt +++ b/src/main/kotlin/net/thauvin/erik/mobibot/modules/CryptoPrices.kt @@ -54,19 +54,20 @@ class CryptoPrices : ThreadedModule() { override fun commandResponse(channel: String, cmd: String, args: String, event: GenericMessageEvent) { synchronized(this) { if (pubDate != today()) { - CODES.clear() + CURRENCIES.clear() } } super.commandResponse(channel, cmd, args, event) } /** - * Returns the cryptocurrency market price from [Coinbase](https://developers.coinbase.com/api/v2#get-spot-price). + * Returns the cryptocurrency market price from + * [Coinbase](https://docs.cloud.coinbase.com/sign-in-with-coinbase/docs/api-prices#get-spot-price). */ override fun run(channel: String, cmd: String, args: String, event: GenericMessageEvent) { - if (CODES.isEmpty()) { + if (CURRENCIES.isEmpty()) { try { - loadCodes() + loadCurrencies() } catch (e: ModuleException) { if (logger.isWarnEnabled) logger.warn(e.debugMessage, e) } @@ -74,8 +75,8 @@ class CryptoPrices : ThreadedModule() { val debugMessage = "crypto($cmd $args)" if (args == CURRENCY_CODES_KEYWORD) { - event.sendMessage("The supported currency codes are:") - event.sendList(ArrayList(CODES.keys), 10, isIndent = true) + event.sendMessage("The supported currencies are:") + event.sendList(ArrayList(CURRENCIES.keys), 10, isIndent = true) } else if (args.matches("\\w+( [a-zA-Z]{3}+)?".toRegex())) { try { val price = currentPrice(args.split(' ')) @@ -84,7 +85,7 @@ class CryptoPrices : ThreadedModule() { } catch (ignore: IllegalArgumentException) { price.amount } - event.respond("${price.base} current price is $amount [${CODES[price.currency]}]") + event.respond("${price.base} current price is $amount [${CURRENCIES[price.currency]}]") } catch (e: CryptoException) { if (logger.isWarnEnabled) logger.warn("$debugMessage => ${e.statusCode}", e) e.message?.let { @@ -104,13 +105,13 @@ class CryptoPrices : ThreadedModule() { // Crypto command private const val CRYPTO_CMD = "crypto" - // Currency codes - private val CODES: MutableMap = mutableMapOf() + // Fiat Currencies + private val CURRENCIES: MutableMap = mutableMapOf() // Currency codes keyword private const val CURRENCY_CODES_KEYWORD = "codes" - // Last currency table retrieval date + // Last currencies retrieval date private var pubDate = "" /** @@ -128,31 +129,32 @@ class CryptoPrices : ThreadedModule() { * For testing purposes. */ fun getCurrencyName(code: String): String? { - return CODES[code] + return CURRENCIES[code] } /** - * Loads the country ISO codes. + * Loads the Fiat currencies.. */ @JvmStatic @Throws(ModuleException::class) - fun loadCodes() { - if (CODES.isEmpty()) { - try { - val json = JSONObject(CryptoPrice.apiCall(listOf("currencies"))) - val data = json.getJSONArray("data") - for (i in 0 until data.length()) { - val d = data.getJSONObject(i) - CODES[d.getString("id")] = d.getString("name") - } - pubDate = today() - } catch (e: CryptoException) { - throw ModuleException( - "loadCodes(): CE", - "An error has occurred while retrieving the currency table.", - e - ) + fun loadCurrencies() { + try { + val json = JSONObject(CryptoPrice.apiCall(listOf("currencies"))) + val data = json.getJSONArray("data") + if (CURRENCIES.isNotEmpty()) { + CURRENCIES.clear() } + for (i in 0 until data.length()) { + val d = data.getJSONObject(i) + CURRENCIES[d.getString("id")] = d.getString("name") + } + pubDate = today() + } catch (e: CryptoException) { + throw ModuleException( + "loadCurrencies(): CE", + "An error has occurred while retrieving the currencies table.", + e + ) } } } @@ -166,7 +168,7 @@ class CryptoPrices : ThreadedModule() { add(helpFormat("%c $CRYPTO_CMD BTC")) add(helpFormat("%c $CRYPTO_CMD ETH EUR")) add(helpFormat("%c $CRYPTO_CMD ETH2 GPB")) - add("To list the supported currency codes:") + add("To list the supported currencies:") add(helpFormat("%c $CRYPTO_CMD $CURRENCY_CODES_KEYWORD")) } } diff --git a/src/main/kotlin/net/thauvin/erik/mobibot/modules/CurrencyConverter.kt b/src/main/kotlin/net/thauvin/erik/mobibot/modules/CurrencyConverter.kt index 9c4cfe0..0a2921b 100644 --- a/src/main/kotlin/net/thauvin/erik/mobibot/modules/CurrencyConverter.kt +++ b/src/main/kotlin/net/thauvin/erik/mobibot/modules/CurrencyConverter.kt @@ -47,6 +47,7 @@ import org.slf4j.Logger import org.slf4j.LoggerFactory import java.io.IOException import java.net.URL +import java.util.* /** @@ -60,50 +61,50 @@ class CurrencyConverter : ThreadedModule() { override fun commandResponse(channel: String, cmd: String, args: String, event: GenericMessageEvent) { synchronized(this) { if (pubDate != today()) { - CODES.clear() + SYMBOLS.clear() } } super.commandResponse(channel, cmd, args, event) } + // Reload currency codes + private fun reload() { + if (SYMBOLS.isEmpty()) { + try { + loadSymbols() + } catch (e: ModuleException) { + if (logger.isWarnEnabled) logger.warn(e.debugMessage, e) + } + } + } + /** * Converts the specified currencies. */ override fun run(channel: String, cmd: String, args: String, event: GenericMessageEvent) { - if (CODES.isEmpty()) { - try { - loadCodes() - } catch (e: ModuleException) { - if (logger.isWarnEnabled) logger.warn(e.debugMessage, e) - } - } + reload() - if (CODES.isEmpty()) { - event.respond(EMPTY_CODES_TABLE) + if (SYMBOLS.isEmpty()) { + event.respond(EMPTY_SYMBOLS_TABLE) } else if (args.matches("\\d+([,\\d]+)?(\\.\\d+)? [a-zA-Z]{3}+ to [a-zA-Z]{3}+".toRegex())) { val msg = convertCurrency(args) event.respond(msg.msg) if (msg.isError) { helpResponse(event) } - } else if (args.contains(CURRENCY_CODES_KEYWORD)) { + } else if (args.contains(CODES_KEYWORD)) { event.sendMessage("The supported currency codes are:") - event.sendList(ArrayList(CODES.keys.sorted()), 11, isIndent = true) + event.sendList(SYMBOLS.keys.toList(), 11, isIndent = true) } else { helpResponse(event) } } override fun helpResponse(event: GenericMessageEvent): Boolean { - if (CODES.isEmpty()) { - try { - loadCodes() - } catch (e: ModuleException) { - if (logger.isWarnEnabled) logger.warn(e.debugMessage, e) - } - } - if (CODES.isEmpty()) { - event.sendMessage(EMPTY_CODES_TABLE) + reload() + + if (SYMBOLS.isEmpty()) { + event.sendMessage(EMPTY_SYMBOLS_TABLE) } else { val nick = event.bot().nick event.sendMessage("To convert from one currency to another:") @@ -116,7 +117,7 @@ class CurrencyConverter : ThreadedModule() { event.sendMessage("To list the supported currency codes:") event.sendMessage( helpFormat( - helpCmdSyntax("%c $CURRENCY_CMD $CURRENCY_CODES_KEYWORD", nick, isPrivateMsgEnabled) + helpCmdSyntax("%c $CURRENCY_CMD $CODES_KEYWORD", nick, isPrivateMsgEnabled) ) ) } @@ -128,15 +129,15 @@ class CurrencyConverter : ThreadedModule() { private const val CURRENCY_CMD = "currency" // Currency codes keyword - private const val CURRENCY_CODES_KEYWORD = "codes" + private const val CODES_KEYWORD = "codes" - // Empty code table. - private const val EMPTY_CODES_TABLE = "Sorry, but the currency table is empty." + // Empty symbols table. + private const val EMPTY_SYMBOLS_TABLE = "Sorry, but the currency table is empty." - // Currency codes - private val CODES: MutableMap = mutableMapOf() + // Currency symbols + private val SYMBOLS: TreeMap = TreeMap() - // Last currency table retrieval date + // Last currency retrieval date private var pubDate = "" /** @@ -151,7 +152,7 @@ class CurrencyConverter : ThreadedModule() { } else { val to = cmds[1].uppercase() val from = cmds[3].uppercase() - if (CODES.contains(to) && CODES.contains(from)) { + if (SYMBOLS.contains(to) && SYMBOLS.contains(from)) { try { val amt = cmds[0].replace(",", "") val url = URL("https://api.exchangerate.host/convert?from=$to&to=$from&amount=$amt") @@ -159,7 +160,7 @@ class CurrencyConverter : ThreadedModule() { if (json.getBoolean("success")) { PublicMessage( - "${cmds[0]} ${CODES[to]} = ${json.getDouble("result")} ${CODES[from]}" + "${cmds[0]} ${SYMBOLS[to]} = ${json.getDouble("result")} ${SYMBOLS[from]}" ) } else { ErrorMessage("Sorry, an error occurred while converting the currencies.") @@ -175,29 +176,30 @@ class CurrencyConverter : ThreadedModule() { } /** - * Loads the country ISO codes. + * Loads the currency ISO symbols. */ @JvmStatic @Throws(ModuleException::class) - fun loadCodes() { - if (CODES.isEmpty()) { - try { - val url = URL("https://api.exchangerate.host/symbols") - val json = JSONObject(url.reader()) - if (json.getBoolean("success")) { - val symbols = json.getJSONObject("symbols") - for (key in symbols.keys()) { - CODES[key] = symbols.getJSONObject(key).getString("description") - } - pubDate = today() + fun loadSymbols() { + try { + val url = URL("https://api.exchangerate.host/symbols") + val json = JSONObject(url.reader()) + if (json.getBoolean("success")) { + val symbols = json.getJSONObject("symbols") + if (SYMBOLS.isNotEmpty()) { + SYMBOLS.clear() } - } catch (e: IOException) { - throw ModuleException( - "loadCodes(): IOE", - "An IO error has occurred while retrieving the currency table.", - e - ) + for (key in symbols.keys()) { + SYMBOLS[key] = symbols.getJSONObject(key).getString("description") + } + pubDate = today() } + } catch (e: IOException) { + throw ModuleException( + "loadCodes(): IOE", + "An IO error has occurred while retrieving the currencies.", + e + ) } } } diff --git a/src/test/kotlin/net/thauvin/erik/mobibot/modules/CryptoPricesTest.kt b/src/test/kotlin/net/thauvin/erik/mobibot/modules/CryptoPricesTest.kt index b8480cd..1fb689f 100644 --- a/src/test/kotlin/net/thauvin/erik/mobibot/modules/CryptoPricesTest.kt +++ b/src/test/kotlin/net/thauvin/erik/mobibot/modules/CryptoPricesTest.kt @@ -39,7 +39,7 @@ import assertk.assertions.prop import net.thauvin.erik.crypto.CryptoPrice import net.thauvin.erik.mobibot.modules.CryptoPrices.Companion.currentPrice import net.thauvin.erik.mobibot.modules.CryptoPrices.Companion.getCurrencyName -import net.thauvin.erik.mobibot.modules.CryptoPrices.Companion.loadCodes +import net.thauvin.erik.mobibot.modules.CryptoPrices.Companion.loadCurrencies import org.testng.annotations.BeforeClass import org.testng.annotations.Test @@ -50,7 +50,7 @@ class CryptoPricesTest { @BeforeClass @Throws(ModuleException::class) fun before() { - loadCodes() + loadCurrencies() } @Test diff --git a/src/test/kotlin/net/thauvin/erik/mobibot/modules/CurrencyConverterTest.kt b/src/test/kotlin/net/thauvin/erik/mobibot/modules/CurrencyConverterTest.kt index 1e9a346..4149793 100644 --- a/src/test/kotlin/net/thauvin/erik/mobibot/modules/CurrencyConverterTest.kt +++ b/src/test/kotlin/net/thauvin/erik/mobibot/modules/CurrencyConverterTest.kt @@ -38,7 +38,7 @@ import assertk.assertions.isInstanceOf import assertk.assertions.matches import assertk.assertions.prop import net.thauvin.erik.mobibot.modules.CurrencyConverter.Companion.convertCurrency -import net.thauvin.erik.mobibot.modules.CurrencyConverter.Companion.loadCodes +import net.thauvin.erik.mobibot.modules.CurrencyConverter.Companion.loadSymbols import net.thauvin.erik.mobibot.msg.ErrorMessage import net.thauvin.erik.mobibot.msg.Message import net.thauvin.erik.mobibot.msg.PublicMessage @@ -53,7 +53,7 @@ class CurrencyConverterTest { @BeforeClass @Throws(ModuleException::class) fun before() { - loadCodes() + loadSymbols() } @Test diff --git a/version.properties b/version.properties index 4c555de..b0089fc 100644 --- a/version.properties +++ b/version.properties @@ -1,9 +1,9 @@ #Generated by the Semver Plugin for Gradle -#Mon Jul 11 07:36:52 PDT 2022 -version.buildmeta=324 +#Mon Jul 11 13:05:47 PDT 2022 +version.buildmeta=329 version.major=0 version.minor=8 version.patch=0 version.prerelease=rc version.project=mobibot -version.semver=0.8.0-rc+324 +version.semver=0.8.0-rc+329