junobuild_storage/
runtime.rs1use 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
16pub 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 STATE.with(|state| update_certified_asset_impl(asset, config, &mut state.borrow_mut().runtime));
33
34 certificate.update_certified_data();
36}
37
38pub fn delete_certified_asset(asset: &Asset, certificate: &impl StorageCertificateStrategy) {
39 STATE.with(|state| delete_certified_asset_impl(asset, &mut state.borrow_mut().runtime));
41
42 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
69pub 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
144pub 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
184pub 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}