use std::time::Duration;
use spider_agent::scripting::{ScriptConfig, ScriptContext, ScriptEngine};
#[tokio::main]
async fn main() -> Result<(), Box<dyn std::error::Error>> {
env_logger::init();
let engine = ScriptEngine::new(ScriptConfig {
enabled: true,
num_workers: 2,
queue_capacity: 16,
max_concurrent: 2,
default_timeout: Duration::from_secs(5),
max_output_bytes: 64 * 1024,
allow_network: true,
allow_filesystem: true,
inject_page_html: true,
html_max_bytes: 8 * 1024,
});
let ctx = ScriptContext {
url: Some("https://shop.example.com/widget".into()),
title: Some("Widget Catalog".into()),
html: Some(
"<div><span class=price>$1999</span><span class=stock>42 in stock</span></div>".into(),
),
memory_json: None,
};
println!("== Python ==");
let py = engine
.run_python(
r#"
import json
import re
numbers = [int(n) for n in re.findall(r"\d+", agent.html)]
record = {"url": agent.url, "numbers": numbers}
agent.write_file("record.json", json.dumps(record))
print("wrote:", agent.read_file("record.json"))
print("count:", len(numbers), "sum:", sum(numbers))
"#
.to_string(),
ctx.clone(),
None,
)
.await;
print_result(&py);
println!("\n== JavaScript ==");
let js = engine
.run_javascript(
r#"
const numbers = (agent.html.match(/\d+/g) || []).map(Number);
const record = { url: agent.url, numbers };
agent.write_file("record.json", JSON.stringify(record));
console.log("wrote:", agent.read_file("record.json"));
console.log("count:", numbers.length, "sum:", numbers.reduce((a, b) => a + b, 0));
numbers.reduce((a, b) => a + b, 0) // surfaces as result.value
"#
.to_string(),
ctx.clone(),
None,
)
.await;
print_result(&js);
if let Some(v) = &js.value {
println!("result.value = {}", v);
}
println!("\n== Python + agent.fetch ==");
let fetch = engine
.run_python(
r#"
resp = agent.fetch("https://example.com")
print("status:", resp["status"], "ok:", resp["ok"], "body_bytes:", len(resp["body"]))
"#
.to_string(),
ScriptContext::default(),
Some(Duration::from_secs(15)),
)
.await;
print_result(&fetch);
println!("\n== Timeout via check_interrupted ==");
let timed = engine
.run_python(
r#"
i = 0
while True:
i += 1
if i % 10000 == 0:
agent.check_interrupted() # raises KeyboardInterrupt when flagged
"#
.to_string(),
ScriptContext::default(),
Some(Duration::from_millis(150)),
)
.await;
println!(
"timed_out={} elapsed_ms={} (this is the expected outcome)",
timed.timed_out, timed.elapsed_ms
);
Ok(())
}
fn print_result(r: &spider_agent::scripting::ScriptResult) {
println!("success: {} elapsed_ms: {}", r.success, r.elapsed_ms);
if !r.stdout.is_empty() {
for line in r.stdout.lines() {
println!(" stdout │ {line}");
}
}
if !r.stderr.is_empty() {
for line in r.stderr.lines() {
println!(" stderr │ {line}");
}
}
}