Add hydrus wrapper with services and version info

Signed-off-by: trivernis <trivernis@protonmail.com>
pull/1/head
trivernis 3 years ago
parent 21cd993416
commit ef8d998efb
Signed by: Trivernis
GPG Key ID: DFFFCC2C7A02DB45

@ -25,6 +25,7 @@ use serde::Serialize;
static ACCESS_KEY_HEADER: &str = "Hydrus-Client-API-Access-Key"; static ACCESS_KEY_HEADER: &str = "Hydrus-Client-API-Access-Key";
#[derive(Clone)]
pub struct Client { pub struct Client {
inner: reqwest::Client, inner: reqwest::Client,
base_url: String, base_url: String,

@ -2,6 +2,15 @@ use crate::endpoints::common::BasicServiceInfo;
use crate::endpoints::Endpoint; use crate::endpoints::Endpoint;
use std::collections::HashMap; use std::collections::HashMap;
pub static SERVICE_TYPE_LOCAL_TAGS: &str = "local_tags";
pub static SERVICE_TYPE_TAG_REPOSITORIES: &str = "tag_repositories";
pub static SERVICE_TYPE_LOCAL_FILES: &str = "local_files";
pub static SERVICE_TYPE_FILE_REPOSITORIES: &str = "file_repositories";
pub static SERVICE_TYPE_ALL_LOCAL_FILES: &str = "all_local_files";
pub static SERVICE_TYPE_ALL_KNOWN_FILES: &str = "all_known_files";
pub static SERVICE_TYPE_ALL_KNOWN_TAGS: &str = "all_known_tags";
pub static SERVICE_TYPE_TRASH: &str = "trash";
#[derive(Debug, Clone, Deserialize)] #[derive(Debug, Clone, Deserialize)]
pub struct ApiVersionResponse { pub struct ApiVersionResponse {
pub version: u32, pub version: u32,

@ -7,6 +7,7 @@ pub type Result<T> = std::result::Result<T, Error>;
pub enum Error { pub enum Error {
Reqwest(reqwest::Error), Reqwest(reqwest::Error),
Hydrus(String), Hydrus(String),
InvalidServiceType(String),
} }
impl fmt::Display for Error { impl fmt::Display for Error {
@ -14,6 +15,9 @@ impl fmt::Display for Error {
match self { match self {
Self::Reqwest(e) => e.fmt(f), Self::Reqwest(e) => e.fmt(f),
Self::Hydrus(msg) => msg.fmt(f), Self::Hydrus(msg) => msg.fmt(f),
Self::InvalidServiceType(service_type) => {
write!(f, "Invalid Service Type '{}'", service_type)
}
} }
} }
} }
@ -23,6 +27,7 @@ impl StdError for Error {
match self { match self {
Self::Reqwest(e) => e.source(), Self::Reqwest(e) => e.source(),
Self::Hydrus(_) => None, Self::Hydrus(_) => None,
Self::InvalidServiceType(_) => None,
} }
} }
} }

@ -37,6 +37,9 @@ extern crate serde;
pub mod client; pub mod client;
pub mod endpoints; pub mod endpoints;
pub mod error; pub mod error;
mod models;
pub(crate) mod utils; pub(crate) mod utils;
pub use client::Client; pub use client::Client;
pub use models::hydrus::Hydrus;
pub use models::*;

@ -0,0 +1,31 @@
use crate::error::Result;
use crate::models::version::Version;
use crate::service::Services;
use crate::Client;
pub struct Hydrus {
client: Client,
}
impl Hydrus {
/// Creates a new high level Hydrus API client
pub fn new(client: Client) -> Self {
Self { client }
}
/// Returns the Hydrus and API Version
pub async fn version(&mut self) -> Result<Version> {
let response = self.client.api_version().await?;
Ok(Version {
api: response.version,
hydrus: response.hydrus_version,
})
}
/// Returns a list of available services
pub async fn services(&mut self) -> Result<Services> {
let response = self.client.get_services().await?;
Ok(Services::from_response(self.client.clone(), response))
}
}

@ -0,0 +1,4 @@
pub mod builders;
pub mod hydrus;
pub mod service;
pub mod version;

