Skip to main content

remendo/config/
remote.rs

1//! Remote Sashiko instance configuration.
2
3use serde::Deserialize;
4
5/// Default request timeout in seconds.
6const fn default_timeout() -> u64 {
7    15
8}
9
10/// Default maximum retry count.
11const fn default_retries() -> u32 {
12    3
13}
14
15/// Configuration for a single remote Sashiko instance.
16///
17/// Each remote represents an independent Sashiko deployment
18/// that the TUI can connect to as a separate "mailbox."
19#[derive(Debug, Clone, PartialEq, Eq, Deserialize)]
20pub struct RemoteConfig {
21    /// Human-readable name for this remote (used in the sidebar).
22    pub name: String,
23    /// Base URL of the Sashiko instance (e.g., `"https://sashiko.dev"`).
24    pub url: String,
25    /// Environment variable name containing an auth token (optional).
26    /// The env var **name** is stored, not the token itself.
27    #[serde(default)]
28    pub auth_env: Option<String>,
29    /// Request timeout in seconds. Defaults to 15.
30    #[serde(default = "default_timeout")]
31    pub timeout_seconds: u64,
32    /// Maximum number of retries on transient failures. Defaults to 3.
33    #[serde(default = "default_retries")]
34    pub max_retries: u32,
35}
36
37impl RemoteConfig {
38    /// Create a fixture `RemoteConfig` with the given name for testing.
39    #[cfg(any(test, feature = "test-support"))]
40    #[must_use]
41    pub fn fixture(name: &str) -> Self {
42        Self {
43            name: name.to_string(),
44            url: format!("https://{name}.example.com"),
45            auth_env: None,
46            timeout_seconds: 15,
47            max_retries: 3,
48        }
49    }
50}
51
52#[cfg(test)]
53#[allow(clippy::expect_used)]
54mod tests {
55    use super::*;
56
57    #[test]
58    fn deserialize_remote_with_defaults() {
59        let toml_str = r#"
60            name = "upstream"
61            url = "https://sashiko.dev"
62        "#;
63        let remote: RemoteConfig = toml::from_str(toml_str).expect("parse remote");
64        assert_eq!(remote.name, "upstream");
65        assert_eq!(remote.url, "https://sashiko.dev");
66        assert_eq!(remote.timeout_seconds, 15);
67        assert_eq!(remote.max_retries, 3);
68        assert!(remote.auth_env.is_none());
69    }
70
71    #[test]
72    fn deserialize_remote_with_overrides() {
73        let toml_str = r#"
74            name = "staging"
75            url = "https://staging.sashiko.dev"
76            auth_env = "SASHIKO_TOKEN"
77            timeout_seconds = 30
78            max_retries = 5
79        "#;
80        let remote: RemoteConfig = toml::from_str(toml_str).expect("parse remote overrides");
81        assert_eq!(remote.timeout_seconds, 30);
82        assert_eq!(remote.max_retries, 5);
83        assert_eq!(remote.auth_env.as_deref(), Some("SASHIKO_TOKEN"));
84    }
85}