| use super::RuntimeState; |
| use super::callbacks::audio_callback; |
| use super::callbacks::clear_timeout_callback; |
| use super::callbacks::exit_callback; |
| use super::callbacks::generated_image_callback; |
| use super::callbacks::image_callback; |
| use super::callbacks::load_callback; |
| use super::callbacks::notify_callback; |
| use super::callbacks::set_timeout_callback; |
| use super::callbacks::store_callback; |
| use super::callbacks::text_callback; |
| use super::callbacks::tool_callback; |
| use super::callbacks::yield_control_callback; |
|
|
| pub(super) fn install_globals(scope: &mut v8::PinScope<'_, '_>) -> Result<(), String> { |
| let global = scope.get_current_context().global(scope); |
| delete_global(scope, global, "console")?; |
| delete_global(scope, global, "Atomics")?; |
| delete_global(scope, global, "SharedArrayBuffer")?; |
| delete_global(scope, global, "WebAssembly")?; |
|
|
| let tools = build_tools_object(scope)?; |
| let all_tools = build_all_tools_value(scope)?; |
| let clear_timeout = helper_function(scope, "clearTimeout", clear_timeout_callback)?; |
| let set_timeout = helper_function(scope, "setTimeout", set_timeout_callback)?; |
| let text = helper_function(scope, "text", text_callback)?; |
| let image = helper_function(scope, "image", image_callback)?; |
| let audio = helper_function(scope, "audio", audio_callback)?; |
| let generated_image = helper_function(scope, "generatedImage", generated_image_callback)?; |
| let store = helper_function(scope, "store", store_callback)?; |
| let load = helper_function(scope, "load", load_callback)?; |
| let notify = helper_function(scope, "notify", notify_callback)?; |
| let yield_control = helper_function(scope, "yield_control", yield_control_callback)?; |
| let exit = helper_function(scope, "exit", exit_callback)?; |
|
|
| set_global(scope, global, "tools", tools.into())?; |
| set_global(scope, global, "ALL_TOOLS", all_tools)?; |
| set_global(scope, global, "clearTimeout", clear_timeout.into())?; |
| set_global(scope, global, "setTimeout", set_timeout.into())?; |
| set_global(scope, global, "text", text.into())?; |
| set_global(scope, global, "image", image.into())?; |
| set_global(scope, global, "audio", audio.into())?; |
| set_global(scope, global, "generatedImage", generated_image.into())?; |
| set_global(scope, global, "store", store.into())?; |
| set_global(scope, global, "load", load.into())?; |
| set_global(scope, global, "notify", notify.into())?; |
| set_global(scope, global, "yield_control", yield_control.into())?; |
| set_global(scope, global, "exit", exit.into())?; |
| Ok(()) |
| } |
|
|
| fn build_tools_object<'s>( |
| scope: &mut v8::PinScope<'s, '_>, |
| ) -> Result<v8::Local<'s, v8::Object>, String> { |
| let tools = v8::Object::new(scope); |
| let enabled_tools = scope |
| .get_slot::<RuntimeState>() |
| .map(|state| state.enabled_tools.clone()) |
| .unwrap_or_default(); |
|
|
| for (tool_index, tool) in enabled_tools.iter().enumerate() { |
| let name = v8::String::new(scope, &tool.global_name) |
| .ok_or_else(|| "failed to allocate tool name".to_string())?; |
| let function = tool_function(scope, tool_index)?; |
| tools.set(scope, name.into(), function.into()); |
| } |
| Ok(tools) |
| } |
|
|
| fn build_all_tools_value<'s>( |
| scope: &mut v8::PinScope<'s, '_>, |
| ) -> Result<v8::Local<'s, v8::Value>, String> { |
| let enabled_tools = scope |
| .get_slot::<RuntimeState>() |
| .map(|state| state.enabled_tools.clone()) |
| .unwrap_or_default(); |
| let array = v8::Array::new(scope, enabled_tools.len() as i32); |
| let name_key = v8::String::new(scope, "name") |
| .ok_or_else(|| "failed to allocate ALL_TOOLS name key".to_string())?; |
| let description_key = v8::String::new(scope, "description") |
| .ok_or_else(|| "failed to allocate ALL_TOOLS description key".to_string())?; |
|
|
| for (index, tool) in enabled_tools.iter().enumerate() { |
| let item = v8::Object::new(scope); |
| let name = v8::String::new(scope, &tool.global_name) |
| .ok_or_else(|| "failed to allocate ALL_TOOLS name".to_string())?; |
| let description = v8::String::new(scope, &tool.description) |
| .ok_or_else(|| "failed to allocate ALL_TOOLS description".to_string())?; |
|
|
| if item.set(scope, name_key.into(), name.into()) != Some(true) { |
| return Err("failed to set ALL_TOOLS name".to_string()); |
| } |
| if item.set(scope, description_key.into(), description.into()) != Some(true) { |
| return Err("failed to set ALL_TOOLS description".to_string()); |
| } |
| if array.set_index(scope, index as u32, item.into()) != Some(true) { |
| return Err("failed to append ALL_TOOLS metadata".to_string()); |
| } |
| } |
|
|
| Ok(array.into()) |
| } |
|
|
| fn helper_function<'s, F>( |
| scope: &mut v8::PinScope<'s, '_>, |
| name: &str, |
| callback: F, |
| ) -> Result<v8::Local<'s, v8::Function>, String> |
| where |
| F: v8::MapFnTo<v8::FunctionCallback>, |
| { |
| let name = |
| v8::String::new(scope, name).ok_or_else(|| "failed to allocate helper name".to_string())?; |
| let template = v8::FunctionTemplate::builder(callback) |
| .data(name.into()) |
| .build(scope); |
| template |
| .get_function(scope) |
| .ok_or_else(|| "failed to create helper function".to_string()) |
| } |
|
|
| fn tool_function<'s>( |
| scope: &mut v8::PinScope<'s, '_>, |
| tool_index: usize, |
| ) -> Result<v8::Local<'s, v8::Function>, String> { |
| let data = v8::String::new(scope, &tool_index.to_string()) |
| .ok_or_else(|| "failed to allocate tool callback data".to_string())?; |
| let template = v8::FunctionTemplate::builder(tool_callback) |
| .data(data.into()) |
| .build(scope); |
| template |
| .get_function(scope) |
| .ok_or_else(|| "failed to create tool function".to_string()) |
| } |
|
|
| fn set_global<'s>( |
| scope: &mut v8::PinScope<'s, '_>, |
| global: v8::Local<'s, v8::Object>, |
| name: &str, |
| value: v8::Local<'s, v8::Value>, |
| ) -> Result<(), String> { |
| let key = v8::String::new(scope, name) |
| .ok_or_else(|| format!("failed to allocate global `{name}`"))?; |
| if global.set(scope, key.into(), value) == Some(true) { |
| Ok(()) |
| } else { |
| Err(format!("failed to set global `{name}`")) |
| } |
| } |
|
|
| fn delete_global<'s>( |
| scope: &mut v8::PinScope<'s, '_>, |
| global: v8::Local<'s, v8::Object>, |
| name: &str, |
| ) -> Result<(), String> { |
| let key = v8::String::new(scope, name) |
| .ok_or_else(|| format!("failed to allocate global `{name}`"))?; |
| if global.delete(scope, key.into()) == Some(true) { |
| Ok(()) |
| } else { |
| Err(format!("failed to remove global `{name}`")) |
| } |
| } |
|
|