Skip to content

Commit

Permalink
Fix DID and function signatures for dfx e2e (#3)
Browse files Browse the repository at this point in the history
  • Loading branch information
hansl authored May 26, 2021
1 parent d0581f7 commit 6965d15
Show file tree
Hide file tree
Showing 2 changed files with 52 additions and 31 deletions.
17 changes: 12 additions & 5 deletions assets.did
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
type BatchId = nat;
type ChunkId = nat;
type Key = text;
type Time = int;

type CreateAssetArguments = record {
key: Key;
Expand Down Expand Up @@ -57,15 +58,20 @@ type HttpResponse = record {

type StreamingCallbackHttpResponse = record {
body: blob;
token: opt Token;
token: opt StreamingCallbackToken;
};

type Token = record {};
type StreamingCallbackToken = record {
key: Key;
content_encoding: text;
index: nat;
sha256: opt blob;
};

type StreamingStrategy = variant {
Callback: record {
callback: func (Token) -> (StreamingCallbackHttpResponse) query;
token: Token;
callback: func (StreamingCallbackToken) -> (opt StreamingCallbackHttpResponse) query;
token: StreamingCallbackToken;
};
};

Expand Down Expand Up @@ -98,6 +104,7 @@ service: {
content_encoding: text;
sha256: opt blob; // sha256 of entire asset encoding, calculated by dfx and passed in SetAssetContentArguments
length: nat; // Size of this encoding's blob. Calculated when uploading assets.
modified: Time;
};
}) query;

Expand Down Expand Up @@ -127,7 +134,7 @@ service: {
}) -> ();

http_request: (request: HttpRequest) -> (HttpResponse) query;
http_request_stream_callback: (token: opt Token) -> (StreamingCallbackHttpResponse) query;
http_request_streaming_callback: (token: StreamingCallbackToken) -> (opt StreamingCallbackHttpResponse) query;

authorize: (principal) -> ();
}
66 changes: 40 additions & 26 deletions src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ mod rc_bytes;

