Add definitions updates

Signed-off-by: trivernis <trivernis@protonmail.com>
main
trivernis 3 years ago
parent 697f7463e7
commit 11a2807116
Signed by: Trivernis
GPG Key ID: DFFFCC2C7A02DB45

@ -40,6 +40,14 @@ impl Client {
self.get::<MetadataEndpoint, _>(&[("since", since)]).await
}
/// Returns the parsed update file identified by the given hash.
/// The hash can be retrieved by fetching the metadata with [Client::metadata]
#[tracing::instrument(skip(self), level = "debug")]
pub async fn update<S: AsRef<str> + Debug>(&self, update_hash: S) -> Result<UpdateResponse> {
self.get::<UpdateEndpoint, _>(&[("update_hash", update_hash.as_ref())])
.await
}
/// Performs a get request to the given Get Endpoint
#[tracing::instrument(skip(self), level = "trace")]
async fn get<E: GetEndpoint, Q: Serialize + Debug>(&self, query: &Q) -> Result<E::Response> {

@ -1,11 +1,13 @@
mod metadata;
mod options;
mod update;
use crate::Result;
use std::fmt::Debug;
pub use metadata::*;
pub use options::*;
pub use update::*;
pub trait Endpoint {
fn path() -> &'static str;

@ -0,0 +1,66 @@
use crate::hydrus_serializable::definitions_update::{
HashDefinition, HydrusDefinitionsUpdate, TagDefinition,
};
use crate::hydrus_serializable::wrapper::GenericHydrusSerWrapper;
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),
}
#[derive(Clone, Debug)]
pub struct DefinitionsUpdateResponse {
pub hashes: HashMap<u64, String>,
pub tags: HashMap<u64, String>,
}
impl FromJson for UpdateResponse {
fn from_json(value: Value) -> crate::Result<Self>
where
Self: Sized,
{
let wrapper = serde_json::from_value::<GenericHydrusSerWrapper>(value)?;
match wrapper.type_id {
36 => {
let definitions_update = DefinitionsUpdateResponse::from_wrapper(wrapper)?;
Ok(Self::Definitions(definitions_update))
}
_ => Err(Error::Malformed),
}
}
}
impl DefinitionsUpdateResponse {
fn from_wrapper(wrapper: GenericHydrusSerWrapper) -> Result<Self> {
let mut definitions_update = wrapper.into_inner::<HydrusDefinitionsUpdate>()?;
let hashes = definitions_update
.take::<HashDefinition>()?
.map(|h| h.into_iter().map(|h| (h.id, h.hash)).collect())
.unwrap_or_else(|| HashMap::new());
let tags = definitions_update
.take::<TagDefinition>()?
.map(|t| t.into_iter().map(|t| (t.id, t.tag)).collect())
.unwrap_or_else(|| HashMap::new());
Ok(Self { hashes, tags })
}
}

@ -0,0 +1,71 @@
use crate::constants::HYDRUS_TYPE_DEFINITIONS_UPDATE;
use crate::hydrus_serializable::HydrusSerializable;
use crate::{Error, Result};
use serde::de::DeserializeOwned;
use serde::Deserialize;
use serde_json::Value;
#[derive(Clone, Debug, Deserialize)]
pub struct HydrusDefinitionsUpdate(pub Vec<DefinitionsUpdateEntries>);
impl HydrusDefinitionsUpdate {
pub fn take<D: DefinitionsTrait>(&mut self) -> Result<Option<Vec<D>>> {
let entry_index = self
.0
.iter()
.position(|d| d.definition_id == D::definition_id());
if let Some(idx) = entry_index {
let entry = self.0.swap_remove(idx);
entry.into_inner()
} else {
Ok(None)
}
}
}
impl HydrusSerializable for HydrusDefinitionsUpdate {
fn type_id() -> u64 {
HYDRUS_TYPE_DEFINITIONS_UPDATE
}
}
#[derive(Clone, Debug, Deserialize)]
pub struct DefinitionsUpdateEntries {
pub definition_id: u64,
entries: Value,
}
impl DefinitionsUpdateEntries {
pub fn into_inner<T: DeserializeOwned>(self) -> Result<T> {
serde_json::from_value::<T>(self.entries).map_err(Error::from)
}
}
pub trait DefinitionsTrait: DeserializeOwned {
fn definition_id() -> u64;
}
#[derive(Deserialize, Clone, Debug)]
pub struct HashDefinition {
pub id: u64,
pub hash: String,
}
impl DefinitionsTrait for HashDefinition {
fn definition_id() -> u64 {
0
}
}
#[derive(Deserialize, Clone, Debug)]
pub struct TagDefinition {
pub id: u64,
pub tag: String,
}
impl DefinitionsTrait for TagDefinition {
fn definition_id() -> u64 {
1
}
}

@ -1,3 +1,4 @@
use crate::constants::HYDRUS_TYPE_METADATA;
use crate::hydrus_serializable::HydrusSerializable;
use serde::Deserialize;
@ -17,6 +18,6 @@ pub struct MetadataEntry {
impl HydrusSerializable for HydrusMetadata {
fn type_id() -> u64 {
37
HYDRUS_TYPE_METADATA
}
}

@ -6,6 +6,7 @@ use serde_json::Value;
use std::fmt::Formatter;
use std::marker::PhantomData;
pub mod definitions_update;
pub mod dictionary;
pub mod metadata;
pub mod tag_filter;

@ -1,3 +1,4 @@
use crate::constants::HYDRUS_TYPE_TAG_FILTER;
use crate::hydrus_serializable::HydrusSerializable;
use serde::Deserialize;
use serde_json::Value;
@ -7,6 +8,6 @@ pub struct HydrusTagFilter(pub Value);
impl HydrusSerializable for HydrusTagFilter {
fn type_id() -> u64 {
44
HYDRUS_TYPE_TAG_FILTER
}
}

@ -1,5 +1,7 @@
use crate::hydrus_serializable::{ConstNumberTrait, HydrusSerializable, SerializableId};
use crate::{Error, Result};
use serde::Deserialize;
use serde_json::Value;
#[derive(Clone, Debug, Deserialize)]
pub struct VersionOne;
@ -19,3 +21,24 @@ pub struct HydrusSerWrapper<T: HydrusSerializable> {
pub version: SerializableId<VersionOne>,
pub inner: T,
}
/// A generic hydrus serializable wrapper that allows one
/// to retrieve the type id and act on that
#[derive(Clone, Debug, Deserialize)]
pub struct GenericHydrusSerWrapper {
pub type_id: u64,
#[allow(unused)]
pub version: SerializableId<VersionOne>,
pub inner: Value,
}
impl GenericHydrusSerWrapper {
/// Converts the inner value into the target deserializable format
pub fn into_inner<T: HydrusSerializable>(self) -> Result<T> {
if self.type_id == T::type_id() {
serde_json::from_value(self.inner).map_err(Error::from)
} else {
Err(Error::Malformed)
}
}
}

@ -11,3 +11,12 @@ async fn test_metadata() {
let client = common::get_client();
client.metadata(0).await.unwrap();
}
#[tokio::test]
async fn test_update() {
let client = common::get_client();
client
.update("4a4d13c1fcdf0cf734927ec4c9637fdac6144512ad7dc919e0f222e7b0e71586")
.await
.unwrap();
}

Loading…
Cancel
Save