use crate::client::{Client, ClientType, CryptoClient};
use crate::types::{Amount, ClientOptions, Currency, Symbol, SyncItem, SyncStats, WalletBalance};
use crate::Result;
use async_std::sync::Arc;
use async_trait::async_trait;
use num_bigint::BigInt;
use rpc_json_client::{ClientBuilder, RpcClient};
#[derive(Clone)]
pub struct TurtlRpcClient {
client: Arc<RpcClient>,
}
pub fn get_client(client_type: ClientType, options: ClientOptions) -> crate::Result<Box<Client>> {
match client_type {
ClientType::RPC => Ok(Box::new(TurtlRpcClient::new(options))),
_ => Err(crate::error::ClientError::UnsupportedType(client_type)),
}
}
impl TurtlRpcClient {
pub fn new(options: ClientOptions) -> Self {
let client = ClientBuilder::new(&options.url).with_retry();
let inner_client = if let Some(username) = options.username {
if let Some(password) = options.password {
client.with_user(&username, &password).build()
} else {
client.build()
}
} else {
client.build()
};
TurtlRpcClient {
client: Arc::new(inner_client),
}
}
}
#[async_trait]
impl CryptoClient for TurtlRpcClient {
async fn sync_stats(&self) -> SyncStats {
let result: serde_json::Value = match self.client.execute("getblockchaininfo", &[]).await {
Ok(r) => r,
Err(_e) => {
async_std::task::sleep(std::time::Duration::from_secs(60)).await;
return SyncStats {
current_block: 0,
syncing: true,
sync_item: SyncItem::VerificationProgress,
estimated_sync_item_remaining: 0.0,
};
}
};
let blocks = result.as_object().unwrap().get("blocks").unwrap();
let current_block = blocks.as_u64().unwrap();
let progress = result
.as_object()
.unwrap()
.get("verificationprogress")
.unwrap()
.as_f64()
.unwrap();
let ibd = result
.as_object()
.unwrap()
.get("initialblockdownload")
.unwrap()
.as_bool()
.unwrap();
let (syncing, estimated_sync_item_remaining) = if ibd == false {
(false, 0.0)
} else {
let estimated_sync_item_remaining = 1.0 - progress;
if estimated_sync_item_remaining < 0.001 {
(false, 0.0)
} else {
(true, estimated_sync_item_remaining)
}
};
SyncStats {
current_block,
syncing,
sync_item: SyncItem::VerificationProgress,
estimated_sync_item_remaining,
}
}
async fn wallet_balance(&self, _identifier: &str) -> Result<WalletBalance> {
let result: serde_json::Value = self.client.execute("getwalletinfo", &[]).await?;
let confirmed_balance = result["balance"].as_f64().unwrap_or(0.0);
let unconfirmed_balance = result["unconfirmed_balance"].as_f64().unwrap_or(0.0);
let confirmed_balance = BigInt::from((confirmed_balance * 100_000_000.0).floor() as u64);
let unconfirmed_balance =
BigInt::from((unconfirmed_balance * 100_000_000.0).floor() as u64);
Ok(WalletBalance {
confirmed_balance: Amount {
value: confirmed_balance,
currency: Currency {
symbol: Symbol::BTC,
decimals: 8,
},
},
unconfirmed_balance: Amount {
value: unconfirmed_balance,
currency: Currency {
symbol: Symbol::BTC,
decimals: 8,
},
},
})
}
fn client_type(&self) -> ClientType {
ClientType::RPC
}
}