risq 0.4.1

Re-implementation of Bisq (https://github.com/bisq-network/bisq) in rust
mod hloc;
#[cfg(feature = "statistics")]
pub mod interval;
mod ticker;
mod trade;
mod volume;

pub use hloc::*;
pub use ticker::Ticker;
pub use trade::Trade;
pub use volume::Volume;

#[cfg(feature = "statistics")]
pub use inner::*;
#[cfg(feature = "statistics")]
mod inner {
    use super::{interval::Interval, trade::TradeHistory, *};
    use crate::{
        domain::{
            market::Market,
            offer::{OfferId, OpenOffer},
            CommandResult, FutureCommandResult,
        },
        prelude::*,
    };
    use std::{collections::HashSet, sync::Arc};

    pub struct StatsCacheInner {
        trades: TradeHistory,
        ids: HashSet<OfferId>,
    }
    impl StatsCacheInner {
        fn insert(&mut self, trade: Trade) -> CommandResult {
            if self.ids.insert(trade.offer_id.clone()) {
                self.trades.insert(trade);
                CommandResult::Accepted
            } else {
                CommandResult::Ignored
            }
        }
        fn bootstrap(&mut self, trades: Vec<Trade>) {
            let mut ids = self.ids.clone();
            self.trades.insert_all(
                trades
                    .into_iter()
                    .filter(|t| ids.insert(t.offer_id.clone())),
            );
            self.ids = ids;
        }
        pub fn trades(&self) -> impl DoubleEndedIterator<Item = &Trade> {
            self.trades.iter()
        }
        pub fn hloc(&self, query: HlocQuery) -> Vec<Hloc> {
            Hloc::from_trades(&self.trades, query)
        }
        pub fn ticker<'a>(
            &self,
            market: Option<&'static Market>,
            offers: impl Iterator<Item = &'a OpenOffer>,
        ) -> Vec<Ticker> {
            Ticker::from_trades(&self.trades, market, offers)
        }
        pub fn volumes(
            &self,
            market: Option<&'static Market>,
            interval: Option<Interval>,
        ) -> Vec<Volume> {
            Volume::from_trades(&self.trades, market, interval)
        }
    }

    #[derive(Clone)]
    pub struct StatsCache {
        inner: Arc<locks::RwLock<StatsCacheInner>>,
    }
    impl StatsCache {
        pub fn new() -> Option<Self> {
            Some(Self {
                inner: Arc::new(locks::RwLock::new(StatsCacheInner {
                    trades: TradeHistory::new(),
                    ids: HashSet::new(),
                })),
            })
        }

        pub fn add(&self, trade: Trade) -> impl FutureCommandResult {
            self.inner
                .write()
                .map(move |mut inner| inner.insert(trade))
                .map_err(|_| MailboxError::Closed)
        }
        pub fn bootstrap(&self, trades: Vec<Trade>) -> impl Future<Item = (), Error = ()> {
            self.inner
                .write()
                .map(move |mut inner| {
                    inner.bootstrap(trades);
                })
                .then(|_| Ok(()))
        }

        pub fn inner(
            &self,
        ) -> impl Future<Item = locks::RwLockReadGuard<StatsCacheInner>, Error = ()> {
            self.inner.read()
        }
    }
}

#[cfg(not(feature = "statistics"))]
pub use empty::*;
#[cfg(not(feature = "statistics"))]
mod empty {
    #[derive(Clone)]
    pub struct StatsCache;
    impl StatsCache {
        pub fn new() -> Option<Self> {
            None
        }
    }
}