From d84eceb8408762f320efabfc6b4db901c18f80a8 Mon Sep 17 00:00:00 2001 From: trivernis Date: Sat, 24 Jul 2021 19:06:42 +0200 Subject: [PATCH] Add wrapper for addresses to set and get cookies Signed-off-by: trivernis --- src/api_core/common.rs | 18 +++++++ src/wrapper/address.rs | 99 +++++++++++++++++++++++++++++++++++ src/wrapper/hydrus.rs | 6 +++ src/wrapper/mod.rs | 1 + src/wrapper/url.rs | 11 ++++ tests/wrapper/mod.rs | 1 + tests/wrapper/test_address.rs | 31 +++++++++++ 7 files changed, 167 insertions(+) create mode 100644 src/wrapper/address.rs create mode 100644 tests/wrapper/test_address.rs diff --git a/src/api_core/common.rs b/src/api_core/common.rs index 3a18ba5..a23f9cb 100644 --- a/src/api_core/common.rs +++ b/src/api_core/common.rs @@ -80,3 +80,21 @@ impl From for OptionalStringNumber { Self::String(value) } } + +impl OptionalStringNumber { + pub fn string(&self) -> Option<&str> { + if let Self::String(s) = &self { + Some(s) + } else { + None + } + } + + pub fn number(&self) -> Option { + if let Self::Number(n) = &self { + Some(*n) + } else { + None + } + } +} diff --git a/src/wrapper/address.rs b/src/wrapper/address.rs new file mode 100644 index 0000000..b3f13c7 --- /dev/null +++ b/src/wrapper/address.rs @@ -0,0 +1,99 @@ +use crate::api_core::common::OptionalStringNumber; +use crate::api_core::managing_cookies_and_http_headers::CookieBuilder; +use crate::error::Result; +use crate::Client; +use std::time::{Duration, SystemTime, UNIX_EPOCH}; + +pub struct Address { + client: Client, + domain: String, + path: String, +} + +impl Address { + pub(crate) fn from_str(client: Client, domain: &str) -> Self { + let (domain, path) = domain.split_once("/").unwrap_or((domain, "/")); + Self { + client, + domain: domain.to_string(), + path: path.to_string(), + } + } + + /// Returns the path after the domain name + pub fn path(&self) -> &str { + &self.path + } + + /// Sets the path of the domain that can be used for setting cookies + pub fn set_path(&mut self, path: S) { + self.path = path.to_string(); + } + + /// Sets cookies for the domain + pub async fn set_cookies(&self, cookies: Vec) -> Result<()> { + let cookies = cookies + .into_iter() + .map(|cookie| { + let mut builder = CookieBuilder::default() + .domain(&self.domain) + .path(&self.path) + .name(cookie.name) + .value(cookie.value); + if let Some(expires) = cookie.expires { + builder = + builder.expires(expires.duration_since(UNIX_EPOCH).unwrap().as_secs()); + } + builder.build() + }) + .collect(); + + self.client.set_cookies(cookies).await + } + + /// Returns all cookies stored for this domain + pub async fn get_cookies(&self) -> Result> { + let response = self.client.get_cookies(&self.domain).await?; + let cookies = response + .cookies + .into_iter() + .map(DomainCookie::from) + .collect(); + + Ok(cookies) + } +} + +#[derive(Clone, Debug)] +pub struct DomainCookie { + pub name: String, + pub value: String, + pub expires: Option, +} + +impl DomainCookie { + /// Creates a new cookie that will be expire after the given instant or only last for the session + pub fn new( + name: S1, + value: S2, + expires: Option, + ) -> Self { + Self { + name: name.to_string(), + value: value.to_string(), + expires, + } + } +} + +impl From<[OptionalStringNumber; 5]> for DomainCookie { + fn from(cookie_entry: [OptionalStringNumber; 5]) -> Self { + let name = cookie_entry[0].string().unwrap_or(""); + let value = cookie_entry[1].string().unwrap_or(""); + let expires = cookie_entry[4] + .number() + .map(|n| UNIX_EPOCH + Duration::from_secs(n)); + + Self::new(name, value, expires) + } +} diff --git a/src/wrapper/hydrus.rs b/src/wrapper/hydrus.rs index 33583b9..cc79b8c 100644 --- a/src/wrapper/hydrus.rs +++ b/src/wrapper/hydrus.rs @@ -2,6 +2,7 @@ use crate::api_core::common::FileIdentifier; use crate::api_core::searching_and_fetching_files::FileSearchLocation; use crate::error::Result; use crate::utils::tag_list_to_string_list; +use crate::wrapper::address::Address; use crate::wrapper::builders::import_builder::ImportBuilder; use crate::wrapper::builders::tagging_builder::TaggingBuilder; use crate::wrapper::hydrus_file::HydrusFile; @@ -47,6 +48,11 @@ impl Hydrus { } } + /// Returns the address as an object that can be used to get and set cookies + pub fn address>(&self, address: S) -> Address { + Address::from_str(self.client.clone(), address.as_ref()) + } + /// Returns information about a given url in an object that allows /// further operations with that url pub async fn url>(&self, url: S) -> Result { diff --git a/src/wrapper/mod.rs b/src/wrapper/mod.rs index 1b67080..32d5e62 100644 --- a/src/wrapper/mod.rs +++ b/src/wrapper/mod.rs @@ -1,3 +1,4 @@ +pub mod address; pub mod builders; pub mod hydrus; pub mod hydrus_file; diff --git a/src/wrapper/url.rs b/src/wrapper/url.rs index bd82056..dc7060f 100644 --- a/src/wrapper/url.rs +++ b/src/wrapper/url.rs @@ -2,6 +2,7 @@ use crate::api_core::adding_urls::{ URL_TYPE_FILE, URL_TYPE_GALLERY, URL_TYPE_POST, URL_TYPE_WATCHABLE, }; use crate::error::Result; +use crate::wrapper::address::Address; use crate::wrapper::builders::import_builder::UrlImportBuilder; use crate::wrapper::hydrus_file::HydrusFile; use crate::Client; @@ -59,6 +60,16 @@ impl Url { UrlImportBuilder::new(self.client.clone(), &self.url) } + /// Returns the address to manipulate cookies for this url + pub fn address(&self) -> Address { + let url = self + .normalised_url + .trim_start_matches("http://") + .trim_start_matches("https://"); + + Address::from_str(self.client.clone(), url) + } + /// Associates the url with a list of file hashes pub async fn associate(&mut self, hashes: Vec) -> Result<()> { self.client diff --git a/tests/wrapper/mod.rs b/tests/wrapper/mod.rs index 2133569..61e3aca 100644 --- a/tests/wrapper/mod.rs +++ b/tests/wrapper/mod.rs @@ -3,3 +3,4 @@ mod test_hydrus; mod test_import; mod test_url; mod test_page; +mod test_address; diff --git a/tests/wrapper/test_address.rs b/tests/wrapper/test_address.rs new file mode 100644 index 0000000..68b6f75 --- /dev/null +++ b/tests/wrapper/test_address.rs @@ -0,0 +1,31 @@ +use super::super::common; +use hydrus_api::wrapper::address::{Address, DomainCookie}; +use std::time::{Duration, SystemTime}; + +fn get_address() -> Address { + let hydrus = common::get_hydrus(); + + hydrus.address("trivernis.net/some/path") +} + +#[tokio::test] +async fn it_sets_cookies() { + let address = get_address(); + address + .set_cookies(vec![ + DomainCookie::new("name", "value", None), + DomainCookie::new( + "name2", + "value2", + Some(SystemTime::now() + Duration::from_secs(30)), + ), + ]) + .await + .unwrap(); +} + +#[tokio::test] +async fn it_retrieves_cookies() { + let address = get_address(); + address.get_cookies().await.unwrap(); +}