Skip to main content

junobuild_storage/
runtime.rs

1use crate::certification::types::certified::CertifiedAssetHashes;
2use crate::memory::STATE;
3use crate::strategies::StorageCertificateStrategy;
4use crate::types::config::StorageConfig;
5use crate::types::runtime_state::{
6    BatchId, Batches, ChunkId, Chunks, RuntimeState, StorageRuntimeState,
7};
8use crate::types::store::{Asset, Batch, BatchExpiry, Chunk};
9use ic_cdk::api::time;
10use ic_certification::Hash;
11use junobuild_collections::types::core::CollectionKey;
12use junobuild_shared::rate::types::RateConfig;
13use junobuild_shared::rate::utils::increment_and_assert_rate_store;
14use std::collections::HashMap;
15
16// ---------------------------------------------------------
17// Certified assets
18// ---------------------------------------------------------
19
20pub fn init_certified_assets(asset_hashes: &CertifiedAssetHashes) {
21    STATE.with(|state| {
22        init_certified_assets_impl(asset_hashes, &mut state.borrow_mut().runtime.storage)
23    });
24}
25
26pub fn update_certified_asset(
27    asset: &Asset,
28    config: &StorageConfig,
29    certificate: &impl StorageCertificateStrategy,
30) {
31    // 1. Replace or insert the new asset in tree
32    STATE.with(|state| update_certified_asset_impl(asset, config, &mut state.borrow_mut().runtime));
33
34    // 2. Update the root hash and the canister certified data
35    certificate.update_certified_data();
36}
37
38pub fn delete_certified_asset(asset: &Asset, certificate: &impl StorageCertificateStrategy) {
39    // 1. Remove the asset in tree
40    STATE.with(|state| delete_certified_asset_impl(asset, &mut state.borrow_mut().runtime));
41
42    // 2. Update the root hash and the canister certified data
43    certificate.update_certified_data();
44}
45
46pub fn certified_assets_root_hash() -> Hash {
47    STATE.with(|state| certified_assets_root_hash_impl(&state.borrow().runtime.storage))
48}
49
50fn init_certified_assets_impl(
51    asset_hashes: &CertifiedAssetHashes,
52    storage: &mut StorageRuntimeState,
53) {
54    storage.asset_hashes = asset_hashes.clone();
55}
56
57fn update_certified_asset_impl(asset: &Asset, config: &StorageConfig, runtime: &mut RuntimeState) {
58    runtime.storage.asset_hashes.insert(asset, config);
59}
60
61fn delete_certified_asset_impl(asset: &Asset, runtime: &mut RuntimeState) {
62    runtime.storage.asset_hashes.delete(asset);
63}
64
65fn certified_assets_root_hash_impl(storage: &StorageRuntimeState) -> Hash {
66    storage.asset_hashes.root_hash()
67}
68
69// ---------------------------------------------------------
70// Batch
71// ---------------------------------------------------------
72
73pub fn get_batch(batch_id: &BatchId) -> Option<Batch> {
74    STATE.with(|state| {
75        state
76            .borrow()
77            .runtime
78            .storage
79            .batches
80            .get(batch_id)
81            .cloned()
82    })
83}
84
85pub fn insert_batch(batch_id: &BatchId, batch: Batch) {
86    STATE.with(|state| {
87        insert_batch_impl(
88            batch_id,
89            batch,
90            &mut state.borrow_mut().runtime.storage.batches,
91        )
92    })
93}
94
95pub fn clear_expired_batches() {
96    STATE.with(|state| clear_expired_batches_impl(&mut state.borrow_mut().runtime.storage.batches));
97}
98
99pub fn clear_batch(batch_id: &BatchId, chunk_ids: &[ChunkId]) {
100    STATE.with(|state| {
101        clear_batch_impl(batch_id, chunk_ids, &mut state.borrow_mut().runtime.storage)
102    });
103}
104
105fn insert_batch_impl(batch_id: &BatchId, batch: Batch, batches: &mut Batches) {
106    batches.insert(*batch_id, batch);
107}
108
109fn clear_expired_batches_impl(batches: &mut Batches) {
110    clear_expired_items(batches);
111}
112
113fn clear_expired_items<K, V>(batches: &mut HashMap<K, V>)
114where
115    K: Clone + Eq + std::hash::Hash,
116    V: BatchExpiry,
117{
118    let now = time();
119
120    let expired_ids: Vec<K> = batches
121        .iter()
122        .filter_map(|(id, item)| {
123            if now > item.expires_at() {
124                Some(id.clone())
125            } else {
126                None
127            }
128        })
129        .collect();
130
131    for id in expired_ids {
132        batches.remove(&id);
133    }
134}
135
136fn clear_batch_impl(batch_id: &BatchId, chunk_ids: &[ChunkId], state: &mut StorageRuntimeState) {
137    for chunk_id in chunk_ids.iter() {
138        state.chunks.remove(chunk_id);
139    }
140
141    state.batches.remove(batch_id);
142}
143
144// ---------------------------------------------------------
145// Chunks
146// ---------------------------------------------------------
147
148pub fn get_chunk(chunk_id: &ChunkId) -> Option<Chunk> {
149    STATE.with(|state| {
150        let chunks = state.borrow().runtime.storage.chunks.clone();
151        let chunk = chunks.get(chunk_id);
152        chunk.cloned()
153    })
154}
155
156pub fn clear_expired_chunks() {
157    STATE.with(|state| clear_expired_chunks_impl(&mut state.borrow_mut().runtime.storage));
158}
159
160pub fn insert_chunk(chunk_id: &ChunkId, chunk: Chunk) {
161    STATE.with(|state| {
162        insert_chunk_impl(
163            chunk_id,
164            chunk,
165            &mut state.borrow_mut().runtime.storage.chunks,
166        )
167    })
168}
169
170fn clear_expired_chunks_impl(state: &mut StorageRuntimeState) {
171    let cloned_chunks = state.chunks.clone();
172
173    for (chunk_id, chunk) in cloned_chunks.iter() {
174        if !state.batches.contains_key(&chunk.batch_id) {
175            state.chunks.remove(chunk_id);
176        }
177    }
178}
179
180fn insert_chunk_impl(chunk_id: &ChunkId, chunk: Chunk, chunks: &mut Chunks) {
181    chunks.insert(*chunk_id, chunk);
182}
183
184// ---------------------------------------------------------
185// Rates
186// ---------------------------------------------------------
187
188pub fn increment_and_assert_rate(
189    collection: &CollectionKey,
190    config: &Option<RateConfig>,
191) -> Result<(), String> {
192    STATE.with(|state| {
193        increment_and_assert_rate_store(
194            collection,
195            config,
196            &mut state.borrow_mut().runtime.storage.rate_tokens,
197        )
198    })
199}