use async_trait::async_trait;
use std::sync::Arc;
use std::time::{Duration, Instant};
use thruput_json_rpc_types::{BlockHeight, block::ChainTip, transaction::TxHash};
use thruput_xdr::network_config::NetworkConfig;
use crate::error::RpcServerError;
#[derive(Debug, Clone, Copy)]
pub struct RpcRequestContext {
started_at: Instant,
deadline: Option<Instant>,
}
impl RpcRequestContext {
pub fn new(timeout: Option<Duration>) -> Self {
let started_at = Instant::now();
Self {
started_at,
deadline: timeout.and_then(|timeout| started_at.checked_add(timeout)),
}
}
pub fn unbounded() -> Self {
Self::new(None)
}
pub fn started_at(self) -> Instant {
self.started_at
}
pub fn deadline(self) -> Option<Instant> {
self.deadline
}
pub fn remaining(self) -> Option<Duration> {
self.deadline
.map(|deadline| deadline.saturating_duration_since(Instant::now()))
}
#[must_use]
pub fn capped(self, timeout: Duration) -> Self {
let cap = Instant::now().checked_add(timeout);
self.with_cap(cap)
}
#[must_use]
pub fn capped_from_start(self, timeout: Duration) -> Self {
let cap = self.started_at.checked_add(timeout);
self.with_cap(cap)
}
fn with_cap(self, cap: Option<Instant>) -> Self {
Self {
started_at: self.started_at,
deadline: match (self.deadline, cap) {
(Some(request), Some(cap)) => Some(request.min(cap)),
(Some(request), None) => Some(request),
(None, cap) => cap,
},
}
}
}
#[derive(Debug, Clone)]
#[non_exhaustive]
pub struct ValidatedTransaction {
pub bytes: Vec<u8>,
pub hash: TxHash,
pub block_expiry_height: BlockHeight,
}
#[derive(Debug, Clone)]
#[non_exhaustive]
pub struct TipReading {
pub tip: ChainTip,
pub network_config: NetworkConfig,
pub execution: Option<Arc<thruput_json_rpc_types::network_config::ExecutionConfig>>,
}
impl TipReading {
pub fn new(tip: ChainTip, network_config: NetworkConfig) -> Self {
Self {
tip,
network_config,
execution: None,
}
}
#[must_use]
pub fn with_execution(
mut self,
execution: impl Into<Arc<thruput_json_rpc_types::network_config::ExecutionConfig>>,
) -> Self {
self.execution = Some(execution.into());
self
}
}
#[async_trait]
pub trait ChainPlane: Send + Sync + 'static {
async fn chain_tip(&self, context: RpcRequestContext) -> Result<TipReading, RpcServerError>;
async fn pending_transaction_count(
&self,
context: RpcRequestContext,
) -> Result<u64, RpcServerError>;
}