1use super::*;
4
5impl EffectHandler for DefaultHandler {
6 fn enter_request_scope(&mut self) -> u64 {
10 let id = self.next_scope_id;
11 self.next_scope_id = self.next_scope_id.wrapping_add(1);
12 self.arena_stack.push((id, crate::arena::Arena::new()));
13 id
14 }
15
16 fn exit_request_scope(&mut self, scope_id: u64) {
22 if let Some(pos) = self.arena_stack.iter().position(|(id, _)| *id == scope_id) {
23 self.arena_stack.truncate(pos);
28 }
29 }
30
31 fn note_call_budget(&mut self, cost: u64) -> Result<(), String> {
36 let Some(ceiling) = self.budget_ceiling else { return Ok(()); };
39 loop {
45 let cur = self.budget_remaining.load(Ordering::SeqCst);
46 if cost > cur {
47 let used = ceiling.saturating_sub(cur);
48 return Err(format!(
49 "budget exceeded: requested {cost}, used so far {used}, ceiling {ceiling}"));
50 }
51 let next = cur - cost;
52 if self.budget_remaining.compare_exchange(cur, next,
55 Ordering::SeqCst, Ordering::SeqCst).is_ok() {
56 return Ok(());
57 }
58 }
59 }
60
61 fn dispatch(&mut self, kind: &str, op: &str, args: Vec<Value>) -> Result<Value, String> {
62 if is_pure_call(kind, op) {
66 return call_pure_builtin(kind, op, args);
67 }
68 if kind == "process" {
72 if op == "exit" {
78 self.ensure_kind_allowed("proc_exit")?;
79 let code = match args.first() {
80 Some(Value::Int(n)) => *n,
81 other => {
82 return Err(format!(
83 "process.exit expects an Int status, got {other:?}"
84 ))
85 }
86 };
87 let code = code.clamp(0, 255) as i64;
92 let _ = self.requested_exit.compare_exchange(
95 crate::handler::NO_EXIT,
96 code,
97 Ordering::SeqCst,
98 Ordering::SeqCst,
99 );
100 return Ok(Value::Unit);
101 }
102 self.ensure_kind_allowed("proc")?;
103 return self.dispatch_process(op, args);
104 }
105 if kind == "approval" {
106 self.ensure_kind_allowed("approval")?;
107 return self.dispatch_approval(op, args);
108 }
109 if kind == "log" {
110 let effect_kind = match op {
113 "debug" | "info" | "warn" | "error" => "log",
114 "set_level" | "set_format" => "io",
115 "set_sink" => {
116 self.ensure_kind_allowed("io")?;
117 self.ensure_kind_allowed("fs_write")?;
118 return self.dispatch_log(op, args);
119 }
120 other => return Err(format!("unsupported log.{other}")),
121 };
122 self.ensure_kind_allowed(effect_kind)?;
123 return self.dispatch_log(op, args);
124 }
125 if kind == "fs" {
126 let effect_kind = match op {
127 "exists" | "is_file" | "is_dir" | "stat"
128 | "list_dir" | "walk" | "glob" => "fs_walk",
129 "read_to_string" => "fs_read",
130 "mkdir_p" | "remove" | "write" => "fs_write",
131 "copy" => {
132 self.ensure_kind_allowed("fs_walk")?;
133 self.ensure_kind_allowed("fs_write")?;
134 return self.dispatch_fs(op, args);
135 }
136 other => return Err(format!("unsupported fs.{other}")),
137 };
138 self.ensure_kind_allowed(effect_kind)?;
139 return self.dispatch_fs(op, args);
140 }
141 if kind == "datetime" && op == "now" {
148 self.ensure_kind_allowed("time")?;
149 if let Ok(s) = std::env::var("LEX_TEST_NOW") {
151 if let Ok(secs) = s.trim().parse::<i64>() {
152 return Ok(Value::Int(secs.saturating_mul(1_000_000_000)));
153 }
154 }
155 let now = chrono::Utc::now();
156 let nanos = now.timestamp_nanos_opt().unwrap_or(i64::MAX);
157 return Ok(Value::Int(nanos));
158 }
159 if kind == "crypto" && op == "random" {
160 self.ensure_kind_allowed("random")?;
161 let n = expect_int(args.first())?;
162 if !(0..=1_048_576).contains(&n) {
163 return Err("crypto.random: n must be in 0..=1048576".into());
164 }
165 use rand::{rngs::SysRng, TryRng};
166 let mut buf = vec![0u8; n as usize];
167 SysRng.try_fill_bytes(&mut buf)
168 .map_err(|e| format!("crypto.random: OS RNG: {e}"))?;
169 return Ok(Value::Bytes(buf));
170 }
171 if kind == "crypto" && op == "random_str_hex" {
176 self.ensure_kind_allowed("random")?;
177 let n = expect_int(args.first())?;
178 if !(0..=1_048_576).contains(&n) {
179 return Err("crypto.random_str_hex: n must be in 0..=1048576".into());
180 }
181 use rand::{rngs::SysRng, TryRng};
182 let mut buf = vec![0u8; n as usize];
183 SysRng.try_fill_bytes(&mut buf)
184 .map_err(|e| format!("crypto.random_str_hex: OS RNG: {e}"))?;
185 return Ok(Value::Str(hex::encode(&buf).into()));
186 }
187 if kind == "crypto" && op == "p256_generate" {
200 self.ensure_kind_allowed("random")?;
201 use p256::ecdsa::SigningKey;
202 use rand::{rngs::SysRng, TryRng};
203 for _ in 0..16 {
204 let mut buf = [0u8; 32];
205 SysRng.try_fill_bytes(&mut buf)
206 .map_err(|e| format!("crypto.p256_generate: OS RNG: {e}"))?;
207 if let Ok(sk) = SigningKey::from_slice(&buf) {
208 return Ok(ok(Value::Bytes(sk.to_bytes().to_vec())));
209 }
210 }
211 return Ok(err(Value::Str(
212 "crypto.p256_generate: failed to sample a valid scalar".into())));
213 }
214 if kind == "crypto" && op == "secp256k1_generate" {
221 self.ensure_kind_allowed("random")?;
222 use k256::ecdsa::SigningKey;
223 use rand::{rngs::SysRng, TryRng};
224 for _ in 0..16 {
225 let mut buf = [0u8; 32];
226 SysRng.try_fill_bytes(&mut buf)
227 .map_err(|e| format!("crypto.secp256k1_generate: OS RNG: {e}"))?;
228 if let Ok(sk) = SigningKey::from_slice(&buf) {
229 return Ok(ok(Value::Bytes(sk.to_bytes().to_vec())));
230 }
231 }
232 return Ok(err(Value::Str(
233 "crypto.secp256k1_generate: failed to sample a valid scalar".into())));
234 }
235 if kind == "agent" {
248 let effect_kind = match op {
249 "local_complete" => "llm_local",
250 "cloud_complete" => "llm_cloud",
251 "cloud_stream" => "llm_cloud",
252 "send_a2a" => "a2a",
253 "call_mcp" => "mcp",
254 other => return Err(format!("unsupported agent.{other}")),
255 };
256 self.ensure_kind_allowed(effect_kind)?;
257 return match op {
265 "call_mcp" => Ok(self.dispatch_call_mcp(args)),
266 "local_complete" => Ok(dispatch_llm_local(args)),
267 "cloud_complete" => Ok(dispatch_llm_cloud(args)),
268 "cloud_stream" => Ok(self.dispatch_cloud_stream(args)),
269 _ => Ok(ok(Value::Str(format!("<{effect_kind} stub>").into()))),
270 };
271 }
272 if kind == "stream" {
273 self.ensure_kind_allowed("stream")?;
280 return match op {
281 "next" => Ok(self.dispatch_stream_next(args)),
282 "collect" => Ok(self.dispatch_stream_collect(args)),
283 other => Err(format!("unsupported stream.{other}")),
284 };
285 }
286 if kind == "http" && matches!(op, "send" | "get" | "post" | "stream_lines") {
287 self.ensure_kind_allowed("net")?;
288 return match op {
289 "send" => {
290 let req = expect_record(args.first())?;
291 Ok(http_send_record(self, req))
292 }
293 "get" => {
294 let url = expect_str(args.first())?.to_string();
295 self.ensure_host_allowed(&url)?;
296 Ok(http_send_simple("GET", &url, None, "", None))
297 }
298 "post" => {
299 let url = expect_str(args.first())?.to_string();
300 let body = expect_bytes(args.get(1))?.clone();
301 let content_type = expect_str(args.get(2))?.to_string();
302 self.ensure_host_allowed(&url)?;
303 Ok(http_send_simple("POST", &url, Some(body), &content_type, None))
304 }
305 "stream_lines" => {
306 let url = expect_str(args.first())?.to_string();
307 let headers_val = args.get(1).cloned().unwrap_or(Value::Map(Default::default()));
308 let body = expect_str(args.get(2))?.to_string();
309 self.ensure_host_allowed(&url)?;
310 Ok(http_stream_lines_impl(self, &url, &headers_val, &body))
311 }
312 _ => unreachable!(),
313 };
314 }
315 if kind == "arrow" && op == "read_csv" {
321 self.ensure_kind_allowed("fs_read")?;
322 let path = expect_str(args.first())?.to_string();
323 let resolved = self.resolve_read_path(&path);
324 if !self.policy.allow_fs_read.is_empty()
325 && !self.policy.allow_fs_read.iter().any(|a| resolved.starts_with(a))
326 {
327 return Err(format!("arrow.read_csv: `{path}` outside --allow-fs-read"));
328 }
329 return match crate::arrow::read_csv_at(&resolved) {
330 Ok(v) => Ok(ok(v)),
331 Err(e) => Ok(err(Value::Str(e.into()))),
332 };
333 }
334 if kind == "arrow" && (op == "read_parquet" || op == "read_parquet_cols") {
338 self.ensure_kind_allowed("fs_read")?;
339 let path = expect_str(args.first())?.to_string();
340 let resolved = self.resolve_read_path(&path);
341 if !self.policy.allow_fs_read.is_empty()
342 && !self.policy.allow_fs_read.iter().any(|a| resolved.starts_with(a))
343 {
344 return Err(format!("arrow.{op}: `{path}` outside --allow-fs-read"));
345 }
346 let r = if op == "read_parquet" {
347 crate::arrow::read_parquet_at(&resolved)
348 } else {
349 let cols = match args.get(1) {
350 Some(Value::List(items)) => {
351 let mut out = Vec::with_capacity(items.len());
352 for v in items.iter() {
353 match v {
354 Value::Str(s) => out.push(s.to_string()),
355 other => return Err(format!(
356 "arrow.read_parquet_cols: column name not Str: {other:?}")),
357 }
358 }
359 out
360 }
361 other => return Err(format!(
362 "arrow.read_parquet_cols: expected List[Str], got {other:?}")),
363 };
364 crate::arrow::read_parquet_cols_at(&resolved, &cols)
365 };
366 return match r {
367 Ok(v) => Ok(ok(v)),
368 Err(e) => Ok(err(Value::Str(e.into()))),
369 };
370 }
371 if kind == "arrow" && (op == "write_parquet" || op == "write_csv") {
374 self.ensure_kind_allowed("fs_write")?;
375 let table_v = args.first().cloned().unwrap_or(Value::Unit);
376 let rb = match &table_v {
377 Value::ArrowTable(t) => Arc::clone(t),
378 other => return Err(format!("arrow.{op}: first arg must be arrow.Table, got {other:?}")),
379 };
380 let path = expect_str(args.get(1))?.to_string();
381 if let Err(e) = self.ensure_fs_write_path(&path) {
382 return Ok(err(Value::Str(format!("arrow.{op}: {e}").into())));
383 }
384 let r = if op == "write_parquet" {
385 crate::arrow::write_parquet_at(&rb, std::path::Path::new(&path))
386 } else {
387 crate::arrow::write_csv_at(&rb, std::path::Path::new(&path))
388 };
389 return match r {
390 Ok(_) => Ok(ok(Value::Unit)),
391 Err(e) => Ok(err(Value::Str(e.into()))),
392 };
393 }
394 if kind == "net" && op == "default_opts" {
399 return Ok(ServeOpts::lex_defaults().to_value());
400 }
401 if kind == "tls" {
409 return match op {
410 "from_pem_files" => {
411 self.ensure_kind_allowed("fs_read")?;
412 dispatch_tls_from_pem_files(self, args)
413 }
414 "self_signed" => dispatch_tls_self_signed(args),
415 other => Err(format!("unsupported tls.{other}")),
416 };
417 }
418 if kind == "redis" {
422 self.ensure_kind_allowed("net")?;
423 } else if kind == "rand" {
424 self.ensure_kind_allowed("random")?;
428 } else {
429 self.ensure_kind_allowed(kind)?;
430 }
431 match (kind, op) {
432 ("io", "print") => {
433 let line = expect_str(args.first())?;
434 self.sink.print_line(line);
435 Ok(Value::Unit)
436 }
437 ("io", "read") => {
438 let path = expect_str(args.first())?.to_string();
442 let resolved = self.ensure_fs_read_content_path(&path)?;
443 match std::fs::read_to_string(&resolved) {
444 Ok(s) => Ok(ok(Value::Str(s.into()))),
445 Err(e) => Ok(err(Value::Str(format!("{e}").into()))),
446 }
447 }
448 ("io", "readline") => {
449 use std::io::BufRead;
450 let stdin = std::io::stdin();
451 let mut line = String::new();
452 match stdin.lock().read_line(&mut line) {
453 Ok(0) => Ok(Value::Variant { name: "None".into(), args: vec![] }),
454 Ok(_) => {
455 if line.ends_with('\n') { line.pop(); }
456 if line.ends_with('\r') { line.pop(); }
457 Ok(Value::Variant { name: "Some".into(), args: vec![Value::Str(line.into())] })
458 }
459 Err(_) => Ok(Value::Variant { name: "None".into(), args: vec![] }),
460 }
461 }
462 ("io", "argv") => {
463 let list: Vec<Value> = self.program_args.iter()
464 .map(|s| Value::Str(s.as_str().into()))
465 .collect();
466 Ok(Value::List(list.into()))
467 }
468 ("io", "write") => {
469 let path = expect_str(args.first())?.to_string();
471 let contents = expect_str(args.get(1))?.to_string();
472 self.ensure_fs_write_content_path(&path)?;
473 match std::fs::write(&path, contents) {
474 Ok(_) => Ok(ok(Value::Unit)),
475 Err(e) => Ok(err(Value::Str(format!("{e}").into()))),
476 }
477 }
478 ("time", "now") => {
479 if let Ok(s) = std::env::var("LEX_TEST_NOW") {
481 if let Ok(secs) = s.trim().parse::<i64>() {
482 return Ok(Value::Int(secs));
483 }
484 }
485 let secs = SystemTime::now().duration_since(UNIX_EPOCH)
486 .map_err(|e| format!("time: {e}"))?.as_secs();
487 Ok(Value::Int(secs as i64))
488 }
489 ("time", "now_ms") => {
490 if let Ok(s) = std::env::var("LEX_TEST_NOW") {
495 if let Ok(secs) = s.trim().parse::<i64>() {
496 return Ok(Value::Int(secs.saturating_mul(1000)));
497 }
498 }
499 let ms = SystemTime::now().duration_since(UNIX_EPOCH)
500 .map_err(|e| format!("time: {e}"))?.as_millis();
501 Ok(Value::Int(ms as i64))
502 }
503 ("time", "now_str") => {
504 if let Ok(s) = std::env::var("LEX_TEST_NOW") {
508 if let Ok(secs) = s.trim().parse::<i64>() {
509 let dt = chrono::DateTime::<chrono::Utc>::from_timestamp(secs, 0)
510 .unwrap_or_else(chrono::Utc::now);
511 return Ok(Value::Str(dt.to_rfc3339().into()));
512 }
513 }
514 Ok(Value::Str(chrono::Utc::now().to_rfc3339().into()))
515 }
516 ("time", "mono_ns") => {
517 static MONO_START: OnceLock<std::time::Instant> = OnceLock::new();
525 let start = MONO_START.get_or_init(std::time::Instant::now);
526 let dur = std::time::Instant::now().duration_since(*start);
527 Ok(Value::Int(dur.as_nanos() as i64))
528 }
529 ("time", "sleep_ms") => {
530 let n = expect_int(args.first())?;
538 if n > 0 {
539 let ms = (n as u64).min(60_000);
540 std::thread::sleep(std::time::Duration::from_millis(ms));
541 }
542 Ok(Value::Unit)
543 }
544 ("time", "sleep") => {
545 let nanos = expect_int(args.first())?;
551 if nanos > 0 {
552 let bounded_nanos = (nanos as u64).min(60_000 * 1_000_000);
553 std::thread::sleep(std::time::Duration::from_nanos(bounded_nanos));
554 }
555 Ok(Value::Unit)
556 }
557 ("rand", "int_in") => {
558 let lo = expect_int(args.first())?;
562 let hi = expect_int(args.get(1))?;
563 if hi < lo {
564 return Err(format!("rand.int_in: empty range [{lo}, {hi}]"));
565 }
566 use rand::{rngs::SysRng, TryRng};
567 let span = (hi as i128 - lo as i128 + 1) as u128;
570 let mut buf = [0u8; 16];
571 SysRng.try_fill_bytes(&mut buf)
572 .map_err(|e| format!("rand.int_in: OS RNG: {e}"))?;
573 let draw = (u128::from_le_bytes(buf) % span) as i128;
574 Ok(Value::Int((lo as i128 + draw) as i64))
575 }
576 ("env", "get") => {
581 let name = expect_str(args.first())?;
582 Ok(match std::env::var(name) {
583 Ok(v) => Value::Variant {
584 name: "Some".into(),
585 args: vec![Value::Str(v.into())],
586 },
587 Err(_) => Value::Variant { name: "None".into(), args: Vec::new() },
588 })
589 }
590 ("budget", _) => {
591 Ok(Value::Unit)
594 }
595 ("net", "get") => {
596 let url = expect_str(args.first())?.to_string();
597 self.ensure_host_allowed(&url)?;
598 Ok(http_request("GET", &url, None))
599 }
600 ("net", "post") => {
601 let url = expect_str(args.first())?.to_string();
602 let body = expect_str(args.get(1))?.to_string();
603 self.ensure_host_allowed(&url)?;
604 Ok(http_request("POST", &url, Some(&body)))
605 }
606 ("net", "udp_open") => {
608 let port = match args.first() {
609 Some(Value::Int(n)) if (0..=65535).contains(n) => *n as u16,
610 _ => return Err("net.udp_open(port): port must be Int 0..=65535".into()),
611 };
612 let mut reg = udp_registry().lock().unwrap();
613 if reg.len() >= MAX_UDP_HANDLES {
614 return Ok(err(Value::Str(format!(
615 "net.udp_open: too many open sockets ({MAX_UDP_HANDLES}); \
616 close them with net.udp_close"
617 ).into())));
618 }
619 match std::net::UdpSocket::bind(("0.0.0.0", port)) {
620 Ok(sock) => {
621 let handle = next_udp_handle();
622 reg.insert(handle, sock);
623 Ok(ok(Value::Int(handle as i64)))
624 }
625 Err(e) => Ok(err(Value::Str(format!("net.udp_open: {e}").into()))),
626 }
627 }
628 ("net", "udp_close") => {
629 let handle = expect_int(args.first()).map_err(|e| format!("net.udp_close(sock): {e}"))?;
630 udp_registry().lock().unwrap().remove(&(handle as u64));
633 Ok(ok(Value::Unit))
634 }
635 ("net", "udp_send") => {
636 let handle = expect_int(args.first()).map_err(|e| format!("net.udp_send(sock, ...): {e}"))?;
637 let host = expect_str(args.get(1))?.to_string();
638 let port = match args.get(2) {
639 Some(Value::Int(n)) if (0..=65535).contains(n) => *n as u16,
640 _ => return Err("net.udp_send(sock, host, port, data): port must be Int 0..=65535".into()),
641 };
642 let data = match args.get(3) {
643 Some(Value::Bytes(b)) => b.clone(),
644 _ => return Err("net.udp_send(sock, host, port, data): data must be Bytes".into()),
645 };
646 if let Err(e) = self.ensure_udp_dest_allowed(&host) {
653 return Ok(err(Value::Str(e.into())));
654 }
655 let res = with_udp(handle, "net.udp_send", |sock| {
656 sock.send_to(&data, (host.as_str(), port))
657 .map_err(|e| format!("net.udp_send: {e}"))
658 });
659 match res {
660 Ok(n) => Ok(ok(Value::Int(n as i64))),
661 Err(e) => Ok(err(Value::Str(e.into()))),
662 }
663 }
664 ("net", "udp_recv") => {
665 let handle = expect_int(args.first()).map_err(|e| format!("net.udp_recv(sock, ...): {e}"))?;
666 let timeout_ms = expect_int(args.get(1)).map_err(|e| format!("net.udp_recv(..., timeout_ms): {e}"))?;
667 if timeout_ms < 0 {
668 return Err("net.udp_recv(sock, timeout_ms): timeout_ms must be >= 0".into());
669 }
670 let res = with_udp(handle, "net.udp_recv", |sock| {
671 let d = std::time::Duration::from_millis(
675 if timeout_ms == 0 { 1 } else { timeout_ms as u64 });
676 sock.set_read_timeout(Some(d))
677 .map_err(|e| format!("net.udp_recv: setting timeout: {e}"))?;
678 let mut buf = vec![0u8; 65_507];
683 match sock.recv_from(&mut buf) {
684 Ok((n, addr)) => {
685 buf.truncate(n);
686 Ok(udp_datagram_value(buf, addr))
687 }
688 Err(e) if matches!(e.kind(),
689 std::io::ErrorKind::WouldBlock | std::io::ErrorKind::TimedOut) =>
690 Err(format!("net.udp_recv: timed out after {timeout_ms}ms")),
695 Err(e) => Err(format!("net.udp_recv: {e}")),
696 }
697 });
698 match res {
699 Ok(v) => Ok(ok(v)),
700 Err(e) => Ok(err(Value::Str(e.into()))),
701 }
702 }
703 ("net", "udp_broadcast") => {
704 let handle = expect_int(args.first()).map_err(|e| format!("net.udp_broadcast(sock, on): {e}"))?;
705 let on = matches!(args.get(1), Some(Value::Bool(true)));
706 let res = with_udp(handle, "net.udp_broadcast", |sock| {
707 sock.set_broadcast(on)
708 .map_err(|e| format!("net.udp_broadcast: {e}"))
709 });
710 match res {
711 Ok(()) => Ok(ok(Value::Unit)),
712 Err(e) => Ok(err(Value::Str(e.into()))),
713 }
714 }
715 ("net", "udp_join_multicast") => {
716 let handle = expect_int(args.first()).map_err(|e| format!("net.udp_join_multicast(sock, group): {e}"))?;
717 let group = expect_str(args.get(1))?.to_string();
718 let res = with_udp(handle, "net.udp_join_multicast", |sock| {
719 let g: std::net::Ipv4Addr = group.parse().map_err(|_| format!(
720 "net.udp_join_multicast: `{group}` is not an IPv4 address"))?;
721 if !g.is_multicast() {
722 return Err(format!(
723 "net.udp_join_multicast: {g} is not a multicast address \
724 (224.0.0.0/4)"));
725 }
726 sock.join_multicast_v4(&g, &std::net::Ipv4Addr::UNSPECIFIED)
727 .map_err(|e| format!("net.udp_join_multicast: {e}"))
728 });
729 match res {
730 Ok(()) => Ok(ok(Value::Unit)),
731 Err(e) => Ok(err(Value::Str(e.into()))),
732 }
733 }
734 ("net", "serve") => {
735 let port = match args.first() {
736 Some(Value::Int(n)) if (0..=65535).contains(n) => *n as u16,
737 _ => return Err("net.serve(port, handler): port must be Int 0..=65535".into()),
738 };
739 let handler_name = expect_str(args.get(1))?.to_string();
740 let program = self.program.clone()
741 .ok_or_else(|| "net.serve requires a Program reference; use DefaultHandler::with_program".to_string())?;
742 let policy = self.policy.clone();
743 serve_http(port, handler_name, program, policy, None, ServeOpts::from_env())
744 }
745 ("net", "serve_fn") => {
746 let port = match args.first() {
747 Some(Value::Int(n)) if (0..=65535).contains(n) => *n as u16,
748 _ => return Err("net.serve_fn(port, handler): port must be Int 0..=65535".into()),
749 };
750 let closure = match args.into_iter().nth(1) {
751 Some(c @ Value::Closure { .. }) => c,
752 _ => return Err("net.serve_fn(port, handler): handler must be a closure".into()),
753 };
754 let program = self.program.clone()
755 .ok_or_else(|| "net.serve_fn requires a Program reference; use DefaultHandler::with_program".to_string())?;
756 let policy = self.policy.clone();
757 serve_http_fn(port, closure, program, policy, ServeOpts::from_env())
758 }
759 ("net", "serve_routed") => {
760 let port = match args.first() {
761 Some(Value::Int(n)) if (0..=65535).contains(n) => *n as u16,
762 _ => return Err("net.serve_routed(port, routes, fallback): port must be Int 0..=65535".into()),
763 };
764 let routes_val = args.get(1).cloned()
765 .ok_or_else(|| "net.serve_routed(port, routes, fallback): missing routes".to_string())?;
766 let fallback = match args.into_iter().nth(2) {
767 Some(c @ Value::Closure { .. }) => c,
768 _ => return Err("net.serve_routed(port, routes, fallback): fallback must be a closure".into()),
769 };
770 let routes = decode_routes_arg(routes_val)?;
771 let program = self.program.clone()
772 .ok_or_else(|| "net.serve_routed requires a Program reference; use DefaultHandler::with_program".to_string())?;
773 let policy = self.policy.clone();
774 serve_http_routed(port, routes, fallback, program, policy, ServeOpts::from_env())
775 }
776 ("net", "serve_with") => {
777 let port = match args.first() {
779 Some(Value::Int(n)) if (0..=65535).contains(n) => *n as u16,
780 _ => return Err("net.serve_with(port, handler, opts): port must be Int 0..=65535".into()),
781 };
782 let handler_name = expect_str(args.get(1))?.to_string();
783 let opts = decode_serve_opts(args.get(2)
784 .ok_or_else(|| "net.serve_with(port, handler, opts): missing opts".to_string())?)?;
785 let program = self.program.clone()
786 .ok_or_else(|| "net.serve_with requires a Program reference; use DefaultHandler::with_program".to_string())?;
787 let policy = self.policy.clone();
788 serve_http(port, handler_name, program, policy, None, opts)
789 }
790 ("net", "serve_fn_with") => {
791 let port = match args.first() {
793 Some(Value::Int(n)) if (0..=65535).contains(n) => *n as u16,
794 _ => return Err("net.serve_fn_with(port, handler, opts): port must be Int 0..=65535".into()),
795 };
796 let opts = decode_serve_opts(args.get(2)
797 .ok_or_else(|| "net.serve_fn_with(port, handler, opts): missing opts".to_string())?)?;
798 let closure = match args.into_iter().nth(1) {
799 Some(c @ Value::Closure { .. }) => c,
800 _ => return Err("net.serve_fn_with(port, handler, opts): handler must be a closure".into()),
801 };
802 let program = self.program.clone()
803 .ok_or_else(|| "net.serve_fn_with requires a Program reference; use DefaultHandler::with_program".to_string())?;
804 let policy = self.policy.clone();
805 serve_http_fn(port, closure, program, policy, opts)
806 }
807 ("net", "serve_routed_with") => {
808 let port = match args.first() {
810 Some(Value::Int(n)) if (0..=65535).contains(n) => *n as u16,
811 _ => return Err("net.serve_routed_with(port, routes, fallback, opts): port must be Int 0..=65535".into()),
812 };
813 let routes_val = args.get(1).cloned()
814 .ok_or_else(|| "net.serve_routed_with(port, routes, fallback, opts): missing routes".to_string())?;
815 let opts = decode_serve_opts(args.get(3)
816 .ok_or_else(|| "net.serve_routed_with(port, routes, fallback, opts): missing opts".to_string())?)?;
817 let fallback = match args.into_iter().nth(2) {
818 Some(c @ Value::Closure { .. }) => c,
819 _ => return Err("net.serve_routed_with(port, routes, fallback, opts): fallback must be a closure".into()),
820 };
821 let routes = decode_routes_arg(routes_val)?;
822 let program = self.program.clone()
823 .ok_or_else(|| "net.serve_routed_with requires a Program reference; use DefaultHandler::with_program".to_string())?;
824 let policy = self.policy.clone();
825 serve_http_routed(port, routes, fallback, program, policy, opts)
826 }
827 ("net", "serve_quic") => self.dispatch_serve_quic_named(args),
828 ("net", "serve_quic_fn") => self.dispatch_serve_quic_fn(args),
829 ("net", "serve_quic_routed") => self.dispatch_serve_quic_routed(args),
830 ("net", "serve_tls") => {
831 let port = match args.first() {
832 Some(Value::Int(n)) if (0..=65535).contains(n) => *n as u16,
833 _ => return Err("net.serve_tls(port, cert, key, handler): port must be Int 0..=65535".into()),
834 };
835 let cert_path = expect_str(args.get(1))?.to_string();
836 let key_path = expect_str(args.get(2))?.to_string();
837 let handler_name = expect_str(args.get(3))?.to_string();
838 let program = self.program.clone()
839 .ok_or_else(|| "net.serve_tls requires a Program reference".to_string())?;
840 let policy = self.policy.clone();
841 let cert = std::fs::read(&cert_path)
842 .map_err(|e| format!("net.serve_tls: read cert {cert_path}: {e}"))?;
843 let key = std::fs::read(&key_path)
844 .map_err(|e| format!("net.serve_tls: read key {key_path}: {e}"))?;
845 serve_http(port, handler_name, program, policy, Some(TlsConfig { cert, key }), ServeOpts::from_env())
846 }
847 ("net", "serve_ws") => {
848 let port = match args.first() {
849 Some(Value::Int(n)) if (0..=65535).contains(n) => *n as u16,
850 _ => return Err("net.serve_ws(port, on_message): port must be Int 0..=65535".into()),
851 };
852 let handler_name = expect_str(args.get(1))?.to_string();
853 let program = self.program.clone()
854 .ok_or_else(|| "net.serve_ws requires a Program reference".to_string())?;
855 let policy = self.policy.clone();
856 let registry = Arc::new(crate::ws::ChatRegistry::default());
857 crate::ws::serve_ws(port, handler_name, program, policy, registry)
858 }
859 ("net", "serve_ws_fn") => {
860 let port = match args.first() {
861 Some(Value::Int(n)) if (0..=65535).contains(n) => *n as u16,
862 _ => return Err("net.serve_ws_fn(port, subprotocol, handler): port must be Int 0..=65535".into()),
863 };
864 let subprotocol = expect_str(args.get(1))?.to_string();
865 let closure = match args.into_iter().nth(2) {
866 Some(c @ Value::Closure { .. }) => c,
867 _ => return Err("net.serve_ws_fn(port, subprotocol, handler): handler must be a closure".into()),
868 };
869 let program = self.program.clone()
870 .ok_or_else(|| "net.serve_ws_fn requires a Program reference; use DefaultHandler::with_program".to_string())?;
871 let policy = self.policy.clone();
872 let registry = Arc::new(crate::ws::ChatRegistry::default());
873 crate::ws::serve_ws_fn(port, subprotocol, closure, program, policy, registry)
874 }
875 ("net", "serve_ws_fn_auth") => {
876 let port = match args.first() {
878 Some(Value::Int(n)) if (0..=65535).contains(n) => *n as u16,
879 _ => return Err("net.serve_ws_fn_auth(port, subprotocol, auth, on_message): port must be Int 0..=65535".into()),
880 };
881 let subprotocol = expect_str(args.get(1))?.to_string();
882 let mut it = args.into_iter().skip(2);
883 let auth_closure = match it.next() {
884 Some(c @ Value::Closure { .. }) => c,
885 _ => return Err("net.serve_ws_fn_auth(port, subprotocol, auth, on_message): auth must be a closure".into()),
886 };
887 let handler_closure = match it.next() {
888 Some(c @ Value::Closure { .. }) => c,
889 _ => return Err("net.serve_ws_fn_auth(port, subprotocol, auth, on_message): on_message must be a closure".into()),
890 };
891 let program = self.program.clone()
892 .ok_or_else(|| "net.serve_ws_fn_auth requires a Program reference; use DefaultHandler::with_program".to_string())?;
893 let policy = self.policy.clone();
894 let registry = Arc::new(crate::ws::ChatRegistry::default());
895 crate::ws::serve_ws_fn_auth(
896 port, subprotocol, auth_closure, handler_closure,
897 program, policy, registry,
898 )
899 }
900 ("net", "serve_ws_fn_actor_with") => {
901 let port = match args.first() {
913 Some(Value::Int(n)) if (0..=65535).contains(n) => *n as u16,
914 _ => return Err("net.serve_ws_fn_actor_with(port, subprotocol, name_of, on_message, opts): port must be Int 0..=65535".into()),
915 };
916 let subprotocol = expect_str(args.get(1))?.to_string();
917 let opts = match args.get(4) {
921 Some(v) => crate::handler::http_serve::decode_serve_opts(v)
922 .map_err(|e| format!("net.serve_ws_fn_actor_with: {e} — use net.default_opts()"))?,
923 None => return Err("net.serve_ws_fn_actor_with(port, subprotocol, name_of, on_message, opts): opts is required — use net.default_opts()".into()),
924 };
925 let host = if opts.host.trim().is_empty() {
929 crate::ws::ws_bind_host()
930 } else {
931 opts.host.clone()
932 };
933 let mut it = args.into_iter().skip(2);
934 let name_of_closure = match it.next() {
935 Some(c @ Value::Closure { .. }) => c,
936 _ => return Err("net.serve_ws_fn_actor_with(port, subprotocol, name_of, on_message, opts): name_of must be a closure".into()),
937 };
938 let on_message_closure = match it.next() {
939 Some(c @ Value::Closure { .. }) => c,
940 _ => return Err("net.serve_ws_fn_actor_with(port, subprotocol, name_of, on_message, opts): on_message must be a closure".into()),
941 };
942 let program = self.program.clone()
943 .ok_or_else(|| "net.serve_ws_fn_actor_with requires a Program reference; use DefaultHandler::with_program".to_string())?;
944 let policy = self.policy.clone();
945 let registry = Arc::new(crate::ws::ChatRegistry::default());
946 crate::ws::serve_ws_fn_actor_on(
947 host, port, subprotocol, name_of_closure, on_message_closure,
948 program, policy, registry,
949 )
950 }
951 ("net", "serve_ws_fn_actor") => {
952 let port = match args.first() {
954 Some(Value::Int(n)) if (0..=65535).contains(n) => *n as u16,
955 _ => return Err("net.serve_ws_fn_actor(port, subprotocol, name_of, on_message): port must be Int 0..=65535".into()),
956 };
957 let subprotocol = expect_str(args.get(1))?.to_string();
958 let mut it = args.into_iter().skip(2);
959 let name_of_closure = match it.next() {
960 Some(c @ Value::Closure { .. }) => c,
961 _ => return Err("net.serve_ws_fn_actor(port, subprotocol, name_of, on_message): name_of must be a closure".into()),
962 };
963 let on_message_closure = match it.next() {
964 Some(c @ Value::Closure { .. }) => c,
965 _ => return Err("net.serve_ws_fn_actor(port, subprotocol, name_of, on_message): on_message must be a closure".into()),
966 };
967 let program = self.program.clone()
968 .ok_or_else(|| "net.serve_ws_fn_actor requires a Program reference; use DefaultHandler::with_program".to_string())?;
969 let policy = self.policy.clone();
970 let registry = Arc::new(crate::ws::ChatRegistry::default());
971 crate::ws::serve_ws_fn_actor(
972 port, subprotocol, name_of_closure, on_message_closure,
973 program, policy, registry,
974 )
975 }
976 ("net", "dial_ws") => {
977 let url = expect_str(args.first())?.to_string();
979 let subprotocol = expect_str(args.get(1))?.to_string();
980 let on_open = match args.get(2).cloned() {
981 Some(c @ Value::Closure { .. }) => c,
982 _ => return Err(
983 "net.dial_ws(url, subprotocol, on_open, on_message): on_open must be a closure".into(),
984 ),
985 };
986 let on_message = match args.into_iter().nth(3) {
987 Some(c @ Value::Closure { .. }) => c,
988 _ => return Err(
989 "net.dial_ws(url, subprotocol, on_open, on_message): on_message must be a closure".into(),
990 ),
991 };
992 let program = self.program.clone().ok_or_else(|| {
993 "net.dial_ws requires a Program reference; use DefaultHandler::with_program".to_string()
994 })?;
995 let policy = self.policy.clone();
996 crate::ws::dial_ws(url, subprotocol, on_open, on_message, program, policy)
997 }
998 ("net", "dial_ws_actor") => {
999 let url = expect_str(args.first())?.to_string();
1001 let subprotocol = expect_str(args.get(1))?.to_string();
1002 let name = expect_str(args.get(2))?.to_string();
1003 let on_open = match args.get(3).cloned() {
1004 Some(c @ Value::Closure { .. }) => c,
1005 _ => return Err(
1006 "net.dial_ws_actor(url, subprotocol, name, on_open, on_message): on_open must be a closure".into(),
1007 ),
1008 };
1009 let on_message = match args.into_iter().nth(4) {
1010 Some(c @ Value::Closure { .. }) => c,
1011 _ => return Err(
1012 "net.dial_ws_actor(url, subprotocol, name, on_open, on_message): on_message must be a closure".into(),
1013 ),
1014 };
1015 let program = self.program.clone().ok_or_else(|| {
1016 "net.dial_ws_actor requires a Program reference; use DefaultHandler::with_program".to_string()
1017 })?;
1018 let policy = self.policy.clone();
1019 crate::ws::dial_ws_actor(url, subprotocol, name, on_open, on_message, program, policy)
1020 }
1021 ("chat", "broadcast") => {
1022 let registry = self.chat_registry.as_ref()
1023 .ok_or_else(|| "chat.broadcast called outside a net.serve_ws handler".to_string())?;
1024 let room = expect_str(args.first())?;
1025 let body = expect_str(args.get(1))?;
1026 crate::ws::chat_broadcast(registry, room, body);
1027 Ok(Value::Unit)
1028 }
1029 ("chat", "send") => {
1030 let registry = self.chat_registry.as_ref()
1031 .ok_or_else(|| "chat.send called outside a net.serve_ws handler".to_string())?;
1032 let conn_id = match args.first() {
1033 Some(Value::Int(n)) if *n >= 0 => *n as u64,
1034 _ => return Err("chat.send: conn_id must be non-negative Int".into()),
1035 };
1036 let body = expect_str(args.get(1))?;
1037 Ok(Value::Bool(crate::ws::chat_send(registry, conn_id, body)))
1038 }
1039 ("kv", "open") => {
1040 let path = expect_str(args.first())?.to_string();
1041 if !self.policy.allow_fs_write.is_empty() {
1045 let p = std::path::Path::new(&path);
1046 if !self.policy.allow_fs_write.iter().any(|a| p.starts_with(a)) {
1047 return Ok(err(Value::Str(format!(
1048 "kv.open: `{path}` outside --allow-fs-write").into())));
1049 }
1050 }
1051 match sled::open(&path) {
1052 Ok(db) => {
1053 let handle = next_kv_handle();
1054 kv_registry().lock().unwrap().insert(handle, db);
1055 Ok(ok(Value::Int(handle as i64)))
1056 }
1057 Err(e) => Ok(err(Value::Str(format!("kv.open: {e}").into()))),
1058 }
1059 }
1060 ("kv", "close") => {
1061 let h = expect_kv_handle(args.first())?;
1062 kv_registry().lock().unwrap().remove(h);
1063 Ok(Value::Unit)
1064 }
1065 ("kv", "get") => {
1066 let h = expect_kv_handle(args.first())?;
1067 let key = expect_str(args.get(1))?;
1068 let mut reg = kv_registry().lock().unwrap();
1069 let db = reg.touch_get(h).ok_or_else(|| "kv.get: closed or unknown Kv handle".to_string())?;
1070 match db.get(key.as_bytes()) {
1071 Ok(Some(ivec)) => Ok(some(Value::Bytes(ivec.to_vec()))),
1072 Ok(None) => Ok(none()),
1073 Err(e) => Err(format!("kv.get: {e}")),
1074 }
1075 }
1076 ("kv", "put") => {
1077 let h = expect_kv_handle(args.first())?;
1078 let key = expect_str(args.get(1))?.to_string();
1079 let val = expect_bytes(args.get(2))?.clone();
1080 let mut reg = kv_registry().lock().unwrap();
1081 let db = reg.touch_get(h).ok_or_else(|| "kv.put: closed or unknown Kv handle".to_string())?;
1082 match db.insert(key.as_bytes(), val) {
1083 Ok(_) => Ok(ok(Value::Unit)),
1084 Err(e) => Ok(err(Value::Str(format!("kv.put: {e}").into()))),
1085 }
1086 }
1087 ("kv", "delete") => {
1088 let h = expect_kv_handle(args.first())?;
1089 let key = expect_str(args.get(1))?;
1090 let mut reg = kv_registry().lock().unwrap();
1091 let db = reg.touch_get(h).ok_or_else(|| "kv.delete: closed or unknown Kv handle".to_string())?;
1092 match db.remove(key.as_bytes()) {
1093 Ok(_) => Ok(ok(Value::Unit)),
1094 Err(e) => Ok(err(Value::Str(format!("kv.delete: {e}").into()))),
1095 }
1096 }
1097 ("kv", "contains") => {
1098 let h = expect_kv_handle(args.first())?;
1099 let key = expect_str(args.get(1))?;
1100 let mut reg = kv_registry().lock().unwrap();
1101 let db = reg.touch_get(h).ok_or_else(|| "kv.contains: closed or unknown Kv handle".to_string())?;
1102 match db.contains_key(key.as_bytes()) {
1103 Ok(present) => Ok(Value::Bool(present)),
1104 Err(e) => Err(format!("kv.contains: {e}")),
1105 }
1106 }
1107 ("kv", "list_prefix") => {
1108 let h = expect_kv_handle(args.first())?;
1109 let prefix = expect_str(args.get(1))?;
1110 let mut reg = kv_registry().lock().unwrap();
1111 let db = reg.touch_get(h).ok_or_else(|| "kv.list_prefix: closed or unknown Kv handle".to_string())?;
1112 let mut keys: Vec<Value> = Vec::new();
1113 for kv in db.scan_prefix(prefix.as_bytes()) {
1114 let (k, _) = kv.map_err(|e| format!("kv.list_prefix: {e}"))?;
1115 let s = String::from_utf8_lossy(&k).to_string();
1116 keys.push(Value::Str(s.into()));
1117 }
1118 Ok(Value::List(keys.into()))
1119 }
1120 ("vcs", "put_blob") => {
1128 let content = expect_str(args.first())?.to_string();
1129 match lex_store::Store::open(vcs_store_root())
1130 .and_then(|s| s.put_blob(&content)) {
1131 Ok(sha) => Ok(ok(Value::Str(sha.into()))),
1132 Err(e) => Ok(err(Value::Str(format!("vcs.put_blob: {e}").into()))),
1133 }
1134 }
1135 ("vcs", "get_blob") => {
1136 let sha = expect_str(args.first())?.to_string();
1137 match lex_store::Store::open(vcs_store_root())
1138 .and_then(|s| s.get_blob(&sha)) {
1139 Ok(content) => Ok(ok(Value::Str(content.into()))),
1140 Err(e) => Ok(err(Value::Str(format!("vcs.get_blob: {e}").into()))),
1141 }
1142 }
1143 ("vcs", "has_blob") => {
1144 let sha = expect_str(args.first())?.to_string();
1145 let has = lex_store::Store::open(vcs_store_root())
1146 .map(|s| s.has_blob(&sha)).unwrap_or(false);
1147 Ok(Value::Bool(has))
1148 }
1149 ("vcs", "ref_set") => {
1150 let ns = expect_str(args.first())?.to_string();
1151 let key = expect_str(args.get(1))?.to_string();
1152 let sha = expect_str(args.get(2))?.to_string();
1153 match lex_store::Store::open(vcs_store_root())
1154 .and_then(|s| s.set_blob_ref(&ns, &key, &sha)) {
1155 Ok(()) => Ok(ok(Value::Unit)),
1156 Err(e) => Ok(err(Value::Str(format!("vcs.ref_set: {e}").into()))),
1157 }
1158 }
1159 ("vcs", "ref_get") => {
1160 let ns = expect_str(args.first())?.to_string();
1161 let key = expect_str(args.get(1))?.to_string();
1162 match lex_store::Store::open(vcs_store_root())
1163 .and_then(|s| s.get_blob_ref(&ns, &key)) {
1164 Ok(sha) => Ok(ok(Value::Str(sha.into()))),
1165 Err(e) => Ok(err(Value::Str(format!("vcs.ref_get: {e}").into()))),
1166 }
1167 }
1168 ("sql", "open") => {
1169 let path = expect_str(args.first())?.to_string();
1170 if path.starts_with("postgres://") || path.starts_with("postgresql://") {
1171 match postgres::Client::connect(&path, postgres::NoTls) {
1173 Ok(client) => {
1174 let handle = next_sql_handle();
1175 sql_registry().lock().unwrap().insert(handle, SqlConn::Postgres(client));
1176 Ok(ok(Value::Int(handle as i64)))
1177 }
1178 Err(e) => Ok(err(pg_err_to_sql_error(e, "sql.open"))),
1179 }
1180 } else {
1181 if path != ":memory:" && !self.policy.allow_fs_write.is_empty() {
1184 let p = std::path::Path::new(&path);
1185 if !self.policy.allow_fs_write.iter().any(|a| p.starts_with(a)) {
1186 return Ok(err(sql_error(
1187 format!("sql.open: `{path}` outside --allow-fs-write"),
1188 None, None,
1189 )));
1190 }
1191 }
1192 match rusqlite::Connection::open(&path) {
1193 Ok(conn) => {
1194 let handle = next_sql_handle();
1195 sql_registry().lock().unwrap().insert(handle, SqlConn::Sqlite(conn));
1196 Ok(ok(Value::Int(handle as i64)))
1197 }
1198 Err(e) => Ok(err(sqlite_err_to_sql_error(e, "sql.open"))),
1199 }
1200 }
1201 }
1202 ("sql", "close") => {
1203 let h = expect_sql_handle(args.first())?;
1204 sql_registry().lock().unwrap().remove(h);
1205 Ok(Value::Unit)
1206 }
1207 ("sql", "exec") => {
1208 let h = expect_sql_handle(args.first())?;
1209 let stmt = expect_str(args.get(1))?.to_string();
1210 let params = expect_sql_params(args.get(2))?;
1211 let arc = sql_registry().lock().unwrap()
1212 .touch_get(h)
1213 .ok_or_else(|| "sql.exec: closed or unknown Db handle".to_string())?;
1214 let mut conn = arc.lock().unwrap();
1215 match &mut *conn {
1216 SqlConn::Sqlite(c) => {
1217 let bound = sqlite_params(¶ms);
1218 let bind: Vec<&dyn rusqlite::ToSql> =
1219 bound.iter().map(|p| p as &dyn rusqlite::ToSql).collect();
1220 match c.execute(&stmt, rusqlite::params_from_iter(bind.iter())) {
1221 Ok(n) => Ok(ok(Value::Int(n as i64))),
1222 Err(e) => Ok(err(sqlite_err_to_sql_error(e, "sql.exec"))),
1223 }
1224 }
1225 SqlConn::Postgres(c) => {
1226 let pg = pg_param_refs(¶ms);
1227 let refs: Vec<&(dyn postgres::types::ToSql + Sync)> =
1228 pg.iter().map(|b| b.as_ref()).collect();
1229 match c.execute(pg_rewrite_placeholders(stmt.as_str()).as_str(), &refs) {
1230 Ok(n) => Ok(ok(Value::Int(n as i64))),
1231 Err(e) => Ok(err(pg_err_to_sql_error(e, "sql.exec"))),
1232 }
1233 }
1234 }
1235 }
1236 ("sql", "query") => {
1237 let h = expect_sql_handle(args.first())?;
1238 let stmt_str = expect_str(args.get(1))?.to_string();
1239 let params = expect_sql_params(args.get(2))?;
1240 let arc = sql_registry().lock().unwrap()
1241 .touch_get(h)
1242 .ok_or_else(|| "sql.query: closed or unknown Db handle".to_string())?;
1243 let mut conn = arc.lock().unwrap();
1244 Ok(match &mut *conn {
1245 SqlConn::Sqlite(c) => sql_run_query_sqlite(c, &stmt_str, ¶ms),
1246 SqlConn::Postgres(c) => sql_run_query_pg(c, &stmt_str, ¶ms),
1247 })
1248 }
1249 ("sql", "query_iter") => {
1255 let h = expect_sql_handle(args.first())?;
1256 let stmt_str = expect_str(args.get(1))?.to_string();
1257 let params = expect_sql_params(args.get(2))?;
1258 let arc = sql_registry().lock().unwrap()
1259 .touch_get(h)
1260 .ok_or_else(|| "sql.query_iter: closed or unknown Db handle".to_string())?;
1261
1262 let (sender, receiver) = std::sync::mpsc::sync_channel::<Result<Value, String>>(
1266 CURSOR_CHANNEL_CAPACITY,
1267 );
1268 let cursor_h = next_cursor_handle();
1269 cursor_registry().lock().unwrap().insert(cursor_h, receiver);
1270
1271 let arc_for_thread = Arc::clone(&arc);
1272 let is_sqlite = matches!(*arc.lock().unwrap(), SqlConn::Sqlite(_));
1278 std::thread::spawn(move || {
1279 if is_sqlite {
1280 sqlite_cursor_producer(arc_for_thread, stmt_str, params, sender);
1281 } else {
1282 pg_cursor_producer(arc_for_thread, stmt_str, params, sender);
1283 }
1284 });
1285
1286 Ok(ok(Value::Variant {
1287 name: "__IterCursor".into(),
1288 args: vec![Value::Int(cursor_h as i64)],
1289 }))
1290 }
1291 ("sql", "cursor_next") => {
1297 let h = match args.first() {
1298 Some(Value::Int(n)) if *n >= 0 => *n as u64,
1299 _ => return Err("sql.cursor_next: expected cursor handle (Int)".into()),
1300 };
1301 let rx_arc = match cursor_registry().lock().unwrap().touch_get(h) {
1302 Some(a) => a,
1303 None => return Ok(Value::Variant { name: "None".into(), args: vec![] }),
1304 };
1305 let recv_result = {
1310 let rx = match rx_arc.lock() {
1311 Ok(g) => g,
1312 Err(p) => p.into_inner(),
1313 };
1314 rx.recv()
1315 };
1316 match recv_result {
1317 Ok(Ok(row)) => Ok(Value::Variant {
1318 name: "Some".into(),
1319 args: vec![row],
1320 }),
1321 Ok(Err(_)) | Err(_) => {
1322 cursor_registry().lock().unwrap().remove(h);
1326 Ok(Value::Variant { name: "None".into(), args: vec![] })
1327 }
1328 }
1329 }
1330 ("sql", "begin") => {
1335 let h = expect_sql_handle(args.first())?;
1336 let arc = sql_registry().lock().unwrap()
1337 .touch_get(h)
1338 .ok_or_else(|| "sql.begin: closed or unknown Db handle".to_string())?;
1339 let mut conn = arc.lock().unwrap();
1340 match &mut *conn {
1341 SqlConn::Sqlite(c) => match c.execute_batch("BEGIN") {
1342 Ok(()) => Ok(ok(Value::Int(h as i64))),
1343 Err(e) => Ok(err(sqlite_err_to_sql_error(e, "sql.begin"))),
1344 },
1345 SqlConn::Postgres(c) => match c.batch_execute("BEGIN") {
1346 Ok(()) => Ok(ok(Value::Int(h as i64))),
1347 Err(e) => Ok(err(pg_err_to_sql_error(e, "sql.begin"))),
1348 },
1349 }
1350 }
1351 ("sql", "commit") => {
1352 let h = expect_sql_handle(args.first())?;
1353 let arc = sql_registry().lock().unwrap()
1354 .touch_get(h)
1355 .ok_or_else(|| "sql.commit: closed or unknown SqlTx handle".to_string())?;
1356 let mut conn = arc.lock().unwrap();
1357 match &mut *conn {
1358 SqlConn::Sqlite(c) => match c.execute_batch("COMMIT") {
1359 Ok(()) => Ok(ok(Value::Unit)),
1360 Err(e) => Ok(err(sqlite_err_to_sql_error(e, "sql.commit"))),
1361 },
1362 SqlConn::Postgres(c) => match c.batch_execute("COMMIT") {
1363 Ok(()) => Ok(ok(Value::Unit)),
1364 Err(e) => Ok(err(pg_err_to_sql_error(e, "sql.commit"))),
1365 },
1366 }
1367 }
1368 ("sql", "rollback") => {
1369 let h = expect_sql_handle(args.first())?;
1370 let arc = sql_registry().lock().unwrap()
1371 .touch_get(h)
1372 .ok_or_else(|| "sql.rollback: closed or unknown SqlTx handle".to_string())?;
1373 let mut conn = arc.lock().unwrap();
1374 match &mut *conn {
1375 SqlConn::Sqlite(c) => match c.execute_batch("ROLLBACK") {
1376 Ok(()) => Ok(ok(Value::Unit)),
1377 Err(e) => Ok(err(sqlite_err_to_sql_error(e, "sql.rollback"))),
1378 },
1379 SqlConn::Postgres(c) => match c.batch_execute("ROLLBACK") {
1380 Ok(()) => Ok(ok(Value::Unit)),
1381 Err(e) => Ok(err(pg_err_to_sql_error(e, "sql.rollback"))),
1382 },
1383 }
1384 }
1385 ("sql", "exec_tx") => {
1386 let h = expect_sql_handle(args.first())?;
1387 let stmt = expect_str(args.get(1))?.to_string();
1388 let params = expect_sql_params(args.get(2))?;
1389 let arc = sql_registry().lock().unwrap()
1390 .touch_get(h)
1391 .ok_or_else(|| "sql.exec_tx: closed or unknown SqlTx handle".to_string())?;
1392 let mut conn = arc.lock().unwrap();
1393 match &mut *conn {
1394 SqlConn::Sqlite(c) => {
1395 let bound = sqlite_params(¶ms);
1396 let bind: Vec<&dyn rusqlite::ToSql> =
1397 bound.iter().map(|p| p as &dyn rusqlite::ToSql).collect();
1398 match c.execute(&stmt, rusqlite::params_from_iter(bind.iter())) {
1399 Ok(n) => Ok(ok(Value::Int(n as i64))),
1400 Err(e) => Ok(err(sqlite_err_to_sql_error(e, "sql.exec_tx"))),
1401 }
1402 }
1403 SqlConn::Postgres(c) => {
1404 let pg = pg_param_refs(¶ms);
1405 let refs: Vec<&(dyn postgres::types::ToSql + Sync)> =
1406 pg.iter().map(|b| b.as_ref()).collect();
1407 match c.execute(pg_rewrite_placeholders(stmt.as_str()).as_str(), &refs) {
1408 Ok(n) => Ok(ok(Value::Int(n as i64))),
1409 Err(e) => Ok(err(pg_err_to_sql_error(e, "sql.exec_tx"))),
1410 }
1411 }
1412 }
1413 }
1414 ("sql", "query_tx") => {
1415 let h = expect_sql_handle(args.first())?;
1416 let stmt_str = expect_str(args.get(1))?.to_string();
1417 let params = expect_sql_params(args.get(2))?;
1418 let arc = sql_registry().lock().unwrap()
1419 .touch_get(h)
1420 .ok_or_else(|| "sql.query_tx: closed or unknown SqlTx handle".to_string())?;
1421 let mut conn = arc.lock().unwrap();
1422 Ok(match &mut *conn {
1423 SqlConn::Sqlite(c) => sql_run_query_sqlite(c, &stmt_str, ¶ms),
1424 SqlConn::Postgres(c) => sql_run_query_pg(c, &stmt_str, ¶ms),
1425 })
1426 }
1427 ("sql", "get_str") => Ok(sql_get_col(&args, |v| match v {
1428 Value::Str(s) => Some(Value::Str(s.clone())),
1429 Value::Int(n) => Some(Value::Str(n.to_string().into())),
1430 _ => None,
1431 })?),
1432 ("sql", "get_int") => Ok(sql_get_col(&args, |v| match v {
1433 Value::Int(n) => Some(Value::Int(*n)),
1434 Value::Float(f) => Some(Value::Int(*f as i64)),
1435 _ => None,
1436 })?),
1437 ("sql", "get_float") => Ok(sql_get_col(&args, |v| match v {
1438 Value::Float(f) => Some(Value::Float(*f)),
1439 Value::Int(n) => Some(Value::Float(*n as f64)),
1440 _ => None,
1441 })?),
1442 ("sql", "get_bool") => Ok(sql_get_col(&args, |v| match v {
1443 Value::Bool(b) => Some(Value::Bool(*b)),
1444 Value::Int(n) => Some(Value::Bool(*n != 0)),
1445 _ => None,
1446 })?),
1447
1448 ("redis", "connect") => {
1457 let url = expect_str(args.first())?.to_string();
1458 self.ensure_host_allowed(&url)?;
1459 match redis::Client::open(url.as_str()) {
1460 Ok(client) => match client.get_connection() {
1461 Ok(conn) => {
1462 let handle = next_redis_handle();
1463 redis_registry().lock().unwrap().insert(handle, RedisEntry { url, conn });
1464 Ok(ok(Value::Int(handle as i64)))
1465 }
1466 Err(e) => Ok(err(Value::Str(format!("redis.connect: {e}").into()))),
1467 },
1468 Err(e) => Ok(err(Value::Str(format!("redis.connect: {e}").into()))),
1469 }
1470 }
1471 ("redis", "close") => {
1472 let h = expect_redis_handle(args.first())?;
1473 redis_registry().lock().unwrap().remove(h);
1474 Ok(Value::Unit)
1475 }
1476 ("redis", "get") => {
1477 let h = expect_redis_handle(args.first())?;
1478 let key = expect_str(args.get(1))?.to_string();
1479 let mut reg = redis_registry().lock().unwrap();
1480 let entry = reg.touch_get_mut(h)
1481 .ok_or_else(|| "redis.get: closed or unknown ConnRedis handle".to_string())?;
1482 use redis::Commands;
1483 match entry.conn.get::<_, Option<String>>(&key) {
1484 Ok(Some(v)) => Ok(some(Value::Str(v.into()))),
1485 Ok(None) => Ok(none()),
1486 Err(e) => Err(format!("redis.get: {e}")),
1487 }
1488 }
1489 ("redis", "set") => {
1490 let h = expect_redis_handle(args.first())?;
1491 let key = expect_str(args.get(1))?.to_string();
1492 let val = expect_str(args.get(2))?.to_string();
1493 let mut reg = redis_registry().lock().unwrap();
1494 let entry = reg.touch_get_mut(h)
1495 .ok_or_else(|| "redis.set: closed or unknown ConnRedis handle".to_string())?;
1496 use redis::Commands;
1497 entry.conn.set::<_, _, ()>(&key, &val)
1498 .map_err(|e| format!("redis.set: {e}"))?;
1499 Ok(Value::Unit)
1500 }
1501 ("redis", "set_ex") => {
1502 let h = expect_redis_handle(args.first())?;
1503 let key = expect_str(args.get(1))?.to_string();
1504 let val = expect_str(args.get(2))?.to_string();
1505 let ttl = expect_int(args.get(3))?;
1506 let mut reg = redis_registry().lock().unwrap();
1507 let entry = reg.touch_get_mut(h)
1508 .ok_or_else(|| "redis.set_ex: closed or unknown ConnRedis handle".to_string())?;
1509 use redis::Commands;
1510 entry.conn.set_ex::<_, _, ()>(&key, &val, ttl as u64)
1511 .map_err(|e| format!("redis.set_ex: {e}"))?;
1512 Ok(Value::Unit)
1513 }
1514 ("redis", "del") => {
1515 let h = expect_redis_handle(args.first())?;
1516 let key = expect_str(args.get(1))?.to_string();
1517 let mut reg = redis_registry().lock().unwrap();
1518 let entry = reg.touch_get_mut(h)
1519 .ok_or_else(|| "redis.del: closed or unknown ConnRedis handle".to_string())?;
1520 use redis::Commands;
1521 entry.conn.del::<_, ()>(&key)
1522 .map_err(|e| format!("redis.del: {e}"))?;
1523 Ok(Value::Unit)
1524 }
1525 ("redis", "exists") => {
1526 let h = expect_redis_handle(args.first())?;
1527 let key = expect_str(args.get(1))?.to_string();
1528 let mut reg = redis_registry().lock().unwrap();
1529 let entry = reg.touch_get_mut(h)
1530 .ok_or_else(|| "redis.exists: closed or unknown ConnRedis handle".to_string())?;
1531 use redis::Commands;
1532 let present: bool = entry.conn.exists(&key)
1533 .map_err(|e| format!("redis.exists: {e}"))?;
1534 Ok(Value::Bool(present))
1535 }
1536 ("redis", "expire") => {
1537 let h = expect_redis_handle(args.first())?;
1538 let key = expect_str(args.get(1))?.to_string();
1539 let ttl = expect_int(args.get(2))?;
1540 let mut reg = redis_registry().lock().unwrap();
1541 let entry = reg.touch_get_mut(h)
1542 .ok_or_else(|| "redis.expire: closed or unknown ConnRedis handle".to_string())?;
1543 use redis::Commands;
1544 entry.conn.expire::<_, ()>(&key, ttl)
1545 .map_err(|e| format!("redis.expire: {e}"))?;
1546 Ok(Value::Unit)
1547 }
1548 ("redis", "publish") => {
1549 let h = expect_redis_handle(args.first())?;
1550 let channel = expect_str(args.get(1))?.to_string();
1551 let msg = expect_str(args.get(2))?.to_string();
1552 let mut reg = redis_registry().lock().unwrap();
1553 let entry = reg.touch_get_mut(h)
1554 .ok_or_else(|| "redis.publish: closed or unknown ConnRedis handle".to_string())?;
1555 use redis::Commands;
1556 let n: i64 = entry.conn.publish(&channel, &msg)
1557 .map_err(|e| format!("redis.publish: {e}"))?;
1558 Ok(Value::Int(n))
1559 }
1560 ("redis", "subscribe") => {
1565 let h = expect_redis_handle(args.first())?;
1566 let channel = expect_str(args.get(1))?.to_string();
1567 let closure = match args.into_iter().nth(2) {
1568 Some(c @ Value::Closure { .. }) => c,
1569 _ => return Err("redis.subscribe: handler must be a Closure".into()),
1570 };
1571 let program = self.program.clone()
1572 .ok_or("redis.subscribe: no program; call DefaultHandler::with_program")?;
1573 let policy = self.policy.clone();
1574 let url = redis_registry().lock().unwrap()
1575 .get_url(h)
1576 .ok_or("redis.subscribe: closed or unknown ConnRedis handle")?;
1577 let client = redis::Client::open(url.as_str())
1578 .map_err(|e| format!("redis.subscribe: {e}"))?;
1579 let mut conn = client.get_connection()
1580 .map_err(|e| format!("redis.subscribe: {e}"))?;
1581 let mut pubsub = conn.as_pubsub();
1582 pubsub.subscribe(&channel)
1583 .map_err(|e| format!("redis.subscribe: {e}"))?;
1584 loop {
1585 let msg = pubsub.get_message()
1586 .map_err(|e| format!("redis.subscribe: {e}"))?;
1587 let ch: String = msg.get_channel_name().to_string();
1588 let payload: String = msg.get_payload()
1589 .map_err(|e| format!("redis.subscribe: payload: {e}"))?;
1590 let handler = DefaultHandler::new(policy.clone())
1591 .with_program(Arc::clone(&program));
1592 let mut vm = Vm::with_handler(&program, Box::new(handler));
1593 vm.invoke_closure_value(closure.clone(), vec![
1594 Value::Str(ch.into()),
1595 Value::Str(payload.into()),
1596 ]).map_err(|e| format!("redis.subscribe: handler: {e:?}"))?;
1597 }
1598 }
1599 ("redis", "psubscribe") => {
1600 let h = expect_redis_handle(args.first())?;
1601 let pattern = expect_str(args.get(1))?.to_string();
1602 let closure = match args.into_iter().nth(2) {
1603 Some(c @ Value::Closure { .. }) => c,
1604 _ => return Err("redis.psubscribe: handler must be a Closure".into()),
1605 };
1606 let program = self.program.clone()
1607 .ok_or("redis.psubscribe: no program; call DefaultHandler::with_program")?;
1608 let policy = self.policy.clone();
1609 let url = redis_registry().lock().unwrap()
1610 .get_url(h)
1611 .ok_or("redis.psubscribe: closed or unknown ConnRedis handle")?;
1612 let client = redis::Client::open(url.as_str())
1613 .map_err(|e| format!("redis.psubscribe: {e}"))?;
1614 let mut conn = client.get_connection()
1615 .map_err(|e| format!("redis.psubscribe: {e}"))?;
1616 let mut pubsub = conn.as_pubsub();
1617 pubsub.psubscribe(&pattern)
1618 .map_err(|e| format!("redis.psubscribe: {e}"))?;
1619 loop {
1620 let msg = pubsub.get_message()
1621 .map_err(|e| format!("redis.psubscribe: {e}"))?;
1622 let pat: String = msg.get_pattern()
1623 .ok()
1624 .and_then(|v: Option<String>| v)
1625 .unwrap_or_else(|| pattern.clone());
1626 let ch: String = msg.get_channel_name().to_string();
1627 let payload: String = msg.get_payload()
1628 .map_err(|e| format!("redis.psubscribe: payload: {e}"))?;
1629 let handler = DefaultHandler::new(policy.clone())
1630 .with_program(Arc::clone(&program));
1631 let mut vm = Vm::with_handler(&program, Box::new(handler));
1632 vm.invoke_closure_value(closure.clone(), vec![
1633 Value::Str(pat.into()),
1634 Value::Str(ch.into()),
1635 Value::Str(payload.into()),
1636 ]).map_err(|e| format!("redis.psubscribe: handler: {e:?}"))?;
1637 }
1638 }
1639 ("redis", "lpush") => {
1640 let h = expect_redis_handle(args.first())?;
1641 let key = expect_str(args.get(1))?.to_string();
1642 let val = expect_str(args.get(2))?.to_string();
1643 let mut reg = redis_registry().lock().unwrap();
1644 let entry = reg.touch_get_mut(h)
1645 .ok_or_else(|| "redis.lpush: closed or unknown ConnRedis handle".to_string())?;
1646 use redis::Commands;
1647 let n: i64 = entry.conn.lpush(&key, &val)
1648 .map_err(|e| format!("redis.lpush: {e}"))?;
1649 Ok(Value::Int(n))
1650 }
1651 ("redis", "rpush") => {
1652 let h = expect_redis_handle(args.first())?;
1653 let key = expect_str(args.get(1))?.to_string();
1654 let val = expect_str(args.get(2))?.to_string();
1655 let mut reg = redis_registry().lock().unwrap();
1656 let entry = reg.touch_get_mut(h)
1657 .ok_or_else(|| "redis.rpush: closed or unknown ConnRedis handle".to_string())?;
1658 use redis::Commands;
1659 let n: i64 = entry.conn.rpush(&key, &val)
1660 .map_err(|e| format!("redis.rpush: {e}"))?;
1661 Ok(Value::Int(n))
1662 }
1663 ("redis", "brpop") => {
1664 let h = expect_redis_handle(args.first())?;
1667 let key = expect_str(args.get(1))?.to_string();
1668 let timeout = expect_int(args.get(2))?;
1669 let mut reg = redis_registry().lock().unwrap();
1670 let entry = reg.touch_get_mut(h)
1671 .ok_or_else(|| "redis.brpop: closed or unknown ConnRedis handle".to_string())?;
1672 use redis::Commands;
1673 let result: Option<(String, String)> = entry.conn
1676 .brpop(&key, timeout as f64)
1677 .map_err(|e| format!("redis.brpop: {e}"))?;
1678 match result {
1679 Some((_, v)) => Ok(some(Value::Str(v.into()))),
1680 None => Ok(none()),
1681 }
1682 }
1683 ("redis", "llen") => {
1684 let h = expect_redis_handle(args.first())?;
1685 let key = expect_str(args.get(1))?.to_string();
1686 let mut reg = redis_registry().lock().unwrap();
1687 let entry = reg.touch_get_mut(h)
1688 .ok_or_else(|| "redis.llen: closed or unknown ConnRedis handle".to_string())?;
1689 use redis::Commands;
1690 let n: i64 = entry.conn.llen(&key)
1691 .map_err(|e| format!("redis.llen: {e}"))?;
1692 Ok(Value::Int(n))
1693 }
1694 ("redis", "hset") => {
1695 let h = expect_redis_handle(args.first())?;
1696 let key = expect_str(args.get(1))?.to_string();
1697 let field = expect_str(args.get(2))?.to_string();
1698 let val = expect_str(args.get(3))?.to_string();
1699 let mut reg = redis_registry().lock().unwrap();
1700 let entry = reg.touch_get_mut(h)
1701 .ok_or_else(|| "redis.hset: closed or unknown ConnRedis handle".to_string())?;
1702 use redis::Commands;
1703 entry.conn.hset::<_, _, _, ()>(&key, &field, &val)
1704 .map_err(|e| format!("redis.hset: {e}"))?;
1705 Ok(Value::Unit)
1706 }
1707 ("redis", "hget") => {
1708 let h = expect_redis_handle(args.first())?;
1709 let key = expect_str(args.get(1))?.to_string();
1710 let field = expect_str(args.get(2))?.to_string();
1711 let mut reg = redis_registry().lock().unwrap();
1712 let entry = reg.touch_get_mut(h)
1713 .ok_or_else(|| "redis.hget: closed or unknown ConnRedis handle".to_string())?;
1714 use redis::Commands;
1715 match entry.conn.hget::<_, _, Option<String>>(&key, &field) {
1716 Ok(Some(v)) => Ok(some(Value::Str(v.into()))),
1717 Ok(None) => Ok(none()),
1718 Err(e) => Err(format!("redis.hget: {e}")),
1719 }
1720 }
1721 ("redis", "hdel") => {
1722 let h = expect_redis_handle(args.first())?;
1723 let key = expect_str(args.get(1))?.to_string();
1724 let field = expect_str(args.get(2))?.to_string();
1725 let mut reg = redis_registry().lock().unwrap();
1726 let entry = reg.touch_get_mut(h)
1727 .ok_or_else(|| "redis.hdel: closed or unknown ConnRedis handle".to_string())?;
1728 use redis::Commands;
1729 entry.conn.hdel::<_, _, ()>(&key, &field)
1730 .map_err(|e| format!("redis.hdel: {e}"))?;
1731 Ok(Value::Unit)
1732 }
1733 ("redis", "hgetall") => {
1734 let h = expect_redis_handle(args.first())?;
1735 let key = expect_str(args.get(1))?.to_string();
1736 let mut reg = redis_registry().lock().unwrap();
1737 let entry = reg.touch_get_mut(h)
1738 .ok_or_else(|| "redis.hgetall: closed or unknown ConnRedis handle".to_string())?;
1739 use redis::Commands;
1740 let map: std::collections::HashMap<String, String> = entry.conn
1741 .hgetall(&key)
1742 .map_err(|e| format!("redis.hgetall: {e}"))?;
1743 let pairs: Vec<Value> = map.into_iter()
1744 .map(|(k, v)| Value::Tuple(vec![Value::Str(k.into()), Value::Str(v.into())]))
1745 .collect();
1746 Ok(Value::List(pairs.into()))
1747 }
1748
1749 other => Err(format!("unsupported effect {}.{}", other.0, other.1)),
1753 }
1754 }
1755
1756 fn take_exit(&mut self) -> Option<i32> {
1779 match self.requested_exit.load(Ordering::SeqCst) {
1780 crate::handler::NO_EXIT => None,
1781 code => Some(code as i32),
1782 }
1783 }
1784
1785 fn spawn_for_worker(&self) -> Option<Box<dyn lex_bytecode::vm::EffectHandler + Send>> {
1786 let mut fresh = DefaultHandler::new(self.policy.clone());
1787 fresh.budget_remaining = std::sync::Arc::clone(&self.budget_remaining);
1790 fresh.budget_ceiling = self.budget_ceiling;
1791 fresh.read_root = self.read_root.clone();
1792 fresh.program = self.program.clone();
1793 fresh.chat_registry = self.chat_registry.clone();
1794 fresh.streams = std::sync::Arc::clone(&self.streams);
1799 fresh.next_stream_id = std::sync::Arc::clone(&self.next_stream_id);
1800 fresh.program_args = self.program_args.clone();
1801 fresh.requested_exit = std::sync::Arc::clone(&self.requested_exit);
1804 Some(Box::new(fresh))
1805 }
1806}