implement daemon mode argument option

This commit is contained in:
postscriptum 2025-07-03 12:53:59 +03:00
parent 77d0650aef
commit 1e3043d683
4 changed files with 58 additions and 21 deletions

View file

@ -35,7 +35,9 @@ snac2nex -s /path/to/snac/storage -t /path/to/nex -u user1 -u user2
Supported values: Supported values:
* `c` (`copy`) - copy files * `h` (`hard`) - create hard links * `s` (`soft`) - create soft links (macos, linux, windows only) * `c` (`copy`) - copy files
* `h` (`hard`) - create hard links
* `s` (`soft`) - create soft links (macos, linux, windows only)
-r, --rotate <ROTATE> -r, --rotate <ROTATE>
Keep running as the daemon, renew every `n` seconds Keep running as the daemon, renew every `n` seconds
@ -62,6 +64,9 @@ snac2nex -s /path/to/snac/storage -t /path/to/nex -u user1 -u user2
-k, --keep -k, --keep
Keep Nex entry on Snac post was removed Keep Nex entry on Snac post was removed
-d, --daemon
Disables some debug output
-h, --help -h, --help
Print help (see a summary with '-h') Print help (see a summary with '-h')

View file

@ -48,4 +48,8 @@ pub struct Config {
/// Keep Nex entry on Snac post was removed /// Keep Nex entry on Snac post was removed
#[arg(short, long, default_value_t = false)] #[arg(short, long, default_value_t = false)]
pub keep: bool, pub keep: bool,
/// Disables some debug output
#[arg(short, long, default_value_t = false)]
pub daemon: bool,
} }

View file

