Skip to main content

sz_rust_capability/
facade.rs

1use std::sync::{Arc, OnceLock};
2
3use crate::capability::Capability;
4use crate::error::{CapError, CapResult};
5use crate::metrics::CapMetrics;
6use crate::permission::PermissionChecker;
7use crate::registry::CapabilityRegistry;
8use crate::source::CapabilitySource;
9
10struct CapInstance {
11    registry: Arc<CapabilityRegistry>,
12}
13
14static GLOBAL: OnceLock<CapInstance> = OnceLock::new();
15
16/// Capability Registry 全局 facade,对齐 `Ai` facade 模式。
17///
18/// 使用 `OnceLock<CapInstance>` 全局单例,所有静态方法通过 `instance()` 获取后委托给内部 [`CapabilityRegistry`]。
19///
20/// # 使用方式
21///
22/// ```no_run
23/// use sz_rust_capability::Cap;
24///
25/// Cap::init().ok(); // 初始化(仅需一次)
26/// let metrics = Cap::metrics().unwrap();
27/// ```
28pub struct Cap;
29
30impl Cap {
31    /// 使用外部 registry 初始化全局 facade(与调用方共享同一实例)
32    ///
33    /// 业务应用(如 sz300)持有自己的 `Arc<CapabilityRegistry>` 用于注入
34    /// `AppState` 时,应使用本方法而非 [`Cap::init`]——否则全局 facade 与
35    /// 应用局部 registry 是**两个独立实例**,`Cap::register` 注册的能力
36    /// 无法被业务 handler 访问(2026-08-15 双实例缺陷修复)。
37    pub fn init_with(registry: Arc<CapabilityRegistry>) -> CapResult<()> {
38        GLOBAL
39            .set(CapInstance { registry })
40            .map_err(|_| CapError::NotInitialized)
41    }
42
43    pub fn init() -> CapResult<()> {
44        Self::init_with(Arc::new(CapabilityRegistry::new()))
45    }
46
47    pub fn is_initialized() -> bool {
48        GLOBAL.get().is_some()
49    }
50
51    fn instance() -> CapResult<&'static CapInstance> {
52        GLOBAL.get().ok_or(CapError::NotInitialized)
53    }
54
55    pub fn register(cap: Arc<dyn Capability>) -> CapResult<Option<Arc<dyn Capability>>> {
56        Ok(Self::instance()?.registry.register(cap))
57    }
58
59    pub fn unregister(name: &str) -> CapResult<Option<Arc<dyn Capability>>> {
60        Ok(Self::instance()?.registry.unregister(name))
61    }
62
63    pub fn get(name: &str) -> CapResult<Option<Arc<dyn Capability>>> {
64        Ok(Self::instance()?.registry.get(name))
65    }
66
67    pub fn find_by_tags(
68        tags: &[&str],
69        source: Option<CapabilitySource>,
70    ) -> CapResult<Vec<Arc<dyn Capability>>> {
71        Ok(Self::instance()?.registry.find_by_tags(tags, source))
72    }
73
74    pub fn search(query: &str) -> CapResult<Vec<Arc<dyn Capability>>> {
75        Ok(Self::instance()?.registry.search(query))
76    }
77
78    pub fn list_all() -> CapResult<Vec<Arc<dyn Capability>>> {
79        Ok(Self::instance()?.registry.list_all())
80    }
81
82    pub fn list_by_source(source: CapabilitySource) -> CapResult<Vec<Arc<dyn Capability>>> {
83        Ok(Self::instance()?.registry.list_by_source(source))
84    }
85
86    pub async fn call(name: &str, args: serde_json::Value) -> CapResult<serde_json::Value> {
87        Self::instance()?.registry.call(name, args).await
88    }
89
90    /// 调用能力,携带租户上下文用于权限检查。
91    pub async fn call_with_tenant(
92        name: &str,
93        args: serde_json::Value,
94        tenant_id: i64,
95    ) -> CapResult<serde_json::Value> {
96        Self::instance()?
97            .registry
98            .call_with_tenant(name, args, tenant_id)
99            .await
100    }
101
102    /// 设置权限检查器。
103    pub fn set_permission_checker(checker: Arc<dyn PermissionChecker>) -> CapResult<()> {
104        Self::instance()?.registry.set_permission_checker(checker);
105        Ok(())
106    }
107
108    pub fn metrics() -> CapResult<CapMetrics> {
109        Ok(Self::instance()?.registry.metrics())
110    }
111
112    pub fn len() -> CapResult<usize> {
113        Ok(Self::instance()?.registry.len())
114    }
115
116    pub fn is_empty() -> CapResult<bool> {
117        Ok(Self::instance()?.registry.is_empty())
118    }
119}
120
121#[cfg(test)]
122mod tests {
123    use super::*;
124    use async_trait::async_trait;
125    use serde_json::json;
126
127    struct TestCapability;
128
129    #[async_trait]
130    impl Capability for TestCapability {
131        fn name(&self) -> &'static str {
132            "test_cap"
133        }
134        fn description(&self) -> &'static str {
135            "测试能力"
136        }
137        fn schema(&self) -> serde_json::Value {
138            json!({})
139        }
140        fn tags(&self) -> &[&'static str] {
141            &["test"]
142        }
143        fn source(&self) -> CapabilitySource {
144            CapabilitySource::Skill
145        }
146        async fn call(&self, args: serde_json::Value) -> CapResult<serde_json::Value> {
147            Ok(args)
148        }
149    }
150
151    #[test]
152    fn test_facade_lifecycle() {
153        Cap::init().ok();
154        let cap = Arc::new(TestCapability) as Arc<dyn Capability>;
155        Cap::register(cap).unwrap();
156        assert!(Cap::get("test_cap").unwrap().is_some());
157        assert!(Cap::len().unwrap() >= 1);
158    }
159
160    #[tokio::test]
161    async fn test_call_through_facade() {
162        Cap::init().ok();
163        let cap = Arc::new(TestCapability) as Arc<dyn Capability>;
164        Cap::register(cap).ok();
165        let result = Cap::call("test_cap", json!({"hello": "world"})).await;
166        assert!(result.is_ok());
167    }
168}