Skip to content

Commit

Permalink
feat: add crossplatform-httpclient
Browse files Browse the repository at this point in the history
  • Loading branch information
ngutech21 committed Feb 8, 2024
1 parent 30bc386 commit 22be994
Show file tree
Hide file tree
Showing 12 changed files with 256 additions and 635 deletions.
14 changes: 7 additions & 7 deletions integrationtests/tests/tests.rs
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
#![allow(unused_imports)]
use moksha_core::primitives::PaymentMethod;
use moksha_wallet::client::reqwest::HttpClient;
use moksha_wallet::client::LegacyClient;

use moksha_wallet::client::CashuClient;
use moksha_wallet::http::CrossPlatformHttpClient;
use moksha_wallet::localstore::sqlite::SqliteLocalStore;
use moksha_wallet::wallet::WalletBuilder;
use mokshamint::lightning::lnbits::LnbitsLightningSettings;
Expand All @@ -18,7 +18,7 @@ use tokio::time::{sleep_until, Instant};

#[test]
pub fn test_integration() -> anyhow::Result<()> {
use mokshamint::config::{DatabaseConfig, LightningFeeConfig, ServerConfig};
use mokshamint::config::{DatabaseConfig, ServerConfig};

let docker = clients::Cli::default();
let node = docker.run(Postgres::default());
Expand Down Expand Up @@ -66,14 +66,14 @@ pub fn test_integration() -> anyhow::Result<()> {
// Wait for the server to start
std::thread::sleep(std::time::Duration::from_millis(800));

let client = HttpClient::default();
let client = CrossPlatformHttpClient::new();
let mint_url = Url::parse("http://127.0.0.1:8686")?;
let rt = Runtime::new()?;
rt.block_on(async move {
let keys = client.get_mint_keys(&mint_url).await;
let keys = client.get_keys(&mint_url).await;
assert!(keys.is_ok());

let keysets = client.get_mint_keysets(&mint_url).await;
let keysets = client.get_keysets(&mint_url).await;
assert!(keysets.is_ok());

// create wallet
Expand Down
2 changes: 1 addition & 1 deletion justfile
Original file line number Diff line number Diff line change
Expand Up @@ -64,7 +64,7 @@ run-cli *ARGS:
# run integrationtests
run-itests:
cd integrationtests && \
cargo test -- --ignored
cargo test

# build the mint docker-image
build-docker:
Expand Down
3 changes: 2 additions & 1 deletion moksha-cli/src/main.rs
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ use moksha_core::primitives::{
PaymentMethod, PostMeltOnchainResponse, PostMintQuoteBolt11Response,
PostMintQuoteOnchainResponse,
};
use moksha_wallet::http::CrossPlatformHttpClient;
use num_format::{Locale, ToFormattedString};
use std::io::Write;
use std::{io::stdout, path::PathBuf};
Expand Down Expand Up @@ -72,7 +73,7 @@ async fn main() -> anyhow::Result<()> {
};

let localstore = SqliteLocalStore::with_path(db_path.clone()).await?;
let client = moksha_wallet::client::reqwest::HttpClient::new();
let client = CrossPlatformHttpClient::new();
let wallet = moksha_wallet::wallet::WalletBuilder::default()
.with_client(client)
.with_localstore(localstore)
Expand Down
4 changes: 2 additions & 2 deletions moksha-wallet/examples/receive_tokens.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,15 +2,15 @@ use std::env::temp_dir;

use moksha_core::token::TokenV3;
use moksha_wallet::{
client::reqwest::HttpClient, localstore::sqlite::SqliteLocalStore, wallet::WalletBuilder,
http::CrossPlatformHttpClient, localstore::sqlite::SqliteLocalStore, wallet::WalletBuilder,
};
use url::Url;

#[tokio::main]
async fn main() -> anyhow::Result<()> {
let db_path = temp_dir().join("wallet.db").to_str().unwrap().to_string();
let localstore = SqliteLocalStore::with_path(db_path).await?;
let client = HttpClient::new();
let client = CrossPlatformHttpClient::new();
let wallet = WalletBuilder::default()
.with_client(client)
.with_localstore(localstore)
Expand Down
Original file line number Diff line number Diff line change
@@ -1,11 +1,10 @@
use async_trait::async_trait;
use gloo_net::http::{Request, Response};

use moksha_core::{
blind::BlindedMessage,
keyset::V1Keysets,
primitives::{
CashuErrorResponse, CurrencyUnit, GetMeltOnchainResponse, KeysResponse, MintInfoResponse,
CurrencyUnit, GetMeltOnchainResponse, KeysResponse, MintInfoResponse,
PostMeltBolt11Request, PostMeltBolt11Response, PostMeltOnchainRequest,
PostMeltOnchainResponse, PostMeltQuoteBolt11Request, PostMeltQuoteBolt11Response,
PostMeltQuoteOnchainRequest, PostMeltQuoteOnchainResponse, PostMintBolt11Request,
Expand All @@ -16,36 +15,29 @@ use moksha_core::{
proof::Proofs,
};

use crate::error::MokshaWalletError;
use url::Url;

use super::Client;
use crate::{error::MokshaWalletError, http::CrossPlatformHttpClient};

#[derive(Debug, Clone)]
pub struct WasmClient;

impl WasmClient {
pub fn new() -> Self {
Self {}
}
}
use super::CashuClient;

#[async_trait(?Send)]
impl Client for WasmClient {
impl CashuClient for CrossPlatformHttpClient {
async fn get_keys(&self, mint_url: &Url) -> Result<KeysResponse, MokshaWalletError> {
do_get(&mint_url.join("v1/keys")?).await
self.do_get(&mint_url.join("v1/keys")?).await
}

async fn get_keys_by_id(
&self,
mint_url: &Url,
keyset_id: String,
) -> Result<KeysResponse, MokshaWalletError> {
do_get(&mint_url.join(&format!("v1/keys/{}", keyset_id))?).await
self.do_get(&mint_url.join(&format!("v1/keys/{}", keyset_id))?)
.await
}

async fn get_keysets(&self, mint_url: &Url) -> Result<V1Keysets, MokshaWalletError> {
do_get(&mint_url.join("v1/keysets")?).await
self.do_get(&mint_url.join("v1/keysets")?).await
}

async fn post_swap(
Expand All @@ -56,7 +48,7 @@ impl Client for WasmClient {
) -> Result<PostSwapResponse, MokshaWalletError> {
let body = PostSwapRequest { inputs, outputs };

do_post(&mint_url.join("v1/swap")?, &body).await
self.do_post(&mint_url.join("v1/swap")?, &body).await
}

async fn post_melt_bolt11(
Expand All @@ -72,7 +64,7 @@ impl Client for WasmClient {
outputs,
};

do_post(&mint_url.join("v1/melt/bolt11")?, &body).await
self.do_post(&mint_url.join("v1/melt/bolt11")?, &body).await
}

async fn post_melt_quote_bolt11(
Expand All @@ -86,7 +78,8 @@ impl Client for WasmClient {
unit,
};

do_post(&mint_url.join("v1/melt/quote/bolt11")?, &body).await
self.do_post(&mint_url.join("v1/melt/quote/bolt11")?, &body)
.await
}

async fn get_melt_quote_bolt11(
Expand All @@ -95,7 +88,7 @@ impl Client for WasmClient {
quote: String,
) -> Result<PostMeltQuoteBolt11Response, MokshaWalletError> {
let url = mint_url.join(&format!("v1/melt/quote/bolt11/{}", quote))?;
do_get(&url).await
self.do_get(&url).await
}

async fn post_mint_bolt11(
Expand All @@ -108,7 +101,7 @@ impl Client for WasmClient {
quote,
outputs: blinded_messages,
};
do_post(&mint_url.join("v1/mint/bolt11")?, &body).await
self.do_post(&mint_url.join("v1/mint/bolt11")?, &body).await
}

async fn post_mint_quote_bolt11(
Expand All @@ -118,27 +111,17 @@ impl Client for WasmClient {
unit: CurrencyUnit,
) -> Result<PostMintQuoteBolt11Response, MokshaWalletError> {
let body = PostMintQuoteBolt11Request { amount, unit };
do_post(&mint_url.join("v1/mint/quote/bolt11")?, &body).await
self.do_post(&mint_url.join("v1/mint/quote/bolt11")?, &body)
.await
}

async fn get_mint_quote_bolt11(
&self,
mint_url: &Url,
quote: String,
) -> Result<PostMintQuoteBolt11Response, MokshaWalletError> {
do_get(&mint_url.join(&format!("v1/mint/quote/bolt11/{}", quote))?).await
}

async fn get_info(&self, mint_url: &Url) -> Result<MintInfoResponse, MokshaWalletError> {
do_get(&mint_url.join("v1/info")?).await
}

async fn is_v1_supported(&self, mint_url: &Url) -> Result<bool, MokshaWalletError> {
let resp = Request::get(mint_url.join("v1/info")?.as_str())
.send()
.await?;

Ok(resp.status() == 200)
self.do_get(&mint_url.join(&format!("v1/mint/quote/bolt11/{}", quote))?)
.await
}

async fn post_mint_onchain(
Expand All @@ -151,7 +134,8 @@ impl Client for WasmClient {
quote,
outputs: blinded_messages,
};
do_post(&mint_url.join("v1/mint/btconchain")?, &body).await
self.do_post(&mint_url.join("v1/mint/btconchain")?, &body)
.await
}

async fn post_mint_quote_onchain(
Expand All @@ -160,19 +144,28 @@ impl Client for WasmClient {
amount: u64,
unit: CurrencyUnit,
) -> Result<PostMintQuoteOnchainResponse, MokshaWalletError> {
do_post(
&mint_url.join("v1/mint/quote/btconchain")?,
&PostMintQuoteOnchainRequest { amount, unit },
)
.await
let body = PostMintQuoteOnchainRequest { amount, unit };
self.do_post(&mint_url.join("v1/mint/quote/btconchain")?, &body)
.await
}

async fn get_mint_quote_onchain(
&self,
mint_url: &Url,
quote: String,
) -> Result<PostMintQuoteOnchainResponse, MokshaWalletError> {
do_get(&mint_url.join(&format!("v1/mint/quote/btconchain/{}", quote))?).await
self.do_get(&mint_url.join(&format!("v1/mint/quote/btconchain/{}", quote))?)
.await
}

async fn get_info(&self, mint_url: &Url) -> Result<MintInfoResponse, MokshaWalletError> {
self.do_get(&mint_url.join("v1/info")?).await
}

async fn is_v1_supported(&self, mint_url: &Url) -> Result<bool, MokshaWalletError> {
self.get_status(&mint_url.join("v1/info")?)
.await
.map(|s| s == 200)
}

async fn post_melt_onchain(
Expand All @@ -181,11 +174,9 @@ impl Client for WasmClient {
inputs: Proofs,
quote: String,
) -> Result<PostMeltOnchainResponse, MokshaWalletError> {
do_post(
&mint_url.join("v1/melt/btconchain")?,
&PostMeltOnchainRequest { quote, inputs },
)
.await
let body = PostMeltOnchainRequest { quote, inputs };
self.do_post(&mint_url.join("v1/melt/btconchain")?, &body)
.await
}

async fn post_melt_quote_onchain(
Expand All @@ -200,79 +191,25 @@ impl Client for WasmClient {
amount,
unit,
};
do_post(&mint_url.join("v1/melt/quote/btconchain")?, &body).await
self.do_post(&mint_url.join("v1/melt/quote/btconchain")?, &body)
.await
}

async fn get_melt_quote_onchain(
&self,
mint_url: &Url,
quote: String,
) -> Result<PostMeltQuoteOnchainResponse, MokshaWalletError> {
do_get(&mint_url.join(&format!("/v1/melt/quote/btconchain/{quote}"))?).await
self.do_get(&mint_url.join(&format!("/v1/melt/quote/btconchain/{quote}"))?)
.await
}

async fn get_melt_onchain(
&self,
mint_url: &Url,
txid: String,
) -> Result<GetMeltOnchainResponse, MokshaWalletError> {
do_get(&mint_url.join(&format!("/v1/melt/btconchain/{txid}"))?).await
}
}

async fn do_get<T: serde::de::DeserializeOwned>(url: &Url) -> Result<T, MokshaWalletError> {
let resp = Request::get(url.as_str()).send().await?;
extract_response_data::<T>(resp).await
}

async fn do_post<T: serde::de::DeserializeOwned, B: serde::Serialize>(
url: &Url,
body: &B,
) -> Result<T, MokshaWalletError> {
let resp = Request::post(url.as_str())
.header("content-type", "application/json")
.json(body)?
.send()
.await?;
extract_response_data::<T>(resp).await
}

async fn extract_response_data<T: serde::de::DeserializeOwned>(
response: Response,
) -> Result<T, MokshaWalletError> {
match response.status() {
200 => {
let response_text = response.text().await.unwrap(); // FIXME handle error
match serde_json::from_str::<T>(&response_text) {
Ok(data) => Ok(data),
Err(_) => {
let data = serde_json::from_str::<CashuErrorResponse>(&response_text)
.map_err(|_| MokshaWalletError::UnexpectedResponse(response_text))
.unwrap();

// FIXME: use the error code to return a proper error
match data.detail.as_str() {
"Lightning invoice not paid yet." => {
Err(MokshaWalletError::InvoiceNotPaidYet(data.code, data.detail))
}
_ => Err(MokshaWalletError::MintError(data.detail)),
}
}
}
}
_ => {
let txt = response.text().await.unwrap(); // FIXME handle error
let data = serde_json::from_str::<CashuErrorResponse>(&txt)
.map_err(|_| MokshaWalletError::UnexpectedResponse(txt))
.unwrap();

// FIXME: use the error code to return a proper error
match data.detail.as_str() {
"Lightning invoice not paid yet." => {
Err(MokshaWalletError::InvoiceNotPaidYet(data.code, data.detail))
}
_ => Err(MokshaWalletError::MintError(data.detail)),
}
}
self.do_get(&mint_url.join(&format!("/v1/melt/btconchain/{txid}"))?)
.await
}
}
Loading

0 comments on commit 22be994

Please sign in to comment.