use std::borrow::Cow;
use std::collections::HashMap;
use serde::{Deserialize, Serialize};
use super::Format;
#[derive(Debug)]
pub enum Input<'a, 'b> {
Single(Cow<'a, str>),
List(Cow<'b, [Cow<'a, str>]>),
}
impl<'a, 'b> Input<'a, 'b> {
pub fn into_static(self) -> Input<'static, 'static> {
match self {
Input::Single(Cow::Owned(s)) => Input::Single(Cow::Owned(s)),
Input::Single(Cow::Borrowed(s)) => Input::Single(Cow::Owned(s.to_string())),
Input::List(Cow::Owned(items)) => Input::List(Cow::Owned(
items
.into_iter()
.map(Cow::into_owned)
.map(Cow::Owned)
.collect(),
)),
Input::List(Cow::Borrowed(items)) => Input::List(Cow::Owned(
items
.iter()
.map(std::ops::Deref::deref)
.map(str::to_string)
.map(Cow::Owned)
.collect(),
)),
}
}
}
impl<'a, 'b> Serialize for Input<'a, 'b> {
fn serialize<S: serde::Serializer>(&self, serializer: S) -> Result<S::Ok, S::Error> {
match self {
Input::Single(item) => serializer.serialize_str(item),
Input::List(items) => Serialize::serialize(items, serializer),
}
}
}
impl<'a, 'b> From<&'a str> for Input<'a, 'b> {
fn from(s: &'a str) -> Input<'a, 'b> {
Input::Single(Cow::Borrowed(s))
}
}
impl<'a, 'b> From<String> for Input<'a, 'b> {
fn from(s: String) -> Input<'a, 'b> {
Input::Single(Cow::Owned(s))
}
}
impl<'a, 'b, T: AsRef<str>> From<&'a T> for Input<'a, 'b> {
fn from(s: &'a T) -> Input<'a, 'b> {
Input::Single(Cow::Borrowed(s.as_ref()))
}
}
impl<'a, 'b> From<Vec<String>> for Input<'a, 'b> {
fn from(items: Vec<String>) -> Input<'a, 'b> {
Input::List(Cow::Owned(items.into_iter().map(Cow::Owned).collect()))
}
}
impl<'a, 'b> From<&'a [String]> for Input<'a, 'b> {
fn from(items: &'a [String]) -> Input<'a, 'b> {
Input::List(Cow::Owned(
items
.iter()
.map(std::ops::Deref::deref)
.map(Cow::Borrowed)
.collect(),
))
}
}
impl<'a, 'b, 'c: 'a> From<&'c [&'a str]> for Input<'a, 'b> {
fn from(items: &'c [&'a str]) -> Input<'a, 'b> {
Input::List(Cow::Owned(
items.iter().map(|item| Cow::Borrowed(*item)).collect(),
))
}
}
impl<'a, 'b> From<Vec<Cow<'a, str>>> for Input<'a, 'b> {
fn from(items: Vec<Cow<'a, str>>) -> Input<'a, 'b> {
Input::List(Cow::Owned(items))
}
}
impl<'a, 'b> From<&'b [Cow<'a, str>]> for Input<'a, 'b> {
fn from(items: &'b [Cow<'a, str>]) -> Input<'a, 'b> {
Input::List(Cow::Borrowed(items))
}
}
macro_rules! make_task_types {
(__field_type opt: $field_type:ty) => {
Option<$field_type>
};
(__field_type req: $field_type:ty) => {
$field_type
};
(
$(#[$task_enum_meta:meta])*
$enum_vis:vis enum $Task:ident<'a>;
$(
$(#[$task_meta:meta])*
$struct_vis:vis struct $TaskName:ident<'a> {
operation: $operation:expr,
$(
$(#[$req_field_meta:meta])*
req $req_field_name:ident: $req_field_type:ty,
)*
$(
opt $opt_field_name:ident: $opt_field_type:ty,
)*
}
)*
) => {
$(#[$task_enum_meta])*
$enum_vis enum $Task<'a> {
$(
$TaskName($TaskName<'a>),
)*
}
impl<'a> $Task<'a> {
pub fn operation(&self) -> &'static str {
match self {
$($Task::$TaskName(_) => $operation,)*
}
}
pub fn to_job_task(&self) -> serde_json::Result<serde_json::Value> {
match self {
$($Task::$TaskName(task) => task.to_job_task(),)*
}
}
}
$(
$(#[$task_meta])*
#[derive(serde::Serialize, Debug)]
$struct_vis struct $TaskName<'a> {
$(
$(#[$req_field_meta])*
$struct_vis $req_field_name: make_task_types!(__field_type req: $req_field_type),
)*
$(
#[serde(skip_serializing_if = "Option::is_none")]
$struct_vis $opt_field_name: make_task_types!(__field_type opt: $opt_field_type),
)*
}
hapic::json_api_call!(json <'a> ($crate::ApiCall) $operation: $TaskName<'a> as $TaskName<'a> => TasksOutput as Status);
impl<'a> From<$TaskName<'a>> for $Task<'a> {
fn from(task: $TaskName<'a>) -> $Task<'a> {
$Task::$TaskName(task)
}
}
impl<'a> $TaskName<'a> {
pub fn to_job_task(&self) -> serde_json::Result<serde_json::Value> {
let task = self;
let mut value = serde_json::to_value(task)?;
match &mut value {
serde_json::Value::Object(value) => {
value.insert(
"operation".to_string(),
serde_json::Value::String($operation.to_string()),
);
},
_ => unreachable!(),
}
Ok(value)
}
}
)*
}
}
impl<'a> Task<'a> {
pub fn task_uri(&self, endpoint: &str) -> String {
format!("{endpoint}/{}", self.operation())
}
}
make_task_types!(
pub enum Task<'a>;
pub struct ImportUrl<'a> {
operation: "import/url",
req url: Cow<'a, str>,
opt filename: Cow<'a, str>,
opt headers: HashMap<String, String>,
}
pub struct ImportS3<'a> {
operation: "import/s3",
req bucket: Cow<'a, str>,
req region: Cow<'a, str>,
req access_key_id: Cow<'a, str>,
req secret_access_key: Cow<'a, str>,
opt endpoint: Cow<'a, str>,
opt key: Cow<'a, str>,
opt key_prefix: Cow<'a, str>,
opt session_token: Cow<'a, str>,
opt filename: Cow<'a, str>,
}
pub struct ImportAzureBlob<'a> {
operation: "import/azure/blob",
req storage_account: Cow<'a, str>,
req container: Cow<'a, str>,
opt storage_access_key: Cow<'a, str>,
opt sas_token: Cow<'a, str>,
opt blob: Cow<'a, str>,
opt blob_prefix: Cow<'a, str>,
opt filename: Cow<'a, str>,
}
pub struct ImportGoogleCloud<'a> {
operation: "import/google-cloud-storage",
req project_id: Cow<'a, str>,
req bucket: Cow<'a, str>,
req client_email: Cow<'a, str>,
req private_key: Cow<'a, str>,
opt file: Cow<'a, str>,
opt file_prefix: Cow<'a, str>,
opt filename: Cow<'a, str>,
}
pub struct ImportOpenStack<'a> {
operation: "import/openstack",
req auth_url: Cow<'a, str>,
req username: Cow<'a, str>,
req password: Cow<'a, str>,
req region: Cow<'a, str>,
req container: Cow<'a, str>,
opt tenant_name: Cow<'a, str>,
opt file: Cow<'a, str>,
opt file_prefix: Cow<'a, str>,
opt filename: Cow<'a, str>,
}
pub struct ImportSFTP<'a> {
operation: "import/sftp",
req host: Cow<'a, str>,
req username: Cow<'a, str>,
req password: Cow<'a, str>,
opt port: u16,
opt private_key: Cow<'a, str>,
opt file: Cow<'a, str>,
opt path: Cow<'a, str>,
opt filename: Cow<'a, str>,
}
pub struct Convert<'a> {
operation: "convert",
req input: Input<'a, 'a>,
req output_format: Format,
opt input_format: Format,
opt filename: Cow<'a, str>,
opt engine: Cow<'a, str>,
opt engine_version: Cow<'a, str>,
opt timeout: u32,
}
pub struct Optimize<'a> {
operation: "optimize",
req input: Input<'a, 'a>,
opt input_format: Format,
opt profile: OptimizationProfile,
opt flatten_signatures: bool,
opt colorspace: Colorspace,
opt filename: Cow<'a, str>,
opt engine: Cow<'a, str>,
opt engine_version: Cow<'a, str>,
opt timeout: u32,
}
pub struct Watermark<'a> {
operation: "watermark",
req input: Input<'a, 'a>,
opt input_format: Format,
opt pages: Cow<'a, str>,
opt layer: WatermarkLayer,
opt text: Cow<'a, str>,
opt font_size: u16,
opt font_width_percent: u8,
opt font_color: Cow<'a, str>,
opt font_name: Cow<'a, str>,
opt font_align: FontAlign,
opt image: Cow<'a, str>,
opt image_width: u32,
opt image_width_percent: u8,
opt position_vertical: VerticalPosition,
opt position_horizontal: HorizontalPosition,
opt margin_vertical: u32,
opt opacity: u8,
opt rotation: u16,
opt filename: Cow<'a, str>,
opt engine: Cow<'a, str>,
opt engine_version: Cow<'a, str>,
opt timeout: u32,
}
pub struct Thumbnail<'a> {
operation: "thumbnail",
req input: Cow<'a, str>,
req output_format: Format,
opt input_format: Format,
opt width: u32,
opt height: u32,
opt fit: ThumbnailFit,
opt count: u32,
opt timestamp: Cow<'a, str>,
opt filename: Cow<'a, str>,
opt engine: Cow<'a, str>,
opt engine_version: Cow<'a, str>,
opt timeout: u32,
}
pub struct Merge<'a> {
operation: "merge",
req input: Input<'a, 'a>,
req output_format: Format,
opt filename: Cow<'a, str>,
opt engine: Cow<'a, str>,
opt engine_version: Cow<'a, str>,
opt timeout: u32,
}
pub struct Archive<'a> {
operation: "archive",
req input: Input<'a, 'a>,
req output_format: Format,
opt filename: Cow<'a, str>,
opt engine: Cow<'a, str>,
opt engine_version: Cow<'a, str>,
opt timeout: u32,
}
pub struct Capture<'a> {
operation: "capture-website",
req url: Cow<'a, str>,
req output_format: Format,
req print_background: bool,
req display_header_footer: bool,
#[serde(skip_serializing_if = "HashMap::is_empty")]
req headers: HashMap<String, String>,
opt pages: Cow<'a, str>,
opt zoom: f32,
opt page_width: f32,
opt page_height: f32,
opt margin_top: f32,
opt margin_bottom: f32,
opt margin_left: f32,
opt header_template: Cow<'a, str>,
opt footer_template: Cow<'a, str>,
opt wait_until: CaptureWaitUntil,
opt wait_for_element: Cow<'a, str>,
opt wait_time: u32,
opt css_media_type: CssMediaType,
opt filename: HashMap<String, String>,
opt engine: Cow<'a, str>,
opt engine_version: Cow<'a, str>,
opt timeout: u32,
}
pub struct ExportUrl<'a> {
operation: "export/url",
req input: Input<'a, 'a>,
req inline: bool,
req archive_multiple_files: bool,
}
pub struct ExportS3<'a> {
operation: "export/s3",
req input: Input<'a, 'a>,
req bucket: Cow<'a, str>,
req region: Cow<'a, str>,
req access_key_id: Cow<'a, str>,
req secret_access_key: Cow<'a, str>,
opt endpoint: Cow<'a, str>,
opt key: Cow<'a, str>,
opt key_prefix: Cow<'a, str>,
opt session_token: Cow<'a, str>,
opt acl: Cow<'a, str>,
opt cache_control: Cow<'a, str>,
opt content_disposition: Cow<'a, str>,
opt content_type: Cow<'a, str>,
opt metadata: serde_json::Value,
opt server_side_encrpytion: Cow<'a, str>,
opt tagging: serde_json::Value,
}
pub struct ExportAzureBlob<'a> {
operation: "export/azure/blob",
req input: Input<'a, 'a>,
req storage_account: Cow<'a, str>,
req container: Cow<'a, str>,
opt storage_access_key: Cow<'a, str>,
opt sas_token: Cow<'a, str>,
opt blob: Cow<'a, str>,
opt blob_prefix: Cow<'a, str>,
opt metadata: serde_json::Value,
}
pub struct ExportGoogleCloud<'a> {
operation: "export/google-cloud-storage",
req input: Input<'a, 'a>,
req project_id: Cow<'a, str>,
req bucket: Cow<'a, str>,
req client_email: Cow<'a, str>,
req private_key: Cow<'a, str>,
opt file: Cow<'a, str>,
opt file_prefix: Cow<'a, str>,
}
pub struct ExportOpenStack<'a> {
operation: "export/openstack",
req input: Input<'a, 'a>,
req auth_url: Cow<'a, str>,
req username: Cow<'a, str>,
req password: Cow<'a, str>,
req region: Cow<'a, str>,
req container: Cow<'a, str>,
opt tenant_name: Cow<'a, str>,
opt file: Cow<'a, str>,
opt file_prefix: Cow<'a, str>,
}
pub struct ExportSFTP<'a> {
operation: "export/sftp",
req input: Input<'a, 'a>,
req host: Cow<'a, str>,
req username: Cow<'a, str>,
opt port: u16,
opt password: Cow<'a, str>,
opt private_key: Cow<'a, str>,
opt file: Cow<'a, str>,
opt path: Cow<'a, str>,
}
);
#[derive(Debug, Serialize, PartialEq, Eq)]
pub enum FontAlign {
#[serde(rename = "left")]
Left,
#[serde(rename = "right")]
Right,
#[serde(rename = "center")]
Center,
}
#[derive(Debug, Serialize, PartialEq, Eq)]
pub enum WatermarkLayer {
#[serde(rename = "above")]
Above,
#[serde(rename = "below")]
Below,
}
#[derive(Debug, Serialize, PartialEq, Eq)]
pub enum VerticalPosition {
#[serde(rename = "left")]
Left,
#[serde(rename = "right")]
Right,
#[serde(rename = "center")]
Center,
}
#[derive(Debug, Serialize, PartialEq, Eq)]
pub enum HorizontalPosition {
#[serde(rename = "top")]
Top,
#[serde(rename = "bottom")]
Bottom,
#[serde(rename = "center")]
Center,
}
#[derive(Debug, Serialize, PartialEq, Eq)]
pub enum ThumbnailFit {
#[serde(rename = "max")]
Max,
#[serde(rename = "crop")]
Crop,
#[serde(rename = "scale")]
Scale,
}
#[derive(Debug, Serialize, PartialEq, Eq)]
pub enum OptimizationProfile {
#[serde(rename = "web")]
Web,
#[serde(rename = "print")]
Print,
#[serde(rename = "archive")]
Archive,
#[serde(rename = "mrc")]
Mrc,
#[serde(rename = "max")]
Max,
}
#[derive(Debug, Serialize, PartialEq, Eq)]
pub enum Colorspace {
#[serde(rename = "unchanged")]
Unchanged,
#[serde(rename = "rgb")]
RGB,
#[serde(rename = "cmyk")]
CMYK,
#[serde(rename = "greyscale")]
Greyscale,
}
#[derive(Debug, Serialize, PartialEq, Eq)]
pub enum CaptureWaitUntil {
#[serde(rename = "Load")]
Load,
#[serde(rename = "domcontentloaded")]
DOMContentLoaded,
#[serde(rename = "networkidle0")]
NetworkIdle0,
#[serde(rename = "networkidle2")]
NetworkIdle2,
}
#[derive(Debug, Serialize, PartialEq, Eq)]
pub enum CssMediaType {
#[serde(rename = "print")]
Print,
#[serde(rename = "screen")]
Screen,
}
#[doc(hidden)]
#[derive(Deserialize)]
pub struct TasksOutput {
pub data: Status,
}
impl From<TasksOutput> for Status {
fn from(output: TasksOutput) -> Status {
output.data
}
}
#[derive(Debug, Deserialize)]
pub struct Status {
pub id: String,
#[serde(default)]
pub job_id: Option<String>,
#[serde(default)]
pub name: Option<String>,
pub operation: String,
pub status: super::Status,
#[serde(default)]
#[serde(rename = "message")]
pub status_message: Option<String>,
#[serde(default)]
#[serde(rename = "code")]
pub error_code: Option<String>,
#[serde(default)]
#[serde(rename = "code")]
pub credits: Option<u16>,
#[serde(default)]
pub retry_of_task_id: Option<String>,
#[serde(default)]
pub retries: Vec<String>,
#[serde(default)]
pub engine: Option<String>,
#[serde(default)]
pub engine_version: Option<String>,
#[serde(default)]
pub payload: serde_json::Value,
#[serde(default)]
pub result: Option<HashMap<String, serde_json::Value>>,
#[serde(default)]
pub links: Option<HashMap<String, String>>,
}