shadow_drive_sdk/client/
store_files.rs1use itertools::Itertools;
2use reqwest::multipart::{Form, Part};
3use serde_json::Value;
4use sha2::{Digest, Sha256};
5use solana_sdk::{pubkey::Pubkey, signer::Signer};
6
7use super::ShadowDriveClient;
8use crate::{constants::SHDW_DRIVE_ENDPOINT, error::Error, models::*};
9
10fn upload_message(storage_account_key: &Pubkey, filename_hash: &str) -> String {
11 format!(
12 "Shadow Drive Signed Message:\nStorage Account: {}\nUpload files with hash: {}",
13 storage_account_key, filename_hash
14 )
15}
16
17impl<T> ShadowDriveClient<T>
18where
19 T: Signer,
20{
21 pub async fn store_files(
22 &self,
23 storage_account_key: &Pubkey,
24 data: Vec<ShadowFile>,
25 ) -> ShadowDriveResult<ShadowUploadResponse> {
26 let filenames = data.iter().map(ShadowFile::name).join(",");
27
28 let mut hasher = Sha256::new();
29 hasher.update(&filenames.as_bytes());
30 let filename_hash = hasher.finalize();
31
32 let message_to_sign = upload_message(storage_account_key, &hex::encode(filename_hash));
33 let signature = self
35 .wallet
36 .sign_message(message_to_sign.as_bytes())
37 .to_string();
38
39 let mut form = Form::new();
40
41 for file in data {
42 form = form.part("file", file.into_form_part().await?)
43 }
44
45 form = form
46 .part("message", Part::text(signature))
47 .part("signer", Part::text(self.wallet.pubkey().to_string()))
48 .part(
49 "storage_account",
50 Part::text(storage_account_key.to_string()),
51 )
52 .part("fileNames", Part::text(filenames));
53
54 let response = self
55 .http_client
56 .post(format!("{}/upload", SHDW_DRIVE_ENDPOINT))
57 .multipart(form)
58 .send()
59 .await?;
60
61 if !response.status().is_success() {
62 return Err(Error::ShadowDriveServerError {
63 status: response.status().as_u16(),
64 message: response.json::<Value>().await.unwrap_or(Value::Null),
65 });
66 }
67
68 let response = response.json::<ShadowUploadResponse>().await?;
69
70 Ok(response)
71 }
72}