aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authormetamuffin <metamuffin@disroot.org>2024-06-14 03:57:14 +0200
committermetamuffin <metamuffin@disroot.org>2024-06-14 03:57:14 +0200
commite34da6ca957ec813a361cbcaf0dc89e953af6db1 (patch)
tree08f15f33502a961382fcb3aa2933ab5982b7cc36
parent956b172ddbff214d055127fb89905f0057492a26 (diff)
downloadonline-offsite-backup-e34da6ca957ec813a361cbcaf0dc89e953af6db1.tar
online-offsite-backup-e34da6ca957ec813a361cbcaf0dc89e953af6db1.tar.bz2
online-offsite-backup-e34da6ca957ec813a361cbcaf0dc89e953af6db1.tar.zst
list works
-rw-r--r--src/client.rs50
-rw-r--r--src/main.rs45
-rw-r--r--src/server.rs6
3 files changed, 92 insertions, 9 deletions
diff --git a/src/client.rs b/src/client.rs
new file mode 100644
index 0000000..492008a
--- /dev/null
+++ b/src/client.rs
@@ -0,0 +1,50 @@
+use anyhow::{anyhow, bail, Result};
+use std::{
+ io::{BufRead, BufReader, BufWriter, Write},
+ net::{TcpStream, ToSocketAddrs},
+};
+
+use crate::Serial;
+
+pub struct Client {
+ wsock: BufWriter<TcpStream>,
+ rsock: BufReader<TcpStream>,
+}
+impl Client {
+ pub fn new(address: impl ToSocketAddrs, secret: &str) -> Result<Self> {
+ let mut sock = TcpStream::connect(address)?;
+ writeln!(sock, "{secret}")?;
+ Ok(Self {
+ rsock: BufReader::new(sock.try_clone()?),
+ wsock: BufWriter::new(sock),
+ })
+ }
+ pub fn list(&mut self) -> Result<Vec<(i64, u64, Serial)>> {
+ writeln!(self.wsock, "list")?;
+ self.wsock.flush()?;
+ let mut line = String::new();
+ let mut out = Vec::new();
+ loop {
+ self.rsock.read_line(&mut line)?;
+ if line.trim().is_empty() || line.ends_with("\n\n") {
+ break Ok(out);
+ }
+ check_error(&line)?;
+ let (mtime, rest) = line.trim().split_once(":").ok_or(anyhow!("size missing"))?;
+ let (size, serial) = rest.split_once(":").ok_or(anyhow!("serial missing"))?;
+ out.push((mtime.parse()?, size.parse()?, serial.parse()?));
+ }
+ }
+ pub fn quit(mut self) -> Result<()> {
+ writeln!(self.wsock, "quit")?;
+ self.wsock.flush()?;
+ Ok(())
+ }
+}
+
+fn check_error(line: &str) -> Result<()> {
+ if let Some(message) = line.trim().strip_prefix("error") {
+ bail!("server error: {message}")
+ }
+ Ok(())
+}
diff --git a/src/main.rs b/src/main.rs
index 243c621..c72aad7 100644
--- a/src/main.rs
+++ b/src/main.rs
@@ -1,8 +1,10 @@
-#![feature(iterator_try_collect)]
-#![feature(never_type)]
+#![feature(iterator_try_collect, never_type)]
+pub mod client;
pub mod server;
+use anyhow::Result;
use clap::{Parser, Subcommand};
+use client::Client;
use serde::Deserialize;
use server::server;
use std::{fs::read_to_string, net::SocketAddr, path::PathBuf};
@@ -19,8 +21,17 @@ struct Args {
#[derive(Subcommand)]
enum Action {
Daemon,
- Restore { id: String, destination: PathBuf },
- Backup { path: PathBuf },
+ List {
+ peer: Option<String>,
+ },
+ Restore {
+ peer: String,
+ id: String,
+ destination: PathBuf,
+ },
+ Backup {
+ path: PathBuf,
+ },
}
#[derive(Deserialize)]
@@ -53,7 +64,7 @@ pub struct StorageConfig {
download_speed: usize,
}
-fn main() -> anyhow::Result<()> {
+fn main() -> Result<()> {
env_logger::init_from_env("LOG");
let args = Args::parse();
@@ -62,7 +73,29 @@ fn main() -> anyhow::Result<()> {
match args.action {
Action::Daemon => server(config.into())?,
- Action::Restore { id, destination } => todo!(),
+ Action::List { peer } => {
+ let peers = config.peer.iter().filter(|p| {
+ if let Some(pn) = &peer {
+ pn == &p.name
+ } else {
+ true
+ }
+ });
+
+ for p in peers {
+ println!("peer {:?}", p.name);
+ let mut client = Client::new(p.address, &p.shared_secret)?;
+ for (mtime, size, serial) in client.list()? {
+ println!("\tserial={serial} mtime={mtime} size={size}")
+ }
+ client.quit()?;
+ }
+ }
+ Action::Restore {
+ id,
+ destination,
+ peer,
+ } => todo!(),
Action::Backup { path } => todo!(),
}
Ok(())
diff --git a/src/server.rs b/src/server.rs
index 30ed0c8..d24f1b4 100644
--- a/src/server.rs
+++ b/src/server.rs
@@ -24,7 +24,9 @@ pub fn server(config: Arc<Config>) -> anyhow::Result<!> {
let config = config.clone();
spawn(
move || match handle_connection_wrapper(config, sock, addr) {
- Ok(()) => (),
+ Ok(()) => {
+ info!("connection closed gracefully")
+ }
Err(err) => {
warn!("client error {addr}: {err:?}")
}
@@ -60,7 +62,6 @@ fn handle_connection(
rsock.by_ref().take(4096).read_line(&mut line)?;
let provided_secret = line.trim();
- eprintln!("{:?}", provided_secret);
let Some(peer) = config
.peer
.iter()
@@ -77,7 +78,6 @@ fn handle_connection(
rsock.by_ref().take(4096).read_line(&mut line)?;
let mut toks = line.trim().split(",");
let command = toks.next().ok_or(anyhow!("command missing"))?;
- eprintln!("{command:?}");
match command {
"quit" => break Ok(()),
"list" => {