misskey_http/client/
builder.rs1use std::convert::TryInto;
2use std::result::Result as StdResult;
3
4use crate::client::HttpClient;
5use crate::error::{Error, Result};
6
7use isahc::http::{
8 self,
9 header::{HeaderMap, HeaderName, HeaderValue},
10};
11use url::Url;
12
13#[derive(Debug)]
14struct HttpClientBuilderInner {
15 url: Url,
16 token: Option<String>,
17 additional_headers: HeaderMap,
18}
19
20#[derive(Debug)]
22pub struct HttpClientBuilder {
23 inner: Result<HttpClientBuilderInner>,
24}
25
26trait ResultExt<T, E> {
27 fn err_into<U>(self) -> StdResult<T, U>
28 where
29 E: Into<U>;
30 fn and_then_mut<F>(&mut self, op: F)
31 where
32 F: FnOnce(&mut T) -> StdResult<(), E>;
33}
34
35impl<T, E> ResultExt<T, E> for StdResult<T, E> {
36 fn err_into<U>(self) -> StdResult<T, U>
37 where
38 E: Into<U>,
39 {
40 self.map_err(Into::into)
41 }
42
43 fn and_then_mut<F>(&mut self, f: F)
44 where
45 F: FnOnce(&mut T) -> StdResult<(), E>,
46 {
47 if let Ok(x) = self {
48 if let Err(e) = f(x) {
49 *self = Err(e);
50 }
51 }
52 }
53}
54
55impl HttpClientBuilder {
56 pub fn new<T>(url: T) -> Self
60 where
61 T: TryInto<Url>,
62 T::Error: Into<Error>,
63 {
64 let inner = url.try_into().err_into().map(|url| HttpClientBuilderInner {
65 url,
66 token: None,
67 additional_headers: HeaderMap::new(),
68 });
69 HttpClientBuilder { inner }
70 }
71
72 pub fn with_host<S>(host: S) -> Self
77 where
78 S: AsRef<str>,
79 {
80 let url = format!("https://{}/api/", host.as_ref());
81 HttpClientBuilder::new(url.as_str())
82 }
83
84 pub fn header<K, V>(mut self, key: K, value: V) -> Self
86 where
87 K: TryInto<HeaderName>,
88 V: TryInto<HeaderValue>,
89 K::Error: Into<http::Error>,
90 V::Error: Into<http::Error>,
91 {
92 self.inner.and_then_mut(|inner| {
93 let result = key.try_into().err_into().and_then(|key| {
94 let value = value.try_into().err_into()?;
95 Ok((key, value))
96 });
97 match result {
98 Ok((key, value)) => {
99 inner.additional_headers.insert(key, value);
100 Ok(())
101 }
102 Err(e) => Err(Error::Network(isahc::Error::InvalidHttpFormat(e))),
103 }
104 });
105 self
106 }
107
108 pub fn token<S>(mut self, token: S) -> Self
110 where
111 S: Into<String>,
112 {
113 self.inner.and_then_mut(|inner| {
114 inner.token = Some(token.into());
115 Ok(())
116 });
117 self
118 }
119
120 pub fn build(self) -> Result<HttpClient> {
122 self.inner.and_then(|inner| {
123 Ok(HttpClient {
124 url: inner.url,
125 token: inner.token,
126 client: isahc::HttpClientBuilder::new()
127 .default_headers(&inner.additional_headers)
128 .build()?,
129 })
130 })
131 }
132}