use std::pin::Pin;
use futures::stream::Stream;
use serde::de::DeserializeOwned;
use transports::{DuplexTransport, Transport, TransportError};
use types::{
account::{
AccountChannelsRequest, AccountChannelsResponse, AccountCurrenciesRequest,
AccountCurrenciesResponse, AccountInfoRequest, AccountInfoResponse, AccountLinesRequest,
AccountLinesResponse, AccountOfferRequest, AccountOfferResponse,
},
channels::{ChannelVerifyRequest, ChannelVerifyResponse},
fee::{FeeRequest, FeeResponse},
ledger::{LedgerRequest, LedgerResponse},
submit::{SignAndSubmitRequest, SubmitRequest, SubmitResponse},
subscribe::{SubscribeRequest, SubscriptionEvent},
tx::{TxRequest, TxResponse},
TransactionEntryRequest, TransactionEntryResponse,
};
pub mod transaction;
pub mod transports;
pub mod types;
pub mod utils;
pub mod wallet;
#[derive(Debug)]
pub enum Error {
TransportError(TransportError),
}
impl From<TransportError> for Error {
fn from(e: TransportError) -> Self {
Self::TransportError(e)
}
}
pub struct XRPL<T: Transport> {
transport: T,
}
macro_rules! impl_rpc_method {
($(#[$attr:meta])* $name: ident, $method: expr, $request: ident, $response: ident) => {
$(#[$attr])*
pub async fn $name(&self, params: $request) -> Result<$response, Error> {
Ok(self
.transport
.send_request::<$request, $response>($method, params)
.await?)
}
};
}
impl<T: Transport> XRPL<T> {
pub fn new(transport: T) -> Self {
Self { transport }
}
impl_rpc_method!(
account_channels,
"account_channels",
AccountChannelsRequest,
AccountChannelsResponse
);
impl_rpc_method!(
account_currencies,
"account_currencies",
AccountCurrenciesRequest,
AccountCurrenciesResponse
);
impl_rpc_method!(
account_info,
"account_info",
AccountInfoRequest,
AccountInfoResponse
);
impl_rpc_method!(
account_lines,
"account_lines",
AccountLinesRequest,
AccountLinesResponse
);
impl_rpc_method!(
account_offers,
"account_offers",
AccountOfferRequest,
AccountOfferResponse
);
impl_rpc_method!(
transaction_entry,
"transaction_entry",
TransactionEntryRequest,
TransactionEntryResponse
);
impl_rpc_method!(
submit,
"submit",
SubmitRequest,
SubmitResponse
);
impl_rpc_method!(
sign_and_submit,
"submit",
SignAndSubmitRequest,
SubmitResponse
);
impl_rpc_method!(
fee,
"fee",
FeeRequest,
FeeResponse
);
impl_rpc_method!(
ledger,
"ledger",
LedgerRequest,
LedgerResponse
);
impl_rpc_method!(
channel_verify,
"channel_verify",
ChannelVerifyRequest,
ChannelVerifyResponse
);
impl_rpc_method!(
tx,
"tx",
TxRequest,
TxResponse
);
}
impl<T: DuplexTransport> XRPL<T> {
pub async fn subscribe(
&self,
request: SubscribeRequest,
) -> Result<Pin<Box<dyn Stream<Item = Result<SubscriptionEvent, TransportError>>>>, TransportError> {
self.transport.subscribe(request).await
}
}
#[cfg(test)]
mod tests {
use crate::types::{BigInt, CurrencyAmount};
use super::{transports::HTTPBuilder, types, XRPL};
#[test]
fn create_client() {
let _ = XRPL::new(
HTTPBuilder::default()
.with_endpoint("http://s1.ripple.com:51234/")
.unwrap()
.build()
.unwrap(),
);
}
#[tokio::test]
async fn account_info() {
let c = XRPL::new(
HTTPBuilder::default()
.with_endpoint("http://s1.ripple.com:51234/")
.unwrap()
.build()
.unwrap(),
);
let res = c
.account_info(types::account::AccountInfoRequest {
account: "rG1QQv2nh2gr7RCZ1P8YYcBUKCCN633jCn".to_owned(),
strict: None,
queue: None,
ledger_info: types::LedgerInfo::default(),
signer_lists: None,
})
.await;
match res {
Err(e) => {
eprintln!("test failed: {:?}", e);
}
Ok(res) => {
assert_eq!(res.account_data.balance, CurrencyAmount::XRP(BigInt(9977)),);
}
}
}
}