Improve types

Signed-off-by: trivernis <trivernis@protonmail.com>
pull/2/head
trivernis 3 years ago
parent 6a0df2c7fb
commit 2c5b3225f0
Signed by: Trivernis
GPG Key ID: DFFFCC2C7A02DB45

@ -1,14 +1,14 @@
use crate::error::{Error, Result}; use crate::endpoints::access_management::{
use crate::paths::access_management::{ ApiVersion, ApiVersionResponse, GetServices, GetServicesResponse, SessionKey,
ApiVersionResponse, GetServicesResponse, SessionKeyResponse, VerifyAccessKeyResponse, SessionKeyResponse, VerifyAccessKey, VerifyAccessKeyResponse,
}; };
use crate::paths::adding_files::{ use crate::endpoints::adding_files::{
AddFileRequest, AddFileResponse, ArchiveFilesRequest, ArchiveFilesResponse, DeleteFilesRequest, AddFile, AddFileRequest, AddFileResponse, ArchiveFiles, ArchiveFilesRequest, DeleteFiles,
DeleteFilesResponse, UnarchiveFilesRequest, UnarchiveFilesResponse, UndeleteFilesRequest, DeleteFilesRequest, UnarchiveFiles, UnarchiveFilesRequest, UndeleteFiles, UndeleteFilesRequest,
UndeleteFilesResponse,
}; };
use crate::paths::adding_tags::{AddTagsRequest, AddTagsResponse, CleanTagsResponse}; use crate::endpoints::adding_tags::{AddTags, AddTagsRequest, CleanTags, CleanTagsResponse};
use crate::paths::Path; use crate::endpoints::Endpoint;
use crate::error::{Error, Result};
use crate::utils::string_list_to_json_array; use crate::utils::string_list_to_json_array;
use reqwest::Response; use reqwest::Response;
use serde::de::DeserializeOwned; use serde::de::DeserializeOwned;
@ -23,6 +23,7 @@ pub struct Client {
} }
impl Client { impl Client {
/// Creates a new client to start requests against the hydrus api.
pub fn new<S: AsRef<str>>(url: S, access_key: S) -> Result<Self> { pub fn new<S: AsRef<str>>(url: S, access_key: S) -> Result<Self> {
Ok(Self { Ok(Self {
inner: reqwest::Client::new(), inner: reqwest::Client::new(),
@ -32,13 +33,13 @@ impl Client {
} }
/// Starts a get request to the path associated with the return type /// Starts a get request to the path associated with the return type
async fn get_and_parse<T: DeserializeOwned + Path, Q: Serialize + ?Sized>( async fn get_and_parse<E: Endpoint, Q: Serialize + ?Sized>(
&mut self, &mut self,
query: &Q, query: &Q,
) -> Result<T> { ) -> Result<E::Response> {
let response = self let response = self
.inner .inner
.get(format!("{}/{}", self.base_url, T::get_path())) .get(format!("{}/{}", self.base_url, E::get_path()))
.header(ACCESS_KEY_HEADER, &self.access_key) .header(ACCESS_KEY_HEADER, &self.access_key)
.query(query) .query(query)
.send() .send()
@ -49,10 +50,10 @@ impl Client {
} }
/// Stats a post request to the path associated with the return type /// Stats a post request to the path associated with the return type
async fn post<T: Path, B: Serialize>(&mut self, body: B) -> Result<Response> { async fn post<E: Endpoint>(&mut self, body: E::Request) -> Result<Response> {
let response = self let response = self
.inner .inner
.post(format!("{}/{}", self.base_url, T::get_path())) .post(format!("{}/{}", self.base_url, E::get_path()))
.json(&body) .json(&body)
.header(ACCESS_KEY_HEADER, &self.access_key) .header(ACCESS_KEY_HEADER, &self.access_key)
.send() .send()
@ -62,20 +63,17 @@ impl Client {
} }
/// Stats a post request and parses the body as json /// Stats a post request and parses the body as json
async fn post_and_parse<T: DeserializeOwned + Path, B: Serialize>( async fn post_and_parse<E: Endpoint>(&mut self, body: E::Request) -> Result<E::Response> {
&mut self, let response = self.post::<E>(body).await?;
body: B,
) -> Result<T> {
let response = self.post::<T, B>(body).await?;
Self::extract_content(response).await Self::extract_content(response).await
} }
/// Stats a post request to the path associated with the return type /// Stats a post request to the path associated with the return type
async fn post_binary<T: DeserializeOwned + Path>(&mut self, data: Vec<u8>) -> Result<T> { async fn post_binary<E: Endpoint>(&mut self, data: Vec<u8>) -> Result<E::Response> {
let response = self let response = self
.inner .inner
.post(format!("{}/{}", self.base_url, T::get_path())) .post(format!("{}/{}", self.base_url, E::get_path()))
.body(data) .body(data)
.header(ACCESS_KEY_HEADER, &self.access_key) .header(ACCESS_KEY_HEADER, &self.access_key)
.header("Content-Type", "application/octet-stream") .header("Content-Type", "application/octet-stream")
@ -103,27 +101,27 @@ impl Client {
/// Returns the current API version. It's being incremented every time the API changes. /// Returns the current API version. It's being incremented every time the API changes.
pub async fn api_version(&mut self) -> Result<ApiVersionResponse> { pub async fn api_version(&mut self) -> Result<ApiVersionResponse> {
self.get_and_parse(&()).await self.get_and_parse::<ApiVersion, ()>(&()).await
} }
/// Creates a new session key /// Creates a new session key
pub async fn session_key(&mut self) -> Result<SessionKeyResponse> { pub async fn session_key(&mut self) -> Result<SessionKeyResponse> {
self.get_and_parse(&()).await self.get_and_parse::<SessionKey, ()>(&()).await
} }
/// Verifies if the access key is valid and returns some information about its permissions /// Verifies if the access key is valid and returns some information about its permissions
pub async fn verify_access_key(&mut self) -> Result<VerifyAccessKeyResponse> { pub async fn verify_access_key(&mut self) -> Result<VerifyAccessKeyResponse> {
self.get_and_parse(&()).await self.get_and_parse::<VerifyAccessKey, ()>(&()).await
} }
/// Returns the list of tag and file services of the client /// Returns the list of tag and file services of the client
pub async fn get_services(&mut self) -> Result<GetServicesResponse> { pub async fn get_services(&mut self) -> Result<GetServicesResponse> {
self.get_and_parse(&()).await self.get_and_parse::<GetServices, ()>(&()).await
} }
/// Adds a file to hydrus /// Adds a file to hydrus
pub async fn add_file<S: AsRef<str>>(&mut self, path: S) -> Result<AddFileResponse> { pub async fn add_file<S: AsRef<str>>(&mut self, path: S) -> Result<AddFileResponse> {
self.post_and_parse(AddFileRequest { self.post_and_parse::<AddFile>(AddFileRequest {
path: path.as_ref().to_string(), path: path.as_ref().to_string(),
}) })
.await .await
@ -131,12 +129,12 @@ impl Client {
/// Adds a file from binary data to hydrus /// Adds a file from binary data to hydrus
pub async fn add_binary_file(&mut self, data: Vec<u8>) -> Result<AddFileResponse> { pub async fn add_binary_file(&mut self, data: Vec<u8>) -> Result<AddFileResponse> {
self.post_binary(data).await self.post_binary::<AddFile>(data).await
} }
/// Moves files with matching hashes to the trash /// Moves files with matching hashes to the trash
pub async fn delete_files(&mut self, hashes: Vec<String>) -> Result<()> { pub async fn delete_files(&mut self, hashes: Vec<String>) -> Result<()> {
self.post::<DeleteFilesResponse, DeleteFilesRequest>(DeleteFilesRequest { hashes }) self.post::<DeleteFiles>(DeleteFilesRequest { hashes })
.await?; .await?;
Ok(()) Ok(())
@ -144,7 +142,7 @@ impl Client {
/// Pulls files out of the trash by hash /// Pulls files out of the trash by hash
pub async fn undelete_files(&mut self, hashes: Vec<String>) -> Result<()> { pub async fn undelete_files(&mut self, hashes: Vec<String>) -> Result<()> {
self.post::<UndeleteFilesResponse, UndeleteFilesRequest>(UndeleteFilesRequest { hashes }) self.post::<UndeleteFiles>(UndeleteFilesRequest { hashes })
.await?; .await?;
Ok(()) Ok(())
@ -152,7 +150,7 @@ impl Client {
/// Moves files from the inbox into the archive /// Moves files from the inbox into the archive
pub async fn archive_files(&mut self, hashes: Vec<String>) -> Result<()> { pub async fn archive_files(&mut self, hashes: Vec<String>) -> Result<()> {
self.post::<ArchiveFilesResponse, ArchiveFilesRequest>(ArchiveFilesRequest { hashes }) self.post::<ArchiveFiles>(ArchiveFilesRequest { hashes })
.await?; .await?;
Ok(()) Ok(())
@ -160,24 +158,24 @@ impl Client {
/// Moves files from the archive into the inbox /// Moves files from the archive into the inbox
pub async fn unarchive_files(&mut self, hashes: Vec<String>) -> Result<()> { pub async fn unarchive_files(&mut self, hashes: Vec<String>) -> Result<()> {
self.post::<UnarchiveFilesResponse, UnarchiveFilesRequest>(UnarchiveFilesRequest { self.post::<UnarchiveFiles>(UnarchiveFilesRequest { hashes })
hashes, .await?;
})
.await?;
Ok(()) Ok(())
} }
/// Returns the list of tags as the client would see them in a human friendly order /// Returns the list of tags as the client would see them in a human friendly order
pub async fn clean_tags(&mut self, tags: Vec<String>) -> Result<CleanTagsResponse> { pub async fn clean_tags(&mut self, tags: Vec<String>) -> Result<CleanTagsResponse> {
self.get_and_parse(&[("tags", string_list_to_json_array(tags))]) self.get_and_parse::<CleanTags, [(&str, String)]>(&[(
.await "tags",
string_list_to_json_array(tags),
)])
.await
} }
/// Adds tags to files with the given hashes /// Adds tags to files with the given hashes
pub async fn add_tags(&mut self, request: AddTagsRequest) -> Result<()> { pub async fn add_tags(&mut self, request: AddTagsRequest) -> Result<()> {
self.post::<AddTagsResponse, AddTagsRequest>(request) self.post::<AddTags>(request).await?;
.await?;
Ok(()) Ok(())
} }

@ -1,5 +1,5 @@
use crate::paths::common::BasicServiceInfo; use crate::endpoints::common::BasicServiceInfo;
use crate::paths::Path; use crate::endpoints::Endpoint;
use std::collections::HashMap; use std::collections::HashMap;
#[derive(Debug, Clone, Deserialize)] #[derive(Debug, Clone, Deserialize)]
@ -8,7 +8,12 @@ pub struct ApiVersionResponse {
pub hydrus_version: u32, pub hydrus_version: u32,
} }
impl Path for ApiVersionResponse { pub struct ApiVersion;
impl Endpoint for ApiVersion {
type Request = ();
type Response = ApiVersionResponse;
fn get_path() -> String { fn get_path() -> String {
String::from("api_version") String::from("api_version")
} }
@ -19,7 +24,12 @@ pub struct SessionKeyResponse {
pub session_key: String, pub session_key: String,
} }
impl Path for SessionKeyResponse { pub struct SessionKey;
impl Endpoint for SessionKey {
type Request = ();
type Response = SessionKeyResponse;
fn get_path() -> String { fn get_path() -> String {
String::from("session_key") String::from("session_key")
} }
@ -31,7 +41,12 @@ pub struct VerifyAccessKeyResponse {
pub human_description: String, pub human_description: String,
} }
impl Path for VerifyAccessKeyResponse { pub struct VerifyAccessKey;
impl Endpoint for VerifyAccessKey {
type Request = ();
type Response = VerifyAccessKeyResponse;
fn get_path() -> String { fn get_path() -> String {
String::from("verify_access_key") String::from("verify_access_key")
} }
@ -40,7 +55,12 @@ impl Path for VerifyAccessKeyResponse {
#[derive(Debug, Clone, Deserialize)] #[derive(Debug, Clone, Deserialize)]
pub struct GetServicesResponse(pub HashMap<String, Vec<BasicServiceInfo>>); pub struct GetServicesResponse(pub HashMap<String, Vec<BasicServiceInfo>>);
impl Path for GetServicesResponse { pub struct GetServices;
impl Endpoint for GetServices {
type Request = ();
type Response = GetServicesResponse;
fn get_path() -> String { fn get_path() -> String {
String::from("get_services") String::from("get_services")
} }

@ -1,5 +1,5 @@
use crate::paths::common::BasicHashList; use crate::endpoints::common::BasicHashList;
use crate::paths::Path; use crate::endpoints::Endpoint;
#[derive(Debug, Clone, Serialize)] #[derive(Debug, Clone, Serialize)]
pub struct AddFileRequest { pub struct AddFileRequest {
@ -13,43 +13,61 @@ pub struct AddFileResponse {
pub note: String, pub note: String,
} }
impl Path for AddFileResponse { pub struct AddFile;
impl Endpoint for AddFile {
type Request = AddFileRequest;
type Response = AddFileResponse;
fn get_path() -> String { fn get_path() -> String {
String::from("add_files/add_file") String::from("add_files/add_file")
} }
} }
pub type DeleteFilesRequest = BasicHashList; pub type DeleteFilesRequest = BasicHashList;
pub struct DeleteFilesResponse;
impl Path for DeleteFilesResponse { pub struct DeleteFiles;
impl Endpoint for DeleteFiles {
type Request = DeleteFilesRequest;
type Response = ();
fn get_path() -> String { fn get_path() -> String {
String::from("add_files/delete_files") String::from("add_files/delete_files")
} }
} }
pub type UndeleteFilesRequest = BasicHashList; pub type UndeleteFilesRequest = BasicHashList;
pub struct UndeleteFilesResponse; pub struct UndeleteFiles;
impl Endpoint for UndeleteFiles {
type Request = UndeleteFilesRequest;
type Response = ();
impl Path for UndeleteFilesResponse {
fn get_path() -> String { fn get_path() -> String {
String::from("add_files/undelete_files") String::from("add_files/undelete_files")
} }
} }
pub type ArchiveFilesRequest = BasicHashList; pub type ArchiveFilesRequest = BasicHashList;
pub struct ArchiveFilesResponse; pub struct ArchiveFiles;
impl Endpoint for ArchiveFiles {
type Request = ArchiveFilesRequest;
type Response = ();
impl Path for ArchiveFilesResponse {
fn get_path() -> String { fn get_path() -> String {
String::from("add_files/archive_files") String::from("add_files/archive_files")
} }
} }
pub type UnarchiveFilesRequest = BasicHashList; pub type UnarchiveFilesRequest = BasicHashList;
pub struct UnarchiveFilesResponse; pub struct UnarchiveFiles;
impl Endpoint for UnarchiveFiles {
type Request = UndeleteFilesRequest;
type Response = ();
impl Path for UnarchiveFilesResponse {
fn get_path() -> String { fn get_path() -> String {
String::from("add_files/unarchive_files") String::from("add_files/unarchive_files")
} }

@ -1,4 +1,4 @@
use crate::paths::Path; use crate::endpoints::Endpoint;
use std::collections::HashMap; use std::collections::HashMap;
#[derive(Debug, Clone, Deserialize)] #[derive(Debug, Clone, Deserialize)]
@ -6,7 +6,12 @@ pub struct CleanTagsResponse {
pub tags: Vec<String>, pub tags: Vec<String>,
} }
impl Path for CleanTagsResponse { pub struct CleanTags;
impl Endpoint for CleanTags {
type Request = ();
type Response = CleanTagsResponse;
fn get_path() -> String { fn get_path() -> String {
String::from("add_tags/clean_tags") String::from("add_tags/clean_tags")
} }
@ -19,9 +24,12 @@ pub struct AddTagsRequest {
pub service_names_to_actions_to_tags: HashMap<String, HashMap<String, Vec<String>>>, pub service_names_to_actions_to_tags: HashMap<String, HashMap<String, Vec<String>>>,
} }
pub struct AddTagsResponse; pub struct AddTags;
impl Endpoint for AddTags {
type Request = AddTagsRequest;
type Response = ();
impl Path for AddTagsResponse {
fn get_path() -> String { fn get_path() -> String {
String::from("add_tags/add_tags") String::from("add_tags/add_tags")
} }

@ -0,0 +1,14 @@
use serde::de::DeserializeOwned;
use serde::Serialize;
pub mod access_management;
pub mod adding_files;
pub mod adding_tags;
pub mod common;
pub trait Endpoint {
type Request: Serialize;
type Response: DeserializeOwned;
fn get_path() -> String;
}

@ -6,7 +6,7 @@
//! ## Usage Example //! ## Usage Example
//! ``` //! ```
//! use hydrus_api::Client; //! use hydrus_api::Client;
//! use hydrus_api::paths::adding_tags::{AddTagsRequestBuilder, TagAction}; //! use hydrus_api::endpoints::adding_tags::{AddTagsRequestBuilder, TagAction};
//! use std::env; //! use std::env;
//! # #[tokio::test] //! # #[tokio::test]
//! # async fn doctest() { //! # async fn doctest() {
@ -35,8 +35,8 @@
extern crate serde_derive; extern crate serde_derive;
pub mod client; pub mod client;
pub mod endpoints;
mod error; mod error;
pub mod paths;
pub(crate) mod utils; pub(crate) mod utils;
pub use client::Client; pub use client::Client;

@ -1,8 +0,0 @@
pub mod access_management;
pub mod adding_files;
pub mod adding_tags;
pub mod common;
pub trait Path {
fn get_path() -> String;
}

@ -1,4 +1,4 @@
use hydrus_api::paths::adding_tags::{AddTagsRequestBuilder, TagAction}; use hydrus_api::endpoints::adding_tags::{AddTagsRequestBuilder, TagAction};
mod common; mod common;
#[tokio::test] #[tokio::test]

Loading…
Cancel
Save