secra_memory/
plugin.rs

1use async_trait::async_trait;
2use serde::Serialize;
3use serde::de::DeserializeOwned;
4/// PluginMemoryCache 实现
5use std::sync::Arc;
6use std::time::Duration;
7
8use crate::error::CacheError;
9use crate::cache::Cache;
10use super::manager::MemoryManager;
11
12/// Key 最大长度限制
13const MAX_KEY_LENGTH: usize = 200;
14
15/// 插件内存缓存实例
16///
17/// 每个插件拥有一个独立的 PluginMemoryCache 实例,所有操作自动添加命名空间前缀
18pub struct PluginMemoryCache {
19    /// MemoryManager 引用
20    manager: Arc<MemoryManager>,
21
22    /// 插件 ID
23    plugin_id: String,
24
25    /// 命名空间前缀
26    namespace: String,
27}
28
29impl PluginMemoryCache {
30    /// 创建新的 PluginMemoryCache 实例
31    ///
32    /// # Arguments
33    /// * `manager` - MemoryManager 引用
34    /// * `plugin_id` - 插件 ID
35    ///
36    /// # Returns
37    /// * `Self` - PluginMemoryCache 实例
38    pub(crate) fn new(manager: Arc<MemoryManager>, plugin_id: String) -> Self {
39        // 优化:预分配容量,使用 push_str 比 format! 更快
40        let system_name = manager.system_name();
41        let capacity = system_name.len() + plugin_id.len() + 9; // "plugin::" = 9 chars
42        let mut namespace = String::with_capacity(capacity);
43        namespace.push_str(system_name);
44        namespace.push_str(":plugin:");
45        namespace.push_str(&plugin_id);
46        namespace.push(':');
47        
48        Self {
49            manager,
50            plugin_id,
51            namespace,
52        }
53    }
54
55    /// 构建完整的 Key(添加命名空间前缀)
56    /// 优化:使用 String::with_capacity 预分配容量,减少内存分配
57    fn build_key(&self, business_key: &str) -> Result<String, CacheError> {
58        // 验证业务 Key 格式
59        self.validate_business_key(business_key)?;
60
61        // 优化:预分配容量,避免多次分配,使用 push_str 比 format! 更快
62        let capacity = self.namespace.len() + business_key.len();
63        let mut full_key = String::with_capacity(capacity);
64        full_key.push_str(&self.namespace);
65        full_key.push_str(business_key);
66        Ok(full_key)
67    }
68
69    /// 验证业务 Key 格式
70    /// 优化:提前返回,减少不必要的检查,使用更高效的验证方法
71    fn validate_business_key(&self, key: &str) -> Result<(), CacheError> {
72        // 1. 不能为空(最快检查,优先执行)
73        if key.is_empty() {
74            return Err(CacheError::InvalidKey("Key 不能为空".to_string()));
75        }
76
77        // 2. 长度限制(快速检查,避免后续复杂操作)
78        if key.len() > MAX_KEY_LENGTH {
79            return Err(CacheError::InvalidKey(
80                format!("Key 长度不能超过 {} 字符", MAX_KEY_LENGTH),
81            ));
82        }
83
84        // 3. 不能包含命名空间分隔符(防止绕过隔离)
85        // 优化:使用字节查找,比字符串 contains 更快
86        if key.as_bytes().windows(7).any(|w| w == b"plugin:") {
87            return Err(CacheError::InvalidKey(
88                "Key 不能包含命名空间前缀".to_string(),
89            ));
90        }
91
92        // 4. 字符限制(只允许字母、数字、下划线、连字符、冒号)
93        // 优化:使用字节检查,比字符迭代更快,使用 match 可能更快
94        if !key.as_bytes().iter().all(|&b| {
95            matches!(b, b'a'..=b'z' | b'A'..=b'Z' | b'0'..=b'9' | b'_' | b'-' | b':')
96        }) {
97            return Err(CacheError::InvalidKey(
98                "Key 包含非法字符,只允许字母、数字、下划线、连字符、冒号".to_string(),
99            ));
100        }
101
102        Ok(())
103    }
104
105    /// 验证权限(确保只能操作自己的 Key)
106    fn verify_permission(&self, full_key: &str) -> Result<(), CacheError> {
107        if !full_key.starts_with(&self.namespace) {
108            return Err(CacheError::PermissionDenied(
109                "Key 不属于当前插件".to_string(),
110            ));
111        }
112        Ok(())
113    }
114}
115
116#[async_trait]
117impl Cache for PluginMemoryCache {
118    async fn get<T>(&self, key: &str) -> Result<Option<T>, CacheError>
119    where
120        T: DeserializeOwned,
121    {
122        let full_key = self.build_key(key)?;
123        let cache = self.manager.get_cache();
124
125        // 从内存缓存获取值
126        let json_value = cache.get(&full_key).await;
127
128        // 反序列化
129        // 优化:使用 from_slice 可能更快,但需要先转换为 &[u8]
130        // 当前保持 from_str 以保证代码简洁性
131        match json_value {
132            Some(json) => {
133                let value: T = serde_json::from_str(&json)
134                    .map_err(|e| CacheError::DeserializationFailed(e.to_string()))?;
135                Ok(Some(value))
136            }
137            None => Ok(None),
138        }
139    }
140
141    async fn set<T>(&self, key: &str, value: &T, _ttl: Option<Duration>) -> Result<(), CacheError>
142    where
143        T: Serialize + Sync,
144    {
145        // 优化:先构建 key,避免序列化失败后浪费计算
146        let full_key = self.build_key(key)?;
147        
148        // 优化:使用 to_vec 然后转换为 String,或者直接使用 to_string
149        // 对于大对象,可以考虑使用更快的序列化格式(如 bincode),但会失去可读性
150        // 当前保持 JSON 格式以保证兼容性和可调试性
151        let json_value = serde_json::to_string(value)
152            .map_err(|e| CacheError::SerializationFailed(e.to_string()))?;
153
154        let cache = self.manager.get_cache();
155
156        // moka 的 future::Cache 不支持在 insert 时指定 TTL
157        // 我们使用全局 TTL 配置,忽略传入的 ttl 参数
158        // 注意:如果需要支持每个条目独立的 TTL,需要实现 Expiry trait
159        // 优化:避免不必要的克隆,insert 会获取所有权
160        cache.insert(full_key.clone(), json_value).await;
161
162        // 更新索引(优化:DashMap 操作是同步的)
163        self.manager
164            .add_key_to_index(&self.plugin_id, &full_key);
165
166        Ok(())
167    }
168
169    async fn delete(&self, key: &str) -> Result<bool, CacheError> {
170        let full_key = self.build_key(key)?;
171
172        // 验证权限
173        self.verify_permission(&full_key)?;
174
175        let cache = self.manager.get_cache();
176
177        // 删除 Key
178        let deleted = cache.remove(&full_key).await.is_some();
179
180        // 从索引中移除(优化:DashMap 操作是同步的,无需 await)
181        if deleted {
182            self.manager
183                .remove_key_from_index(&self.plugin_id, &full_key);
184        }
185
186        Ok(deleted)
187    }
188
189    async fn exists(&self, key: &str) -> Result<bool, CacheError> {
190        let full_key = self.build_key(key)?;
191        let cache = self.manager.get_cache();
192
193        // 通过 get 方法检查 Key 是否存在(避免使用同步的 contains_key)
194        let exists = cache.get(&full_key).await.is_some();
195
196        Ok(exists)
197    }
198
199    async fn expire(&self, key: &str, _ttl: Duration) -> Result<bool, CacheError> {
200        let full_key = self.build_key(key)?;
201        let cache = self.manager.get_cache();
202
203        // moka 的 future::Cache 不支持直接更新 TTL
204        // 我们通过重新插入来"续期"(使用全局 TTL 配置)
205        // 获取当前值并重新插入
206        if let Some(value) = cache.get(&full_key).await {
207            cache.insert(full_key, value).await;
208            Ok(true)
209        } else {
210            Ok(false)
211        }
212    }
213
214    async fn ttl(&self, key: &str) -> Result<Option<Duration>, CacheError> {
215        let full_key = self.build_key(key)?;
216        let cache = self.manager.get_cache();
217
218        // moka 不直接支持获取剩余 TTL,返回 None 表示存在但无法获取精确时间
219        // 或者可以通过其他方式实现(如维护一个 TTL 映射表)
220        // 这里简化处理:通过 get 检查 Key 是否存在
221        if cache.get(&full_key).await.is_some() {
222            // moka 不支持直接获取 TTL,返回 None 表示存在但无法确定剩余时间
223            Ok(None)
224        } else {
225            Ok(None) // Key 不存在
226        }
227    }
228
229    async fn clear(&self) -> Result<u64, CacheError> {
230        // 清理当前插件的所有缓存
231        self.manager.clear_plugin(&self.plugin_id).await
232    }
233
234    async fn clear_module(&self, module: &str) -> Result<u64, CacheError> {
235        // 清理当前插件的指定模块缓存
236        self.manager.clear_module(&self.plugin_id, module).await
237    }
238}