Skip to content

Commit 7e7439a

Browse files
committed
chore: add more documents
1 parent d227071 commit 7e7439a

File tree

25 files changed

+410
-186
lines changed

25 files changed

+410
-186
lines changed

README.md

Lines changed: 26 additions & 103 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
# `ic-oss`
2+
23
🗂 A decentralized Object Storage Service on the Internet Computer.
34

45
💝 This project received a **$25k Developer Grant** from the [DFINITY Foundation](https://dfinity.org/grants).
@@ -9,10 +10,12 @@
910

1011
In decentralized enterprise applications, `ic-oss` will be an essential infrastructure.
1112

12-
`ic-oss` is a file infrastructure service, not a user-facing file product, but it will provide a simple management interface.
13+
`ic-oss` is a file infrastructure service, not a user-facing product, but it will provide a simple management interface.
1314

1415
> [!NOTE]
15-
> `ic-oss` is in development and is not suitable for production use yet.
16+
> The main functions of `ic-oss` have been developed, and the cluster management function is still under development (which will be completed soon). It can be used in the production environment.
17+
18+
![IC-OSS](./ic-oss.webp)
1619

1720
## Features
1821

@@ -25,107 +28,27 @@ In decentralized enterprise applications, `ic-oss` will be an essential infrastr
2528
- [ ] Implements file encryption storage using ICP's vetKeys mechanism.
2629
- [ ] Integrates with external storage, supporting file storage in decentralized file services like IPFS and Arweave, with `ic-oss` managing file metadata.
2730

28-
## Running the project locally
29-
30-
If you want to test your project locally, you can use the following commands:
31-
32-
Deploy the bucket canister:
33-
```bash
34-
dfx canister create --specified-id mmrxu-fqaaa-aaaap-ahhna-cai ic_oss_bucket
35-
36-
dfx deploy ic_oss_bucket --argument "(opt variant {Init =
37-
record {
38-
name = \"LDC Labs\";
39-
file_id = 0;
40-
max_file_size = 0;
41-
max_folder_depth = 10;
42-
max_children = 1000;
43-
visibility = 0;
44-
max_custom_data_size = 4096;
45-
enable_hash_index = true;
46-
}
47-
})"
48-
# Output:
49-
# ...
50-
# Installing code for canister ic_oss_bucket, with canister ID mmrxu-fqaaa-aaaap-ahhna-cai
51-
# Deployed canisters.
52-
# URLs:
53-
# Backend canister via Candid interface:
54-
# ic_oss_bucket: http://127.0.0.1:4943/?canisterId=bd3sg-teaaa-aaaaa-qaaba-cai&id=mmrxu-fqaaa-aaaap-ahhna-cai
55-
```
56-
57-
Build cli tool:
58-
```bash
59-
cargo build -p ic-oss-cli
60-
61-
# Run the cli tool
62-
./target/debug/ic-oss-cli --help
63-
./target/debug/ic-oss-cli identity --help
64-
./target/debug/ic-oss-cli upload --help
65-
66-
# Generate a new identity
67-
./target/debug/ic-oss-cli identity --new --file myid.pem
68-
# Output:
69-
# principal: lxph3-nvpsv-yrevd-im4ug-qywcl-5ir34-rpsbs-6olvf-qtugo-iy5ai-jqe
70-
# new identity: myid.pem
71-
```
72-
73-
Add a manager to the bucket canister:
74-
```bash
75-
dfx canister call mmrxu-fqaaa-aaaap-ahhna-cai admin_set_managers '(vec {principal "lxph3-nvpsv-yrevd-im4ug-qywcl-5ir34-rpsbs-6olvf-qtugo-iy5ai-jqe"})'
76-
```
77-
78-
Upload a file to the bucket canister:
79-
```bash
80-
./target/debug/ic-oss-cli -i myid.pem upload -b mmrxu-fqaaa-aaaap-ahhna-cai --file test.tar.gz
81-
# Output:
82-
# ...
83-
# 2024-05-18 18:42:38 uploaded: 99.48%
84-
# 2024-05-18 18:42:38 uploaded: 99.66%
85-
# 2024-05-18 18:42:38 uploaded: 99.82%
86-
# 2024-05-18 18:42:38 uploaded: 100.00%
87-
# upload success, file id: 1, size: 147832281, chunks: 564, retry: 0, time elapsed: PT69.149941S
88-
```
89-
90-
List files:
91-
```bash
92-
dfx canister call ic_oss_bucket list_files '(0, null, null, null)'
93-
```
94-
95-
Get file info:
96-
```bash
97-
dfx canister call ic_oss_bucket get_file_info '(1, null)'
98-
# Output:
99-
# (
100-
# variant {
101-
# Ok = record {
102-
# id = 1 : nat32;
103-
# parent = 0 : nat32;
104-
# status = 0 : int8;
105-
# updated_at = 1_716_028_957_265 : nat;
106-
# hash = opt blob "\b7\bb\90\40\d6\44\79\a7\ca\56\c8\e0\3a\e2\da\dd\c8\19\85\9f\7b\85\84\88\c0\b9\98\ee\de\d6\de\de";
107-
# name = "test.tar.gz";
108-
# size = 147_832_281 : nat;
109-
# content_type = "application/gzip";
110-
# created_at = 1_716_028_890_649 : nat;
111-
# filled = 147_832_281 : nat;
112-
# chunks = 564 : nat32;
113-
# ert = null;
114-
# }
115-
# },
116-
# )
117-
118-
dfx canister call ic_oss_bucket get_file_info_by_hash '(blob "\b7\bb\90\40\d6\44\79\a7\ca\56\c8\e0\3a\e2\da\dd\c8\19\85\9f\7b\85\84\88\c0\b9\98\ee\de\d6\de\de", null)'
119-
```
120-
121-
Delete file:
122-
```bash
123-
dfx canister call ic_oss_bucket delete_file '(1, null)'
124-
```
125-
126-
Download the file in browser:
127-
- by file id: `http://mmrxu-fqaaa-aaaap-ahhna-cai.localhost:4943/f/1`
128-
- by file hash: `http://mmrxu-fqaaa-aaaap-ahhna-cai.localhost:4943/h/b7bb9040d64479a7ca56c8e03ae2daddc819859f7b858488c0b998eeded6dede`
31+
## Libraries
32+
33+
| Library | Description |
34+
| :--------------------------------------------------------------------------------------- | :----------------------------------------------------------------------------------------------------------------------- |
35+
| [ic_oss_bucket](https://github.com/ldclabs/ic-oss/tree/main/src/ic_oss_bucket) | An ICP smart contract and a storage bucket in the ic-oss cluster for storing files and folders. |
36+
| [ic_oss_cluster](https://github.com/ldclabs/ic-oss/tree/main/src/ic_oss_cluster) | An ICP smart contract and the manager of the ic-oss cluster. |
37+
| [ic-oss-can](https://github.com/ldclabs/ic-oss/tree/main/src/ic_oss_can) | A Rust library for implementing large file storage in ICP canisters. |
38+
| [ic-oss-types](https://github.com/ldclabs/ic-oss/tree/main/src/ic_oss_types) | A Rust types library used for integrating with ic-oss cluster. |
39+
| [ic-oss-cose](https://github.com/ldclabs/ic-oss/tree/main/src/ic_oss_cose) | A Rust library based on COSE (RFC9052) and CWT (RFC8392) for issuing and verifying access tokens for the ic-oss cluster. |
40+
| [ic-oss](https://github.com/ldclabs/ic-oss/tree/main/src/ic_oss) | The Rust version of the client SDK for the ic-oss cluster. |
41+
| [ic-oss-cli](https://github.com/ldclabs/ic-oss/tree/main/src/ic_oss_cli) | A command-line tool implemented in Rust for the ic-oss cluster. |
42+
| [examples/ai_canister](https://github.com/ldclabs/ic-oss/tree/main/examples/ai_canister) | A demonstration project used to show how to implement large file storage in the ICP canister by using `ic-oss-can`. |
43+
44+
## Integration Workflow
45+
46+
![IC-OSS Sequence](./ic-oss-sequence.webp)
47+
48+
How to integrate `ic-oss`:
49+
1. The backend of the Dapp calls the API of `ic_oss_cluster` to add access control policies for the user.
50+
2. The frontend of the Dapp uses the `ic-oss-ts` SDK to obtain the `access_token` of the target `ic_oss_bucket` from `ic_oss_cluster`.
51+
3. The frontend of the Dapp uses the `access_token` to call the API of the target `ic_oss_bucket` to operate the authorized files and folders.
12952

13053
## License
13154
Copyright © 2024 [LDC Labs](https://github.com/ldclabs).

examples/ai_canister/README.md

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,11 @@
11
# Example: `ai_canister`
22

3+
[ic-oss](https://github.com/ldclabs/ic-oss) is a decentralized Object Storage Service on the Internet Computer.
4+
5+
`ai_canister` is a demonstration project used to show how to implement large file storage in the ICP canister. By using `ic-oss-can` to include the `ic_oss_fs!` macro in your canister, an `fs` module and a set of Candid file system APIs will be automatically generated. You can use the `ic-oss-cli` tool to upload files to the ICP canister.
6+
7+
For more information about `ic-oss-can`, please refer to [ic-oss-can](https://github.com/ldclabs/ic-oss/tree/main/src/ic_oss_can).
8+
39
## Running the project locally
410

511
If you want to test your project locally, you can use the following commands:
@@ -39,4 +45,4 @@ dfx canister call ai_canister list_files '(0, null, null, null)'
3945
## License
4046
Copyright © 2024 [LDC Labs](https://github.com/ldclabs).
4147

42-
`ldclabs/ic-oss` is licensed under the MIT License. See [LICENSE](../../LICENSE-MIT) for the full license text.
48+
`ldclabs/ic-oss` is licensed under the MIT License. See [LICENSE](../../LICENSE-MIT) for the full license text.

ic-oss-sequence.webp

33.6 KB
Binary file not shown.

ic-oss.webp

42.4 KB
Binary file not shown.

src/ic_oss/Cargo.toml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
[package]
22
name = "ic-oss"
3-
description = "A rust client of ic-oss."
3+
description = "The Rust version of the client SDK for the ic-oss cluster."
44
publish = true
55
repository = "https://github.com/ldclabs/ic-oss/tree/main/src/ic_oss"
66
version.workspace = true

src/ic_oss/README.md

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,15 +1,15 @@
11
# `ic-oss`
2-
32
![License](https://img.shields.io/crates/l/ic-oss.svg)
43
[![Crates.io](https://img.shields.io/crates/d/ic-oss.svg)](https://crates.io/crates/ic-oss)
5-
[![CI](https://github.com/ldclabs/ic-oss/actions/workflows/ci.yml/badge.svg)](https://github.com/ldclabs/ic-oss/actions/workflows/ci.yml)
4+
[![Test](https://github.com/ldclabs/ic-oss/actions/workflows/test.yml/badge.svg)](https://github.com/ldclabs/ic-oss/actions/workflows/test.yml)
65
[![Docs.rs](https://img.shields.io/docsrs/ic-oss?label=docs.rs)](https://docs.rs/ic-oss)
76
[![Latest Version](https://img.shields.io/crates/v/ic-oss.svg)](https://crates.io/crates/ic-oss)
87

9-
A rust client of [ic-oss](https://github.com/ldclabs/ic-oss).
10-
`ic-oss` is a fully open-source decentralized object storage service running on the Internet Computer.
8+
[ic-oss](https://github.com/ldclabs/ic-oss) is a decentralized Object Storage Service on the Internet Computer.
9+
10+
`ic-oss` is the Rust version of the client SDK for the ic-oss cluster.
1111

1212
## License
1313
Copyright © 2024 [LDC Labs](https://github.com/ldclabs).
1414

15-
`ldclabs/ic-oss` is licensed under the MIT License. See [LICENSE](LICENSE) for the full license text.
15+
`ldclabs/ic-oss` is licensed under the MIT License. See [LICENSE](../../LICENSE-MIT) for the full license text.

src/ic_oss_bucket/Cargo.toml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
[package]
22
name = "ic_oss_bucket"
3-
description = "A bucket canister of ic-oss"
3+
description = "An ICP smart contract and a storage bucket in the ic-oss cluster for storing files and folders."
44
publish = false
55
repository = "https://github.com/ldclabs/ic-oss/tree/main/src/ic_oss_bucket"
66
version.workspace = true

src/ic_oss_bucket/README.md

Lines changed: 54 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,48 @@
11
# `ic_oss_bucket`
22

3-
[![CI](https://github.com/ldclabs/ic-oss/actions/workflows/ci.yml/badge.svg)](https://github.com/ldclabs/ic-oss/actions/workflows/ci.yml)
3+
[ic-oss](https://github.com/ldclabs/ic-oss) is a decentralized Object Storage Service on the Internet Computer.
4+
5+
`ic_oss_bucket` is an ICP smart contract and a storage bucket in the `ic-oss` cluster for storing files and folders. The `ic-oss` cluster can deploy one or more buckets for horizontal file storage scaling, managed by `ic_oss_cluster`.
6+
7+
## Features
8+
9+
- [x] Supports large file uploads and downloads through file sharding, concurrent high-speed uploads, resumable uploads, and segmented downloads.
10+
- [x] Provides data verification based on ICP's verification mechanisms to ensure file integrity during reading.
11+
- [x] Supports file directory tree.
12+
- [x] Access control with permissions for public, private, read-only, and write-only for files, folders, and buckets.
13+
14+
## Candid API
15+
16+
```shell
17+
admin_set_auditors : (vec principal) -> (Result);
18+
admin_set_managers : (vec principal) -> (Result);
19+
admin_update_bucket : (UpdateBucketInput) -> (Result);
20+
batch_delete_subfiles : (nat32, vec nat32, opt blob) -> (Result_1);
21+
create_file : (CreateFileInput, opt blob) -> (Result_2);
22+
create_folder : (CreateFolderInput, opt blob) -> (Result_2);
23+
delete_file : (nat32, opt blob) -> (Result_3);
24+
delete_folder : (nat32, opt blob) -> (Result_3);
25+
get_bucket_info : (opt blob) -> (Result_4) query;
26+
get_file_ancestors : (nat32, opt blob) -> (Result_5) query;
27+
get_file_chunks : (nat32, nat32, opt nat32, opt blob) -> (Result_6) query;
28+
get_file_info : (nat32, opt blob) -> (Result_7) query;
29+
get_file_info_by_hash : (blob, opt blob) -> (Result_7) query;
30+
get_folder_ancestors : (nat32, opt blob) -> (Result_5) query;
31+
get_folder_info : (nat32, opt blob) -> (Result_8) query;
32+
http_request : (HttpRequest) -> (HttpStreamingResponse) query;
33+
list_files : (nat32, opt nat32, opt nat32, opt blob) -> (Result_9) query;
34+
list_folders : (nat32, opt blob) -> (Result_10) query;
35+
move_file : (MoveInput, opt blob) -> (Result_11);
36+
move_folder : (MoveInput, opt blob) -> (Result_11);
37+
update_file_chunk : (UpdateFileChunkInput, opt blob) -> (Result_12);
38+
update_file_info : (UpdateFileInput, opt blob) -> (Result_11);
39+
update_folder_info : (UpdateFolderInput, opt blob) -> (Result_11);
40+
validate_admin_set_auditors : (vec principal) -> (Result) query;
41+
validate_admin_set_managers : (vec principal) -> (Result) query;
42+
validate_admin_update_bucket : (UpdateBucketInput) -> (Result) query;
43+
```
444

5-
A bucket canister of [ic-oss](https://github.com/ldclabs/ic-oss).
6-
`ic-oss` is a fully open-source decentralized object storage service running on the Internet Computer.
45+
The complete Candid API definition can be found in the [ic_oss_bucket.did](https://github.com/ldclabs/ic-oss/tree/main/src/ic_oss_bucket/ic_oss_bucket.did) file.
746

847
## Running locally
948

@@ -28,8 +67,10 @@ MYID=$(dfx identity get-principal)
2867
ic-oss-cli -i debug/uploader.pem identity
2968
# principal: nprym-ylvyz-ig3fr-lgcmn-zzzt4-tyuix-3v6bm-fsel7-6lq6x-zh2w7-zqe
3069

70+
# add managers
3171
dfx canister call ic_oss_bucket admin_set_managers "(vec {principal \"$MYID\"; principal \"nprym-ylvyz-ig3fr-lgcmn-zzzt4-tyuix-3v6bm-fsel7-6lq6x-zh2w7-zqe\"})"
3272

73+
# add public keys to verify the access tokens
3374
dfx canister call ic_oss_bucket admin_update_bucket '(record {
3475
name = null;
3576
max_file_size = null;
@@ -43,18 +84,25 @@ dfx canister call ic_oss_bucket admin_update_bucket '(record {
4384
trusted_eddsa_pub_keys = opt vec {vec {19; 152; 246; 44; 109; 26; 69; 124; 81; 186; 106; 75; 95; 61; 189; 47; 105; 252; 169; 50; 22; 33; 141; 200; 153; 126; 65; 107; 209; 125; 147; 202}};
4485
}, null)'
4586

87+
# list files in the folder 2, with a access token
4688
dfx canister call ic_oss_bucket list_files '(2, null, null, opt blob "\84\44\a1\01\38\2e\a0\58\ac\a7\01\78\1b\61\6a\75\71\34\2d\72\75\61\61\61\2d\61\61\61\61\61\2d\71\61\61\67\61\2d\63\61\69\02\78\3f\7a\37\77\6a\70\2d\76\36\66\65\33\2d\6b\6b\73\75\35\2d\32\36\66\36\34\2d\64\65\64\74\77\2d\6a\37\6e\64\6a\2d\35\37\6f\6e\78\2d\71\67\61\36\63\2d\65\74\35\65\33\2d\6e\6a\78\35\33\2d\74\61\65\03\78\1b\6d\6d\72\78\75\2d\66\71\61\61\61\2d\61\61\61\61\70\2d\61\68\68\6e\61\2d\63\61\69\04\1a\66\8f\ce\68\05\1a\66\8f\c0\58\06\1a\66\8f\c0\58\09\78\18\46\6f\6c\64\65\72\2e\2a\3a\31\20\42\75\63\6b\65\74\2e\52\65\61\64\2e\2a\58\40\52\66\3e\e7\55\7e\99\2c\66\6d\65\56\54\9f\30\a1\2e\aa\56\69\66\b6\c6\e9\75\d7\c9\02\4c\24\1d\5d\7e\83\7d\c1\13\c6\00\91\56\d9\6a\ae\34\c3\a5\c9\b4\99\b3\47\b7\68\54\8d\dd\9c\9a\9b\a0\f9\1a\f5")'
89+
90+
# list folders in the root folder 0
4791
dfx canister call ic_oss_bucket list_folders '(0, null)'
4892

93+
# upload a file to the bucket
4994
ic-oss-cli -i debug/uploader.pem upload -b mmrxu-fqaaa-aaaap-ahhna-cai --file README.md
5095

96+
# read the file info
5197
dfx canister call ic_oss_bucket get_file_info '(1, null)'
5298

99+
# update the file 1's status to 0
53100
dfx canister call ic_oss_bucket update_file_info "(record {
54101
id = 1;
55102
status = opt 0;
56103
}, null)"
57104

105+
# create a folder in the root folder
58106
dfx canister call ic_oss_bucket create_folder "(record {
59107
parent = 0;
60108
name = \"home\";
@@ -66,6 +114,7 @@ dfx canister call ic_oss_bucket create_folder "(record {
66114
name = \"jarvis\";
67115
}, null)"
68116

117+
# move the file 1 from the root folder 0 to the folder 2
69118
dfx canister call ic_oss_bucket move_file "(record {
70119
id = 1;
71120
from = 0;
@@ -74,6 +123,7 @@ dfx canister call ic_oss_bucket move_file "(record {
74123

75124
dfx canister call ic_oss_bucket list_files '(2, null, null, null)'
76125

126+
# delete the file 1
77127
dfx canister call ic_oss_bucket delete_file '(1, null)'
78128
```
79129

@@ -85,4 +135,4 @@ Download the file in browser:
85135
## License
86136
Copyright © 2024 [LDC Labs](https://github.com/ldclabs).
87137

88-
`ldclabs/ic-oss` is licensed under the MIT License. See [LICENSE](LICENSE) for the full license text.
138+
`ldclabs/ic-oss` is licensed under the MIT License. See [LICENSE](../../LICENSE-MIT) for the full license text.

src/ic_oss_bucket/src/api_init.rs

Lines changed: 12 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -12,14 +12,14 @@ pub enum CanisterArgs {
1212

1313
#[derive(Clone, Debug, CandidType, Deserialize)]
1414
pub struct InitArgs {
15-
name: String,
16-
file_id: u32,
17-
max_file_size: u64,
18-
max_folder_depth: u8,
19-
max_children: u16,
20-
max_custom_data_size: u16,
21-
enable_hash_index: bool,
22-
visibility: u8, // 0: private; 1: public
15+
name: String, // bucket name
16+
file_id: u32, // the first file id, default is 0
17+
max_file_size: u64, // in bytes, default is 384GB
18+
max_folder_depth: u8, // default is 10
19+
max_children: u16, // maximum number of subfolders and subfiles in a folder., default is 1000
20+
max_custom_data_size: u16, // in bytes, default is 4KB
21+
enable_hash_index: bool, // if enabled, indexing will be built using file hash, allowing files to be read by their hash and preventing duplicate hash for files. default is false
22+
visibility: u8, // 0: private; 1: public, can be accessed by anyone, default is 0
2323
}
2424

2525
#[derive(Clone, Debug, CandidType, Deserialize)]
@@ -97,6 +97,10 @@ fn init(args: Option<CanisterArgs>) {
9797
args.max_custom_data_size
9898
};
9999
b.enable_hash_index = args.enable_hash_index;
100+
101+
// The root folder 0 is created by default
102+
b.folder_id = 1;
103+
b.folder_count = 1;
100104
});
101105
}
102106
CanisterArgs::Upgrade(_) => {

src/ic_oss_bucket/src/api_query.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -160,7 +160,7 @@ fn list_files(
160160
take: Option<u32>,
161161
access_token: Option<ByteBuf>,
162162
) -> Result<Vec<FileInfo>, String> {
163-
let max_prev = store::state::with(|s| s.file_id).saturating_add(1);
163+
let max_prev = store::state::with(|s| s.file_id);
164164
let prev = prev.unwrap_or(max_prev).min(max_prev);
165165
let take = take.unwrap_or(10).min(100);
166166
let canister = ic_cdk::id();

src/ic_oss_bucket/src/store.rs

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -815,7 +815,7 @@ pub mod fs {
815815
pub fn add_folder(metadata: FolderMetadata) -> Result<u32, String> {
816816
state::with_mut(|s| {
817817
FOLDERS.with(|r| {
818-
let id = s.folder_id.saturating_add(1);
818+
let id = s.folder_id;
819819
if id == u32::MAX {
820820
Err("folder id overflow".to_string())?;
821821
}
@@ -828,7 +828,7 @@ pub mod fs {
828828
s.max_children as usize,
829829
)?;
830830

831-
s.folder_id = id;
831+
s.folder_id = s.folder_id.saturating_add(1);
832832
s.folder_count += 1;
833833
Ok(id)
834834
})
@@ -838,7 +838,7 @@ pub mod fs {
838838
pub fn add_file(metadata: FileMetadata) -> Result<u32, String> {
839839
state::with_mut(|s| {
840840
FOLDERS.with(|r| {
841-
let id = s.file_id.saturating_add(1);
841+
let id = s.file_id;
842842
if id == u32::MAX {
843843
Err("file id overflow".to_string())?;
844844
}
@@ -860,7 +860,7 @@ pub mod fs {
860860
}
861861
}
862862

863-
s.file_id = id;
863+
s.file_id = s.file_id.saturating_add(1);
864864
s.file_count += 1;
865865
parent.files.insert(id);
866866
FS_METADATA_STORE.with(|r| r.borrow_mut().insert(id, metadata));

0 commit comments

Comments
 (0)