Skip to content

Commit

Permalink
some cleanup
Browse files Browse the repository at this point in the history
  • Loading branch information
tweissin committed Nov 24, 2024
1 parent ff843f5 commit 8d81732
Show file tree
Hide file tree
Showing 5 changed files with 60 additions and 149 deletions.
2 changes: 1 addition & 1 deletion Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

3 changes: 2 additions & 1 deletion Cargo.toml
Original file line number Diff line number Diff line change
@@ -1,7 +1,8 @@
[package]
name = "webdav-sync"
version = "0.1.0"
version = "0.2.0"
edition = "2018"
authors = ["Tom Weissinger"]

[dependencies]
notify = "7.0.0"
Expand Down
73 changes: 26 additions & 47 deletions src/fswatch.rs
Original file line number Diff line number Diff line change
@@ -1,10 +1,8 @@
use std::{io, time::Duration};

use notify::RecursiveMode;
use crate::webdav::WebDav;
use notify_debouncer_full::new_debouncer;

use rustydav::client;
use std::fs;
use notify::RecursiveMode;
use std::sync::mpsc::channel;
use std::time::Duration;

// see https://github.com/notify-rs/notify/blob/main/examples/debouncer_full.rs
pub fn run(
Expand All @@ -13,15 +11,25 @@ pub fn run(
password: &str,
dir_to_watch: &str,
) -> Result<(), notify::Error> {
let client = client::Client::init(username, password);

// setup debouncer
let (tx, rx) = std::sync::mpsc::channel();
let (tx, rx) = channel();

// no specific tickrate, max debounce time 2 seconds
let mut debouncer = new_debouncer(Duration::from_secs(2), None, tx)?;
let mut watcher = new_debouncer(Duration::from_secs(2), None, tx)?;

watcher.watch(dir_to_watch, RecursiveMode::Recursive)?;

let wd = WebDav::new(
String::from(hostname),
String::from(username),
String::from(password),
);

debouncer.watch(dir_to_watch, RecursiveMode::Recursive)?;
println!();
println!("==========================");
println!("Beginning filesystem watch of: {}", dir_to_watch);
println!(" and syncing to: {}", hostname);
println!();

// print all events and errors
for result in rx {
Expand All @@ -30,68 +38,39 @@ pub fn run(
for event in events {
if event.event.kind.is_create() {
let path_clone = event.event.paths[0].clone();
println!("File created: {}", path_clone.display());
upload_to_webdav(&client, hostname, path_clone);
println!("Create: {}", path_clone.display());
wd.write_file(path_clone);
} else if event.event.kind.is_modify() {
if event.event.paths.len() == 1 {
let path_clone = event.event.paths[0].clone();
println!("File modified: {}", path_clone.display());
upload_to_webdav(&client, hostname, path_clone);
println!("Modify: {}", path_clone.display());
wd.write_file(path_clone);
} else {
let src_path = event.event.paths[0].clone();
let dst_path = event.event.paths[1].clone();
println!(
"File renamed from: {} to: {}",
"Rename from: {} to: {}",
src_path.display(),
dst_path.display()
);
// Optionally handle renames
}
} else if event.event.kind.is_remove() {
let path_clone = event.event.paths[0].clone();
println!("File deleted: {}", path_clone.display());
println!("Remove: {}", path_clone.display());
// Optionally handle deletions
}
}
}
Err(errors) => {
// Handle errors
for error in errors {
println!("Error: {:?}", error);
println!("watch error: {:?}", error);
}
}
}
println!();
}
Ok(())
}

fn upload_to_webdav(client: &client::Client, hostname: &str, path: std::path::PathBuf) {
match load_file_to_bytes(&path) {
Ok(file_content) => {
// Generate the remote path
let remote_path = format!(
"http://{}/{}",
hostname,
path.file_name().unwrap().to_string_lossy()
);
println!("Uploading to: {}", remote_path);

// Upload the file
// (&self, body: B, path: &str)
match client.put(file_content, &remote_path) {
Ok(_) => println!("Uploaded: {}", remote_path),
Err(e) => eprintln!("Failed to upload {}: {:?}", remote_path, e),
}
}
Err(e) => {
eprintln!("Failed to load file: {}", e);
}
}
}

fn load_file_to_bytes(path: &std::path::PathBuf) -> io::Result<Vec<u8>> {
let error = format!("Unable to read file {}", path.display());
let buffer = fs::read(path).expect(&error);
Ok(buffer)
}
3 changes: 2 additions & 1 deletion src/main.rs
Original file line number Diff line number Diff line change
@@ -1,10 +1,11 @@
use clap::Parser;
mod fswatch;
mod webdav;
use std::{env, io::Result};

