Skip to content

Commit

Permalink
outgoing http request fixes
Browse files Browse the repository at this point in the history
  • Loading branch information
bdemann committed Sep 15, 2023
1 parent ad486ed commit d9d5e7c
Show file tree
Hide file tree
Showing 8 changed files with 130 additions and 94 deletions.
2 changes: 1 addition & 1 deletion .github/workflows/test.yml
Original file line number Diff line number Diff line change
Expand Up @@ -83,7 +83,6 @@
# These are the ones that don't work
# "examples/tuple_types",
# "examples/service",
# "examples/outgoing_http_requests",
# "examples/robust_imports",
# "examples/run_time_errors",
# "examples/rust_type_conversions",
Expand Down Expand Up @@ -180,6 +179,7 @@ jobs:
"examples/null_example",
"examples/optional_types",
"examples/pre_and_post_upgrade",
"examples/outgoing_http_requests",
"examples/primitive_types",
"examples/principal",
"examples/query",
Expand Down
2 changes: 1 addition & 1 deletion examples/optional_types/src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -58,7 +58,7 @@ export default class {
}

@query([], Opt(text))
getOptNull(): Opt<string> {
getOptNull(): Opt<text> {
return [];
}

Expand Down
31 changes: 14 additions & 17 deletions examples/outgoing_http_requests/src/index.did
Original file line number Diff line number Diff line change
@@ -1,17 +1,14 @@
type HttpHeader = record { value : text; name : text };
type HttpResponse = record {
status : nat;
body : vec nat8;
headers : vec HttpHeader;
};
type HttpTransformArgs = record { context : vec nat8; response : HttpResponse };
type ManualReply = record {
status : nat;
body : vec nat8;
headers : vec HttpHeader;
};
service : () -> {
xkcd : () -> (ManualReply);
xkcdRaw : () -> (ManualReply);
xkcdTransform : (HttpTransformArgs) -> (HttpResponse) query;
}
type rec_1 = record {value:text; name:text};
type rec_0 = record {status:nat; body:vec nat8; headers:vec rec_1};
type rec_3 = record {value:text; name:text};
type rec_2 = record {status:nat; body:vec nat8; headers:vec rec_3};
type rec_6 = record {value:text; name:text};
type rec_5 = record {status:nat; body:vec nat8; headers:vec rec_6};
type rec_4 = record {context:vec nat8; response:rec_5};
type rec_8 = record {value:text; name:text};
type rec_7 = record {status:nat; body:vec nat8; headers:vec rec_8};
service: () -> {
xkcd: () -> (rec_0);
xkcdRaw: () -> (rec_2) query;
xkcdTransform: (rec_4) -> (rec_7) query;
}
14 changes: 11 additions & 3 deletions examples/outgoing_http_requests/src/index.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,13 @@
import { ic, Principal, query, update, Service, Some, None } from 'azle';
import {
ic,
Principal,
query,
update,
Service,
Some,
None,
Manual
} from 'azle';
import {
HttpResponse,
HttpTransformArgs,
Expand Down Expand Up @@ -28,9 +37,8 @@ export default class extends Service {
});
}

