d_id/
client.rs

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        // unwrap warranted because the client is always built with the BASE_URL
49        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        // unwrap() is warranted because self.headers has default headers set with one initial entry
134        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            // unwrap() is warranted because self.headers has default headers set with one intial entry
154            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}