secra_plugins 0.1.32

生产级插件系统 - 插件的生命周期
Documentation
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
//! 插件元数据定义

use serde::{Deserialize, Serialize};

/// 插件元数据
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct PluginMetadata {
    /// 插件 ID(唯一标识)
    pub id: String,
    /// 插件名称
    pub name: String,
    /// 插件版本
    pub version: String,
    /// 插件描述
    pub description: String,
    /// 插件作者
    pub author: String,
    /// 数据库 Schema 名称
    pub schema_name: String,
    /// 依赖的插件列表
    pub dependencies: Vec<String>,
    /// 路由前缀标识(用于插件路由注册)
    pub route_prefix: Option<String>,
    /// 是否为中间插件(用于在父子体系中提供共用能力)
    pub is_middle_plugin: bool,
    /// 是否为子插件(true 时必须指定父插件信息)
    pub is_sub_plugin: bool,
    /// 父插件 ID(仅对子插件必填)
    pub parent_plugin_id: Option<String>,
}

impl PluginMetadata {
    /// 创建新的插件元数据构建器
    ///
    /// 使用构建器模式创建插件元数据,允许链式调用设置各个字段。
    ///
    /// # 返回值
    /// * `PluginMetadataBuilder` - 元数据构建器实例
    ///
    /// # 示例
    /// ```no_run
    /// let metadata = PluginMetadata::builder()
    ///     .id("my-plugin".to_string())
    ///     .name("My Plugin".to_string())
    ///     .version("1.0.0".to_string())
    ///     .build()?;
    /// ```
    pub fn builder() -> PluginMetadataBuilder {
        PluginMetadataBuilder::default()
    }
    
    /// 检查是否为根插件(非子插件)
    ///
    /// 根插件是独立的插件,不是任何其他插件的子插件。
    ///
    /// # 返回值
    /// * `bool` - 如果是根插件返回 `true`,如果是子插件返回 `false`
    ///
    /// # 示例
    /// ```no_run
    /// if metadata.is_root_plugin() {
    ///     println!("这是一个根插件");
    /// }
    /// ```
    pub fn is_root_plugin(&self) -> bool {
        !self.is_sub_plugin
    }
    
    /// 检查是否有依赖
    ///
    /// 检查插件是否依赖其他插件。
    ///
    /// # 返回值
    /// * `bool` - 如果有依赖返回 `true`,否则返回 `false`
    ///
    /// # 示例
    /// ```no_run
    /// if metadata.has_dependencies() {
    ///     println!("插件依赖: {:?}", metadata.dependencies);
    /// }
    /// ```
    pub fn has_dependencies(&self) -> bool {
        !self.dependencies.is_empty()
    }
    
    /// 检查是否支持路由
    ///
    /// 检查插件是否配置了路由前缀,即是否支持 HTTP 路由注册。
    ///
    /// # 返回值
    /// * `bool` - 如果配置了路由前缀返回 `true`,否则返回 `false`
    ///
    /// # 示例
    /// ```no_run
    /// if metadata.has_routes() {
    ///     println!("路由前缀: {:?}", metadata.route_prefix);
    /// }
    /// ```
    pub fn has_routes(&self) -> bool {
        self.route_prefix.is_some()
    }
    
    /// 验证元数据的有效性
    ///
    /// 检查元数据的必填字段和业务规则是否满足要求。
    /// 验证包括:
    /// - 必填字段(ID、名称、版本)不能为空
    /// - 子插件必须指定父插件ID
    /// - 非子插件不能指定父插件ID
    ///
    /// # 返回值
    /// * `Result<(), String>` - 验证通过返回 `Ok(())`,失败返回错误消息
    ///
    /// # 验证规则
    /// * `id` 不能为空
    /// * `name` 不能为空
    /// * `version` 不能为空
    /// * 如果 `is_sub_plugin` 为 `true`,则 `parent_plugin_id` 必须存在
    /// * 如果 `is_sub_plugin` 为 `false`,则 `parent_plugin_id` 必须为 `None`
    ///
    /// # 示例
    /// ```no_run
    /// match metadata.validate() {
    ///     Ok(_) => println!("元数据验证通过"),
    ///     Err(e) => println!("元数据验证失败: {}", e),
    /// }
    /// ```
    pub fn validate(&self) -> Result<(), String> {
        // 验证必填字段
        if self.id.is_empty() {
            return Err("插件 ID 不能为空".to_string());
        }
        if self.name.is_empty() {
            return Err("插件名称不能为空".to_string());
        }
        if self.version.is_empty() {
            return Err("插件版本不能为空".to_string());
        }
        
        // 验证子插件必须指定父插件
        if self.is_sub_plugin && self.parent_plugin_id.is_none() {
            return Err("子插件必须指定父插件 ID".to_string());
        }
        
        // 验证非子插件不能有父插件 ID
        if !self.is_sub_plugin && self.parent_plugin_id.is_some() {
            return Err("非子插件不能指定父插件 ID".to_string());
        }
        
        Ok(())
    }
}

