context69_sdk/client/library/
files.rs1use 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}