|
|
@ -11,6 +11,7 @@ use crate::api_core::adding_urls::{
|
|
|
|
AddUrl, AddUrlRequest, AddUrlResponse, AssociateUrl, AssociateUrlRequest, GetUrlFiles,
|
|
|
|
AddUrl, AddUrlRequest, AddUrlResponse, AssociateUrl, AssociateUrlRequest, GetUrlFiles,
|
|
|
|
GetUrlFilesResponse, GetUrlInfo, GetUrlInfoResponse,
|
|
|
|
GetUrlFilesResponse, GetUrlInfo, GetUrlInfoResponse,
|
|
|
|
};
|
|
|
|
};
|
|
|
|
|
|
|
|
use crate::api_core::client_builder::ClientBuilder;
|
|
|
|
use crate::api_core::common::{FileIdentifier, FileMetadataInfo, FileRecord, OptionalStringNumber};
|
|
|
|
use crate::api_core::common::{FileIdentifier, FileMetadataInfo, FileRecord, OptionalStringNumber};
|
|
|
|
use crate::api_core::managing_cookies_and_http_headers::{
|
|
|
|
use crate::api_core::managing_cookies_and_http_headers::{
|
|
|
|
GetCookies, GetCookiesResponse, SetCookies, SetCookiesRequest, SetUserAgent,
|
|
|
|
GetCookies, GetCookiesResponse, SetCookies, SetCookiesRequest, SetUserAgent,
|
|
|
@ -21,8 +22,8 @@ use crate::api_core::managing_pages::{
|
|
|
|
GetPages, GetPagesResponse,
|
|
|
|
GetPages, GetPagesResponse,
|
|
|
|
};
|
|
|
|
};
|
|
|
|
use crate::api_core::searching_and_fetching_files::{
|
|
|
|
use crate::api_core::searching_and_fetching_files::{
|
|
|
|
FileMetadata, FileMetadataResponse, FileSearchOptions, GetFile, SearchFiles,
|
|
|
|
FileMetadata, FileMetadataResponse, FileSearchOptions, GetFile, SearchFileHashes,
|
|
|
|
SearchFilesResponse, SearchQueryEntry,
|
|
|
|
SearchFileHashesResponse, SearchFiles, SearchFilesResponse, SearchQueryEntry,
|
|
|
|
};
|
|
|
|
};
|
|
|
|
use crate::api_core::Endpoint;
|
|
|
|
use crate::api_core::Endpoint;
|
|
|
|
use crate::error::{Error, Result};
|
|
|
|
use crate::error::{Error, Result};
|
|
|
@ -32,6 +33,7 @@ use crate::utils::{
|
|
|
|
use reqwest::Response;
|
|
|
|
use reqwest::Response;
|
|
|
|
use serde::de::DeserializeOwned;
|
|
|
|
use serde::de::DeserializeOwned;
|
|
|
|
use serde::Serialize;
|
|
|
|
use serde::Serialize;
|
|
|
|
|
|
|
|
use std::fmt::Debug;
|
|
|
|
|
|
|
|
|
|
|
|
static ACCESS_KEY_HEADER: &str = "Hydrus-Client-API-Access-Key";
|
|
|
|
static ACCESS_KEY_HEADER: &str = "Hydrus-Client-API-Access-Key";
|
|
|
|
|
|
|
|
|
|
|
@ -40,12 +42,17 @@ static ACCESS_KEY_HEADER: &str = "Hydrus-Client-API-Access-Key";
|
|
|
|
/// over the REST api.
|
|
|
|
/// over the REST api.
|
|
|
|
#[derive(Debug)]
|
|
|
|
#[derive(Debug)]
|
|
|
|
pub struct Client {
|
|
|
|
pub struct Client {
|
|
|
|
inner: reqwest::Client,
|
|
|
|
pub(crate) inner: reqwest::Client,
|
|
|
|
base_url: String,
|
|
|
|
pub(crate) base_url: String,
|
|
|
|
access_key: String,
|
|
|
|
pub(crate) access_key: String,
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
impl Client {
|
|
|
|
impl Client {
|
|
|
|
|
|
|
|
/// Returns a builder for the client
|
|
|
|
|
|
|
|
pub fn builder() -> ClientBuilder {
|
|
|
|
|
|
|
|
ClientBuilder::default()
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/// Creates a new client to start requests against the hydrus api.
|
|
|
|
/// Creates a new client to start requests against the hydrus api.
|
|
|
|
pub fn new<S: AsRef<str>>(url: S, access_key: S) -> Self {
|
|
|
|
pub fn new<S: AsRef<str>>(url: S, access_key: S) -> Self {
|
|
|
|
Self {
|
|
|
|
Self {
|
|
|
@ -56,8 +63,9 @@ impl Client {
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/// Starts a get request to the path
|
|
|
|
/// Starts a get request to the path
|
|
|
|
async fn get<E: Endpoint, Q: Serialize + ?Sized>(&self, query: &Q) -> Result<Response> {
|
|
|
|
#[tracing::instrument(skip(self), level = "trace")]
|
|
|
|
log::debug!("GET request to {}", E::path());
|
|
|
|
async fn get<E: Endpoint, Q: Serialize + Debug + ?Sized>(&self, query: &Q) -> Result<Response> {
|
|
|
|
|
|
|
|
tracing::trace!("GET request to {}", E::path());
|
|
|
|
let response = self
|
|
|
|
let response = self
|
|
|
|
.inner
|
|
|
|
.inner
|
|
|
|
.get(format!("{}/{}", self.base_url, E::path()))
|
|
|
|
.get(format!("{}/{}", self.base_url, E::path()))
|
|
|
@ -70,7 +78,8 @@ impl Client {
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/// Starts a get request to the path associated with the Endpoint Type
|
|
|
|
/// Starts a get request to the path associated with the Endpoint Type
|
|
|
|
async fn get_and_parse<E: Endpoint, Q: Serialize + ?Sized>(
|
|
|
|
#[tracing::instrument(skip(self), level = "trace")]
|
|
|
|
|
|
|
|
async fn get_and_parse<E: Endpoint, Q: Serialize + Debug + ?Sized>(
|
|
|
|
&self,
|
|
|
|
&self,
|
|
|
|
query: &Q,
|
|
|
|
query: &Q,
|
|
|
|
) -> Result<E::Response> {
|
|
|
|
) -> Result<E::Response> {
|
|
|
@ -80,8 +89,9 @@ impl Client {
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/// Stats a post request to the path associated with the Endpoint Type
|
|
|
|
/// Stats a post request to the path associated with the Endpoint Type
|
|
|
|
|
|
|
|
#[tracing::instrument(skip(self), level = "trace")]
|
|
|
|
async fn post<E: Endpoint>(&self, body: E::Request) -> Result<Response> {
|
|
|
|
async fn post<E: Endpoint>(&self, body: E::Request) -> Result<Response> {
|
|
|
|
log::debug!("POST request to {}", E::path());
|
|
|
|
tracing::trace!("POST request to {}", E::path());
|
|
|
|
let response = self
|
|
|
|
let response = self
|
|
|
|
.inner
|
|
|
|
.inner
|
|
|
|
.post(format!("{}/{}", self.base_url, E::path()))
|
|
|
|
.post(format!("{}/{}", self.base_url, E::path()))
|
|
|
@ -94,6 +104,7 @@ impl Client {
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/// Stats a post request and parses the body as json
|
|
|
|
/// Stats a post request and parses the body as json
|
|
|
|
|
|
|
|
#[tracing::instrument(skip(self), level = "trace")]
|
|
|
|
async fn post_and_parse<E: Endpoint>(&self, body: E::Request) -> Result<E::Response> {
|
|
|
|
async fn post_and_parse<E: Endpoint>(&self, body: E::Request) -> Result<E::Response> {
|
|
|
|
let response = self.post::<E>(body).await?;
|
|
|
|
let response = self.post::<E>(body).await?;
|
|
|
|
|
|
|
|
|
|
|
@ -101,8 +112,9 @@ 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
|
|
|
|
|
|
|
|
#[tracing::instrument(skip(self, data), level = "trace")]
|
|
|
|
async fn post_binary<E: Endpoint>(&self, data: Vec<u8>) -> Result<E::Response> {
|
|
|
|
async fn post_binary<E: Endpoint>(&self, data: Vec<u8>) -> Result<E::Response> {
|
|
|
|
log::debug!("Binary POST request to {}", E::path());
|
|
|
|
tracing::trace!("Binary POST request to {}", E::path());
|
|
|
|
let response = self
|
|
|
|
let response = self
|
|
|
|
.inner
|
|
|
|
.inner
|
|
|
|
.post(format!("{}/{}", self.base_url, E::path()))
|
|
|
|
.post(format!("{}/{}", self.base_url, E::path()))
|
|
|
@ -117,10 +129,11 @@ impl Client {
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/// Returns an error with the response text content if the status doesn't indicate success
|
|
|
|
/// Returns an error with the response text content if the status doesn't indicate success
|
|
|
|
|
|
|
|
#[tracing::instrument(level = "trace")]
|
|
|
|
async fn extract_error(response: Response) -> Result<Response> {
|
|
|
|
async fn extract_error(response: Response) -> Result<Response> {
|
|
|
|
if !response.status().is_success() {
|
|
|
|
if !response.status().is_success() {
|
|
|
|
let msg = response.text().await?;
|
|
|
|
let msg = response.text().await?;
|
|
|
|
log::error!("API returned error '{}'", msg);
|
|
|
|
tracing::error!("API returned error '{}'", msg);
|
|
|
|
Err(Error::Hydrus(msg))
|
|
|
|
Err(Error::Hydrus(msg))
|
|
|
|
} else {
|
|
|
|
} else {
|
|
|
|
Ok(response)
|
|
|
|
Ok(response)
|
|
|
@ -128,51 +141,55 @@ impl Client {
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/// Parses the response as JSOn
|
|
|
|
/// Parses the response as JSOn
|
|
|
|
async fn extract_content<T: DeserializeOwned>(response: Response) -> Result<T> {
|
|
|
|
#[tracing::instrument(level = "trace")]
|
|
|
|
response.json::<T>().await.map_err(Error::from)
|
|
|
|
async fn extract_content<T: DeserializeOwned + Debug>(response: Response) -> Result<T> {
|
|
|
|
|
|
|
|
let content = response.json::<T>().await?;
|
|
|
|
|
|
|
|
tracing::trace!("response content: {:?}", content);
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
Ok(content)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/// 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.
|
|
|
|
|
|
|
|
#[tracing::instrument(skip(self), level = "debug")]
|
|
|
|
pub async fn api_version(&self) -> Result<ApiVersionResponse> {
|
|
|
|
pub async fn api_version(&self) -> Result<ApiVersionResponse> {
|
|
|
|
log::trace!("Getting api version");
|
|
|
|
|
|
|
|
self.get_and_parse::<ApiVersion, ()>(&()).await
|
|
|
|
self.get_and_parse::<ApiVersion, ()>(&()).await
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/// Creates a new session key
|
|
|
|
/// Creates a new session key
|
|
|
|
|
|
|
|
#[tracing::instrument(skip(self), level = "debug")]
|
|
|
|
pub async fn session_key(&self) -> Result<SessionKeyResponse> {
|
|
|
|
pub async fn session_key(&self) -> Result<SessionKeyResponse> {
|
|
|
|
log::trace!("Getting session key");
|
|
|
|
|
|
|
|
self.get_and_parse::<SessionKey, ()>(&()).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
|
|
|
|
|
|
|
|
#[tracing::instrument(skip(self), level = "debug")]
|
|
|
|
pub async fn verify_access_key(&self) -> Result<VerifyAccessKeyResponse> {
|
|
|
|
pub async fn verify_access_key(&self) -> Result<VerifyAccessKeyResponse> {
|
|
|
|
log::trace!("Verifying access key");
|
|
|
|
|
|
|
|
self.get_and_parse::<VerifyAccessKey, ()>(&()).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
|
|
|
|
|
|
|
|
#[tracing::instrument(skip(self), level = "debug")]
|
|
|
|
pub async fn get_services(&self) -> Result<GetServicesResponse> {
|
|
|
|
pub async fn get_services(&self) -> Result<GetServicesResponse> {
|
|
|
|
log::trace!("Getting services");
|
|
|
|
|
|
|
|
self.get_and_parse::<GetServices, ()>(&()).await
|
|
|
|
self.get_and_parse::<GetServices, ()>(&()).await
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/// Adds a file to hydrus
|
|
|
|
/// Adds a file to hydrus
|
|
|
|
pub async fn add_file<S: ToString>(&self, path: S) -> Result<AddFileResponse> {
|
|
|
|
#[tracing::instrument(skip(self), level = "debug")]
|
|
|
|
|
|
|
|
pub async fn add_file<S: ToString + Debug>(&self, path: S) -> Result<AddFileResponse> {
|
|
|
|
let path = path.to_string();
|
|
|
|
let path = path.to_string();
|
|
|
|
log::trace!("Adding file {}", path);
|
|
|
|
|
|
|
|
self.post_and_parse::<AddFile>(AddFileRequest { path })
|
|
|
|
self.post_and_parse::<AddFile>(AddFileRequest { path })
|
|
|
|
.await
|
|
|
|
.await
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/// Adds a file from binary data to hydrus
|
|
|
|
/// Adds a file from binary data to hydrus
|
|
|
|
|
|
|
|
#[tracing::instrument(skip(self, data), level = "debug")]
|
|
|
|
pub async fn add_binary_file(&self, data: Vec<u8>) -> Result<AddFileResponse> {
|
|
|
|
pub async fn add_binary_file(&self, data: Vec<u8>) -> Result<AddFileResponse> {
|
|
|
|
log::trace!("Adding binary file");
|
|
|
|
|
|
|
|
self.post_binary::<AddFile>(data).await
|
|
|
|
self.post_binary::<AddFile>(data).await
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/// Moves files with matching hashes to the trash
|
|
|
|
/// Moves files with matching hashes to the trash
|
|
|
|
|
|
|
|
#[tracing::instrument(skip(self), level = "debug")]
|
|
|
|
pub async fn delete_files(&self, hashes: Vec<String>) -> Result<()> {
|
|
|
|
pub async fn delete_files(&self, hashes: Vec<String>) -> Result<()> {
|
|
|
|
log::trace!("Deleting files {:?}", hashes);
|
|
|
|
|
|
|
|
self.post::<DeleteFiles>(DeleteFilesRequest { hashes })
|
|
|
|
self.post::<DeleteFiles>(DeleteFilesRequest { hashes })
|
|
|
|
.await?;
|
|
|
|
.await?;
|
|
|
|
|
|
|
|
|
|
|
@ -180,8 +197,8 @@ impl Client {
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/// Pulls files out of the trash by hash
|
|
|
|
/// Pulls files out of the trash by hash
|
|
|
|
|
|
|
|
#[tracing::instrument(skip(self), level = "debug")]
|
|
|
|
pub async fn undelete_files(&self, hashes: Vec<String>) -> Result<()> {
|
|
|
|
pub async fn undelete_files(&self, hashes: Vec<String>) -> Result<()> {
|
|
|
|
log::trace!("Undeleting files {:?}", hashes);
|
|
|
|
|
|
|
|
self.post::<UndeleteFiles>(UndeleteFilesRequest { hashes })
|
|
|
|
self.post::<UndeleteFiles>(UndeleteFilesRequest { hashes })
|
|
|
|
.await?;
|
|
|
|
.await?;
|
|
|
|
|
|
|
|
|
|
|
@ -189,8 +206,8 @@ impl Client {
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/// Moves files from the inbox into the archive
|
|
|
|
/// Moves files from the inbox into the archive
|
|
|
|
|
|
|
|
#[tracing::instrument(skip(self), level = "debug")]
|
|
|
|
pub async fn archive_files(&self, hashes: Vec<String>) -> Result<()> {
|
|
|
|
pub async fn archive_files(&self, hashes: Vec<String>) -> Result<()> {
|
|
|
|
log::trace!("Archiving files {:?}", hashes);
|
|
|
|
|
|
|
|
self.post::<ArchiveFiles>(ArchiveFilesRequest { hashes })
|
|
|
|
self.post::<ArchiveFiles>(ArchiveFilesRequest { hashes })
|
|
|
|
.await?;
|
|
|
|
.await?;
|
|
|
|
|
|
|
|
|
|
|
@ -198,8 +215,8 @@ impl Client {
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/// Moves files from the archive into the inbox
|
|
|
|
/// Moves files from the archive into the inbox
|
|
|
|
|
|
|
|
#[tracing::instrument(skip(self), level = "debug")]
|
|
|
|
pub async fn unarchive_files(&self, hashes: Vec<String>) -> Result<()> {
|
|
|
|
pub async fn unarchive_files(&self, hashes: Vec<String>) -> Result<()> {
|
|
|
|
log::trace!("Unarchiving files {:?}", hashes);
|
|
|
|
|
|
|
|
self.post::<UnarchiveFiles>(UnarchiveFilesRequest { hashes })
|
|
|
|
self.post::<UnarchiveFiles>(UnarchiveFilesRequest { hashes })
|
|
|
|
.await?;
|
|
|
|
.await?;
|
|
|
|
|
|
|
|
|
|
|
@ -207,8 +224,8 @@ impl Client {
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/// 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
|
|
|
|
|
|
|
|
#[tracing::instrument(skip(self), level = "debug")]
|
|
|
|
pub async fn clean_tags(&self, tags: Vec<String>) -> Result<CleanTagsResponse> {
|
|
|
|
pub async fn clean_tags(&self, tags: Vec<String>) -> Result<CleanTagsResponse> {
|
|
|
|
log::trace!("Cleaning tags {:?}", tags);
|
|
|
|
|
|
|
|
self.get_and_parse::<CleanTags, [(&str, String)]>(&[(
|
|
|
|
self.get_and_parse::<CleanTags, [(&str, String)]>(&[(
|
|
|
|
"tags",
|
|
|
|
"tags",
|
|
|
|
string_list_to_json_array(tags),
|
|
|
|
string_list_to_json_array(tags),
|
|
|
@ -217,37 +234,47 @@ impl Client {
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/// Adds tags to files with the given hashes
|
|
|
|
/// Adds tags to files with the given hashes
|
|
|
|
|
|
|
|
#[tracing::instrument(skip(self), level = "debug")]
|
|
|
|
pub async fn add_tags(&self, request: AddTagsRequest) -> Result<()> {
|
|
|
|
pub async fn add_tags(&self, request: AddTagsRequest) -> Result<()> {
|
|
|
|
log::trace!("Adding tags {:?}", request);
|
|
|
|
|
|
|
|
self.post::<AddTags>(request).await?;
|
|
|
|
self.post::<AddTags>(request).await?;
|
|
|
|
|
|
|
|
|
|
|
|
Ok(())
|
|
|
|
Ok(())
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/// Searches for files in the inbox, the archive or both
|
|
|
|
/// Searches for files
|
|
|
|
|
|
|
|
#[tracing::instrument(skip(self), level = "debug")]
|
|
|
|
pub async fn search_files(
|
|
|
|
pub async fn search_files(
|
|
|
|
&self,
|
|
|
|
&self,
|
|
|
|
query: Vec<SearchQueryEntry>,
|
|
|
|
query: Vec<SearchQueryEntry>,
|
|
|
|
options: FileSearchOptions,
|
|
|
|
options: FileSearchOptions,
|
|
|
|
) -> Result<SearchFilesResponse> {
|
|
|
|
) -> Result<SearchFilesResponse> {
|
|
|
|
log::trace!("Searching for files with tags {:?}", query);
|
|
|
|
|
|
|
|
let mut args = options.into_query_args();
|
|
|
|
let mut args = options.into_query_args();
|
|
|
|
args.push(("tags", search_query_list_to_json_array(query)));
|
|
|
|
args.push(("tags", search_query_list_to_json_array(query)));
|
|
|
|
self.get_and_parse::<SearchFiles, [(&str, String)]>(&args)
|
|
|
|
self.get_and_parse::<SearchFiles, [(&str, String)]>(&args)
|
|
|
|
.await
|
|
|
|
.await
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/// Searches for file hashes
|
|
|
|
|
|
|
|
#[tracing::instrument(skip(self), level = "debug")]
|
|
|
|
|
|
|
|
pub async fn search_file_hashes(
|
|
|
|
|
|
|
|
&self,
|
|
|
|
|
|
|
|
query: Vec<SearchQueryEntry>,
|
|
|
|
|
|
|
|
options: FileSearchOptions,
|
|
|
|
|
|
|
|
) -> Result<SearchFileHashesResponse> {
|
|
|
|
|
|
|
|
let mut args = options.into_query_args();
|
|
|
|
|
|
|
|
args.push(("tags", search_query_list_to_json_array(query)));
|
|
|
|
|
|
|
|
args.push(("return_hashes", String::from("true")));
|
|
|
|
|
|
|
|
self.get_and_parse::<SearchFileHashes, [(&str, String)]>(&args)
|
|
|
|
|
|
|
|
.await
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/// Returns the metadata for a given list of file_ids or hashes
|
|
|
|
/// Returns the metadata for a given list of file_ids or hashes
|
|
|
|
|
|
|
|
#[tracing::instrument(skip(self), level = "debug")]
|
|
|
|
pub async fn get_file_metadata(
|
|
|
|
pub async fn get_file_metadata(
|
|
|
|
&self,
|
|
|
|
&self,
|
|
|
|
file_ids: Vec<u64>,
|
|
|
|
file_ids: Vec<u64>,
|
|
|
|
hashes: Vec<String>,
|
|
|
|
hashes: Vec<String>,
|
|
|
|
) -> Result<FileMetadataResponse> {
|
|
|
|
) -> Result<FileMetadataResponse> {
|
|
|
|
log::trace!(
|
|
|
|
|
|
|
|
"Getting file info for ids {:?} or hashes {:?}",
|
|
|
|
|
|
|
|
file_ids,
|
|
|
|
|
|
|
|
hashes
|
|
|
|
|
|
|
|
);
|
|
|
|
|
|
|
|
let query = if file_ids.len() > 0 {
|
|
|
|
let query = if file_ids.len() > 0 {
|
|
|
|
("file_ids", number_list_to_json_array(file_ids))
|
|
|
|
("file_ids", number_list_to_json_array(file_ids))
|
|
|
|
} else {
|
|
|
|
} else {
|
|
|
@ -258,11 +285,11 @@ impl Client {
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/// Returns the metadata for a single file identifier
|
|
|
|
/// Returns the metadata for a single file identifier
|
|
|
|
|
|
|
|
#[tracing::instrument(skip(self), level = "debug")]
|
|
|
|
pub async fn get_file_metadata_by_identifier(
|
|
|
|
pub async fn get_file_metadata_by_identifier(
|
|
|
|
&self,
|
|
|
|
&self,
|
|
|
|
id: FileIdentifier,
|
|
|
|
id: FileIdentifier,
|
|
|
|
) -> Result<FileMetadataInfo> {
|
|
|
|
) -> Result<FileMetadataInfo> {
|
|
|
|
log::trace!("Getting file metadata {:?}", id);
|
|
|
|
|
|
|
|
let mut response = match id.clone() {
|
|
|
|
let mut response = match id.clone() {
|
|
|
|
FileIdentifier::ID(id) => self.get_file_metadata(vec![id], vec![]).await?,
|
|
|
|
FileIdentifier::ID(id) => self.get_file_metadata(vec![id], vec![]).await?,
|
|
|
|
FileIdentifier::Hash(hash) => self.get_file_metadata(vec![], vec![hash]).await?,
|
|
|
|
FileIdentifier::Hash(hash) => self.get_file_metadata(vec![], vec![hash]).await?,
|
|
|
@ -275,8 +302,8 @@ impl Client {
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/// Returns the bytes of a file from hydrus
|
|
|
|
/// Returns the bytes of a file from hydrus
|
|
|
|
|
|
|
|
#[tracing::instrument(skip(self), level = "debug")]
|
|
|
|
pub async fn get_file(&self, id: FileIdentifier) -> Result<FileRecord> {
|
|
|
|
pub async fn get_file(&self, id: FileIdentifier) -> Result<FileRecord> {
|
|
|
|
log::trace!("Getting file {:?}", id);
|
|
|
|
|
|
|
|
let response = match id {
|
|
|
|
let response = match id {
|
|
|
|
FileIdentifier::ID(id) => {
|
|
|
|
FileIdentifier::ID(id) => {
|
|
|
|
self.get::<GetFile, [(&str, u64)]>(&[("file_id", id)])
|
|
|
|
self.get::<GetFile, [(&str, u64)]>(&[("file_id", id)])
|
|
|
@ -300,28 +327,31 @@ impl Client {
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/// Returns all files associated with the given url
|
|
|
|
/// Returns all files associated with the given url
|
|
|
|
pub async fn get_url_files<S: AsRef<str>>(&self, url: S) -> Result<GetUrlFilesResponse> {
|
|
|
|
#[tracing::instrument(skip(self), level = "debug")]
|
|
|
|
log::trace!("Getting files for url {}", url.as_ref());
|
|
|
|
pub async fn get_url_files<S: AsRef<str> + Debug>(
|
|
|
|
|
|
|
|
&self,
|
|
|
|
|
|
|
|
url: S,
|
|
|
|
|
|
|
|
) -> Result<GetUrlFilesResponse> {
|
|
|
|
self.get_and_parse::<GetUrlFiles, [(&str, &str)]>(&[("url", url.as_ref())])
|
|
|
|
self.get_and_parse::<GetUrlFiles, [(&str, &str)]>(&[("url", url.as_ref())])
|
|
|
|
.await
|
|
|
|
.await
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/// Returns information about the given url
|
|
|
|
/// Returns information about the given url
|
|
|
|
pub async fn get_url_info<S: AsRef<str>>(&self, url: S) -> Result<GetUrlInfoResponse> {
|
|
|
|
#[tracing::instrument(skip(self), level = "debug")]
|
|
|
|
log::trace!("Getting info for url {}", url.as_ref());
|
|
|
|
pub async fn get_url_info<S: AsRef<str> + Debug>(&self, url: S) -> Result<GetUrlInfoResponse> {
|
|
|
|
self.get_and_parse::<GetUrlInfo, [(&str, &str)]>(&[("url", url.as_ref())])
|
|
|
|
self.get_and_parse::<GetUrlInfo, [(&str, &str)]>(&[("url", url.as_ref())])
|
|
|
|
.await
|
|
|
|
.await
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/// Adds an url to hydrus, optionally with additional tags and a destination page
|
|
|
|
/// Adds an url to hydrus, optionally with additional tags and a destination page
|
|
|
|
|
|
|
|
#[tracing::instrument(skip(self), level = "debug")]
|
|
|
|
pub async fn add_url(&self, request: AddUrlRequest) -> Result<AddUrlResponse> {
|
|
|
|
pub async fn add_url(&self, request: AddUrlRequest) -> Result<AddUrlResponse> {
|
|
|
|
log::trace!("Adding url {:?}", request);
|
|
|
|
|
|
|
|
self.post_and_parse::<AddUrl>(request).await
|
|
|
|
self.post_and_parse::<AddUrl>(request).await
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/// Associates urls with the given file hashes
|
|
|
|
/// Associates urls with the given file hashes
|
|
|
|
|
|
|
|
#[tracing::instrument(skip(self), level = "debug")]
|
|
|
|
pub async fn associate_urls(&self, urls: Vec<String>, hashes: Vec<String>) -> Result<()> {
|
|
|
|
pub async fn associate_urls(&self, urls: Vec<String>, hashes: Vec<String>) -> Result<()> {
|
|
|
|
log::trace!("Associating urls {:?} with hashes {:?}", urls, hashes);
|
|
|
|
|
|
|
|
self.post::<AssociateUrl>(AssociateUrlRequest {
|
|
|
|
self.post::<AssociateUrl>(AssociateUrlRequest {
|
|
|
|
hashes,
|
|
|
|
hashes,
|
|
|
|
urls_to_add: urls,
|
|
|
|
urls_to_add: urls,
|
|
|
@ -333,8 +363,8 @@ impl Client {
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/// Disassociates urls with the given file hashes
|
|
|
|
/// Disassociates urls with the given file hashes
|
|
|
|
|
|
|
|
#[tracing::instrument(skip(self), level = "debug")]
|
|
|
|
pub async fn disassociate_urls(&self, urls: Vec<String>, hashes: Vec<String>) -> Result<()> {
|
|
|
|
pub async fn disassociate_urls(&self, urls: Vec<String>, hashes: Vec<String>) -> Result<()> {
|
|
|
|
log::trace!("Disassociating urls {:?} with hashes {:?}", urls, hashes);
|
|
|
|
|
|
|
|
self.post::<AssociateUrl>(AssociateUrlRequest {
|
|
|
|
self.post::<AssociateUrl>(AssociateUrlRequest {
|
|
|
|
hashes,
|
|
|
|
hashes,
|
|
|
|
urls_to_add: vec![],
|
|
|
|
urls_to_add: vec![],
|
|
|
@ -346,22 +376,25 @@ impl Client {
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/// Returns all pages of the client
|
|
|
|
/// Returns all pages of the client
|
|
|
|
|
|
|
|
#[tracing::instrument(skip(self), level = "debug")]
|
|
|
|
pub async fn get_pages(&self) -> Result<GetPagesResponse> {
|
|
|
|
pub async fn get_pages(&self) -> Result<GetPagesResponse> {
|
|
|
|
log::trace!("Getting pages");
|
|
|
|
|
|
|
|
self.get_and_parse::<GetPages, ()>(&()).await
|
|
|
|
self.get_and_parse::<GetPages, ()>(&()).await
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/// Returns information about a single page
|
|
|
|
/// Returns information about a single page
|
|
|
|
pub async fn get_page_info<S: AsRef<str>>(&self, page_key: S) -> Result<GetPageInfoResponse> {
|
|
|
|
#[tracing::instrument(skip(self), level = "debug")]
|
|
|
|
log::trace!("Getting information for page {}", page_key.as_ref());
|
|
|
|
pub async fn get_page_info<S: AsRef<str> + Debug>(
|
|
|
|
|
|
|
|
&self,
|
|
|
|
|
|
|
|
page_key: S,
|
|
|
|
|
|
|
|
) -> Result<GetPageInfoResponse> {
|
|
|
|
self.get_and_parse::<GetPageInfo, [(&str, &str)]>(&[("page_key", page_key.as_ref())])
|
|
|
|
self.get_and_parse::<GetPageInfo, [(&str, &str)]>(&[("page_key", page_key.as_ref())])
|
|
|
|
.await
|
|
|
|
.await
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/// Focuses a page in the client
|
|
|
|
/// Focuses a page in the client
|
|
|
|
pub async fn focus_page<S: ToString>(&self, page_key: S) -> Result<()> {
|
|
|
|
#[tracing::instrument(skip(self), level = "debug")]
|
|
|
|
|
|
|
|
pub async fn focus_page<S: ToString + Debug>(&self, page_key: S) -> Result<()> {
|
|
|
|
let page_key = page_key.to_string();
|
|
|
|
let page_key = page_key.to_string();
|
|
|
|
log::trace!("Focussing page {}", page_key);
|
|
|
|
|
|
|
|
self.post::<FocusPage>(FocusPageRequest { page_key })
|
|
|
|
self.post::<FocusPage>(FocusPageRequest { page_key })
|
|
|
|
.await?;
|
|
|
|
.await?;
|
|
|
|
|
|
|
|
|
|
|
@ -369,19 +402,14 @@ impl Client {
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/// Adds files to a page
|
|
|
|
/// Adds files to a page
|
|
|
|
pub async fn add_files_to_page<S: ToString>(
|
|
|
|
#[tracing::instrument(skip(self), level = "debug")]
|
|
|
|
|
|
|
|
pub async fn add_files_to_page<S: ToString + Debug>(
|
|
|
|
&self,
|
|
|
|
&self,
|
|
|
|
page_key: S,
|
|
|
|
page_key: S,
|
|
|
|
file_ids: Vec<u64>,
|
|
|
|
file_ids: Vec<u64>,
|
|
|
|
hashes: Vec<String>,
|
|
|
|
hashes: Vec<String>,
|
|
|
|
) -> Result<()> {
|
|
|
|
) -> Result<()> {
|
|
|
|
let page_key = page_key.to_string();
|
|
|
|
let page_key = page_key.to_string();
|
|
|
|
log::trace!(
|
|
|
|
|
|
|
|
"Adding files with ids {:?} or hashes {:?} to page {}",
|
|
|
|
|
|
|
|
file_ids,
|
|
|
|
|
|
|
|
hashes,
|
|
|
|
|
|
|
|
page_key
|
|
|
|
|
|
|
|
);
|
|
|
|
|
|
|
|
self.post::<AddFiles>(AddFilesRequest {
|
|
|
|
self.post::<AddFiles>(AddFilesRequest {
|
|
|
|
page_key,
|
|
|
|
page_key,
|
|
|
|
file_ids,
|
|
|
|
file_ids,
|
|
|
@ -393,8 +421,11 @@ impl Client {
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/// Returns all cookies for the given domain
|
|
|
|
/// Returns all cookies for the given domain
|
|
|
|
pub async fn get_cookies<S: AsRef<str>>(&self, domain: S) -> Result<GetCookiesResponse> {
|
|
|
|
#[tracing::instrument(skip(self), level = "debug")]
|
|
|
|
log::trace!("Getting cookies");
|
|
|
|
pub async fn get_cookies<S: AsRef<str> + Debug>(
|
|
|
|
|
|
|
|
&self,
|
|
|
|
|
|
|
|
domain: S,
|
|
|
|
|
|
|
|
) -> Result<GetCookiesResponse> {
|
|
|
|
self.get_and_parse::<GetCookies, [(&str, &str)]>(&[("domain", domain.as_ref())])
|
|
|
|
self.get_and_parse::<GetCookies, [(&str, &str)]>(&[("domain", domain.as_ref())])
|
|
|
|
.await
|
|
|
|
.await
|
|
|
|
}
|
|
|
|
}
|
|
|
@ -402,8 +433,8 @@ impl Client {
|
|
|
|
/// Sets some cookies for some websites.
|
|
|
|
/// Sets some cookies for some websites.
|
|
|
|
/// Each entry needs to be in the format `[<name>, <value>, <domain>, <path>, <expires>]`
|
|
|
|
/// Each entry needs to be in the format `[<name>, <value>, <domain>, <path>, <expires>]`
|
|
|
|
/// with the types `[String, String, String, String, u64]`
|
|
|
|
/// with the types `[String, String, String, String, u64]`
|
|
|
|
|
|
|
|
#[tracing::instrument(skip(self), level = "debug")]
|
|
|
|
pub async fn set_cookies(&self, cookies: Vec<[OptionalStringNumber; 5]>) -> Result<()> {
|
|
|
|
pub async fn set_cookies(&self, cookies: Vec<[OptionalStringNumber; 5]>) -> Result<()> {
|
|
|
|
log::trace!("Setting cookies {:?}", cookies);
|
|
|
|
|
|
|
|
self.post::<SetCookies>(SetCookiesRequest { cookies })
|
|
|
|
self.post::<SetCookies>(SetCookiesRequest { cookies })
|
|
|
|
.await?;
|
|
|
|
.await?;
|
|
|
|
|
|
|
|
|
|
|
@ -411,9 +442,9 @@ impl Client {
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/// Sets the user agent that is being used for every request hydrus starts
|
|
|
|
/// Sets the user agent that is being used for every request hydrus starts
|
|
|
|
pub async fn set_user_agent<S: ToString>(&self, user_agent: S) -> Result<()> {
|
|
|
|
#[tracing::instrument(skip(self), level = "debug")]
|
|
|
|
|
|
|
|
pub async fn set_user_agent<S: ToString + Debug>(&self, user_agent: S) -> Result<()> {
|
|
|
|
let user_agent = user_agent.to_string();
|
|
|
|
let user_agent = user_agent.to_string();
|
|
|
|
log::trace!("Setting user agent to {}", user_agent);
|
|
|
|
|
|
|
|
self.post::<SetUserAgent>(SetUserAgentRequest { user_agent })
|
|
|
|
self.post::<SetUserAgent>(SetUserAgentRequest { user_agent })
|
|
|
|
.await?;
|
|
|
|
.await?;
|
|
|
|
|
|
|
|
|
|
|
|