use std::collections::HashMap;
use std::fmt::{self, Debug, Display};
use reqwest::{Method, Url};
use serde::{self, Deserialize, Serialize};
use serde_json;
use crate::ucare::{encode_json, rest::Client, IntoUrlQuery, Result};
pub struct Service<'a> {
client: &'a Client,
}
pub fn new_svc(client: &Client) -> Service {
Service { client }
}
impl Service<'_> {
pub fn info(&self, file_id: &str) -> Result<Info> {
self.client.call::<String, String, Info>(
Method::GET,
format!("/files/{}/", file_id),
None,
None,
)
}
pub fn list(&self, params: ListParams) -> Result<List> {
self.client.call::<ListParams, String, List>(
Method::GET,
format!("/files/"),
Some(params),
None,
)
}
pub fn get_page(&self, url: &str) -> Result<List> {
let url = Url::parse(url)?;
self.client.call_url::<String, List>(Method::GET, url, None)
}
pub fn store(&self, file_id: &str) -> Result<Info> {
self.client.call::<String, String, Info>(
Method::PUT,
format!("/files/{}/storage/", file_id),
None,
None,
)
}
pub fn batch_store(&self, file_ids: &[&str]) -> Result<BatchInfo> {
let json = encode_json(&file_ids)?;
self.client.call::<String, Vec<u8>, BatchInfo>(
Method::PUT,
format!("/files/storage/"),
None,
Some(json),
)
}
pub fn delete(&self, file_id: &str) -> Result<Info> {
self.client.call::<String, String, Info>(
Method::DELETE,
format!("/files/{}/storage/", file_id),
None,
None,
)
}
pub fn batch_delete(&self, file_ids: &[&str]) -> Result<BatchInfo> {
let json = encode_json(&file_ids)?;
self.client.call::<String, Vec<u8>, BatchInfo>(
Method::DELETE,
format!("/files/storage/"),
None,
Some(json),
)
}
pub fn copy(&self, params: CopyParams) -> Result<LocalCopyInfo> {
let json = encode_json(¶ms)?;
self.client.call::<String, Vec<u8>, LocalCopyInfo>(
Method::POST,
format!("/files/"),
None,
Some(json),
)
}
pub fn local_copy(&self, mut params: CopyParams) -> Result<LocalCopyInfo> {
if let None = params.store {
params.store = Some(ToStore::False);
}
if let None = params.make_public {
params.make_public = Some(MakePublic::True);
}
let json = encode_json(¶ms)?;
self.client.call::<String, Vec<u8>, LocalCopyInfo>(
Method::POST,
format!("/files/local_copy/"),
None,
Some(json),
)
}
pub fn remote_copy(&self, mut params: CopyParams) -> Result<RemoteCopyInfo> {
if let None = params.make_public {
params.make_public = Some(MakePublic::True);
}
let json = encode_json(¶ms)?;
self.client.call::<String, Vec<u8>, RemoteCopyInfo>(
Method::POST,
format!("/files/remote_copy/"),
None,
Some(json),
)
}
}
#[derive(Debug, Deserialize)]
pub struct Info {
pub uuid: String,
pub datetime_removed: Option<String>,
pub datetime_stored: Option<String>,
pub datetime_uploaded: Option<String>,
pub image_info: Option<ImageInfo>,
pub is_image: Option<bool>,
pub is_ready: Option<bool>,
pub mime_type: Option<String>,
pub original_file_url: Option<String>,
pub original_filename: Option<String>,
pub size: Option<i32>,
pub url: Option<String>,
pub variations: Option<serde_json::Value>,
pub video_info: Option<VideoInfo>,
pub source: Option<String>,
pub rekognition_info: Option<HashMap<String, f32>>,
}
#[derive(Debug, Deserialize)]
pub struct ImageInfo {
pub color_mode: Option<ColorMode>,
pub orientation: Option<i32>,
pub format: Option<String>,
pub sequence: Option<bool>,
pub height: Option<i32>,
pub width: Option<i32>,
pub geo_location: Option<ImageInfoGeoLocation>,
pub datetime_original: Option<String>,
pub dpi: Option<Vec<f32>>,
}
#[derive(Debug, Deserialize)]
pub struct ImageInfoGeoLocation {
pub latitude: Option<f32>,
pub longitude: Option<f32>,
}
#[derive(Debug, Eq, PartialEq, Ord, PartialOrd, Hash, Deserialize)]
pub enum ColorMode {
RGB,
RGBA,
RGBa,
RGBX,
L,
LA,
La,
P,
PA,
CMYK,
YCbCr,
HSV,
LAB,
}
#[derive(Debug, PartialEq, Deserialize)]
pub struct VideoInfo {
pub duration: Option<f32>,
pub format: Option<String>,
pub bitrate: Option<f32>,
pub audio: Option<VideoInfoAudio>,
pub video: Option<VideoInfoVideo>,
}
#[derive(Debug, PartialEq, Deserialize)]
pub struct VideoInfoAudio {
pub bitrate: Option<f32>,
pub codec: Option<String>,
pub sample_rate: Option<f32>,
pub channels: Option<String>,
}
#[derive(Debug, PartialEq, Deserialize)]
pub struct VideoInfoVideo {
pub height: Option<f32>,
pub width: Option<f32>,
pub frame_rate: Option<f32>,
pub bitrate: Option<f32>,
pub codec: Option<String>,
}
pub struct ListParams {
pub removed: Option<bool>,
pub stored: Option<bool>,
pub limit: Option<i32>,
pub ordering: Option<Ordering>,
pub from: Option<String>,
}
pub enum Ordering {
DatetimeUploaded,
DatetimeUploadedNeg,
Size,
SizeNeg,
}
impl Display for Ordering {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
let val = match *self {
Ordering::DatetimeUploaded => "datetime_uploaded",
Ordering::DatetimeUploadedNeg => "-datetime_uploaded",
Ordering::Size => "size",
Ordering::SizeNeg => "-size",
};
write!(f, "{}", val)
}
}
impl IntoUrlQuery for ListParams {
fn into_query(self) -> String {
let mut q = String::new();
q.push_str("removed=");
if let Some(val) = self.removed {
q.push_str(val.to_string().as_str());
} else {
q.push_str("false");
}
q.push('&');
if let Some(val) = self.stored {
q.push_str("stored=");
q.push_str(val.to_string().as_str());
q.push('&');
}
q.push_str("limit=");
if let Some(val) = self.limit {
q.push_str(val.to_string().as_str());
} else {
q.push_str("1000");
}
q.push('&');
q.push_str("ordering=");
if let Some(val) = self.ordering {
q.push_str(val.to_string().as_str());
} else {
q.push_str(Ordering::DatetimeUploaded.to_string().as_str());
}
if let Some(val) = self.from {
q.push('&');
q.push_str("from=");
q.push_str(val.as_str());
}
q
}
}
#[derive(Debug, Deserialize)]
pub struct List {
pub results: Option<Vec<Info>>,
pub next: Option<String>,
pub previous: Option<String>,
pub total: Option<i32>,
pub per_page: Option<i32>,
}
#[derive(Debug, Eq, PartialEq, Ord, PartialOrd, Hash, Serialize)]
pub enum ToStore {
#[serde(rename = "true")]
True,
#[serde(rename = "false")]
False,
}
#[derive(Debug, Eq, PartialEq, Ord, PartialOrd, Hash, Serialize)]
pub enum MakePublic {
#[serde(rename = "true")]
True,
#[serde(rename = "false")]
False,
}
#[derive(Debug, Eq, PartialEq, Ord, PartialOrd, Hash, Serialize)]
pub enum Pattern {
#[serde(rename = "${default}")]
Default,
#[serde(rename = "${filename} ${effects} ${ext}")]
AutoFilename,
#[serde(rename = "${effects}")]
Effects,
#[serde(rename = "${filename}")]
Filename,
#[serde(rename = "${uuid}")]
Uuid,
#[serde(rename = "${ext}")]
Ext,
}
#[derive(Debug, PartialEq, Serialize)]
pub struct CopyParams {
pub source: String,
#[serde(skip_serializing_if = "Option::is_none")]
pub store: Option<ToStore>,
#[serde(skip_serializing_if = "Option::is_none")]
pub make_public: Option<MakePublic>,
#[serde(skip_serializing_if = "Option::is_none")]
pub target: Option<String>,
#[serde(skip_serializing_if = "Option::is_none")]
pub pattern: Option<Pattern>,
}
#[derive(Debug, Deserialize)]
pub struct LocalCopyInfo {
pub result: Info,
}
#[derive(Debug, Deserialize)]
pub struct RemoteCopyInfo {
#[serde(skip_deserializing)]
pub already_exists: bool,
pub result: Option<String>,
}
#[derive(Debug, Deserialize)]
pub struct BatchInfo {
pub problems: Option<HashMap<String, String>>,
pub result: Option<Vec<Info>>,
}