fix(executor-core): F-Q-002 promote sdk::bridge::block_on, migrate 9 SDK modules

Replace ten near-identical `block_on` helpers (one per SDK module)
with a single shared `sdk::bridge::block_on(service: &str, fut)`.
The helper takes a service-prefix string and a future whose error
implements Display, so each module's `KvError`/`DocsError`/etc.
still self-formats.

Migrated:
- kv, docs, pubsub, users, dead_letters, secrets, files, email
- queue.rs has two helpers; the inline-shaped enqueue path and the
  block_on_u64 (u64→i64) wrapper are left in place — the latter
  could use the shared helper but the local form is one less call
  site per finding overlap. Will revisit on a later pass if needed.
- http.rs is intentionally NOT migrated: it has per-variant error
  mapping via `map_http_err` that the generic helper can't express.

Net: -218 / +97 lines across the 9 migrated files. Single source of
truth for the runtime-handle lookup and error wrapping.

AUDIT.md anchor: F-Q-002.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This commit is contained in:
MechaCat02
2026-06-07 19:54:37 +02:00
parent 04dc81115e
commit 5c50ce2e11
9 changed files with 97 additions and 218 deletions

View File

@@ -23,12 +23,11 @@
use std::sync::Arc;
use picloud_shared::{DocId, DocRow, DocsError, DocsService, SdkCallCx, Services};
use picloud_shared::{DocId, DocRow, DocsService, SdkCallCx, Services};
use rhai::{Array, Dynamic, Engine as RhaiEngine, EvalAltResult, Map, Module};
use tokio::runtime::Handle as TokioHandle;
use uuid::Uuid;
use super::bridge::{dynamic_to_json, json_to_dynamic};
use super::bridge::{block_on, dynamic_to_json, json_to_dynamic};
/// Per-call handle captured by the Rhai SDK. Cheap to clone (two Arcs
/// plus an owned string).
@@ -79,7 +78,7 @@ fn register_create(engine: &mut RhaiEngine) {
|handle: &mut DocsHandle, data: Map| -> Result<String, Box<EvalAltResult>> {
let h = handle.clone();
let json = dynamic_to_json(&Dynamic::from(data));
let id = block_on(async move { h.service.create(&h.cx, &h.collection, json).await })?;
let id = block_on("docs", async move { h.service.create(&h.cx, &h.collection, json).await })?;
Ok(id.to_string())
},
);
@@ -92,7 +91,7 @@ fn register_get(engine: &mut RhaiEngine) {
let h = handle.clone();
let parsed_id = parse_doc_id(id)?;
let row =
block_on(async move { h.service.get(&h.cx, &h.collection, parsed_id).await })?;
block_on("docs", async move { h.service.get(&h.cx, &h.collection, parsed_id).await })?;
Ok(row.map_or(Dynamic::UNIT, |d| Dynamic::from(doc_to_map(&d))))
},
);
@@ -104,7 +103,7 @@ fn register_find(engine: &mut RhaiEngine) {
|handle: &mut DocsHandle, filter: Map| -> Result<Array, Box<EvalAltResult>> {
let h = handle.clone();
let json = dynamic_to_json(&Dynamic::from(filter));
let rows = block_on(async move { h.service.find(&h.cx, &h.collection, json).await })?;
let rows = block_on("docs", async move { h.service.find(&h.cx, &h.collection, json).await })?;
Ok(rows
.iter()
.map(|d| Dynamic::from(doc_to_map(d)))
@@ -120,7 +119,7 @@ fn register_find_one(engine: &mut RhaiEngine) {
let h = handle.clone();
let json = dynamic_to_json(&Dynamic::from(filter));
let row =
block_on(async move { h.service.find_one(&h.cx, &h.collection, json).await })?;
block_on("docs", async move { h.service.find_one(&h.cx, &h.collection, json).await })?;
Ok(row.map_or(Dynamic::UNIT, |d| Dynamic::from(doc_to_map(&d))))
},
);
@@ -133,7 +132,7 @@ fn register_update(engine: &mut RhaiEngine) {
let h = handle.clone();
let parsed_id = parse_doc_id(id)?;
let json = dynamic_to_json(&Dynamic::from(data));
block_on(async move {
block_on("docs", async move {
h.service
.update(&h.cx, &h.collection, parsed_id, json)
.await
@@ -148,7 +147,7 @@ fn register_delete(engine: &mut RhaiEngine) {
|handle: &mut DocsHandle, id: &str| -> Result<bool, Box<EvalAltResult>> {
let h = handle.clone();
let parsed_id = parse_doc_id(id)?;
block_on(async move { h.service.delete(&h.cx, &h.collection, parsed_id).await })
block_on("docs", async move { h.service.delete(&h.cx, &h.collection, parsed_id).await })
},
);
}
@@ -192,7 +191,7 @@ fn list_call(
limit: u32,
) -> Result<Map, Box<EvalAltResult>> {
let h = handle.clone();
let page = block_on(async move {
let page = block_on("docs", async move {
h.service
.list(&h.cx, &h.collection, cursor.as_deref(), limit)
.await
@@ -233,23 +232,3 @@ fn parse_doc_id(id: &str) -> Result<DocId, Box<EvalAltResult>> {
})
}
/// Mirrors `kv.rs::block_on` — Tokio runtime is reachable from inside
/// the `spawn_blocking` wrapper that owns Rhai execution. Errors
/// prefix with `"docs: "` so scripts see `docs: forbidden`,
/// `docs: document not found`, `docs: unsupported operator: …`, etc.
fn block_on<F, T>(fut: F) -> Result<T, Box<EvalAltResult>>
where
F: std::future::Future<Output = Result<T, DocsError>> + Send,
T: Send,
{
let handle = TokioHandle::try_current().map_err(|e| -> Box<EvalAltResult> {
EvalAltResult::ErrorRuntime(
format!("docs: no tokio runtime available: {e}").into(),
rhai::Position::NONE,
)
.into()
})?;
handle.block_on(fut).map_err(|err| -> Box<EvalAltResult> {
EvalAltResult::ErrorRuntime(format!("docs: {err}").into(), rhai::Position::NONE).into()
})
}