metabox_sdk/databox/mod.rs
1use ic_agent::{Agent, identity::Secp256k1Identity};
2use ic_agent::agent::http_transport::ReqwestHttpReplicaV2Transport;
3use garcon::Delay;
4use std::fs;
5use std::path::Path;
6use std::ffi::OsStr;
7use sha256::digest_bytes;
8use rayon::prelude::*;
9use candid::{Encode, Decode, Nat, Principal};
10mod databox_did;
11pub use databox_did::{ClearAllResult, DeleteKeyResult, UploadResult, Avatar, PUT, Chunk, FilePut, PutResult, DataErr, FileExt, GetAssetExtKeyResult, GET, GetPlainResult, CanisterStateResult, CycleBalanceResult, AvlSMResult, GetAssetExtsResult};
12
13const UPDATE_SIZE: usize = 1992288;
14
15#[derive(Debug)]
16pub enum UploadStatus {
17 Ok,
18 Err(DataErr),
19}
20
21#[derive(Debug)]
22pub struct PutPlainFileResult {
23 pub file_name: String,
24 pub file_extension: String,
25 pub file_key: String,
26 pub upload_status: UploadStatus,
27 pub databox_canister_id: Principal,
28 pub total_size: u64,
29 pub chunk_number: u64,
30}
31
32/// Put plain files
33///
34/// Example code :
35/// ``` no_run
36/// use metabox_sdk::databox::{self, PutPlainFileResult};
37///
38/// async fn put_plain_files(folder_path: &str, data_box_canister_id_text: &str,) -> Vec<PutPlainFileResult> {
39/// databox::put_plain_files("identities/identity.pem", folder_path, data_box_canister_id_text).await
40/// }
41///
42/// #[tokio::main]
43/// async fn main() {
44/// let response_1 = put_plain_files("source/", "4radi-oqaaa-aaaan-qapwa-cai").await;
45/// let mut index = 0;
46/// for i in &response_1 {
47/// index += 1;
48/// println!("file index: {:?}", index);
49/// println!("file name: {:?}", i.file_name);
50/// println!("file extension: {:?}", i.file_extension);
51/// println!("file key: {:?}", i.file_key);
52/// println!("file upload_status: {:?}", i.upload_status);
53/// println!("file in data box: {:?}", i.databox_canister_id.to_text());
54/// println!("file total_size: {:?}", i.total_size);
55/// println!("file chunk number: {:?}", i.chunk_number);
56/// println!("\n");
57/// }
58/// }
59/// ```
60pub async fn put_plain_files(pem_identity_path: &str, folder_path: &str, data_box_canister_id_text: &str,) -> Vec<PutPlainFileResult> {
61 let canister_id = Principal::from_text(data_box_canister_id_text).unwrap();
62 let mut ans: Vec<PutPlainFileResult> = Vec::new();
63 let paths = fs::read_dir(&folder_path).unwrap();
64 for path in paths {
65 let file_path = path.unwrap().file_name().into_string().unwrap();
66 let pos: Vec<&str> = file_path.split(".").collect();
67 let file_name = String::from(pos[0]);
68 let file_extension = String::from(get_file_type(&String::from(pos[1])));
69 let s = folder_path.to_owned() + &file_path;
70
71 let (file_size, slice_size, data_slice) = get_file_from_source(&s);
72
73 let puts = build_put_plain_args(
74 file_name.clone(),
75 file_extension.clone(),
76 file_size.try_into().unwrap(),
77 slice_size.try_into().unwrap(),
78 &data_slice,
79 );
80 let file_key = match &puts[0] {
81 FilePut::PlainFilePut(put) => {
82 match put {
83 PUT::segment {file_extension, order, chunk_number, chunk, aes_pub_key, file_name, file_key, total_size} => {
84 file_key.clone()
85 }
86 _ => {"".to_string()}
87 }
88 }
89 _ => {"".to_string()}
90 };
91
92 let mut flag = false;
93 for put in &puts {
94 let _response_blob = build_agent(pem_identity_path)
95 .update(&canister_id, "put")
96 .with_arg(Encode!(&put).expect("encode piece failed"))
97 .call_and_wait(get_waiter())
98 .await
99 .expect("response error");
100 let _response = Decode!(&_response_blob, PutResult).unwrap();
101 match _response {
102 PutResult::ok(..) => {
103 },
104 PutResult::err(data_err) => {
105 ans.push(PutPlainFileResult {
106 file_name: file_name.clone(),
107 file_extension: file_extension.clone(),
108 file_key: file_key.clone(),
109 upload_status: UploadStatus::Err(data_err),
110 databox_canister_id: canister_id,
111 total_size: file_size.try_into().unwrap(),
112 chunk_number: slice_size.try_into().unwrap(),
113 });
114 flag = true;
115 break;
116 }
117 }
118 }
119 if !flag { ans.push(PutPlainFileResult {
120 file_name: file_name.clone(),
121 file_extension: file_extension.clone(),
122 file_key: file_key.clone(),
123 upload_status: UploadStatus::Ok,
124 databox_canister_id: canister_id,
125 total_size: file_size.try_into().unwrap(),
126 chunk_number: slice_size.try_into().unwrap(),
127 }); }
128 }
129 ans
130}
131
132/// Put a plain file
133///
134/// Example code :
135/// ``` no_run
136/// use metabox_sdk::databox::{self, PutPlainFileResult};
137///
138/// async fn put_plain_file(file_path_str: &str, data_box_canister_id_text: &str,) -> PutPlainFileResult {
139/// databox::put_plain_file("identities/identity.pem", file_path_str, data_box_canister_id_text).await
140/// }
141///
142/// #[tokio::main]
143/// async fn main() {
144/// let response_2 = put_plain_file("source/bitcoin.pdf", "4radi-oqaaa-aaaan-qapwa-cai").await;
145/// println!("file name: {:?}", response_2.file_name);
146/// println!("file extension: {:?}", response_2.file_extension);
147/// println!("file key: {:?}", response_2.file_key);
148/// println!("file upload_status: {:?}", response_2.upload_status);
149/// println!("file in data box: {:?}", response_2.databox_canister_id.to_text());
150/// println!("file total_size: {:?}", response_2.total_size);
151/// println!("file chunk number: {:?}", response_2.chunk_number);
152/// }
153/// ```
154pub async fn put_plain_file(pem_identity_path: &str, file_path_str: &str, data_box_canister_id_text: &str,) -> PutPlainFileResult {
155 let canister_id = Principal::from_text(data_box_canister_id_text).unwrap();
156 let file_path = Path::new(file_path_str);
157 let file_name = file_path.file_stem().unwrap().to_str().unwrap().to_owned();
158 let file_extension = String::from(get_file_type(file_path.extension().unwrap().to_str().unwrap()));
159
160 let (file_size, slice_size, data_slice) = get_file_from_source(file_path_str);
161 let puts = build_put_plain_args(
162 file_name.clone(),
163 file_extension.clone(),
164 file_size.try_into().unwrap(),
165 slice_size.try_into().unwrap(),
166 &data_slice,
167 );
168 let file_key = match &puts[0] {
169 FilePut::PlainFilePut(put) => {
170 match put {
171 PUT::segment {file_extension, order, chunk_number, chunk, aes_pub_key, file_name, file_key, total_size} => {
172 file_key.clone()
173 }
174 _ => {"".to_string()}
175 }
176 }
177 _ => {"".to_string()}
178 };
179
180 for put in &puts {
181 let _response_blob = build_agent(pem_identity_path)
182 .update(&canister_id, "put")
183 .with_arg(Encode!(&put).expect("encode piece failed"))
184 .call_and_wait(get_waiter())
185 .await
186 .expect("response error");
187 let _response = Decode!(&_response_blob, PutResult).unwrap();
188 match _response {
189 PutResult::ok(..) => {
190 },
191 PutResult::err(data_err) => {
192 return PutPlainFileResult {
193 file_name: file_name.clone(),
194 file_extension: file_extension.clone(),
195 file_key: file_key.clone(),
196 upload_status: UploadStatus::Err(data_err),
197 databox_canister_id: canister_id,
198 total_size: file_size.try_into().unwrap(),
199 chunk_number: slice_size.try_into().unwrap(),
200 };
201 }
202 }
203 }
204 PutPlainFileResult {
205 file_name: file_name.clone(),
206 file_extension: file_extension.clone(),
207 file_key: file_key.clone(),
208 upload_status: UploadStatus::Ok,
209 databox_canister_id: canister_id,
210 total_size: file_size.try_into().unwrap(),
211 chunk_number: slice_size.try_into().unwrap(),
212 }
213}
214
215/// Upload avatar
216///
217/// Example code :
218/// ``` no_run
219/// use metabox_sdk::databox::{self, UploadResult};
220///
221/// async fn upload_avatar(data_box_canister_id_text: &str, avatar_file_path: &str) -> UploadResult {
222/// databox::upload_avatar("identities/identity.pem", data_box_canister_id_text, avatar_file_path).await
223/// }
224///
225/// #[tokio::main]
226/// async fn main() {
227/// println!("upload avatar result:{:?}", upload_avatar("4radi-oqaaa-aaaan-qapwa-cai", "source/avatar.jpg").await);
228/// }
229/// ```
230pub async fn upload_avatar(pem_identity_path: &str, data_box_canister_id_text: &str, avatar_file_path: &str) -> UploadResult {
231 let canister_id = Principal::from_text(data_box_canister_id_text).unwrap();
232 let context = fs::read(avatar_file_path).expect("read file failed");
233 let file_extension = String::from(get_file_type(Path::new(avatar_file_path).extension().unwrap().to_str().unwrap()));
234 let upload_args = Avatar {
235 data: context,
236 data_type: file_extension,
237 };
238 let response_blob = build_agent(pem_identity_path)
239 .update(&canister_id, "upload")
240 .with_arg(Encode!(&upload_args).expect("encode piece failed"))
241 .call_and_wait(get_waiter())
242 .await
243 .expect("response error");
244 let response = Decode!(&response_blob, UploadResult).unwrap();
245 response
246}
247
248/// Delete a file
249///
250/// Example code :
251/// ``` no_run
252/// use metabox_sdk::databox::{self, DeleteKeyResult};
253///
254/// async fn delete_file(data_box_canister_id_text: &str, file_key: String) -> DeleteKeyResult {
255/// databox::delete_file("identities/identity.pem", data_box_canister_id_text, file_key).await
256/// }
257///
258/// #[tokio::main]
259/// async fn main() {
260/// println!("delete file result:{:?}", delete_file("4radi-oqaaa-aaaan-qapwa-cai", "4da18028cb05cdb1a8e271c02c48dceef6ad89811adab9f9a3ab9e96db020fb9".to_string()).await);
261/// }
262/// ```
263pub async fn delete_file(pem_identity_path: &str, data_box_canister_id_text: &str, file_key: String) -> DeleteKeyResult {
264 let canister_id = Principal::from_text(data_box_canister_id_text).unwrap();
265 let response_blob = build_agent(pem_identity_path)
266 .update(&canister_id, "deletekey")
267 .with_arg(Encode!(&file_key).expect("encode piece failed"))
268 .call_and_wait(get_waiter())
269 .await
270 .expect("response error");
271 let response = Decode!(&response_blob, DeleteKeyResult).unwrap();
272 response
273}
274
275/// Clear the DataBox
276///
277/// Example code :
278/// ``` no_run
279/// use metabox_sdk::databox::{self, ClearAllResult};
280///
281/// async fn clear_data_box(data_box_canister_id_text: &str,) -> ClearAllResult {
282/// databox::clear_data_box("identities/identity.pem", data_box_canister_id_text).await
283/// }
284///
285/// #[tokio::main]
286/// async fn main() {
287/// println!("clear data box result:{:?}", clear_data_box("4radi-oqaaa-aaaan-qapwa-cai").await);
288/// }
289/// ```
290pub async fn clear_data_box(pem_identity_path: &str, data_box_canister_id_text: &str,) -> ClearAllResult {
291 let canister_id = Principal::from_text(data_box_canister_id_text).unwrap();
292 let response_blob = build_agent(pem_identity_path)
293 .update(&canister_id, "clearall")
294 .with_arg(Encode!().expect("encode piece failed"))
295 .call_and_wait(get_waiter())
296 .await
297 .expect("response error");
298 let response = Decode!(&response_blob, ClearAllResult).unwrap();
299 response
300}
301
302/// Get the plain file Data
303///
304/// Example code :
305/// ``` no_run
306/// use std::io::Write;
307/// use std::fs::OpenOptions;
308/// use metabox_sdk::databox::{self, DataErr};
309///
310/// async fn get_plain_file(data_box_canister_id_text: &str, file_key: &str) -> Result<Vec<u8>, DataErr> {
311/// databox::get_plain_file("identities/identity.pem", data_box_canister_id_text, file_key).await
312/// }
313///
314/// #[tokio::main]
315/// async fn main() {
316/// let response_3 = get_plain_file("4radi-oqaaa-aaaan-qapwa-cai", "14d37b8971e5c73a523de39e0682ba0c08df3a503c49f4f976fe282bc60abfef").await.unwrap();
317/// let mut file = std::fs::File::create("output/a.pdf").expect("create failed");
318/// file.write_all(&response_3).expect("write failed");
319/// }
320/// ```
321pub async fn get_plain_file(pem_identity_path: &str, data_box_canister_id_text: &str, file_key: &str) -> Result<Vec<u8>, DataErr> {
322 let canister_id = Principal::from_text(data_box_canister_id_text).unwrap();
323 let agent = build_agent(pem_identity_path);
324 let file_ext = get_file_info(pem_identity_path, data_box_canister_id_text, file_key).await.unwrap();
325 match file_ext {
326 FileExt::PlainFileExt(asset_ext) => {
327 let waiter = get_waiter();
328 let mut i = 0;
329 let need_query_times = asset_ext.need_query_times;
330 let mut ans: Vec<u8> = Vec::new();
331 while Nat::from(i) < need_query_times {
332 let arg = GET {
333 flag: Nat::from(i),
334 file_key: file_key.to_string(),
335 };
336 let response_blob = agent
337 .update(&canister_id, "getPlain")
338 .with_arg(Encode!(&arg).expect("encode piece failed"))
339 .call_and_wait(waiter.clone())
340 .await
341 .expect("response error");
342 i += 1;
343 let response = Decode!(&response_blob, GetPlainResult).unwrap();
344 match response {
345 GetPlainResult::ok(mut payload) => {
346 ans.append(&mut payload)
347 },
348 GetPlainResult::err(data_err) => {
349 return Err(data_err);
350 },
351 }
352 }
353 Ok(ans)
354 },
355 _ => {
356 Err(DataErr::FileKeyErr)
357 }
358 }
359}
360
361/// Get a file 's information
362///
363/// Example code :
364/// ``` no_run
365/// use metabox_sdk::databox::{self, FileExt, DataErr};
366///
367/// async fn get_file_info(data_box_canister_id_text: &str, file_key: &str) -> Result<FileExt, DataErr> {
368/// databox::get_file_info("identities/identity.pem", data_box_canister_id_text, file_key).await
369/// }
370///
371/// #[tokio::main]
372/// async fn main() {
373/// match get_file_info("4radi-oqaaa-aaaan-qapwa-cai", "3166112af0dcc940f8e7f2199a4200cfb5e2efb40796391201b8fe9e4ff7ca84").await {
374/// Ok(file_ext) => {
375/// match file_ext {
376/// FileExt::PlainFileExt(asset_ext) => {
377/// println!("file name: {:?}", asset_ext.file_name);
378/// println!("file extension: {:?}", asset_ext.file_extension);
379/// println!("file key: {:?}", asset_ext.file_key);
380/// println!("file total_size: {:?}", asset_ext.total_size);
381/// println!("file upload_status: {:?}", asset_ext.upload_status);
382/// println!("file in data box: {:?}", asset_ext.bucket_id.to_text());
383/// println!("file aes_pub_key: {:?}", asset_ext.aes_pub_key);
384/// println!("file need_query_times: {:?}", asset_ext.need_query_times);
385/// }
386/// _ => {}
387/// }
388/// }
389/// Err(error) => {
390/// println!("get file info error: {:?}", error);
391/// }
392/// }
393/// }
394/// ```
395pub async fn get_file_info(pem_identity_path: &str, data_box_canister_id_text: &str, file_key: &str) -> Result<FileExt, DataErr> {
396 let canister_id = Principal::from_text(data_box_canister_id_text).unwrap();
397 let response_blob = build_agent(pem_identity_path)
398 .query(&canister_id, "getAssetextkey")
399 .with_arg(Encode!(&file_key).expect("encode piece failed"))
400 .call()
401 .await
402 .expect("response error");
403 let response = Decode!(&response_blob, GetAssetExtKeyResult).unwrap();
404 match response {
405 GetAssetExtKeyResult::ok(file_ext) => Ok(file_ext),
406 GetAssetExtKeyResult::err(data_err) => Err(data_err),
407 }
408}
409
410/// Get all plain files 's information
411///
412/// Example code :
413/// ``` no_run
414/// use metabox_sdk::databox::{self, FileExt, DataErr};
415///
416/// async fn get_all_plain_files_info(data_box_canister_id_text: &str) -> Result<Vec<FileExt>, DataErr> {
417/// databox::get_all_plain_files_info("identities/identity.pem", data_box_canister_id_text).await
418/// }
419///
420/// #[tokio::main]
421/// async fn main() {
422/// match get_all_plain_files_info("4radi-oqaaa-aaaan-qapwa-cai").await {
423/// Ok(file_ext_s) => {
424/// let mut index = 0;
425/// for i in &file_ext_s {
426/// index += 1;
427/// match i {
428/// FileExt::PlainFileExt(asset_ext) => {
429/// println!("file index: {:?}", index);
430/// println!("file name: {:?}", asset_ext.file_name);
431/// println!("file extension: {:?}", asset_ext.file_extension);
432/// println!("file key: {:?}", asset_ext.file_key);
433/// println!("file total_size: {:?}", asset_ext.total_size);
434/// println!("file upload_status: {:?}", asset_ext.upload_status);
435/// println!("file in data box: {:?}", asset_ext.bucket_id.to_text());
436/// println!("file aes_pub_key: {:?}", asset_ext.aes_pub_key);
437/// println!("file need_query_times: {:?}", asset_ext.need_query_times);
438/// println!("\n");
439/// }
440/// _ => {}
441/// }
442/// }
443/// }
444/// Err(error) => {
445/// println!("get all plain files info error: {:?}", error);
446/// }
447/// }
448/// }
449/// ```
450pub async fn get_all_plain_files_info(pem_identity_path: &str, data_box_canister_id_text: &str) -> Result<Vec<FileExt>, DataErr> {
451 let canister_id = Principal::from_text(data_box_canister_id_text).unwrap();
452 let response_blob = build_agent(pem_identity_path)
453 .query(&canister_id, "getAssetexts")
454 .with_arg(Encode!().expect("encode piece failed"))
455 .call()
456 .await
457 .expect("response error");
458 let response = Decode!(&response_blob, GetAssetExtsResult).unwrap();
459 match response {
460 GetAssetExtsResult::ok(plain_assets, ..) => {
461 return Ok(plain_assets);
462 },
463 GetAssetExtsResult::err(data_err) => {
464 return Err(data_err);
465 },
466 }
467}
468
469/// Get DataBox version
470///
471/// Example code :
472/// ``` no_run
473/// use candid::Nat;
474/// use metabox_sdk::databox;
475///
476/// async fn get_version(data_box_canister_id_text: &str,) -> Nat {
477/// databox::get_version("identities/identity.pem", data_box_canister_id_text).await
478/// }
479///
480/// #[tokio::main]
481/// async fn main() {
482/// println!("data box version: {:?}", get_version("4radi-oqaaa-aaaan-qapwa-cai").await);
483/// }
484/// ```
485pub async fn get_version(pem_identity_path: &str, data_box_canister_id_text: &str,) -> Nat {
486 let canister_id = Principal::from_text(data_box_canister_id_text).unwrap();
487 let response_blob = build_agent(pem_identity_path)
488 .query(&canister_id, "getVersion")
489 .with_arg(Encode!().expect("encode piece failed"))
490 .call()
491 .await
492 .expect("response error");
493 let response = Decode!(&response_blob, Nat).unwrap();
494 response
495}
496
497/// Get DataBox canister state
498///
499/// Example code :
500/// ``` no_run
501/// use metabox_sdk::databox::{self, CanisterStateResult};
502///
503/// async fn get_canister_state(data_box_canister_id_text: &str,) -> CanisterStateResult {
504/// databox::get_canister_state("identities/identity.pem", data_box_canister_id_text).await
505/// }
506///
507/// #[tokio::main]
508/// async fn main() {
509/// println!("data box canister state: {:?}", get_canister_state("4radi-oqaaa-aaaan-qapwa-cai").await);
510/// }
511/// ```
512pub async fn get_canister_state(pem_identity_path: &str, data_box_canister_id_text: &str,) -> CanisterStateResult {
513 let canister_id = Principal::from_text(data_box_canister_id_text).unwrap();
514 let response_blob = build_agent(pem_identity_path)
515 .query(&canister_id, "canisterState")
516 .with_arg(Encode!().expect("encode piece failed"))
517 .call()
518 .await
519 .expect("response error");
520 let response = Decode!(&response_blob, CanisterStateResult).unwrap();
521 response
522}
523
524/// Get DataBox cycle balance
525///
526/// Example code :
527/// ``` no_run
528/// use metabox_sdk::databox::{self, CycleBalanceResult};
529///
530/// async fn get_cycle_balance(data_box_canister_id_text: &str,) -> CycleBalanceResult {
531/// databox::get_cycle_balance("identities/identity.pem", data_box_canister_id_text).await
532/// }
533///
534/// #[tokio::main]
535/// async fn main() {
536/// println!("data box cycle balance: {:?}", get_cycle_balance("4radi-oqaaa-aaaan-qapwa-cai").await);
537/// }
538/// ```
539pub async fn get_cycle_balance(pem_identity_path: &str, data_box_canister_id_text: &str,) -> CycleBalanceResult {
540 let canister_id = Principal::from_text(data_box_canister_id_text).unwrap();
541 let response_blob = build_agent(pem_identity_path)
542 .query(&canister_id, "cycleBalance")
543 .with_arg(Encode!().expect("encode piece failed"))
544 .call()
545 .await
546 .expect("response error");
547 let response = Decode!(&response_blob, CycleBalanceResult).unwrap();
548 response
549}
550
551/// Get DataBox available stable memory
552///
553/// Example code :
554/// ``` no_run
555/// use metabox_sdk::databox::{self, AvlSMResult};
556///
557/// async fn get_avl_sm(data_box_canister_id_text: &str,) -> AvlSMResult {
558/// databox::get_avl_sm("identities/identity.pem", data_box_canister_id_text).await
559/// }
560///
561/// #[tokio::main]
562/// async fn main() {
563/// println!("data box available stable memory: {:?}", get_avl_sm("4radi-oqaaa-aaaan-qapwa-cai").await);
564/// }
565/// ```
566pub async fn get_avl_sm(pem_identity_path: &str, data_box_canister_id_text: &str,) -> AvlSMResult {
567 let canister_id = Principal::from_text(data_box_canister_id_text).unwrap();
568 let response_blob = build_agent(pem_identity_path)
569 .query(&canister_id, "avlSM")
570 .with_arg(Encode!().expect("encode piece failed"))
571 .call()
572 .await
573 .expect("response error");
574 let response = Decode!(&response_blob, AvlSMResult).unwrap();
575 response
576}
577
578/// Get DataBox owner
579///
580/// Example code :
581/// ``` no_run
582/// use candid::Principal;
583/// use metabox_sdk::databox::{self, AvlSMResult};
584///
585/// async fn get_owner(data_box_canister_id_text: &str,) -> Principal {
586/// databox::get_owner("identities/identity.pem", data_box_canister_id_text).await
587/// }
588///
589/// #[tokio::main]
590/// async fn main() {
591/// println!("data box owner: {:?}", get_owner("4radi-oqaaa-aaaan-qapwa-cai").await.to_text());
592/// }
593/// ```
594pub async fn get_owner(pem_identity_path: &str, data_box_canister_id_text: &str,) -> candid::Principal {
595 let canister_id = Principal::from_text(data_box_canister_id_text).unwrap();
596 let response_blob = build_agent(pem_identity_path)
597 .query(&canister_id, "getOwner")
598 .with_arg(Encode!().expect("encode piece failed"))
599 .call()
600 .await
601 .expect("response error");
602 let response = Decode!(&response_blob, candid::Principal).unwrap();
603 response
604}
605
606// Access file from file path, slice and return [each slice] array
607fn get_file_from_source(path: &str) -> (usize, usize, Vec<Vec<u8>>) {
608 let context = fs::read(path).expect("read file failed");
609 let size = context.len();
610 let slice_size = if context.len() % UPDATE_SIZE == 0 {
611 context.len() / UPDATE_SIZE
612 } else {
613 context.len() / UPDATE_SIZE + 1
614 };
615 let mut res = Vec::new();
616 for index in 0..slice_size {
617 if index == slice_size - 1 {
618 res.push(context[index * UPDATE_SIZE..context.len()].to_owned())
619 } else {
620 res.push(context[index * UPDATE_SIZE..(index + 1) * UPDATE_SIZE].to_owned())
621 }
622 }
623 (size, slice_size, res)
624}
625
626fn build_put_plain_args(
627 file_name: String,
628 file_extension: String,
629 total_size: u64,
630 chunk_number: u64,
631 data_slice: &Vec<Vec<u8>>,
632) -> Vec<FilePut> {
633 let mut order = 0;
634 let mut puts: Vec<FilePut> = Vec::new();
635 let file_key = get_file_key(&get_file_sha256_digest(data_slice));
636 for data in data_slice {
637 puts.push(FilePut::PlainFilePut(PUT::segment {
638 aes_pub_key: None,
639 file_key: file_key.clone(),
640 file_name: file_name.clone(),
641 file_extension: file_extension.clone(),
642 chunk: Chunk {
643 data: data.clone(),
644 },
645 chunk_number: Nat::from(chunk_number),
646 order: Nat::from(order),
647 total_size: total_size.clone(),
648 }));
649 order += 1;
650 }
651 puts
652}
653
654fn get_file_sha256_digest(context: &Vec<Vec<u8>>) -> Vec<Vec<u8>> {
655 let mut digests = vec![vec![0x00 as u8]; context.len()];
656 let mut contents = digests.iter_mut().zip(context.iter()).collect::<Vec<_>>();
657 contents
658 .par_iter_mut()
659 .for_each(|(d, text)| **d = digest_bytes(*text).into_bytes()[..32].to_vec());
660 digests
661}
662
663fn get_file_key(digests: &Vec<Vec<u8>>) -> String {
664 let mut digest = vec![0x00 as u8; 32 * digests.len()];
665 let mut _index = 0;
666 for bytes in digests {
667 for byte in bytes {
668 digest.push(*byte);
669 _index += 1;
670 }
671 }
672 digest_bytes(&digest)
673}
674
675fn get_file_type(file_type: &str) -> &str {
676 if file_type == "pdf" {
677 return "application/pdf";
678 } else if file_type == "jpg" || file_type == "jpeg" {
679 return "image/jpg";
680 } else if file_type == "png" {
681 return "image/png";
682 } else if file_type == "mp4" {
683 return "video/mp4";
684 } else if file_type == "mp3" {
685 return "audio/mp3";
686 } else if file_type == "gif" {
687 return "image/gif";
688 } else if file_type == "txt" {
689 return "text/plain";
690 } else if file_type == "ppt" || file_type == "pptx" {
691 return "application/vnd.ms-powerpoint";
692 } else if file_type == "html" || file_type == "xhtml" {
693 return "text/html";
694 } else if file_type == "doc" || file_type == "docx" {
695 return "application/msword";
696 } else if file_type == "xls" {
697 return "application/x-xls";
698 } else if file_type == "apk" {
699 return "application/vnd.android.package-archive";
700 } else if file_type == "svg" {
701 return "text/xml";
702 } else if file_type == "wmv" {
703 return "video/x-ms-wmv";
704 } else {
705 return "application/octet-stream";
706 }
707}
708
709fn get_waiter() -> Delay {
710 let waiter = garcon::Delay::builder()
711 .throttle(std::time::Duration::from_millis(500))
712 .timeout(std::time::Duration::from_secs(60 * 5))
713 .build();
714 waiter
715}
716
717fn build_agent(pem_identity_path: &str) -> Agent {
718 let url = "https://ic0.app".to_string();
719 let identity = Secp256k1Identity::from_pem_file(String::from(pem_identity_path)).unwrap();
720 let transport = ReqwestHttpReplicaV2Transport::create(url).expect("transport error");
721 let agent = Agent::builder()
722 .with_transport(transport)
723 .with_identity(identity)
724 .build()
725 .expect("build agent error");
726 agent
727}
728
729// pub async fn put_encrypt_files(pem_identity_path: &str, folder_path: &str, databox_canister_id_text: &str,) -> Vec<PutPlainFileResult> {
730// let canister_id = Principal::from_text(databox_canister_id_text).unwrap();
731// let agent = build_agent(pem_identity_path);
732// let waiter = get_waiter();
733//
734// let mut ans: Vec<PutPlainFileResult> = Vec::new();
735// let paths = fs::read_dir(&folder_path).unwrap();
736// for path in paths {
737// let file_path = path.unwrap().file_name().into_string().unwrap();
738// let pos: Vec<&str> = file_path.split(".").collect();
739// let file_name = String::from(pos[0]);
740// let file_extension = String::from(get_file_type(&String::from(pos[1])));
741// let s = folder_path.to_owned() + &file_path;
742//
743// let (file_size, slice_size, data_slice) = get_file_from_source(&s);
744//
745// let puts = build_put_plain_args(
746// file_name.clone(),
747// file_extension.clone(),
748// file_size.try_into().unwrap(),
749// slice_size.try_into().unwrap(),
750// &data_slice,
751// );
752//
753// let file_key = match &puts[0] {
754// FilePut::PlainFilePut(put) => {
755// match put {
756// PUT::segment {file_extension, order, chunk_number, chunk, aes_pub_key, file_name, file_key, total_size} => {
757// file_key.clone()
758// }
759// _ => {"".to_string()}
760// }
761// }
762// _ => {"".to_string()}
763// };
764//
765// let mut flag = false;
766// for put in &puts {
767// let _response_blob = agent
768// .update(&canister_id, "put")
769// .with_arg(Encode!(&put).expect("encode piece failed"))
770// .call_and_wait(waiter.clone())
771// .await
772// .expect("response error");
773// let _response = Decode!(&_response_blob, PutResult).unwrap();
774// match _response {
775// PutResult::ok(..) => {
776// },
777// PutResult::err(data_err) => {
778// ans.push(PutPlainFileResult {
779// file_name: file_name.clone(),
780// file_extension: file_extension.clone(),
781// file_key: file_key.clone(),
782// upload_status: UploadStatus::Err(data_err),
783// databox_canister_id: canister_id,
784// total_size: file_size.try_into().unwrap(),
785// chunk_number: slice_size.try_into().unwrap(),
786// });
787// flag = true;
788// break;
789// }
790// }
791// }
792// if !flag { ans.push(PutPlainFileResult {
793// file_name: file_name.clone(),
794// file_extension: file_extension.clone(),
795// file_key: file_key.clone(),
796// upload_status: UploadStatus::Ok,
797// databox_canister_id: canister_id,
798// total_size: file_size.try_into().unwrap(),
799// chunk_number: slice_size.try_into().unwrap(),
800// }); }
801// }
802// ans
803// }
804
805/*fn build_ciphertext_put(
806 file_name: String,
807 file_extension: String,
808 total_size: u64,
809 data_slice: &Vec<Vec<u8>>,
810 aes_key_text: &Vec<u8>, // aes_key mingwen
811 rsa_key: &Rsa<Private>, // rsa密钥
812 iv: &Vec<u8>, //
813) -> Vec<FilePut> {
814 let mut order = 0;
815 let mut puts = vec![];
816 let mut encrypted_aes_key = vec![];
817 let _ = rsa_key.public_encrypt(aes_key_text, &mut encrypted_aes_key, Padding::PKCS1);
818 let encrypted_aes_key = hex::encode(&encrypted_aes_key);
819 let mut cipher_text = vec![vec![]; data_slice.len()];
820 let aes_key = AesKey::new_encrypt(aes_key_text).expect("get aes key failed");
821 cipher_text
822 .iter_mut()
823 .zip(data_slice.iter())
824 .collect::<Vec<_>>()
825 .par_iter_mut()
826 .for_each(|(cipher, data)| {
827 let mut iv_temp = iv.clone();
828 aes_ige(*data, *cipher, &aes_key, &mut iv_temp, Mode::Encrypt)
829 });
830 let file_key = get_file_key(&get_file_sha256_digest(&cipher_text));
831 for cipher in cipher_text {
832 puts.push(FilePut::EncryptFilePut(PUT::segment {
833 aes_pub_key: Some(encrypted_aes_key.clone()),
834 file_key: file_key.clone(),
835 file_name: file_name.clone(),
836 file_extension: file_extension.clone(),
837 chunk: Chunk {
838 data: cipher.to_vec(),
839 },
840 chunk_number: Nat::from(cipher.len()),
841 order: Nat::from(order),
842 total_size: total_size.clone(),
843 }));
844 order += 1;
845 }
846 puts
847}*/