feat: 重构项目结构并添加核心功能
refactor: 将代码按功能模块重新组织到 core/runtime/control 等目录 feat(core): 添加 Context、FlowNode 等核心 trait 和类型 feat(runtime): 实现 FlowEngine 和状态管理 feat(control): 添加顺序/并行/条件控制流节点 feat(nodes): 实现 HTTP/DB/MQ 等业务节点 docs: 更新 README 添加架构说明和快速开始示例 test: 添加性能测试脚本和示例代码
This commit is contained in:
19
dsl-flow/examples/basic.rs
Normal file
19
dsl-flow/examples/basic.rs
Normal file
@ -0,0 +1,19 @@
|
||||
use dsl_flow::*;
|
||||
|
||||
#[tokio::main]
|
||||
async fn main() -> Result<(), Box<dyn std::error::Error + Send + Sync>> {
|
||||
tracing_subscriber::fmt().with_env_filter("info").init();
|
||||
let store = InMemoryStateStore::default();
|
||||
let engine = FlowEngine::new(store, FlowOptions { stateful: false, expr_engine: ExprEngineKind::Rhai });
|
||||
let flow = Flow::new(sequence! {
|
||||
expr_set(ExprEngineKind::Rhai, "1 + 2", "calc.sum"),
|
||||
fork_join! {
|
||||
expr_set(ExprEngineKind::Rhai, "ctx.calc.sum * 2", "calc.double"),
|
||||
expr_set(ExprEngineKind::Rhai, "ctx.calc.sum * 3", "calc.triple")
|
||||
}
|
||||
});
|
||||
let ctx = Context::new();
|
||||
let out = engine.run_stateless(&flow, ctx).await?;
|
||||
println!("{}", serde_json::to_string_pretty(&out.data)?);
|
||||
Ok(())
|
||||
}
|
||||
67
dsl-flow/examples/report.rs
Normal file
67
dsl-flow/examples/report.rs
Normal file
@ -0,0 +1,67 @@
|
||||
use std::fs;
|
||||
use std::path::PathBuf;
|
||||
use serde_json::Value;
|
||||
|
||||
fn read_json_lines(path: &str) -> Vec<Value> {
|
||||
let p = PathBuf::from(path);
|
||||
if !p.exists() {
|
||||
return vec![];
|
||||
}
|
||||
let content = fs::read_to_string(p).unwrap_or_default();
|
||||
content
|
||||
.lines()
|
||||
.filter_map(|l| serde_json::from_str::<Value>(l).ok())
|
||||
.collect()
|
||||
}
|
||||
|
||||
fn summarize(items: Vec<Value>) -> (usize, usize, f64, Vec<(String, f64)>) {
|
||||
let mut total = 0usize;
|
||||
let mut failed = 0usize;
|
||||
let mut duration = 0f64;
|
||||
let mut tests = Vec::new();
|
||||
for v in items {
|
||||
let t = v.get("type").and_then(|x| x.as_str()).unwrap_or("");
|
||||
if t == "test" {
|
||||
let name = v.get("name").and_then(|x| x.as_str()).unwrap_or("").to_string();
|
||||
let event = v.get("event").and_then(|x| x.as_str()).unwrap_or("");
|
||||
let time = v.get("exec_time").and_then(|x| x.as_f64()).unwrap_or(0.0);
|
||||
total += 1;
|
||||
if event == "failed" {
|
||||
failed += 1;
|
||||
}
|
||||
duration += time;
|
||||
tests.push((name, time));
|
||||
}
|
||||
}
|
||||
tests.sort_by(|a, b| b.1.partial_cmp(&a.1).unwrap());
|
||||
(total, failed, duration, tests)
|
||||
}
|
||||
|
||||
fn main() {
|
||||
let out_dir = PathBuf::from("target/test-reports");
|
||||
let _ = fs::create_dir_all(&out_dir);
|
||||
let default = read_json_lines("target/test-report-default.json");
|
||||
let js = read_json_lines("target/test-report-js.json");
|
||||
let (t1, f1, d1, s1) = summarize(default);
|
||||
let (t2, f2, d2, s2) = summarize(js);
|
||||
let mut md = String::new();
|
||||
md.push_str("# dsl-flow Test Report\n");
|
||||
md.push_str("\n");
|
||||
md.push_str("## Default features\n");
|
||||
md.push_str(&format!("- total: {}\n- failed: {}\n- duration: {:.3}s\n", t1, f1, d1));
|
||||
md.push_str("- top slow tests:\n");
|
||||
for (name, time) in s1.iter().take(5) {
|
||||
md.push_str(&format!(" - {}: {:.3}s\n", name, time));
|
||||
}
|
||||
md.push_str("\n");
|
||||
md.push_str("## JS feature\n");
|
||||
md.push_str(&format!("- total: {}\n- failed: {}\n- duration: {:.3}s\n", t2, f2, d2));
|
||||
md.push_str("- top slow tests:\n");
|
||||
for (name, time) in s2.iter().take(5) {
|
||||
md.push_str(&format!(" - {}: {:.3}s\n", name, time));
|
||||
}
|
||||
let out_path = out_dir.join("summary.md");
|
||||
let _ = fs::write(out_path, md);
|
||||
println!("report generated in target/test-reports/summary.md");
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user