use anyhow::Result; use gethostname::gethostname; use local_ip_address::local_ip; use dns_lookup::lookup_addr; use std::env; use std::process; use uzers::{get_current_uid, get_current_gid, get_current_username, get_current_groupname}; use rusqlite::Connection; use crate::meta_plugin::MetaPlugin; #[derive(Debug, Clone, Default)] pub struct CwdMetaPlugin { meta_name: String, is_saved: bool, outputs: std::collections::HashMap, } impl CwdMetaPlugin { pub fn new( _options: Option>, outputs: Option>, ) -> CwdMetaPlugin { // Start with default outputs let mut final_outputs = std::collections::HashMap::new(); let default_outputs = Self::default().default_outputs(); for output_name in default_outputs { final_outputs.insert(output_name.clone(), serde_yaml::Value::String(output_name)); } if let Some(outs) = outputs { for (key, value) in outs { final_outputs.insert(key, value); } } CwdMetaPlugin { meta_name: "cwd".to_string(), is_saved: false, outputs: final_outputs, } } pub fn new_simple() -> CwdMetaPlugin { Self::new(None, None) } } impl MetaPlugin for CwdMetaPlugin { fn is_internal(&self) -> bool { true } fn finalize(&mut self, _conn: &Connection) -> Result<()> { // Since we save during initialize(), return Ok to avoid duplicate saves Ok(()) } fn update(&mut self, _data: &[u8], _conn: &Connection) { // No update needed } fn meta_name(&mut self) -> String { self.meta_name.clone() } fn initialize(&mut self, conn: &Connection, item_id: i64) -> Result<()> { let cwd = match env::current_dir() { Ok(path) => path.to_string_lossy().to_string(), Err(_) => "unknown".to_string(), }; // Use central output handler self.save_meta(conn, item_id, "cwd", cwd)?; self.is_saved = true; Ok(()) } fn outputs(&self) -> &std::collections::HashMap { &self.outputs } fn outputs_mut(&mut self) -> &mut std::collections::HashMap { &mut self.outputs } fn default_outputs(&self) -> Vec { vec!["cwd".to_string()] } fn default_options(&self) -> std::collections::HashMap { std::collections::HashMap::new() } } #[derive(Debug, Clone, Default)] pub struct UidMetaPlugin { meta_name: String, is_saved: bool, outputs: std::collections::HashMap, } impl UidMetaPlugin { pub fn new( _options: Option>, outputs: Option>, ) -> UidMetaPlugin { // Start with default outputs let mut final_outputs = std::collections::HashMap::new(); let default_outputs = Self::default().default_outputs(); for output_name in default_outputs { final_outputs.insert(output_name.clone(), serde_yaml::Value::String(output_name)); } if let Some(outs) = outputs { for (key, value) in outs { final_outputs.insert(key, value); } } UidMetaPlugin { meta_name: "uid".to_string(), is_saved: false, outputs: final_outputs, } } pub fn new_simple() -> UidMetaPlugin { Self::new(None, None) } } impl MetaPlugin for UidMetaPlugin { fn is_internal(&self) -> bool { true } fn finalize(&mut self, _conn: &Connection) -> Result<()> { // Since we save during initialize(), return Ok to avoid duplicate saves Ok(()) } fn update(&mut self, _data: &[u8], _conn: &Connection) { // No update needed } fn meta_name(&mut self) -> String { self.meta_name.clone() } fn initialize(&mut self, conn: &Connection, item_id: i64) -> Result<()> { let uid = get_current_uid().to_string(); self.save_meta(conn, item_id, "uid", uid)?; self.is_saved = true; Ok(()) } fn outputs(&self) -> &std::collections::HashMap { &self.outputs } fn outputs_mut(&mut self) -> &mut std::collections::HashMap { &mut self.outputs } fn default_outputs(&self) -> Vec { vec!["uid".to_string()] } fn default_options(&self) -> std::collections::HashMap { std::collections::HashMap::new() } } #[derive(Debug, Clone, Default)] pub struct UserMetaPlugin { meta_name: String, is_saved: bool, outputs: std::collections::HashMap, } impl UserMetaPlugin { pub fn new( _options: Option>, outputs: Option>, ) -> UserMetaPlugin { // Start with default outputs let mut final_outputs = std::collections::HashMap::new(); let default_outputs = Self::default().default_outputs(); for output_name in default_outputs { final_outputs.insert(output_name.clone(), serde_yaml::Value::String(output_name)); } if let Some(outs) = outputs { for (key, value) in outs { final_outputs.insert(key, value); } } UserMetaPlugin { meta_name: "user".to_string(), is_saved: false, outputs: final_outputs, } } pub fn new_simple() -> UserMetaPlugin { Self::new(None, None) } } impl MetaPlugin for UserMetaPlugin { fn is_internal(&self) -> bool { true } fn finalize(&mut self, _conn: &Connection) -> Result<()> { // Since we save during initialize(), return Ok to avoid duplicate saves Ok(()) } fn update(&mut self, _data: &[u8], _conn: &Connection) { // No update needed } fn meta_name(&mut self) -> String { self.meta_name.clone() } fn initialize(&mut self, conn: &Connection, item_id: i64) -> Result<()> { let user = match get_current_username() { Some(username) => username.to_string_lossy().to_string(), None => "unknown".to_string(), }; self.save_meta(conn, item_id, "user", user)?; self.is_saved = true; Ok(()) } fn outputs(&self) -> &std::collections::HashMap { &self.outputs } fn outputs_mut(&mut self) -> &mut std::collections::HashMap { &mut self.outputs } fn default_outputs(&self) -> Vec { vec!["user".to_string()] } fn default_options(&self) -> std::collections::HashMap { std::collections::HashMap::new() } } #[derive(Debug, Clone, Default)] pub struct GidMetaPlugin { meta_name: String, is_saved: bool, outputs: std::collections::HashMap, } impl GidMetaPlugin { pub fn new( _options: Option>, outputs: Option>, ) -> GidMetaPlugin { // Start with default outputs let mut final_outputs = std::collections::HashMap::new(); let default_outputs = Self::default().default_outputs(); for output_name in default_outputs { final_outputs.insert(output_name.clone(), serde_yaml::Value::String(output_name)); } if let Some(outs) = outputs { for (key, value) in outs { final_outputs.insert(key, value); } } GidMetaPlugin { meta_name: "gid".to_string(), is_saved: false, outputs: final_outputs, } } pub fn new_simple() -> GidMetaPlugin { Self::new(None, None) } } impl MetaPlugin for GidMetaPlugin { fn is_internal(&self) -> bool { true } fn finalize(&mut self, _conn: &Connection) -> Result<()> { // Since we save during initialize(), return Ok to avoid duplicate saves Ok(()) } fn update(&mut self, _data: &[u8], _conn: &Connection) { // No update needed } fn meta_name(&mut self) -> String { self.meta_name.clone() } fn initialize(&mut self, conn: &Connection, item_id: i64) -> Result<()> { let gid = get_current_gid().to_string(); self.save_meta(conn, item_id, "gid", gid)?; self.is_saved = true; Ok(()) } fn outputs(&self) -> &std::collections::HashMap { &self.outputs } fn outputs_mut(&mut self) -> &mut std::collections::HashMap { &mut self.outputs } fn default_outputs(&self) -> Vec { vec!["gid".to_string()] } fn default_options(&self) -> std::collections::HashMap { std::collections::HashMap::new() } } #[derive(Debug, Clone, Default)] pub struct GroupMetaPlugin { meta_name: String, is_saved: bool, outputs: std::collections::HashMap, } impl GroupMetaPlugin { pub fn new( _options: Option>, outputs: Option>, ) -> GroupMetaPlugin { // Start with default outputs let mut final_outputs = std::collections::HashMap::new(); let default_outputs = Self::default().default_outputs(); for output_name in default_outputs { final_outputs.insert(output_name.clone(), serde_yaml::Value::String(output_name)); } if let Some(outs) = outputs { for (key, value) in outs { final_outputs.insert(key, value); } } GroupMetaPlugin { meta_name: "group".to_string(), is_saved: false, outputs: final_outputs, } } pub fn new_simple() -> GroupMetaPlugin { Self::new(None, None) } } impl MetaPlugin for GroupMetaPlugin { fn is_internal(&self) -> bool { true } fn finalize(&mut self, _conn: &Connection) -> Result<()> { // Since we save during initialize(), return Ok to avoid duplicate saves Ok(()) } fn update(&mut self, _data: &[u8], _conn: &Connection) { // No update needed } fn meta_name(&mut self) -> String { self.meta_name.clone() } fn initialize(&mut self, conn: &Connection, item_id: i64) -> Result<()> { let group = match get_current_groupname() { Some(groupname) => groupname.to_string_lossy().to_string(), None => "unknown".to_string(), }; self.save_meta(conn, item_id, "group", group)?; self.is_saved = true; Ok(()) } fn outputs(&self) -> &std::collections::HashMap { &self.outputs } fn outputs_mut(&mut self) -> &mut std::collections::HashMap { &mut self.outputs } fn default_outputs(&self) -> Vec { vec!["group".to_string()] } fn default_options(&self) -> std::collections::HashMap { std::collections::HashMap::new() } } #[derive(Debug, Clone, Default)] pub struct ShellMetaPlugin { meta_name: String, is_saved: bool, outputs: std::collections::HashMap, } impl ShellMetaPlugin { pub fn new( _options: Option>, outputs: Option>, ) -> ShellMetaPlugin { // Start with default outputs let mut final_outputs = std::collections::HashMap::new(); let default_outputs = Self::default().default_outputs(); for output_name in default_outputs { final_outputs.insert(output_name.clone(), serde_yaml::Value::String(output_name)); } if let Some(outs) = outputs { for (key, value) in outs { final_outputs.insert(key, value); } } ShellMetaPlugin { meta_name: "shell".to_string(), is_saved: false, outputs: final_outputs, } } pub fn new_simple() -> ShellMetaPlugin { Self::new(None, None) } } impl MetaPlugin for ShellMetaPlugin { fn is_internal(&self) -> bool { true } fn finalize(&mut self, _conn: &Connection) -> Result<()> { // Since we save during initialize(), return Ok to avoid duplicate saves Ok(()) } fn update(&mut self, _data: &[u8], _conn: &Connection) { // No update needed } fn meta_name(&mut self) -> String { self.meta_name.clone() } fn initialize(&mut self, conn: &Connection, item_id: i64) -> Result<()> { let shell = match env::var("SHELL") { Ok(shell) => shell, Err(_) => "unknown".to_string(), }; self.save_meta(conn, item_id, "shell", shell)?; self.is_saved = true; Ok(()) } fn outputs(&self) -> &std::collections::HashMap { &self.outputs } fn outputs_mut(&mut self) -> &mut std::collections::HashMap { &mut self.outputs } fn default_outputs(&self) -> Vec { vec!["shell".to_string()] } fn default_options(&self) -> std::collections::HashMap { std::collections::HashMap::new() } } #[derive(Debug, Clone, Default)] pub struct ShellPidMetaPlugin { meta_name: String, is_saved: bool, outputs: std::collections::HashMap, } impl ShellPidMetaPlugin { pub fn new( _options: Option>, outputs: Option>, ) -> ShellPidMetaPlugin { // Start with default outputs let mut final_outputs = std::collections::HashMap::new(); let default_outputs = Self::default().default_outputs(); for output_name in default_outputs { final_outputs.insert(output_name.clone(), serde_yaml::Value::String(output_name)); } if let Some(outs) = outputs { for (key, value) in outs { final_outputs.insert(key, value); } } ShellPidMetaPlugin { meta_name: "shell_pid".to_string(), is_saved: false, outputs: final_outputs, } } pub fn new_simple() -> ShellPidMetaPlugin { Self::new(None, None) } } impl MetaPlugin for ShellPidMetaPlugin { fn is_internal(&self) -> bool { true } fn finalize(&mut self, _conn: &Connection) -> Result<()> { // Since we save during initialize(), return Ok to avoid duplicate saves Ok(()) } fn update(&mut self, _data: &[u8], _conn: &Connection) { // No update needed } fn meta_name(&mut self) -> String { self.meta_name.clone() } fn initialize(&mut self, conn: &Connection, item_id: i64) -> Result<()> { let pid = match env::var("PPID") { Ok(ppid) => ppid, Err(_) => process::id().to_string(), }; self.save_meta(conn, item_id, "shell_pid", pid)?; self.is_saved = true; Ok(()) } fn outputs(&self) -> &std::collections::HashMap { &self.outputs } fn outputs_mut(&mut self) -> &mut std::collections::HashMap { &mut self.outputs } fn default_outputs(&self) -> Vec { vec!["shell_pid".to_string()] } fn default_options(&self) -> std::collections::HashMap { std::collections::HashMap::new() } } #[derive(Debug, Clone, Default)] pub struct KeepPidMetaPlugin { meta_name: String, is_saved: bool, outputs: std::collections::HashMap, } impl KeepPidMetaPlugin { pub fn new( _options: Option>, outputs: Option>, ) -> KeepPidMetaPlugin { // Start with default outputs let mut final_outputs = std::collections::HashMap::new(); let default_outputs = Self::default().default_outputs(); for output_name in default_outputs { final_outputs.insert(output_name.clone(), serde_yaml::Value::String(output_name)); } if let Some(outs) = outputs { for (key, value) in outs { final_outputs.insert(key, value); } } KeepPidMetaPlugin { meta_name: "keep_pid".to_string(), is_saved: false, outputs: final_outputs, } } pub fn new_simple() -> KeepPidMetaPlugin { Self::new(None, None) } } impl MetaPlugin for KeepPidMetaPlugin { fn is_internal(&self) -> bool { true } fn finalize(&mut self, _conn: &Connection) -> Result<()> { // Since we save during initialize(), return Ok to avoid duplicate saves Ok(()) } fn update(&mut self, _data: &[u8], _conn: &Connection) { // No update needed } fn meta_name(&mut self) -> String { self.meta_name.clone() } fn initialize(&mut self, conn: &Connection, item_id: i64) -> Result<()> { let pid = process::id().to_string(); self.save_meta(conn, item_id, "keep_pid", pid)?; self.is_saved = true; Ok(()) } fn outputs(&self) -> &std::collections::HashMap { &self.outputs } fn outputs_mut(&mut self) -> &mut std::collections::HashMap { &mut self.outputs } fn default_outputs(&self) -> Vec { vec!["keep_pid".to_string()] } fn default_options(&self) -> std::collections::HashMap { std::collections::HashMap::new() } } #[derive(Debug, Clone, Default)] pub struct HostnameMetaPlugin { meta_name: String, is_saved: bool, outputs: std::collections::HashMap, } impl HostnameMetaPlugin { pub fn new( _options: Option>, outputs: Option>, ) -> HostnameMetaPlugin { // Start with default outputs let mut final_outputs = std::collections::HashMap::new(); let default_outputs = Self::default().default_outputs(); for output_name in default_outputs { final_outputs.insert(output_name.clone(), serde_yaml::Value::String(output_name)); } if let Some(outs) = outputs { for (key, value) in outs { final_outputs.insert(key, value); } } HostnameMetaPlugin { meta_name: "hostname".to_string(), is_saved: false, outputs: final_outputs, } } pub fn new_simple() -> HostnameMetaPlugin { Self::new(None, None) } } impl MetaPlugin for HostnameMetaPlugin { fn is_internal(&self) -> bool { true } fn finalize(&mut self, _conn: &Connection) -> Result<()> { // Since we save during initialize(), return Ok to avoid duplicate saves Ok(()) } fn update(&mut self, _data: &[u8], _conn: &Connection) { // No update needed for hostname } fn meta_name(&mut self) -> String { self.meta_name.clone() } fn initialize(&mut self, conn: &Connection, item_id: i64) -> Result<()> { let hostname = match gethostname().into_string() { Ok(hostname) => hostname, Err(_) => "unknown".to_string(), }; self.save_meta(conn, item_id, "hostname", hostname)?; self.is_saved = true; Ok(()) } fn outputs(&self) -> &std::collections::HashMap { &self.outputs } fn outputs_mut(&mut self) -> &mut std::collections::HashMap { &mut self.outputs } fn default_outputs(&self) -> Vec { vec!["hostname".to_string()] } fn default_options(&self) -> std::collections::HashMap { std::collections::HashMap::new() } } #[derive(Debug, Clone, Default)] pub struct FullHostnameMetaPlugin { meta_name: String, is_saved: bool, outputs: std::collections::HashMap, } impl FullHostnameMetaPlugin { pub fn new( _options: Option>, outputs: Option>, ) -> FullHostnameMetaPlugin { // Start with default outputs let mut final_outputs = std::collections::HashMap::new(); let default_outputs = Self::default().default_outputs(); for output_name in default_outputs { final_outputs.insert(output_name.clone(), serde_yaml::Value::String(output_name)); } if let Some(outs) = outputs { for (key, value) in outs { final_outputs.insert(key, value); } } FullHostnameMetaPlugin { meta_name: "full_hostname".to_string(), is_saved: false, outputs: final_outputs, } } pub fn new_simple() -> FullHostnameMetaPlugin { Self::new(None, None) } } impl MetaPlugin for FullHostnameMetaPlugin { fn is_internal(&self) -> bool { true } fn finalize(&mut self, _conn: &Connection) -> Result<()> { // Since we save during initialize(), return Ok to avoid duplicate saves Ok(()) } fn update(&mut self, _data: &[u8], _conn: &Connection) { // No update needed for full hostname } fn meta_name(&mut self) -> String { self.meta_name.clone() } fn initialize(&mut self, conn: &Connection, item_id: i64) -> Result<()> { // Try to get the FQDN through reverse DNS lookup let hostname = match local_ip() { Ok(my_local_ip) => { match lookup_addr(&my_local_ip) { Ok(hostname) => hostname, Err(_) => { // Fall back to regular hostname if reverse DNS fails match gethostname().into_string() { Ok(hostname) => hostname, Err(_) => "unknown".to_string(), } } } } Err(_) => { // Fall back to regular hostname if we can't get local IP match gethostname().into_string() { Ok(hostname) => hostname, Err(_) => "unknown".to_string(), } } }; self.save_meta(conn, item_id, "full_hostname", hostname)?; self.is_saved = true; Ok(()) } fn outputs(&self) -> &std::collections::HashMap { &self.outputs } fn outputs_mut(&mut self) -> &mut std::collections::HashMap { &mut self.outputs } fn default_outputs(&self) -> Vec { vec!["full_hostname".to_string()] } fn default_options(&self) -> std::collections::HashMap { std::collections::HashMap::new() } }