quickjs-rusty
quickjs-rusty copied to clipboard
Implement timeout feature
As per this issue in the old repo.
I tested the solution and it works (the example evaluates a list of expressions given an Object as global):
pub fn execute_js_isolated_new(
input_data: Value,
js_code: &[String],
) -> Result<Vec<ExecutionResult>, String> {
let context = Context::builder()
.memory_limit(1024 * 1024)
.build()
.unwrap();
context
.set_global(
"input",
to_js(unsafe { context.context_raw() }, &input_data).unwrap(),
)
.unwrap();
let timeout = Box::new(SystemTime::now() + Duration::from_millis(TIMEOUT_MS));
let ptr = Box::into_raw(timeout);
extern "C" fn timeout_interrupt(
_rt: *mut q::JSRuntime,
opaque: *mut std::ffi::c_void,
) -> ::std::os::raw::c_int {
let ts: SystemTime = unsafe { std::ptr::read(opaque as *const SystemTime) };
if SystemTime::now().gt(&ts) { 1 } else { 0 }
}
let runtime = unsafe { q::JS_GetRuntime(context.context_raw()) };
unsafe {
q::JS_SetInterruptHandler(
runtime,
Some(timeout_interrupt),
ptr as *mut std::ffi::c_void,
);
}
let mut values = Vec::new();
for s in js_code {
let maybe_eval_res = context.eval(
&format!(
r#"
let __result;
try {{
__result = {{ success: {} }};
}} catch (e) {{
__result = {{ error: e.toString() }};
}}
JSON.stringify(__result);
"#,
s
),
true,
);
let final_val = match maybe_eval_res {
Ok(r) => {
let result_str = r.to_string().map_err(|e| e.to_string())?;
serde_json::from_str(&result_str).map_err(|e| e.to_string())?
}
Err(e) => ExecutionResult::Error(e.to_string()),
};
values.push(final_val);
}
Ok(values)
}