From 4c94c794ec805cf643826973e4f83826a1231e54 Mon Sep 17 00:00:00 2001 From: Lars Wirzenius Date: Mon, 21 Mar 2022 12:01:40 +0200 Subject: fix: old typo in doc comment Sponsored-by: author --- src/client.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'src/client.rs') diff --git a/src/client.rs b/src/client.rs index b58f89c..c4fbfec 100644 --- a/src/client.rs +++ b/src/client.rs @@ -147,7 +147,7 @@ impl BackupClient { Ok(has) } - /// Upload a data chunk to the srver. + /// Upload a data chunk to the server. pub async fn upload_chunk(&self, chunk: DataChunk) -> Result { let enc = self.cipher.encrypt_chunk(&chunk)?; let res = self -- cgit v1.2.1 From 48139725676fcce89a70897546969623f2474693 Mon Sep 17 00:00:00 2001 From: Lars Wirzenius Date: Mon, 21 Mar 2022 09:12:49 +0200 Subject: feat! store list of generations in a "client trust root" chunk Backups made with this version can't be restored with old clients, and vice version. Sponsored-by: author --- src/client.rs | 52 ++++++++++++++++++++++++++++++++++++++++++---------- 1 file changed, 42 insertions(+), 10 deletions(-) (limited to 'src/client.rs') diff --git a/src/client.rs b/src/client.rs index c4fbfec..5b13cb7 100644 --- a/src/client.rs +++ b/src/client.rs @@ -1,6 +1,8 @@ //! Client to the Obnam server HTTP API. -use crate::chunk::{DataChunk, GenerationChunk, GenerationChunkError}; +use crate::chunk::{ + ClientTrust, ClientTrustError, DataChunk, GenerationChunk, GenerationChunkError, +}; use crate::chunkid::ChunkId; use crate::chunkmeta::ChunkMeta; use crate::cipher::{CipherEngine, CipherError}; @@ -54,6 +56,10 @@ pub enum ClientError { #[error(transparent)] GenerationChunkError(#[from] GenerationChunkError), + /// An error regarding client trust. + #[error(transparent)] + ClientTrust(#[from] ClientTrustError), + /// An error using a backup's local metadata. #[error(transparent)] LocalGenerationError(#[from] LocalGenerationError), @@ -170,18 +176,44 @@ impl BackupClient { Ok(chunk_id) } - /// List backup generations known by the server. - pub async fn list_generations(&self) -> Result { - let (_, body) = self.get("", &[("generation", "true")]).await?; + /// Get current client trust chunk from repository, if there is one. + pub async fn get_client_trust(&self) -> Result, ClientError> { + let ids = self.find_client_trusts().await?; + let mut latest: Option = None; + for id in ids { + let chunk = self.fetch_chunk(&id).await?; + let new = ClientTrust::from_data_chunk(&chunk)?; + if let Some(t) = &latest { + if new.timestamp() > t.timestamp() { + latest = Some(new); + } + } else { + latest = Some(new); + } + } + Ok(latest) + } + + async fn find_client_trusts(&self) -> Result, ClientError> { + let body = match self.get("", &[("label", "client-trust")]).await { + Ok((_, body)) => body, + Err(err) => return Err(err), + }; - let map: HashMap = - serde_yaml::from_slice(&body).map_err(ClientError::YamlParse)?; - debug!("list_generations: map={:?}", map); - let finished = map + let hits: HashMap = + serde_json::from_slice(&body).map_err(ClientError::JsonParse)?; + let ids = hits.iter().map(|(id, _)| id.into()).collect(); + Ok(ids) + } + + /// List backup generations known by the server. + pub fn list_generations(&self, trust: &ClientTrust) -> GenerationList { + let finished = trust + .backups() .iter() - .map(|(id, meta)| FinishedGeneration::new(id, meta.ended().map_or("", |s| s))) + .map(|id| FinishedGeneration::new(&format!("{}", id), "")) .collect(); - Ok(GenerationList::new(finished)) + GenerationList::new(finished) } /// Fetch a data chunk from the server, given the chunk identifier. -- cgit v1.2.1