diff --git a/crates/executor-core/src/sdk/bridge.rs b/crates/executor-core/src/sdk/bridge.rs index 3179a7c..bdc4b0d 100644 --- a/crates/executor-core/src/sdk/bridge.rs +++ b/crates/executor-core/src/sdk/bridge.rs @@ -43,6 +43,15 @@ where }) } +/// Build a Rhai runtime error from a message. Returns the boxed error +/// directly because every caller needs a `Box` (Rhai's error +/// type) — the shared home for the pattern the SDK bridges (secrets, email, +/// users, …) previously each copied. +#[allow(clippy::unnecessary_box_returns)] +pub(crate) fn runtime_err(msg: &str) -> Box { + EvalAltResult::ErrorRuntime(msg.into(), rhai::Position::NONE).into() +} + /// Convert a `serde_json::Value` into a Rhai `Dynamic` suitable for /// pushing into a script's scope. Numbers prefer the narrowest type /// (`i64` over `f64`); anything that can't round-trip falls back to a diff --git a/crates/executor-core/src/sdk/email.rs b/crates/executor-core/src/sdk/email.rs index eabd908..7f89117 100644 --- a/crates/executor-core/src/sdk/email.rs +++ b/crates/executor-core/src/sdk/email.rs @@ -26,7 +26,7 @@ use std::sync::Arc; -use super::bridge::block_on; +use super::bridge::{block_on, runtime_err}; use picloud_shared::{OutboundEmail, SdkCallCx, Services}; use rhai::{Array, Engine as RhaiEngine, EvalAltResult, Map, Module}; @@ -124,8 +124,3 @@ fn addresses(opts: &Map, key: &str) -> Result, Box> { } } } - -#[allow(clippy::unnecessary_box_returns)] -fn runtime_err(msg: &str) -> Box { - EvalAltResult::ErrorRuntime(msg.into(), rhai::Position::NONE).into() -} diff --git a/crates/executor-core/src/sdk/http.rs b/crates/executor-core/src/sdk/http.rs index 7219dc0..520c5a2 100644 --- a/crates/executor-core/src/sdk/http.rs +++ b/crates/executor-core/src/sdk/http.rs @@ -32,11 +32,10 @@ use std::collections::BTreeMap; use std::sync::Arc; -use picloud_shared::{HttpError, HttpRequest, HttpResponse, HttpService, SdkCallCx, Services}; +use picloud_shared::{HttpRequest, HttpResponse, HttpService, SdkCallCx, Services}; use rhai::{Dynamic, Engine as RhaiEngine, EvalAltResult, Map, Module}; -use tokio::runtime::Handle as TokioHandle; -use super::bridge::{dynamic_to_json, json_to_dynamic}; +use super::bridge::{block_on, dynamic_to_json, json_to_dynamic, runtime_err}; /// Bridge-side defaults (the service clamps server-side too). The /// `MAX_*` ceilings stay `i64` because they're compared against the @@ -280,7 +279,11 @@ fn invoke( max_redirects: opts.max_redirects, script_id: Some(cx.script_id.to_string()), }; - let resp = block_on(svc, cx, req)?; + let resp = { + let svc = svc.clone(); + let cx = cx.clone(); + block_on("http", async move { svc.request(&cx, req).await })? + }; Ok(response_to_dynamic(&resp)) } @@ -310,7 +313,11 @@ fn invoke_form( max_redirects: opts.max_redirects, script_id: Some(cx.script_id.to_string()), }; - let resp = block_on(svc, cx, req)?; + let resp = { + let svc = svc.clone(); + let cx = cx.clone(); + block_on("http", async move { svc.request(&cx, req).await })? + }; Ok(response_to_dynamic(&resp)) } @@ -356,36 +363,10 @@ fn dyn_to_string(v: &Dynamic) -> String { } } -// Rhai's native-fn error channel is `Box`, so these -// helpers return the boxed form the call sites need. +// A validation error, prefixed like the service's runtime errors (the shared +// `bridge::block_on("http", …)` prefixes the same way, so messages are uniform). +// Delegates to `bridge::runtime_err`; the boxed return is Rhai's error channel. #[allow(clippy::unnecessary_box_returns)] fn err(msg: String) -> Box { - EvalAltResult::ErrorRuntime(format!("http: {msg}").into(), rhai::Position::NONE).into() -} - -/// Run the async service call from the synchronous Rhai context. Same -/// pattern as `kv`/`docs`: the script runs under `spawn_blocking`, so a -/// runtime handle is reachable and blocking on it is correct. -fn block_on( - svc: &Arc, - cx: &Arc, - req: HttpRequest, -) -> Result> { - let handle = TokioHandle::try_current().map_err(|e| -> Box { - EvalAltResult::ErrorRuntime( - format!("http: no tokio runtime available: {e}").into(), - rhai::Position::NONE, - ) - .into() - })?; - let svc = svc.clone(); - let cx = cx.clone(); - handle - .block_on(async move { svc.request(&cx, req).await }) - .map_err(map_http_err) -} - -#[allow(clippy::unnecessary_box_returns)] -fn map_http_err(e: HttpError) -> Box { - EvalAltResult::ErrorRuntime(format!("http: {e}").into(), rhai::Position::NONE).into() + runtime_err(&format!("http: {msg}")) } diff --git a/crates/executor-core/src/sdk/secrets.rs b/crates/executor-core/src/sdk/secrets.rs index 0db54fa..d133150 100644 --- a/crates/executor-core/src/sdk/secrets.rs +++ b/crates/executor-core/src/sdk/secrets.rs @@ -21,7 +21,7 @@ use std::sync::Arc; use picloud_shared::{SdkCallCx, SecretsListPage, Services}; use rhai::{Array, Dynamic, Engine as RhaiEngine, EvalAltResult, Map, Module}; -use super::bridge::{block_on, dynamic_to_json, json_to_dynamic}; +use super::bridge::{block_on, dynamic_to_json, json_to_dynamic, runtime_err}; pub(super) fn register(engine: &mut RhaiEngine, services: &Services, cx: Arc) { let svc = services.secrets.clone(); @@ -124,10 +124,3 @@ fn list_page_to_map(page: SecretsListPage) -> Map { ); m } - -// Returns the boxed error directly because every caller needs a -// `Box` (Rhai's error type), matching the other bridges. -#[allow(clippy::unnecessary_box_returns)] -fn runtime_err(msg: &str) -> Box { - EvalAltResult::ErrorRuntime(msg.into(), rhai::Position::NONE).into() -} diff --git a/crates/executor-core/src/sdk/users.rs b/crates/executor-core/src/sdk/users.rs index a0bdccc..06d6e69 100644 --- a/crates/executor-core/src/sdk/users.rs +++ b/crates/executor-core/src/sdk/users.rs @@ -50,7 +50,7 @@ use std::sync::Arc; -use super::bridge::block_on; +use super::bridge::{block_on, runtime_err}; use picloud_shared::{ AppUser, AppUserId, CreateUserInput, EmailTemplateOpts, GeneratedAccept, GeneratedSession, InviteOpts, SdkCallCx, Services, UpdateUserInput, UsersListOpts, UsersListPage, UsersService, @@ -615,8 +615,3 @@ fn optional_string(opts: &Map, key: &str) -> Option { Some(d) => Some(d.to_string()), } } - -#[allow(clippy::unnecessary_box_returns)] -fn runtime_err(msg: &str) -> Box { - EvalAltResult::ErrorRuntime(msg.into(), rhai::Position::NONE).into() -}