Skip to main content

context69_sdk/client/library/
files.rs

1use context69_contracts::{
2    LibraryFileDetailResponse, LibraryUploadResponse, MoveFileRequest, PrepareLibraryUploadRequest,
3    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        let filename = filename.into();
64        let media_type = media_type.into();
65        let sha256: String = Sha256::digest(&bytes)
66            .iter()
67            .map(|byte| format!("{byte:02x}"))
68            .collect();
69        let prepared = self
70            .prepare_upload(&PrepareLibraryUploadRequest {
71                folder_id,
72                filename: filename.clone(),
73                media_type: media_type.clone(),
74                size_bytes: bytes.len() as i64,
75                sha256: sha256.clone(),
76            })
77            .await?;
78        if !prepared.upload_required {
79            return Ok(LibraryUploadResponse {
80                files: prepared.file.into_iter().collect(),
81                jobs: prepared.job.into_iter().collect(),
82            });
83        }
84
85        let part = Part::bytes(bytes)
86            .file_name(filename)
87            .mime_str(&media_type)?;
88        let path = format!("{}/files/upload", self.base_path);
89        self.client
90            .execute_json(
91                self.client
92                    .authorized_request(Method::POST, &path)
93                    .await?
94                    .multipart(file_upload_form_with_sha256(folder_id, sha256, part)),
95            )
96            .await
97    }
98}
99
100pub struct LibraryFileApi<'a> {
101    client: &'a Context69Client,
102    base_path: String,
103    file_id: Uuid,
104}
105
106impl<'a> LibraryFileApi<'a> {
107    pub(super) fn new(client: &'a Context69Client, base_path: String, file_id: Uuid) -> Self {
108        Self {
109            client,
110            base_path,
111            file_id,
112        }
113    }
114
115    pub async fn get(&self) -> Result<LibraryFileDetailResponse, Error> {
116        let path = format!("{}/files/{}", self.base_path, self.file_id);
117        self.client
118            .execute_json(self.client.authorized_request(Method::GET, &path).await?)
119            .await
120    }
121
122    pub async fn move_to(
123        &self,
124        request: &MoveFileRequest,
125    ) -> Result<LibraryFileDetailResponse, Error> {
126        let path = format!("{}/files/{}/move", self.base_path, self.file_id);
127        self.client
128            .execute_json(
129                self.client
130                    .authorized_request(Method::POST, &path)
131                    .await?
132                    .json(request),
133            )
134            .await
135    }
136
137    pub async fn delete(&self) -> Result<(), Error> {
138        let path = format!("{}/files/{}", self.base_path, self.file_id);
139        self.client
140            .execute_empty(
141                self.client
142                    .authorized_request(Method::DELETE, &path)
143                    .await?,
144            )
145            .await
146    }
147}