Compare commits

...

5 Commits

@ -1,6 +1,6 @@
[package] [package]
name = "hydrus-api" name = "hydrus-api"
version = "0.9.3" version = "0.10.2"
authors = ["trivernis <trivernis@protonmail.com>"] authors = ["trivernis <trivernis@protonmail.com>"]
edition = "2018" edition = "2018"
license = "Apache-2.0" license = "Apache-2.0"
@ -36,4 +36,4 @@ features = ["macros", "rt-multi-thread"]
default = ["json"] default = ["json"]
rustls = ["reqwest/rustls"] rustls = ["reqwest/rustls"]
cbor = ["ciborium", "base64"] cbor = ["ciborium", "base64"]
json = ["serde_json"] json = ["serde_json"]

@ -6,6 +6,17 @@ use std::collections::HashMap;
pub struct BasicServiceInfo { pub struct BasicServiceInfo {
pub name: String, pub name: String,
pub service_key: String, pub service_key: String,
#[serde(alias = "type")]
pub service_type: u64,
pub type_pretty: String,
}
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct ServiceItem {
pub name: String,
#[serde(alias = "type")]
pub service_type: u64,
pub type_pretty: String,
} }
impl BasicServiceInfo { impl BasicServiceInfo {
@ -200,6 +211,10 @@ pub struct FileMetadataServices {
#[derive(Clone, Debug, Deserialize)] #[derive(Clone, Debug, Deserialize)]
pub struct FileMetadataServiceCurrent { pub struct FileMetadataServiceCurrent {
pub name: String,
#[serde(alias = "type")]
pub service_type: u64,
pub type_pretty: String,
pub time_imported: u64, pub time_imported: u64,
} }

@ -1,4 +1,4 @@
use crate::api_core::common::BasicServiceInfo; use crate::api_core::common::{BasicServiceInfo, ServiceItem};
use crate::api_core::endpoints::Endpoint; use crate::api_core::endpoints::Endpoint;
use std::collections::HashMap; use std::collections::HashMap;
@ -62,7 +62,13 @@ impl Endpoint for VerifyAccessKey {
} }
#[derive(Debug, Clone, Deserialize)] #[derive(Debug, Clone, Deserialize)]
pub struct GetServicesResponse(pub HashMap<String, Vec<BasicServiceInfo>>); pub struct GetServicesResponse {
pub services: HashMap<String, ServiceItem>,
pub version: u64,
pub hydrus_version: u64,
#[serde(flatten)]
pub other: HashMap<String, Vec<BasicServiceInfo>>,
}
pub struct GetServices; pub struct GetServices;

@ -21,9 +21,7 @@ impl Endpoint for CleanTags {
#[derive(Debug, Clone, Serialize)] #[derive(Debug, Clone, Serialize)]
pub struct AddTagsRequest { pub struct AddTagsRequest {
pub hashes: Vec<String>, pub hashes: Vec<String>,
pub service_names_to_tags: HashMap<String, Vec<String>>,
pub service_keys_to_tags: HashMap<String, Vec<String>>, pub service_keys_to_tags: HashMap<String, Vec<String>>,
pub service_names_to_actions_to_tags: HashMap<String, HashMap<String, Vec<String>>>,
pub service_keys_to_actions_to_tags: HashMap<String, HashMap<String, Vec<String>>>, pub service_keys_to_actions_to_tags: HashMap<String, HashMap<String, Vec<String>>>,
} }
@ -41,9 +39,7 @@ impl Endpoint for AddTags {
#[derive(Default)] #[derive(Default)]
pub struct AddTagsRequestBuilder { pub struct AddTagsRequestBuilder {
hashes: Vec<String>, hashes: Vec<String>,
service_names_to_tags: HashMap<String, Vec<String>>,
service_keys_to_tags: HashMap<String, Vec<String>>, service_keys_to_tags: HashMap<String, Vec<String>>,
service_names_to_actions_to_tags: HashMap<String, HashMap<String, Vec<String>>>,
service_keys_to_actions_to_tags: HashMap<String, HashMap<String, Vec<String>>>, service_keys_to_actions_to_tags: HashMap<String, HashMap<String, Vec<String>>>,
} }
@ -100,11 +96,8 @@ impl AddTagsRequestBuilder {
} }
/// Adds a single tag for a given service /// Adds a single tag for a given service
pub fn add_tag<S: AsRef<str>>(mut self, service_id: ServiceIdentifier, tag: S) -> Self { pub fn add_tag<S: AsRef<str>>(mut self, service_key: String, tag: S) -> Self {
let (service, relevant_mappings) = match service_id { let (service, relevant_mappings) = (service_key, &mut self.service_keys_to_tags);
ServiceIdentifier::Name(name) => (name, &mut self.service_names_to_tags),
ServiceIdentifier::Key(key) => (key, &mut self.service_keys_to_tags),
};
if let Some(mappings) = relevant_mappings.get_mut(&service) { if let Some(mappings) = relevant_mappings.get_mut(&service) {
mappings.push(tag.as_ref().into()) mappings.push(tag.as_ref().into())
} else { } else {
@ -115,11 +108,8 @@ impl AddTagsRequestBuilder {
} }
/// Adds multiple tags for a given service /// Adds multiple tags for a given service
pub fn add_tags(mut self, service_id: ServiceIdentifier, mut tags: Vec<String>) -> Self { pub fn add_tags(mut self, service_key: String, mut tags: Vec<String>) -> Self {
let (service, relevant_mappings) = match service_id { let (service, relevant_mappings) = (service_key, &mut self.service_keys_to_tags);
ServiceIdentifier::Name(name) => (name, &mut self.service_names_to_tags),
ServiceIdentifier::Key(key) => (key, &mut self.service_keys_to_tags),
};
if let Some(mappings) = relevant_mappings.get_mut(&service) { if let Some(mappings) = relevant_mappings.get_mut(&service) {
mappings.append(&mut tags); mappings.append(&mut tags);
} else { } else {
@ -132,14 +122,11 @@ impl AddTagsRequestBuilder {
/// Adds one tag for a given service with a defined action /// Adds one tag for a given service with a defined action
pub fn add_tag_with_action<S: AsRef<str>>( pub fn add_tag_with_action<S: AsRef<str>>(
mut self, mut self,
service_id: ServiceIdentifier, service_key: String,
tag: S, tag: S,
action: TagAction, action: TagAction,
) -> Self { ) -> Self {
let (service, relevant_mappings) = match service_id { let (service, relevant_mappings) = (service_key, &mut self.service_keys_to_actions_to_tags);
ServiceIdentifier::Name(name) => (name, &mut self.service_names_to_actions_to_tags),
ServiceIdentifier::Key(key) => (key, &mut self.service_keys_to_actions_to_tags),
};
let action_id = action.into_id(); let action_id = action.into_id();
if let Some(actions) = relevant_mappings.get_mut(&service) { if let Some(actions) = relevant_mappings.get_mut(&service) {
if let Some(tags) = actions.get_mut(&action_id.to_string()) { if let Some(tags) = actions.get_mut(&action_id.to_string()) {
@ -159,9 +146,7 @@ impl AddTagsRequestBuilder {
pub fn build(self) -> AddTagsRequest { pub fn build(self) -> AddTagsRequest {
AddTagsRequest { AddTagsRequest {
hashes: self.hashes, hashes: self.hashes,
service_names_to_tags: self.service_names_to_tags,
service_keys_to_tags: self.service_keys_to_tags, service_keys_to_tags: self.service_keys_to_tags,
service_names_to_actions_to_tags: self.service_names_to_actions_to_tags,
service_keys_to_actions_to_tags: self.service_keys_to_actions_to_tags, service_keys_to_actions_to_tags: self.service_keys_to_actions_to_tags,
} }
} }

@ -207,8 +207,18 @@ pub struct FileFullMetadata {
pub is_trashed: bool, pub is_trashed: bool,
pub file_services: FileMetadataServices, pub file_services: FileMetadataServices,
pub known_urls: Vec<String>, pub known_urls: Vec<String>,
pub service_keys_to_statuses_to_tags: HashMap<String, HashMap<String, Vec<String>>>, /// map of service keys to tags
pub service_keys_to_statuses_to_display_tags: HashMap<String, HashMap<String, Vec<String>>>, pub tags: HashMap<String, ServiceTags>,
}
#[derive(Clone, Debug, Default, Deserialize)]
pub struct ServiceTags {
pub name: String,
#[serde(alias = "type")]
pub service_type: u64,
pub type_pretty: String,
pub storage_tags: HashMap<String, Vec<String>>,
pub display_tags: HashMap<String, Vec<String>>,
} }
pub trait FileMetadataType: Clone + Debug { pub trait FileMetadataType: Clone + Debug {

@ -1,6 +1,6 @@
use crate::api_core::common::ServiceIdentifier; use crate::api_core::common::ServiceIdentifier;
use crate::api_core::endpoints::adding_tags::{AddTagsRequestBuilder, TagAction}; use crate::api_core::endpoints::adding_tags::{AddTagsRequestBuilder, TagAction};
use crate::error::Result; use crate::error::{Error, Result};
use crate::wrapper::tag::Tag; use crate::wrapper::tag::Tag;
use crate::Client; use crate::Client;
use std::collections::HashMap; use std::collections::HashMap;
@ -59,10 +59,25 @@ impl TaggingBuilder {
pub async fn run(self) -> Result<()> { pub async fn run(self) -> Result<()> {
let mut request = AddTagsRequestBuilder::default().add_hashes(self.hashes); let mut request = AddTagsRequestBuilder::default().add_hashes(self.hashes);
for (service, action_tag_mappings) in self.tag_mappings { for (service, action_tag_mappings) in self.tag_mappings {
let service_key = match service {
ServiceIdentifier::Name(n) => self
.client
.get_services()
.await?
.other
.values()
.flatten()
.filter(|v| *v.name == n)
.next()
.ok_or_else(|| Error::Hydrus(String::from("Service not found")))?
.service_key
.clone(),
ServiceIdentifier::Key(k) => k,
};
for (action, tags) in action_tag_mappings { for (action, tags) in action_tag_mappings {
for tag in tags { for tag in tags {
request = request.add_tag_with_action( request = request.add_tag_with_action(
service.clone().into(), service_key.clone(),
tag.to_string(), tag.to_string(),
action.clone(), action.clone(),
); );

@ -1,6 +1,6 @@
use crate::api_core::common::FileIdentifier; use crate::api_core::common::{FileIdentifier, ServiceIdentifier};
use crate::api_core::endpoints::searching_and_fetching_files::FullMetadata; use crate::api_core::endpoints::searching_and_fetching_files::FullMetadata;
use crate::error::Result; use crate::error::{Error, Result};
use crate::wrapper::address::Address; use crate::wrapper::address::Address;
use crate::wrapper::builders::delete_files_builder::DeleteFilesBuilder; use crate::wrapper::builders::delete_files_builder::DeleteFilesBuilder;
use crate::wrapper::builders::import_builder::ImportBuilder; use crate::wrapper::builders::import_builder::ImportBuilder;
@ -125,4 +125,25 @@ impl Hydrus {
pub async fn set_user_agent<S: ToString + Debug>(&self, user_agent: S) -> Result<()> { pub async fn set_user_agent<S: ToString + Debug>(&self, user_agent: S) -> Result<()> {
self.client.set_user_agent(user_agent).await self.client.set_user_agent(user_agent).await
} }
/// Returns the key for a given service identifier
pub async fn get_service_key(&self, service: ServiceIdentifier) -> Result<String> {
let key = match service {
ServiceIdentifier::Name(n) => self
.client
.get_services()
.await?
.other
.values()
.flatten()
.filter(|v| *v.name == n)
.next()
.ok_or_else(|| Error::Hydrus(String::from("Service not found")))?
.service_key
.clone(),
ServiceIdentifier::Key(k) => k,
};
Ok(key)
}
} }

@ -295,10 +295,10 @@ impl HydrusFile {
let metadata = self.metadata().await?; let metadata = self.metadata().await?;
let mut tag_mappings = HashMap::new(); let mut tag_mappings = HashMap::new();
for (service, status_tags) in &metadata.service_keys_to_statuses_to_tags { for (service, service_tags) in &metadata.tags {
let mut tag_list = Vec::new(); let mut tag_list = Vec::new();
for (_, tags) in status_tags { for (_, tags) in &service_tags.storage_tags {
tag_list.append(&mut tags.into_iter().map(|t| t.into()).collect()) tag_list.append(&mut tags.into_iter().map(|t| t.into()).collect())
} }
tag_mappings.insert(ServiceIdentifier::Key(service.clone()), tag_list); tag_mappings.insert(ServiceIdentifier::Key(service.clone()), tag_list);
@ -312,10 +312,10 @@ impl HydrusFile {
let metadata = self.metadata().await?; let metadata = self.metadata().await?;
let mut tag_mappings = HashMap::new(); let mut tag_mappings = HashMap::new();
for (service, status_tags) in &metadata.service_keys_to_statuses_to_tags { for (service, service_tags) in &metadata.tags {
let mut tag_list = Vec::new(); let mut tag_list = Vec::new();
for (_, tags) in status_tags { for (_, tags) in &service_tags.storage_tags {
tag_list.append(&mut tags.into_iter().map(|t| t.into()).collect()) tag_list.append(&mut tags.into_iter().map(|t| t.into()).collect())
} }
tag_mappings.insert(ServiceIdentifier::Key(service.clone()), tag_list); tag_mappings.insert(ServiceIdentifier::Key(service.clone()), tag_list);
@ -337,11 +337,11 @@ impl HydrusFile {
} }
/// Adds tags for a specific service to the file /// Adds tags for a specific service to the file
pub async fn add_tags(&mut self, service: ServiceIdentifier, tags: Vec<Tag>) -> Result<()> { pub async fn add_tags(&mut self, service_key: String, tags: Vec<Tag>) -> Result<()> {
let hash = self.hash().await?; let hash = self.hash().await?;
let request = AddTagsRequestBuilder::default() let request = AddTagsRequestBuilder::default()
.add_hash(hash) .add_hash(hash)
.add_tags(service, tag_list_to_string_list(tags)) .add_tags(service_key, tag_list_to_string_list(tags))
.build(); .build();
self.client.add_tags(request).await self.client.add_tags(request).await
@ -350,7 +350,7 @@ impl HydrusFile {
/// Allows modification of tags by using the defined tag actions /// Allows modification of tags by using the defined tag actions
pub async fn modify_tags( pub async fn modify_tags(
&mut self, &mut self,
service: ServiceIdentifier, service_key: String,
action: TagAction, action: TagAction,
tags: Vec<Tag>, tags: Vec<Tag>,
) -> Result<()> { ) -> Result<()> {
@ -358,7 +358,8 @@ impl HydrusFile {
let mut reqwest = AddTagsRequestBuilder::default().add_hash(hash); let mut reqwest = AddTagsRequestBuilder::default().add_hash(hash);
for tag in tags { for tag in tags {
reqwest = reqwest.add_tag_with_action(service.clone(), tag.to_string(), action.clone()); reqwest =
reqwest.add_tag_with_action(service_key.clone(), tag.to_string(), action.clone());
} }
self.client.add_tags(reqwest.build()).await self.client.add_tags(reqwest.build()).await

@ -135,7 +135,7 @@ pub struct Services {
impl Services { impl Services {
/// Creates the services list from a given hydrus response /// Creates the services list from a given hydrus response
pub fn from_response(client: Client, response: GetServicesResponse) -> Self { pub fn from_response(client: Client, response: GetServicesResponse) -> Self {
let mut response = response.0; let mut response = response.other;
let mut mapped_types = HashMap::with_capacity(response.keys().len()); let mut mapped_types = HashMap::with_capacity(response.keys().len());
let keys = response.keys().cloned().collect::<Vec<String>>().clone(); let keys = response.keys().cloned().collect::<Vec<String>>().clone();

@ -27,5 +27,5 @@ async fn it_verifies_the_access_key() {
async fn it_returns_a_list_of_services() { async fn it_returns_a_list_of_services() {
let client = common::get_client(); let client = common::get_client();
let services_response = client.get_services().await.unwrap(); let services_response = client.get_services().await.unwrap();
assert!(services_response.0.keys().len() > 0); assert!(services_response.other.keys().len() > 0);
} }

@ -27,11 +27,11 @@ async fn it_adds_tags() {
let request = AddTagsRequestBuilder::default() let request = AddTagsRequestBuilder::default()
.add_hash(EMPTY_HASH) // valid hash, I hope no files are affected .add_hash(EMPTY_HASH) // valid hash, I hope no files are affected
.add_tags( .add_tags(
ServiceIdentifier::name("my tags"), "6c6f63616c2074616773".into(),
vec!["beach".into(), "summer".into()], vec!["beach".into(), "summer".into()],
) )
.add_tag_with_action( .add_tag_with_action(
ServiceIdentifier::name("my tags"), "6c6f63616c2074616773".into(),
"rain", "rain",
TagAction::DeleteFromLocalService, TagAction::DeleteFromLocalService,
) )
@ -49,7 +49,7 @@ async fn it_searches_for_tags() {
"*", "*",
TagSearchOptions::default() TagSearchOptions::default()
.display_type(TagDisplayType::Display) .display_type(TagDisplayType::Display)
.tag_service(ServiceIdentifier::name("public tag repository")), .tag_service(ServiceIdentifier::name("all known tags")),
) )
.await .await
.unwrap(); .unwrap();

@ -52,7 +52,7 @@ async fn it_fetches_file_metadata() {
client client
.get_file_metadata::<FullMetadata>( .get_file_metadata::<FullMetadata>(
vec![], vec![],
vec!["0000000000000000000000000000000000000000000000000000000000000000".to_string()], vec!["9641a590e66d9f2e5137b6bcba07fdf6cec3ffaa54de2565c3afcc2125ad1160".to_string()],
) )
.await .await
.unwrap(); .unwrap();

@ -58,7 +58,7 @@ async fn it_has_tags() {
async fn it_adds_tags() { async fn it_adds_tags() {
let mut file = get_file().await; let mut file = get_file().await;
file.add_tags( file.add_tags(
ServiceName::my_tags().into(), "6c6f63616c2074616773".into(),
vec!["character:megumin".into(), "ark mage".into()], vec!["character:megumin".into(), "ark mage".into()],
) )
.await .await
@ -69,8 +69,8 @@ async fn it_adds_tags() {
async fn it_modifies_tags() { async fn it_modifies_tags() {
let mut file = get_file().await; let mut file = get_file().await;
file.modify_tags( file.modify_tags(
ServiceName::my_tags().into(), "6c6f63616c2074616773".into(),
TagAction::RescindPendFromRepository, TagAction::DeleteFromLocalService,
vec!["ark mage".into()], vec!["ark mage".into()],
) )
.await .await

Loading…
Cancel
Save