Skip to content

Commit 49f5055

Browse files
authored
Merge pull request #16 from CeerDecy/feature/http-node
feat: add schema field constraints and scaffold http node
2 parents 4b57b68 + 7f60c13 commit 49f5055

35 files changed

Lines changed: 1607 additions & 158 deletions

File tree

Cargo.lock

Lines changed: 384 additions & 4 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

auto-engine-core/Cargo.toml

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,8 @@ wasmtime = "39.0.1"
2525
wasmtime-wasi = "39.0.1"
2626
anyhow = "1.0.100"
2727
convert_case = "0.10.0"
28+
leptess = "0.14.0"
29+
reqwest = { version = "0.12.9", default-features = false, features = ["json", "rustls-tls"] }
2830

2931
[features]
3032
default = ["types", "context", "event", "pipeline", "runner", "utils"]

auto-engine-core/src/context.rs

Lines changed: 3 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -62,14 +62,13 @@ impl Context {
6262
pub async fn get_value_parse(&self, key: &str) -> Option<serde_json::Value> {
6363
let mut default_value = None;
6464
let mut key = key.to_string();
65-
for caps in utils::REGEX_PARSE_VARIABLES.captures_iter(&key) {
66-
let var_name = (&caps[1]).to_string();
65+
if let Some(caps) = utils::REGEX_PARSE_VARIABLES.captures_iter(&key).next() {
66+
let var_name = (caps[1]).to_string();
6767
let default = caps.get(2).map(|m| m.as_str()).unwrap_or("");
68-
if default != "" {
68+
if !default.is_empty() {
6969
default_value = Some(serde_json::Value::String(default.to_string()));
7070
}
7171
key = var_name;
72-
break;
7372
}
7473

7574
let value = self.get_value(&key).await;

auto-engine-core/src/node.rs

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,11 @@
11
pub mod data_aggregator;
2+
pub mod http;
23
pub mod image_match;
34
pub mod keyboard;
45
pub mod mouse_click;
56
pub mod mouse_move;
7+
pub mod ocr;
8+
pub mod screen_capture;
69
pub mod start;
710
pub mod time_wait;
811
#[cfg(feature = "wasm")]

auto-engine-core/src/node/data_aggregator/node.rs

Lines changed: 9 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
1-
use crate::types::node::{FieldType, I18nValue, NodeDefine, SchemaField};
1+
use crate::types::field::{FieldType, SchemaField};
2+
use crate::types::node::{I18nValue, NodeDefine};
23
use std::collections::HashMap;
34

45
pub const NODE_TYPE: &str = "DataAggregator";
@@ -26,7 +27,7 @@ impl NodeDefine for DataAggregatorNode {
2627

2728
fn icon(&self) -> String {
2829
String::from(
29-
"data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSIyNCIgaGVpZ2h0PSIyNCIgdmlld0JveD0iMCAwIDI0IDI0IiBmaWxsPSJub25lIiBzdHJva2U9ImN1cnJlbnRDb2xvciIgc3Ryb2tlLXdpZHRoPSIyIiBzdHJva2UtbGluZWNhcD0icm91bmQiIHN0cm9rZS1saW5lam9pbj0icm91bmQiPjxwYXRoIGQ9Ik0yMSAxNlY4YTIgMiAwIDAgMC0xLTEuNzNsLTctNGEyIDIgMCAwIDAtMiAwbC03IDRBMiAyIDAgMCAwIDMgOHY4YTIgMiAwIDAgMCAxIDEuNzNsNyA0YTIgMiAwIDAgMCAyIDBsNy00QTIgMiAwIDAgMCAyMSAxNnoiLz48cG9seWxpbmUgcG9pbnRzPSI3LjUgNC4yMSAxMiA2LjgxIDE2LjUgNC4yMSIvPjxwb2x5bGluZSBwb2ludHM9IjcuNSAxOS43OSA3LjUgMTQuNiAzIDE3LjQiLz48cG9seWxpbmUgcG9pbnRzPSIyMSAxMi4yIDIxIDE2Ljc5IDE2LjUgMTkuNzkgMTYuNSAxNC42Ii8+PHBvbHlsaW5lIHBvaW50cz0iMy4yNyA2Ljk2IDEyIDEyLjAxIDIwLjczIDYuOTYiLz48bGluZSB4MT0iMTIiIHgyPSIxMiIgeTE9IjIyLjA4IiB5Mj0iMTIiLz48L3N2Zz4=",
30+
"data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSIyNCIgaGVpZ2h0PSIyNCIgdmlld0JveD0iMCAwIDI0IDI0IiBmaWxsPSJub25lIiBzdHJva2U9ImN1cnJlbnRDb2xvciIgc3Ryb2tlLXdpZHRoPSIxLjUiIHN0cm9rZS1saW5lY2FwPSJyb3VuZCIgc3Ryb2tlLWxpbmVqb2luPSJyb3VuZCIgY2xhc3M9Imx1Y2lkZSBsdWNpZGUtYmV0d2Vlbi1ob3Jpem9udGFsLXN0YXJ0LWljb24gbHVjaWRlLWJldHdlZW4taG9yaXpvbnRhbC1zdGFydCI+PHJlY3Qgd2lkdGg9IjEzIiBoZWlnaHQ9IjciIHg9IjgiIHk9IjMiIHJ4PSIxIi8+PHBhdGggZD0ibTIgOSAzIDMtMyAzIi8+PHJlY3Qgd2lkdGg9IjEzIiBoZWlnaHQ9IjciIHg9IjgiIHk9IjE0IiByeD0iMSIvPjwvc3ZnPg==",
3031
)
3132
}
3233

@@ -44,7 +45,7 @@ impl NodeDefine for DataAggregatorNode {
4445
})
4546
}
4647

47-
fn output_schema(&self,_input: HashMap<String, serde_json::Value>) -> Vec<SchemaField> {
48+
fn output_schema(&self, _input: HashMap<String, serde_json::Value>) -> Vec<SchemaField> {
4849
vec![
4950
SchemaField {
5051
name: "result".to_string(),
@@ -56,6 +57,7 @@ impl NodeDefine for DataAggregatorNode {
5657
}),
5758
enums: vec![],
5859
default: None,
60+
condition: None,
5961
},
6062
SchemaField {
6163
name: "count".to_string(),
@@ -67,6 +69,7 @@ impl NodeDefine for DataAggregatorNode {
6769
}),
6870
enums: vec![],
6971
default: None,
72+
condition: None,
7073
},
7174
]
7275
}
@@ -83,6 +86,7 @@ impl NodeDefine for DataAggregatorNode {
8386
}),
8487
enums: vec!["object".to_string(), "array".to_string()],
8588
default: Some("object".to_string()),
89+
condition: None,
8690
},
8791
SchemaField {
8892
name: "sources".to_string(),
@@ -95,6 +99,7 @@ impl NodeDefine for DataAggregatorNode {
9599
}),
96100
enums: vec![],
97101
default: None,
102+
condition: None,
98103
},
99104
SchemaField {
100105
name: "keys".to_string(),
@@ -106,6 +111,7 @@ impl NodeDefine for DataAggregatorNode {
106111
}),
107112
enums: vec![],
108113
default: None,
114+
condition: None,
109115
},
110116
]
111117
}

