1
//! This module provides the root object of the object graph of a repository.
2
//!
3
//! The manifest contains a list of all the archives in the repository, as well
4
//! default chunk settings, and a time stamp for preventing replay attacks.
5
//!
6
//! All operations on a manifest require a reference to the repository for context.
7
//! The repository is not encapsulated in the manifest because the manifest needs
8
//! to be triviallly serializeable and deserilazeable.
9
pub mod archive;
10
pub mod driver;
11
pub mod target;
12

13
pub use self::archive::{ActiveArchive, StoredArchive};
14
use crate::repository::backend::Manifest as BackendManifest;
15
use crate::repository::backend::Result;
16
use crate::repository::{Backend, BackendClone, ChunkSettings, Repository};
17

18
use chrono::prelude::*;
19
use serde::{Deserialize, Serialize};
20

21
/// Repository manifest
22
///
23
/// This is the root object of the repository, all objects that are active can
24
/// be reached through the Mainfest.
25
#[derive(Serialize, Deserialize, Clone, Debug)]
26
pub struct Manifest<T: Backend> {
27
    internal_manifest: T::Manifest,
28
}
29

30
impl<T: BackendClone> Manifest<T> {
31
    /// Loads the manifest from the repository
32
    ///
33
    /// # Panics
34
    ///
35
    /// Will panic if loading the manifest fails
36 1
    pub fn load(repo: &Repository<T>) -> Manifest<T>
37
    where
38
        T: Backend,
39
    {
40 1
        let internal_manifest = repo.backend_manifest();
41
        Manifest { internal_manifest }
42
    }
43

44
    /// Set the Chunk Settings used by the repository
45 1
    pub async fn set_chunk_settings(&mut self, settings: ChunkSettings) -> Result<()> {
46 1
        self.internal_manifest.write_chunk_settings(settings).await
47
    }
48

49
    /// Gets the default Chunk Settings for the repository
50 1
    pub async fn chunk_settings(&mut self) -> ChunkSettings {
51 1
        self.internal_manifest.chunk_settings().await
52
    }
53

54
    /// Commits an archive to the manifest, then the manifest to the repository
55
    ///
56
    /// Consumes the repository while commiting it.
57
    ///
58
    /// # Panics
59
    ///
60
    /// Will panic if commiting the archive to the repository fails
61 1
    pub async fn commit_archive(
62
        &mut self,
63
        repo: &mut Repository<impl BackendClone>,
64
        archive: ActiveArchive,
65
    ) -> Result<()> {
66 1
        let stored_archive = archive.store(repo).await;
67 1
        self.internal_manifest.write_archive(stored_archive).await?;
68 1
        repo.commit_index().await;
69 1
        Ok(())
70
    }
71

72
    /// Returns a copy of the list of archives in this repository
73
    ///
74
    /// Theses can be converted into full archives with `StoredArchive::load`
75 1
    pub async fn archives(&mut self) -> Vec<StoredArchive> {
76 1
        self.internal_manifest.archive_iterator().await.collect()
77
    }
78

79
    /// Provides the timestamp of the manifest's last modification
80 1
    pub async fn timestamp(&mut self) -> Result<DateTime<FixedOffset>> {
81 1
        self.internal_manifest.last_modification().await
82
    }
83
}
84

85
#[cfg(test)]
86
mod tests {
87
    use super::*;
88
    use crate::repository::*;
89

90
    #[test]
91
    fn chunk_settings_sanity() {
92
        smol::block_on(async {
93
            let settings = ChunkSettings {
94
                encryption: Encryption::NoEncryption,
95
                compression: Compression::NoCompression,
96
                hmac: HMAC::Blake2b,
97
            };
98

99
            let key = Key::random(32);
100
            let backend = crate::repository::backend::mem::Mem::new(settings, key.clone(), 4);
101
            let repo = Repository::with(backend, settings, key, 2);
102
            let mut manifest = Manifest::load(&repo);
103

104
            manifest.set_chunk_settings(settings).await.unwrap();
105
            let new_settings = manifest.chunk_settings().await;
106

107
            assert_eq!(settings, new_settings);
108
        });
109
    }
110

111
    #[test]
112
    fn new_archive_updates_time() {
113
        smol::block_on(async {
114
            let settings = ChunkSettings::lightweight();
115
            let key = Key::random(32);
116
            let backend = crate::repository::backend::mem::Mem::new(settings, key.clone(), 4);
117
            let repo = Repository::with(backend.clone(), settings, key, 2);
118

119
            let mut manifest = Manifest::load(&repo);
120

121
            let dummy1 = StoredArchive::dummy_archive();
122
            backend.get_manifest().write_archive(dummy1).await.unwrap();
123
            let time1 = manifest.timestamp().await.unwrap();
124
            std::thread::sleep(std::time::Duration::from_millis(10));
125
            let dummy2 = StoredArchive::dummy_archive();
126
            backend.get_manifest().write_archive(dummy2).await.unwrap();
127
            let time2 = manifest.timestamp().await.unwrap();
128

129
            assert!(time2 > time1);
130
        });
131
    }
132
}

Read our documentation on viewing source code .

Loading