1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
use std::{
    path::{Path, PathBuf},
    sync::Arc,
};

use crate::{
    digesters::ImmutableDigester,
    entities::{CardanoDbBeacon, ProtocolMessage, ProtocolMessagePartKey},
    logging::LoggerExtensions,
    signable_builder::SignableBuilder,
    StdResult,
};
use anyhow::Context;
use async_trait::async_trait;
use slog::{info, Logger};

/// This structure is responsible for calculating the message for Cardano immutable files snapshots.
pub struct CardanoImmutableFilesFullSignableBuilder {
    immutable_digester: Arc<dyn ImmutableDigester>,
    logger: Logger,
    dirpath: PathBuf,
}

impl CardanoImmutableFilesFullSignableBuilder {
    /// Constructor
    pub fn new(
        immutable_digester: Arc<dyn ImmutableDigester>,
        dirpath: &Path,
        logger: Logger,
    ) -> Self {
        Self {
            immutable_digester,
            logger: logger.new_with_component_name::<Self>(),
            dirpath: dirpath.to_owned(),
        }
    }
}

#[async_trait]
impl SignableBuilder<CardanoDbBeacon> for CardanoImmutableFilesFullSignableBuilder {
    async fn compute_protocol_message(
        &self,
        beacon: CardanoDbBeacon,
    ) -> StdResult<ProtocolMessage> {
        let digest = self
            .immutable_digester
            .compute_digest(&self.dirpath, &beacon)
            .await
            .with_context(|| {
                format!(
                    "Cardano Immutable Files Full Signable Builder can not compute digest of '{}'",
                    &self.dirpath.display()
                )
            })?;
        info!(self.logger, "Computed Digest = '{digest}'.");
        let mut protocol_message = ProtocolMessage::new();
        protocol_message.set_message_part(ProtocolMessagePartKey::SnapshotDigest, digest);

        Ok(protocol_message)
    }
}

#[cfg(test)]
mod tests {
    use async_trait::async_trait;
    use std::path::Path;

    use crate::digesters::{ImmutableDigester, ImmutableDigesterError};
    use crate::entities::CardanoDbBeacon;
    use crate::test_utils::TestLogger;

    use super::*;

    #[derive(Default)]
    pub struct ImmutableDigesterImpl;

    #[async_trait]
    impl ImmutableDigester for ImmutableDigesterImpl {
        async fn compute_digest(
            &self,
            _dirpath: &Path,
            beacon: &CardanoDbBeacon,
        ) -> Result<String, ImmutableDigesterError> {
            Ok(format!("immutable {}", beacon.immutable_file_number))
        }
    }

    #[tokio::test]
    async fn compute_signable() {
        let digester = ImmutableDigesterImpl;
        let signable_builder = CardanoImmutableFilesFullSignableBuilder::new(
            Arc::new(digester),
            Path::new(""),
            TestLogger::stdout(),
        );
        let protocol_message = signable_builder
            .compute_protocol_message(CardanoDbBeacon::default())
            .await
            .unwrap();

        assert_eq!(
            &"immutable 0".to_string(),
            protocol_message
                .get_message_part(&ProtocolMessagePartKey::SnapshotDigest)
                .unwrap()
        );
    }
}