/// 插件元数据构建器
#[derive(Default)]
pub struct PluginMetadataBuilder {
    id: Option<String>,
    name: Option<String>,
    version: Option<String>,
    description: Option<String>,
    author: Option<String>,
    schema_name: Option<String>,
    dependencies: Vec<String>,
    route_prefix: Option<String>,
    is_middle_plugin: bool,
    is_sub_plugin: bool,
    parent_plugin_id: Option<String>,
}

impl PluginMetadataBuilder {
    /// 设置插件 ID
    ///
    /// 设置插件的唯一标识符。ID 必须唯一,用于区分不同的插件。
    ///
    /// # 参数
    /// * `id` - 插件ID字符串
    ///
    /// # 返回值
    /// * `Self` - 返回自身,支持链式调用
    pub fn id(mut self, id: String) -> Self {
        self.id = Some(id);
        self
    }
    
    /// 设置插件名称
    ///
    /// 设置插件的显示名称,用于用户界面展示。
    ///
    /// # 参数
    /// * `name` - 插件名称字符串
    ///
    /// # 返回值
    /// * `Self` - 返回自身,支持链式调用
    pub fn name(mut self, name: String) -> Self {
        self.name = Some(name);
        self
    }
    
    /// 设置插件版本
    ///
    /// 设置插件的版本号,遵循语义化版本规范(如 "1.0.0")。
    ///
    /// # 参数
    /// * `version` - 插件版本字符串
    ///
    /// # 返回值
    /// * `Self` - 返回自身,支持链式调用
    pub fn version(mut self, version: String) -> Self {
        self.version = Some(version);
        self
    }
    
    /// 设置插件描述
    ///
    /// 设置插件的描述信息,用于说明插件的功能和用途。
    ///
    /// # 参数
    /// * `description` - 插件描述字符串
    ///
    /// # 返回值
    /// * `Self` - 返回自身,支持链式调用
    ///
    /// # 注意
    /// 描述是可选的,如果不设置则使用空字符串。
    pub fn description(mut self, description: String) -> Self {
        self.description = Some(description);
        self
    }
    
    /// 设置插件作者
    ///
    /// 设置插件的作者信息。
    ///
    /// # 参数
    /// * `author` - 作者名称字符串
    ///
    /// # 返回值
    /// * `Self` - 返回自身,支持链式调用
    ///
    /// # 注意
    /// 作者是可选的,如果不设置则使用空字符串。
    pub fn author(mut self, author: String) -> Self {
        self.author = Some(author);
        self
    }
    
    /// 设置数据库 Schema 名称
    ///
    /// 设置插件使用的数据库 Schema 名称。如果不设置,默认使用 `plugin_{id}` 格式。
    ///
    /// # 参数
    /// * `schema_name` - Schema 名称字符串
    ///
    /// # 返回值
    /// * `Self` - 返回自身,支持链式调用
    ///
    /// # 默认值
    /// 如果不设置,构建时会自动生成:`plugin_{id}`(将 ID 中的连字符替换为下划线)。
    pub fn schema_name(mut self, schema_name: String) -> Self {
        self.schema_name = Some(schema_name);
        self
    }
    
    /// 添加依赖
    ///
    /// 添加一个依赖的插件ID。可以多次调用此方法来添加多个依赖。
    ///
    /// # 参数
    /// * `dependency` - 依赖的插件ID
    ///
    /// # 返回值
    /// * `Self` - 返回自身,支持链式调用
    ///
    /// # 示例
    /// ```no_run
    /// builder
    ///     .add_dependency("plugin-a".to_string())
    ///     .add_dependency("plugin-b".to_string())
    /// ```
    pub fn add_dependency(mut self, dependency: String) -> Self {
        self.dependencies.push(dependency);
        self
    }
    
    /// 设置依赖列表
    ///
    /// 一次性设置所有依赖的插件ID列表。会替换之前通过 `add_dependency` 添加的依赖。
    ///
    /// # 参数
    /// * `dependencies` - 依赖插件ID的向量
    ///
    /// # 返回值
    /// * `Self` - 返回自身,支持链式调用
    ///
    /// # 示例
    /// ```no_run
    /// builder.dependencies(vec![
    ///     "plugin-a".to_string(),
    ///     "plugin-b".to_string(),
    /// ])
    /// ```
    pub fn dependencies(mut self, dependencies: Vec<String>) -> Self {
        self.dependencies = dependencies;
        self
    }
    
