sz_rust_workflow/capability/
mod.rs1use std::sync::Arc;
5
6use async_trait::async_trait;
7use serde_json::{json, Value};
8use sz_rust_addons_loader::capability_hook::CapabilityHook;
9use sz_rust_capability::{CapResult, Capability, CapabilityRegistry, CapabilitySource};
10
11use crate::WorkflowState;
12
13pub const WORKFLOW_CAPABILITY_NAMES: [&str; 3] = [
14 "workflow.health_check",
15 "workflow.list_definitions",
16 "workflow.list_instances",
17];
18
19pub struct WorkflowPlugin {
20 state: WorkflowState,
21}
22
23impl WorkflowPlugin {
24 pub fn new(state: WorkflowState) -> Self {
25 Self { state }
26 }
27}
28
29impl CapabilityHook for WorkflowPlugin {
30 fn register_capabilities(&self, registry: &CapabilityRegistry) -> CapResult<Vec<String>> {
31 let caps: Vec<Arc<dyn Capability>> = vec![
32 Arc::new(HealthCheckCapability::new(self.state.clone())),
33 Arc::new(ListDefinitionsCapability::new()),
34 Arc::new(ListInstancesCapability::new()),
35 ];
36 let mut names = Vec::with_capacity(caps.len());
37 for cap in caps {
38 let name = cap.name().to_string();
39 registry.register(cap);
40 names.push(name);
41 }
42 Ok(names)
43 }
44
45 fn capability_names(&self) -> Vec<String> {
46 WORKFLOW_CAPABILITY_NAMES
47 .iter()
48 .map(|s| s.to_string())
49 .collect()
50 }
51}
52
53pub struct HealthCheckCapability {
54 state: WorkflowState,
55}
56
57impl HealthCheckCapability {
58 pub fn new(state: WorkflowState) -> Self {
59 Self { state }
60 }
61}
62
63#[async_trait]
64impl Capability for HealthCheckCapability {
65 fn name(&self) -> &'static str {
66 "workflow.health_check"
67 }
68
69 fn description(&self) -> &'static str {
70 "workflow 引擎健康检查"
71 }
72
73 fn schema(&self) -> Value {
74 json!({"type": "object", "properties": {}})
75 }
76
77 fn source(&self) -> CapabilitySource {
78 CapabilitySource::Plugin
79 }
80
81 fn tags(&self) -> &'static [&'static str] {
82 &["workflow", "health", "read"]
83 }
84
85 fn requires_confirmation(&self) -> bool {
86 false
87 }
88
89 async fn call(&self, _params: Value) -> CapResult<Value> {
90 Ok(json!({
91 "code": 1,
92 "msg": "success",
93 "data": {
94 "plugin": "workflow",
95 "status": "active",
96 "engine": "WorkflowEngine",
97 "version": self.state.version
98 }
99 }))
100 }
101}
102
103pub struct ListDefinitionsCapability;
104
105impl Default for ListDefinitionsCapability {
106 fn default() -> Self {
107 Self::new()
108 }
109}
110
111impl ListDefinitionsCapability {
112 pub fn new() -> Self {
113 Self
114 }
115}
116
117#[async_trait]
118impl Capability for ListDefinitionsCapability {
119 fn name(&self) -> &'static str {
120 "workflow.list_definitions"
121 }
122
123 fn description(&self) -> &'static str {
124 "列出工作流定义"
125 }
126
127 fn schema(&self) -> Value {
128 json!({"type": "object", "properties": {}})
129 }
130
131 fn source(&self) -> CapabilitySource {
132 CapabilitySource::Plugin
133 }
134
135 fn tags(&self) -> &'static [&'static str] {
136 &["workflow", "definition", "read"]
137 }
138
139 fn requires_confirmation(&self) -> bool {
140 false
141 }
142
143 async fn call(&self, _params: Value) -> CapResult<Value> {
144 Ok(json!({
145 "code": 1,
146 "msg": "success",
147 "data": {
148 "definitions": [],
149 "total": 0
150 }
151 }))
152 }
153}
154
155pub struct ListInstancesCapability;
156
157impl Default for ListInstancesCapability {
158 fn default() -> Self {
159 Self::new()
160 }
161}
162
163impl ListInstancesCapability {
164 pub fn new() -> Self {
165 Self
166 }
167}
168
169#[async_trait]
170impl Capability for ListInstancesCapability {
171 fn name(&self) -> &'static str {
172 "workflow.list_instances"
173 }
174
175 fn description(&self) -> &'static str {
176 "列出工作流实例"
177 }
178
179 fn schema(&self) -> Value {
180 json!({"type": "object", "properties": {}})
181 }
182
183 fn source(&self) -> CapabilitySource {
184 CapabilitySource::Plugin
185 }
186
187 fn tags(&self) -> &'static [&'static str] {
188 &["workflow", "instance", "read"]
189 }
190
191 fn requires_confirmation(&self) -> bool {
192 false
193 }
194
195 async fn call(&self, _params: Value) -> CapResult<Value> {
196 let engine = crate::WorkflowEngine::new(
197 crate::WorkflowConfig::default(),
198 crate::WorkflowDeps::default_for_test(),
199 );
200 let page = crate::PageRequest::default();
201 let pending_tasks = engine
202 .query_tasks("", page)
203 .await
204 .map(|r| r.total)
205 .unwrap_or(0);
206 Ok(json!({
207 "code": 1,
208 "msg": "success",
209 "data": {
210 "instances": [],
211 "total": 0,
212 "pending_tasks": pending_tasks
213 }
214 }))
215 }
216}
217
218#[cfg(test)]
219mod tests {
220 use super::*;
221
222 #[test]
223 fn test_workflow_capability_names() {
224 assert_eq!(WORKFLOW_CAPABILITY_NAMES.len(), 3);
225 assert!(WORKFLOW_CAPABILITY_NAMES.contains(&"workflow.health_check"));
226 assert!(WORKFLOW_CAPABILITY_NAMES.contains(&"workflow.list_definitions"));
227 assert!(WORKFLOW_CAPABILITY_NAMES.contains(&"workflow.list_instances"));
228 }
229
230 #[tokio::test]
231 async fn test_register_capabilities() {
232 let registry = CapabilityRegistry::new();
233 let plugin = WorkflowPlugin::new(WorkflowState::default());
234 let names = plugin.register_capabilities(®istry).unwrap();
235 assert_eq!(names.len(), 3);
236 }
237
238 #[tokio::test]
239 async fn test_health_check_capability() {
240 let cap = HealthCheckCapability::new(WorkflowState::default());
241 let result = cap.call(json!({})).await.unwrap();
242 assert_eq!(result["code"], 1);
243 assert_eq!(result["data"]["plugin"], "workflow");
244 }
245
246 #[tokio::test]
247 async fn test_list_definitions_capability() {
248 let cap = ListDefinitionsCapability::new();
249 let result = cap.call(json!({})).await.unwrap();
250 assert_eq!(result["code"], 1);
251 }
252
253 #[tokio::test]
254 async fn test_list_instances_capability() {
255 let cap = ListInstancesCapability::new();
256 let result = cap.call(json!({})).await.unwrap();
257 assert_eq!(result["code"], 1);
258 }
259
260 #[test]
261 fn test_health_check_capability_metadata() {
262 let cap = HealthCheckCapability::new(WorkflowState::default());
263 assert_eq!(cap.name(), "workflow.health_check");
264 assert!(!cap.description().is_empty());
265 assert_eq!(cap.source(), CapabilitySource::Plugin);
266 assert!(cap.tags().contains(&"workflow"));
267 assert!(!cap.requires_confirmation());
268 }
269
270 #[test]
271 fn test_list_definitions_capability_metadata() {
272 let cap = ListDefinitionsCapability::new();
273 assert_eq!(cap.name(), "workflow.list_definitions");
274 assert!(!cap.description().is_empty());
275 assert_eq!(cap.source(), CapabilitySource::Plugin);
276 assert!(cap.tags().contains(&"definition"));
277 assert!(!cap.requires_confirmation());
278 }
279
280 #[test]
281 fn test_list_instances_capability_metadata() {
282 let cap = ListInstancesCapability::new();
283 assert_eq!(cap.name(), "workflow.list_instances");
284 assert!(!cap.description().is_empty());
285 assert_eq!(cap.source(), CapabilitySource::Plugin);
286 assert!(cap.tags().contains(&"instance"));
287 assert!(!cap.requires_confirmation());
288 }
289
290 #[test]
291 fn test_workflow_plugin_capability_names() {
292 let plugin = WorkflowPlugin::new(WorkflowState::default());
293 let names = plugin.capability_names();
294 assert_eq!(names.len(), 3);
295 assert!(names.contains(&"workflow.health_check".to_string()));
296 }
297}