From 7f28129c005977aaf720d48751f8eac3541ef78e Mon Sep 17 00:00:00 2001 From: Andrew Phillips Date: Mon, 18 Aug 2025 10:51:58 -0300 Subject: [PATCH] feat: add central metadata output handler Co-authored-by: aider (openai/andrew/openrouter/qwen/qwen3-coder) --- src/meta_plugin.rs | 25 +++++++++++++------- src/meta_plugin/digest.rs | 21 ++++++----------- src/meta_plugin/magic.rs | 23 ++++-------------- src/meta_plugin/system.rs | 49 +++++++++++++++++++++++++++++---------- 4 files changed, 64 insertions(+), 54 deletions(-) diff --git a/src/meta_plugin.rs b/src/meta_plugin.rs index 17bc624..800ce29 100644 --- a/src/meta_plugin.rs +++ b/src/meta_plugin.rs @@ -38,6 +38,19 @@ pub enum MetaPluginType { FullHostname, } +/// Central function to handle metadata output with name mapping +pub fn output_metadata(conn: &Connection, item_id: i64, name: &str, value: String, output_names: &std::collections::HashMap) -> Result<()> { + let output_name = output_names.get(name).cloned().unwrap_or_else(|| name.to_string()); + debug!("META: Saving metadata: item_id={}, name={}, value={}", item_id, output_name, value); + let meta = crate::db::Meta { + id: item_id, + name: output_name, + value, + }; + crate::db::store_meta(conn, meta)?; + Ok(()) +} + pub trait MetaPlugin { fn is_supported(&self) -> bool { true @@ -64,17 +77,11 @@ pub trait MetaPlugin { Ok(()) } - // Save metadata to database + // Save metadata to database using central output handler fn save_meta(&mut self, conn: &Connection, item_id: i64, value: String) -> Result<()> { let meta_name = self.meta_name(); - debug!("META: Saving metadata: item_id={}, name={}, value={}", item_id, meta_name, value); - let meta = crate::db::Meta { - id: item_id, - name: meta_name, - value, - }; - crate::db::store_meta(conn, meta)?; - Ok(()) + // Default implementation: no output name mapping + output_metadata(conn, item_id, &meta_name, value, &std::collections::HashMap::new()) } // Configure plugin with options diff --git a/src/meta_plugin/digest.rs b/src/meta_plugin/digest.rs index d5bdbf7..ecb6c9b 100644 --- a/src/meta_plugin/digest.rs +++ b/src/meta_plugin/digest.rs @@ -3,7 +3,7 @@ use sha2::{Digest, Sha256}; use std::time::Instant; use rusqlite::Connection; -use crate::meta_plugin::MetaPlugin; +use crate::meta_plugin::{MetaPlugin, output_metadata}; #[derive(Debug, Clone, Default)] pub struct DigestSha256MetaPlugin { @@ -11,7 +11,7 @@ pub struct DigestSha256MetaPlugin { meta_name: String, item_id: Option, conn: Option<*mut Connection>, - output_name: Option, + output_names: std::collections::HashMap, } impl DigestSha256MetaPlugin { @@ -21,7 +21,7 @@ impl DigestSha256MetaPlugin { meta_name: "digest_sha256".to_string(), item_id: None, conn: None, - output_name: None, + output_names: std::collections::HashMap::new(), } } } @@ -47,13 +47,8 @@ impl MetaPlugin for DigestSha256MetaPlugin { let hash_result = self.hasher.finalize_reset(); let hex_string = format!("{:x}", hash_result); - // Save the hash as metadata - let meta = crate::db::Meta { - id: item_id, - name: self.get_output_name(&self.meta_name), - value: hex_string, - }; - crate::db::store_meta(conn_ref, meta)?; + // Save the hash as metadata using central output handler + let _ = output_metadata(conn_ref, item_id, &self.meta_name, hex_string, &self.output_names); } Ok(()) } @@ -71,9 +66,7 @@ impl MetaPlugin for DigestSha256MetaPlugin { if let Some(outputs_map) = outputs.as_mapping() { for (key, value) in outputs_map { if let (Some(key_str), Some(value_str)) = (key.as_str(), value.as_str()) { - if key_str == "digest_sha256" { - self.output_name = Some(value_str.to_string()); - } + self.output_names.insert(key_str.to_string(), value_str.to_string()); } } } @@ -82,7 +75,7 @@ impl MetaPlugin for DigestSha256MetaPlugin { } fn get_output_name(&self, default_name: &str) -> String { - self.output_name.clone().unwrap_or_else(|| default_name.to_string()) + self.output_names.get(default_name).cloned().unwrap_or_else(|| default_name.to_string()) } } diff --git a/src/meta_plugin/magic.rs b/src/meta_plugin/magic.rs index 14d1e7f..64553db 100644 --- a/src/meta_plugin/magic.rs +++ b/src/meta_plugin/magic.rs @@ -3,7 +3,7 @@ use magic::{Cookie, CookieFlags}; use rusqlite::Connection; use std::io; -use crate::meta_plugin::MetaPlugin; +use crate::meta_plugin::{MetaPlugin, output_metadata}; #[derive(Debug)] pub struct MagicFileMetaPlugin { @@ -64,36 +64,21 @@ impl MagicFileMetaPlugin { // Save file type if let Ok(file_type) = self.get_magic_result(CookieFlags::empty()) { if !file_type.is_empty() { - let meta = crate::db::Meta { - id: item_id, - name: self.get_output_name("file_type"), - value: file_type, - }; - let _ = crate::db::store_meta(conn_ref, meta); + let _ = output_metadata(conn_ref, item_id, "file_type", file_type, &self.output_names); } } // Save MIME type if let Ok(mime_type) = self.get_magic_result(CookieFlags::MIME_TYPE) { if !mime_type.is_empty() { - let meta = crate::db::Meta { - id: item_id, - name: self.get_output_name("mime_type"), - value: mime_type, - }; - let _ = crate::db::store_meta(conn_ref, meta); + let _ = output_metadata(conn_ref, item_id, "mime_type", mime_type, &self.output_names); } } // Save MIME encoding if let Ok(mime_encoding) = self.get_magic_result(CookieFlags::MIME_ENCODING) { if !mime_encoding.is_empty() { - let meta = crate::db::Meta { - id: item_id, - name: self.get_output_name("mime_encoding"), - value: mime_encoding, - }; - let _ = crate::db::store_meta(conn_ref, meta); + let _ = output_metadata(conn_ref, item_id, "mime_encoding", mime_encoding, &self.output_names); } } diff --git a/src/meta_plugin/system.rs b/src/meta_plugin/system.rs index c47ec07..e12b4b1 100644 --- a/src/meta_plugin/system.rs +++ b/src/meta_plugin/system.rs @@ -8,12 +8,13 @@ use uzers::{get_current_uid, get_current_gid, get_current_username, get_current_ use rusqlite::Connection; use crate::common::is_binary::is_binary; -use crate::meta_plugin::MetaPlugin; +use crate::meta_plugin::{MetaPlugin, output_metadata}; #[derive(Debug, Clone, Default)] pub struct CwdMetaPlugin { meta_name: String, is_saved: bool, + output_names: std::collections::HashMap, } #[derive(Debug, Clone, Default)] @@ -24,7 +25,7 @@ pub struct BinaryMetaPlugin { is_saved: bool, item_id: Option, conn: Option<*mut Connection>, - output_name: Option, + output_names: std::collections::HashMap, } impl BinaryMetaPlugin { @@ -36,7 +37,7 @@ impl BinaryMetaPlugin { is_saved: false, item_id: None, conn: None, - output_name: None, + output_names: std::collections::HashMap::new(), } } @@ -67,13 +68,8 @@ impl MetaPlugin for BinaryMetaPlugin { let is_binary = is_binary(&self.buffer); let value = if is_binary { "true".to_string() } else { "false".to_string() }; - // Save to database immediately - let meta = crate::db::Meta { - id: item_id, - name: self.get_output_name(&self.meta_name), - value, - }; - let _ = crate::db::store_meta(conn_ref, meta); + // Save to database immediately using central output handler + let _ = output_metadata(conn_ref, item_id, &self.meta_name, value, &self.output_names); self.is_saved = true; } @@ -98,11 +94,21 @@ impl MetaPlugin for BinaryMetaPlugin { self.max_buffer_size = size as usize; } } + + if let Some(outputs) = options.get("outputs") { + if let Some(outputs_map) = outputs.as_mapping() { + for (key, value) in outputs_map { + if let (Some(key_str), Some(value_str)) = (key.as_str(), value.as_str()) { + self.output_names.insert(key_str.to_string(), value_str.to_string()); + } + } + } + } Ok(()) } fn get_output_name(&self, default_name: &str) -> String { - self.output_name.clone().unwrap_or_else(|| default_name.to_string()) + self.output_names.get(default_name).cloned().unwrap_or_else(|| default_name.to_string()) } } @@ -111,6 +117,7 @@ impl CwdMetaPlugin { CwdMetaPlugin { meta_name: "cwd".to_string(), is_saved: false, + output_names: std::collections::HashMap::new(), } } } @@ -138,10 +145,28 @@ impl MetaPlugin for CwdMetaPlugin { Ok(path) => path.to_string_lossy().to_string(), Err(_) => "unknown".to_string(), }; - self.save_meta(conn, item_id, cwd)?; + // Use central output handler + output_metadata(conn, item_id, &self.meta_name, cwd, &self.output_names)?; self.is_saved = true; Ok(()) } + + fn configure(&mut self, options: &std::collections::HashMap) -> Result<()> { + if let Some(outputs) = options.get("outputs") { + if let Some(outputs_map) = outputs.as_mapping() { + for (key, value) in outputs_map { + if let (Some(key_str), Some(value_str)) = (key.as_str(), value.as_str()) { + self.output_names.insert(key_str.to_string(), value_str.to_string()); + } + } + } + } + Ok(()) + } + + fn get_output_name(&self, default_name: &str) -> String { + self.output_names.get(default_name).cloned().unwrap_or_else(|| default_name.to_string()) + } } #[derive(Debug, Clone, Default)]