Currency cleanup
This commit is contained in:
parent
78a0df8a8e
commit
55f279c9b1
5 changed files with 88 additions and 84 deletions
|
@ -54,19 +54,20 @@ class CryptoPrices : ThreadedModule() {
|
||||||
override fun commandResponse(channel: String, cmd: String, args: String, event: GenericMessageEvent) {
|
override fun commandResponse(channel: String, cmd: String, args: String, event: GenericMessageEvent) {
|
||||||
synchronized(this) {
|
synchronized(this) {
|
||||||
if (pubDate != today()) {
|
if (pubDate != today()) {
|
||||||
CODES.clear()
|
CURRENCIES.clear()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
super.commandResponse(channel, cmd, args, event)
|
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) {
|
override fun run(channel: String, cmd: String, args: String, event: GenericMessageEvent) {
|
||||||
if (CODES.isEmpty()) {
|
if (CURRENCIES.isEmpty()) {
|
||||||
try {
|
try {
|
||||||
loadCodes()
|
loadCurrencies()
|
||||||
} catch (e: ModuleException) {
|
} catch (e: ModuleException) {
|
||||||
if (logger.isWarnEnabled) logger.warn(e.debugMessage, e)
|
if (logger.isWarnEnabled) logger.warn(e.debugMessage, e)
|
||||||
}
|
}
|
||||||
|
@ -74,8 +75,8 @@ class CryptoPrices : ThreadedModule() {
|
||||||
|
|
||||||
val debugMessage = "crypto($cmd $args)"
|
val debugMessage = "crypto($cmd $args)"
|
||||||
if (args == CURRENCY_CODES_KEYWORD) {
|
if (args == CURRENCY_CODES_KEYWORD) {
|
||||||
event.sendMessage("The supported currency codes are:")
|
event.sendMessage("The supported currencies are:")
|
||||||
event.sendList(ArrayList(CODES.keys), 10, isIndent = true)
|
event.sendList(ArrayList(CURRENCIES.keys), 10, isIndent = true)
|
||||||
} else if (args.matches("\\w+( [a-zA-Z]{3}+)?".toRegex())) {
|
} else if (args.matches("\\w+( [a-zA-Z]{3}+)?".toRegex())) {
|
||||||
try {
|
try {
|
||||||
val price = currentPrice(args.split(' '))
|
val price = currentPrice(args.split(' '))
|
||||||
|
@ -84,7 +85,7 @@ class CryptoPrices : ThreadedModule() {
|
||||||
} catch (ignore: IllegalArgumentException) {
|
} catch (ignore: IllegalArgumentException) {
|
||||||
price.amount
|
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) {
|
} catch (e: CryptoException) {
|
||||||
if (logger.isWarnEnabled) logger.warn("$debugMessage => ${e.statusCode}", e)
|
if (logger.isWarnEnabled) logger.warn("$debugMessage => ${e.statusCode}", e)
|
||||||
e.message?.let {
|
e.message?.let {
|
||||||
|
@ -104,13 +105,13 @@ class CryptoPrices : ThreadedModule() {
|
||||||
// Crypto command
|
// Crypto command
|
||||||
private const val CRYPTO_CMD = "crypto"
|
private const val CRYPTO_CMD = "crypto"
|
||||||
|
|
||||||
// Currency codes
|
// Fiat Currencies
|
||||||
private val CODES: MutableMap<String, String> = mutableMapOf()
|
private val CURRENCIES: MutableMap<String, String> = mutableMapOf()
|
||||||
|
|
||||||
// Currency codes keyword
|
// Currency codes keyword
|
||||||
private const val CURRENCY_CODES_KEYWORD = "codes"
|
private const val CURRENCY_CODES_KEYWORD = "codes"
|
||||||
|
|
||||||
// Last currency table retrieval date
|
// Last currencies retrieval date
|
||||||
private var pubDate = ""
|
private var pubDate = ""
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -128,31 +129,32 @@ class CryptoPrices : ThreadedModule() {
|
||||||
* For testing purposes.
|
* For testing purposes.
|
||||||
*/
|
*/
|
||||||
fun getCurrencyName(code: String): String? {
|
fun getCurrencyName(code: String): String? {
|
||||||
return CODES[code]
|
return CURRENCIES[code]
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Loads the country ISO codes.
|
* Loads the Fiat currencies..
|
||||||
*/
|
*/
|
||||||
@JvmStatic
|
@JvmStatic
|
||||||
@Throws(ModuleException::class)
|
@Throws(ModuleException::class)
|
||||||
fun loadCodes() {
|
fun loadCurrencies() {
|
||||||
if (CODES.isEmpty()) {
|
try {
|
||||||
try {
|
val json = JSONObject(CryptoPrice.apiCall(listOf("currencies")))
|
||||||
val json = JSONObject(CryptoPrice.apiCall(listOf("currencies")))
|
val data = json.getJSONArray("data")
|
||||||
val data = json.getJSONArray("data")
|
if (CURRENCIES.isNotEmpty()) {
|
||||||
for (i in 0 until data.length()) {
|
CURRENCIES.clear()
|
||||||
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
|
|
||||||
)
|
|
||||||
}
|
}
|
||||||
|
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 BTC"))
|
||||||
add(helpFormat("%c $CRYPTO_CMD ETH EUR"))
|
add(helpFormat("%c $CRYPTO_CMD ETH EUR"))
|
||||||
add(helpFormat("%c $CRYPTO_CMD ETH2 GPB"))
|
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"))
|
add(helpFormat("%c $CRYPTO_CMD $CURRENCY_CODES_KEYWORD"))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -47,6 +47,7 @@ import org.slf4j.Logger
|
||||||
import org.slf4j.LoggerFactory
|
import org.slf4j.LoggerFactory
|
||||||
import java.io.IOException
|
import java.io.IOException
|
||||||
import java.net.URL
|
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) {
|
override fun commandResponse(channel: String, cmd: String, args: String, event: GenericMessageEvent) {
|
||||||
synchronized(this) {
|
synchronized(this) {
|
||||||
if (pubDate != today()) {
|
if (pubDate != today()) {
|
||||||
CODES.clear()
|
SYMBOLS.clear()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
super.commandResponse(channel, cmd, args, event)
|
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.
|
* Converts the specified currencies.
|
||||||
*/
|
*/
|
||||||
override fun run(channel: String, cmd: String, args: String, event: GenericMessageEvent) {
|
override fun run(channel: String, cmd: String, args: String, event: GenericMessageEvent) {
|
||||||
if (CODES.isEmpty()) {
|
reload()
|
||||||
try {
|
|
||||||
loadCodes()
|
|
||||||
} catch (e: ModuleException) {
|
|
||||||
if (logger.isWarnEnabled) logger.warn(e.debugMessage, e)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (CODES.isEmpty()) {
|
if (SYMBOLS.isEmpty()) {
|
||||||
event.respond(EMPTY_CODES_TABLE)
|
event.respond(EMPTY_SYMBOLS_TABLE)
|
||||||
} else if (args.matches("\\d+([,\\d]+)?(\\.\\d+)? [a-zA-Z]{3}+ to [a-zA-Z]{3}+".toRegex())) {
|
} else if (args.matches("\\d+([,\\d]+)?(\\.\\d+)? [a-zA-Z]{3}+ to [a-zA-Z]{3}+".toRegex())) {
|
||||||
val msg = convertCurrency(args)
|
val msg = convertCurrency(args)
|
||||||
event.respond(msg.msg)
|
event.respond(msg.msg)
|
||||||
if (msg.isError) {
|
if (msg.isError) {
|
||||||
helpResponse(event)
|
helpResponse(event)
|
||||||
}
|
}
|
||||||
} else if (args.contains(CURRENCY_CODES_KEYWORD)) {
|
} else if (args.contains(CODES_KEYWORD)) {
|
||||||
event.sendMessage("The supported currency codes are:")
|
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 {
|
} else {
|
||||||
helpResponse(event)
|
helpResponse(event)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun helpResponse(event: GenericMessageEvent): Boolean {
|
override fun helpResponse(event: GenericMessageEvent): Boolean {
|
||||||
if (CODES.isEmpty()) {
|
reload()
|
||||||
try {
|
|
||||||
loadCodes()
|
if (SYMBOLS.isEmpty()) {
|
||||||
} catch (e: ModuleException) {
|
event.sendMessage(EMPTY_SYMBOLS_TABLE)
|
||||||
if (logger.isWarnEnabled) logger.warn(e.debugMessage, e)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if (CODES.isEmpty()) {
|
|
||||||
event.sendMessage(EMPTY_CODES_TABLE)
|
|
||||||
} else {
|
} else {
|
||||||
val nick = event.bot().nick
|
val nick = event.bot().nick
|
||||||
event.sendMessage("To convert from one currency to another:")
|
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("To list the supported currency codes:")
|
||||||
event.sendMessage(
|
event.sendMessage(
|
||||||
helpFormat(
|
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"
|
private const val CURRENCY_CMD = "currency"
|
||||||
|
|
||||||
// Currency codes keyword
|
// Currency codes keyword
|
||||||
private const val CURRENCY_CODES_KEYWORD = "codes"
|
private const val CODES_KEYWORD = "codes"
|
||||||
|
|
||||||
// Empty code table.
|
// Empty symbols table.
|
||||||
private const val EMPTY_CODES_TABLE = "Sorry, but the currency table is empty."
|
private const val EMPTY_SYMBOLS_TABLE = "Sorry, but the currency table is empty."
|
||||||
|
|
||||||
// Currency codes
|
// Currency symbols
|
||||||
private val CODES: MutableMap<String, String> = mutableMapOf()
|
private val SYMBOLS: TreeMap<String, String> = TreeMap()
|
||||||
|
|
||||||
// Last currency table retrieval date
|
// Last currency retrieval date
|
||||||
private var pubDate = ""
|
private var pubDate = ""
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -151,7 +152,7 @@ class CurrencyConverter : ThreadedModule() {
|
||||||
} else {
|
} else {
|
||||||
val to = cmds[1].uppercase()
|
val to = cmds[1].uppercase()
|
||||||
val from = cmds[3].uppercase()
|
val from = cmds[3].uppercase()
|
||||||
if (CODES.contains(to) && CODES.contains(from)) {
|
if (SYMBOLS.contains(to) && SYMBOLS.contains(from)) {
|
||||||
try {
|
try {
|
||||||
val amt = cmds[0].replace(",", "")
|
val amt = cmds[0].replace(",", "")
|
||||||
val url = URL("https://api.exchangerate.host/convert?from=$to&to=$from&amount=$amt")
|
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")) {
|
if (json.getBoolean("success")) {
|
||||||
PublicMessage(
|
PublicMessage(
|
||||||
"${cmds[0]} ${CODES[to]} = ${json.getDouble("result")} ${CODES[from]}"
|
"${cmds[0]} ${SYMBOLS[to]} = ${json.getDouble("result")} ${SYMBOLS[from]}"
|
||||||
)
|
)
|
||||||
} else {
|
} else {
|
||||||
ErrorMessage("Sorry, an error occurred while converting the currencies.")
|
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
|
@JvmStatic
|
||||||
@Throws(ModuleException::class)
|
@Throws(ModuleException::class)
|
||||||
fun loadCodes() {
|
fun loadSymbols() {
|
||||||
if (CODES.isEmpty()) {
|
try {
|
||||||
try {
|
val url = URL("https://api.exchangerate.host/symbols")
|
||||||
val url = URL("https://api.exchangerate.host/symbols")
|
val json = JSONObject(url.reader())
|
||||||
val json = JSONObject(url.reader())
|
if (json.getBoolean("success")) {
|
||||||
if (json.getBoolean("success")) {
|
val symbols = json.getJSONObject("symbols")
|
||||||
val symbols = json.getJSONObject("symbols")
|
if (SYMBOLS.isNotEmpty()) {
|
||||||
for (key in symbols.keys()) {
|
SYMBOLS.clear()
|
||||||
CODES[key] = symbols.getJSONObject(key).getString("description")
|
|
||||||
}
|
|
||||||
pubDate = today()
|
|
||||||
}
|
}
|
||||||
} catch (e: IOException) {
|
for (key in symbols.keys()) {
|
||||||
throw ModuleException(
|
SYMBOLS[key] = symbols.getJSONObject(key).getString("description")
|
||||||
"loadCodes(): IOE",
|
}
|
||||||
"An IO error has occurred while retrieving the currency table.",
|
pubDate = today()
|
||||||
e
|
|
||||||
)
|
|
||||||
}
|
}
|
||||||
|
} catch (e: IOException) {
|
||||||
|
throw ModuleException(
|
||||||
|
"loadCodes(): IOE",
|
||||||
|
"An IO error has occurred while retrieving the currencies.",
|
||||||
|
e
|
||||||
|
)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -39,7 +39,7 @@ import assertk.assertions.prop
|
||||||
import net.thauvin.erik.crypto.CryptoPrice
|
import net.thauvin.erik.crypto.CryptoPrice
|
||||||
import net.thauvin.erik.mobibot.modules.CryptoPrices.Companion.currentPrice
|
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.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.BeforeClass
|
||||||
import org.testng.annotations.Test
|
import org.testng.annotations.Test
|
||||||
|
|
||||||
|
@ -50,7 +50,7 @@ class CryptoPricesTest {
|
||||||
@BeforeClass
|
@BeforeClass
|
||||||
@Throws(ModuleException::class)
|
@Throws(ModuleException::class)
|
||||||
fun before() {
|
fun before() {
|
||||||
loadCodes()
|
loadCurrencies()
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
|
|
|
@ -38,7 +38,7 @@ import assertk.assertions.isInstanceOf
|
||||||
import assertk.assertions.matches
|
import assertk.assertions.matches
|
||||||
import assertk.assertions.prop
|
import assertk.assertions.prop
|
||||||
import net.thauvin.erik.mobibot.modules.CurrencyConverter.Companion.convertCurrency
|
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.ErrorMessage
|
||||||
import net.thauvin.erik.mobibot.msg.Message
|
import net.thauvin.erik.mobibot.msg.Message
|
||||||
import net.thauvin.erik.mobibot.msg.PublicMessage
|
import net.thauvin.erik.mobibot.msg.PublicMessage
|
||||||
|
@ -53,7 +53,7 @@ class CurrencyConverterTest {
|
||||||
@BeforeClass
|
@BeforeClass
|
||||||
@Throws(ModuleException::class)
|
@Throws(ModuleException::class)
|
||||||
fun before() {
|
fun before() {
|
||||||
loadCodes()
|
loadSymbols()
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
|
|
|
@ -1,9 +1,9 @@
|
||||||
#Generated by the Semver Plugin for Gradle
|
#Generated by the Semver Plugin for Gradle
|
||||||
#Mon Jul 11 07:36:52 PDT 2022
|
#Mon Jul 11 13:05:47 PDT 2022
|
||||||
version.buildmeta=324
|
version.buildmeta=329
|
||||||
version.major=0
|
version.major=0
|
||||||
version.minor=8
|
version.minor=8
|
||||||
version.patch=0
|
version.patch=0
|
||||||
version.prerelease=rc
|
version.prerelease=rc
|
||||||
version.project=mobibot
|
version.project=mobibot
|
||||||
version.semver=0.8.0-rc+324
|
version.semver=0.8.0-rc+329
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue