summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorLars Wirzenius <liw@liw.fi>2021-05-23 11:40:24 +0300
committerLars Wirzenius <liw@liw.fi>2021-05-29 11:41:15 +0300
commit566dd94d2e46c489b50d84a1fd24683460e5cfdc (patch)
tree880260f2815e385d33bbc6e049df5573556113f5
parent94c8021f00fb299e799af68ce0d26be4a659d5d1 (diff)
downloadobnam2-566dd94d2e46c489b50d84a1fd24683460e5cfdc.tar.gz
refactor: split bare chunk server client into its own struct
This makes the code doing HTTP requests simpler for easier comprehension and debugging.
-rw-r--r--src/client.rs155
1 files changed, 84 insertions, 71 deletions
diff --git a/src/client.rs b/src/client.rs
index 0f8a72f..114574c 100644
--- a/src/client.rs
+++ b/src/client.rs
@@ -74,21 +74,14 @@ pub enum ClientError {
pub type ClientResult<T> = Result<T, ClientError>;
pub struct BackupClient {
- client: Client,
- base_url: String,
+ chunk_client: ChunkClient,
}
impl BackupClient {
pub fn new(config: &ClientConfig) -> ClientResult<Self> {
info!("creating backup client with config: {:#?}", config);
- let config = config.config();
- let client = Client::builder()
- .danger_accept_invalid_certs(!config.verify_tls_cert)
- .build()
- .map_err(ClientError::ReqwestError)?;
Ok(Self {
- client,
- base_url: config.server_url.to_string(),
+ chunk_client: ChunkClient::new(config)?,
})
}
@@ -130,6 +123,88 @@ impl BackupClient {
Ok(chunk_ids)
}
+ pub fn has_chunk(&self, meta: &ChunkMeta) -> ClientResult<Option<ChunkId>> {
+ self.chunk_client.has_chunk(meta)
+ }
+
+ pub fn upload_chunk(&self, meta: ChunkMeta, chunk: DataChunk) -> ClientResult<ChunkId> {
+ self.chunk_client.upload_chunk(meta, chunk)
+ }
+
+ pub fn upload_gen_chunk(&self, meta: ChunkMeta, gen: GenerationChunk) -> ClientResult<ChunkId> {
+ let data = gen.to_data_chunk()?;
+ self.upload_chunk(meta, data)
+ }
+
+ pub fn upload_new_file_chunks(&self, chunker: Chunker) -> ClientResult<Vec<ChunkId>> {
+ let mut chunk_ids = vec![];
+ for item in chunker {
+ let (meta, chunk) = item?;
+ if let Some(chunk_id) = self.has_chunk(&meta)? {
+ chunk_ids.push(chunk_id.clone());
+ info!("reusing existing chunk {}", chunk_id);
+ } else {
+ let chunk_id = self.upload_chunk(meta, chunk)?;
+ chunk_ids.push(chunk_id.clone());
+ info!("created new chunk {}", chunk_id);
+ }
+ }
+
+ Ok(chunk_ids)
+ }
+
+ pub fn list_generations(&self) -> ClientResult<GenerationList> {
+ self.chunk_client.list_generations()
+ }
+
+ pub fn fetch_chunk(&self, chunk_id: &ChunkId) -> ClientResult<DataChunk> {
+ self.chunk_client.fetch_chunk(chunk_id)
+ }
+
+ fn fetch_generation_chunk(&self, gen_id: &str) -> ClientResult<GenerationChunk> {
+ let chunk_id = ChunkId::recreate(gen_id);
+ let chunk = self.fetch_chunk(&chunk_id)?;
+ let gen = GenerationChunk::from_data_chunk(&chunk)?;
+ Ok(gen)
+ }
+
+ pub fn fetch_generation(&self, gen_id: &str, dbname: &Path) -> ClientResult<LocalGeneration> {
+ let gen = self.fetch_generation_chunk(gen_id)?;
+
+ // Fetch the SQLite file, storing it in the named file.
+ let mut dbfile = File::create(&dbname)
+ .map_err(|err| ClientError::FileCreate(dbname.to_path_buf(), err))?;
+ for id in gen.chunk_ids() {
+ let chunk = self.fetch_chunk(id)?;
+ dbfile
+ .write_all(chunk.data())
+ .map_err(|err| ClientError::FileWrite(dbname.to_path_buf(), err))?;
+ }
+ info!("downloaded generation to {}", dbname.display());
+
+ let gen = LocalGeneration::open(dbname)?;
+ Ok(gen)
+ }
+}
+
+pub struct ChunkClient {
+ client: Client,
+ base_url: String,
+}
+
+impl ChunkClient {
+ pub fn new(config: &ClientConfig) -> ClientResult<Self> {
+ let config = config.config();
+ let client = Client::builder()
+ .danger_accept_invalid_certs(!config.verify_tls_cert)
+ .build()
+ .map_err(ClientError::ReqwestError)?;
+ Ok(Self {
+ client,
+ base_url: config.server_url.to_string(),
+ })
+ }
+
fn base_url(&self) -> &str {
&self.base_url
}
@@ -191,43 +266,6 @@ impl BackupClient {
Ok(chunk_id)
}
- pub fn upload_gen_chunk(&self, meta: ChunkMeta, gen: GenerationChunk) -> ClientResult<ChunkId> {
- let res = self
- .client
- .post(&self.chunks_url())
- .header("chunk-meta", meta.to_json())
- .body(serde_json::to_string(&gen).map_err(ClientError::JsonGenerate)?)
- .send()
- .map_err(ClientError::ReqwestError)?;
- debug!("upload_chunk: res={:?}", res);
- let res: HashMap<String, String> = res.json().map_err(ClientError::ReqwestError)?;
- let chunk_id = if let Some(chunk_id) = res.get("chunk_id") {
- debug!("upload_chunk: id={}", chunk_id);
- chunk_id.parse().unwrap()
- } else {
- return Err(ClientError::NoCreatedChunkId);
- };
- info!("uploaded_generation chunk {}", chunk_id);
- Ok(chunk_id)
- }
-
- pub fn upload_new_file_chunks(&self, chunker: Chunker) -> ClientResult<Vec<ChunkId>> {
- let mut chunk_ids = vec![];
- for item in chunker {
- let (meta, chunk) = item?;
- if let Some(chunk_id) = self.has_chunk(&meta)? {
- chunk_ids.push(chunk_id.clone());
- info!("reusing existing chunk {}", chunk_id);
- } else {
- let chunk_id = self.upload_chunk(meta, chunk)?;
- chunk_ids.push(chunk_id.clone());
- info!("created new chunk {}", chunk_id);
- }
- }
-
- Ok(chunk_ids)
- }
-
pub fn list_generations(&self) -> ClientResult<GenerationList> {
let url = format!("{}?generation=true", &self.chunks_url());
trace!("list_generations: url={:?}", url);
@@ -301,31 +339,6 @@ impl BackupClient {
Ok(chunk)
}
-
- fn fetch_generation_chunk(&self, gen_id: &str) -> ClientResult<GenerationChunk> {
- let chunk_id = ChunkId::recreate(gen_id);
- let chunk = self.fetch_chunk(&chunk_id)?;
- let gen = GenerationChunk::from_data_chunk(&chunk)?;
- Ok(gen)
- }
-
- pub fn fetch_generation(&self, gen_id: &str, dbname: &Path) -> ClientResult<LocalGeneration> {
- let gen = self.fetch_generation_chunk(gen_id)?;
-
- // Fetch the SQLite file, storing it in the named file.
- let mut dbfile = File::create(&dbname)
- .map_err(|err| ClientError::FileCreate(dbname.to_path_buf(), err))?;
- for id in gen.chunk_ids() {
- let chunk = self.fetch_chunk(id)?;
- dbfile
- .write_all(chunk.data())
- .map_err(|err| ClientError::FileWrite(dbname.to_path_buf(), err))?;
- }
- info!("downloaded generation to {}", dbname.display());
-
- let gen = LocalGeneration::open(dbname)?;
- Ok(gen)
- }
}
fn current_timestamp() -> String {