mod event_matcher;
use crate::casper_client::configuration::CasperClientConfiguration;
use crate::error::LivenetError;
use crate::log;
use casper_types::execution::ExecutionResult;
use casper_types::TransactionHash;
use futures_util::StreamExt;
use reqwest_eventsource::{Error as EventSourceError, Event, EventSource};
use std::time::Duration;
pub struct TransactionWatcher {
events_url: String,
timeout: Duration
}
impl TransactionWatcher {
pub fn new(cfg: &CasperClientConfiguration, timeout: Duration) -> Self {
Self {
events_url: cfg.events_url.clone(),
timeout
}
}
pub async fn start_watching(&self) -> Result<TransactionWatch, LivenetError> {
log::debug(format!(
"[WATCHER] Connecting to events stream: {}",
self.events_url
));
let es = EventSource::get(&self.events_url);
Ok(TransactionWatch {
es,
timeout: self.timeout
})
}
}
pub struct TransactionWatch {
es: EventSource,
timeout: Duration
}
impl TransactionWatch {
pub async fn wait_for_transaction_hash(
self,
transaction_hash: &TransactionHash
) -> Result<ExecutionResult, LivenetError> {
log::debug(format!(
"[WATCHER] Starting to monitor for transaction: {}",
transaction_hash
));
let transaction_hash_str = transaction_hash.to_hex_string();
tokio::time::timeout(
self.timeout,
Self::monitor_events_until_found(self.es, &transaction_hash_str)
)
.await
.map_err(|_| {
LivenetError::ExecutionError(String::from(
"Timeout waiting for transaction to be processed."
))
})?
}
async fn monitor_events_until_found(
mut es: EventSource,
transaction_hash: &str
) -> Result<ExecutionResult, LivenetError> {
log::debug("[WATCHER] Monitoring stream for events...");
let mut event_count = 0;
while let Some(event) = es.next().await {
match event {
Ok(Event::Open) => {}
Ok(Event::Message(msg)) => {
event_count += 1;
if let Some(result) = event_matcher::find_result(&msg.data, transaction_hash)? {
log::debug(format!(
"[WATCHER] FOUND transaction in event #{}!",
event_count
));
es.close();
return Ok(result);
}
}
Err(EventSourceError::StreamEnded) => break,
Err(e) => {
return Err(LivenetError::ClientError(format!(
"Error reading event stream: {}",
e
)));
}
}
}
log::debug(format!(
"[WATCHER] Stream ended after {} events, transaction not found",
event_count
));
Err(LivenetError::ClientError(
"Stream ended, transaction not found.".to_string()
))
}
}