junobuild_cdn/storage/state/
stable.rs1use crate::proposals::ProposalId;
2use crate::storage::state::types::{ProposalAssetKey, ProposalAssetsStable};
3use crate::storage::{ProposalContentChunkKey, ProposalContentChunksStable};
4use crate::strategies::CdnStableStrategy;
5use junobuild_collections::types::core::CollectionKey;
6use junobuild_shared::serializers::deserialize_from_bytes;
7use junobuild_shared::types::core::Blob;
8use junobuild_storage::stable_utils::insert_asset_encoding_stable;
9use junobuild_storage::types::state::FullPath;
10use junobuild_storage::types::store::{Asset, AssetEncoding, BlobOrKey};
11use std::borrow::Cow;
12use std::ops::RangeBounds;
13
14pub fn get_asset(
15 cdn_stable: &impl CdnStableStrategy,
16 proposal_id: &ProposalId,
17 collection: &CollectionKey,
18 full_path: &FullPath,
19) -> Option<Asset> {
20 cdn_stable.with_assets(|assets| get_asset_impl(proposal_id, collection, full_path, assets))
21}
22
23fn get_asset_impl(
24 proposal_id: &ProposalId,
25 collection: &CollectionKey,
26 full_path: &FullPath,
27 assets: &ProposalAssetsStable,
28) -> Option<Asset> {
29 assets.get(&proposal_asset_key(proposal_id, collection, full_path))
30}
31
32pub fn get_content_chunks(
33 cdn_stable: &impl CdnStableStrategy,
34 encoding: &AssetEncoding,
35 chunk_index: usize,
36) -> Option<Blob> {
37 cdn_stable.with_content_chunks(|content_chunks| {
38 get_content_chunks_impl(encoding, chunk_index, content_chunks)
39 })
40}
41
42fn get_content_chunks_impl(
43 encoding: &AssetEncoding,
44 chunk_index: usize,
45 content_chunks: &ProposalContentChunksStable,
46) -> Option<Blob> {
47 let key: ProposalContentChunkKey =
48 deserialize_from_bytes(Cow::Owned(encoding.content_chunks[chunk_index].clone()));
49 content_chunks.get(&key)
50}
51
52pub fn get_assets(
53 cdn_stable: &impl CdnStableStrategy,
54 proposal_id: &ProposalId,
55) -> Vec<(ProposalAssetKey, Asset)> {
56 cdn_stable.with_assets(|assets| get_assets_impl(proposal_id, assets))
57}
58
59fn get_assets_impl(
60 proposal_id: &ProposalId,
61 proposal_assets: &ProposalAssetsStable,
62) -> Vec<(ProposalAssetKey, Asset)> {
63 proposal_assets
64 .range(filter_assets_range(proposal_id))
65 .collect()
66}
67
68fn filter_assets_range(proposal_id: &ProposalId) -> impl RangeBounds<ProposalAssetKey> {
69 let start_key = ProposalAssetKey {
70 proposal_id: *proposal_id,
71 collection: "".to_string(),
72 full_path: "".to_string(),
73 };
74
75 let end_key = ProposalAssetKey {
76 proposal_id: *proposal_id + 1,
77 collection: "".to_string(),
78 full_path: "".to_string(),
79 };
80
81 start_key..end_key
82}
83
84pub fn insert_asset_encoding(
85 cdn_stable: &impl CdnStableStrategy,
86 proposal_id: &ProposalId,
87 full_path: &FullPath,
88 encoding_type: &str,
89 encoding: &AssetEncoding,
90 asset: &mut Asset,
91) {
92 let stable_key_fn = {
93 let proposal_id = *proposal_id;
94
95 move |full_path: &FullPath, encoding_type: &str, chunk_index: usize| {
96 proposal_encoding_chunk_key(&proposal_id, full_path, encoding_type, chunk_index)
97 }
98 };
99
100 cdn_stable.with_content_chunks_mut(|content_chunks| {
101 insert_asset_encoding_stable(
102 full_path,
103 encoding_type,
104 encoding,
105 asset,
106 stable_key_fn,
107 content_chunks,
108 )
109 })
110}
111
112pub fn insert_asset(
113 cdn_stable: &impl CdnStableStrategy,
114 proposal_id: &ProposalId,
115 collection: &CollectionKey,
116 full_path: &FullPath,
117 asset: &Asset,
118) {
119 cdn_stable.with_assets_mut(|assets| {
120 insert_asset_impl(proposal_id, collection, full_path, asset, assets)
121 })
122}
123
124fn insert_asset_impl(
125 proposal_id: &ProposalId,
126 collection: &CollectionKey,
127 full_path: &FullPath,
128 asset: &Asset,
129 assets: &mut ProposalAssetsStable,
130) {
131 assets.insert(
132 proposal_asset_key(proposal_id, collection, full_path),
133 asset.clone(),
134 );
135}
136
137pub fn delete_asset(cdn_stable: &impl CdnStableStrategy, key: &ProposalAssetKey) -> Option<Asset> {
138 cdn_stable.with_assets_mut(|assets| delete_asset_impl(key, assets))
139}
140
141fn delete_asset_impl(key: &ProposalAssetKey, assets: &mut ProposalAssetsStable) -> Option<Asset> {
142 assets.remove(key)
143}
144
145pub fn delete_content_chunks(
146 cdn_stable: &impl CdnStableStrategy,
147 content_chunks_keys: &[BlobOrKey],
148) {
149 cdn_stable.with_content_chunks_mut(|content_chunks| {
150 delete_content_chunks_impl(content_chunks_keys, content_chunks)
151 })
152}
153
154fn delete_content_chunks_impl(
155 content_chunks_keys: &[BlobOrKey],
156 content_chunks: &mut ProposalContentChunksStable,
157) {
158 for chunk in content_chunks_keys.iter() {
159 let key: ProposalContentChunkKey = deserialize_from_bytes(Cow::Owned(chunk.clone()));
160 content_chunks.remove(&key);
161 }
162}
163
164fn proposal_asset_key(
165 proposal_id: &ProposalId,
166 collection: &CollectionKey,
167 full_path: &FullPath,
168) -> ProposalAssetKey {
169 ProposalAssetKey {
170 proposal_id: *proposal_id,
171 collection: collection.clone(),
172 full_path: full_path.clone(),
173 }
174}
175
176fn proposal_encoding_chunk_key(
177 proposal_id: &ProposalId,
178 full_path: &FullPath,
179 encoding_type: &str,
180 chunk_index: usize,
181) -> ProposalContentChunkKey {
182 ProposalContentChunkKey {
183 proposal_id: *proposal_id,
184 full_path: full_path.clone(),
185 encoding_type: encoding_type.to_owned(),
186 chunk_index,
187 }
188}