mobibot/bin/main/net/thauvin/erik/mobibot/modules/CryptoPrices.kt

159 lines
5.9 KiB
Kotlin

/*
* CryptoPrices.kt
*
* Copyright 2004-2023 Erik C. Thauvin (erik@thauvin.net)
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
*
* Redistributions of source code must retain the above copyright notice, this
* list of conditions and the following disclaimer.
*
* Redistributions in binary form must reproduce the above copyright notice,
* this list of conditions and the following disclaimer in the documentation
* and/or other materials provided with the distribution.
*
* Neither the name of this project nor the names of its contributors may be
* used to endorse or promote products derived from this software without
* specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
* DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
* SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
* CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
* OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
package net.thauvin.erik.mobibot.modules
import net.thauvin.erik.crypto.CryptoException
import net.thauvin.erik.crypto.CryptoPrice
import net.thauvin.erik.crypto.CryptoPrice.Companion.spotPrice
import net.thauvin.erik.mobibot.Utils.helpFormat
import net.thauvin.erik.mobibot.Utils.sendList
import net.thauvin.erik.mobibot.Utils.sendMessage
import org.json.JSONObject
import org.pircbotx.hooks.types.GenericMessageEvent
import org.slf4j.Logger
import org.slf4j.LoggerFactory
import java.io.IOException
/**
* The Cryptocurrency Prices module.
*/
class CryptoPrices : AbstractModule() {
private val logger: Logger = LoggerFactory.getLogger(CryptoPrices::class.java)
override val name = "CryptoPrices"
/**
* Returns the cryptocurrency market price from
* [Coinbase](https://docs.cloud.coinbase.com/sign-in-with-coinbase/docs/api-prices#get-spot-price).
*/
override fun commandResponse(channel: String, cmd: String, args: String, event: GenericMessageEvent) {
if (CURRENCIES.isEmpty()) {
try {
loadCurrencies()
} catch (e: ModuleException) {
if (logger.isWarnEnabled) logger.warn(e.debugMessage, e)
}
}
val debugMessage = "crypto($cmd $args)"
if (args == CODES_KEYWORD) {
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(' '))
val amount = try {
price.toCurrency()
} catch (ignore: IllegalArgumentException) {
price.amount
}
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 {
event.respond(it)
}
} catch (e: IOException) {
if (logger.isErrorEnabled) logger.error(debugMessage, e)
event.respond("An IO error has occurred while retrieving the cryptocurrency market price.")
}
} else {
helpResponse(event)
}
}
companion object {
// Crypto command
private const val CRYPTO_CMD = "crypto"
// Fiat Currencies
private val CURRENCIES: MutableMap<String, String> = mutableMapOf()
// Currency codes keyword
private const val CODES_KEYWORD = "codes"
/**
* Get current market price.
*/
@JvmStatic
fun currentPrice(args: List<String>): CryptoPrice {
return if (args.size == 2)
spotPrice(args[0], args[1])
else
spotPrice(args[0])
}
/**
* For testing purposes.
*/
fun getCurrencyName(code: String): String? {
return CURRENCIES[code]
}
/**
* Loads the Fiat currencies..
*/
@JvmStatic
@Throws(ModuleException::class)
fun loadCurrencies() {
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)
CURRENCIES[d.getString("id")] = d.getString("name")
}
} catch (e: CryptoException) {
throw ModuleException(
"loadCurrencies(): CE",
"An error has occurred while retrieving the currencies table.",
e
)
}
}
}
init {
commands.add(CRYPTO_CMD)
with(help) {
add("To retrieve a cryptocurrency's market price:")
add(helpFormat("%c $CRYPTO_CMD <symbol> [<currency>]"))
add("For example:")
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 currencies:")
add(helpFormat("%c $CRYPTO_CMD $CODES_KEYWORD"))
}
loadCurrencies()
}
}