//! This module provides the root object of the object graph of a repository.
//!
//! The manifest contains a list of all the archives in the repository, as well
//! default chunk settings, and a time stamp for preventing replay attacks.
//!
//! All operations on a manifest require a reference to the repository for context.
//! The repository is not encapsulated in the manifest because the manifest needs
//! to be triviallly serializeable and deserilazeable.
pub mod archive;
pub mod target;
use crate::repository::{Backend, ChunkSettings, Key, Repository};
use chrono::prelude::*;
use rmp_serde::{Deserializer, Serializer};
use serde::{Deserialize, Serialize};
pub use self::archive::{Archive, StoredArchive};
/// Repository manifest
///
/// Has special all zero key
///
/// This is the root object of the repository, all objects that are active can
/// be reached through the Mainfest.
#[derive(Serialize, Deserialize, Clone, Debug)]
pub struct Manifest {
/// Time stamp the manifiest was commited at. This is updated every time commit() is called
///
/// This value is primarly for preventing replay attacks
timestamp: DateTime<FixedOffset>,
/// Default settings for new chunks in this repository
chunk_settings: ChunkSettings,
/// List of archives in the repository,
archives: Vec<StoredArchive>,
}
impl Manifest {
/// Creates a new empty manifest with the given chunk settings
pub fn empty_manifest(settings: ChunkSettings) -> Manifest {
Manifest {
timestamp: Local::now().with_timezone(Local::now().offset()),
chunk_settings: settings,
archives: Vec::new(),
}
}
/// Commits the manifest to the repository
///
/// Will overwrite existing manifest. Will additionally update the
/// timestamp of the mainfest. Commits the index of the repository after it is done
///
/// # Panics
///
/// Will panic if the write to the repository fails
pub fn commit(&mut self, repo: &mut Repository<impl Backend>) {
self.timestamp = Local::now().with_timezone(Local::now().offset());
let mut bytes = Vec::<u8>::new();
self.serialize(&mut Serializer::new(&mut bytes))
.expect("Unable to serialize manifest.");
repo.write_chunk_with_id(bytes, Key::mainfest_key())
.expect("Unable to write manifest");
repo.commit_index();
}
/// Loads the manifest from the repository
///
/// # Panics
///
/// Will panic if loading the manifest fails
pub fn load(repo: &Repository<impl Backend>) -> Manifest {
let bytes = repo
.read_chunk(Key::mainfest_key())
.expect("Unable to read manifest from repo");
let mut de = Deserializer::new(&bytes[..]);
let manifest: Manifest =
Deserialize::deserialize(&mut de).expect("Unable to deserialze Manifest.");
manifest
}
/// Commits an archive to the manifest, then the manifest to the repository
///
/// Consumes the repository while commiting it.
///
/// # Panics
///
/// Will panic if commiting the archive to the repository fails
pub fn commit_archive(&mut self, repo: &mut Repository<impl Backend>, archive: Archive) {
let stored_archive = archive.store(repo);
self.archives.push(stored_archive);
self.commit(repo);
}
/// Returns a copy of the list of archives in this repository
///
/// Theses can be converted into full archives with StoredArchive::load
pub fn archives(&self) -> Vec<StoredArchive> {
self.archives.clone()
}
}