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