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}