toonify/
toonify_file.rs

1/*
2 * Copyright 2022 XXIV
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 *     http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16use std::io::{ErrorKind, Read};
17use reqwest::blocking::multipart;
18use crate::error::ToonifyError;
19
20pub struct ToonifyFile {
21    #[doc(hidden)]
22    response: Result<std::string::String, String>
23}
24
25#[doc(hidden)]
26struct ToonifyFileInternal {
27    api_key: String,
28    image_file: String
29}
30
31impl ToonifyFile {
32
33    /// `image_file` Image file.
34    ///
35    /// `api_key` Toonify API key.
36    pub fn new(image_file: &str, api_key: &str) -> Self {
37        let internal = ToonifyFileInternal::new(image_file, api_key);
38        let response = internal.http();
39        Self {
40            response
41        }
42    }
43
44    #[doc(hidden)]
45    fn is_error(&self) -> Option<std::string::String> {
46        match self.response.clone() {
47            Ok(response) => match json::parse(&response) {
48                Ok(json) => if json.has_key("err") {
49                    Some(json["err"].to_string())
50                } else if json.has_key("status") {
51                    Some(json["status"].to_string())
52                } else {
53                    None
54                },
55                Err(_) => None
56            },
57            Err(err) => if err.is_empty() {
58                None
59            } else {
60                Some(err)
61            }
62        }
63    }
64
65    #[doc(hidden)]
66    fn json(&self, key: &str) -> Option<std::string::String> {
67        match self.response.clone() {
68            Ok(response) => match json::parse(&response) {
69                Ok(json) => if json.has_key(key) {
70                    Some(json[key].to_string())
71                } else {
72                    None
73                },
74                Err(_) => None
75            },
76            Err(_) => None
77        }
78    }
79
80    /// Return image URI.
81    pub fn image(&self) -> Result<std::string::String, ToonifyError> {
82        match self.is_error() {
83            Some(error) => Err(ToonifyError::Error(error)),
84            None => match self.json("output_url") {
85                Some(image) => Ok(image),
86                None => Err(ToonifyError::Null(String::from("null")))
87            }
88        }
89    }
90
91    /// Return image id.
92    pub fn id(&self) -> Result<std::string::String, ToonifyError> {
93        match self.is_error() {
94            Some(error) => Err(ToonifyError::Error(error)),
95            None => match self.json("id") {
96                Some(id) => Ok(id),
97                None => Err(ToonifyError::Null(String::from("null")))
98            }
99        }
100    }
101}
102
103impl ToonifyFileInternal {
104    fn new(image_file: &str, api_key: &str) -> Self {
105        Self {
106            api_key: api_key.to_string(),
107            image_file: image_file.to_string()
108        }
109    }
110
111    fn http(&self) -> Result<std::string::String, String> {
112        match multipart::Form::new().file("image", &self.image_file) {
113            Ok(form) => match reqwest::blocking::Client::new()
114                .post("https://api.deepai.org/api/toonify")
115                .header("api-key", self.api_key.clone())
116                .multipart(form)
117                .send() {
118                Ok(mut data) => {
119                    let mut body = std::string::String::new();
120                    match data.read_to_string(&mut body) {
121                        Ok(_) => Ok(body),
122                        Err(_) => Err("".to_string())
123                    }
124                },
125                Err(_) => Err("".to_string())
126            },
127            Err(err) => match err.kind() {
128                ErrorKind::NotFound => Err(err.to_string()),
129                _ => Err("".to_string())
130            }
131        }
132    }
133}