@ -0,0 +1,113 @@
use crate::endpoints::access_management::GetServicesResponse;
use crate::endpoints::access_management::{
SERVICE_TYPE_ALL_KNOWN_FILES, SERVICE_TYPE_ALL_KNOWN_TAGS, SERVICE_TYPE_ALL_LOCAL_FILES,
SERVICE_TYPE_FILE_REPOSITORIES, SERVICE_TYPE_LOCAL_FILES, SERVICE_TYPE_LOCAL_TAGS,
SERVICE_TYPE_TAG_REPOSITORIES, SERVICE_TYPE_TRASH,
};
use crate::error::Error;
use crate::Client;
use std::collections::HashMap;
use std::convert::TryFrom;
#[derive(Clone, PartialOrd, PartialEq, Hash)]
pub enum ServiceType {
LocalTags,
TagRepositories,
LocalFiles,
FileRepositories,
AllLocalFiles,
AllKnownFiles,
AllKnownTags,
Trash,
}
impl Eq for ServiceType {}
impl TryFrom<String> for ServiceType {
type Error = Error;
fn try_from(value: String) -> Result<Self, Self::Error> {
match value.as_str() {
s if s == SERVICE_TYPE_LOCAL_TAGS => Ok(Self::LocalTags),
s if s == SERVICE_TYPE_TAG_REPOSITORIES => Ok(Self::TagRepositories),
s if s == SERVICE_TYPE_LOCAL_FILES => Ok(Self::LocalFiles),
s if s == SERVICE_TYPE_FILE_REPOSITORIES => Ok(Self::FileRepositories),
s if s == SERVICE_TYPE_ALL_LOCAL_FILES => Ok(Self::AllLocalFiles),
s if s == SERVICE_TYPE_ALL_KNOWN_FILES => Ok(Self::AllKnownFiles),
s if s == SERVICE_TYPE_ALL_KNOWN_TAGS => Ok(Self::AllKnownTags),
s if s == SERVICE_TYPE_TRASH => Ok(Self::Trash),
_ => Err(Error::InvalidServiceType(value)),
}
}
}
impl ToString for ServiceType {
fn to_string(&self) -> String {
match self {
ServiceType::LocalTags => String::from(SERVICE_TYPE_LOCAL_TAGS),
ServiceType::TagRepositories => String::from(SERVICE_TYPE_TAG_REPOSITORIES),
ServiceType::LocalFiles => String::from(SERVICE_TYPE_LOCAL_FILES),
ServiceType::FileRepositories => String::from(SERVICE_TYPE_FILE_REPOSITORIES),
ServiceType::AllLocalFiles => String::from(SERVICE_TYPE_ALL_LOCAL_FILES),
ServiceType::AllKnownFiles => String::from(SERVICE_TYPE_ALL_KNOWN_FILES),
ServiceType::AllKnownTags => String::from(SERVICE_TYPE_ALL_KNOWN_TAGS),
ServiceType::Trash => String::from(SERVICE_TYPE_TRASH),
}
}
}
#[derive(Clone)]
pub struct Service {
client: Client,
pub name: String,
pub key: String,
pub service_type: ServiceType,
}
#[derive(Clone)]
pub struct Services {
inner: HashMap<ServiceType, Vec<Service>>,
}
impl Services {
pub fn from_response(client: Client, response: GetServicesResponse) -> Self {
let mut response = response.0;
let mut mapped_types = HashMap::with_capacity(response.keys().len());
let keys = response.keys().cloned().collect::<Vec<String>>().clone();
for service_type in &keys {
if let Ok(mapped_type) = ServiceType::try_from(service_type.clone()) {
let basic_services = response.remove(service_type).unwrap();
let mut service_list = Vec::new();
for basic_service in basic_services {
service_list.push(Service {
service_type: mapped_type.clone(),
name: basic_service.name,
key: basic_service.service_key,
client: client.clone(),
})
}
mapped_types.insert(mapped_type, service_list);
}
}
Self {
inner: mapped_types,
}
}
/// Returns a list of all services of the given type
pub fn get_services(&self, service_type: ServiceType) -> Vec<&Service> {
if let Some(services) = self.inner.get(&service_type) {
let mut borrowed_services = Vec::with_capacity(services.len());
for service in services {
borrowed_services.push(service)
}
borrowed_services
} else {
Vec::with_capacity(0)
}
}
}