@ -13,30 +13,38 @@ fn main() -> Result<()> {
use config::Config; use config::Config;
let c = Config::parse(); let c = Config::parse();
println!("Sync `{}` for users {:?}...", &c.source, &c.user);
let n = Nex::init( let n = Nex::init(
c.target, c.target,
c.format_filename, c.format_filename,
c.format_updated, c.format_updated,
c.format_content, c.format_content,
c.attachment, c.attachment,
!c.keep, (!c.keep, !c.daemon),
&c.user, &c.user,
)?; )?;
let s = Snac::init(c.source, c.user)?; let s = Snac::init(c.source, c.user)?;
println!("export begin..."); let mut r = sync(&s, &n, !c.daemon)?;
let mut r = sync(&s, &n)?;
match c.rotate { match c.rotate {
Some(t) => loop { Some(t) => loop {
println!( if !c.daemon {
"queue completed:\n\tcreated: {}\n\tupdated: {}\n\tdeleted:\n\t\tfiles: {}\n\t\tdirectories: {}\n\tignored: {}\n\ttotal: {}\nawait {t} seconds to rotate...", println!(
r.created, r.updated, r.deleted.files, r.deleted.directories, r.ignored, r.total "queue completed:\n\tcreated: {}\n\tupdated: {}\n\tdeleted:\n\t\tfiles: {}\n\t\tdirectories: {}\n\tignored: {}\n\ttotal: {}\nawait {t} seconds to rotate...",
); r.created,
r.updated,
r.deleted.files,
r.deleted.directories,
r.ignored,
r.total
);
}
std::thread::sleep(std::time::Duration::from_secs(t)); std::thread::sleep(std::time::Duration::from_secs(t));
r = sync(&s, &n)?; r = sync(&s, &n, !c.daemon)?;
}, },
None => println!( None => println!(
"export completed:\n\tcreated: {}\n\tupdated: {}\n\tdeleted:\n\t\tfiles: {}\n\t\tdirectories: {}\n\tignored: {}\n\ttotal: {}", "Sync operation completed:\n\tcreated: {}\n\tupdated: {}\n\tdeleted:\n\t\tfiles: {}\n\t\tdirectories: {}\n\tignored: {}\n\ttotal: {}",
r.created, r.updated, r.deleted.files, r.deleted.directories, r.ignored, r.total r.created, r.updated, r.deleted.files, r.deleted.directories, r.ignored, r.total
), ),
} }
@ -44,11 +52,13 @@ fn main() -> Result<()> {
Ok(()) Ok(())
} }
fn sync(snac: &Snac, nex: &Nex) -> Result<Response> { fn sync(snac: &Snac, nex: &Nex, is_debug: bool) -> Result<Response> {
use std::collections::HashSet; use std::collections::HashSet;
let mut r = Response::default(); let mut r = Response::default();
for user in &snac.users { for user in &snac.users {
println!("\tsync profile for `{}`...", user.name); if is_debug {
println!("\tsync profile for `{}`...", user.name);
}
let mut keep = if nex.is_cleanup() { let mut keep = if nex.is_cleanup() {
Some(HashSet::with_capacity(100)) // @TODO estimated Some(HashSet::with_capacity(100)) // @TODO estimated
} else { } else {
@ -62,7 +72,9 @@ fn sync(snac: &Snac, nex: &Nex) -> Result<Response> {
} }
// skip non authorized content // skip non authorized content
if let Some(content) = post.source_content { if let Some(content) = post.source_content {
println!("\t\tsync post `{}`...", post.id); if is_debug {
println!("\t\tsync post `{}`...", post.id);
}
let response = nex.sync( let response = nex.sync(
&user.name, &user.name,
content, content,
@ -99,15 +111,21 @@ fn sync(snac: &Snac, nex: &Nex) -> Result<Response> {
match response.change { match response.change {
Change::Created => { Change::Created => {
r.created += 1; r.created += 1;
println!("\t\t\tcreate new post file.") if is_debug {
println!("\t\t\tcreate new post file.")
}
} }
Change::Ignored => { Change::Ignored => {
r.ignored += 1; r.ignored += 1;
println!("\t\t\tpost file is up to date.") if is_debug {
println!("\t\t\tpost file is up to date.")
}
} }
Change::Updated => { Change::Updated => {
r.updated += 1; r.updated += 1;
println!("\t\t\tpost file update with new content.") if is_debug {
println!("\t\t\tpost file update with new content.")
}
} }
} }
if let Some(ref mut k) = keep if let Some(ref mut k) = keep

View file

@ -18,6 +18,7 @@ pub struct Nex {
attachment: Attachment, attachment: Attachment,
filename: String, filename: String,
is_cleanup: bool, is_cleanup: bool,
is_debug: bool,
pattern: String, pattern: String,
time_format: String, time_format: String,
users: HashMap<String, PathBuf>, users: HashMap<String, PathBuf>,
@ -30,7 +31,7 @@ impl Nex {
time_format: String, time_format: String,
pattern: String, pattern: String,
attachment_mode: Option<String>, attachment_mode: Option<String>,
is_cleanup: bool, (is_cleanup, is_debug): (bool, bool),
user_names: &Vec<String>, user_names: &Vec<String>,
) -> Result<Self> { ) -> Result<Self> {
use std::path::MAIN_SEPARATOR; use std::path::MAIN_SEPARATOR;
@ -55,6 +56,7 @@ impl Nex {
attachment: Attachment::init(attachment_mode)?, attachment: Attachment::init(attachment_mode)?,
filename, filename,
is_cleanup, is_cleanup,
is_debug,
pattern, pattern,
time_format, time_format,
users, users,
@ -225,7 +227,9 @@ impl Nex {
} }
pub fn clean(&self, name: &str, ignore: HashSet<PathBuf>) -> Result<Clean> { pub fn clean(&self, name: &str, ignore: HashSet<PathBuf>) -> Result<Clean> {
println!("\t\tcleanup..."); if self.is_debug {
println!("\t\tcleanup...");
}
let mut r = Clean::default(); let mut r = Clean::default();
for entry in for entry in
walkdir::WalkDir::new(PathBuf::from(self.users.get(name).unwrap())).follow_links(false) walkdir::WalkDir::new(PathBuf::from(self.users.get(name).unwrap())).follow_links(false)
@ -233,7 +237,9 @@ impl Nex {
let e = entry?; let e = entry?;
let p = e.path(); let p = e.path();
let s = p.to_string_lossy(); let s = p.to_string_lossy();
println!("\t\tcheck `{s}`..."); if self.is_debug {
println!("\t\tcheck `{s}`...");
}
if ignore.contains(p) { if ignore.contains(p) {
continue; continue;
} }
@ -241,11 +247,15 @@ impl Nex {
if m.is_file() { if m.is_file() {
fs::remove_file(p)?; fs::remove_file(p)?;
r.files += 1; r.files += 1;
println!("\t\t\tdelete file `{s}`"); if self.is_debug {
println!("\t\t\tdelete file `{s}`");
}
} else if m.is_dir() { } else if m.is_dir() {
fs::remove_dir_all(p)?; fs::remove_dir_all(p)?;
r.directories += 1; r.directories += 1;
println!("\t\t\tdelete directory `{s}`"); if self.is_debug {
println!("\t\t\tdelete directory `{s}`");
}
} else { } else {
panic!() panic!()
} }