Skip to main content

context69_sdk/client/library/
files.rs

1use context69_contracts::{
2    LibraryFileDetailResponse, LibraryFileUploadMetadata, LibraryUploadResponse, MoveFileRequest,
3    PrepareLibraryUploadRequest, PrepareLibraryUploadResponse,
4};
5use reqwest::{Method, multipart::Part};
6use sha2::{Digest, Sha256};
7use uuid::Uuid;
8
9use super::Context69Client;
10use crate::{
11    Error,
12    client::transport::{file_upload_form, file_upload_form_with_sha256},
13};
14
15pub struct LibraryFilesApi<'a> {
16    client: &'a Context69Client,
17    base_path: String,
18}
19
20impl<'a> LibraryFilesApi<'a> {
21    pub(super) fn new(client: &'a Context69Client, base_path: String) -> Self {
22        Self { client, base_path }
23    }
24
25    pub async fn upload(
26        &self,
27        folder_id: Option<Uuid>,
28        files: Vec<Part>,
29    ) -> Result<LibraryUploadResponse, Error> {
30        let path = format!("{}/files/upload", self.base_path);
31        self.client
32            .execute_json(
33                self.client
34                    .authorized_request(Method::POST, &path)
35                    .await?
36                    .multipart(file_upload_form(folder_id, files)),
37            )
38            .await
39    }
40
41    pub async fn prepare_upload(
42        &self,
43        request: &PrepareLibraryUploadRequest,
44    ) -> Result<PrepareLibraryUploadResponse, Error> {
45        let path = format!("{}/files/prepare-upload", self.base_path);
46        self.client
47            .execute_json(
48                self.client
49                    .authorized_request(Method::POST, &path)
50                    .await?
51                    .json(request),
52            )
53            .await
54    }
55
56    pub async fn upload_bytes_deduplicated(
57        &self,
58        folder_id: Option<Uuid>,
59        filename: impl Into<String>,
60        media_type: impl Into<String>,
61        bytes: Vec<u8>,
62    ) -> Result<LibraryUploadResponse, Error> {
63        self.upload_bytes_deduplicated_with_metadata(folder_id, filename, media_type, bytes, None)
64            .await
65    }
66
67    pub async fn upload_bytes_deduplicated_with_metadata(
68        &self,
69        folder_id: Option<Uuid>,
70        filename: impl Into<String>,
71        media_type: impl Into<String>,
72        bytes: Vec<u8>,
73        metadata: Option<LibraryFileUploadMetadata>,
74    ) -> Result<LibraryUploadResponse, Error> {
75        let filename = filename.into();
76        let media_type = media_type.into();
77        let sha256: String = Sha256::digest(&bytes)
78            .iter()
79            .map(|byte| format!("{byte:02x}"))
80            .collect();
81        let prepared = self
82            .prepare_upload(&PrepareLibraryUploadRequest {
83                folder_id,
84                filename: filename.clone(),
85                media_type: media_type.clone(),
86                size_bytes: bytes.len() as i64,
87                sha256: sha256.clone(),
88                metadata: metadata.clone(),
89            })
90            .await?;
91        if !prepared.upload_required {
92            return Ok(LibraryUploadResponse {
93                files: prepared.file.into_iter().collect(),
94                jobs: prepared.job.into_iter().collect(),
95            });
96        }
97
98        let part = Part::bytes(bytes)
99            .file_name(filename)
100            .mime_str(&media_type)?;
101        let path = format!("{}/files/upload", self.base_path);
102        self.client
103            .execute_json(
104                self.client
105                    .authorized_request(Method::POST, &path)
106                    .await?
107                    .multipart(file_upload_form_with_sha256(
108                        folder_id,
109                        sha256,
110                        metadata.as_ref(),
111                        part,
112                    )?),
113            )
114            .await
115    }
116}
117
118pub struct LibraryFileApi<'a> {
119    client: &'a Context69Client,
120    base_path: String,
121    file_id: Uuid,
122}
123
124impl<'a> LibraryFileApi<'a> {
125    pub(super) fn new(client: &'a Context69Client, base_path: String, file_id: Uuid) -> Self {
126        Self {
127            client,
128            base_path,
129            file_id,
130        }
131    }
132
133    pub async fn get(&self) -> Result<LibraryFileDetailResponse, Error> {
134        let path = format!("{}/files/{}", self.base_path, self.file_id);
135        self.client
136            .execute_json(self.client.authorized_request(Method::GET, &path).await?)
137            .await
138    }
139
140    pub async fn move_to(
141        &self,
142        request: &MoveFileRequest,
143    ) -> Result<LibraryFileDetailResponse, Error> {
144        let path = format!("{}/files/{}/move", self.base_path, self.file_id);
145        self.client
146            .execute_json(
147                self.client
148                    .authorized_request(Method::POST, &path)
149                    .await?
150                    .json(request),
151            )
152            .await
153    }
154
155    pub async fn delete(&self) -> Result<(), Error> {
156        let path = format!("{}/files/{}", self.base_path, self.file_id);
157        self.client
158            .execute_empty(
159                self.client
160                    .authorized_request(Method::DELETE, &path)
161                    .await?,
162            )
163            .await
164    }
165}