use crate::hydrus_serializable::content_update::{ ContentUpdatesAndAction, HydrusContentUpdate, MappingsUpdateEntry, TagParentsUpdateEntry, TagSiblingsUpdateEntry, }; use crate::hydrus_serializable::definitions_update::{ HashDefinition, HydrusDefinitionsUpdate, TagDefinition, }; use crate::hydrus_serializable::wrapper::GenericHydrusSerWrapper; use crate::Error::Malformed; use crate::Result; use crate::{Endpoint, Error, FromJson, GetEndpoint}; use serde_json::Value; use std::collections::HashMap; pub struct UpdateEndpoint; impl Endpoint for UpdateEndpoint { fn path() -> &'static str { "update" } } impl GetEndpoint for UpdateEndpoint { type Response = UpdateResponse; } #[derive(Clone, Debug)] pub enum UpdateResponse { Definitions(DefinitionsUpdateResponse), Content(ContentUpdateResponse), } impl FromJson for UpdateResponse { fn from_json(value: Value) -> crate::Result where Self: Sized, { let wrapper = serde_json::from_value::(value)?; match wrapper.type_id { 34 => { let content_update = ContentUpdateResponse::from_wrapper(wrapper)?; Ok(Self::Content(content_update)) } 36 => { let definitions_update = DefinitionsUpdateResponse::from_wrapper(wrapper)?; Ok(Self::Definitions(definitions_update)) } _ => Err(Error::Malformed), } } } trait FromWrapper { fn from_wrapper(wrapper: GenericHydrusSerWrapper) -> Result where Self: Sized; } #[derive(Clone, Debug)] pub struct DefinitionsUpdateResponse { pub hashes: HashMap, pub tags: HashMap, } impl FromWrapper for DefinitionsUpdateResponse { fn from_wrapper(wrapper: GenericHydrusSerWrapper) -> Result { let mut definitions_update = wrapper.into_inner::()?; let hashes = definitions_update .take::()? .map(|h| h.into_iter().map(|h| (h.id, h.hash)).collect()) .unwrap_or_default(); let tags = definitions_update .take::()? .map(|t| t.into_iter().map(|t| (t.id, t.tag)).collect()) .unwrap_or_default(); Ok(Self { hashes, tags }) } } #[derive(Clone, Debug)] pub struct ContentUpdateResponse { pub mappings: HashMap>>, pub tag_parents: HashMap>, pub tag_siblings: HashMap>, } impl FromWrapper for ContentUpdateResponse { fn from_wrapper(wrapper: GenericHydrusSerWrapper) -> Result { let mut content_update = wrapper.into_inner::()?; let mappings = content_update .take::()? .map(Self::map_mappings_update) .unwrap_or_default(); let tag_parents = content_update .take::()? .map(Self::map_tag_parents_update) .unwrap_or_default(); let tag_siblings = content_update .take::()? .map(Self::map_tag_siblings_update) .unwrap_or_default(); Ok(Self { mappings, tag_parents, tag_siblings, }) } } impl ContentUpdateResponse { fn map_mappings_update( update: Vec>, ) -> HashMap>> { update .into_iter() .filter_map(Self::map_update_and_action) .map(|(action, entries)| { ( action, entries .into_iter() .map(|e| (e.tag_id, e.hash_ids)) .collect::>>(), ) }) .collect() } fn map_tag_parents_update( update: Vec>, ) -> HashMap> { update .into_iter() .filter_map(Self::map_update_and_action::) .map(|(action, entries)| { ( action, entries .into_iter() .map(|e| (e.child_id, e.parent_id)) .collect::>(), ) }) .collect() } fn map_tag_siblings_update( update: Vec>, ) -> HashMap> { update .into_iter() .filter_map(Self::map_update_and_action::) .map(|(a, entries)| { ( a, entries .into_iter() .map(|e| (e.tag_id, e.sibling_id)) .collect::>(), ) }) .collect() } fn map_update_and_action( entry: ContentUpdatesAndAction, ) -> Option<(ContentUpdateAction, Vec)> { Some(( ContentUpdateAction::from_number(entry.action).ok()?, entry.updates, )) } } #[derive(Clone, Debug, Ord, PartialOrd, Eq, PartialEq, Hash)] pub enum ContentUpdateAction { Add = 0, Delete = 1, } impl ContentUpdateAction { pub fn from_number(num: u64) -> Result { match num { 0 => Ok(Self::Add), 1 => Ok(Self::Delete), _ => Err(Malformed), } } }