    /// 设置路由前缀
    ///
    /// 设置插件的 HTTP 路由前缀。如果设置了路由前缀,插件可以注册 HTTP 路由。
    ///
    /// # 参数
    /// * `prefix` - 路由前缀字符串(如 "/api/my-plugin")
    ///
    /// # 返回值
    /// * `Self` - 返回自身,支持链式调用
    ///
    /// # 注意
    /// 路由前缀是可选的。如果不需要 HTTP 路由功能,可以不设置。
    pub fn route_prefix(mut self, prefix: String) -> Self {
        self.route_prefix = Some(prefix);
        self
    }
    
    /// 设置是否为中间插件
    ///
    /// 设置插件是否为中间插件。中间插件用于在父子插件体系中提供共用能力。
    ///
    /// # 参数
    /// * `is_middle` - 是否为中间插件
    ///
    /// # 返回值
    /// * `Self` - 返回自身,支持链式调用
    ///
    /// # 默认值
    /// 默认为 `false`。
    pub fn is_middle_plugin(mut self, is_middle: bool) -> Self {
        self.is_middle_plugin = is_middle;
        self
    }
    
    /// 设置是否为子插件
    ///
    /// 设置插件是否为子插件。子插件必须指定父插件ID。
    ///
    /// # 参数
    /// * `is_sub` - 是否为子插件
    ///
    /// # 返回值
    /// * `Self` - 返回自身,支持链式调用
    ///
    /// # 注意
    /// 如果设置为 `true`,必须同时调用 `parent_plugin_id` 设置父插件ID。
    ///
    /// # 默认值
    /// 默认为 `false`。
    pub fn is_sub_plugin(mut self, is_sub: bool) -> Self {
        self.is_sub_plugin = is_sub;
        self
    }
    
    /// 设置父插件 ID
    ///
    /// 设置子插件的父插件ID。只有当 `is_sub_plugin` 为 `true` 时才需要设置。
    ///
    /// # 参数
    /// * `parent_id` - 父插件ID字符串
    ///
    /// # 返回值
    /// * `Self` - 返回自身,支持链式调用
    ///
    /// # 注意
    /// 只有子插件才需要设置父插件ID。非子插件设置父插件ID会在构建时验证失败。
    pub fn parent_plugin_id(mut self, parent_id: String) -> Self {
        self.parent_plugin_id = Some(parent_id);
        self
    }
    
    /// 构建元数据
    ///
    /// 使用构建器中设置的参数创建 `PluginMetadata` 实例。
    /// 构建过程会验证必填字段和业务规则。
    ///
    /// # 返回值
    /// * `Result<PluginMetadata, String>` - 成功时返回元数据实例,失败返回错误消息
    ///
    /// # 错误
    /// * 如果必填字段(ID、名称、版本)未设置,返回错误
    /// * 如果子插件未设置父插件ID,返回错误
    /// * 如果非子插件设置了父插件ID,返回错误
    ///
    /// # 默认值
    /// * `schema_name`: 如果不设置,自动生成 `plugin_{id}` 格式
    /// * `description`: 如果不设置,使用空字符串
    /// * `author`: 如果不设置,使用空字符串
    /// * `dependencies`: 如果不设置,使用空向量
    /// * `route_prefix`: 如果不设置,使用 `None`
    /// * `is_middle_plugin`: 默认为 `false`
    /// * `is_sub_plugin`: 默认为 `false`
    ///
    /// # 示例
    /// ```no_run
    /// let metadata = PluginMetadataBuilder::default()
    ///     .id("my-plugin".to_string())
    ///     .name("My Plugin".to_string())
    ///     .version("1.0.0".to_string())
    ///     .build()?;
    /// ```
    pub fn build(self) -> Result<PluginMetadata, String> {
        let id = self.id.ok_or("插件 ID 不能为空")?;
        
        let metadata = PluginMetadata {
            schema_name: self.schema_name.unwrap_or_else(|| {
                // 默认使用插件 ID 作为 schema 名称
                format!("plugin_{}", id.replace("-", "_"))
            }),
            id,
            name: self.name.ok_or("插件名称不能为空")?,
            version: self.version.ok_or("插件版本不能为空")?,
            description: self.description.unwrap_or_default(),
            author: self.author.unwrap_or_default(),
            dependencies: self.dependencies,
            route_prefix: self.route_prefix,
            is_middle_plugin: self.is_middle_plugin,
            is_sub_plugin: self.is_sub_plugin,
            parent_plugin_id: self.parent_plugin_id,
        };
        
        // 验证元数据
        metadata.validate()?;
        
        Ok(metadata)
    }
}