move parsing into list_folders

This commit is contained in:
grimhilt 2023-06-17 01:20:00 +02:00
parent b911ad8606
commit ea2b0772af
2 changed files with 117 additions and 68 deletions

View File

@ -7,7 +7,7 @@ use clap::Values;
use regex::Regex; use regex::Regex;
use xml::reader::{EventReader, XmlEvent}; use xml::reader::{EventReader, XmlEvent};
use crate::services::api::ApiError; use crate::services::api::ApiError;
use crate::services::list_folders::ListFolders; use crate::services::list_folders::{ListFolders, FolderContent};
use crate::services::download_files::DownloadFiles; use crate::services::download_files::DownloadFiles;
use crate::store::object; use crate::store::object;
use crate::commands; use crate::commands;
@ -28,7 +28,7 @@ pub fn clone(remote: Values<'_>) {
} }
}; };
let local_path = match d.clone() { let ref_path = match d.clone() {
Some(dir) => Path::new(&dir).to_owned(), Some(dir) => Path::new(&dir).to_owned(),
None => { None => {
let iter = Path::new(dist_path_str).iter(); let iter = Path::new(dist_path_str).iter();
@ -53,16 +53,33 @@ pub fn clone(remote: Values<'_>) {
url_request.push_str(folder.as_str()); url_request.push_str(folder.as_str());
// request folder content // request folder content
let mut body = Default::default(); let mut objs = vec![];
tokio::runtime::Runtime::new().unwrap().block_on(async { tokio::runtime::Runtime::new().unwrap().block_on(async {
body = ListFolders::new(url_request.as_str()) let res = ListFolders::new(url_request.as_str())
.gethref()
.send_with_res() .send_with_res()
.await; .await;
objs = match res {
Ok(o) => o,
Err(ApiError::IncorrectRequest(err)) => {
eprintln!("fatal: {}", err.status());
std::process::exit(1);
},
Err(ApiError::EmptyError(_)) => {
eprintln!("Failed to get body");
vec![]
}
Err(ApiError::RequestError(err)) => {
eprintln!("fatal: {}", err);
std::process::exit(1);
},
Err(ApiError::Unexpected(_)) => todo!()
}
}); });
// create folder // create folder
if first_iter { if first_iter {
if DirBuilder::new().create(local_path.clone()).is_err() { if DirBuilder::new().create(ref_path.clone()).is_err() {
eprintln!("fatal: directory already exist"); eprintln!("fatal: directory already exist");
// destination path 'path' already exists and is not an empty directory. // destination path 'path' already exists and is not an empty directory.
//std::process::exit(1); //std::process::exit(1);
@ -71,56 +88,53 @@ pub fn clone(remote: Values<'_>) {
} }
} else { } else {
// create folder // create folder
let local_folder = get_local_path(folder, local_path.clone(), username, dist_path_str); let local_folder = get_local_path(folder, ref_path.clone(), username, dist_path_str);
if let Err(err) = DirBuilder::new().recursive(true).create(local_folder.clone()) { if let Err(err) = DirBuilder::new().recursive(true).create(local_folder.clone()) {
eprintln!("error: cannot create directory {}: {}", local_folder.display(), err); eprintln!("error: cannot create directory {}: {}", local_folder.display(), err);
} }
// add tree // add tree
let path_folder = local_folder.strip_prefix(local_path.clone()).unwrap(); let path_folder = local_folder.strip_prefix(ref_path.clone()).unwrap();
if object::add_tree(&path_folder).is_err() { if object::add_tree(&path_folder).is_err() {
eprintln!("error: cannot store object {}", path_folder.display()); eprintln!("error: cannot store object {}", path_folder.display());
} }
} }
// find folders and files in response // find folders and files in response
let objects = get_objects_xml(body); let mut iter = objs.iter();
let mut iter = objects.iter();
iter.next(); // jump first element which is the folder cloned iter.next(); // jump first element which is the folder cloned
for object in iter { for object in iter {
if object.chars().last().unwrap() == '/' { if object.href.clone().unwrap().chars().last().unwrap() == '/' {
folders.push(object.to_string()); folders.push(object.href.clone().unwrap().to_string());
} else { } else {
files.push(object.to_string()); files.push(object.href.clone().unwrap().to_string());
} }
} }
first_iter = false; first_iter = false;
} }
download_files(&domain, local_path.clone(), username, dist_path_str, files); download_files(ref_path.clone(), files);
} }
fn download_files(domain: &str, local_p: PathBuf, username: &str, dist_p: &str, files: Vec<String>) { fn download_files(local_p: PathBuf, files: Vec<String>) {
dbg!(local_p.clone()); for remote_file in files {
for dist_file in files {
dbg!(dist_file.clone());
tokio::runtime::Runtime::new().unwrap().block_on(async { tokio::runtime::Runtime::new().unwrap().block_on(async {
let res = DownloadFiles::new() let res = DownloadFiles::new()
.set_url_with_remote(dist_file.as_str()) .set_url_with_remote(remote_file.as_str())
.save(local_p.clone()).await; .save(local_p.clone()).await;
match res { match res {
Ok(()) => { Ok(()) => {
let s = &get_local_path_t(&dist_file.clone()); let s = &get_local_path_t(&remote_file.clone());
let ss = s.strip_prefix("/").unwrap(); let ss = s.strip_prefix("/").unwrap();
let relative_p = Path::new(ss); let relative_p = Path::new(ss);
if let Err(_) = object::add_blob(relative_p, "tmpdate") { if let Err(_) = object::add_blob(relative_p, "tmpdate") {
eprintln!("error saving reference of {}", dist_file.clone()); eprintln!("error saving reference of {}", remote_file.clone());
} }
}, },
Err(ApiError::Unexpected(_)) => { Err(ApiError::Unexpected(_)) => {
eprintln!("error writing {}", dist_file); eprintln!("error writing {}", remote_file);
}, },
Err(ApiError::IncorrectRequest(err)) => { Err(ApiError::IncorrectRequest(err)) => {
eprintln!("fatal: {}", err.status()); eprintln!("fatal: {}", err.status());
@ -136,36 +150,6 @@ fn download_files(domain: &str, local_p: PathBuf, username: &str, dist_p: &str,
} }
} }
fn get_objects_xml(xml: String) -> Vec<String> {
let cursor = Cursor::new(xml);
let parser = EventReader::new(cursor);
let mut should_get = false;
let mut objects: Vec<String> = vec![];
for event in parser {
match event {
Ok(XmlEvent::StartElement { name, .. }) => {
should_get = name.local_name == "href";
}
Ok(XmlEvent::Characters(text)) => {
if !text.trim().is_empty() && should_get {
objects.push(text);
}
}
Ok(XmlEvent::EndElement { .. }) => {
should_get = false;
}
Err(e) => {
eprintln!("Error: {}", e);
break;
}
_ => {}
}
}
objects
}
fn get_url_props(url: &str) -> (String, Option<&str>, &str) { fn get_url_props(url: &str) -> (String, Option<&str>, &str) {
let mut username = None; let mut username = None;
let mut domain = ""; let mut domain = "";
@ -241,4 +225,3 @@ mod tests {
assert_eq!(get_url_props("nextcloud.example.com/foo/bar"), (sld.clone(), None, p)); assert_eq!(get_url_props("nextcloud.example.com/foo/bar"), (sld.clone(), None, p));
} }
} }

View File

@ -1,8 +1,31 @@
use crate::services::api::{ApiBuilder, ApiError}; use crate::services::api::{ApiBuilder, ApiError};
use xml::reader::{EventReader, XmlEvent};
use std::io::Cursor;
use reqwest::{Method, IntoUrl, Response, Error}; use reqwest::{Method, IntoUrl, Response, Error};
pub struct FolderContent {
pub href: Option<String>,
}
impl Clone for FolderContent {
fn clone(&self) -> Self {
FolderContent {
href: self.href.clone(),
}
}
}
impl FolderContent {
fn new() -> Self {
FolderContent {
href: None,
}
}
}
pub struct ListFolders { pub struct ListFolders {
api_builder: ApiBuilder, api_builder: ApiBuilder,
xml_balises: Vec<String>,
} }
impl ListFolders { impl ListFolders {
@ -10,14 +33,20 @@ impl ListFolders {
ListFolders { ListFolders {
api_builder: ApiBuilder::new() api_builder: ApiBuilder::new()
.set_request(Method::from_bytes(b"PROPFIND").unwrap(), url), .set_request(Method::from_bytes(b"PROPFIND").unwrap(), url),
xml_balises: vec![],
} }
} }
pub fn gethref(&mut self) -> &mut ListFolders {
self.xml_balises.push(String::from("href"));
self
}
pub async fn send(&mut self) -> Result<Response, Error> { pub async fn send(&mut self) -> Result<Response, Error> {
self.api_builder.send().await self.api_builder.send().await
} }
pub async fn send_with_err(mut self) -> Result<String, ApiError> { pub async fn send_with_err(&mut self) -> Result<String, ApiError> {
let res = self.send().await.map_err(ApiError::RequestError)?; let res = self.send().await.map_err(ApiError::RequestError)?;
if res.status().is_success() { if res.status().is_success() {
let body = res.text().await.map_err(ApiError::EmptyError)?; let body = res.text().await.map_err(ApiError::EmptyError)?;
@ -27,22 +56,59 @@ impl ListFolders {
} }
} }
pub async fn send_with_res(self) -> String { pub async fn send_with_res(&mut self) -> Result<Vec<FolderContent>, ApiError> {
match self.send_with_err().await { match self.send_with_err().await {
Ok(body) => body, Ok(body) => Ok(self.parse(body)),
Err(ApiError::IncorrectRequest(err)) => { Err(err) => Err(err),
eprintln!("fatal: {}", err.status());
std::process::exit(1);
},
Err(ApiError::EmptyError(_)) => {
eprintln!("Failed to get body");
String::from("")
} }
Err(ApiError::RequestError(err)) => { }
eprintln!("fatal: {}", err);
std::process::exit(1); pub fn parse(&self, xml: String) -> Vec<FolderContent> {
}, let cursor = Cursor::new(xml);
_ => todo!(), let parser = EventReader::new(cursor);
let mut should_get = false;
let mut values: Vec<FolderContent> = vec![];
let mut iter = self.xml_balises.iter();
let mut val = iter.next();
let mut content = FolderContent::new();
for event in parser {
match event {
Ok(XmlEvent::StartElement { name, .. }) => {
if let Some(v) = val.clone() {
should_get = &name.local_name == v;
} else {
// end of balises to get then start over for next object
values.push(content.clone());
iter = self.xml_balises.iter();
val = iter.next();
content = FolderContent::new();
if let Some(v) = val.clone() {
should_get = &name.local_name == v;
} }
} }
} }
Ok(XmlEvent::Characters(text)) => {
if !text.trim().is_empty() && should_get {
match val.unwrap().as_str() {
"href" => content.href = Some(text),
_ => (),
}
val = iter.next()
}
}
Ok(XmlEvent::EndElement { .. }) => {
should_get = false;
}
Err(e) => {
eprintln!("Error: {}", e);
break;
}
_ => {}
}
}
values
}
}