Skip to content

Commit

Permalink
feat: quotes client (#478)
Browse files Browse the repository at this point in the history
* feat: quotes client

* refactor: better naming of QuoteType enum

* refactor: use better cli arguments

* refactor: display quote info in json format
  • Loading branch information
thevaibhav-dixit authored Dec 5, 2023
1 parent ffc5978 commit d9383c5
Show file tree
Hide file tree
Showing 6 changed files with 178 additions and 2 deletions.
1 change: 1 addition & 0 deletions Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

1 change: 1 addition & 0 deletions cli/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -36,3 +36,4 @@ tracing-opentelemetry = { workspace = true }
axum = { workspace = true }
chrono = { workspace = true }
sqlx = { workspace = true }
serde_json = { workspace = true }
48 changes: 47 additions & 1 deletion cli/src/app.rs
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ use rust_decimal::Decimal;
use std::{collections::HashMap, path::PathBuf};
use url::Url;

use super::{config::*, price_client::*};
use super::{config::*, price_client::*, quotes_client::*};
use shared::pubsub::memory;

#[derive(Parser)]
Expand Down Expand Up @@ -63,6 +63,28 @@ enum Command {
expiry: Option<u64>,
amount: Decimal,
},

/// Gets a quote from the quote serve
GetQuote {
/// quote server URL
#[clap(short, long, action, value_parser, env = "QUOTE_SERVER_URL")]
url: Option<Url>,
#[clap(short, long)]
immediate_execution: bool,
#[clap(short, long, action, value_enum, value_parser, default_value_t = QuoteDirection::Buy)]
direction: QuoteDirection,
#[clap(short, long, action, value_enum, value_parser, default_value_t = Currency::Cents)]
currency: Currency,
amount: u64,
},

AcceptQuote {
/// quote server URL
#[clap(short, long, action, value_parser, env = "QUOTE_SERVER_URL")]
url: Option<Url>,
#[clap(short, long)]
id: String,
},
}

pub async fn run() -> anyhow::Result<()> {
Expand Down Expand Up @@ -105,6 +127,23 @@ pub async fn run() -> anyhow::Result<()> {
expiry,
amount,
} => price_cmd(url, direction, expiry, amount).await?,

Command::GetQuote {
url,
immediate_execution,
direction,
currency,
amount,
} => {
let client = get_quotes_client(url).await;
client
.get_quote(direction, currency, immediate_execution, amount)
.await?
}
Command::AcceptQuote { url, id } => {
let client = get_quotes_client(url).await;
client.accept_quote(id).await?;
}
}
Ok(())
}
Expand Down Expand Up @@ -294,6 +333,13 @@ async fn price_cmd(
client.get_price(direction, expiry, amount).await
}

async fn get_quotes_client(url: Option<Url>) -> QuotesClient {
QuotesClient::new(
url.map(|url| QuotesClientConfig { url })
.unwrap_or_default(),
)
}

fn price_stream_throttle_period() -> Duration {
Duration::from_std(std::time::Duration::from_millis(500)).unwrap()
}
Expand Down
1 change: 1 addition & 0 deletions cli/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -8,3 +8,4 @@ mod tracing;

mod db;
mod price_client;
mod quotes_client;
123 changes: 123 additions & 0 deletions cli/src/quotes_client.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,123 @@
use clap::ValueEnum;
use tonic::transport::channel::Channel;
use url::Url;

use ::quotes_server::proto;
type ProtoClient = proto::quote_service_client::QuoteServiceClient<Channel>;

#[derive(Debug, Copy, Clone, PartialEq, Eq, ValueEnum)]
pub enum QuoteDirection {
Buy,
Sell,
}

#[derive(Debug, Copy, Clone, PartialEq, Eq, ValueEnum)]
pub enum Currency {
Sats,
Cents,
}

pub struct QuotesClientConfig {
pub url: Url,
}

impl Default for QuotesClientConfig {
fn default() -> Self {
Self {
url: Url::parse("http://localhost:3326").unwrap(),
}
}
}

pub struct QuotesClient {
config: QuotesClientConfig,
}

impl QuotesClient {
pub fn new(config: QuotesClientConfig) -> Self {
Self { config }
}

async fn connect(&self) -> anyhow::Result<ProtoClient> {
match ProtoClient::connect(self.config.url.to_string()).await {
Ok(client) => Ok(client),
Err(err) => {
eprintln!(
"Couldn't connect to quotes server\nAre you sure its running on {}?\n",
self.config.url
);
Err(anyhow::anyhow!(err))
}
}
}

pub async fn get_quote(
&self,
direction: QuoteDirection,
currency: Currency,
immediate_execution: bool,
amount: u64,
) -> anyhow::Result<()> {
let mut client = self.connect().await?;

match (direction, currency) {
(QuoteDirection::Buy, Currency::Sats) => {
let request = tonic::Request::new(proto::GetQuoteToSellUsdRequest {
quote_for: Some(
proto::get_quote_to_sell_usd_request::QuoteFor::AmountToBuyInSats(amount),
),
immediate_execution,
});
let response = client.get_quote_to_sell_usd(request).await?;
output_json(response)?;
}
(QuoteDirection::Sell, Currency::Sats) => {
let request = tonic::Request::new(proto::GetQuoteToBuyUsdRequest {
quote_for: Some(
proto::get_quote_to_buy_usd_request::QuoteFor::AmountToSellInSats(amount),
),
immediate_execution,
});
let response = client.get_quote_to_buy_usd(request).await?;
output_json(response)?;
}
(QuoteDirection::Buy, Currency::Cents) => {
let request = tonic::Request::new(proto::GetQuoteToBuyUsdRequest {
quote_for: Some(
proto::get_quote_to_buy_usd_request::QuoteFor::AmountToBuyInCents(amount),
),
immediate_execution,
});
let response = client.get_quote_to_buy_usd(request).await?;
output_json(response)?;
}
(QuoteDirection::Sell, Currency::Cents) => {
let request = tonic::Request::new(proto::GetQuoteToSellUsdRequest {
quote_for: Some(
proto::get_quote_to_sell_usd_request::QuoteFor::AmountToSellInCents(amount),
),
immediate_execution,
});
let response = client.get_quote_to_sell_usd(request).await?;
output_json(response)?;
}
};

Ok(())
}

pub async fn accept_quote(&self, quote_id: String) -> anyhow::Result<()> {
let mut client = self.connect().await?;

let request = tonic::Request::new(proto::AcceptQuoteRequest { quote_id });
let _ = client.accept_quote(request).await?.into_inner();
println!("Quote accepted!");

Ok(())
}
}

fn output_json<T: serde::Serialize>(response: tonic::Response<T>) -> anyhow::Result<()> {
println!("{}", serde_json::to_string_pretty(&response.into_inner())?);
Ok(())
}
6 changes: 5 additions & 1 deletion quotes-server/build.rs
Original file line number Diff line number Diff line change
@@ -1,5 +1,9 @@
fn main() -> Result<(), Box<dyn std::error::Error>> {
std::env::set_var("PROTOC", protobuf_src::protoc());
tonic_build::compile_protos("../proto/quotes/quote_service.proto")?;

tonic_build::configure()
.type_attribute(".", "#[derive(serde::Serialize)]")
.type_attribute(".", "#[serde(rename_all = \"camelCase\")]")
.compile(&["../proto/quotes/quote_service.proto"], &["../proto"])?;
Ok(())
}

0 comments on commit d9383c5

Please sign in to comment.