auto-engine-core/src/node/data_aggregator/runner.rs

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,6 @@ use crate::types::node::{NodeRunner, NodeRunnerControl, NodeRunnerController, No
33
use serde::{Deserialize, Serialize};
44
use serde_json::Value;
55
use std::collections::HashMap;
6-
use std::time::Duration;
76

87
#[derive(Serialize, Deserialize, Clone, Debug)]
98
pub struct DataAggregatorParam {
@@ -35,7 +34,7 @@ impl NodeRunner for DataAggregatorRunner {
3534
let map = ctx.string_value.read().await;
3635
log::info!("map: {:?}", map.keys());
3736
}
38-
let mut values= vec![];
37+
let mut values = vec![];
3938

4039
for source in param.sources.iter() {
4140
match ctx.get_value_parse(source).await {
@@ -52,7 +51,7 @@ impl NodeRunner for DataAggregatorRunner {
5251
// Array mode: return values as an array
5352
Value::Array(values)
5453
}
55-
"object" | _ => {
54+
"object" => {
5655
// Object mode: use keys if provided, otherwise use indices
5756
let mut map = serde_json::Map::new();
5857
for (i, value) in values.iter().enumerate() {
@@ -65,6 +64,9 @@ impl NodeRunner for DataAggregatorRunner {
6564
}
6665
Value::Object(map)
6766
}
67+
_ => {
68+
return Err(format!("Invalid mode: {}", param.mode));
69+
}
6870
};
6971

7072
let mut output = HashMap::new();

auto-engine-core/src/node/http.rs

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
pub mod node;
2+
pub mod runner;
Lines changed: 141 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,141 @@
1+
use crate::types::field::{FieldType, SchemaField};
2+
use crate::types::node::{I18nValue, NodeDefine};
3+
use std::collections::HashMap;
4+
5+
pub const NODE_TYPE: &str = "HTTPClient";
6+
7+
#[derive(Default)]
8+
pub struct HttpNode;
9+
10+
impl HttpNode {
11+
pub fn new() -> Self {
12+
Self {}
13+
}
14+
}
15+
16+
impl NodeDefine for HttpNode {
17+
fn action_type(&self) -> String {
18+
NODE_TYPE.to_string()
19+
}
20+
21+
fn name(&self) -> I18nValue {
22+
I18nValue {
23+
zh: "HTTP 请求".to_string(),
24+
en: "HTTP Request".to_string(),
25+
}
26+
}
27+
28+
fn icon(&self) -> String {
29+
String::from(
30+
"data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSIyNCIgaGVpZ2h0PSIyNCIgdmlld0JveD0iMCAwIDI0IDI0IiBmaWxsPSJub25lIiBzdHJva2U9ImN1cnJlbnRDb2xvciIgc3Ryb2tlLXdpZHRoPSIxLjUiIHN0cm9rZS1saW5lY2FwPSJyb3VuZCIgc3Ryb2tlLWxpbmVqb2luPSJyb3VuZCIgY2xhc3M9Imx1Y2lkZSBsdWNpZGUtZ2xvYmUtaWNvbiBsdWNpZGUtZ2xvYmUiPjxjaXJjbGUgY3g9IjEyIiBjeT0iMTIiIHI9IjEwIi8+PHBhdGggZD0iTTEyIDJhMTQuNSAxNC41IDAgMCAwIDAgMjAgMTQuNSAxNC41IDAgMCAwIDAtMjAiLz48cGF0aCBkPSJNMiAxMmgyMCIvPjwvc3ZnPg==",
31+
)
32+
}
33+
34+
fn category(&self) -> Option<I18nValue> {
35+
Some(I18nValue {
36+
zh: "网络请求".to_string(),
37+
en: "Network".to_string(),
38+
})
39+
}
40+
41+
fn description(&self) -> Option<I18nValue> {
42+
Some(I18nValue {
43+
zh: "发送简单的 HTTP 请求(基于 reqwest)。".to_string(),
44+
en: "Send simple HTTP requests using reqwest.".to_string(),
45+
})
46+
}
47+
48+
fn output_schema(&self, _input: HashMap<String, serde_json::Value>) -> Vec<SchemaField> {
49+
vec![
50+
SchemaField {
51+
name: "status".to_string(),
52+
field_type: FieldType::Number,
53+
item_type: None,
54+
description: Some(I18nValue {
55+
zh: "HTTP 状态码".to_string(),
56+
en: "HTTP status code".to_string(),
57+
}),
58+
enums: vec![],
59+
default: None,
60+
condition: None,
61+
},
62+
SchemaField {
63+
name: "body".to_string(),
64+
field_type: FieldType::String,
65+
item_type: None,
66+
description: Some(I18nValue {
67+
zh: "响应正文".to_string(),
68+
en: "Response body".to_string(),
69+
}),
70+
enums: vec![],
71+
default: None,
72+
condition: None,
73+
},
74+
]
75+
}
76+
77+
fn input_schema(&self) -> Vec<SchemaField> {
78+
vec![
79+
SchemaField {
80+
name: "method".to_string(),
81+
field_type: FieldType::String,
82+
item_type: None,
83+
description: Some(I18nValue {
84+
zh: "HTTP 方法,支持 GET/POST".to_string(),
85+
en: "HTTP method, supports GET/POST".to_string(),
86+
}),
87+
enums: vec!["GET".to_string(), "POST".to_string()],
88+
default: Some("GET".to_string()),
89+
condition: None,
90+
},
91+
SchemaField {
92+
name: "url".to_string(),
93+
field_type: FieldType::String,
94+
item_type: None,
95+
description: Some(I18nValue {
96+
zh: "请求 URL".to_string(),
97+
en: "Request URL".to_string(),
98+
}),
99+
enums: vec![],
100+
default: None,
101+
condition: None,
102+
},
103+
SchemaField {
104+
name: "headers".to_string(),
105+
field_type: FieldType::Array,
106+
item_type: Some(FieldType::String),
107+
description: Some(I18nValue {
108+
zh: "可选请求头列表,格式:Key: Value".to_string(),
109+
en: "Optional headers list, format: Key: Value".to_string(),
110+
}),
111+
enums: vec![],
112+
default: None,
113+
condition: None,
114+
},
115+
SchemaField {
116+
name: "body".to_string(),
117+
field_type: FieldType::String,
118+
item_type: None,
119+
description: Some(I18nValue {
120+
zh: "POST 请求体,文本/JSON 皆可。".to_string(),
121+
en: "POST body, plain text or JSON string.".to_string(),
122+
}),
123+
enums: vec![],
124+
default: Some("".to_string()),
125+
condition: None,
126+
},
127+
SchemaField {
128+
name: "timeout_ms".to_string(),
129+
field_type: FieldType::Number,
130+
item_type: None,
131+
description: Some(I18nValue {
132+
zh: "请求超时时间(毫秒),默认 30000。".to_string(),
133+
en: "Request timeout in milliseconds, default 30000.".to_string(),
134+
}),
135+
enums: vec![],
136+
default: Some("30000".to_string()),
137+
condition: None,
138+
},
139+
]
140+
}
141+
}

0 commit comments

Comments
 (0)