From 4d5b5c26f7c4b45434448d9ff8eb5d02c5737665 Mon Sep 17 00:00:00 2001 From: Lars Wirzenius Date: Mon, 9 Nov 2020 10:47:05 +0200 Subject: fetch gen sqlite file when restoring --- src/bin/obnam-restore.rs | 90 ++++++++---------------------------------------- src/client.rs | 36 +++++++++++++++++++ 2 files changed, 51 insertions(+), 75 deletions(-) (limited to 'src') diff --git a/src/bin/obnam-restore.rs b/src/bin/obnam-restore.rs index 2014ef8..21cc096 100644 --- a/src/bin/obnam-restore.rs +++ b/src/bin/obnam-restore.rs @@ -1,23 +1,12 @@ -// Fetch a backup generation's chunks, write to stdout. - -use log::{debug, info, trace}; -use obnam::chunk::{DataChunk, GenerationChunk}; -use obnam::chunkid::ChunkId; +use log::{debug, info}; +use obnam::client::BackupClient; //use obnam::chunkmeta::ChunkMeta; use serde::Deserialize; -use std::io::{stdout, Write}; +use std::fs::File; +use std::io::prelude::*; use std::path::{Path, PathBuf}; use structopt::StructOpt; -#[derive(Debug, thiserror::Error)] -enum ClientError { - #[error("Server does not have generation {0}")] - GenerationNotFound(String), - - #[error("Server does not have chunk {0}")] - ChunkNotFound(String), -} - #[derive(Debug, StructOpt)] #[structopt(name = "obnam-backup", about = "Simplistic backup client")] struct Opt { @@ -26,6 +15,9 @@ struct Opt { #[structopt()] gen_id: String, + + #[structopt(parse(from_os_str))] + dbname: PathBuf, } fn main() -> anyhow::Result<()> { @@ -38,17 +30,15 @@ fn main() -> anyhow::Result<()> { info!("opt: {:?}", opt); info!("config: {:?}", config); - let client = reqwest::blocking::Client::builder() - .danger_accept_invalid_certs(true) - .build()?; - let mut stdout = stdout(); - - let gen = fetch_generation(&client, &config, &opt.gen_id)?; + let client = BackupClient::new(&config.server_name, config.server_port)?; + let gen = client.fetch_generation(&opt.gen_id)?; debug!("gen: {:?}", gen); - for id in gen.chunk_ids() { - let chunk = fetch_chunk(&client, &config, id)?; - debug!("got chunk: {}", id); - stdout.write_all(chunk.data())?; + { + let mut dbfile = File::create(&opt.dbname)?; + for id in gen.chunk_ids() { + let chunk = client.fetch_chunk(id)?; + dbfile.write_all(chunk.data())?; + } } Ok(()) @@ -67,53 +57,3 @@ impl Config { Ok(config) } } - -fn fetch_generation( - client: &reqwest::blocking::Client, - config: &Config, - gen_id: &str, -) -> anyhow::Result { - let url = format!( - "http://{}:{}/chunks/{}", - config.server_name, config.server_port, gen_id, - ); - - trace!("fetch_generation: url={:?}", url); - let req = client.get(&url).build()?; - - let res = client.execute(req)?; - debug!("fetch_generation: status={}", res.status()); - if res.status() != 200 { - debug!("fetch_generation: error from server"); - return Err(ClientError::GenerationNotFound(gen_id.to_string()).into()); - } - - let text = res.text()?; - debug!("fetch_generation: text={:?}", text); - let gen = serde_json::from_str(&text)?; - Ok(gen) -} - -fn fetch_chunk( - client: &reqwest::blocking::Client, - config: &Config, - chunk_id: &ChunkId, -) -> anyhow::Result { - let url = format!( - "http://{}:{}/chunks/{}", - config.server_name, config.server_port, chunk_id, - ); - - trace!("fetch_chunk: url={:?}", url); - let req = client.get(&url).build()?; - - let res = client.execute(req)?; - debug!("fetch_chunk: status={}", res.status()); - if res.status() != 200 { - debug!("fetch_chunk: error from server"); - return Err(ClientError::ChunkNotFound(chunk_id.to_string()).into()); - } - - let body = res.bytes()?; - Ok(DataChunk::new(body.to_vec())) -} diff --git a/src/client.rs b/src/client.rs index 24d961a..ecfc42c 100644 --- a/src/client.rs +++ b/src/client.rs @@ -32,6 +32,12 @@ impl ClientConfig { pub enum ClientError { #[error("Server successful response to creating chunk lacked chunk id")] NoCreatedChunkId, + + #[error("Server does not have chunk {0}")] + ChunkNotFound(String), + + #[error("Server does not have generation {0}")] + GenerationNotFound(String), } pub struct BackupClient { @@ -178,4 +184,34 @@ impl BackupClient { debug!("list_generations: map={:?}", map); Ok(map.keys().into_iter().map(|key| key.into()).collect()) } + + pub fn fetch_chunk(&self, chunk_id: &ChunkId) -> anyhow::Result { + let url = format!("{}/{}", self.base_url(), chunk_id); + trace!("fetch_chunk: url={:?}", url); + let req = self.client.get(&url).build()?; + let res = self.client.execute(req)?; + debug!("fetch_chunk: status={}", res.status()); + if res.status() != 200 { + return Err(ClientError::ChunkNotFound(chunk_id.to_string()).into()); + } + + let body = res.bytes()?; + Ok(DataChunk::new(body.to_vec())) + } + + pub fn fetch_generation(&self, gen_id: &str) -> anyhow::Result { + let url = format!("{}/{}", self.base_url(), gen_id); + trace!("fetch_generation: url={:?}", url); + let req = self.client.get(&url).build()?; + let res = self.client.execute(req)?; + debug!("fetch_generation: status={}", res.status()); + if res.status() != 200 { + return Err(ClientError::GenerationNotFound(gen_id.to_string()).into()); + } + + let text = res.text()?; + debug!("fetch_generation: text={:?}", text); + let gen = serde_json::from_str(&text)?; + Ok(gen) + } } -- cgit v1.2.1