diff --git a/src/compiler/rust/canister/src/ic/candid_decode.rs b/src/compiler/rust/canister/src/ic/candid_decode.rs index 94d3392527..3082fa6163 100644 --- a/src/compiler/rust/canister/src/ic/candid_decode.rs +++ b/src/compiler/rust/canister/src/ic/candid_decode.rs @@ -1,6 +1,6 @@ use std::convert::TryInto; -use wasmedge_quickjs::{Context, JsArrayBuffer, JsFn, JsString, JsValue}; +use wasmedge_quickjs::{Context, JsFn, JsValue}; pub struct NativeFunction; impl JsFn for NativeFunction { diff --git a/src/compiler/rust/canister/src/ic/clear_timer.rs b/src/compiler/rust/canister/src/ic/clear_timer.rs index 46ef273e64..8841300272 100644 --- a/src/compiler/rust/canister/src/ic/clear_timer.rs +++ b/src/compiler/rust/canister/src/ic/clear_timer.rs @@ -1,21 +1,18 @@ -use std::convert::TryInto; +use wasmedge_quickjs::{Context, JsFn, JsValue}; -use quickjs_wasm_rs::{CallbackArg, JSContextRef, JSValueRef}; +pub struct NativeFunction; +impl JsFn for NativeFunction { + fn call(context: &mut Context, this_val: JsValue, argv: &[JsValue]) -> JsValue { + let timer_id_string = if let JsValue::String(js_string) = argv.get(0).unwrap() { + js_string.to_string() + } else { + panic!("conversion from JsValue to JsString failed") + }; + let timer_id_u64: u64 = timer_id_string.parse().unwrap(); + let timer_id = ic_cdk_timers::TimerId::from(slotmap::KeyData::from_ffi(timer_id_u64)); -pub fn native_function<'a>( - context: &'a JSContextRef, - _this: &CallbackArg, - args: &[CallbackArg], -) -> Result, anyhow::Error> { - let timer_id_vec_u8: Vec = args - .get(0) - .expect("clearTimer must have one argument") - .to_js_value()? - .try_into()?; + ic_cdk_timers::clear_timer(timer_id); - let timer_id_u64: u64 = candid::decode_one(&timer_id_vec_u8)?; - let timer_id = ic_cdk_timers::TimerId::from(slotmap::KeyData::from_ffi(timer_id_u64)); - - ic_cdk_timers::clear_timer(timer_id); - context.undefined_value() + JsValue::UnDefined + } } diff --git a/src/compiler/rust/canister/src/ic/mod.rs b/src/compiler/rust/canister/src/ic/mod.rs index 585e3cb187..e69ca27162 100644 --- a/src/compiler/rust/canister/src/ic/mod.rs +++ b/src/compiler/rust/canister/src/ic/mod.rs @@ -9,7 +9,7 @@ mod candid_encode; mod canister_balance; mod canister_balance128; mod canister_version; -// mod clear_timer; +mod clear_timer; mod data_certificate; mod id; mod instruction_counter; @@ -29,8 +29,8 @@ mod reject; // mod reject_message; mod reply_raw; mod set_certified_data; -// mod set_timer; -// mod set_timer_interval; +mod set_timer; +mod set_timer_interval; mod stable64_grow; mod stable64_read; mod stable64_size; @@ -133,13 +133,12 @@ pub fn register(context: &mut wasmedge_quickjs::Context) { .into(), ); - // ic.set_property( - // "clearTimer", - // context - // .wrap_callback2(clear_timer::native_function) - // .unwrap(), - // ) - // .unwrap(); + ic.set( + "clearTimer", + context + .new_function::("") + .into(), + ); ic.set( "dataCertificate", @@ -265,18 +264,17 @@ pub fn register(context: &mut wasmedge_quickjs::Context) { .into(), ); - // ic.set_property( - // "setTimer", - // context.wrap_callback2(set_timer::native_function).unwrap(), - // ) - // .unwrap(); - // ic.set_property( - // "setTimerInterval", - // context - // .wrap_callback2(set_timer_interval::native_function) - // .unwrap(), - // ) - // .unwrap(); + ic.set( + "setTimer", + context.new_function::("").into(), + ); + + ic.set( + "setTimerInterval", + context + .new_function::("") + .into(), + ); ic.set( "stable64Grow", diff --git a/src/compiler/rust/canister/src/ic/set_timer.rs b/src/compiler/rust/canister/src/ic/set_timer.rs index 19b7212046..aa724a2b9a 100644 --- a/src/compiler/rust/canister/src/ic/set_timer.rs +++ b/src/compiler/rust/canister/src/ic/set_timer.rs @@ -1,63 +1,53 @@ use std::convert::TryInto; -use quickjs_wasm_rs::{to_qjs_value, CallbackArg, JSContextRef, JSValue, JSValueRef}; use slotmap::Key; - -use crate::CONTEXT; - -pub fn native_function<'a>( - context: &'a JSContextRef, - _this: &CallbackArg, - args: &[CallbackArg], -) -> Result, anyhow::Error> { - let candid_encoded_array_buffer: Vec = args - .get(0) - .expect("performanceCounter must have one argument") - .to_js_value()? - .try_into()?; - - let delay_as_u64: u64 = candid::decode_one(&candid_encoded_array_buffer)?; - - let delay = core::time::Duration::new(delay_as_u64, 0); - - let callback_id: String = args - .get(1) - .expect("An argument for 'callback' was not provided") - .to_js_value()? - .try_into()?; - - let closure = move || { - CONTEXT.with(|context| { - let mut context = context.borrow_mut(); - let context = context.as_mut().unwrap(); - - let global = context.global_object().unwrap(); - - let timer_callback = global - .get_property("_azleTimerCallbacks") - .unwrap() - .get_property(callback_id.as_str()) - .unwrap_or_else(|e| ic_cdk::api::trap(e.to_string().as_str())); - - // TODO I am not sure what the first parameter to call is supposed to be - let callback_result = timer_callback.call(&timer_callback, &[]); - - if let Err(e) = callback_result { - ic_cdk::api::trap(e.to_string().as_str()) - } - }); - }; - - let timer_id: ic_cdk_timers::TimerId = ic_cdk_timers::set_timer(delay, closure); - let timer_id_as_u64: u64 = timer_id.data().as_ffi(); - let timer_id_candid_encoded_bytes: JSValue = candid::encode_one(timer_id_as_u64) - .unwrap_or_else(|e| { - // If something goes wrong we need to clear the timer before - // throwing to the JS above. - ic_cdk_timers::clear_timer(timer_id); - ic_cdk::api::trap(e.to_string().as_str()); - }) - .into(); - - to_qjs_value(&context, &timer_id_candid_encoded_bytes) +use wasmedge_quickjs::{AsObject, Context, JsFn, JsValue}; + +use crate::RUNTIME; + +pub struct NativeFunction; +impl JsFn for NativeFunction { + fn call(context: &mut Context, this_val: JsValue, argv: &[JsValue]) -> JsValue { + let delay_string = if let JsValue::String(js_string) = argv.get(0).unwrap() { + js_string.to_string() + } else { + panic!("conversion from JsValue to JsString failed") + }; + let delay_u64: u64 = delay_string.parse().unwrap(); + let delay = core::time::Duration::new(delay_u64, 0); + + let callback_id = if let JsValue::String(js_string) = argv.get(1).unwrap() { + js_string.to_string() + } else { + panic!("conversion from JsValue to JsString failed") + }; + + let closure = move || { + RUNTIME.with(|runtime| { + let mut runtime = runtime.borrow_mut(); + let runtime = runtime.as_mut().unwrap(); + + runtime.run_with_context(|context| { + let global = context.get_global(); + + let timer_callback = global + .get("_azleTimerCallbacks") + .to_obj() + .unwrap() + .get(callback_id.as_str()) + .to_function() + .unwrap(); + + timer_callback.call(&[]); + + // TODO handle errors + }); + }); + }; + + let timer_id: ic_cdk_timers::TimerId = ic_cdk_timers::set_timer(delay, closure); + let timer_id_u64: u64 = timer_id.data().as_ffi(); + + context.new_string(&timer_id_u64.to_string()).into() + } } diff --git a/src/compiler/rust/canister/src/ic/set_timer_interval.rs b/src/compiler/rust/canister/src/ic/set_timer_interval.rs index d448972b4b..6394080b6a 100644 --- a/src/compiler/rust/canister/src/ic/set_timer_interval.rs +++ b/src/compiler/rust/canister/src/ic/set_timer_interval.rs @@ -1,63 +1,53 @@ use std::convert::TryInto; -use quickjs_wasm_rs::{to_qjs_value, CallbackArg, JSContextRef, JSValue, JSValueRef}; use slotmap::Key; - -use crate::CONTEXT; - -pub fn native_function<'a>( - context: &'a JSContextRef, - _this: &CallbackArg, - args: &[CallbackArg], -) -> Result, anyhow::Error> { - let candid_encoded_array_buffer: Vec = args - .get(0) - .expect("performanceCounter must have one argument") - .to_js_value()? - .try_into()?; - - let interval_as_u64: u64 = candid::decode_one(&candid_encoded_array_buffer)?; - - let interval = core::time::Duration::new(interval_as_u64, 0); - - let callback_id: String = args - .get(1) - .expect("An argument for 'callback' was not provided") - .to_js_value()? - .try_into()?; - - let closure = move || { - CONTEXT.with(|context| { - let mut context = context.borrow_mut(); - let context = context.as_mut().unwrap(); - - let global = context.global_object().unwrap(); - - let timer_callback = global - .get_property("_azleTimerCallbacks") - .unwrap() - .get_property(callback_id.as_str()) - .unwrap_or_else(|e| ic_cdk::api::trap(e.to_string().as_str())); - - // TODO I am not sure what the first parameter to call is supposed to be - let callback_result = timer_callback.call(&timer_callback, &[]); - - if let Err(e) = callback_result { - ic_cdk::api::trap(e.to_string().as_str()) - } - }); - }; - - let timer_id: ic_cdk_timers::TimerId = ic_cdk_timers::set_timer_interval(interval, closure); - let timer_id_as_u64: u64 = timer_id.data().as_ffi(); - let timer_id_candid_encoded_bytes: JSValue = candid::encode_one(timer_id_as_u64) - .unwrap_or_else(|e| { - // If something goes wrong we need to clear the timer before - // throwing to the JS above. - ic_cdk_timers::clear_timer(timer_id); - ic_cdk::api::trap(e.to_string().as_str()); - }) - .into(); - - to_qjs_value(&context, &timer_id_candid_encoded_bytes) +use wasmedge_quickjs::{AsObject, Context, JsFn, JsValue}; + +use crate::RUNTIME; + +pub struct NativeFunction; +impl JsFn for NativeFunction { + fn call(context: &mut Context, this_val: JsValue, argv: &[JsValue]) -> JsValue { + let interval_string = if let JsValue::String(js_string) = argv.get(0).unwrap() { + js_string.to_string() + } else { + panic!("conversion from JsValue to JsString failed") + }; + let interval_u64: u64 = interval_string.parse().unwrap(); + let interval = core::time::Duration::new(interval_u64, 0); + + let callback_id = if let JsValue::String(js_string) = argv.get(1).unwrap() { + js_string.to_string() + } else { + panic!("conversion from JsValue to JsString failed") + }; + + let closure = move || { + RUNTIME.with(|runtime| { + let mut runtime = runtime.borrow_mut(); + let runtime = runtime.as_mut().unwrap(); + + runtime.run_with_context(|context| { + let global = context.get_global(); + + let timer_callback = global + .get("_azleTimerCallbacks") + .to_obj() + .unwrap() + .get(callback_id.as_str()) + .to_function() + .unwrap(); + + timer_callback.call(&[]); + + // TODO handle errors + }); + }); + }; + + let timer_id: ic_cdk_timers::TimerId = ic_cdk_timers::set_timer_interval(interval, closure); + let timer_id_u64: u64 = timer_id.data().as_ffi(); + + context.new_string(&timer_id_u64.to_string()).into() + } } diff --git a/src/lib/ic/clear_timer.ts b/src/lib/ic/clear_timer.ts index 1423ca8a4a..21f3cad766 100644 --- a/src/lib/ic/clear_timer.ts +++ b/src/lib/ic/clear_timer.ts @@ -11,7 +11,7 @@ export function clearTimer(timerId: TimerId): Void { return undefined as any; } - globalThis._azleIc.clearTimer(encode(TimerId, timerId).buffer); + globalThis._azleIc.clearTimer(timerId.toString()); const timerCallbackId = globalThis._azleIcTimers[timerId.toString()]; diff --git a/src/lib/ic/set_timer.ts b/src/lib/ic/set_timer.ts index 669f0cdcb0..df4d8e8f90 100644 --- a/src/lib/ic/set_timer.ts +++ b/src/lib/ic/set_timer.ts @@ -24,15 +24,12 @@ export function setTimer( const timerCallbackId = `_timer_${v4()}`; - const timerId = decode( - nat64, - globalThis._azleIc.setTimer( - encode(nat64, delay).buffer, - timerCallbackId - ) + const timerId = globalThis._azleIc.setTimer( + delay.toString(), + timerCallbackId ); - globalThis._azleIcTimers[timerId.toString()] = timerCallbackId; + globalThis._azleIcTimers[timerId] = timerCallbackId; globalThis._azleTimerCallbacks[timerCallbackId] = () => { try { @@ -43,5 +40,5 @@ export function setTimer( } }; - return timerId; + return BigInt(timerId); } diff --git a/src/lib/ic/set_timer_interval.ts b/src/lib/ic/set_timer_interval.ts index 809e1c5e10..57d3f95a15 100644 --- a/src/lib/ic/set_timer_interval.ts +++ b/src/lib/ic/set_timer_interval.ts @@ -24,19 +24,16 @@ export function setTimerInterval( const timerCallbackId = `_interval_timer_${v4()}`; - const timerId = decode( - nat64, - globalThis._azleIc.setTimerInterval( - encode(nat64, interval).buffer, - timerCallbackId - ) + const timerId = globalThis._azleIc.setTimerInterval( + interval.toString(), + timerCallbackId ); - globalThis._azleIcTimers[timerId.toString()] = timerCallbackId; + globalThis._azleIcTimers[timerId] = timerCallbackId; // We don't delete this even if the callback throws because // it still needs to be here for the next tick globalThis._azleTimerCallbacks[timerCallbackId] = callback; - return timerId; + return BigInt(timerId); } diff --git a/src/lib/ic/types/azle_ic.ts b/src/lib/ic/types/azle_ic.ts index a6a4691f81..8aec2d0776 100644 --- a/src/lib/ic/types/azle_ic.ts +++ b/src/lib/ic/types/azle_ic.ts @@ -25,7 +25,7 @@ export type AzleIc = { canisterBalance: () => bigint; canisterBalance128: () => string; canisterVersion: () => bigint; - clearTimer: (timerIdBytes: ArrayBufferLike) => void; + clearTimer: (timerIdString: string) => void; dataCertificate: () => ArrayBufferLike | undefined; id: () => string; instructionCounter: () => bigint; @@ -48,14 +48,11 @@ export type AzleIc = { rejectCode: () => number; replyRaw: (bytes: ArrayBufferLike) => void; setCertifiedData: (dataBytes: ArrayBufferLike) => void; - setTimer: ( - delayBytes: ArrayBufferLike, - timerCallbackId: string - ) => ArrayBufferLike; + setTimer: (delayString: string, timerCallbackId: string) => string; setTimerInterval: ( - intervalBytes: ArrayBufferLike, + intervalString: string, timerCallbackId: string - ) => ArrayBufferLike; + ) => string; stableBytes: () => ArrayBufferLike; stableGrow: (newPages: string) => string; stableRead: (offset: string, length: string) => ArrayBufferLike;