From adac2e6cda90006c5c3730a17369b111ca55de46 Mon Sep 17 00:00:00 2001 From: grimhilt Date: Sun, 15 Sep 2024 21:26:49 +0200 Subject: [PATCH] feat(enumerator): started enumerator and improved service --- src/services/downloader.rs | 0 src/services/enumerator.rs | 91 ++++++++++++++++++++++++++++++++++++++ src/services/req_props.rs | 63 ++++++++++++-------------- src/services/service.rs | 68 +++++++++++++++++----------- 4 files changed, 162 insertions(+), 60 deletions(-) create mode 100644 src/services/downloader.rs create mode 100644 src/services/enumerator.rs diff --git a/src/services/downloader.rs b/src/services/downloader.rs new file mode 100644 index 0000000..e69de29 diff --git a/src/services/enumerator.rs b/src/services/enumerator.rs new file mode 100644 index 0000000..102f02c --- /dev/null +++ b/src/services/enumerator.rs @@ -0,0 +1,91 @@ +use super::{ + req_props::{Props, ReqProps, Response}, + service::Service, +}; +use std::sync::Arc; +use tokio::sync::Mutex; + +pub const DEFAULT_DEPTH: usize = 3; + +pub struct Enumerator<'a> { + service: &'a Service, + path: String, + depth: usize, + properties: Vec, +} + +impl<'a> Enumerator<'a> { + pub fn new(service: &'a Service) -> Self { + Enumerator { + service, + path: String::new(), + depth: DEFAULT_DEPTH, + properties: Vec::new(), + } + } + + pub fn set_path(mut self, path: String) -> Self { + self.path = path; + self + } + + pub fn set_depth(mut self, depth: usize) -> Self { + self.depth = depth; + self + } + + pub fn get_properties(mut self, properties: Vec) -> Self { + self.properties.extend(properties); + self + } + + pub async fn enumerate(&self) -> Result<(Vec, Vec), std::io::Error> { + let (tx, mut rx) = tokio::sync::mpsc::unbounded_channel(); + let files = Arc::new(Mutex::new(Vec::new())); + let folders = Arc::new(Mutex::new(Vec::new())); + let service = Arc::from(self.service.clone()); + + tx.send(self.path.clone()); + + let mut handles = vec![]; + + while let Some(path) = rx.recv().await { + let tx_clone = tx.clone(); + let files_clone = Arc::clone(&files); + let folders_clone = Arc::clone(&folders); + let service_clone = Arc::clone(&service); + let properties = self.properties.clone(); + + let handle = tokio::task::spawn_blocking(move || async move { + let res = ReqProps::new(&service_clone) + .set_path(path) + // .set_depth(self.depth) + .get_properties(properties) + .send() + .await + .unwrap(); + + for obj in res.responses { + if obj.is_dir() { + todo!("Deal to have good href"); + tx_clone.send(obj.href.clone()); + folders_clone.lock().await.push(obj); + } else { + files_clone.lock().await.push(obj); + } + } + }); + handles.push(handle); + } + + // Wait for all tasks to complete + for handle in handles { + handle.await; + } + + Ok(( + Arc::try_unwrap(files).unwrap().into_inner(), + Arc::try_unwrap(folders).unwrap().into_inner(), + )) + } +} diff --git a/src/services/req_props.rs b/src/services/req_props.rs index e6eacfe..76ce6c0 100644 --- a/src/services/req_props.rs +++ b/src/services/req_props.rs @@ -1,9 +1,9 @@ -use crate::services::service::Service; +use crate::services::service::{Request, Service}; use crate::store::object::Obj; -use crate::config::config::Config; use serde::Deserialize; use serde_xml_rs::from_str; +#[derive(Clone)] pub enum Props { CreationDate, LastModified, @@ -25,7 +25,6 @@ pub enum Props { ContainedFileCountm, } - #[derive(Deserialize, Debug)] struct Propstat { #[serde(rename = "prop")] @@ -41,19 +40,24 @@ struct Prop { } #[derive(Deserialize, Debug)] -struct Response { +pub struct Response { #[serde(rename = "href")] - href: String, + pub href: String, #[serde(rename = "propstat")] propstat: Propstat, } -#[derive(Deserialize, Debug)] -struct Multistatus { - #[serde(rename = "response")] - responses: Vec, +impl Response { + pub fn is_dir(&self) -> bool { + todo!("is dir reponse") + } } +#[derive(Deserialize, Debug)] +pub struct Multistatus { + #[serde(rename = "response")] + pub responses: Vec, +} impl From<&Props> for &str { fn from(variant: &Props) -> Self { @@ -65,23 +69,21 @@ impl From<&Props> for &str { } } -pub struct ReqProps { - service: Service, +pub struct ReqProps<'a> { + request: Request<'a>, properties: Vec, } -impl ReqProps { - pub fn new(path: &str) -> Self { - let mut service = Service::new(); - service.propfind(path.to_owned()); +impl<'a> ReqProps<'a> { + pub fn new(service: &'a Service) -> Self { ReqProps { - service, + request: Request::new(service), properties: Vec::new(), } } - pub fn set_config(mut self, config: &Config) -> Self { - self.service.set_config(config.clone()); + pub fn set_path(mut self, path: String) -> Self { + self.request.propfind(path); self } @@ -105,23 +107,16 @@ impl ReqProps { xml } - pub async fn send(&mut self) { - dbg!("send"); - let res = self.service.send().await; - dbg!("Sent"); - let text = res.unwrap().text().await.unwrap(); - self.parse(&text); - } - - fn parse (&self, xml: &str) { - dbg!("Parsing"); + pub async fn send(&mut self) -> Result { + let res = self.request.send().await; + let xml = res.unwrap().text().await?; let multistatus: Multistatus = from_str(&xml).unwrap(); - dbg!(multistatus); + Ok(multistatus) } } -impl From for ReqProps { - fn from(obj: Obj) -> Self { - ReqProps::new(obj.get_obj_path().to_str().unwrap()) - } -} +// impl From for ReqProps<'_> { +// fn from(obj: Obj) -> Self { +// ReqProps::new(obj.get_obj_path().to_str().unwrap()) +// } +// } diff --git a/src/services/service.rs b/src/services/service.rs index 7d104cc..26e5dc9 100644 --- a/src/services/service.rs +++ b/src/services/service.rs @@ -1,6 +1,6 @@ -use crate::config::config::Config; -use reqwest::{Client, ClientBuilder}; +use crate::commands::clone::UrlProps; use reqwest::{header::HeaderMap, Method, Url}; +use reqwest::{Client, ClientBuilder}; const USER_AGENT: &str = "Nextsync"; @@ -34,20 +34,39 @@ impl ClientConfig { } } +#[derive(Clone)] pub struct Service { + url_base: String, +} + +impl From<&UrlProps<'_>> for Service { + fn from(url_props: &UrlProps) -> Self { + todo!("Auth"); + let mut url_base = if url_props.is_secure { + String::from("https://") + } else { + String::from("http://") + }; + url_base.push_str(url_props.domain); + + Service { url_base } + } +} + +pub struct Request<'a> { + service: &'a Service, client: ClientConfig, - config: Option, method: Option, url: Option, headers: HeaderMap, body: Option, } -impl Service { - pub fn new() -> Self { - Service { +impl<'a> Request<'a> { + pub fn new(service: &'a Service) -> Self { + Request { + service, client: ClientConfig::new(), - config: None, method: None, url: None, headers: HeaderMap::new(), @@ -55,10 +74,6 @@ impl Service { } } - pub fn set_config(&mut self, config: Config) { - self.config = Some(config); - } - pub fn propfind(&mut self, url: String) -> &mut Self { self.method = Some(Method::from_bytes(b"PROPFIND").expect("Cannot be invalid")); self.url = Some(url); @@ -66,21 +81,22 @@ impl Service { } pub async fn send(&mut self) -> Result { - let mut url = self - .config - .clone() - .expect("A config must be provided to service") - .get_nsconfig() - .get_remote("origin") - .url - .expect("An url must be set on the remote"); - url.push_str(&self.url.clone().unwrap()); + todo!() + // let mut url = self + // .config + // .clone() + // .expect("A config must be provided to service") + // .get_nsconfig() + // .get_remote("origin") + // .url + // .expect("An url must be set on the remote"); + // url.push_str(&self.url.clone().unwrap()); - self.client - .build() - .request(self.method.clone().expect("Method must be set"), url) - .bearer_auth("rK5ud2NmrR8p586Th7v272HRgUcZcEKIEluOGjzQQRj7gWMMAISFTiJcFnnmnNiu2VVlENks") - .send() - .await + // self.client + // .build() + // .request(self.method.clone().expect("Method must be set"), url) + // .bearer_auth("rK5ud2NmrR8p586Th7v272HRgUcZcEKIEluOGjzQQRj7gWMMAISFTiJcFnnmnNiu2VVlENks") + // .send() + // .await } }