Compare commits

..

3 commits

Author SHA1 Message Date
1906a24343 Updated dependencies 2023-01-29 01:13:40 -08:00
416a52ec18 Updated copyright 2023-01-29 00:49:09 -08:00
cb8bf44768 Added id to CryptoException 2023-01-29 00:41:58 -08:00
13 changed files with 67 additions and 42 deletions

View file

@ -1,6 +1,6 @@
<component name="CopyrightManager">
<copyright>
<option name="notice" value="&amp;#36;file.fileName&#10;&#10;Copyright (c) 2021-&amp;#36;today.year, Erik C. Thauvin (erik@thauvin.net)&#10;All rights reserved.&#10;&#10;Redistribution and use in source and binary forms, with or without&#10;modification, are permitted provided that the following conditions are met:&#10;&#10; Redistributions of source code must retain the above copyright notice, this&#10; list of conditions and the following disclaimer.&#10;&#10; Redistributions in binary form must reproduce the above copyright notice,&#10; this list of conditions and the following disclaimer in the documentation&#10; and/or other materials provided with the distribution.&#10;&#10; Neither the name of this project nor the names of its contributors may be&#10; used to endorse or promote products derived from this software without&#10; specific prior written permission.&#10;&#10;THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS &quot;AS IS&quot;&#10;AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE&#10;IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE&#10;DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE&#10;FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL&#10;DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR&#10;SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER&#10;CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,&#10;OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE&#10;OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE." />
<option name="notice" value="&amp;#36;file.fileName&#10;&#10;Copyright 2021-&amp;#36;today.year Erik C. Thauvin (erik@thauvin.net)&#10;&#10;Redistribution and use in source and binary forms, with or without&#10;modification, are permitted provided that the following conditions are met:&#10;&#10; Redistributions of source code must retain the above copyright notice, this&#10; list of conditions and the following disclaimer.&#10;&#10; Redistributions in binary form must reproduce the above copyright notice,&#10; this list of conditions and the following disclaimer in the documentation&#10; and/or other materials provided with the distribution.&#10;&#10; Neither the name of this project nor the names of its contributors may be&#10; used to endorse or promote products derived from this software without&#10; specific prior written permission.&#10;&#10;THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS &quot;AS IS&quot;&#10;AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE&#10;IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE&#10;DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE&#10;FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL&#10;DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR&#10;SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER&#10;CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,&#10;OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE&#10;OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE." />
<option name="myName" value="Erik's Copyright Notice" />
</copyright>
</component>

2
.idea/kotlinc.xml generated
View file

@ -1,6 +1,6 @@
<?xml version="1.0" encoding="UTF-8"?>
<project version="4">
<component name="KotlinJpsPluginSettings">
<option name="version" value="1.7.20" />
<option name="version" value="1.8.0" />
</component>
</project>

5
.idea/misc.xml generated
View file

@ -4,5 +4,8 @@
<component name="FrameworkDetectionExcludesConfiguration">
<file type="web" url="file://$PROJECT_DIR$" />
</component>
<component name="ProjectRootManager" version="2" languageLevel="JDK_11" project-jdk-name="18" project-jdk-type="JavaSDK" />
<component name="PDMPlugin">
<option name="skipTestSources" value="false" />
</component>
<component name="ProjectRootManager" version="2" languageLevel="JDK_11" project-jdk-name="19" project-jdk-type="JavaSDK" />
</project>

View file

@ -1,5 +1,4 @@
Copyright (c) 2021-2022, Erik C. Thauvin (erik@thauvin.net)
All rights reserved.
Copyright 2021-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:

View file

