artifactory_web_api/
lib.rs1use std::io::Write;
4use std::path::Path;
5
6use chrono::offset::FixedOffset;
7use chrono::DateTime;
8use serde_derive::*;
9use thiserror::Error;
10use url::Url;
11
12pub struct Client {
14 origin: String,
15}
16
17impl Client {
18 pub fn new<S: AsRef<str>>(origin: S) -> Self {
22 Self {
23 origin: origin.as_ref().to_string(),
24 }
25 }
26
27 pub async fn file_info(&self, path: ArtifactoryPath) -> Result<FileInfo, Error> {
29 let url = format!("{}/artifactory/api/storage/{}", self.origin, path.0);
30 let url = Url::parse(&url).unwrap();
31
32 let info: FileInfo = reqwest::get(url).await?.json().await?;
33
34 Ok(info)
35 }
36
37 pub async fn pull<F>(
42 &self,
43 path: ArtifactoryPath,
44 dest: &Path,
45 mut progress: F,
46 ) -> Result<(), Error>
47 where
48 F: FnMut(DownloadProgress),
49 {
50 let url = format!("{}/artifactory/{}", self.origin, path.0);
51 let url = Url::parse(&url).unwrap();
52
53 let mut dest = std::fs::File::create(dest)?;
54
55 let mut res = reqwest::get(url).await?;
56
57 let expected_bytes_downloaded = res.content_length().unwrap_or(0);
58 let mut bytes_downloaded = 0;
59 while let Some(chunk) = res.chunk().await? {
60 bytes_downloaded += chunk.as_ref().len() as u64;
61 dest.write_all(chunk.as_ref())?;
62 let status = DownloadProgress {
63 expected_bytes_downloaded,
64 bytes_downloaded,
65 };
66 progress(status);
67 }
68
69 Ok(())
70 }
71}
72
73pub struct ArtifactoryPath(String);
75
76impl<S: AsRef<str>> From<S> for ArtifactoryPath {
77 fn from(s: S) -> Self {
78 Self(s.as_ref().to_string())
79 }
80}
81
82#[derive(Debug, Deserialize)]
84#[serde(rename_all = "camelCase")]
85pub struct FileInfo {
86 uri: Url,
87 download_uri: Url,
88 repo: String,
89 path: String,
90 remote_url: Option<Url>,
91 created: DateTime<FixedOffset>,
92 created_by: String,
93 last_modified: DateTime<FixedOffset>,
94 modified_by: String,
95 last_updated: DateTime<FixedOffset>,
96 size: String,
97 mime_type: String,
98 pub checksums: Checksums,
99 original_checksums: OriginalChecksums,
100}
101
102#[derive(Debug, Deserialize)]
104pub struct Checksums {
105 #[serde(with = "hex")]
106 pub md5: Vec<u8>,
107 #[serde(with = "hex")]
108 pub sha1: Vec<u8>,
109 #[serde(with = "hex")]
110 pub sha256: Vec<u8>,
111}
112
113#[derive(Debug, Deserialize)]
115pub struct OriginalChecksums {
116 md5: Option<String>,
117 sha1: Option<String>,
118 sha256: Option<String>,
119}
120
121#[derive(Clone, Copy, Debug)]
122pub struct DownloadProgress {
123 pub expected_bytes_downloaded: u64,
124 pub bytes_downloaded: u64,
125}
126
127#[derive(Error, Debug)]
128pub enum Error {
129 #[error("An IO error occurred.")]
130 Io(#[from] std::io::Error),
131 #[error("A HTTP related error occurred.")]
132 Reqwest(#[from] reqwest::Error),
133}