1use std::time::Duration;
2
3use url::Url;
4
5use crate::error::KagiError;
6
7#[derive(Clone, Debug)]
8pub struct ClientConfig {
9 pub base_url: Url,
10 pub timeout: Duration,
11 pub user_agent: String,
12}
13
14impl Default for ClientConfig {
15 fn default() -> Self {
16 Self {
17 base_url: Url::parse("https://kagi.com").expect("static URL is valid"),
18 timeout: Duration::from_secs(20),
19 user_agent: format!("kagi-sdk-rust/{}", env!("CARGO_PKG_VERSION")),
20 }
21 }
22}
23
24impl ClientConfig {
25 pub fn with_base_url(mut self, base_url: Url) -> Self {
26 self.base_url = base_url;
27 self
28 }
29
30 pub fn with_timeout(mut self, timeout: Duration) -> Self {
31 self.timeout = timeout;
32 self
33 }
34
35 pub fn with_user_agent(mut self, user_agent: impl Into<String>) -> Self {
36 self.user_agent = user_agent.into();
37 self
38 }
39
40 pub(crate) fn validate(&self) -> Result<(), KagiError> {
41 if !matches!(self.base_url.scheme(), "http" | "https") {
42 return Err(KagiError::InvalidClientConfiguration {
43 reason: "base_url must use http or https".to_string(),
44 });
45 }
46
47 if self.timeout.is_zero() {
48 return Err(KagiError::InvalidClientConfiguration {
49 reason: "timeout must be greater than zero".to_string(),
50 });
51 }
52
53 if self.user_agent.trim().is_empty() {
54 return Err(KagiError::InvalidClientConfiguration {
55 reason: "user_agent cannot be empty".to_string(),
56 });
57 }
58
59 Ok(())
60 }
61}