1use crate::{
6 backend::get_backend,
7 header_names::USER_AGENT,
8 settings::{validate_request, GLOBAL_SETTINGS},
9 Request, Response, Result,
10};
11
12#[derive(Default)]
14pub struct Client {
15 settings: ClientSettings,
16}
17
18impl Client {
19 pub fn new(mut settings: ClientSettings) -> Self {
20 settings.update_from_global_settings();
21 Self { settings }
22 }
23
24 #[cfg(feature = "ohttp")]
26 pub fn with_ohttp_channel(
27 channel: &str,
28 settings: ClientSettings,
29 ) -> Result<Self, crate::ViaductError> {
30 if !crate::ohttp::is_ohttp_channel_configured(channel) {
31 return Err(crate::ViaductError::OhttpChannelNotConfigured(
32 channel.to_string(),
33 ));
34 }
35 let mut client_settings = settings;
36 client_settings.ohttp_channel = Some(channel.to_string());
37 Ok(Self::new(client_settings))
38 }
39
40 fn set_user_agent(&self, request: &mut Request) -> Result<()> {
41 if let Some(user_agent) = &self.settings.user_agent {
42 request.headers.insert_if_missing(USER_AGENT, user_agent)?;
43 }
44 Ok(())
45 }
46
47 pub async fn send(&self, mut request: Request) -> Result<Response> {
48 validate_request(&request)?;
49 self.set_user_agent(&mut request)?;
50
51 #[cfg(feature = "ohttp")]
53 if let Some(channel) = &self.settings.ohttp_channel {
54 crate::debug!(
55 "Client configured for OHTTP channel '{}', processing request via OHTTP",
56 channel
57 );
58 return crate::ohttp::process_ohttp_request(request, channel, self.settings.clone())
59 .await;
60 }
61
62 crate::debug!("Processing request via standard backend");
64 get_backend()?
65 .send_request(request, self.settings.clone())
66 .await
67 }
68
69 pub fn send_sync(&self, request: Request) -> Result<Response> {
70 pollster::block_on(self.send(request))
71 }
72}
73
74#[derive(Debug, uniffi::Record, Clone)]
75#[repr(C)]
76pub struct ClientSettings {
77 #[uniffi(default = 60_000)]
79 pub timeout: u32,
80 #[uniffi(default = 10)]
82 pub redirect_limit: u32,
83 #[cfg(feature = "ohttp")]
85 pub ohttp_channel: Option<String>,
86 #[uniffi(default = None)]
91 pub user_agent: Option<String>,
92}
93
94impl ClientSettings {
95 pub fn update_from_global_settings(&mut self) {
96 let settings = GLOBAL_SETTINGS.read();
97 if self.user_agent.is_none() {
98 self.user_agent = settings.default_user_agent.clone();
99 }
100 }
101}
102
103impl Default for ClientSettings {
104 fn default() -> Self {
105 Self {
106 timeout: 60000,
107 redirect_limit: 10,
108 user_agent: None,
109 #[cfg(feature = "ohttp")]
110 ohttp_channel: None,
111 }
112 }
113}
114
115#[cfg(test)]
116mod test {
117 use url::Url;
118
119 use super::*;
120 use crate::settings;
121
122 #[test]
123 fn test_user_agent() {
124 let mut req = Request::get(Url::parse("http://example.com/").unwrap());
125 let client = Client::new(ClientSettings::default());
127 client.set_user_agent(&mut req).unwrap();
128 assert_eq!(req.headers.get(USER_AGENT), None);
129 settings::set_global_default_user_agent("global-user-agent".into());
131 let client = Client::new(ClientSettings::default());
132 let mut req = Request::get(Url::parse("http://example.com/").unwrap());
133 client.set_user_agent(&mut req).unwrap();
134 assert_eq!(req.headers.get(USER_AGENT), Some("global-user-agent"));
135 let client = Client::new(ClientSettings {
137 user_agent: Some("client-settings-user-agent".into()),
138 ..ClientSettings::default()
139 });
140 let mut req = Request::get(Url::parse("http://example.com/").unwrap());
141 client.set_user_agent(&mut req).unwrap();
142 assert_eq!(
143 req.headers.get(USER_AGENT),
144 Some("client-settings-user-agent")
145 );
146 let mut req = Request::get(Url::parse("http://example.com/").unwrap());
148 req.headers
149 .insert(USER_AGENT, "request-user-agent")
150 .unwrap();
151 client.set_user_agent(&mut req).unwrap();
152 assert_eq!(req.headers.get(USER_AGENT), Some("request-user-agent"));
153 }
154}