fix: implement all 24 FIX_PLAN issues across 6 phases
Phase 1 — Critical Safety: - #11: bounded IPC reads via read_bounded_line (server + client) - #13: sound Send+Sync via Arc<Mutex<RuntimeHandle>>; remove unsafe impl Sync - #10: ItemSource enum (Core/NativePlugin/ScriptPlugin) on LaunchItem; script plugin allowlist guard in launch_item() Phase 2 — Config System Overhaul: - #6: remove dead enabled_plugins field - #1: replace #[serde(flatten)] with explicit Config::plugin_config - #4: Server.config Arc<RwLock<Config>>; ConfigProvider shares same Arc - #2/#3: atomic config save (temp+rename); TOCTOU fixed — write lock held across mutation and save() in config_editor - #23: fs2 lock_exclusive() on .lock sidecar file in Config::save() - #16: SIGHUP handler reloads config; ExecReload in systemd service Phase 3 — Plugin Architecture: - #7: HostAPI v4 with get_config_string/int/bool; PLUGIN_CONFIG OnceLock in native_loader, set_shared_config() called from Server::bind() - #5: PluginEntry + Request::PluginList + Response::PluginList; plugin_registry in ProviderManager tracks active and suppressed native plugins; cmd_list_installed shows both script and native plugins - #9: suppressed native plugin log level info! → warn! - #8: ProviderType doc glossary; plugins/mod.rs terminology table Phase 4 — Data Integrity: - #12: all into_inner() in server.rs + providers/mod.rs → explicit Response::Error; watcher exits on poisoned lock - #14: FrecencyStore::prune() (180-day age + 5000-entry cap) called on load - #17: empty command guard in launch_item(); warn in lua_provider - #24: 5-min periodic frecency save thread; SIGTERM/SIGINT saves frecency before exit (replaces ctrlc handler) Phase 5 — UI & UX: - #19: provider_meta.rs ProviderMeta + meta_for(); three match blocks collapsed - #18: desktop file dedup via seen_basenames HashSet in ApplicationProvider - #20: search_filtered gains tag_filter param; non-frecency path now filters - #15: widget refresh 5s→10s; skip when user is typing Phase 6 — Hardening: - #22: catch_unwind removed from reload_runtimes(); direct drop() - #21: AtomicUsize + RAII ConnectionGuard; MAX_CONNECTIONS = 16 Deps: add fs2 = "0.4"; remove ctrlc and toml_edit from owlry-core
This commit is contained in:
@@ -33,7 +33,8 @@ pub use abi_stable::std_types::{ROption, RStr, RString, RVec};
|
||||
/// Current plugin API version - plugins must match this
|
||||
/// v2: Added ProviderPosition for widget support
|
||||
/// v3: Added priority field for plugin-declared result ordering
|
||||
pub const API_VERSION: u32 = 3;
|
||||
/// v4: Added get_config_string/int/bool to HostAPI for plugin config access
|
||||
pub const API_VERSION: u32 = 4;
|
||||
|
||||
/// Plugin metadata returned by the info function
|
||||
#[repr(C)]
|
||||
@@ -295,6 +296,18 @@ pub struct HostAPI {
|
||||
|
||||
/// Log a message at error level
|
||||
pub log_error: extern "C" fn(message: RStr<'_>),
|
||||
|
||||
/// Read a string value from this plugin's config section.
|
||||
/// Parameters: plugin_id (the calling plugin's ID), key
|
||||
/// Returns RSome(value) if set, RNone otherwise.
|
||||
pub get_config_string:
|
||||
extern "C" fn(plugin_id: RStr<'_>, key: RStr<'_>) -> ROption<RString>,
|
||||
|
||||
/// Read an integer value from this plugin's config section.
|
||||
pub get_config_int: extern "C" fn(plugin_id: RStr<'_>, key: RStr<'_>) -> ROption<i64>,
|
||||
|
||||
/// Read a boolean value from this plugin's config section.
|
||||
pub get_config_bool: extern "C" fn(plugin_id: RStr<'_>, key: RStr<'_>) -> ROption<bool>,
|
||||
}
|
||||
|
||||
use std::sync::OnceLock;
|
||||
@@ -378,6 +391,30 @@ pub fn log_error(message: &str) {
|
||||
}
|
||||
}
|
||||
|
||||
/// Read a string value from this plugin's config section (convenience wrapper).
|
||||
/// `plugin_id` must match the ID the plugin declares in its `PluginInfo`.
|
||||
pub fn get_config_string(plugin_id: &str, key: &str) -> Option<String> {
|
||||
host_api().and_then(|api| {
|
||||
(api.get_config_string)(RStr::from_str(plugin_id), RStr::from_str(key))
|
||||
.into_option()
|
||||
.map(|s| s.into_string())
|
||||
})
|
||||
}
|
||||
|
||||
/// Read an integer value from this plugin's config section (convenience wrapper).
|
||||
pub fn get_config_int(plugin_id: &str, key: &str) -> Option<i64> {
|
||||
host_api().and_then(|api| {
|
||||
(api.get_config_int)(RStr::from_str(plugin_id), RStr::from_str(key)).into_option()
|
||||
})
|
||||
}
|
||||
|
||||
/// Read a boolean value from this plugin's config section (convenience wrapper).
|
||||
pub fn get_config_bool(plugin_id: &str, key: &str) -> Option<bool> {
|
||||
host_api().and_then(|api| {
|
||||
(api.get_config_bool)(RStr::from_str(plugin_id), RStr::from_str(key)).into_option()
|
||||
})
|
||||
}
|
||||
|
||||
/// Helper macro for defining plugin vtables
|
||||
///
|
||||
/// Usage:
|
||||
|
||||
Reference in New Issue
Block a user