shadow_drive_sdk/client/
store_files.rs

1use 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        //Signature implements Display as a base58 encoded string
34        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}