mithril_common/digesters/
immutable_file_observer.rs

1use crate::digesters::ImmutableFile;
2use crate::entities::ImmutableFileNumber;
3use crate::{StdError, StdResult};
4use anyhow::{anyhow, Context};
5use async_trait::async_trait;
6use std::ops::Add;
7use std::path::PathBuf;
8use thiserror::Error;
9use tokio::sync::RwLock;
10
11/// Retrieve data on [ImmutableFile] from a cardano database.
12#[async_trait]
13pub trait ImmutableFileObserver
14where
15    Self: Sync + Send,
16{
17    /// Get the [ImmutableFileNumber] of the last immutable file in the cardano database.
18    async fn get_last_immutable_number(&self) -> StdResult<u64>;
19}
20
21/// [ImmutableFileObserver] related errors.
22#[derive(Error, Debug)]
23pub enum ImmutableFileObserverError {
24    /// Raised when the no immutables files were available.
25    #[error("no immutable file was returned")]
26    Missing(),
27
28    /// Raised when [immutable file listing][ImmutableFile::list_completed_in_dir] fails.
29    #[error("immutable file creation error")]
30    ImmutableFileListing(#[source] StdError),
31}
32
33/// An [ImmutableFileObserver] using the filesystem.
34pub struct ImmutableFileSystemObserver {
35    db_path: PathBuf,
36}
37
38impl ImmutableFileSystemObserver {
39    /// [ImmutableFileSystemObserver] factory.
40    pub fn new(db_path: &PathBuf) -> Self {
41        let db_path = db_path.to_owned();
42
43        Self { db_path }
44    }
45}
46
47#[async_trait]
48impl ImmutableFileObserver for ImmutableFileSystemObserver {
49    async fn get_last_immutable_number(&self) -> StdResult<u64> {
50        let immutable_file_number = ImmutableFile::list_completed_in_dir(&self.db_path)
51            .map_err(|e| anyhow!(e))
52            .with_context(|| "Immutable File System Observer can not list all immutable files")?
53            .into_iter()
54            .next_back()
55            .ok_or(anyhow!(ImmutableFileObserverError::Missing()))?
56            .number;
57
58        Ok(immutable_file_number)
59    }
60}
61
62/// An [ImmutableFileObserver] yielding fixed results for tests purpose.
63pub struct DumbImmutableFileObserver {
64    /// The [ImmutableFileNumber] that shall be returned by
65    /// [get_last_immutable_number][ImmutableFileObserver::get_last_immutable_number]
66    pub shall_return: RwLock<Option<ImmutableFileNumber>>,
67}
68
69impl Default for DumbImmutableFileObserver {
70    fn default() -> Self {
71        let mut observer = Self::new();
72        observer.shall_return = RwLock::new(Some(500));
73
74        observer
75    }
76}
77
78impl DumbImmutableFileObserver {
79    /// [DumbImmutableFileObserver] factory.
80    pub fn new() -> Self {
81        Self {
82            shall_return: RwLock::new(None),
83        }
84    }
85
86    /// Update the stored [immutable file number][DumbImmutableFileObserver::shall_return].
87    pub async fn shall_return(&self, what: Option<u64>) -> &Self {
88        let mut shall_return = self.shall_return.write().await;
89        *shall_return = what;
90        self
91    }
92
93    /// Increase by one the stored [immutable file number][DumbImmutableFileObserver::shall_return],
94    /// return the updated value.
95    pub async fn increase(&self) -> StdResult<u64> {
96        let new_number = self
97            .shall_return
98            .write()
99            .await
100            .ok_or_else(|| anyhow!(ImmutableFileObserverError::Missing()))?
101            .add(1);
102        self.shall_return(Some(new_number)).await;
103
104        Ok(new_number)
105    }
106}
107
108#[async_trait]
109impl ImmutableFileObserver for DumbImmutableFileObserver {
110    async fn get_last_immutable_number(&self) -> StdResult<u64> {
111        self.shall_return
112            .read()
113            .await
114            .ok_or_else(|| anyhow!(ImmutableFileObserverError::Missing()))
115    }
116}
117
118#[cfg(test)]
119mod tests {}