From 4fd28eff9bc6615b170705b2d26add3d93771e17 Mon Sep 17 00:00:00 2001 From: Luke Kim <80174+lukekim@users.noreply.github.com> Date: Mon, 22 Apr 2024 12:47:01 +0900 Subject: [PATCH] Remove deprecated Asset Prices API support --- README.md | 48 ----------- src/client.rs | 66 +-------------- src/lib.rs | 2 - src/prices.rs | 198 ------------------------------------------- tests/price_test.rs | 30 ------- tests/readme_test.rs | 32 ------- 6 files changed, 2 insertions(+), 374 deletions(-) delete mode 100644 src/prices.rs diff --git a/README.md b/README.md index 972c7d7..9122577 100644 --- a/README.md +++ b/README.md @@ -55,54 +55,6 @@ async fn main() { ``` -### HTTP API - -#### Prices - -Get the supported pairs: - -```rust -use spiceai::Client; - -#[tokio::main] -async fn main() { - let mut client = Client::new("API_KEY").await.unwrap(); - let supported_pairs = client.get_supported_pairs().await; -} -``` - -Get the latest price for a token pair: - -```rust -use spiceai::Client; - -#[tokio::main] -async fn main() { - let mut client = Client::new("API_KEY").await.unwrap(); - let price_data = client.get_prices(&["BTC-USDC"]).await; -} -``` - -Get historical data: - -```rust -use spiceai::Client; -use chrono::Utc; -use chrono::Duration; -use std::ops::Sub; - -#[tokio::main] -async fn main() { - let mut client = Client::new("API_KEY").await.unwrap(); - let now = Utc::now(); - let start = now.sub(Duration::seconds(3600)); - - let historical_price_data = client - .get_historical_prices(&["BTC-USDC"], Some(start), Some(now), Option::None).await; -} - -``` - ## Documentation Check out our [Documentation](https://docs.spice.ai/sdks/rust-sdk) to learn more about how to use the Rust SDK. diff --git a/src/client.rs b/src/client.rs index 3f94a0d..e31d0d2 100644 --- a/src/client.rs +++ b/src/client.rs @@ -1,14 +1,11 @@ use crate::{ config::{FIRECACHE_ADDR, FLIGHT_ADDR, HTTPS_ADDR}, flight::SqlFlightClient, - prices::PricesClient, tls::new_tls_flight_channel, - HistoricalPriceData, LatestPricesResponse, }; use arrow_flight::decode::FlightRecordBatchStream; -use chrono::{DateTime, Utc}; use futures::try_join; -use std::{collections::HashMap, error::Error}; +use std::error::Error; use tonic::transport::Channel; struct SpiceClientConfig { @@ -41,13 +38,11 @@ impl SpiceClientConfig { } /// The `SpiceClient` is the main entry point for interacting with the Spice API. -/// It provides methods for querying the Spice Flight and Firecache endpoints, -/// as well as the Spice Prices endpoint. +/// It provides methods for querying the Spice Flight and Firecache endpoints. #[allow(clippy::module_name_repetitions)] pub struct SpiceClient { flight: SqlFlightClient, firecache: SqlFlightClient, - prices: PricesClient, } impl SpiceClient { @@ -66,7 +61,6 @@ impl SpiceClient { Ok(Self { flight: SqlFlightClient::new(config.flight_channel, api_key.to_string()), firecache: SqlFlightClient::new(config.firecache_channel, api_key.to_string()), - prices: PricesClient::new(Some(config.https_addr), api_key.to_string()), }) } @@ -100,60 +94,4 @@ impl SpiceClient { ) -> Result> { self.firecache.query(query).await } - - /// Get the supported pairs: - /// ```rust - /// # use spiceai::Client; - /// # - /// # #[tokio::main] - /// # async fn main() { - /// # let mut client = Client::new("API_KEY").await.unwrap(); - /// let supported_pairs = client.get_supported_pairs().await; - /// # } - /// ``` - pub async fn get_supported_pairs(&self) -> Result, Box> { - self.prices.get_supported_pairs().await - } - - /// Get the latest price for a token pair: - /// ```rust - /// # use spiceai::Client; - /// # - /// # #[tokio::main] - /// # async fn main() { - /// # let mut client = Client::new("API_KEY").await.unwrap(); - /// let price_data = client.get_prices(&["BTC-USDC"]).await; - /// # } - /// ``` - pub async fn get_prices(&self, pairs: &[&str]) -> Result> { - self.prices.get_prices(pairs).await - } - - /// Get historical data: - /// ```rust - /// # use spiceai::Client; - /// # use chrono::Utc; - /// # use chrono::Duration; - /// # use std::ops::Sub; - /// # - /// # #[tokio::main] - /// # async fn main() { - /// # let mut client = Client::new("API_KEY").await.unwrap(); - /// # let now = Utc::now(); - /// # let start = now.sub(Duration::seconds(3600)); - /// let historical_price_data = client - /// .get_historical_prices(&["BTC-USDC"], Some(start), Some(now), Option::None).await; - /// # } - /// ``` - pub async fn get_historical_prices( - &self, - pairs: &[&str], - start: Option>, - end: Option>, - granularity: Option<&str>, - ) -> Result>, Box> { - self.prices - .get_historical_prices(pairs, start, end, granularity) - .await - } } diff --git a/src/lib.rs b/src/lib.rs index ad02044..b368e0e 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -3,11 +3,9 @@ mod client; mod config; mod flight; -mod prices; mod tls; pub use client::SpiceClient as Client; -pub use prices::{HistoricalPriceData, LatestPriceDetail, LatestPricesResponse}; // Further public exports and integrations pub use futures::StreamExt; diff --git a/src/prices.rs b/src/prices.rs deleted file mode 100644 index 8f3ac6a..0000000 --- a/src/prices.rs +++ /dev/null @@ -1,198 +0,0 @@ -use std::collections::HashMap; -use std::error::Error; -use std::fmt; - -use chrono::{DateTime, Utc}; -use reqwest::{Response, StatusCode}; -use serde::{de::DeserializeOwned, Deserialize}; - -use crate::config::HTTPS_ADDR; - -#[derive(Debug, Deserialize)] -pub struct HistoricalPriceData { - pub timestamp: DateTime, - pub price: f64, - pub high: Option, - pub low: Option, - pub open: Option, - pub close: Option, -} - -impl fmt::Display for HistoricalPriceData { - fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { - write!( - f, - "Timestamp: {}, Price: {}, High: {:?}, Low: {:?}, Open: {:?}, Close: {:?}", - self.timestamp, self.price, self.high, self.low, self.open, self.close - ) - } -} - -#[derive(Debug, Deserialize)] -pub struct LatestPriceDetail { - #[serde(deserialize_with = "string_to_float_map")] - pub prices: HashMap, - #[serde( - rename = "minPrice", - default, - deserialize_with = "string_to_float_option" - )] - pub min_price: Option, - #[serde( - rename = "maxPrice", - default, - deserialize_with = "string_to_float_option" - )] - pub max_price: Option, - #[serde( - rename = "meanPrice", - default, - deserialize_with = "string_to_float_option" - )] - pub mean_price: Option, -} -impl fmt::Display for LatestPriceDetail { - fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { - let prices_str = self - .prices - .iter() - .map(|(k, v)| format!("{}: {}", k, v)) - .collect::>() - .join(", "); - write!( - f, - "Prices: [{}], Min Price: {:?}, Max Price: {:?}, Mean Price: {:?}", - prices_str, self.min_price, self.max_price, self.mean_price - ) - } -} - -#[derive(Debug, Deserialize)] -pub struct LatestPricesResponse { - // This assumes each key in the JSON (like "BTC-USDC", "LTC-USDT") is dynamic and represents a currency pair - #[serde(flatten)] - pub prices: HashMap, -} - -impl fmt::Display for LatestPricesResponse { - fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { - let prices_str = self - .prices - .iter() - .map(|(pair, detail)| format!("Pair: {}, Details: [{}]", pair, detail)) - .collect::>() - .join("\n"); - write!(f, "{}", prices_str) - } -} - -fn string_to_float_map<'de, D>(deserializer: D) -> Result, D::Error> -where - D: serde::Deserializer<'de>, -{ - let map = HashMap::::deserialize(deserializer)?; - map.into_iter() - .map(|(k, v)| v.parse::().map(|v_f64| (k, v_f64))) - .collect::, std::num::ParseFloatError>>() - .map_err(serde::de::Error::custom) -} - -fn string_to_float_option<'de, D>(deserializer: D) -> Result, D::Error> -where - D: serde::Deserializer<'de>, -{ - Option::deserialize(deserializer)? - .map(|x: String| x.parse::()) - .transpose() - .map_err(|x| serde::de::Error::custom(x.to_string())) -} - -async fn map_reqwest_response(resp: Response) -> Result> { - match resp.status() { - StatusCode::OK => { - let response: T = resp.json().await?; - Ok(response) - } - StatusCode::BAD_REQUEST => Err("Bad request".into()), - StatusCode::TOO_MANY_REQUESTS => Err("Rate limit exceeded, slow down".into()), - StatusCode::INTERNAL_SERVER_ERROR => Err("Internal server error".into()), - _ => Err(format!("Unexpected response status: {}", resp.status()).into()), - } -} - -pub struct PricesClient { - base_url: String, - _api_key: String, - client: reqwest::Client, -} - -impl PricesClient { - pub fn new(base_url: Option, api_key: String) -> Self { - let default_url = HTTPS_ADDR.to_string(); - let client = reqwest::Client::new(); - PricesClient { - base_url: base_url.unwrap_or(default_url), - _api_key: api_key, - client, - } - } - - fn add_headers(&self, request_builder: reqwest::RequestBuilder) -> reqwest::RequestBuilder { - request_builder - .header("X-API-Key", &self._api_key) - .header("Accept", "application/json") - .header("User-Agent", "spice-rs 1.0") - } - - pub async fn get_supported_pairs(&self) -> Result, Box> { - let url = format!("{}/v1/prices/pairs", self.base_url); - let request = self.client.get(&url); - let response: Vec = self.add_headers(request).send().await?.json().await?; - Ok(response) - } - - pub async fn get_prices(&self, pairs: &[&str]) -> Result> { - let url = format!("{}/v1/prices?pairs={}", self.base_url, pairs.join(",")); - - self.add_headers(self.client.get(&url)) - .send() - .await - .map(map_reqwest_response)? - .await - } - - pub async fn get_historical_prices( - &self, - pairs: &[&str], - start: Option>, - end: Option>, - granularity: Option<&str>, - ) -> Result>, Box> { - let mut url = format!( - "{}/v1/prices/historical?pairs={}", - self.base_url, - pairs.join(",") - ); - - if let Some(start_time) = start { - let timestamp = start_time.timestamp(); - url.push_str(&format!("&start={}", timestamp)); - } - - if let Some(end_time) = end { - let timestamp = end_time.timestamp(); - url.push_str(&format!("&end={}", timestamp)); - } - - if let Some(gran) = granularity { - url.push_str(&format!("&granularity={}", gran)); - } - - println!("URL: {}", url); - self.add_headers(self.client.get(&url)) - .send() - .await - .map(map_reqwest_response)? - .await - } -} diff --git a/tests/price_test.rs b/tests/price_test.rs index ff7a4e4..5a6f842 100644 --- a/tests/price_test.rs +++ b/tests/price_test.rs @@ -12,34 +12,4 @@ mod tests { .await .expect("Failed to create client") } - - #[tokio::test] - async fn test_get_supported_pairs() { - let spice_client = new_client().await; - let result = spice_client.get_supported_pairs().await; - assert!(result.is_ok()); - } - - #[tokio::test] - async fn test_get_prices() { - let spice_client = new_client().await; - let pair = "BTC-USD"; - let result = spice_client.get_prices(&[pair]).await; - assert!(result.is_ok()); - } - - #[tokio::test] - async fn test_get_historical_prices() { - let spice_client = new_client().await; - let pair1 = "BTC-USD"; - let pair2 = "ETH-USD"; - - let start_time = Utc.timestamp_opt(1697669766, 0).single(); - let end_time = Utc.timestamp_opt(1697756166, 0).single(); - - let result = spice_client - .get_historical_prices(&[pair1, pair2], start_time, end_time, Some("1h")) - .await; - assert!(result.is_ok()); - } } diff --git a/tests/readme_test.rs b/tests/readme_test.rs index 04523db..382e9d1 100644 --- a/tests/readme_test.rs +++ b/tests/readme_test.rs @@ -19,37 +19,5 @@ mod tests { if data.is_err() { panic!("failed to query: {:#?}", data.expect_err("")) } - let supported_pairs = client.get_supported_pairs().await; - if supported_pairs.is_err() { - panic!( - "failed to get supported pairs: {:#?}", - supported_pairs.expect_err("") - ) - } - let price_data = client.get_prices(&["BTC-USDC"]).await; - if price_data.is_err() { - panic!("failed to get prices: {:#?}", price_data.expect_err("")) - } - let historical_price_data = client - .get_historical_prices(&["BTC-USDC"], Option::None, Option::None, Option::None) - .await; - if historical_price_data.is_err() { - panic!( - "failed to get prices: {:#?}", - historical_price_data.expect_err("") - ) - } - let now = Utc::now(); - let start = now.sub(Duration::seconds(3600)); - - let historical_price_data = client - .get_historical_prices(&["BTC-USDC"], Some(start), Some(now), Option::None) - .await; - if historical_price_data.is_err() { - panic!( - "failed to get prices: {:#?}", - historical_price_data.expect_err("") - ) - } } }