diff --git a/canister_templates/stable.wasm b/canister_templates/stable.wasm index 2c4058913d..e268860f02 100644 Binary files a/canister_templates/stable.wasm and b/canister_templates/stable.wasm differ diff --git a/src/build/stable/commands/compile/wasm_binary/rust/stable_canister_template/src/azle_error.rs b/src/build/stable/commands/compile/wasm_binary/rust/stable_canister_template/src/azle_error.rs new file mode 100644 index 0000000000..4e8257f119 --- /dev/null +++ b/src/build/stable/commands/compile/wasm_binary/rust/stable_canister_template/src/azle_error.rs @@ -0,0 +1,44 @@ +#[derive(Debug)] +pub enum AzleError { + Init(Box), + PostUpgrade(Box), + MethodExecution(Box), + QuickJSContextNotInitialized, + QuickJSCallbackExecutionFailed(Box), + WasmDataVecToString(Box), + WasmDataStringToStruct(Box), +} + +impl std::fmt::Display for AzleError { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + match self { + AzleError::QuickJSContextNotInitialized => { + write!(f, "QuickJS context not initialized") + } + AzleError::QuickJSCallbackExecutionFailed(error) => { + write!(f, "QuickJS callback execution failed: {}", error) + } + AzleError::MethodExecution(error) => { + write!(f, "Azle MethodExecutionError: {}", error) + } + AzleError::Init(error) => write!(f, "Azle InitError: {}", error), + AzleError::PostUpgrade(error) => write!(f, "Azle PostUpgradeError: {}", error), + AzleError::WasmDataVecToString(error) => { + write!( + f, + "WasmData conversion failed while converting Vec to String: {}", + error + ) + } + AzleError::WasmDataStringToStruct(error) => { + write!( + f, + "WasmData conversion failed while converting String to WasmData Struct: {}", + error + ) + } + } + } +} + +impl std::error::Error for AzleError {} diff --git a/src/build/stable/commands/compile/wasm_binary/rust/stable_canister_template/src/candid.rs b/src/build/stable/commands/compile/wasm_binary/rust/stable_canister_template/src/candid.rs index 1be5a877c0..68795f0f8c 100644 --- a/src/build/stable/commands/compile/wasm_binary/rust/stable_canister_template/src/candid.rs +++ b/src/build/stable/commands/compile/wasm_binary/rust/stable_canister_template/src/candid.rs @@ -1,17 +1,19 @@ use crate::{ ic, quickjs_with_ctx, wasm_binary_manipulation::get_js_code, CONTEXT_REF_CELL, MODULE_NAME, }; +use std::error::Error; -// TODO we might not need any of these panic hooks - -// Heavily inspired by https://stackoverflow.com/a/47676844 #[no_mangle] pub fn get_candid_and_method_meta_pointer() -> *mut std::os::raw::c_char { std::panic::set_hook(Box::new(|panic_info| { - let msg = match panic_info.payload().downcast_ref::<&str>() { - Some(s) => *s, - None => "Unknown panic message", + let msg = if let Some(s) = panic_info.payload().downcast_ref::<&str>() { + *s + } else if let Some(s) = panic_info.payload().downcast_ref::() { + s.as_str() + } else { + "Unknown panic message" }; + let location = if let Some(location) = panic_info.location() { format!(" at {}:{}", location.file(), location.line()) } else { @@ -23,44 +25,46 @@ pub fn get_candid_and_method_meta_pointer() -> *mut std::os::raw::c_char { ic_cdk::println!("{}", message); })); - let runtime = rquickjs::Runtime::new().unwrap(); - let context = rquickjs::Context::full(&runtime).unwrap(); + match initialize_and_get_candid() { + Ok(c_string) => c_string, + Err(e) => { + ic_cdk::trap(&format!("Error during candid initialization: {}", e)); + } + } +} + +fn initialize_and_get_candid() -> Result<*mut std::os::raw::c_char, Box> { + let runtime = rquickjs::Runtime::new()?; + let context = rquickjs::Context::full(&runtime)?; CONTEXT_REF_CELL.with(|context_ref_cell| { *context_ref_cell.borrow_mut() = Some(context); }); - quickjs_with_ctx(|ctx| { + quickjs_with_ctx(|ctx| -> Result<*mut std::os::raw::c_char, Box> { ctx.clone() .globals() - .set("_azleNodeWasmEnvironment", true) - .unwrap(); + .set("_azleNodeWasmEnvironment", true)?; - ic::register(ctx.clone()); + ic::register(ctx.clone())?; ctx.clone() .globals() - .set("exports", rquickjs::Object::new(ctx.clone()).unwrap()) - .unwrap(); + .set("exports", rquickjs::Object::new(ctx.clone())?)?; - ctx.clone() - .globals() - .set("_azleExperimental", false) - .unwrap(); + ctx.clone().globals().set("_azleExperimental", false)?; - let js = get_js_code(); + let js = get_js_code()?; - // TODO is there a better name for this main module? - // TODO this returns a promise...make sure we handle it appropriately - rquickjs::Module::evaluate(ctx.clone(), MODULE_NAME, js).unwrap(); + rquickjs::Module::evaluate(ctx.clone(), MODULE_NAME, std::str::from_utf8(&js)?)?; let get_candid_and_method_meta: rquickjs::Function = - ctx.globals().get("_azleGetCandidAndMethodMeta").unwrap(); + ctx.globals().get("_azleGetCandidAndMethodMeta")?; - let candid_and_method_meta: String = get_candid_and_method_meta.call(()).unwrap(); + let candid_and_method_meta: String = get_candid_and_method_meta.call(())?; - let c_string = std::ffi::CString::new(candid_and_method_meta).unwrap(); + let c_string = std::ffi::CString::new(candid_and_method_meta)?; - c_string.into_raw() + Ok(c_string.into_raw()) }) } diff --git a/src/build/stable/commands/compile/wasm_binary/rust/stable_canister_template/src/execute_method_js.rs b/src/build/stable/commands/compile/wasm_binary/rust/stable_canister_template/src/execute_method_js.rs index 92f1a3be2f..b77716badc 100644 --- a/src/build/stable/commands/compile/wasm_binary/rust/stable_canister_template/src/execute_method_js.rs +++ b/src/build/stable/commands/compile/wasm_binary/rust/stable_canister_template/src/execute_method_js.rs @@ -1,15 +1,16 @@ use crate::quickjs_with_ctx; +use std::error::Error; #[no_mangle] #[allow(unused)] pub extern "C" fn execute_method_js(function_index: i32, pass_arg_data: i32) { - let function_name = &function_index.to_string(); - let pass_arg_data = if pass_arg_data == 1 { true } else { false }; + let function_name = function_index.to_string(); + let pass_arg_data = pass_arg_data == 1; - quickjs_with_ctx(|ctx| { - let callbacks: rquickjs::Object = ctx.clone().globals().get("_azleCallbacks").unwrap(); + if let Err(error) = quickjs_with_ctx(|ctx| -> Result<(), Box> { + let callbacks: rquickjs::Object = ctx.clone().globals().get("_azleCallbacks")?; - let method_callback: rquickjs::Function = callbacks.get(function_name).unwrap(); + let method_callback: rquickjs::Function = callbacks.get(&function_name)?; let candid_args = if pass_arg_data { ic_cdk::api::call::arg_data_raw() @@ -17,8 +18,10 @@ pub extern "C" fn execute_method_js(function_index: i32, pass_arg_data: i32) { vec![] }; - method_callback - .call::<_, rquickjs::Undefined>((candid_args,)) - .unwrap(); - }); + method_callback.call::<_, rquickjs::Undefined>((candid_args,))?; + + Ok(()) + }) { + ic_cdk::trap(&format!("Azle MethodExecutionError: {}", error)); + } } diff --git a/src/build/stable/commands/compile/wasm_binary/rust/stable_canister_template/src/ic/accept_message.rs b/src/build/stable/commands/compile/wasm_binary/rust/stable_canister_template/src/ic/accept_message.rs index be743b1e03..397d574334 100644 --- a/src/build/stable/commands/compile/wasm_binary/rust/stable_canister_template/src/ic/accept_message.rs +++ b/src/build/stable/commands/compile/wasm_binary/rust/stable_canister_template/src/ic/accept_message.rs @@ -1,8 +1,7 @@ use rquickjs::{Ctx, Function}; -pub fn get_function(context: Ctx) -> Function { +pub fn get_function(context: Ctx) -> Result { Function::new(context, || { ic_cdk::api::call::accept_message(); }) - .unwrap() } diff --git a/src/build/stable/commands/compile/wasm_binary/rust/stable_canister_template/src/ic/arg_data_raw.rs b/src/build/stable/commands/compile/wasm_binary/rust/stable_canister_template/src/ic/arg_data_raw.rs index 18648c2133..cbf16b11a2 100644 --- a/src/build/stable/commands/compile/wasm_binary/rust/stable_canister_template/src/ic/arg_data_raw.rs +++ b/src/build/stable/commands/compile/wasm_binary/rust/stable_canister_template/src/ic/arg_data_raw.rs @@ -1,8 +1,7 @@ use rquickjs::{Ctx, Function, TypedArray}; -pub fn get_function(context: Ctx) -> Function { +pub fn get_function(context: Ctx) -> Result { Function::new(context.clone(), move || { TypedArray::::new(context.clone(), ic_cdk::api::call::arg_data_raw()) }) - .unwrap() } diff --git a/src/build/stable/commands/compile/wasm_binary/rust/stable_canister_template/src/ic/call_raw.rs b/src/build/stable/commands/compile/wasm_binary/rust/stable_canister_template/src/ic/call_raw.rs index a15cb91428..53354b45c2 100644 --- a/src/build/stable/commands/compile/wasm_binary/rust/stable_canister_template/src/ic/call_raw.rs +++ b/src/build/stable/commands/compile/wasm_binary/rust/stable_canister_template/src/ic/call_raw.rs @@ -19,6 +19,8 @@ pub fn get_function(ctx: Ctx) -> Function { quickjs_with_ctx(move |ctx| { resolve_or_reject(ctx.clone(), &call_result, &promise_id); + + Ok(()) }); }); diff --git a/src/build/stable/commands/compile/wasm_binary/rust/stable_canister_template/src/ic/caller.rs b/src/build/stable/commands/compile/wasm_binary/rust/stable_canister_template/src/ic/caller.rs index a58cad407b..31fe0bae5c 100644 --- a/src/build/stable/commands/compile/wasm_binary/rust/stable_canister_template/src/ic/caller.rs +++ b/src/build/stable/commands/compile/wasm_binary/rust/stable_canister_template/src/ic/caller.rs @@ -1,8 +1,7 @@ -use rquickjs::{Ctx, Function, TypedArray}; +use rquickjs::{Ctx, Function, Result, TypedArray}; -pub fn get_function(context: Ctx) -> Function { +pub fn get_function(context: Ctx) -> Result { Function::new(context.clone(), move || { TypedArray::::new(context.clone(), ic_cdk::api::caller().as_slice()) }) - .unwrap() } diff --git a/src/build/stable/commands/compile/wasm_binary/rust/stable_canister_template/src/ic/mod.rs b/src/build/stable/commands/compile/wasm_binary/rust/stable_canister_template/src/ic/mod.rs index e1fdf03216..75fdbc87de 100644 --- a/src/build/stable/commands/compile/wasm_binary/rust/stable_canister_template/src/ic/mod.rs +++ b/src/build/stable/commands/compile/wasm_binary/rust/stable_canister_template/src/ic/mod.rs @@ -41,197 +41,161 @@ mod time; mod trap; #[allow(unused)] -pub fn register(context: rquickjs::Ctx) { - let ic = rquickjs::Object::new(context.clone()).unwrap(); +pub fn register(context: rquickjs::Ctx) -> rquickjs::Result<()> { + let ic = rquickjs::Object::new(context.clone())?; ic.set( "acceptMessage", accept_message::get_function(context.clone()), - ) - .unwrap(); + )?; - ic.set("argDataRaw", arg_data_raw::get_function(context.clone())) - .unwrap(); + ic.set("argDataRaw", arg_data_raw::get_function(context.clone()))?; - ic.set("callRaw", call_raw::get_function(context.clone())) - .unwrap(); + ic.set("callRaw", call_raw::get_function(context.clone()))?; - ic.set("caller", caller::get_function(context.clone())) - .unwrap(); + ic.set("caller", caller::get_function(context.clone()))?; ic.set( "candidCompiler", candid_compiler::get_function(context.clone()), - ) - .unwrap(); + )?; - ic.set("candidDecode", candid_decode::get_function(context.clone())) - .unwrap(); + ic.set("candidDecode", candid_decode::get_function(context.clone()))?; - ic.set("candidEncode", candid_encode::get_function(context.clone())) - .unwrap(); + ic.set("candidEncode", candid_encode::get_function(context.clone()))?; ic.set( "canisterBalance", canister_balance::get_function(context.clone()), - ) - .unwrap(); + )?; ic.set( "canisterVersion", canister_version::get_function(context.clone()), - ) - .unwrap(); + )?; - ic.set("clearTimer", clear_timer::get_function(context.clone())) - .unwrap(); + ic.set("clearTimer", clear_timer::get_function(context.clone()))?; - ic.set("cyclesBurn", cycles_burn::get_function(context.clone())) - .unwrap(); + ic.set("cyclesBurn", cycles_burn::get_function(context.clone()))?; ic.set( "dataCertificate", data_certificate::get_function(context.clone()), - ) - .unwrap(); + )?; - ic.set("id", id::get_function(context.clone())).unwrap(); + ic.set("id", id::get_function(context.clone()))?; ic.set( "instructionCounter", instruction_counter::get_function(context.clone()), - ) - .unwrap(); + )?; - ic.set("isController", is_controller::get_function(context.clone())) - .unwrap(); + ic.set("isController", is_controller::get_function(context.clone()))?; - ic.set("methodName", method_name::get_function(context.clone())) - .unwrap(); + ic.set("methodName", method_name::get_function(context.clone()))?; ic.set( "msgCyclesAccept", msg_cycles_accept::get_function(context.clone()), - ) - .unwrap(); + )?; ic.set( "msgCyclesAvailable", msg_cycles_available::get_function(context.clone()), - ) - .unwrap(); + )?; ic.set( "msgCyclesRefunded", msg_cycles_refunded::get_function(context.clone()), - ) - .unwrap(); + )?; - ic.set("notifyRaw", notify_raw::get_function(context.clone())) - .unwrap(); + ic.set("notifyRaw", notify_raw::get_function(context.clone()))?; ic.set( "performanceCounter", performance_counter::get_function(context.clone()), - ) - .unwrap(); + )?; - ic.set("print", print::get_function(context.clone())) - .unwrap(); + ic.set("print", print::get_function(context.clone()))?; - ic.set("reject", reject::get_function(context.clone())) - .unwrap(); + ic.set("reject", reject::get_function(context.clone()))?; - ic.set("rejectCode", reject_code::get_function(context.clone())) - .unwrap(); + ic.set("rejectCode", reject_code::get_function(context.clone()))?; ic.set( "rejectMessage", reject_message::get_function(context.clone()), - ) - .unwrap(); + )?; - ic.set("replyRaw", reply_raw::get_function(context.clone())) - .unwrap(); + ic.set("replyRaw", reply_raw::get_function(context.clone()))?; ic.set( "setCertifiedData", set_certified_data::get_function(context.clone()), - ) - .unwrap(); + )?; - ic.set("setTimer", set_timer::get_function(context.clone())) - .unwrap(); + ic.set("setTimer", set_timer::get_function(context.clone()))?; ic.set( "setTimerInterval", set_timer_interval::get_function(context.clone()), - ) - .unwrap(); + )?; ic.set( "stableBTreeMapContainsKey", stable_b_tree_map_contains_key::get_function(context.clone()), - ) - .unwrap(); + )?; ic.set( "stableBTreeMapGet", stable_b_tree_map_get::get_function(context.clone()), - ) - .unwrap(); + )?; ic.set( "stableBTreeMapInit", stable_b_tree_map_init::get_function(context.clone()), - ) - .unwrap(); + )?; ic.set( "stableBTreeMapInsert", stable_b_tree_map_insert::get_function(context.clone()), - ) - .unwrap(); + )?; ic.set( "stableBTreeMapIsEmpty", stable_b_tree_map_is_empty::get_function(context.clone()), - ) - .unwrap(); + )?; ic.set( "stableBTreeMapItems", stable_b_tree_map_items::get_function(context.clone()), - ) - .unwrap(); + )?; ic.set( "stableBTreeMapKeys", stable_b_tree_map_keys::get_function(context.clone()), - ) - .unwrap(); + )?; ic.set( "stableBTreeMapLen", stable_b_tree_map_len::get_function(context.clone()), - ) - .unwrap(); + )?; ic.set( "stableBTreeMapRemove", stable_b_tree_map_remove::get_function(context.clone()), - ) - .unwrap(); + )?; ic.set( "stableBTreeMapValues", stable_b_tree_map_values::get_function(context.clone()), - ) - .unwrap(); + )?; - ic.set("time", time::get_function(context.clone())).unwrap(); + ic.set("time", time::get_function(context.clone()))?; - ic.set("trap", trap::get_function(context.clone())).unwrap(); + ic.set("trap", trap::get_function(context.clone()))?; - context.clone().globals().set("_azleIcStable", ic).unwrap(); + context.clone().globals().set("_azleIcStable", ic)?; + + Ok(()) } diff --git a/src/build/stable/commands/compile/wasm_binary/rust/stable_canister_template/src/ic/set_timer.rs b/src/build/stable/commands/compile/wasm_binary/rust/stable_canister_template/src/ic/set_timer.rs index f675303c43..c164724579 100644 --- a/src/build/stable/commands/compile/wasm_binary/rust/stable_canister_template/src/ic/set_timer.rs +++ b/src/build/stable/commands/compile/wasm_binary/rust/stable_canister_template/src/ic/set_timer.rs @@ -21,6 +21,8 @@ pub fn get_function(ctx: Ctx) -> Function { if result.is_exception() { panic!("Timer callback threw an exception"); } + + Ok(()) }); }; diff --git a/src/build/stable/commands/compile/wasm_binary/rust/stable_canister_template/src/ic/set_timer_interval.rs b/src/build/stable/commands/compile/wasm_binary/rust/stable_canister_template/src/ic/set_timer_interval.rs index f79a5cf391..3ad861ea06 100644 --- a/src/build/stable/commands/compile/wasm_binary/rust/stable_canister_template/src/ic/set_timer_interval.rs +++ b/src/build/stable/commands/compile/wasm_binary/rust/stable_canister_template/src/ic/set_timer_interval.rs @@ -21,6 +21,8 @@ pub fn get_function(ctx: Ctx) -> Function { if result.is_exception() { panic!("Timer interval callback threw an exception"); } + + Ok(()) }); }; diff --git a/src/build/stable/commands/compile/wasm_binary/rust/stable_canister_template/src/init_and_post_upgrade.rs b/src/build/stable/commands/compile/wasm_binary/rust/stable_canister_template/src/init_and_post_upgrade.rs index a6d1925e11..dfa1cf8d5a 100644 --- a/src/build/stable/commands/compile/wasm_binary/rust/stable_canister_template/src/init_and_post_upgrade.rs +++ b/src/build/stable/commands/compile/wasm_binary/rust/stable_canister_template/src/init_and_post_upgrade.rs @@ -4,7 +4,7 @@ use crate::{ execute_method_js::execute_method_js, ic, quickjs_with_ctx, wasm_binary_manipulation::{get_js_code, get_wasm_data}, - CONTEXT_REF_CELL, MEMORY_MANAGER_REF_CELL, MODULE_NAME, + AzleError, CONTEXT_REF_CELL, MEMORY_MANAGER_REF_CELL, MODULE_NAME, }; #[inline(never)] @@ -15,39 +15,49 @@ pub extern "C" fn init(function_index: i32, pass_arg_data: i32) { // This causes problems during Wasm binary manipulation format!("prevent init and post_upgrade optimization"); - initialize(true, function_index, pass_arg_data); + if let Err(e) = initialize(true, function_index, pass_arg_data) { + let azle_error = AzleError::Init(e); + + ic_cdk::trap(&azle_error.to_string()); + } } #[inline(never)] #[no_mangle] pub extern "C" fn post_upgrade(function_index: i32, pass_arg_data: i32) { - initialize(false, function_index, pass_arg_data); + if let Err(e) = initialize(false, function_index, pass_arg_data) { + ic_cdk::trap(&format!("Azle PostUpgradeError: {}", e)); + } } -fn initialize(init: bool, function_index: i32, pass_arg_data: i32) { - std::panic::set_hook(Box::new(|panic_info| { - let msg = if let Some(s) = panic_info.payload().downcast_ref::<&str>() { - *s - } else if let Some(s) = panic_info.payload().downcast_ref::() { - s.as_str() - } else { - "Unknown panic message" - }; +fn initialize( + init: bool, + function_index: i32, + pass_arg_data: i32, +) -> Result<(), Box> { + // std::panic::set_hook(Box::new(|panic_info| { + // let msg = if let Some(s) = panic_info.payload().downcast_ref::<&str>() { + // *s + // } else if let Some(s) = panic_info.payload().downcast_ref::() { + // s.as_str() + // } else { + // "Unknown panic message" + // }; - let location = if let Some(location) = panic_info.location() { - format!(" at {}:{}", location.file(), location.line()) - } else { - " (unknown location)".to_string() - }; + // let location = if let Some(location) = panic_info.location() { + // format!(" at {}:{}", location.file(), location.line()) + // } else { + // " (unknown location)".to_string() + // }; - let message = &format!("Panic occurred: {}{}", msg, location); + // let message = &format!("Panic occurred: {}{}", msg, location); - ic_cdk::println!("{}", message); + // ic_cdk::println!("{}", message); - ic_cdk::trap(message); - })); + // ic_cdk::trap(message); + // })); - let wasm_data = get_wasm_data(); + let wasm_data = get_wasm_data()?; let env_vars: Vec<(&str, &str)> = wasm_data .env_vars @@ -57,62 +67,66 @@ fn initialize(init: bool, function_index: i32, pass_arg_data: i32) { let polyfill_memory = MEMORY_MANAGER_REF_CELL.with(|manager| manager.borrow().get(MemoryId::new(254))); + ic_wasi_polyfill::init_with_memory(&[], &env_vars, polyfill_memory); - let js = get_js_code(); + let js = get_js_code()?; initialize_js( - std::str::from_utf8(&js).unwrap(), + std::str::from_utf8(&js)?, init, function_index, pass_arg_data, - ); + )?; + + Ok(()) } // TODO do we need all these clonse? -// TODO do not forget to deal with the event loop everywhere -pub fn initialize_js(js: &str, init: bool, function_index: i32, pass_arg_data: i32) { - let runtime = rquickjs::Runtime::new().unwrap(); - let context = rquickjs::Context::full(&runtime).unwrap(); +pub fn initialize_js( + js: &str, + init: bool, + function_index: i32, + pass_arg_data: i32, +) -> Result<(), Box> { + let runtime = rquickjs::Runtime::new()?; + let context = rquickjs::Context::full(&runtime)?; CONTEXT_REF_CELL.with(|context_ref_cell| { *context_ref_cell.borrow_mut() = Some(context); }); - quickjs_with_ctx(|ctx| { + quickjs_with_ctx(|ctx| -> Result<(), Box> { ctx.clone() .globals() - .set("_azleNodeWasmEnvironment", false) - .unwrap(); + .set("_azleNodeWasmEnvironment", false)?; - ic::register(ctx.clone()); + ic::register(ctx.clone())?; - let env = rquickjs::Object::new(ctx.clone()).unwrap(); + let env = rquickjs::Object::new(ctx.clone())?; for (key, value) in std::env::vars() { - env.set(key, value).unwrap(); + env.set(key, value)?; } - let process = rquickjs::Object::new(ctx.clone()).unwrap(); + let process = rquickjs::Object::new(ctx.clone())?; - process.set("env", env).unwrap(); + process.set("env", env)?; - ctx.clone().globals().set("process", process).unwrap(); + ctx.clone().globals().set("process", process)?; ctx.clone() .globals() - .set("exports", rquickjs::Object::new(ctx.clone()).unwrap()) - .unwrap(); + .set("exports", rquickjs::Object::new(ctx.clone())?)?; - ctx.clone() - .globals() - .set("_azleExperimental", false) - .unwrap(); + ctx.clone().globals().set("_azleExperimental", false)?; // TODO is there a better name for this main module? // TODO this returns a promise...make sure we handle it appropriately - rquickjs::Module::evaluate(ctx.clone(), MODULE_NAME, js).unwrap(); - }); + rquickjs::Module::evaluate(ctx.clone(), MODULE_NAME, js)?; + + Ok(()) + })?; // TODO is it possible to just put this all in the same quickjs_with_ctx? if function_index != -1 { @@ -121,13 +135,16 @@ pub fn initialize_js(js: &str, init: bool, function_index: i32, pass_arg_data: i // _azleInitCalled and _azlePostUpgradeCalled refer to Azle's own init/post_upgrade methods being called // these variables do not indicate if the developer's own init/post_upgrade methods were called - quickjs_with_ctx(|ctx| { + quickjs_with_ctx(|ctx| -> Result<(), Box> { let assignment = if init { "globalThis._azleInitCalled = true;" } else { "globalThis._azlePostUpgradeCalled = true;" }; - ctx.eval::<(), _>(assignment).unwrap(); - }); + ctx.eval::<(), _>(assignment)?; + Ok(()) + })?; + + Ok(()) } diff --git a/src/build/stable/commands/compile/wasm_binary/rust/stable_canister_template/src/lib.rs b/src/build/stable/commands/compile/wasm_binary/rust/stable_canister_template/src/lib.rs index 9f8b2f0621..d624c2295f 100644 --- a/src/build/stable/commands/compile/wasm_binary/rust/stable_canister_template/src/lib.rs +++ b/src/build/stable/commands/compile/wasm_binary/rust/stable_canister_template/src/lib.rs @@ -1,16 +1,11 @@ -// TODO the plan is to integrate rquickjs for stable -// TODO and at that time create two crates -// TODO we should place each crate at src/build/stable/commands/compile/rust -// TODO and src/build/experimental/commands/compile/rust respectively - use std::cell::RefCell; -// #[allow(unused)] use ic_stable_structures::{ memory_manager::{MemoryManager, VirtualMemory}, DefaultMemoryImpl, }; +mod azle_error; mod candid; mod chunk; mod execute_method_js; @@ -21,6 +16,7 @@ mod quickjs_with_ctx; mod stable_b_tree_map; mod wasm_binary_manipulation; +pub use azle_error::AzleError; pub use quickjs_with_ctx::quickjs_with_ctx; const MODULE_NAME: &str = "main"; diff --git a/src/build/stable/commands/compile/wasm_binary/rust/stable_canister_template/src/quickjs_with_ctx.rs b/src/build/stable/commands/compile/wasm_binary/rust/stable_canister_template/src/quickjs_with_ctx.rs index 9f5c999062..f5bdcd6cb5 100644 --- a/src/build/stable/commands/compile/wasm_binary/rust/stable_canister_template/src/quickjs_with_ctx.rs +++ b/src/build/stable/commands/compile/wasm_binary/rust/stable_canister_template/src/quickjs_with_ctx.rs @@ -1,30 +1,30 @@ -use crate::CONTEXT_REF_CELL; +use std::error::Error; + use rquickjs::Ctx; -pub fn quickjs_with_ctx(callback: F) -> R +use crate::{AzleError, CONTEXT_REF_CELL}; + +pub fn quickjs_with_ctx(callback: F) -> Result> where - F: FnOnce(Ctx) -> R, + F: FnOnce(Ctx) -> Result>, { CONTEXT_REF_CELL.with(|context_ref_cell| { let context_ref = context_ref_cell.borrow(); - let context = context_ref.as_ref().unwrap(); + let context = context_ref + .as_ref() + .ok_or(AzleError::QuickJSContextNotInitialized)?; context.with(|ctx| { - let result = callback(ctx.clone()); + let result = + callback(ctx.clone()).map_err(|e| AzleError::QuickJSCallbackExecutionFailed(e))?; run_event_loop(ctx); - result + Ok(result) }) }) } -fn run_event_loop(ctx: rquickjs::Ctx) { - loop { - let result = ctx.execute_pending_job(); - - if result == false { - break; - } - } +fn run_event_loop(ctx: Ctx) { + while ctx.execute_pending_job() {} } diff --git a/src/build/stable/commands/compile/wasm_binary/rust/stable_canister_template/src/wasm_binary_manipulation.rs b/src/build/stable/commands/compile/wasm_binary/rust/stable_canister_template/src/wasm_binary_manipulation.rs index 3b8ee8680b..cb3149f4bb 100644 --- a/src/build/stable/commands/compile/wasm_binary/rust/stable_canister_template/src/wasm_binary_manipulation.rs +++ b/src/build/stable/commands/compile/wasm_binary/rust/stable_canister_template/src/wasm_binary_manipulation.rs @@ -1,5 +1,9 @@ +use std::error::Error; + use serde::{Deserialize, Serialize}; +use crate::AzleError; + #[derive(Debug, Serialize, Deserialize)] pub struct WasmData { #[serde(rename = "envVars")] @@ -9,49 +13,55 @@ pub struct WasmData { #[inline(never)] #[no_mangle] extern "C" fn init_js_passive_data(js_vec_location: i32) -> usize { - "123_456_789".parse::().unwrap() + js_vec_location as usize // TODO must be like this for weird optimization reasons + // This is to prevent compiler optimizations that interfere with the Wasm binary manipulation + std::env::var("init_js_passive_data").map_or(0, |s| s.len()) + js_vec_location as usize } -// TODO seems we need to do this to stop the compiler from hard-coding the result of this function where it is called -// TODO hopefully there's a less hacky way to do this #[inline(never)] #[no_mangle] extern "C" fn js_passive_data_size() -> usize { - "123_456_789".parse().unwrap() + // This is to prevent compiler optimizations that interfere with the Wasm binary manipulation + std::env::var("js_passive_data_size").map_or(0, |s| s.len()) } // TODO waiting on license inspired from https://github.com/adambratschikaye/wasm-inject-data/blob/main/src/static_wasm.rs -pub fn get_js_code() -> Vec { +pub fn get_js_code() -> Result, Box> { let size = js_passive_data_size(); let mut js_vec = vec![243; size]; let js_vec_location = js_vec.as_mut_ptr() as i32; init_js_passive_data(js_vec_location); - js_vec + Ok(js_vec) } #[inline(never)] #[no_mangle] extern "C" fn init_wasm_data_passive_data(wasm_data_vec_location: i32) -> usize { - "123_456_789".parse::().unwrap() + wasm_data_vec_location as usize // TODO must be like this for weird optimization reasons + // This is to prevent compiler optimizations that interfere with the Wasm binary manipulation + std::env::var("init_wasm_data_passive_data").map_or(0, |s| s.len()) + + wasm_data_vec_location as usize } -// TODO seems we need to do this to stop the compiler from hard-coding the result of this function where it is called -// TODO hopefully there's a less hacky way to do this #[inline(never)] #[no_mangle] extern "C" fn wasm_data_passive_data_size() -> usize { - "123_456_789".parse().unwrap() + // This is to prevent compiler optimizations that interfere with the Wasm binary manipulation + std::env::var("wasm_data_passive_data_size").map_or(0, |s| s.len()) } // TODO waiting on license inspired from https://github.com/adambratschikaye/wasm-inject-data/blob/main/src/static_wasm.rs -pub fn get_wasm_data() -> WasmData { +pub fn get_wasm_data() -> Result> { let size = wasm_data_passive_data_size(); let mut wasm_data_vec = vec![243; size]; let wasm_data_vec_location = wasm_data_vec.as_mut_ptr() as i32; init_wasm_data_passive_data(wasm_data_vec_location); - serde_json::from_str(std::str::from_utf8(&wasm_data_vec).unwrap()).unwrap() + let wasm_data_str = std::str::from_utf8(&wasm_data_vec) + .map_err(|e| AzleError::WasmDataVecToString(e.into()))?; + let wasm_data: WasmData = serde_json::from_str(wasm_data_str) + .map_err(|e| AzleError::WasmDataStringToStruct(e.into()))?; + + Ok(wasm_data) }