internetarchive_rs/
client_uploader_traits_impl.rs1use std::future::Future;
2use std::path::Path;
3
4use client_uploader_traits::{
5 ClientContext, CreatePublication, CreatePublicationRequest, DownloadNamedPublicFile,
6 ExistingFileConflictPolicy, ExistingFileConflictPolicyKind, ListResourceFiles,
7 MaybeAuthenticatedClient, PublicationOutcome, ReadPublicResource, RepositoryFile,
8 RepositoryRecord, SearchPublicResources, SearchResultsLike, UpdatePublication,
9 UpdatePublicationRequest, UploadSourceKind, UploadSpecLike,
10};
11
12use crate::downloads::ResolvedDownload;
13use crate::endpoint::Endpoint;
14use crate::error::InternetArchiveError;
15use crate::metadata::ItemMetadata;
16use crate::model::{Item, ItemFile, SearchDocument, SearchResponse, SearchResultPage};
17use crate::poll::PollOptions;
18use crate::search::SearchQuery;
19use crate::upload::{FileConflictPolicy, UploadSource, UploadSpec};
20use crate::workflow::{PublishOutcome, PublishRequest};
21use crate::{InternetArchiveClient, ItemIdentifier};
22
23fn into_create_publish_request(
24 request: CreatePublicationRequest<ItemIdentifier, ItemMetadata, UploadSpec>,
25) -> PublishRequest {
26 PublishRequest::new(request.target, request.metadata, request.uploads)
27}
28
29fn into_update_publish_request(
30 request: UpdatePublicationRequest<ItemIdentifier, ItemMetadata, FileConflictPolicy, UploadSpec>,
31) -> PublishRequest {
32 let mut publish_request =
33 PublishRequest::new(request.resource_id, request.metadata, request.uploads);
34 publish_request.conflict_policy = request.policy;
35 publish_request
36}
37
38impl ClientContext for InternetArchiveClient {
39 type Endpoint = Endpoint;
40 type PollOptions = PollOptions;
41 type Error = InternetArchiveError;
42
43 fn endpoint(&self) -> &Self::Endpoint {
44 self.endpoint()
45 }
46
47 fn poll_options(&self) -> &Self::PollOptions {
48 self.poll_options()
49 }
50
51 fn request_timeout(&self) -> Option<std::time::Duration> {
52 self.request_timeout()
53 }
54
55 fn connect_timeout(&self) -> Option<std::time::Duration> {
56 self.connect_timeout()
57 }
58}
59
60impl MaybeAuthenticatedClient for InternetArchiveClient {
61 fn has_auth(&self) -> bool {
62 self.has_auth()
63 }
64}
65
66impl UploadSpecLike for UploadSpec {
67 fn filename(&self) -> &str {
68 &self.filename
69 }
70
71 fn source_kind(&self) -> UploadSourceKind {
72 match &self.source {
73 UploadSource::Path(_) => UploadSourceKind::Path,
74 UploadSource::Bytes(_) => UploadSourceKind::Bytes,
75 }
76 }
77
78 fn content_length(&self) -> Option<u64> {
79 match &self.source {
80 UploadSource::Path(path) => std::fs::metadata(path).ok().map(|metadata| metadata.len()),
81 UploadSource::Bytes(bytes) => u64::try_from(bytes.len()).ok(),
82 }
83 }
84
85 fn content_type(&self) -> Option<&str> {
86 Some(self.content_type.as_ref())
87 }
88}
89
90impl RepositoryFile for ItemFile {
91 type Id = String;
92
93 fn file_id(&self) -> Option<Self::Id> {
94 None
95 }
96
97 fn file_name(&self) -> &str {
98 &self.name
99 }
100
101 fn size_bytes(&self) -> Option<u64> {
102 self.size
103 }
104
105 fn checksum(&self) -> Option<&str> {
106 self.md5
107 .as_deref()
108 .or(self.sha1.as_deref())
109 .or(self.crc32.as_deref())
110 }
111}
112
113impl RepositoryRecord for Item {
114 type Id = ItemIdentifier;
115 type File = ItemFile;
116
117 fn resource_id(&self) -> Option<Self::Id> {
118 self.identifier()
119 }
120
121 fn title(&self) -> Option<&str> {
122 self.metadata.title()
123 }
124
125 fn files(&self) -> &[Self::File] {
126 &self.files
127 }
128}
129
130impl SearchResultsLike for SearchResultPage {
131 type Item = SearchDocument;
132
133 fn items(&self) -> &[Self::Item] {
134 &self.docs
135 }
136
137 fn total_hits(&self) -> Option<u64> {
138 Some(self.num_found)
139 }
140}
141
142impl SearchResultsLike for SearchResponse {
143 type Item = SearchDocument;
144
145 fn items(&self) -> &[Self::Item] {
146 &self.response.docs
147 }
148
149 fn total_hits(&self) -> Option<u64> {
150 Some(self.response.num_found)
151 }
152}
153
154impl PublicationOutcome for PublishOutcome {
155 type PublicResource = Item;
156
157 fn public_resource(&self) -> &Self::PublicResource {
158 &self.item
159 }
160
161 fn created(&self) -> Option<bool> {
162 Some(self.created)
163 }
164}
165
166impl ExistingFileConflictPolicy for FileConflictPolicy {
167 fn kind(&self) -> ExistingFileConflictPolicyKind {
168 match self {
169 Self::Error => ExistingFileConflictPolicyKind::Error,
170 Self::Skip => ExistingFileConflictPolicyKind::Skip,
171 Self::Overwrite => ExistingFileConflictPolicyKind::Overwrite,
172 Self::OverwriteKeepingHistory => {
173 ExistingFileConflictPolicyKind::OverwriteKeepingHistory
174 }
175 }
176 }
177}
178
179impl ReadPublicResource for InternetArchiveClient {
180 type ResourceId = ItemIdentifier;
181 type Resource = Item;
182
183 fn get_public_resource(
184 &self,
185 id: &Self::ResourceId,
186 ) -> impl Future<Output = Result<Self::Resource, Self::Error>> {
187 self.get_item(id)
188 }
189}
190
191impl SearchPublicResources for InternetArchiveClient {
192 type Query = SearchQuery;
193 type SearchResults = SearchResponse;
194
195 fn search_public_resources(
196 &self,
197 query: &Self::Query,
198 ) -> impl Future<Output = Result<Self::SearchResults, Self::Error>> {
199 self.search(query)
200 }
201}
202
203impl ListResourceFiles for InternetArchiveClient {
204 type ResourceId = ItemIdentifier;
205 type File = ItemFile;
206
207 async fn list_resource_files(
208 &self,
209 id: &Self::ResourceId,
210 ) -> Result<Vec<Self::File>, Self::Error> {
211 Ok(self.get_item(id).await?.files)
212 }
213}
214
215impl DownloadNamedPublicFile for InternetArchiveClient {
216 type ResourceId = ItemIdentifier;
217 type Download = ResolvedDownload;
218
219 async fn download_named_public_file_to_path(
220 &self,
221 id: &Self::ResourceId,
222 name: &str,
223 path: &Path,
224 ) -> Result<Self::Download, Self::Error> {
225 self.download_to_path(id, name, path).await?;
226 self.resolve_download(id, name)
227 }
228}
229
230impl CreatePublication for InternetArchiveClient {
231 type CreateTarget = ItemIdentifier;
232 type Metadata = ItemMetadata;
233 type Upload = UploadSpec;
234 type Output = PublishOutcome;
235
236 fn create_publication(
237 &self,
238 request: CreatePublicationRequest<Self::CreateTarget, Self::Metadata, Self::Upload>,
239 ) -> impl Future<Output = Result<Self::Output, Self::Error>> {
240 self.publish_item(into_create_publish_request(request))
241 }
242}
243
244impl UpdatePublication for InternetArchiveClient {
245 type ResourceId = ItemIdentifier;
246 type Metadata = ItemMetadata;
247 type FilePolicy = FileConflictPolicy;
248 type Upload = UploadSpec;
249 type Output = PublishOutcome;
250
251 fn update_publication(
252 &self,
253 request: UpdatePublicationRequest<
254 Self::ResourceId,
255 Self::Metadata,
256 Self::FilePolicy,
257 Self::Upload,
258 >,
259 ) -> impl Future<Output = Result<Self::Output, Self::Error>> {
260 self.upsert_item(into_update_publish_request(request))
261 }
262}