Initial draft

This commit is contained in:
Dennis Nemec
2025-09-26 16:41:42 +02:00
commit 3f57ddefb7
10 changed files with 502 additions and 0 deletions

1
.gitignore vendored Normal file
View File

@ -0,0 +1 @@
/target

309
Cargo.lock generated Normal file
View File

@ -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"

12
Cargo.toml Normal file
View File

@ -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"

55
src/app.rs Normal file
View File

@ -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<dyn std::error::Error>> {
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<dyn std::error::Error>> {
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));
}
}

73
src/config.rs Normal file
View File

@ -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<Config, ConfigErr> {
let toml_contents = read_to_string(config_file);
if let Ok(toml_contents) = toml_contents {
let config = toml::from_str::<Config>(&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<Config, ConfigErr> {
let config: Config = Config {
period: 30,
dir: String::from("SV_FILE_WATCHER"),
watch_path: String::from("<ERPFRAME_DIR>"),
watch_file_prefix: String::from("<ERPFRAME_LOG_FILE_PREFIX>"),
watch_file_size: 0,
service_name: String::from("<ERPFRAME_SERVICE_NAME>")
};
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)))
}
}

52
src/main.rs Normal file
View File

@ -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<dyn std::error::Error>> {
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(())
}

0
src/util.rs Normal file
View File

0
test/error/sv_test.log Normal file
View File

0
test/error/sv_test2.log Normal file
View File

View File