.
This commit is contained in:
@@ -6,7 +6,7 @@ description = "Detect and Act on unauthorized access of any kind from any source
|
||||
authors = ["jkoontsiii@gmail.com"]
|
||||
license = "MIT"
|
||||
repository = "https://github.com/helloimalemur/watchman"
|
||||
keywords = ["file-integrity", "filesystem-integirty", "change-detection", "watchman"]
|
||||
keywords = ["file-integrity", "filesystem-integrity", "change-detection", "watchman"]
|
||||
readme = "README.md"
|
||||
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
|
||||
|
||||
@@ -28,4 +28,6 @@ serde = { version = "1.0.219", features = ["derive"] }
|
||||
tokio = { version = "1.44.1", features = ["rt", "rt-multi-thread", "macros"] }
|
||||
walkdir = "2.5.0"
|
||||
whoami = "1.5.2"
|
||||
lazy_static = "1.5.0"
|
||||
lazy_static = "1.5.0"
|
||||
log = "0.4"
|
||||
env_logger = "0.11"
|
||||
21
LICENSE
Normal file
21
LICENSE
Normal file
@@ -0,0 +1,21 @@
|
||||
MIT License
|
||||
|
||||
Copyright (c) 2025 Watchman contributors
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
in the Software without restriction, including without limitation the rights
|
||||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
copies of the Software, and to permit persons to whom the Software is
|
||||
furnished to do so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in all
|
||||
copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
SOFTWARE.
|
||||
@@ -6,19 +6,19 @@ pub fn configure_linux_service() {
|
||||
.arg("daemon-reload")
|
||||
.output()
|
||||
{
|
||||
println!("{}", String::from_utf8_lossy(&o.stdout));
|
||||
if o.status.success() { log::info!("{}", String::from_utf8_lossy(&o.stdout)); } else { log::error!("{}", String::from_utf8_lossy(&o.stderr)); }
|
||||
if let Ok(o) = process::Command::new("systemctl")
|
||||
.arg("enable")
|
||||
.arg("watchman")
|
||||
.output()
|
||||
{
|
||||
println!("{}", String::from_utf8_lossy(&o.stdout));
|
||||
if o.status.success() { log::info!("{}", String::from_utf8_lossy(&o.stdout)); } else { log::error!("{}", String::from_utf8_lossy(&o.stderr)); }
|
||||
if let Ok(o) = process::Command::new("systemctl")
|
||||
.arg("restart")
|
||||
.arg("watchman")
|
||||
.output()
|
||||
{
|
||||
println!("{}", String::from_utf8_lossy(&o.stdout));
|
||||
if o.status.success() { log::info!("{}", String::from_utf8_lossy(&o.stdout)); } else { log::error!("{}", String::from_utf8_lossy(&o.stderr)); }
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -27,15 +27,15 @@ pub fn configure_linux_service() {
|
||||
pub fn write_service_file<T: ToString>(path: T) {
|
||||
if whoami::username().eq_ignore_ascii_case("root") {
|
||||
if fs::write(path.to_string(), service_file()).is_ok() {
|
||||
println!(
|
||||
log::info!(
|
||||
"{}\n ~~~~~~~ SERVICE CONFIG CREATED ~~~~~~~",
|
||||
service_file()
|
||||
);
|
||||
} else {
|
||||
println!("{}", "COULD NOT WRITE SERVICE CONFIG TO FILE");
|
||||
log::error!("{}", "COULD NOT WRITE SERVICE CONFIG TO FILE");
|
||||
}
|
||||
} else {
|
||||
println!(
|
||||
log::error!(
|
||||
"{}",
|
||||
"PLEASE RUN AS ROOT - COULD NOT WRITE SERVICE CONFIG TO FILE"
|
||||
);
|
||||
@@ -51,7 +51,7 @@ Description=Watchman
|
||||
Type=simple
|
||||
User=root
|
||||
Group=root
|
||||
ExecStart=/root/.cargo/bin/watchman
|
||||
ExecStart=/usr/local/bin/watchman
|
||||
|
||||
[Install]
|
||||
WantedBy=multi-user.target
|
||||
|
||||
@@ -7,20 +7,13 @@ pub fn configure_macos_service() {
|
||||
.arg("/Library/LaunchDaemons/com.helloimalemur.watchman.plist")
|
||||
.output()
|
||||
{
|
||||
println!("{}", String::from_utf8_lossy(&o.stdout));
|
||||
if o.status.success() { log::info!("{}", String::from_utf8_lossy(&o.stdout)); } else { log::error!("{}", String::from_utf8_lossy(&o.stderr)); }
|
||||
if let Ok(o) = process::Command::new("launchctl")
|
||||
.arg("start")
|
||||
.arg("com.helloimalemur.watchman")
|
||||
.output()
|
||||
{
|
||||
println!("{}", String::from_utf8_lossy(&o.stdout));
|
||||
// if let Ok(o) = process::Command::new("systemctl")
|
||||
// .arg("restart")
|
||||
// .arg("watchman")
|
||||
// .output()
|
||||
// {
|
||||
// println!("{}", String::from_utf8_lossy(&o.stdout));
|
||||
// }
|
||||
if o.status.success() { log::info!("{}", String::from_utf8_lossy(&o.stdout)); } else { log::error!("{}", String::from_utf8_lossy(&o.stderr)); }
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -28,26 +21,32 @@ pub fn configure_macos_service() {
|
||||
pub fn write_launch_file<T: ToString>(path: T) {
|
||||
if whoami::username().eq_ignore_ascii_case("root") {
|
||||
if fs::write(path.to_string(), launch_file()).is_ok() {
|
||||
println!(
|
||||
log::info!(
|
||||
"{}\n ~~~~~~~ SERVICE CONFIG CREATED ~~~~~~~",
|
||||
launch_file()
|
||||
);
|
||||
// sudo chown root:wheel /Library/LaunchDaemons/com.yourname.yourapp.plist
|
||||
// sudo chmod 644 /Library/LaunchDaemons/com.yourname.yourapp.plist
|
||||
let _ = process::Command::new("chown")
|
||||
match process::Command::new("chown")
|
||||
.arg("root:wheel")
|
||||
.arg(path.to_string())
|
||||
.spawn();
|
||||
.output() {
|
||||
Ok(o) => { if !o.status.success() { log::error!("chown failed: {}", String::from_utf8_lossy(&o.stderr)); } },
|
||||
Err(e) => log::error!("failed to execute chown: {}", e),
|
||||
}
|
||||
|
||||
let _ = process::Command::new("chmod")
|
||||
match process::Command::new("chmod")
|
||||
.arg("644")
|
||||
.arg(path.to_string())
|
||||
.spawn();
|
||||
.output() {
|
||||
Ok(o) => { if !o.status.success() { log::error!("chmod failed: {}", String::from_utf8_lossy(&o.stderr)); } },
|
||||
Err(e) => log::error!("failed to execute chmod: {}", e),
|
||||
}
|
||||
} else {
|
||||
println!("{}", "COULD NOT WRITE SERVICE CONFIG TO FILE");
|
||||
log::error!("{}", "COULD NOT WRITE SERVICE CONFIG TO FILE");
|
||||
}
|
||||
} else {
|
||||
println!(
|
||||
log::error!(
|
||||
"{}",
|
||||
"PLEASE RUN AS ROOT - COULD NOT WRITE SERVICE CONFIG TO FILE"
|
||||
);
|
||||
|
||||
@@ -16,7 +16,8 @@ mod util;
|
||||
|
||||
#[tokio::main]
|
||||
async fn main() {
|
||||
println!("OS: {}", OS);
|
||||
env_logger::init();
|
||||
log::info!("OS: {}", OS);
|
||||
let arguments = Arguments::parse();
|
||||
let mut prom = Prometheus::new();
|
||||
prom.start().await;
|
||||
|
||||
@@ -7,8 +7,15 @@ use std::time::Duration;
|
||||
|
||||
pub async fn reboot_system(settings_map: Config) {
|
||||
let _res = send_discord("System rebooting", settings_map, &"".to_string()).await;
|
||||
if let Ok(reboot) = Command::new("reboot").output() {
|
||||
println!("{:#?}", reboot)
|
||||
match Command::new("reboot").output() {
|
||||
Ok(reboot) => {
|
||||
if reboot.status.success() {
|
||||
log::info!("reboot invoked: {}", String::from_utf8_lossy(&reboot.stdout));
|
||||
} else {
|
||||
log::error!("reboot failed: {}", String::from_utf8_lossy(&reboot.stderr));
|
||||
}
|
||||
}
|
||||
Err(e) => log::error!("failed to execute reboot: {}", e),
|
||||
}
|
||||
}
|
||||
|
||||
@@ -16,23 +23,23 @@ pub async fn unmount_encrypted_volumes() {
|
||||
match OS {
|
||||
"linux" => {
|
||||
if let Ok(output) = Command::new("dmsetup").arg("ls").output() {
|
||||
let encrypted_vols = String::from_utf8(output.stdout.to_vec()).unwrap();
|
||||
let encrypted_vols = String::from_utf8(output.stdout.to_vec()).unwrap_or_default();
|
||||
for ea in encrypted_vols.lines() {
|
||||
let vol_split: Vec<_> = ea.split_ascii_whitespace().collect();
|
||||
let luks_vol = vol_split.first().unwrap().to_string();
|
||||
// println!("{}", luks_vol);
|
||||
// println!("{}", command_str);
|
||||
if let Ok(res) = Command::new("cat").arg("/proc/mounts").output() {
|
||||
let mount_file_results = String::from_utf8(res.stdout.to_vec()).unwrap();
|
||||
for mount in mount_file_results.lines() {
|
||||
let luks_vol_str = luks_vol.as_str();
|
||||
if mount.contains(luks_vol_str) {
|
||||
let mount_split: Vec<&str> = mount.split_ascii_whitespace().collect();
|
||||
let vol_mount_path = mount_split.get(1).unwrap();
|
||||
// println!("{}", vol_mount_path);
|
||||
commit_umount_volume(vol_mount_path);
|
||||
thread::sleep(Duration::new(1, 0));
|
||||
commit_luks_close(luks_vol_str);
|
||||
if let Some(first) = vol_split.first() {
|
||||
let luks_vol = first.to_string();
|
||||
if let Ok(res) = Command::new("cat").arg("/proc/mounts").output() {
|
||||
let mount_file_results = String::from_utf8(res.stdout.to_vec()).unwrap_or_default();
|
||||
for mount in mount_file_results.lines() {
|
||||
let luks_vol_str = luks_vol.as_str();
|
||||
if mount.contains(luks_vol_str) {
|
||||
let mount_split: Vec<&str> = mount.split_ascii_whitespace().collect();
|
||||
if let Some(vol_mount_path) = mount_split.get(1) {
|
||||
commit_umount_volume(vol_mount_path);
|
||||
thread::sleep(Duration::new(1, 0));
|
||||
commit_luks_close(luks_vol_str);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -47,7 +54,7 @@ fn commit_umount_volume(vol_mount_path: &str) {
|
||||
match OS {
|
||||
"linux" => {
|
||||
if let Ok(res) = Command::new("umount").arg(vol_mount_path).output() {
|
||||
println!("{}", String::from_utf8(res.stdout.to_vec()).unwrap())
|
||||
if res.status.success() { log::info!("{}", String::from_utf8_lossy(&res.stdout)); } else { log::error!("{}", String::from_utf8_lossy(&res.stderr)); }
|
||||
}
|
||||
}
|
||||
_ => {}
|
||||
@@ -57,13 +64,13 @@ fn commit_umount_volume(vol_mount_path: &str) {
|
||||
fn commit_luks_close(luks_vol: &str) {
|
||||
match OS {
|
||||
"linux" => {
|
||||
println!("close luks");
|
||||
log::info!("close luks");
|
||||
if let Ok(res) = Command::new("cryptsetup")
|
||||
.arg("luksClose")
|
||||
.arg(luks_vol)
|
||||
.output()
|
||||
{
|
||||
println!("{}", String::from_utf8(res.stdout.to_vec()).unwrap())
|
||||
if res.status.success() { log::info!("{}", String::from_utf8_lossy(&res.stdout)); } else { log::error!("{}", String::from_utf8_lossy(&res.stderr)); }
|
||||
}
|
||||
}
|
||||
_ => {}
|
||||
|
||||
@@ -12,7 +12,9 @@ pub struct NETMon {
|
||||
triggered: bool,
|
||||
interfaces: Vec<String>,
|
||||
settings_map: Config,
|
||||
state: Arc<Mutex<Vec<SocketInfo>>>
|
||||
state: Arc<Mutex<Vec<SocketInfo>>>,
|
||||
fail_count: u32,
|
||||
last_reboot: Option<std::time::SystemTime>,
|
||||
}
|
||||
|
||||
impl NETMon {
|
||||
@@ -24,7 +26,7 @@ impl NETMon {
|
||||
let moved_sockets = sockets_info.clone();
|
||||
for si in moved_sockets {
|
||||
match si.protocol_socket_info {
|
||||
ProtocolSocketInfo::Tcp(tcp_si) => println!(
|
||||
ProtocolSocketInfo::Tcp(tcp_si) => log::debug!(
|
||||
"TCP {}:{} -> {}:{} {:?} - {}",
|
||||
tcp_si.local_addr,
|
||||
tcp_si.local_port,
|
||||
@@ -33,7 +35,7 @@ impl NETMon {
|
||||
si.associated_pids,
|
||||
tcp_si.state
|
||||
),
|
||||
ProtocolSocketInfo::Udp(udp_si) => println!(
|
||||
ProtocolSocketInfo::Udp(udp_si) => log::debug!(
|
||||
"UDP {}:{} -> *:* {:?}",
|
||||
udp_si.local_addr, udp_si.local_port, si.associated_pids
|
||||
),
|
||||
@@ -44,21 +46,61 @@ impl NETMon {
|
||||
triggered: false,
|
||||
interfaces: vec![],
|
||||
settings_map,
|
||||
state: Arc::new(Mutex::new(sockets_info.clone()))
|
||||
state: Arc::new(Mutex::new(sockets_info.clone())),
|
||||
fail_count: 0,
|
||||
last_reboot: None,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl EventMonitor for NETMon {
|
||||
async fn check(&mut self) {
|
||||
if let Ok(check) = httping::ping("koonts.net", "", "https", 443).await {
|
||||
self.triggered = !check
|
||||
let host = self
|
||||
.settings_map
|
||||
.get::<String>("net_mon_ping_host")
|
||||
.unwrap_or_else(|_| "cloudflare.com".to_string());
|
||||
let reboot_on_fail = self
|
||||
.settings_map
|
||||
.get::<String>("net_mon_reboot_on_failure")
|
||||
.unwrap_or_else(|_| "false".to_string())
|
||||
.eq_ignore_ascii_case("true");
|
||||
|
||||
match httping::ping(host.as_str(), "", "https", 443).await {
|
||||
Ok(ok) => {
|
||||
if !ok {
|
||||
self.fail_count += 1;
|
||||
self.triggered = true;
|
||||
} else {
|
||||
if self.triggered { log::info!("Network connectivity restored to {}", host); }
|
||||
self.fail_count = 0;
|
||||
self.triggered = false;
|
||||
}
|
||||
}
|
||||
Err(e) => {
|
||||
log::warn!("Network ping error to {}: {}", host, e);
|
||||
self.fail_count += 1;
|
||||
self.triggered = true;
|
||||
}
|
||||
}
|
||||
|
||||
if self.triggered {
|
||||
println!("{} :: ALERT NET", Local::now());
|
||||
net_alert(self.settings_map.clone()).await;
|
||||
log::warn!("{} :: Network connectivity check failed ({} consecutive failures)", Local::now(), self.fail_count);
|
||||
// Simple backoff: only reboot after 3 consecutive failures and at most once every 10 minutes
|
||||
if reboot_on_fail && self.fail_count >= 3 {
|
||||
let now = std::time::SystemTime::now();
|
||||
let should_reboot = match self.last_reboot {
|
||||
None => true,
|
||||
Some(t) => now.duration_since(t).map(|d| d.as_secs() >= 600).unwrap_or(true),
|
||||
};
|
||||
if should_reboot {
|
||||
log::error!("Rebooting due to sustained network failure");
|
||||
self.last_reboot = Some(now);
|
||||
net_alert(self.settings_map.clone()).await;
|
||||
} else {
|
||||
log::warn!("Reboot on network failure suppressed due to backoff window");
|
||||
}
|
||||
}
|
||||
}
|
||||
// println!("check net: {}", self.triggered);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -1,8 +1,11 @@
|
||||
use actix_web::http::header;
|
||||
use actix_web::{get, web, App, Error, HttpResponse, HttpServer, Responder};
|
||||
use actix_web::{get, App, Error, HttpResponse, HttpServer};
|
||||
use prometheus::{Encoder, TextEncoder};
|
||||
use std::thread;
|
||||
|
||||
use config::Config;
|
||||
use crate::util::get_config_dir;
|
||||
|
||||
pub struct Prometheus {}
|
||||
|
||||
impl Prometheus {
|
||||
@@ -12,12 +15,35 @@ impl Prometheus {
|
||||
pub async fn start(&self) {
|
||||
let _handle = thread::spawn(|| {
|
||||
let rt = tokio::runtime::Runtime::new();
|
||||
let _ = rt.unwrap().block_on(
|
||||
HttpServer::new(|| App::new().service(metrics))
|
||||
.bind(("127.0.0.1", 8323))
|
||||
.unwrap()
|
||||
.run(),
|
||||
);
|
||||
|
||||
// Read optional bind config
|
||||
let mut addr = String::from("127.0.0.1");
|
||||
let mut port: u16 = 8323;
|
||||
let config_path = format!("{}config/settings.toml", get_config_dir());
|
||||
if std::path::Path::new(&config_path).exists() {
|
||||
if let Ok(cfg) = Config::builder()
|
||||
.add_source(config::File::with_name(&config_path))
|
||||
.build()
|
||||
{
|
||||
if let Ok(a) = cfg.get::<String>("prom_bind_addr") { addr = a; }
|
||||
if let Ok(p) = cfg.get::<String>("prom_bind_port") {
|
||||
if let Ok(n) = p.parse::<u16>() { port = n; } else { log::warn!("Invalid prom_bind_port '{}', using default {}", p, port); }
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
let server = HttpServer::new(|| App::new().service(metrics))
|
||||
.bind((addr.as_str(), port));
|
||||
|
||||
match server {
|
||||
Ok(s) => {
|
||||
log::info!("Prometheus exporter listening on {}:{}", addr, port);
|
||||
let _ = rt.unwrap().block_on(s.run());
|
||||
}
|
||||
Err(e) => {
|
||||
log::error!("Failed to bind Prometheus exporter on {}:{}: {}", addr, port, e);
|
||||
}
|
||||
}
|
||||
});
|
||||
// let _ = handle.join();
|
||||
}
|
||||
@@ -27,18 +53,17 @@ impl Prometheus {
|
||||
async fn metrics() -> Result<HttpResponse, Error> {
|
||||
let encoder = TextEncoder::new();
|
||||
|
||||
// HTTP_COUNTER.inc();
|
||||
// let timer = HTTP_REQ_HISTOGRAM.with_label_values(&["all"]).start_timer();
|
||||
|
||||
let metric_families = prometheus::gather();
|
||||
let mut buffer = vec![];
|
||||
encoder.encode(&metric_families, &mut buffer).unwrap();
|
||||
// HTTP_BODY_GAUGE.set(buffer.len() as f64);
|
||||
let response = String::from_utf8(buffer.clone()).unwrap();
|
||||
if let Err(e) = encoder.encode(&metric_families, &mut buffer) {
|
||||
log::error!("Failed to encode Prometheus metrics: {}", e);
|
||||
}
|
||||
let response = String::from_utf8(buffer.clone()).unwrap_or_else(|e| {
|
||||
log::error!("Failed to build Prometheus metrics body: {}", e);
|
||||
String::new()
|
||||
});
|
||||
buffer.clear();
|
||||
|
||||
// timer.observe_duration();
|
||||
|
||||
Ok(HttpResponse::Ok()
|
||||
.insert_header(header::ContentType(mime::TEXT_PLAIN))
|
||||
.body(response))
|
||||
|
||||
@@ -113,7 +113,7 @@ pub fn write_default_config<T: ToString>(path: T, webhook: String) {
|
||||
)
|
||||
.is_ok()
|
||||
{
|
||||
println!(
|
||||
log::info!(
|
||||
"{}\n ~~~~~~~ UNABLE TO LOCATE CONFIG FILE - DEFAULT CONFIG CREATED ~~~~~~~",
|
||||
default_config().replace("https://discord.com/api/webhooks/", webhook.as_str())
|
||||
);
|
||||
|
||||
@@ -47,7 +47,7 @@ impl AppState {
|
||||
|
||||
pub fn config(&mut self, args: Arguments) {
|
||||
// check for config file if it doesn't exist write default config
|
||||
println!("Configuring..");
|
||||
log::info!("Configuring..");
|
||||
let cache_dir = get_cache_dir();
|
||||
let config_dir = get_config_dir();
|
||||
|
||||
@@ -61,10 +61,10 @@ impl AppState {
|
||||
if let Some(service_command) = args.service {
|
||||
match service_command.as_str() {
|
||||
"install" => {
|
||||
println!("Installing..");
|
||||
log::info!("Installing..");
|
||||
setup_service();
|
||||
if !Path::new(settings_file_path.as_str()).exists() {
|
||||
println!("Settings.toml does not exist");
|
||||
log::warn!("Settings.toml does not exist; writing default and exiting after service install");
|
||||
crate::util::write_default_config(settings_file_path.clone(), webhook.clone());
|
||||
exit(0);
|
||||
}
|
||||
@@ -78,26 +78,32 @@ impl AppState {
|
||||
}
|
||||
|
||||
if !Path::new(settings_file_path.as_str()).exists() {
|
||||
println!("Settings.toml does not exist");
|
||||
log::warn!("Settings.toml does not exist; writing default");
|
||||
write_default_config(settings_file_path.clone(), webhook);
|
||||
}
|
||||
|
||||
let blacklist_file_path = format!("{}config/file_mon_blacklist", config_dir);
|
||||
if !Path::new(blacklist_file_path.as_str()).exists() {
|
||||
println!("file_mon_blacklist does not exist");
|
||||
log::warn!("file_mon_blacklist does not exist; creating default");
|
||||
write_default_blacklist(blacklist_file_path.clone());
|
||||
}
|
||||
let config = Config::builder();
|
||||
let settings = config
|
||||
let settings = match config
|
||||
.add_source(config::File::with_name(settings_file_path.as_str()))
|
||||
.build()
|
||||
.expect("Configuration error: unable to parse settings");
|
||||
{
|
||||
Ok(s) => s,
|
||||
Err(e) => {
|
||||
log::error!("Configuration error: unable to parse settings: {}", e);
|
||||
exit(2);
|
||||
}
|
||||
};
|
||||
|
||||
// initialize monitoring modules
|
||||
let mut monitors: Vec<Monitors> = vec![];
|
||||
if settings
|
||||
.get::<String>("usb_mon_enabled")
|
||||
.unwrap()
|
||||
.unwrap_or("false".to_string())
|
||||
.eq_ignore_ascii_case("true")
|
||||
{
|
||||
monitors.push(Monitors::USBMon(USBMon::new(settings.clone())));
|
||||
@@ -111,14 +117,14 @@ impl AppState {
|
||||
// }
|
||||
if settings
|
||||
.get::<String>("burn_file_mon_enabled")
|
||||
.unwrap()
|
||||
.unwrap_or("false".to_string())
|
||||
.eq_ignore_ascii_case("true")
|
||||
{
|
||||
monitors.push(Monitors::SSHBurnMon(SSHBurnMon::new(settings.clone())));
|
||||
}
|
||||
if settings
|
||||
.get::<String>("fs_mon_enabled")
|
||||
.unwrap()
|
||||
.unwrap_or("false".to_string())
|
||||
.eq_ignore_ascii_case("true")
|
||||
{
|
||||
monitors.push(Monitors::FileChanges(FileChanges::new(
|
||||
@@ -140,20 +146,18 @@ impl AppState {
|
||||
}
|
||||
|
||||
pub async fn run(&mut self) {
|
||||
let fs_check_tick = self
|
||||
// Defaults if not configured or parse fails
|
||||
let n_fs_check_tick: u64 = self
|
||||
.settings_map
|
||||
.get::<String>("fs_tick_delay_seconds")
|
||||
.expect("tick_delay_seconds not found in Settings.toml");
|
||||
let n_fs_check_tick = fs_check_tick
|
||||
.parse::<u64>()
|
||||
.expect("unable to parse fs_tick_delay_seconds");
|
||||
let tick = self
|
||||
.get::<String>("fs_tick_delay_seconds").ok()
|
||||
.and_then(|v| match v.parse::<u64>() { Ok(n) => Some(n), Err(e) => { log::warn!("Invalid fs_tick_delay_seconds '{}': {}. Using default 300.", v, e); None } })
|
||||
.unwrap_or(300);
|
||||
let n_tick: u64 = self
|
||||
.settings_map
|
||||
.get::<String>("tick_delay_seconds")
|
||||
.expect("tick_delay_seconds not found in Settings.toml");
|
||||
let n_tick = tick
|
||||
.parse::<u64>()
|
||||
.expect("unable to parse tick_delay_seconds");
|
||||
.get::<String>("tick_delay_seconds").ok()
|
||||
.and_then(|v| match v.parse::<u64>() { Ok(n) => Some(n), Err(e) => { log::warn!("Invalid tick_delay_seconds '{}': {}. Using default 5.", v, e); None } })
|
||||
.unwrap_or(5);
|
||||
|
||||
let mut last = SystemTime::now();
|
||||
loop {
|
||||
let mut binding = self.monitors.lock();
|
||||
@@ -161,34 +165,33 @@ impl AppState {
|
||||
for i in bind.iter_mut() {
|
||||
match i {
|
||||
Monitors::USBMon(e) => {
|
||||
// println!("{:#?}", e);
|
||||
e.check().await;
|
||||
}
|
||||
// Monitors::NetMon(e) => {
|
||||
// // println!("{:#?}", e);
|
||||
// e.check().await;
|
||||
// }
|
||||
Monitors::SSHBurnMon(e) => {
|
||||
// println!("{:#?}", e);
|
||||
e.check().await;
|
||||
}
|
||||
Monitors::FileChanges(e) => {
|
||||
// println!("{:#?}", e);
|
||||
let now = SystemTime::now();
|
||||
let dur_since = now.duration_since(last).unwrap();
|
||||
let dur_since = match now.duration_since(last) {
|
||||
Ok(d) => d,
|
||||
Err(e) => {
|
||||
log::warn!("SystemTime went backwards: {}", e);
|
||||
Duration::new(0, 0)
|
||||
}
|
||||
};
|
||||
if dur_since.as_secs() > n_fs_check_tick {
|
||||
// println!("fs_tick");
|
||||
last = SystemTime::now();
|
||||
e.check().await;
|
||||
}
|
||||
}
|
||||
Monitors::NewClients(e) => {
|
||||
// println!("{:#?}", e);
|
||||
e.check().await;
|
||||
}
|
||||
}
|
||||
tokio::time::sleep(Duration::new(n_tick, 0)).await;
|
||||
// println!("tick");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user