confium_daemon/methods/plugin.rs
1//! Plugin lifecycle methods: `plugin_load`, `plugin_unload`, `plugin_list`.
2
3use std::collections::HashMap;
4use std::path::PathBuf;
5
6use serde::Deserialize;
7use serde_json::{Value, json};
8
9use crate::error::RpcError;
10use crate::server::SharedConfium;
11
12/// `plugin_load({ "path": "...", "name": "botan", "options": {} })`
13/// → `{"success": true}`
14///
15/// Delegates to [`Confium::load_plugin`]. The options map is passed
16/// through as a string-keyed map (matching the C FFI's `Options` type,
17/// which is `HashMap<String, String>` today).
18///
19/// `name` is accepted for API parity with the C FFI's
20/// `cfm_plugin_load(cfm, name, path, opts)` but is not yet forwarded
21/// to the core (the core stub derives the name from the path). When
22/// the core accepts an explicit name, this handler will pass it
23/// through unchanged.
24#[derive(Deserialize)]
25#[allow(dead_code)]
26struct PluginLoadParams {
27 path: String,
28 name: String,
29 #[serde(default)]
30 options: HashMap<String, String>,
31}
32
33pub async fn plugin_load(
34 cfm: SharedConfium,
35 params: Value,
36) -> std::result::Result<Value, RpcError> {
37 let p: PluginLoadParams =
38 serde_json::from_value(params).map_err(|e| RpcError::InvalidParams {
39 detail: e.to_string(),
40 })?;
41
42 let mut cfm = cfm.borrow_mut();
43 cfm.load_plugin(&PathBuf::from(&p.path), &p.options)
44 .map_err(|e| RpcError::Engine {
45 message: e.to_string(),
46 })?;
47
48 Ok(json!({ "success": true }))
49}
50
51/// `plugin_unload({ "name": "botan" })` → `{"success": true}`
52///
53/// The core `unload` path is not yet implemented (the FFI is a stub),
54/// so this handler returns the engine's "not implemented" error. When
55/// the core lands, the handler becomes a one-line adapter.
56pub async fn plugin_unload(
57 _cfm: SharedConfium,
58 _params: Value,
59) -> std::result::Result<Value, RpcError> {
60 Err(RpcError::Engine {
61 message: "plugin_unload is not yet implemented in confium-core".to_string(),
62 })
63}
64
65/// `plugin_list()` → `{"plugins": [{"name": "botan"}, ...]}`
66///
67/// Lists the providers currently registered on the owned Confium. The
68/// core's `providers` field is private, so we return an empty list
69/// today; once a public accessor lands, this will return the full list
70/// with metadata.
71pub async fn plugin_list(
72 _cfm: SharedConfium,
73 _params: Value,
74) -> std::result::Result<Value, RpcError> {
75 // The providers vector is private in confium-core; we can't
76 // enumerate it without a public accessor. Return an empty list
77 // as a placeholder — the shape is stable for clients.
78 Ok(json!({ "plugins": [] }))
79}
80
81#[cfg(test)]
82mod tests {
83 use super::*;
84 use crate::test_util::test_confium;
85
86 #[tokio::test]
87 async fn plugin_list_returns_array() {
88 let result = plugin_list(test_confium(), json!({})).await.unwrap();
89 assert!(result.get("plugins").unwrap().is_array());
90 }
91}