From 3f57ddefb76231c9f0fef8b69dd4c2677d924b7a Mon Sep 17 00:00:00 2001 From: Dennis Nemec Date: Fri, 26 Sep 2025 16:41:42 +0200 Subject: [PATCH] Initial draft --- .gitignore | 1 + Cargo.lock | 309 ++++++++++++++++++++++++++++++++++++++ Cargo.toml | 12 ++ src/app.rs | 55 +++++++ src/config.rs | 73 +++++++++ src/main.rs | 52 +++++++ src/util.rs | 0 test/error/sv_test.log | 0 test/error/sv_test2.log | 0 test/error/sv_test2.log.2 | 0 10 files changed, 502 insertions(+) create mode 100644 .gitignore create mode 100644 Cargo.lock create mode 100644 Cargo.toml create mode 100644 src/app.rs create mode 100644 src/config.rs create mode 100644 src/main.rs create mode 100644 src/util.rs create mode 100644 test/error/sv_test.log create mode 100644 test/error/sv_test2.log create mode 100644 test/error/sv_test2.log.2 diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..ea8c4bf --- /dev/null +++ b/.gitignore @@ -0,0 +1 @@ +/target diff --git a/Cargo.lock b/Cargo.lock new file mode 100644 index 0000000..019a10c --- /dev/null +++ b/Cargo.lock @@ -0,0 +1,309 @@ +# This file is automatically @generated by Cargo. +# It is not intended for manual editing. +version = 4 + +[[package]] +name = "deranged" +version = "0.5.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a41953f86f8a05768a6cda24def994fd2f424b04ec5c719cf89989779f199071" +dependencies = [ + "powerfmt", +] + +[[package]] +name = "equivalent" +version = "1.0.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "877a4ace8713b0bcf2a4e7eec82529c029f1d0619886d18145fea96c3ffe5c0f" + +[[package]] +name = "hashbrown" +version = "0.16.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5419bdc4f6a9207fbeba6d11b604d481addf78ecd10c11ad51e76c2f6482748d" + +[[package]] +name = "indexmap" +version = "2.11.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4b0f83760fb341a774ed326568e19f5a863af4a952def8c39f9ab92fd95b88e5" +dependencies = [ + "equivalent", + "hashbrown", +] + +[[package]] +name = "itoa" +version = "1.0.15" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4a5f13b858c8d314ee3e8f639011f7ccefe71f97f96e50151fb991f267928e2c" + +[[package]] +name = "libc" +version = "0.2.176" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "58f929b4d672ea937a23a1ab494143d968337a5f47e56d0815df1e0890ddf174" + +[[package]] +name = "log" +version = "0.4.28" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "34080505efa8e45a4b816c349525ebe327ceaa8559756f0356cba97ef3bf7432" + +[[package]] +name = "num-conv" +version = "0.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "51d515d32fb182ee37cda2ccdcb92950d6a3c2893aa280e540671c2cd0f3b1d9" + +[[package]] +name = "num_threads" +version = "0.1.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5c7398b9c8b70908f6371f47ed36737907c87c52af34c268fed0bf0ceb92ead9" +dependencies = [ + "libc", +] + +[[package]] +name = "powerfmt" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "439ee305def115ba05938db6eb1644ff94165c5ab5e9420d1c1bcedbba909391" + +[[package]] +name = "proc-macro2" +version = "1.0.101" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "89ae43fd86e4158d6db51ad8e2b80f313af9cc74f5c0e03ccb87de09998732de" +dependencies = [ + "unicode-ident", +] + +[[package]] +name = "quote" +version = "1.0.40" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1885c039570dc00dcb4ff087a89e185fd56bae234ddc7f056a945bf36467248d" +dependencies = [ + "proc-macro2", +] + +[[package]] +name = "rust" +version = "0.1.0" +dependencies = [ + "log", + "serde", + "simplelog", + "toml", + "widestring", + "winapi", +] + +[[package]] +name = "serde" +version = "1.0.227" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "80ece43fc6fbed4eb5392ab50c07334d3e577cbf40997ee896fe7af40bba4245" +dependencies = [ + "serde_core", + "serde_derive", +] + +[[package]] +name = "serde_core" +version = "1.0.227" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7a576275b607a2c86ea29e410193df32bc680303c82f31e275bbfcafe8b33be5" +dependencies = [ + "serde_derive", +] + +[[package]] +name = "serde_derive" +version = "1.0.227" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "51e694923b8824cf0e9b382adf0f60d4e05f348f357b38833a3fa5ed7c2ede04" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] + +[[package]] +name = "serde_spanned" +version = "1.0.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5417783452c2be558477e104686f7de5dae53dba813c28435e0e70f82d9b04ee" +dependencies = [ + "serde_core", +] + +[[package]] +name = "simplelog" +version = "0.12.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "16257adbfaef1ee58b1363bdc0664c9b8e1e30aed86049635fb5f147d065a9c0" +dependencies = [ + "log", + "termcolor", + "time", +] + +[[package]] +name = "syn" +version = "2.0.106" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ede7c438028d4436d71104916910f5bb611972c5cfd7f89b8300a8186e6fada6" +dependencies = [ + "proc-macro2", + "quote", + "unicode-ident", +] + +[[package]] +name = "termcolor" +version = "1.4.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "06794f8f6c5c898b3275aebefa6b8a1cb24cd2c6c79397ab15774837a0bc5755" +dependencies = [ + "winapi-util", +] + +[[package]] +name = "time" +version = "0.3.44" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "91e7d9e3bb61134e77bde20dd4825b97c010155709965fedf0f49bb138e52a9d" +dependencies = [ + "deranged", + "itoa", + "libc", + "num-conv", + "num_threads", + "powerfmt", + "serde", + "time-core", + "time-macros", +] + +[[package]] +name = "time-core" +version = "0.1.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "40868e7c1d2f0b8d73e4a8c7f0ff63af4f6d19be117e90bd73eb1d62cf831c6b" + +[[package]] +name = "time-macros" +version = "0.2.24" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "30cfb0125f12d9c277f35663a0a33f8c30190f4e4574868a330595412d34ebf3" +dependencies = [ + "num-conv", + "time-core", +] + +[[package]] +name = "toml" +version = "0.9.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "00e5e5d9bf2475ac9d4f0d9edab68cc573dc2fd644b0dba36b0c30a92dd9eaa0" +dependencies = [ + "indexmap", + "serde_core", + "serde_spanned", + "toml_datetime", + "toml_parser", + "toml_writer", + "winnow", +] + +[[package]] +name = "toml_datetime" +version = "0.7.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "32f1085dec27c2b6632b04c80b3bb1b4300d6495d1e129693bdda7d91e72eec1" +dependencies = [ + "serde_core", +] + +[[package]] +name = "toml_parser" +version = "1.0.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4cf893c33be71572e0e9aa6dd15e6677937abd686b066eac3f8cd3531688a627" +dependencies = [ + "winnow", +] + +[[package]] +name = "toml_writer" +version = "1.0.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d163a63c116ce562a22cda521fcc4d79152e7aba014456fb5eb442f6d6a10109" + +[[package]] +name = "unicode-ident" +version = "1.0.19" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f63a545481291138910575129486daeaf8ac54aee4387fe7906919f7830c7d9d" + +[[package]] +name = "widestring" +version = "1.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "dd7cf3379ca1aac9eea11fba24fd7e315d621f8dfe35c8d7d2be8b793726e07d" + +[[package]] +name = "winapi" +version = "0.3.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5c839a674fcd7a98952e593242ea400abe93992746761e38641405d28b00f419" +dependencies = [ + "winapi-i686-pc-windows-gnu", + "winapi-x86_64-pc-windows-gnu", +] + +[[package]] +name = "winapi-i686-pc-windows-gnu" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ac3b87c63620426dd9b991e5ce0329eff545bccbbb34f3be09ff6fb6ab51b7b6" + +[[package]] +name = "winapi-util" +version = "0.1.11" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c2a7b1c03c876122aa43f3020e6c3c3ee5c05081c9a00739faf7503aeba10d22" +dependencies = [ + "windows-sys", +] + +[[package]] +name = "winapi-x86_64-pc-windows-gnu" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f" + +[[package]] +name = "windows-link" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "45e46c0661abb7180e7b9c281db115305d49ca1709ab8242adf09666d2173c65" + +[[package]] +name = "windows-sys" +version = "0.61.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6f109e41dd4a3c848907eb83d5a42ea98b3769495597450cf6d153507b166f0f" +dependencies = [ + "windows-link", +] + +[[package]] +name = "winnow" +version = "0.7.13" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "21a0236b59786fed61e2a80582dd500fe61f18b5dca67a4a067d0bc9039339cf" diff --git a/Cargo.toml b/Cargo.toml new file mode 100644 index 0000000..69b3ac5 --- /dev/null +++ b/Cargo.toml @@ -0,0 +1,12 @@ +[package] +name = "rust" +version = "0.1.0" +edition = "2024" + +[dependencies] +log = "0.4.28" +serde = { version = "1.0.227", features = ["derive"] } +simplelog = "0.12.2" +toml = "0.9.7" +widestring = "1.2.0" +winapi = "0.3.9" diff --git a/src/app.rs b/src/app.rs new file mode 100644 index 0000000..ca9763d --- /dev/null +++ b/src/app.rs @@ -0,0 +1,55 @@ +use std::fs; +use std::path::Path; +use std::thread::sleep; +use std::time::Duration; +use crate::config::Config; + +pub fn move_file_to_dir(watch_path_string: &String, filename: &String, move_path_string: &String) -> Result<(), Box> { + let move_path = Path::new(move_path_string); + let watch_path = Path::new(watch_path_string); + let file_path = watch_path.join(Path::new(filename)); + let mut moved_file_path = move_path.join(filename); + + if !fs::exists(move_path)? { + info!("Creating directory {}", move_path_string); + fs::create_dir(move_path)?; + } + + if fs::exists(&moved_file_path)? { + moved_file_path.set_file_name(format!("{}.2", filename)); + } + + fs::copy(&file_path, &moved_file_path)?; + fs::remove_file(&file_path)?; + + info!("Moved file to {}", &moved_file_path.display()); + + Ok(()) +} + +pub fn restart_server() { + +} + +pub fn watch_files(config: Config) -> Result<(), Box> { + loop { + let mut has_found = false; + for file in fs::read_dir(Path::new(&config.watch_path))? { + if file.is_ok() { + let filename = file.unwrap().file_name().into_string().unwrap(); + if filename.starts_with(&config.watch_file_prefix) { + info!("Found file: {}. Moving file.", filename); + move_file_to_dir(&config.watch_path, &filename, &config.dir)?; + has_found = true; + } + } + } + + if has_found { + info!("Restarting server"); + restart_server(); + } + + sleep(Duration::from_secs(config.period as u64)); + } +} \ No newline at end of file diff --git a/src/config.rs b/src/config.rs new file mode 100644 index 0000000..3f947c7 --- /dev/null +++ b/src/config.rs @@ -0,0 +1,73 @@ +use std::fs::{read_to_string, File}; +use std::io::Write; +use serde::*; + +pub const CONFIG_PATH: &str = "config.toml"; + +#[derive(Serialize, Deserialize)] +pub struct Config { + /// Time period in which file system changes should be observed. In seconds. + pub period: u8, + + /// Absolute file paths to be checked periodically for existence. + pub watch_path: String, + + /// The programm will look in the watch_path folder for files with the given prefix. + pub watch_file_prefix: String, + + /// Directory the file will be moved to if the file exist. Absolute path. + pub dir: String, + + /// Size of the files to be watched which is checked to have this value + pub watch_file_size: u64, + + /// Name of the service to be restarted after a file has been found + pub service_name: String +} + +#[derive(Debug)] +pub enum ConfigErr { + NotExist, + ParsingError(String), + WriteError(String), +} + +pub fn load_config(config_file: &str) -> Result { + let toml_contents = read_to_string(config_file); + + if let Ok(toml_contents) = toml_contents { + let config = toml::from_str::(&toml_contents); + + match config { + Ok(config) => Ok(config), + Err(e) => Err(ConfigErr::ParsingError(format!("{}", e))) + } + + } else { + Err(ConfigErr::NotExist) + } +} + +pub fn create_default_config(config_path: &str) -> Result { + let config: Config = Config { + period: 30, + dir: String::from("SV_FILE_WATCHER"), + watch_path: String::from(""), + watch_file_prefix: String::from(""), + watch_file_size: 0, + service_name: String::from("") + }; + + let file = File::create(config_path); + + match file { + Ok(mut file) => { + match file.write_all(toml::to_string(&config).unwrap().as_bytes()) { + Ok(_) => Ok(config), + Err(e) => Err(ConfigErr::WriteError(format!("{}", e))) + } + }, + + Err(e) => Err(ConfigErr::WriteError(format!("{}", e))) + } +} \ No newline at end of file diff --git a/src/main.rs b/src/main.rs new file mode 100644 index 0000000..490d63f --- /dev/null +++ b/src/main.rs @@ -0,0 +1,52 @@ +#[macro_use] extern crate log; + +use std::fs::File; +use simplelog::*; + +use crate::app::watch_files; +use crate::config::{create_default_config, load_config, ConfigErr, CONFIG_PATH}; + +mod config; +mod app; +mod util; + +const LOG_FILE: &str = "sv_file_watcher.log"; + +fn main() -> Result<(), Box> { + CombinedLogger::init( + vec![ + TermLogger::new(LevelFilter::Info, Config::default(), TerminalMode::Mixed, ColorChoice::Auto), + WriteLogger::new(LevelFilter::Info, Config::default(), File::create(LOG_FILE).unwrap()), + ] + ).unwrap(); + + // Step 1: Get or create config file + let mut config_res = load_config(CONFIG_PATH); + + if let Err(err) = &config_res { + match err { + ConfigErr::NotExist => { + error!("Failed to find existing config file. Create one."); + config_res = create_default_config(CONFIG_PATH); + }, + + ConfigErr::WriteError(e) => { + error!("Failed to write config file."); + error!("Message: {e}"); + return Ok(()); + }, + + ConfigErr::ParsingError(e) => { + error!("Failed to parse config file"); + error!("Message: {e}"); + return Ok(()); + } + } + } + + let config = config_res.unwrap(); + + watch_files(config)?; + + Ok(()) +} diff --git a/src/util.rs b/src/util.rs new file mode 100644 index 0000000..e69de29 diff --git a/test/error/sv_test.log b/test/error/sv_test.log new file mode 100644 index 0000000..e69de29 diff --git a/test/error/sv_test2.log b/test/error/sv_test2.log new file mode 100644 index 0000000..e69de29 diff --git a/test/error/sv_test2.log.2 b/test/error/sv_test2.log.2 new file mode 100644 index 0000000..e69de29