opencode_sdk_rs/
config.rs1use std::{collections::HashMap, time::Duration};
2
3use http::HeaderMap;
4
5pub const DEFAULT_BASE_URL: &str = "http://localhost:54321";
7
8pub const DEFAULT_TIMEOUT: Duration = Duration::from_mins(1);
10
11pub const DEFAULT_MAX_RETRIES: u32 = 2;
13
14pub const ENV_BASE_URL: &str = "OPENCODE_BASE_URL";
16
17#[derive(Debug, Clone)]
23pub struct ClientOptions {
24 pub base_url: Option<String>,
26
27 pub timeout: Option<Duration>,
29
30 pub max_retries: Option<u32>,
32
33 pub default_headers: Option<HeaderMap>,
35
36 pub default_query: Option<HashMap<String, String>>,
38}
39
40impl Default for ClientOptions {
41 fn default() -> Self {
42 let base_url = std::env::var(ENV_BASE_URL).ok();
43
44 Self {
45 base_url,
46 timeout: None,
47 max_retries: None,
48 default_headers: None,
49 default_query: None,
50 }
51 }
52}
53
54impl ClientOptions {
55 #[must_use]
58 pub const fn empty() -> Self {
59 Self {
60 base_url: None,
61 timeout: None,
62 max_retries: None,
63 default_headers: None,
64 default_query: None,
65 }
66 }
67
68 #[must_use]
71 pub(crate) fn resolve_base_url(&self) -> &str {
72 self.base_url.as_deref().unwrap_or(DEFAULT_BASE_URL)
73 }
74
75 #[must_use]
76 pub(crate) fn resolve_timeout(&self) -> Duration {
77 self.timeout.unwrap_or(DEFAULT_TIMEOUT)
78 }
79
80 #[must_use]
81 pub(crate) fn resolve_max_retries(&self) -> u32 {
82 self.max_retries.unwrap_or(DEFAULT_MAX_RETRIES)
83 }
84
85 #[must_use]
86 pub(crate) fn resolve_default_headers(&self) -> HeaderMap {
87 self.default_headers.clone().unwrap_or_default()
88 }
89
90 #[must_use]
91 pub(crate) fn resolve_default_query(&self) -> HashMap<String, String> {
92 self.default_query.clone().unwrap_or_default()
93 }
94}
95
96#[cfg(test)]
97mod tests {
98 use super::*;
99
100 #[test]
101 fn empty_has_all_none() {
102 let opts = ClientOptions::empty();
103 assert!(opts.base_url.is_none());
104 assert!(opts.timeout.is_none());
105 assert!(opts.max_retries.is_none());
106 assert!(opts.default_headers.is_none());
107 assert!(opts.default_query.is_none());
108 }
109
110 #[test]
111 fn resolve_falls_back_to_defaults() {
112 let opts = ClientOptions::empty();
113 assert_eq!(opts.resolve_base_url(), DEFAULT_BASE_URL);
114 assert_eq!(opts.resolve_timeout(), DEFAULT_TIMEOUT);
115 assert_eq!(opts.resolve_max_retries(), DEFAULT_MAX_RETRIES);
116 assert!(opts.resolve_default_headers().is_empty());
117 assert!(opts.resolve_default_query().is_empty());
118 }
119
120 #[test]
121 fn resolve_uses_provided_values() {
122 let opts = ClientOptions {
123 base_url: Some("http://example.com".to_owned()),
124 timeout: Some(Duration::from_secs(30)),
125 max_retries: Some(5),
126 default_headers: None,
127 default_query: None,
128 };
129 assert_eq!(opts.resolve_base_url(), "http://example.com");
130 assert_eq!(opts.resolve_timeout(), Duration::from_secs(30));
131 assert_eq!(opts.resolve_max_retries(), 5);
132 }
133}