Added support for CryptoPrice country codes

This commit is contained in:
Erik C. Thauvin 2022-07-11 07:36:31 -07:00
parent a18c15e172
commit 78a0df8a8e
4 changed files with 86 additions and 5 deletions

View file

@ -12,6 +12,7 @@
<ID>LongParameterList:EntryLink.kt$EntryLink$( // Link's comments val comments: MutableList&lt;EntryComment&gt; = mutableListOf(), // Tags/categories val tags: MutableList&lt;SyndCategory&gt; = mutableListOf(), // Channel var channel: String, // Creation date var date: Date = Calendar.getInstance().time, // Link's URL var link: String, // Author's login var login: String = "", // Author's nickname var nick: String, // Link's title var title: String )</ID> <ID>LongParameterList:EntryLink.kt$EntryLink$( // Link's comments val comments: MutableList&lt;EntryComment&gt; = mutableListOf(), // Tags/categories val tags: MutableList&lt;SyndCategory&gt; = mutableListOf(), // Channel var channel: String, // Creation date var date: Date = Calendar.getInstance().time, // Link's URL var link: String, // Author's login var login: String = "", // Author's nickname var nick: String, // Link's title var title: String )</ID>
<ID>LongParameterList:Twitter.kt$Twitter.Companion$( consumerKey: String?, consumerSecret: String?, token: String?, tokenSecret: String?, handle: String?, message: String, isDm: Boolean )</ID> <ID>LongParameterList:Twitter.kt$Twitter.Companion$( consumerKey: String?, consumerSecret: String?, token: String?, tokenSecret: String?, handle: String?, message: String, isDm: Boolean )</ID>
<ID>MagicNumber:Comment.kt$Comment$3</ID> <ID>MagicNumber:Comment.kt$Comment$3</ID>
<ID>MagicNumber:CryptoPrices.kt$CryptoPrices$10</ID>
<ID>MagicNumber:CurrencyConverter.kt$CurrencyConverter$11</ID> <ID>MagicNumber:CurrencyConverter.kt$CurrencyConverter$11</ID>
<ID>MagicNumber:CurrencyConverter.kt$CurrencyConverter.Companion$3</ID> <ID>MagicNumber:CurrencyConverter.kt$CurrencyConverter.Companion$3</ID>
<ID>MagicNumber:CurrencyConverter.kt$CurrencyConverter.Companion$4</ID> <ID>MagicNumber:CurrencyConverter.kt$CurrencyConverter.Companion$4</ID>

View file

@ -35,7 +35,10 @@ import net.thauvin.erik.crypto.CryptoException
import net.thauvin.erik.crypto.CryptoPrice import net.thauvin.erik.crypto.CryptoPrice
import net.thauvin.erik.crypto.CryptoPrice.Companion.spotPrice import net.thauvin.erik.crypto.CryptoPrice.Companion.spotPrice
import net.thauvin.erik.mobibot.Utils.helpFormat import net.thauvin.erik.mobibot.Utils.helpFormat
import net.thauvin.erik.mobibot.Utils.sendList
import net.thauvin.erik.mobibot.Utils.sendMessage import net.thauvin.erik.mobibot.Utils.sendMessage
import net.thauvin.erik.mobibot.Utils.today
import org.json.JSONObject
import org.pircbotx.hooks.types.GenericMessageEvent import org.pircbotx.hooks.types.GenericMessageEvent
import org.slf4j.Logger import org.slf4j.Logger
import org.slf4j.LoggerFactory import org.slf4j.LoggerFactory
@ -48,13 +51,32 @@ class CryptoPrices : ThreadedModule() {
private val logger: Logger = LoggerFactory.getLogger(CryptoPrices::class.java) private val logger: Logger = LoggerFactory.getLogger(CryptoPrices::class.java)
override val name = "CryptoPrices" override val name = "CryptoPrices"
override fun commandResponse(channel: String, cmd: String, args: String, event: GenericMessageEvent) {
synchronized(this) {
if (pubDate != today()) {
CODES.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://developers.coinbase.com/api/v2#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()) {
try {
loadCodes()
} catch (e: ModuleException) {
if (logger.isWarnEnabled) logger.warn(e.debugMessage, e)
}
}
val debugMessage = "crypto($cmd $args)" val debugMessage = "crypto($cmd $args)"
if (args.matches("\\w+( [a-zA-Z]{3}+)?".toRegex())) { if (args == CURRENCY_CODES_KEYWORD) {
event.sendMessage("The supported currency codes are:")
event.sendList(ArrayList(CODES.keys), 10, isIndent = true)
} else if (args.matches("\\w+( [a-zA-Z]{3}+)?".toRegex())) {
try { try {
val price = currentPrice(args.split(' ')) val price = currentPrice(args.split(' '))
val amount = try { val amount = try {
@ -62,7 +84,7 @@ class CryptoPrices : ThreadedModule() {
} catch (ignore: IllegalArgumentException) { } catch (ignore: IllegalArgumentException) {
price.amount price.amount
} }
event.respond("${price.base} current price is $amount [${price.currency}]") event.respond("${price.base} current price is $amount [${CODES[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 {
@ -82,6 +104,15 @@ class CryptoPrices : ThreadedModule() {
// Crypto command // Crypto command
private const val CRYPTO_CMD = "crypto" private const val CRYPTO_CMD = "crypto"
// Currency codes
private val CODES: MutableMap<String, String> = mutableMapOf()
// Currency codes keyword
private const val CURRENCY_CODES_KEYWORD = "codes"
// Last currency table retrieval date
private var pubDate = ""
/** /**
* Get current market price. * Get current market price.
*/ */
@ -92,6 +123,38 @@ class CryptoPrices : ThreadedModule() {
else else
spotPrice(args[0]) spotPrice(args[0])
} }
/**
* For testing purposes.
*/
fun getCurrencyName(code: String): String? {
return CODES[code]
}
/**
* Loads the country ISO codes.
*/
@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
)
}
}
}
} }
init { init {
@ -103,6 +166,8 @@ 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(helpFormat("%c $CRYPTO_CMD $CURRENCY_CODES_KEYWORD"))
} }
} }
} }

View file

@ -38,12 +38,21 @@ import assertk.assertions.isGreaterThan
import assertk.assertions.prop 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.loadCodes
import org.testng.annotations.BeforeClass
import org.testng.annotations.Test import org.testng.annotations.Test
/** /**
* The `CryptoPricesTest` class. * The `CryptoPricesTest` class.
*/ */
class CryptoPricesTest { class CryptoPricesTest {
@BeforeClass
@Throws(ModuleException::class)
fun before() {
loadCodes()
}
@Test @Test
@Throws(ModuleException::class) @Throws(ModuleException::class)
fun testMarketPrice() { fun testMarketPrice() {
@ -61,4 +70,10 @@ class CryptoPricesTest {
prop(CryptoPrice::amount).transform { it.signum() }.isGreaterThan(0) prop(CryptoPrice::amount).transform { it.signum() }.isGreaterThan(0)
} }
} }
@Test
fun testGetCurrencyName() {
assertThat(getCurrencyName("USD")).isEqualTo("US Dollar")
assertThat(getCurrencyName("EUR")).isEqualTo("Euro")
}
} }

View file

@ -1,9 +1,9 @@
#Generated by the Semver Plugin for Gradle #Generated by the Semver Plugin for Gradle
#Sun Jul 10 23:07:38 PDT 2022 #Mon Jul 11 07:36:52 PDT 2022
version.buildmeta=315 version.buildmeta=324
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+315 version.semver=0.8.0-rc+324