// TODO: Figure out how to do manuals in new syntax
// TODO the replica logs give some concerning output: https://forum.dfinity.org/t/fix-me-in-http-outcalls-call-raw/19435
@query([HttpResponse], HttpResponse, { manual: true })
@update([], HttpResponse, { manual: true })
async xkcdRaw(): Promise<Manual<HttpResponse>> {
const httpResponse = await ic.callRaw(
Principal.fromText('aaaaa-aa'),
Expand Down
Original file line number Diff line number Diff line change
@@ -1,11 +1,11 @@
use crate::traits::to_ident::ToIdent;
use quote::quote;
use serde::{Deserialize, Serialize};
use std::{
env,
fs::{self, File},
io::Write,
};
use crate::traits::to_ident::ToIdent;

mod ic;
mod traits;
Expand All @@ -14,7 +14,7 @@ mod traits;
struct CompilerInfo {
file_names: Vec<String>,
ts_root: String,
canister_methods: CanisterMethods
canister_methods: CanisterMethods,
}

#[derive(Debug, Serialize, Deserialize)]
Expand All @@ -30,7 +30,8 @@ struct CanisterMethods {

#[derive(Debug, Serialize, Deserialize)]
struct CanisterMethod {
name: String
name: String,
composite: Option<bool>,
}

fn main() -> Result<(), String> {
Expand All @@ -46,68 +47,86 @@ fn main() -> Result<(), String> {

let compiler_info = get_compiler_info(&args[1])?;


let ic = ic::generate();

let pre_upgrade_method = compiler_info.canister_methods.pre_upgrade.map(|canister_method| {
let rust_function_name = canister_method.name.to_ident();
let js_function_name = &canister_method.name;

quote! {
#[ic_cdk_macros::pre_upgrade]
fn #rust_function_name() {
execute_js(#js_function_name, false);
}
}
});

let inspect_message_method = compiler_info.canister_methods.inspect_message.map(|canister_method| {
let rust_function_name = canister_method.name.to_ident();
let js_function_name = &canister_method.name;

quote! {
#[ic_cdk_macros::inspect_message]
fn #rust_function_name() {
execute_js(#js_function_name, true);
let pre_upgrade_method = compiler_info
.canister_methods
.pre_upgrade
.map(|canister_method| {
let rust_function_name = canister_method.name.to_ident();
let js_function_name = &canister_method.name;

quote! {
#[ic_cdk_macros::pre_upgrade]
fn #rust_function_name() {
execute_js(#js_function_name, false);
}
}
}
});

let heartbeat_method = compiler_info.canister_methods.heartbeat.map(|canister_method| {
let rust_function_name = canister_method.name.to_ident();
let js_function_name = &canister_method.name;
});

let inspect_message_method =
compiler_info
.canister_methods
.inspect_message
.map(|canister_method| {
let rust_function_name = canister_method.name.to_ident();
let js_function_name = &canister_method.name;

quote! {
#[ic_cdk_macros::inspect_message]
fn #rust_function_name() {
execute_js(#js_function_name, true);
}
}
});

quote! {
#[ic_cdk_macros::heartbeat]
fn #rust_function_name() {
execute_js(#js_function_name, false);
let heartbeat_method = compiler_info
.canister_methods
.heartbeat
.map(|canister_method| {
let rust_function_name = canister_method.name.to_ident();
let js_function_name = &canister_method.name;

quote! {
#[ic_cdk_macros::heartbeat]
fn #rust_function_name() {
execute_js(#js_function_name, false);
}
}
}
});

let query_methods = compiler_info.canister_methods.queries.iter().map(|canister_method| {
let rust_function_name = canister_method.name.to_ident();
let js_function_name = &canister_method.name;

quote! {
#[ic_cdk_macros::query(manual_reply = true)]
fn #rust_function_name() {
execute_js(#js_function_name, true);
});

let query_methods = compiler_info
.canister_methods
.queries
.iter()
.map(|canister_method| {
let rust_function_name = canister_method.name.to_ident();
let js_function_name = &canister_method.name;
let is_composite = canister_method.composite.unwrap_or(false);

quote! {
#[ic_cdk_macros::query(manual_reply = true, composite = #is_composite)]
fn #rust_function_name() {
execute_js(#js_function_name, true);
}
}
}
});

let update_methods = compiler_info.canister_methods.updates.iter().map(|canister_method| {
let rust_function_name = canister_method.name.to_ident();
let js_function_name = &canister_method.name;

quote! {
#[ic_cdk_macros::update(manual_reply = true)]
fn #rust_function_name() {
execute_js(#js_function_name, true);
});

let update_methods = compiler_info
.canister_methods
.updates
.iter()
.map(|canister_method| {
let rust_function_name = canister_method.name.to_ident();
let js_function_name = &canister_method.name;

quote! {
#[ic_cdk_macros::update(manual_reply = true)]
fn #rust_function_name() {
execute_js(#js_function_name, true);
}
}
}
});
});

let lib_file = quote! {
#![allow(non_snake_case)]
Expand Down Expand Up @@ -165,7 +184,7 @@ fn main() -> Result<(), String> {
static CONTEXT: RefCell<Option<JSContextRef>> = RefCell::new(None);

static MEMORY_MANAGER_REF_CELL: RefCell<MemoryManager<DefaultMemoryImpl>> = RefCell::new(MemoryManager::init(DefaultMemoryImpl::default()));

static STABLE_B_TREE_MAPS: RefCell<BTreeMap<u8, AzleStableBTreeMap>> = RefCell::new(BTreeMap::new());
}

Expand Down
1 change: 1 addition & 0 deletions src/compiler/utils/types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -58,6 +58,7 @@ export type CanisterMethods = {
// TODO things like guard might also go in here
export type CanisterMethod = {
name: string;
composite?: boolean;
};

export type Plugin = {
Expand Down
4 changes: 2 additions & 2 deletions src/lib_new/ic.ts
Original file line number Diff line number Diff line change
Expand Up @@ -737,8 +737,8 @@ export const ic: Ic = globalThis._azleIc
.buffer;
return globalThis._azleIc.replyRaw(bytes);
},
replyRaw: (counterType: blob) => {
return globalThis._azleIc.replyRaw(counterType.buffer);
replyRaw: (replyBuffer: blob) => {
return globalThis._azleIc.replyRaw(replyBuffer.buffer);
},
setCertifiedData: (data) => {
const dataBytes = new Uint8Array(
Expand Down
33 changes: 22 additions & 11 deletions src/lib_new/method_decorators.ts
Original file line number Diff line number Diff line change
Expand Up @@ -231,9 +231,12 @@ function setupCanisterMethod(
);
}

const originalMethod = descriptor.value;

if (mode === 'query') {
target.constructor._azleCanisterMethods.queries.push({
name: key
name: key,
composite: isAsync(originalMethod, key)
});
}

Expand Down Expand Up @@ -261,8 +264,6 @@ function setupCanisterMethod(
};
}

const originalMethod = descriptor.value;

// This must remain a function and not an arrow function
// in order to set the context (this) correctly
descriptor.value = function (...args: any[]) {
Expand Down Expand Up @@ -295,21 +296,19 @@ function setupCanisterMethod(
) {
result
.then((result) => {
const encodeReadyResult =
result === undefined ? [] : [result];

const encoded = IDL.encode(
returnCandid[0],
encodeReadyResult
);

// TODO this won't be accurate because we have most likely had
// TODO cross-canister calls
console.log(
`final instructions: ${ic.instructionCounter()}`
);

if (!manual) {
const encodeReadyResult =
result === undefined ? [] : [result];
const encoded = IDL.encode(
returnCandid[0],
encodeReadyResult
);
ic.replyRaw(new Uint8Array(encoded));
}
})
Expand Down Expand Up @@ -338,3 +337,15 @@ function setupCanisterMethod(

return descriptor;
}

function isAsync(originalFunction: any, key: string) {
if (originalFunction[Symbol.toStringTag] === 'AsyncFunction') {
return true;
} else if (originalFunction.constructor.name === 'AsyncFunction') {
return true;
} else if (originalFunction.toString().includes('async ')) {
return true;
} else {
return false;
}
}

0 comments on commit d9d5e7c

Please sign in to comment.