Skip to main content

junobuild_satellite/assets/storage/
handlers.rs

1use crate::assets::storage::state::{
2    get_asset, get_config, get_rule, insert_asset, insert_asset_encoding,
3};
4use crate::certification::strategy_impls::StorageCertificate;
5use crate::controllers::store::get_controllers;
6use junobuild_collections::assert::stores::assert_permission;
7use junobuild_collections::types::rules::Rule;
8use junobuild_shared::ic::api::id;
9use junobuild_shared::types::core::Blob;
10use junobuild_shared::types::state::Controllers;
11use junobuild_storage::constants::ASSET_ENCODING_NO_COMPRESSION;
12use junobuild_storage::errors::JUNO_STORAGE_ERROR_SET_NOT_ALLOWED;
13use junobuild_storage::http::types::HeaderField;
14use junobuild_storage::runtime::update_certified_asset as update_runtime_certified_asset;
15use junobuild_storage::types::store::{Asset, AssetKey};
16use junobuild_storage::utils::map_content_encoding;
17
18/// Handles the setting of an asset within the store. This function performs
19/// various checks and operations to ensure the asset can be set and updated
20/// correctly.
21///
22/// # Parameters
23/// - `key`: A reference to the `AssetKey` representing the unique identifier
24///   for the asset within the collection.
25/// - `content`: A reference to the `String` containing the asset content to be
26///   stored.
27/// - `headers`: A slice of `HeaderField` representing any additional headers
28///   associated with the asset.
29///
30/// # Returns
31/// - `Result<(), String>`: Returns `Ok(())` if the asset is successfully set.
32///   Returns an `Err(String)` with an error message if the operation fails.
33///
34/// # Errors
35/// - Returns an error if the asset cannot be retrieved from the storage.
36/// - Returns an error if the permission check fails when the asset is
37///   identified as existing and private.
38///
39/// # Important Note
40/// The content is set for the identity encoding, meaning there is no
41/// compression applied.
42pub fn set_asset_handler(
43    key: &AssetKey,
44    content: &Blob,
45    headers: &[HeaderField],
46) -> Result<(), String> {
47    let rule = get_rule(&key.collection)?;
48
49    let existing_asset = get_asset(&key.collection, &key.full_path, &rule);
50
51    if let Some(ref existing_asset) = existing_asset {
52        let controllers: Controllers = get_controllers();
53        // The handler is used in Serverless Functions therefore the caller is itself.
54        // This allows to assert for permission. Useful for collection set as "Private".
55        let caller = id();
56
57        if !assert_permission(&rule.write, existing_asset.key.owner, caller, &controllers) {
58            return Err(JUNO_STORAGE_ERROR_SET_NOT_ALLOWED.to_string());
59        }
60    }
61
62    set_asset_handler_impl(key, &existing_asset, content, headers, &rule)
63}
64
65fn set_asset_handler_impl(
66    key: &AssetKey,
67    existing_asset: &Option<Asset>,
68    content: &Blob,
69    headers: &[HeaderField],
70    rule: &Rule,
71) -> Result<(), String> {
72    let mut asset = Asset::prepare(key.clone(), headers.to_vec(), existing_asset);
73
74    let encoding = map_content_encoding(content);
75
76    insert_asset_encoding(
77        &key.full_path,
78        ASSET_ENCODING_NO_COMPRESSION,
79        &encoding,
80        &mut asset,
81        rule,
82    );
83
84    insert_asset(&key.collection, &key.full_path, &asset, rule);
85
86    let config = get_config();
87
88    update_runtime_certified_asset(&asset, &config, &StorageCertificate);
89
90    Ok(())
91}