nextsync-rust/src/services/download_files.rs
2023-07-14 15:33:44 +02:00

96 lines
3.2 KiB
Rust

use std::path::PathBuf;
use futures_util::StreamExt;
use std::fs::File;
use std::fs::OpenOptions;
use std::io::{self, Write};
use reqwest::{Method, Response, Error};
use crate::utils::api::ApiProps;
use crate::services::api::{ApiBuilder, ApiError};
pub struct DownloadFiles {
api_builder: ApiBuilder,
relative_ps: String,
}
impl DownloadFiles {
pub fn new() -> Self {
DownloadFiles {
api_builder: ApiBuilder::new(),
relative_ps: String::from(""),
}
}
pub fn set_url(&mut self, relative_ps: &str, api_props: &ApiProps) -> &mut DownloadFiles {
self.relative_ps = relative_ps.to_string();
self.api_builder.set_req(Method::GET, relative_ps, api_props);
self
}
pub async fn send(&mut self) -> Result<Response, Error> {
self.api_builder.send().await
}
pub async fn _send_with_err(mut self) -> Result<Vec<u8>, ApiError> {
let res = self.send().await.map_err(ApiError::RequestError)?;
if res.status().is_success() {
let body = res.bytes().await.map_err(ApiError::EmptyError)?;
Ok(body.to_vec())
} else {
Err(ApiError::IncorrectRequest(res))
}
}
pub fn save_stream(&mut self, ref_p: PathBuf, callback: Option<impl Fn(u64)>) -> Result<(), ApiError> {
let abs_p = ref_p.join(PathBuf::from(self.relative_ps.clone()));
let mut file = File::create(abs_p).unwrap();
tokio::runtime::Runtime::new().unwrap().block_on(async {
let res = self.send().await.map_err(ApiError::RequestError)?;
if res.status().is_success() {
let mut stream = res.bytes_stream();
while let Some(chunk) = stream.next().await {
let unwrap_chunk = chunk.unwrap();
// save chunk inside file
if let Err(err) = file.write_all(&unwrap_chunk) {
return Err(ApiError::Unexpected(err.to_string()));
} else if let Some(fct) = &callback {
// call callback with size of this chunk
fct(unwrap_chunk.len().try_into().unwrap());
}
}
Ok(())
} else {
Err(ApiError::IncorrectRequest(res))
}
})
}
pub fn save(&mut self, ref_p: PathBuf) -> Result<(), ApiError> {
tokio::runtime::Runtime::new().unwrap().block_on(async {
let p = ref_p.join(PathBuf::from(self.relative_ps.clone()));
let res = self.send().await.map_err(ApiError::RequestError)?;
if res.status().is_success() {
let body = res.bytes().await.map_err(ApiError::EmptyError)?;
match Self::write_file(p, &body.to_vec()) {
Err(_) => Err(ApiError::Unexpected(String::from(""))),
Ok(_) => Ok(()),
}
} else {
Err(ApiError::IncorrectRequest(res))
}
})
}
fn write_file(path: PathBuf, content: &Vec<u8>) -> io::Result<()> {
let mut f = OpenOptions::new()
.write(true)
.create(true)
.open(path.clone())?;
f.write_all(&content)?;
Ok(())
}
}