@ -0,0 +1,4 @@
pub struct Version {
pub api: u32,
pub hydrus: u32,
}

@ -0,0 +1,5 @@
mod test_access_management;
mod test_adding_files;
mod test_adding_tags;
mod test_adding_urls;
mod test_searching_and_fetching_files;

@ -1,4 +1,4 @@
mod common; use super::super::common;
#[tokio::test] #[tokio::test]
async fn it_returns_the_api_version() { async fn it_returns_the_api_version() {

@ -1,4 +1,4 @@
mod common; use super::super::common;
#[tokio::test] #[tokio::test]
async fn it_adds_files() { async fn it_adds_files() {

@ -1,5 +1,5 @@
use super::super::common;
use hydrus_api::endpoints::adding_tags::{AddTagsRequestBuilder, TagAction}; use hydrus_api::endpoints::adding_tags::{AddTagsRequestBuilder, TagAction};
mod common;
#[tokio::test] #[tokio::test]
async fn it_cleans_tags() { async fn it_cleans_tags() {

@ -1,7 +1,6 @@
use super::super::common;
use hydrus_api::endpoints::adding_urls::{AddUrlRequestBuilder, URL_TYPE_POST}; use hydrus_api::endpoints::adding_urls::{AddUrlRequestBuilder, URL_TYPE_POST};
mod common;
#[tokio::test] #[tokio::test]
async fn it_returns_files_for_an_url() { async fn it_returns_files_for_an_url() {
let mut client = common::get_client(); let mut client = common::get_client();

@ -1,8 +1,7 @@
use super::super::common;
use hydrus_api::endpoints::common::FileIdentifier; use hydrus_api::endpoints::common::FileIdentifier;
use hydrus_api::endpoints::searching_and_fetching_files::FileSearchLocation; use hydrus_api::endpoints::searching_and_fetching_files::FileSearchLocation;
mod common;
#[tokio::test] #[tokio::test]
async fn is_searches_files() { async fn is_searches_files() {
let mut client = common::get_client(); let mut client = common::get_client();

@ -1,4 +1,5 @@
use hydrus_api::client::Client; use hydrus_api::client::Client;
use hydrus_api::Hydrus;
use log::LevelFilter; use log::LevelFilter;
use std::env; use std::env;
use std::sync::atomic::{AtomicBool, Ordering}; use std::sync::atomic::{AtomicBool, Ordering};
@ -15,9 +16,16 @@ pub fn setup() {
pub fn get_client() -> Client { pub fn get_client() -> Client {
setup(); setup();
Client::new( Client::new(
env::var("HYDRUS_URL").unwrap(), env::var("HYDRUS_URL").unwrap(),
env::var("HYDRUS_ACCESS_KEY").unwrap(), env::var("HYDRUS_ACCESS_KEY").unwrap(),
) )
.unwrap() .unwrap()
} }
pub fn get_hydrus() -> Hydrus {
let client = get_client();
Hydrus::new(client)
}

@ -0,0 +1,3 @@
mod client;
mod common;
mod wrapper;

@ -0,0 +1 @@
mod test_hydrus;

@ -0,0 +1,20 @@
use super::super::common;
use hydrus_api::service::ServiceType;
#[tokio::test]
async fn it_retrieves_version_info() {
let mut hydrus = common::get_hydrus();
let version = hydrus.version().await.unwrap();
assert!(version.hydrus > 0);
assert!(version.api > 0);
}
#[tokio::test]
async fn it_retrieves_services() {
let mut hydrus = common::get_hydrus();
let services = hydrus.services().await.unwrap();
// assuming hydrus is configured correctly
assert!(services.get_services(ServiceType::AllKnownFiles).len() > 0);
assert!(services.get_services(ServiceType::AllKnownTags).len() > 0);
}
Loading…
Cancel
Save