-
Notifications
You must be signed in to change notification settings - Fork 3
Implement price-feed feature #49
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,61 @@ | ||
| use serde::Deserialize; | ||
| use thiserror::Error; | ||
|
|
||
| #[derive(Error, Debug)] | ||
| pub enum PriceFetcherError { | ||
| #[error("Request error: {0}")] | ||
| Request(#[from] minreq::Error), | ||
| #[error("Rate limit exceeded (429)")] | ||
| RateLimit, | ||
| #[error("Response status error: {0}")] | ||
| Status(i32), | ||
| #[error("Parse error: {0}")] | ||
| Parse(String), | ||
| #[error("Internal runtime error: {0}")] | ||
| Internal(String), | ||
| } | ||
|
|
||
| #[derive(Deserialize)] | ||
| struct BitcoinResponse { | ||
| bitcoin: BitcoinPrice, | ||
| } | ||
|
|
||
| #[derive(Deserialize)] | ||
| struct BitcoinPrice { | ||
| usd: f64, | ||
| } | ||
|
|
||
| pub trait PriceFetcher { | ||
| fn fetch_price(&self) -> Result<f64, PriceFetcherError>; | ||
| } | ||
|
Comment on lines
28
to
30
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. [P1] Trait returns crate-wide
Note: If this suggestion doesn't match your team's coding style, reply to this and let me know. I'll remember it for next time! Prompt To Fix With AIThis is a comment left during a code review.
Path: crates/cli-client/src/price_fetcher.rs
Line: 27:29
Comment:
[P1] Trait returns crate-wide `Error` instead of `PriceFetcherError`
`PriceFetcher::fetch_price()` returning `Result<f64, Error>` makes the trait harder to reuse and mock because it couples the fetcher layer to the entire CLI error enum. Since this module already defines `PriceFetcherError`, consider making the trait return `Result<f64, PriceFetcherError>` and converting to `crate::error::Error` at the CLI boundary.
<sub>Note: If this suggestion doesn't match your team's coding style, reply to this and let me know. I'll remember it for next time!</sub>
How can I resolve this? If you propose a fix, please make it concise. |
||
|
|
||
| #[derive(Default)] | ||
| pub struct CoingeckoPriceFetcher; | ||
|
|
||
| impl CoingeckoPriceFetcher { | ||
| const URL: &'static str = "https://api.coingecko.com/api/v3/simple/price?ids=bitcoin&vs_currencies=usd&precision=8"; | ||
| const TIMEOUT_SECS: u64 = 5; | ||
| } | ||
|
|
||
| impl PriceFetcher for CoingeckoPriceFetcher { | ||
| fn fetch_price(&self) -> Result<f64, PriceFetcherError> { | ||
| let resp = minreq::get(Self::URL) | ||
| .with_header("User-Agent", "simplicity-dex/1.0") | ||
| .with_timeout(Self::TIMEOUT_SECS) | ||
| .send() | ||
| .map_err(PriceFetcherError::from)?; | ||
|
|
||
| match resp.status_code { | ||
| 200 => resp | ||
| .json::<BitcoinResponse>() | ||
| .map(|data| data.bitcoin.usd) | ||
| .map_err(|e| PriceFetcherError::Parse(e.to_string())), | ||
| 429 => Err(PriceFetcherError::RateLimit), | ||
| status => Err(PriceFetcherError::Status(status)), | ||
| } | ||
| } | ||
| } | ||
zahorodnyi marked this conversation as resolved.
Show resolved
Hide resolved
|
||
|
|
||
| pub fn fetch_btc_usd_price<T: PriceFetcher>(fetcher: &T) -> Result<f64, PriceFetcherError> { | ||
| fetcher.fetch_price() | ||
| } | ||
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Trait uses synchronous blocking HTTP in async context.
fetch_price()calls blockingminreq::get()which blocks the tokio runtime thread. Either mark trait method as async or usetokio::task::spawn_blocking()when calling it.Prompt To Fix With AI