@ -1,10 +1,16 @@
[![License (3-Clause BSD)](https://img.shields.io/badge/license-BSD%203--Clause-blue.svg?style=flat-square)](https://opensource.org/licenses/BSD-3-Clause) [![Release](https://img.shields.io/github/release/ethauvin/cryptoprice.svg)](https://github.com/ethauvin/cryptoprice/releases/latest) [![Maven Central](https://maven-badges.herokuapp.com/maven-central/net.thauvin.erik/cryptoprice/badge.svg?color=blue)](https://maven-badges.herokuapp.com/maven-central/net.thauvin.erik/cryptoprice) <!-- [![Nexus Snapshot](https://img.shields.io/nexus/s/net.thauvin.erik/cryptoprice?server=https%3A%2F%2Foss.sonatype.org%2F)](https://oss.sonatype.org/content/repositories/snapshots/net/thauvin/erik/cryptoprice/) -->
[![License (3-Clause BSD)](https://img.shields.io/badge/license-BSD%203--Clause-blue.svg?style=flat-square)](https://opensource.org/licenses/BSD-3-Clause)
[![Kotlin](https://img.shields.io/badge/kotlin-1.8.0-blue)](https://kotlinlang.org/)
[![Nexus Snapshot](https://img.shields.io/nexus/s/net.thauvin.erik/cryptoprice?label=snapshot&server=https%3A%2F%2Foss.sonatype.org%2F)](https://oss.sonatype.org/content/repositories/snapshots/net/thauvin/erik/cryptoprice/)
[![Release](https://img.shields.io/github/release/ethauvin/cryptoprice.svg)](https://github.com/ethauvin/cryptoprice/releases/latest)
[![Maven Central](https://maven-badges.herokuapp.com/maven-central/net.thauvin.erik/cryptoprice/badge.svg?color=blue)](https://maven-badges.herokuapp.com/maven-central/net.thauvin.erik/cryptoprice)
[![Quality Gate Status](https://sonarcloud.io/api/project_badges/measure?project=ethauvin_cryptoprice&metric=alert_status)](https://sonarcloud.io/dashboard?id=ethauvin_cryptoprice) [![GitHub CI](https://github.com/ethauvin/cryptoprice/actions/workflows/gradle.yml/badge.svg)](https://github.com/ethauvin/cryptoprice/actions/workflows/gradle.yml) [![CircleCI](https://circleci.com/gh/ethauvin/cryptoprice/tree/master.svg?style=shield)](https://circleci.com/gh/ethauvin/cryptoprice/tree/master)
[![Quality Gate Status](https://sonarcloud.io/api/project_badges/measure?project=ethauvin_cryptoprice&metric=alert_status)](https://sonarcloud.io/dashboard?id=ethauvin_cryptoprice)
[![GitHub CI](https://github.com/ethauvin/cryptoprice/actions/workflows/gradle.yml/badge.svg)](https://github.com/ethauvin/cryptoprice/actions/workflows/gradle.yml)
[![CircleCI](https://circleci.com/gh/ethauvin/cryptoprice/tree/master.svg?style=shield)](https://circleci.com/gh/ethauvin/cryptoprice/tree/master)
# Retrieve cryptocurrencies current (buy, sell or spot) prices
A simple Kotlin/Java/Android implementation of the prices [Coinbase Public API](https://docs.cloud.coinbase.com/sign-in-with-coinbase/docs/api-prices).
A simple implementation of the prices [Coinbase Public API](https://docs.cloud.coinbase.com/sign-in-with-coinbase/docs/api-prices).
## Examples (TL;DR)
@ -32,6 +38,7 @@ To use with [Gradle](https://gradle.org/), include the following dependency in y
```gradle
repositories {
mavenCentral()
maven { url = uri("https://oss.sonatype.org/content/repositories/snapshots") } // only needed for SNAPSHOT
}
dependencies {
@ -85,7 +92,7 @@ val euro = CryptoPrice("BTC", "EUR", 23456.78.toBigDecimal())
println(euro.toCurrency()) // €23,456.78
val krone = CryptoPrice("BTC", "DKK", 123456.78.toBigDecimal())
println(krone.toCurrency(Locale("da", "DK"))) // 123.456,78 kr.
println(krone.toCurrency(Locale.Builder().setLanguage("da").setRegion("DK").build())) // 123.456,78 kr.
```
##### JSON

View file

@ -7,22 +7,22 @@ import org.gradle.api.tasks.testing.logging.TestLogEvent
plugins {
id("application")
id("com.github.ben-manes.versions") version "0.42.0"
id("io.gitlab.arturbosch.detekt") version "1.21.0"
id("com.github.ben-manes.versions") version "0.44.0"
id("io.gitlab.arturbosch.detekt") version "1.22.0"
id("java")
id("maven-publish")
id("org.jetbrains.dokka") version "1.7.10"
id("org.jetbrains.dokka") version "1.7.20"
id("org.jetbrains.kotlinx.kover") version "0.6.1"
id("org.sonarqube") version "3.4.0.2513"
id("org.sonarqube") version "3.5.0.2730"
id("signing")
kotlin("jvm") version "1.7.20"
kotlin("jvm") version "1.8.0"
}
defaultTasks(ApplicationPlugin.TASK_RUN_NAME)
description = "Retrieve cryptocurrencies prices."
description = "Retrieve cryptocurrencies prices"
group = "net.thauvin.erik"
version = "1.0.0"
version = "1.0.1-SNAPSHOT"
val deployDir = "deploy"
val gitHub = "ethauvin/$name"
@ -168,8 +168,8 @@ publishing {
}
}
scm {
connection.set("scm:git:git://github.com/$gitHub.git")
developerConnection.set("scm:git:git@github.com:$gitHub.git")
connection.set("scm:git://github.com/$gitHub.git")
developerConnection.set("scm:git@github.com:$gitHub.git")
url.set(mavenUrl)
}
issueManagement {

View file

@ -2,8 +2,8 @@ import org.jetbrains.kotlin.gradle.tasks.KotlinCompile
plugins {
id("application")
id("com.github.ben-manes.versions") version "0.42.0"
kotlin("jvm") version "1.7.20"
id("com.github.ben-manes.versions") version "0.44.0"
kotlin("jvm") version "1.8.0"
}
// ./gradlew run
@ -20,7 +20,7 @@ repositories {
}
dependencies {
implementation("net.thauvin.erik:cryptoprice:1.0.0")
implementation("net.thauvin.erik:cryptoprice:1.1.0-SNAPSHOT")
implementation("org.json:json:20220924")
}

View file

@ -1,5 +1,5 @@
distributionBase=GRADLE_USER_HOME
distributionPath=wrapper/dists
distributionUrl=https\://services.gradle.org/distributions/gradle-7.5.1-bin.zip
distributionUrl=https\://services.gradle.org/distributions/gradle-7.6-bin.zip
zipStoreBase=GRADLE_USER_HOME
zipStorePath=wrapper/dists

View file

@ -1,5 +1,5 @@
distributionBase=GRADLE_USER_HOME
distributionPath=wrapper/dists
distributionUrl=https\://services.gradle.org/distributions/gradle-7.5.1-bin.zip
distributionUrl=https\://services.gradle.org/distributions/gradle-7.6-bin.zip
zipStoreBase=GRADLE_USER_HOME
zipStorePath=wrapper/dists

14
pom.xml
View file

@ -8,9 +8,9 @@
<modelVersion>4.0.0</modelVersion>
<groupId>net.thauvin.erik</groupId>
<artifactId>cryptoprice</artifactId>
<version>1.0.0</version>
<version>1.0.1-SNAPSHOT</version>
<name>cryptoprice</name>
<description>Retrieve cryptocurrencies prices.</description>
<description>Retrieve cryptocurrencies prices</description>
<url>https://github.com/ethauvin/cryptoprice</url>
<licenses>
<license>
@ -27,8 +27,8 @@
</developer>
</developers>
<scm>
<connection>scm:git:git://github.com/ethauvin/cryptoprice.git</connection>
<developerConnection>scm:git:git@github.com:ethauvin/cryptoprice.git</developerConnection>
<connection>scm:git://github.com/ethauvin/cryptoprice.git</connection>
<developerConnection>scm:git@github.com:ethauvin/cryptoprice.git</developerConnection>
<url>https://github.com/ethauvin/cryptoprice</url>
</scm>
<issueManagement>
@ -40,7 +40,7 @@
<dependency>
<groupId>org.jetbrains.kotlin</groupId>
<artifactId>kotlin-bom</artifactId>
<version>1.7.10</version>
<version>1.8.0</version>
<type>pom</type>
<scope>import</scope>
</dependency>
@ -50,7 +50,7 @@
<dependency>
<groupId>org.jetbrains.kotlin</groupId>
<artifactId>kotlin-stdlib-jdk8</artifactId>
<version>1.7.10</version>
<version>1.8.0</version>
<scope>runtime</scope>
</dependency>
<dependency>
@ -62,7 +62,7 @@
<dependency>
<groupId>org.json</groupId>
<artifactId>json</artifactId>
<version>20220320</version>
<version>20220924</version>
<scope>runtime</scope>
</dependency>
</dependencies>

View file

@ -1,8 +1,7 @@
/*
* CryptoException.kt
*
* Copyright (c) 2021-2022, Erik C. Thauvin (erik@thauvin.net)
* All rights reserved.
* Copyright 2021-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:
@ -37,6 +36,7 @@ package net.thauvin.erik.crypto
*/
class CryptoException @JvmOverloads constructor(
var statusCode: Int = NO_STATUS,
var id: String,
message: String,
cause: Throwable? = null
) : Exception(message, cause) {

View file

@ -1,8 +1,7 @@
/*
* CryptoPrice.kt
*
* Copyright (c) 2021-2022, Erik C. Thauvin (erik@thauvin.net)
* All rights reserved.
* Copyright 2021-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:
@ -73,9 +72,9 @@ open class CryptoPrice(val base: String, val currency: String, val amount: BigDe
return CryptoPrice(getString("base"), getString("currency"), getString("amount").toBigDecimal())
}
} catch (e: NumberFormatException) {
throw CryptoException(message = "Could not convert amount to number.", cause = e)
throw CryptoException(id = "convert_error", message = "Could not convert amount to number.", cause = e)
} catch (e: JSONException) {
throw CryptoException(message = "Could not parse price data.", cause = e)
throw CryptoException(id = "parse_error", message = "Could not parse price data.", cause = e)
}
}
@ -101,17 +100,24 @@ open class CryptoPrice(val base: String, val currency: String, val amount: BigDe
val request = Request.Builder().url(httpUrl).build()
val response = client.newCall(request).execute()
val body = response.body?.string() ?: throw CryptoException(response.code, "Empty response.")
val body = response.body?.string() ?: throw CryptoException(
response.code,
id = "empty_response",
message = "Empty response."
)
try {
val json = JSONObject(body)
if (response.isSuccessful) {
return body
} else {
val data = json.getJSONArray("errors")
throw CryptoException(response.code, data.getJSONObject(0).getString("message"))
throw CryptoException(
response.code, data.getJSONObject(0).getString("id"),
data.getJSONObject(0).getString("message")
)
}
} catch (e: JSONException) {
throw CryptoException(response.code, "Could not parse data.", e)
throw CryptoException(response.code, id = "parse_error", "Could not parse data.", e)
}
}

View file

@ -1,8 +1,7 @@
/*
* CryptoPriceTest.kt
*
* Copyright (c) 2021-2022, Erik C. Thauvin (erik@thauvin.net)
* All rights reserved.
* Copyright 2021-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:
@ -134,6 +133,13 @@ class CryptoPriceTest {
block = { spotPrice("FOO") }
)
try {
spotPrice("BAR")
} catch (e: CryptoException) {
assertThat(e.id, "spotPrice(bar) error id").isEqualTo("not_found")
assertThat(e.message, "spotPrice(bar) error message").isEqualTo("Invalid base currency")
}
assertFailsWith(
message = "buyPrice(BTC,BAR)",
exceptionClass = CryptoException::class,
@ -183,7 +189,11 @@ class CryptoPriceTest {
assertEquals("A$12,345.60", aud.toCurrency(), "CryptoPrice(LTC,AUD)")
val dk = CryptoPrice("BCH", "DKK", d)
assertEquals("12.345,60 kr.", dk.toCurrency(Locale("da", "DK")), "CryptoPrice(BCH,DKK)")
assertEquals(
"12.345,60 kr.", dk.toCurrency(
Locale.Builder().setLanguage("da").setRegion("DK").build()
), "CryptoPrice(BCH,DKK)"
)
val jp = CryptoPrice("BTC", "JPY", d)
assertEquals("¥12,345.60", jp.toCurrency(Locale.JAPAN), "CryptoPrice(BTC,JPY)")