wall_rs/
source.rs

1use crate::config::Config;
2use crate::error::Error;
3use octocrab as Git;
4use octocrab::models::repos::Release;
5use octocrab::{Octocrab, Page};
6use reqwest::Client as Http;
7use std::io::Cursor;
8use std::sync::Arc;
9use std::{fs, io};
10
11static USER_AGENT: &str = concat!(env!("CARGO_PKG_NAME"), "/", env!("CARGO_PKG_VERSION"),);
12
13pub struct Source {
14    git: Arc<Octocrab>,
15    http: Http,
16}
17
18impl Source {
19    pub fn new(_config: Option<Config>) -> Self {
20        Self {
21            git: Git::instance(),
22            http: Http::builder().user_agent(USER_AGENT).build().unwrap(),
23        }
24    }
25
26    pub async fn get_versions(&self) -> Result<Page<Release>, Error> {
27        let releases = self
28            .git
29            .repos("akumarujon", "wall-rs-mirror")
30            .releases()
31            .list()
32            .send()
33            .await;
34
35        let releases = match releases {
36            Ok(r) => r,
37            Err(err) => return Err(Error::ReleaseFetchError(err)),
38        };
39
40        Ok(releases)
41    }
42
43    pub async fn get_latest_version(&self) -> Result<String, Error> {
44        let releases = self
45            .git
46            .repos("akumarujon", "wall-rs-mirror")
47            .releases()
48            .list()
49            .send()
50            .await;
51
52        let releases = match releases {
53            Ok(r) => r,
54            Err(err) => return Err(Error::ReleaseFetchError(err)),
55        };
56
57        let latest = match releases.items.first() {
58            Some(v) => v,
59            None => return Err(Error::NoVersionFound),
60        };
61
62        Ok(latest.tag_name.to_owned())
63    }
64
65    pub async fn download_file<T>(&self, url: T, dest: T) -> Result<(), Error>
66    where
67        T: ToString,
68    {
69        let response = match self.http.get(url.to_string()).send().await {
70            Ok(d) => d,
71            Err(_) => return Err(Error::NoInternetConnection),
72        };
73
74        let mut file = match std::fs::File::create(dest.to_string().clone()) {
75            Ok(f) => f,
76            Err(_) => return Err(Error::CantCreateDownloadedFile(dest.to_string())),
77        };
78
79        let mut content = Cursor::new(match response.bytes().await {
80            Ok(b) => b,
81            Err(_) => return Err(Error::CantCreateCursorBytes),
82        });
83
84        match std::io::copy(&mut content, &mut file) {
85            Ok(_) => {}
86            Err(_) => return Err(Error::CantCopyBytes),
87        };
88
89        Ok(())
90    }
91
92    pub fn extract_file<T>(&self, file: T) -> Result<(), Error>
93    where
94        T: AsRef<str>,
95    {
96        let fname = std::path::Path::new(file.as_ref());
97        let file = fs::File::open(fname).unwrap();
98
99        let mut archive = zip::ZipArchive::new(file).unwrap();
100
101        for i in 0..archive.len() {
102            let mut file = archive.by_index(i).unwrap();
103            let outpath = match file.enclosed_name() {
104                Some(path) => path.to_owned(),
105                None => continue,
106            };
107
108            {
109                let comment = file.comment();
110                if !comment.is_empty() {
111                    println!("File {i} comment: {comment}");
112                }
113            }
114
115            if (*file.name()).ends_with('/') {
116                println!("File {} extracted to \"{}\"", i, outpath.display());
117                fs::create_dir_all(&outpath).unwrap();
118            } else {
119                println!(
120                    "File {} extracted to \"{}\" ({} bytes)",
121                    i,
122                    outpath.display(),
123                    file.size()
124                );
125                if let Some(p) = outpath.parent() {
126                    if !p.exists() {
127                        fs::create_dir_all(p).unwrap();
128                    }
129                }
130                let mut outfile = fs::File::create(&outpath).unwrap();
131                io::copy(&mut file, &mut outfile).unwrap();
132            }
133
134            // Get and Set permissions
135            #[cfg(unix)]
136            {
137                use std::os::unix::fs::PermissionsExt;
138
139                if let Some(mode) = file.unix_mode() {
140                    fs::set_permissions(&outpath, fs::Permissions::from_mode(mode)).unwrap();
141                }
142            }
143        }
144
145        Ok(())
146    }
147}