1use crate::error::Error;
2use crate::prelude::*;
3use crate::support::*;
4use base64::engine::{general_purpose, Engine};
5pub use http_body_util::{BodyExt, Empty, Full};
6pub use hyper::{
7 body::{Body, Bytes},
8 client::conn::http1::handshake,
9 header::{HeaderMap, HeaderName, HeaderValue},
10 Method, Request, Uri,
11};
12pub use serde::{Deserialize, Serialize};
13use std::env;
14pub use tokio::{
15 io::{AsyncWriteExt, BufWriter},
16 net::TcpStream,
17};
18
19const BASE_URL: &str = "https://api.d-id.com";
20const AUTHORIZATION_HEADER: &str = "authorization";
21
22static HOST: &str = "host";
23static AUTHORITY: &str = "api.d-id.com";
24
25#[derive(Debug)]
26pub struct Client {
27 pub url: Uri,
28 pub method: Method,
29 pub headers: HeaderMap,
30}
31
32impl Client {
33 fn build_request<T: Body>(&self, body: T) -> Result<Request<T>> {
34 let mut req_builder = Request::builder()
35 .uri(self.url.clone())
36 .method(self.method.clone());
37
38 for (name, value) in self.headers.clone().iter() {
39 req_builder = req_builder.header(name, value);
40 }
41
42 let req = req_builder.body(body)?;
43
44 Ok(req)
45 }
46
47 pub fn format_address(&self) -> String {
48 let host = self.url.host().unwrap();
50 let addr = format!("{}:{}", host, "443");
51 addr
52 }
53
54 pub async fn send_request<T: Body + Send + 'static>(&self, body: T) -> Result<Bytes>
55 where
56 T::Data: Send,
57 T::Error: Into<Box<dyn std::error::Error + Send + Sync>>,
58 {
59 let req = self.build_request(body)?;
60 let stream = TcpStream::connect(self.format_address()).await?;
61 let tls_stream = async_native_tls::connect(self.url.host().unwrap(), stream).await?;
62 let io = TokioIo::new(tls_stream);
63 let (mut sender, conn) = handshake(io).await?;
64 tokio::task::spawn(async move {
65 if let Err(e) = conn.await {
66 eprintln!("connection error: {}", e);
67 }
68 });
69
70 let mut res = sender.send_request(req).await?;
71
72 if res.status().is_client_error() {
73 let w = Vec::new();
74 let mut writer = BufWriter::new(w);
75 while let Some(resulting_frame) = res.frame().await {
76 let frame = resulting_frame?;
77 if let Some(chunk) = frame.data_ref() {
78 writer.write_all(chunk).await?;
79 }
80 writer.flush().await?;
81 }
82
83 let err_value = serde_json::from_slice::<serde_json::Value>(&writer.into_inner())?;
84
85 return Err(Box::new(Error::ClientSendRequestError(err_value)));
86 }
87
88 let w = Vec::new();
89 let mut writer = BufWriter::new(w);
90 while let Some(resulting_frame) = res.frame().await {
91 let frame = resulting_frame?;
92 if let Some(chunk) = frame.data_ref() {
93 writer.write_all(chunk).await?;
94 }
95 writer.flush().await?;
96 }
97 Ok(Bytes::from(writer.into_inner()))
98 }
99}
100
101#[derive(Debug)]
102pub struct ClientBuilder {
103 pub url: Option<Uri>,
104 method: Option<Method>,
105 headers: Option<HeaderMap>,
106}
107
108impl ClientBuilder {
109 pub fn new() -> Result<Self> {
110 let mut cb = ClientBuilder::default();
111 let mut apikey = env::var("D_ID_API_KEY")?;
112 let b64 = general_purpose::STANDARD.encode(apikey.as_bytes());
113 apikey = format!("Basic {}", b64);
114 cb = cb.header(AUTHORIZATION_HEADER, &apikey)?;
115 Ok(cb)
116 }
117
118 pub fn path(mut self, path: impl Into<String>) -> Result<Self> {
119 let url = format!("{}{}", BASE_URL, path.into()).parse::<Uri>()?;
120 self.url = Some(url);
121 Ok(self)
122 }
123
124 pub fn method(mut self, method: impl Into<String>) -> Result<Self> {
125 let method = method.into().parse::<Method>()?;
126 self.method = Some(method);
127 Ok(self)
128 }
129
130 pub fn header(mut self, name: &str, value: &str) -> Result<Self> {
131 let header_name = name.parse::<HeaderName>()?;
132 let header_value = value.parse::<HeaderValue>()?;
133 self.headers
135 .as_mut()
136 .unwrap()
137 .append(header_name, header_value);
138 Ok(self)
139 }
140
141 pub fn build(self) -> Result<Client> {
142 let Some(url) = self.url else {
143 return Err(Box::new(Error::ClientBuildError(
144 "url is not set".to_string(),
145 )));
146 };
147
148 let method = self.method.unwrap_or(Method::GET);
149
150 Ok(Client {
151 url,
152 method,
153 headers: self.headers.unwrap(),
155 })
156 }
157}
158
159impl Default for ClientBuilder {
160 fn default() -> Self {
161 let host_header = HeaderName::from_static(HOST);
162 let authority_header = HeaderValue::from_static(AUTHORITY);
163 let mut headers = HeaderMap::new();
164 headers.append(host_header, authority_header);
165 Self {
166 url: None,
167 method: None,
168 headers: Some(headers),
169 }
170 }
171}