From ea2b0772af5c3a269ecc95b45c5ced742a0690d7 Mon Sep 17 00:00:00 2001 From: grimhilt Date: Sat, 17 Jun 2023 01:20:00 +0200 Subject: [PATCH] move parsing into list_folders --- src/commands/clone.rs | 87 +++++++++++++------------------- src/services/list_folders.rs | 98 ++++++++++++++++++++++++++++++------ 2 files changed, 117 insertions(+), 68 deletions(-) diff --git a/src/commands/clone.rs b/src/commands/clone.rs index 3ea27cb..3da901c 100644 --- a/src/commands/clone.rs +++ b/src/commands/clone.rs @@ -7,7 +7,7 @@ use clap::Values; use regex::Regex; use xml::reader::{EventReader, XmlEvent}; 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::store::object; 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(), None => { let iter = Path::new(dist_path_str).iter(); @@ -53,16 +53,33 @@ pub fn clone(remote: Values<'_>) { url_request.push_str(folder.as_str()); // request folder content - let mut body = Default::default(); + let mut objs = vec![]; 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() .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 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"); // destination path 'path' already exists and is not an empty directory. //std::process::exit(1); @@ -71,56 +88,53 @@ pub fn clone(remote: Values<'_>) { } } else { // 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()) { eprintln!("error: cannot create directory {}: {}", local_folder.display(), err); } // 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() { eprintln!("error: cannot store object {}", path_folder.display()); } } // find folders and files in response - let objects = get_objects_xml(body); - let mut iter = objects.iter(); + let mut iter = objs.iter(); iter.next(); // jump first element which is the folder cloned for object in iter { - if object.chars().last().unwrap() == '/' { - folders.push(object.to_string()); + if object.href.clone().unwrap().chars().last().unwrap() == '/' { + folders.push(object.href.clone().unwrap().to_string()); } else { - files.push(object.to_string()); + files.push(object.href.clone().unwrap().to_string()); } } 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) { - dbg!(local_p.clone()); - for dist_file in files { - dbg!(dist_file.clone()); +fn download_files(local_p: PathBuf, files: Vec) { + for remote_file in files { tokio::runtime::Runtime::new().unwrap().block_on(async { 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; match res { 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 relative_p = Path::new(ss); 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(_)) => { - eprintln!("error writing {}", dist_file); + eprintln!("error writing {}", remote_file); }, Err(ApiError::IncorrectRequest(err)) => { 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 { - let cursor = Cursor::new(xml); - let parser = EventReader::new(cursor); - - let mut should_get = false; - let mut objects: Vec = 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) { let mut username = None; let mut domain = ""; @@ -241,4 +225,3 @@ mod tests { assert_eq!(get_url_props("nextcloud.example.com/foo/bar"), (sld.clone(), None, p)); } } - diff --git a/src/services/list_folders.rs b/src/services/list_folders.rs index 5764fb5..ff8dc63 100644 --- a/src/services/list_folders.rs +++ b/src/services/list_folders.rs @@ -1,8 +1,31 @@ use crate::services::api::{ApiBuilder, ApiError}; +use xml::reader::{EventReader, XmlEvent}; +use std::io::Cursor; use reqwest::{Method, IntoUrl, Response, Error}; +pub struct FolderContent { + pub href: Option, +} + +impl Clone for FolderContent { + fn clone(&self) -> Self { + FolderContent { + href: self.href.clone(), + } + } +} + +impl FolderContent { + fn new() -> Self { + FolderContent { + href: None, + } + } +} + pub struct ListFolders { api_builder: ApiBuilder, + xml_balises: Vec, } impl ListFolders { @@ -10,14 +33,20 @@ impl ListFolders { ListFolders { api_builder: ApiBuilder::new() .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 { self.api_builder.send().await } - pub async fn send_with_err(mut self) -> Result { + pub async fn send_with_err(&mut self) -> Result { let res = self.send().await.map_err(ApiError::RequestError)?; if res.status().is_success() { 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, ApiError> { match self.send_with_err().await { - Ok(body) => body, - Err(ApiError::IncorrectRequest(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); - }, - _ => todo!(), + Ok(body) => Ok(self.parse(body)), + Err(err) => Err(err), } } + + pub fn parse(&self, xml: String) -> Vec { + let cursor = Cursor::new(xml); + let parser = EventReader::new(cursor); + + let mut should_get = false; + let mut values: Vec = 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 + } }