use crate::rc_bytes::RcBytes;
use ic_cdk::api::{caller, data_certificate, set_certified_data, time, trap};
use ic_cdk::export::candid::{CandidType, Deserialize, Func, Nat, Principal};
use ic_cdk::export::candid::{CandidType, Deserialize, Func, Int, Nat, Principal};
use ic_cdk_macros::{init, post_upgrade, pre_upgrade, query, update};
use ic_certified_map::{AsHashTree, Hash, HashTree, RbTree};
use num_traits::ToPrimitive;
Expand Down Expand Up @@ -81,10 +81,10 @@ struct AssetDetails {

#[derive(Clone, Debug, CandidType, Deserialize)]
struct AssetEncodingDetails {
modified: Timestamp,
content_encoding: String,
sha256: Option<ByteBuf>,
length: Nat,
modified: Timestamp,
}

struct Chunk {
Expand All @@ -96,7 +96,7 @@ struct Batch {
expires_at: Timestamp,
}

type Timestamp = u64;
type Timestamp = Int;
type BatchId = Nat;
type ChunkId = Nat;
type Key = String;
Expand Down Expand Up @@ -210,7 +210,7 @@ struct HttpResponse {
}

#[derive(Clone, Debug, CandidType, Deserialize)]
struct Token {
struct StreamingCallbackToken {
key: String,
content_encoding: String,
index: Nat,
Expand All @@ -220,13 +220,16 @@ struct Token {

#[derive(Clone, Debug, CandidType, Deserialize)]
enum StreamingStrategy {
Callback { callback: Func, token: Token },
Callback {
callback: Func,
token: StreamingCallbackToken,
},
}

#[derive(Clone, Debug, CandidType, Deserialize)]
struct StreamingCallbackHttpResponse {
body: RcBytes,
token: Option<Token>,
token: Option<StreamingCallbackToken>,
}

#[update]
Expand Down Expand Up @@ -273,7 +276,7 @@ fn store(arg: StoreArg) {
let encoding = asset.encodings.entry(arg.content_encoding).or_default();
encoding.total_length = arg.content.len();
encoding.content_chunks = vec![RcBytes::from(arg.content)];
encoding.modified = time() as u64;
encoding.modified = Int::from(time() as u64);
encoding.sha256 = hash;

on_asset_change(&arg.key, asset);
Expand All @@ -292,7 +295,7 @@ fn create_batch() -> CreateBatchResponse {
batches.insert(
batch_id.clone(),
Batch {
expires_at: now + BATCH_EXPIRY_NANOS,
expires_at: Int::from(now + BATCH_EXPIRY_NANOS),
},
);
s.chunks.borrow_mut().retain(|_, c| {
Expand All @@ -315,7 +318,7 @@ fn create_chunk(arg: CreateChunkArg) -> CreateChunkResponse {
let mut batch = batches
.get_mut(&arg.batch_id)
.unwrap_or_else(|| trap("batch not found"));
batch.expires_at = now + BATCH_EXPIRY_NANOS;
batch.expires_at = Int::from(now + BATCH_EXPIRY_NANOS);

let chunk_id = s.next_chunk_id.borrow().clone();
*s.next_chunk_id.borrow_mut() += 1;
Expand Down Expand Up @@ -437,10 +440,10 @@ fn list() -> Vec<AssetDetails> {
.encodings
.iter()
.map(|(enc_name, enc)| AssetEncodingDetails {
modified: enc.modified,
content_encoding: enc_name.clone(),
sha256: Some(ByteBuf::from(enc.sha256)),
length: Nat::from(enc.total_length),
modified: enc.modified.clone(),
})
.collect();
encodings.sort_by(|l, r| l.content_encoding.cmp(&r.content_encoding));
Expand All @@ -461,11 +464,11 @@ fn create_token(
enc: &AssetEncoding,
key: &str,
chunk_index: usize,
) -> Option<Token> {
) -> Option<StreamingCallbackToken> {
if chunk_index + 1 >= enc.content_chunks.len() {
None
} else {
Some(Token {
Some(StreamingCallbackToken {
key: key.to_string(),
content_encoding: enc_name.to_string(),
index: Nat::from(chunk_index + 1),
Expand Down Expand Up @@ -543,16 +546,18 @@ fn build_http_response(path: &str, encodings: Vec<String>, index: usize) -> Http

if let Some(certificate_header) = index_redirect_certificate {
if let Some(asset) = assets.get(INDEX_FILE) {
for (enc_name, enc) in asset.encodings.iter() {
if enc.certified {
return build_200(
asset,
enc_name,
enc,
INDEX_FILE,
index,
Some(certificate_header),
);
for enc_name in encodings.iter() {
if let Some(enc) = asset.encodings.get(enc_name) {
if enc.certified {
return build_200(
asset,
enc_name,
enc,
INDEX_FILE,
index,
Some(certificate_header),
);
}
}
}
}
Expand Down Expand Up @@ -675,12 +680,12 @@ fn http_request(req: HttpRequest) -> HttpResponse {

#[query]
fn http_request_streaming_callback(
Token {
StreamingCallbackToken {
key,
content_encoding,
index,
..
}: Token,
sha256,
}: StreamingCallbackToken,
) -> StreamingCallbackHttpResponse {
STATE.with(|s| {
let assets = s.assets.borrow();
Expand All @@ -691,6 +696,13 @@ fn http_request_streaming_callback(
.encodings
.get(&content_encoding)
.expect("Invalid token on streaming: encoding not found.");

if let Some(expected_hash) = sha256 {
if expected_hash != enc.sha256 {
trap("sha256 mismatch");
}
}

// MAX is good enough. This means a chunk would be above 64-bits, which is impossible...
let chunk_index = index.0.to_usize().unwrap_or(usize::MAX);

Expand Down Expand Up @@ -730,7 +742,7 @@ fn do_set_asset_content(arg: SetAssetContentArguments) {
let asset = assets
.get_mut(&arg.key)
.unwrap_or_else(|| trap("asset not found"));
let now = time() as u64;
let now = Int::from(time() as u64);

let mut chunks = s.chunks.borrow_mut();

Expand Down Expand Up @@ -812,6 +824,8 @@ fn on_asset_change(key: &str, asset: &mut Asset) {
if let Some(enc) = asset.encodings.get(*enc_name) {
if enc.certified {
return;
} else {
break;
}
}
}
Expand Down

0 comments on commit 6965d15

Please sign in to comment.