Skip to content

Commit

Permalink
finish cleaning up main Rust functionality outside of the ic object
Browse files Browse the repository at this point in the history
  • Loading branch information
lastmjs committed Oct 28, 2024
1 parent edf1af2 commit 8128e89
Show file tree
Hide file tree
Showing 9 changed files with 69 additions and 62 deletions.
Binary file modified canister_templates/stable.wasm
Binary file not shown.
Original file line number Diff line number Diff line change
Expand Up @@ -19,10 +19,15 @@ pub fn record_benchmark(function_name: &str, instructions: u64) -> Result<(), Bo
quickjs_with_ctx(|ctx| {
let timestamp = ic_cdk::api::time();

let method_names: rquickjs::Object =
ctx.clone().globals().get("_azleCanisterMethodNames")?;

let method_name: String = method_names.get(function_name)?;
let method_names: rquickjs::Object = ctx
.clone()
.globals()
.get("_azleCanisterMethodNames")
.map_err(|e| format!("Failed to get globalThis._azleCanisterMethodNames: {e}"))?;

let method_name: String = method_names.get(function_name).map_err(|e| {
format!("Failed to get globalThis._azleCanisterMethodNames[{function_name}]: {e}")
})?;

BENCHMARKS_REF_CELL.with(|benchmarks_ref_cell| {
let mut benchmarks = benchmarks_ref_cell.borrow_mut();
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@ pub fn get_candid_and_method_meta_pointer() -> CCharPtr {
match initialize_and_get_candid() {
Ok(c_char_ptr) => c_char_ptr,
Err(error) => {
ic_cdk::trap(&format!("Azle CandidAndMethodMetaError: {}", error));
ic_cdk::trap(&format!("Azle CandidAndMethodMetaError: {error}"));
}
}
}
Expand Down Expand Up @@ -51,12 +51,7 @@ fn initialize_and_get_candid() -> Result<CCharPtr, Box<dyn Error>> {
.clone()
.globals()
.get("_azleGetCandidAndMethodMeta")
.map_err(|e| {
format!(
"Failed to get globalThis._azleGetCandidAndMethodMeta: {}",
e
)
})?;
.map_err(|e| format!("Failed to get globalThis._azleGetCandidAndMethodMeta: {e}"))?;

let candid_and_method_meta_js_value =
quickjs_call_with_error_handling(ctx.clone(), get_candid_and_method_meta, ())?;
Expand Down
Original file line number Diff line number Diff line change
@@ -1,9 +1,9 @@
use std::error::Error;

use rquickjs::function::IntoArgs;

use crate::quickjs_with_ctx::run_event_loop;

use std::error::Error;

pub fn quickjs_call_with_error_handling<'a>(
ctx: rquickjs::Ctx<'a>,
function: rquickjs::Function<'a>,
Expand All @@ -14,6 +14,7 @@ pub fn quickjs_call_with_error_handling<'a>(
Err(_) => trap_on_last_exception(ctx.clone())?,
};

// TODO we run the event loop here and also in handle_promise_error, is that a problem?
run_event_loop(ctx.clone());

if result.is_promise() {
Expand Down Expand Up @@ -46,7 +47,7 @@ pub fn handle_promise_error(

match promise.state() {
rquickjs::promise::PromiseState::Rejected => {
promise.result::<rquickjs::Value>(); // TODO is this strictly necessary?
promise.result::<rquickjs::Value>();
trap_on_last_exception(ctx.clone())?;
}
_ => {}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,20 +5,31 @@ use crate::{

#[no_mangle]
#[allow(unused)]
pub extern "C" fn execute_method_js(function_index: i32, pass_arg_data: i32) {
pub extern "C" fn execute_method_js(function_index: i32, pass_arg_data_raw: i32) {
let function_name = function_index.to_string();
let pass_arg_data = pass_arg_data == 1;
let pass_arg_data = pass_arg_data_raw == 1;

let quickjs_result = quickjs_with_ctx(|ctx| {
let result = execute_method_js_with_result(function_name, pass_arg_data);

if let Err(e) = result {
ic_cdk::trap(&format!("Azle CanisterMethodError: {}", e));
}
}

fn execute_method_js_with_result(
function_name: String,
pass_arg_data: bool,
) -> Result<(), Box<dyn std::error::Error>> {
quickjs_with_ctx(|ctx| {
let callbacks: rquickjs::Object = ctx
.clone()
.globals()
.get("_azleCallbacks")
.map_err(|e| format!("Failed to get _azleCallbacks global: {}", e))?;
.map_err(|e| format!("Failed to get globalThis._azleCallbacks: {e}"))?;

let method_callback: rquickjs::Function = callbacks
.get(&function_name)
.map_err(|e| format!("Failed to get method callback from _azleCallbacks: {}", e))?;
let method_callback: rquickjs::Function = callbacks.get(&function_name).map_err(|e| {
format!("Failed to get globalThis._azleCallbacks[{function_name}]: {e}")
})?;

let candid_args = if pass_arg_data {
ic_cdk::api::call::arg_data_raw()
Expand All @@ -29,20 +40,18 @@ pub extern "C" fn execute_method_js(function_index: i32, pass_arg_data: i32) {
quickjs_call_with_error_handling(ctx.clone(), method_callback, (candid_args,))?;

Ok(())
});
})?;

if let Err(e) = quickjs_result {
ic_cdk::trap(&format!("Azle CanisterMethodError: {}", e));
}
let record_benchmarks = WASM_DATA_REF_CELL
.with(|wasm_data_ref_cell| wasm_data_ref_cell.borrow().clone())
.as_ref()
.ok_or("could not convert wasm_data_ref_cell to ref")?
.record_benchmarks;

if WASM_DATA_REF_CELL.with(|wasm_data_ref_cell| {
wasm_data_ref_cell
.borrow()
.as_ref()
.unwrap()
.record_benchmarks
}) {
if record_benchmarks {
let instructions = ic_cdk::api::performance_counter(1);
record_benchmark(&function_name, instructions);
record_benchmark(&function_name, instructions)?;
}

Ok(())
}
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
use ic_stable_structures::memory_manager::MemoryId;

use crate::{
error::handle_promise_error,
execute_method_js::execute_method_js,
ic, quickjs_with_ctx,
wasm_binary_manipulation::{get_js_code, get_wasm_data},
Expand Down Expand Up @@ -62,7 +63,6 @@ fn initialize(
Ok(())
}

// TODO do we need all these clonse?
pub fn initialize_js(
js: &str,
init: bool,
Expand All @@ -77,12 +77,6 @@ pub fn initialize_js(
});

quickjs_with_ctx(|ctx| -> Result<(), Box<dyn std::error::Error>> {
ctx.clone()
.globals()
.set("_azleNodeWasmEnvironment", false)?;

ic::register(ctx.clone())?;

let env = rquickjs::Object::new(ctx.clone())?;

for (key, value) in std::env::vars() {
Expand All @@ -95,36 +89,40 @@ pub fn initialize_js(

ctx.clone().globals().set("process", process)?;

ctx.clone()
.globals()
.set("_azleNodeWasmEnvironment", false)?;

ctx.clone()
.globals()
.set("exports", rquickjs::Object::new(ctx.clone())?)?;

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)?;
if init {
ctx.clone().globals().set("_azleInitCalled", true)?;
ctx.clone().globals().set("_azlePostUpgradeCalled", false)?;
} else {
ctx.clone().globals().set("_azleInitCalled", false)?;
ctx.clone().globals().set("_azlePostUpgradeCalled", true)?;
}

Ok(())
})?;
ic::register(ctx.clone())?;

// TODO is it possible to just put this all in the same quickjs_with_ctx?
if function_index != -1 {
execute_method_js(function_index, pass_arg_data);
}
let promise = rquickjs::Module::evaluate(ctx.clone(), MODULE_NAME, js)?;

// _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| -> Result<(), Box<dyn std::error::Error>> {
let assignment = if init {
"globalThis._azleInitCalled = true;"
} else {
"globalThis._azlePostUpgradeCalled = true;"
};
handle_promise_error(ctx.clone(), promise)?;

ctx.eval::<(), _>(assignment)?;
Ok(())
})?;

execute_developer_init_or_post_upgrade(function_index, pass_arg_data);

Ok(())
}

fn execute_developer_init_or_post_upgrade(function_index: i32, pass_arg_data: i32) {
if function_index != -1 {
execute_method_js(function_index, pass_arg_data);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -4,8 +4,6 @@ use rquickjs::Ctx;

use crate::CONTEXT_REF_CELL;

// TODO should we get rid of the result when calling the callback?
// TODO I am not sure we need to do that
pub fn quickjs_with_ctx<F, R>(callback: F) -> Result<R, Box<dyn Error>>
where
F: FnOnce(Ctx) -> Result<R, Box<dyn Error>>,
Expand All @@ -18,7 +16,7 @@ where

context.with(|ctx| {
let result = callback(ctx.clone())
.map_err(|e| format!("QuickJS callback execution failed: {}", e))?;
.map_err(|e| format!("QuickJS callback execution failed: {e}"))?;

run_event_loop(ctx);

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -64,6 +64,7 @@ pub fn get_wasm_data() -> Result<WasmData, Box<dyn Error>> {
e
)
})?;

let wasm_data: WasmData = serde_json::from_str(wasm_data_str).map_err(|e| {
format!(
"WasmData conversion failed while converting String to WasmData struct: {}",
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -103,7 +103,7 @@ export function getTests(
const canister1Id = getCanisterId('canister1');
const canister2Id = getCanisterId('canister2');
const partialErrorMessage = new RegExp(
`Error from Canister ${canister1Id}: Canister called \`ic0.trap\` with message: Error: Rejection code 5, IC0503: Error from Canister ${canister2Id}: Canister called \`ic0.trap\` with message: hahahaha`
`Error from Canister ${canister1Id}: Canister called \`ic0.trap\` with message: Uncaught Error: Rejection code 5, IC0503: Error from Canister ${canister2Id}: Canister called \`ic0.trap\` with message: hahahaha`
);

await expect(canister1.trap()).rejects.toThrow(partialErrorMessage);
Expand Down

0 comments on commit 8128e89

Please sign in to comment.