shadow_drive_sdk/client/
edit_file.rs

1use reqwest::multipart::{Form, Part};
2use serde_json::Value;
3use solana_sdk::{pubkey::Pubkey, signer::Signer};
4
5use super::ShadowDriveClient;
6use crate::{
7    constants::{SHDW_DRIVE_ENDPOINT, SHDW_DRIVE_OBJECT_PREFIX},
8    error::Error,
9    models::*,
10};
11
12impl<T> ShadowDriveClient<T>
13where
14    T: Signer,
15{
16    /// Replace an existing file on the Shadow Drive with the given updated file.
17    /// * `storage_account_key` - The public key of the [`StorageAccount`](crate::models::StorageAccount) that contains the file.
18    /// * `url` - The Shadow Drive url of the file you want to replace.
19    /// * `data` - The updated [`ShadowFile`](crate::models::ShadowFile).
20    /// # Example
21    ///
22    /// ```
23    /// # use shadow_drive_rust::{ShadowDriveClient, derived_addresses::storage_account};
24    /// # use solana_client::rpc_client::RpcClient;
25    /// # use solana_sdk::{
26    /// # pubkey::Pubkey,
27    /// # signature::Keypair,
28    /// # signer::{keypair::read_keypair_file, Signer},
29    /// # };
30    /// #
31    /// # let keypair = read_keypair_file(KEYPAIR_PATH).expect("failed to load keypair at path");
32    /// # let user_pubkey = keypair.pubkey();
33    /// # let rpc_client = RpcClient::new("https://ssc-dao.genesysgo.net");
34    /// # let shdw_drive_client = ShadowDriveClient::new(keypair, rpc_client);
35    /// # let (storage_account_key, _) = storage_account(&user_pubkey, 0);
36    /// # let url = String::from("https://shdw-drive.genesysgo.net/B7Qk2omAvchkePhdGovCVQuVpZHcieqPQCwFxeeBZGuT/file.txt");
37    /// # let file = tokio::fs::File::open("example.png")
38    /// #   .await
39    /// #   .expect("failed to open file");
40    /// #
41    /// let edit_file_response = shdw_drive_client
42    ///     .edit_file(&storage_account_key, url, file)
43    ///     .await?;
44    /// ```
45    pub async fn edit_file(
46        &self,
47        storage_account_key: &Pubkey,
48        data: ShadowFile,
49    ) -> ShadowDriveResult<ShadowEditResponse> {
50        let message_to_sign = edit_message(storage_account_key, data.name(), &data.sha256().await?);
51
52        let signature = self
53            .wallet
54            .sign_message(message_to_sign.as_bytes())
55            .to_string();
56
57        let url = format!(
58            "{}/{}/{}",
59            SHDW_DRIVE_OBJECT_PREFIX,
60            storage_account_key,
61            data.name()
62        );
63
64        let form = Form::new()
65            .part("file", data.into_form_part().await?)
66            .part("message", Part::text(signature))
67            .part("signer", Part::text(self.wallet.pubkey().to_string()))
68            .part(
69                "storage_account",
70                Part::text(storage_account_key.to_string()),
71            )
72            .part("url", Part::text(url));
73
74        let response = self
75            .http_client
76            .post(format!("{}/edit", SHDW_DRIVE_ENDPOINT))
77            .multipart(form)
78            .send()
79            .await?;
80
81        if !response.status().is_success() {
82            return Err(Error::ShadowDriveServerError {
83                status: response.status().as_u16(),
84                message: response.json::<Value>().await?,
85            });
86        }
87
88        let response = response.json::<ShadowEditResponse>().await?;
89
90        Ok(response)
91    }
92}
93
94fn edit_message(storage_account_key: &Pubkey, filename: &str, new_hash: &str) -> String {
95    format!(
96        "Shadow Drive Signed Message:\n StorageAccount: {}\nFile to edit: {}\nNew file hash: {}",
97        storage_account_key, filename, new_hash
98    )
99}