Skip to content

Commit 7804f24

Browse files
feat: use a single usage collection
1 parent 91f7962 commit 7804f24

File tree

8 files changed

+74
-60
lines changed

8 files changed

+74
-60
lines changed

src/libs/collections/src/constants.rs

Lines changed: 3 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -19,8 +19,7 @@ pub const DEFAULT_DB_LOG_RULE: SetRule = SetRule {
1919
rate_config: None,
2020
};
2121

22-
pub const USER_USAGE_DB_COLLECTION_KEY: &str = "#user_usage_db";
23-
pub const USER_USAGE_STORAGE_COLLECTION_KEY: &str = "#user_usage_storage";
22+
pub const USER_USAGE_COLLECTION_KEY: &str = "#user-usage";
2423

2524
pub const DEFAULT_USER_USAGE_RULE: SetRule = SetRule {
2625
read: Managed,
@@ -34,7 +33,7 @@ pub const DEFAULT_USER_USAGE_RULE: SetRule = SetRule {
3433
rate_config: None,
3534
};
3635

37-
pub const DEFAULT_DB_COLLECTIONS: [(&str, SetRule); 4] = [
36+
pub const DEFAULT_DB_COLLECTIONS: [(&str, SetRule); 3] = [
3837
(
3938
"#user",
4039
SetRule {
@@ -50,8 +49,7 @@ pub const DEFAULT_DB_COLLECTIONS: [(&str, SetRule); 4] = [
5049
},
5150
),
5251
(LOG_COLLECTION_KEY, DEFAULT_DB_LOG_RULE),
53-
(USER_USAGE_DB_COLLECTION_KEY, DEFAULT_USER_USAGE_RULE),
54-
(USER_USAGE_STORAGE_COLLECTION_KEY, DEFAULT_USER_USAGE_RULE),
52+
(USER_USAGE_COLLECTION_KEY, DEFAULT_USER_USAGE_RULE),
5553
];
5654

5755
pub const DB_COLLECTIONS_NO_USER_USAGE: [&str; 1] = [LOG_COLLECTION_KEY];

src/libs/satellite/src/impls.rs

Lines changed: 11 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
1+
use std::fmt::{Display, Formatter, Result as FmtResult};
12
use crate::memory::init_stable_state;
2-
use crate::types::state::{HeapState, RuntimeState, State};
3+
use crate::types::state::{CollectionType, HeapState, RuntimeState, State};
34

45
impl Default for State {
56
fn default() -> Self {
@@ -10,3 +11,12 @@ impl Default for State {
1011
}
1112
}
1213
}
14+
15+
impl Display for CollectionType {
16+
fn fmt(&self, f: &mut Formatter<'_>) -> FmtResult {
17+
write!(f, "{}", match self {
18+
CollectionType::Db => "db",
19+
CollectionType::Storage => "storage",
20+
})
21+
}
22+
}

src/libs/satellite/src/rules/upgrade.rs

Lines changed: 3 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -1,34 +1,21 @@
11
use crate::memory::STATE;
22
use crate::rules::store::set_rule_db;
33
use junobuild_collections::constants::{
4-
DEFAULT_USER_USAGE_RULE, USER_USAGE_DB_COLLECTION_KEY, USER_USAGE_STORAGE_COLLECTION_KEY,
4+
DEFAULT_USER_USAGE_RULE, USER_USAGE_COLLECTION_KEY,
55
};
66

77
/// One time upgrade
88
99
pub fn init_user_usage_collections() {
1010
let col = STATE.with(|state| {
1111
let rules = &state.borrow_mut().heap.db.rules;
12-
rules.get(USER_USAGE_DB_COLLECTION_KEY).cloned()
12+
rules.get(USER_USAGE_COLLECTION_KEY).cloned()
1313
});
1414

1515
if col.is_none() {
1616
// We are ignoring potential issues because we are processing during an upgrade.
1717
let _ = set_rule_db(
18-
USER_USAGE_DB_COLLECTION_KEY.to_string(),
19-
DEFAULT_USER_USAGE_RULE,
20-
);
21-
}
22-
23-
let col_storage = STATE.with(|state| {
24-
let rules = &state.borrow_mut().heap.db.rules;
25-
rules.get(USER_USAGE_STORAGE_COLLECTION_KEY).cloned()
26-
});
27-
28-
if col_storage.is_none() {
29-
// We are ignoring potential issues because we are processing during an upgrade.
30-
let _ = set_rule_db(
31-
USER_USAGE_STORAGE_COLLECTION_KEY.to_string(),
18+
USER_USAGE_COLLECTION_KEY.to_string(),
3219
DEFAULT_USER_USAGE_RULE,
3320
);
3421
}

src/libs/satellite/src/usage/assert.rs

Lines changed: 5 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,6 @@
11
use crate::usage::store::increment_usage;
22
use crate::usage::utils::{is_db_collection_no_usage, is_storage_collection_no_usage};
3-
use junobuild_collections::constants::{
4-
USER_USAGE_DB_COLLECTION_KEY, USER_USAGE_STORAGE_COLLECTION_KEY,
5-
};
3+
use crate::types::state::CollectionType;
64
use junobuild_collections::types::core::CollectionKey;
75
use junobuild_shared::controllers::is_controller;
86
use junobuild_shared::types::state::{Controllers, UserId};
@@ -21,7 +19,7 @@ pub fn increment_and_assert_db_usage(
2119
caller,
2220
controllers,
2321
collection,
24-
&USER_USAGE_DB_COLLECTION_KEY.to_string(),
22+
&CollectionType::Db,
2523
max_changes_per_user,
2624
)
2725
}
@@ -40,7 +38,7 @@ pub fn increment_and_assert_storage_usage(
4038
caller,
4139
controllers,
4240
collection,
43-
&USER_USAGE_STORAGE_COLLECTION_KEY.to_string(),
41+
&CollectionType::Storage,
4442
max_changes_per_user,
4543
)
4644
}
@@ -49,15 +47,15 @@ fn increment_and_assert_usage(
4947
caller: UserId,
5048
controllers: &Controllers,
5149
collection: &CollectionKey,
52-
user_usage_collection: &CollectionKey,
50+
collection_type: &CollectionType,
5351
max_changes_per_user: Option<u32>,
5452
) -> Result<(), String> {
5553
// We only collect usage for users
5654
if is_controller(caller, controllers) {
5755
return Ok(());
5856
}
5957

60-
let user_usage = increment_usage(user_usage_collection, collection, &caller)?;
58+
let user_usage = increment_usage(collection, collection_type, &caller)?;
6159

6260
if let Some(max_changes_per_user) = max_changes_per_user {
6361
if user_usage.changes_count > max_changes_per_user {

src/libs/satellite/src/usage/impls.rs

Lines changed: 24 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,9 @@
1-
use crate::usage::types::state::UserUsage;
1+
use crate::usage::types::state::{UserUsage, UserUsageKey};
22
use ic_cdk::api::time;
3-
use junobuild_shared::types::state::{Timestamp, Version, Versioned};
3+
use junobuild_collections::types::core::CollectionKey;
4+
use junobuild_shared::types::state::{Timestamp, UserId, Version, Versioned};
45
use junobuild_shared::version::next_version;
6+
use crate::types::state::CollectionType;
57

68
impl UserUsage {
79
pub fn increment(current_user_usage: &Option<UserUsage>) -> Self {
@@ -45,3 +47,23 @@ impl Versioned for UserUsage {
4547
self.version
4648
}
4749
}
50+
51+
impl UserUsageKey {
52+
pub fn create(
53+
user_id: &UserId,
54+
collection_key: &CollectionKey,
55+
collection_type: &CollectionType,
56+
) -> Self {
57+
Self {
58+
user_id: *user_id,
59+
collection_key: collection_key.clone(),
60+
collection_type: collection_type.clone(),
61+
}
62+
}
63+
64+
pub fn to_key(
65+
&self
66+
) -> String {
67+
format!("{}#{}#{}", self.user_id.to_text(), self.collection_type, self.collection_key)
68+
}
69+
}
Lines changed: 13 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -1,40 +1,33 @@
1-
use crate::usage::types::state::UserUsage;
2-
use crate::usage::utils::build_user_usage_key;
1+
use crate::usage::types::state::{UserUsage, UserUsageKey};
32
use crate::{get_doc_store, set_doc_store, SetDoc};
43
use ic_cdk::id;
54
use junobuild_collections::types::core::CollectionKey;
65
use junobuild_shared::types::state::UserId;
76
use junobuild_utils::{decode_doc_data, encode_doc_data};
7+
use junobuild_collections::constants::USER_USAGE_COLLECTION_KEY;
8+
use crate::types::state::CollectionType;
89

910
pub fn increment_usage(
10-
user_usage_collection: &CollectionKey,
11-
collection: &CollectionKey,
11+
collection_key: &CollectionKey,
12+
collection_type: &CollectionType,
1213
user_id: &UserId,
1314
) -> Result<UserUsage, String> {
14-
let key = build_user_usage_key(user_id, collection);
15+
let user_usage_key = UserUsageKey::create(user_id, collection_key, collection_type);
16+
let key = user_usage_key.to_key();
1517

16-
let doc = get_doc_store(id(), user_usage_collection.to_string(), key.clone())?;
18+
let doc = get_doc_store(id(), USER_USAGE_COLLECTION_KEY.to_string(), key.clone())?;
1719

18-
let current_usage: Option<UserUsage> = match &doc {
19-
None => None,
20-
Some(doc) => decode_doc_data(&doc.data)?,
21-
};
20+
let current_usage = doc.as_ref().map(|doc| decode_doc_data(&doc.data)).transpose()?;
2221

2322
let update_usage = UserUsage::increment(&current_usage);
2423

25-
let update_doc: SetDoc = SetDoc {
24+
let update_doc = SetDoc {
2625
data: encode_doc_data(&update_usage)?,
27-
description: match &doc {
28-
None => None,
29-
Some(doc) => doc.description.clone(),
30-
},
31-
version: match &doc {
32-
None => None,
33-
Some(doc) => doc.version.clone(),
34-
},
26+
description: doc.as_ref().and_then(|d| d.description.clone()),
27+
version: doc.as_ref().and_then(|d| d.version.clone()),
3528
};
3629

37-
set_doc_store(id(), user_usage_collection.to_string(), key, update_doc)?;
30+
set_doc_store(id(), USER_USAGE_COLLECTION_KEY.to_string(), key, update_doc)?;
3831

3932
Ok(update_usage)
4033
}

src/libs/satellite/src/usage/types.rs

Lines changed: 15 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,22 @@
11
pub mod state {
22
use candid::CandidType;
3-
use junobuild_shared::types::core::Key;
4-
use junobuild_shared::types::state::{Timestamp, Version};
3+
use junobuild_shared::types::state::{Timestamp, UserId, Version};
54
use serde::{Deserialize, Serialize};
5+
use junobuild_collections::types::core::CollectionKey;
6+
use crate::types::state::CollectionType;
67

7-
pub type UserUsageKey = Key;
8+
/// A unique key for identifying user usage within a collection.
9+
///
10+
/// It consists of:
11+
/// - `user_id`: The unique identifier for the user which is matched to the caller.
12+
/// - `collection_key`: The collection where usage is tracked.
13+
/// - `collection_type`: The type of collection (`Db` for datastore, `Storage` for assets).
14+
#[derive(CandidType, Serialize, Deserialize, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
15+
pub struct UserUsageKey {
16+
pub user_id: UserId,
17+
pub collection_key: CollectionKey,
18+
pub collection_type: CollectionType,
19+
}
820

921
/// Tracks the usage (create, set and delete) of a user in a collection.
1022
///
Lines changed: 0 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,7 @@
1-
use crate::usage::types::state::UserUsageKey;
21
use junobuild_collections::constants::{
32
ASSETS_COLLECTIONS_NO_USER_USAGE, DB_COLLECTIONS_NO_USER_USAGE,
43
};
54
use junobuild_collections::types::core::CollectionKey;
6-
use junobuild_shared::types::state::UserId;
75

86
pub fn is_db_collection_no_usage(collection: &CollectionKey) -> bool {
97
DB_COLLECTIONS_NO_USER_USAGE.contains(&collection.as_str())
@@ -12,7 +10,3 @@ pub fn is_db_collection_no_usage(collection: &CollectionKey) -> bool {
1210
pub fn is_storage_collection_no_usage(collection: &CollectionKey) -> bool {
1311
ASSETS_COLLECTIONS_NO_USER_USAGE.contains(&collection.as_str())
1412
}
15-
16-
pub fn build_user_usage_key(user_id: &UserId, collection_key: &CollectionKey) -> UserUsageKey {
17-
format!("{}#{}", user_id.to_text(), collection_key)
18-
}

0 commit comments

Comments
 (0)