/// Filesystem watcher that syncs with WebDav
#[derive(Parser, Debug)]
#[command(version, about, long_about = None)]
#[command(version, author = env!("CARGO_PKG_AUTHORS"))]
struct Args {
/// WebDav username
#[arg(short, long, default_value_t=get_default_from_env("WEBDAV_USERNAME"))]
Expand Down
128 changes: 29 additions & 99 deletions src/webdav.rs
Original file line number Diff line number Diff line change
@@ -1,125 +1,55 @@
use hyperdav::Client;
use rustydav::client;
use std::fs;
use std::fs::File;
use std::io;
use std::io::BufReader;
use std::path::PathBuf;
use std::thread;
use std::time::Instant;

pub struct WebDav {
client: Client,
dir_to_watch: PathBuf,
client: rustydav::client::Client,
hostname: String,
}

impl WebDav {
pub fn new(host: String, username: String, password: String, dir_to_watch: String) -> WebDav {
pub fn new(host: String, username: String, password: String) -> WebDav {
WebDav {
client: Client::new()
.credentials(username, password)
.build(&host)
.unwrap(),
dir_to_watch: PathBuf::from(dir_to_watch),
client: client::Client::init(&username, &password),
hostname: host,
}
}
pub fn write_file(&self, path_buf: PathBuf) -> io::Result<()> {
let f = File::open(&path_buf)?;
let reader = BufReader::new(f);

let mut path_vec: Vec<String> = vec![];
let is_file = path_buf.is_file();
make_path_vec(&self.dir_to_watch, &path_buf, &mut path_vec);

if is_file {
let path_and_file_vec = path_vec.clone();
if path_vec.len() > 0 {
path_vec.pop();
self.mkdir(path_vec);
pub fn write_file(&self, path_buf: PathBuf) {
match Self::load_file_to_bytes(&path_buf) {
Ok(file_content) => {
// Generate the remote path
let remote_path = format!(
"http://{}/{}",
self.hostname,
path_buf.file_name().unwrap().to_string_lossy()
);
println!("Uploading to: {}", remote_path);

// Upload the file
// (&self, body: B, path: &str)
match self.client.put(file_content, &remote_path) {
Ok(_) => println!("Uploaded: {}", remote_path),
Err(e) => eprintln!("Failed to upload {}: {:?}", remote_path, e),
}
}
let size: u64 = fs::metadata(&path_buf)?.len();
let now = Instant::now();

// put the file!
self.put_file(path_and_file_vec, reader);

let duration = now.elapsed();
let kbps = (size as u128 / duration.as_millis()) as f64 / 1000.0;
println!(
"{:?} elapsed {} ms, {} Kbps, {} bytes",
thread::current().id(),
duration.as_millis(),
kbps,
size
);
Ok(())
} else {
self.mkdir(path_vec);
Ok(())
}
}

fn put_file(&self, path_and_file_vec: Vec<String>, reader: BufReader<File>) {
let pathstr = path_and_file_vec.join("/");
println!("{:?} WebDav: write '{}'", thread::current().id(), pathstr);
match self.client.put(reader, path_and_file_vec) {
Err(err) => {
println!("problem writing file {}", err);
Err(e) => {
eprintln!("Failed to load file: {}", e);
}
_ => (),
}
}

fn mkdir(&self, path_vec: Vec<String>) {
let pathstr = path_vec.join("/");
if pathstr.len() == 0 {
// nothing to do
return;
}
println!("{:?} WebDav: mkdir '{}'", thread::current().id(), pathstr);

match self.client.mkcol(&path_vec) {
Err(err) => {
println!("problem making directory '{}' {}", pathstr, err);
}
_ => (),
}
fn load_file_to_bytes(path: &std::path::PathBuf) -> io::Result<Vec<u8>> {
let error = format!("Unable to read file {}", path.display());
let buffer = fs::read(path).expect(&error);
Ok(buffer)
}
}

fn make_path_vec(dir_to_watch: &PathBuf, incoming_path: &PathBuf, path_vec: &mut Vec<String>) {
let mut iter1 = dir_to_watch.iter();
let mut iter2 = incoming_path.iter();
loop {
match iter1.next() {
Some(_) => iter2.next(),
None => break,
};
}
loop {
match iter2.next() {
Some(val) => {
let p = String::from(val.to_str().unwrap());
path_vec.push(p)
}
None => break,
}
}
}

#[cfg(test)]
mod tests {
use super::*;
use std::path::PathBuf;

#[test]
fn test_split_pathbuf() {
let mut splitted_path: Vec<String> = vec![];
let dir_to_watch = PathBuf::from("/Users/tweissin/deletemesoon");
let incoming_path = PathBuf::from("/Users/tweissin/deletemesoon/one/two/three.txt");
make_path_vec(&dir_to_watch, &incoming_path, &mut splitted_path);
assert_eq!(3, splitted_path.len());
assert_eq!("one", splitted_path[0]);
assert_eq!("two", splitted_path[1]);
assert_eq!("three.txt", splitted_path[2]);
}
}

0 comments on commit 8d81732

Please sign in to comment.