firebase_rs_sdk/remote_config/
settings.rs

1//! Remote Config settings surface.
2//!
3//! Mirrors the configuration exposed by the Firebase JS SDK (`RemoteConfigSettings`) with
4//! validation tailored for the Rust API.
5
6use crate::remote_config::error::{invalid_argument, RemoteConfigResult};
7
8/// Default timeout for fetch operations (60 seconds).
9pub const DEFAULT_FETCH_TIMEOUT_MILLIS: u64 = 60_000;
10/// Default minimum interval between successful fetches (12 hours).
11pub const DEFAULT_MINIMUM_FETCH_INTERVAL_MILLIS: u64 = 12 * 60 * 60 * 1_000;
12
13/// Configuration options for Remote Config fetch behaviour.
14#[derive(Clone, Debug, PartialEq, Eq)]
15pub struct RemoteConfigSettings {
16    fetch_timeout_millis: u64,
17    minimum_fetch_interval_millis: u64,
18}
19
20impl RemoteConfigSettings {
21    /// Creates a new settings object after validating values.
22    pub fn new(
23        fetch_timeout_millis: u64,
24        minimum_fetch_interval_millis: u64,
25    ) -> RemoteConfigResult<Self> {
26        validate_fetch_timeout(fetch_timeout_millis)?;
27        validate_minimum_fetch_interval(minimum_fetch_interval_millis)?;
28        Ok(Self {
29            fetch_timeout_millis,
30            minimum_fetch_interval_millis,
31        })
32    }
33
34    /// Returns the fetch timeout in milliseconds.
35    pub fn fetch_timeout_millis(&self) -> u64 {
36        self.fetch_timeout_millis
37    }
38
39    /// Returns the minimum fetch interval in milliseconds.
40    pub fn minimum_fetch_interval_millis(&self) -> u64 {
41        self.minimum_fetch_interval_millis
42    }
43
44    pub(crate) fn set_fetch_timeout_millis(&mut self, value: u64) -> RemoteConfigResult<()> {
45        validate_fetch_timeout(value)?;
46        self.fetch_timeout_millis = value;
47        Ok(())
48    }
49
50    pub(crate) fn set_minimum_fetch_interval_millis(
51        &mut self,
52        value: u64,
53    ) -> RemoteConfigResult<()> {
54        validate_minimum_fetch_interval(value)?;
55        self.minimum_fetch_interval_millis = value;
56        Ok(())
57    }
58}
59
60impl Default for RemoteConfigSettings {
61    fn default() -> Self {
62        Self {
63            fetch_timeout_millis: DEFAULT_FETCH_TIMEOUT_MILLIS,
64            minimum_fetch_interval_millis: DEFAULT_MINIMUM_FETCH_INTERVAL_MILLIS,
65        }
66    }
67}
68
69/// Partial update to apply on top of existing settings.
70#[derive(Clone, Debug, Default, PartialEq, Eq)]
71pub struct RemoteConfigSettingsUpdate {
72    pub fetch_timeout_millis: Option<u64>,
73    pub minimum_fetch_interval_millis: Option<u64>,
74}
75
76impl RemoteConfigSettingsUpdate {
77    pub fn is_empty(&self) -> bool {
78        self.fetch_timeout_millis.is_none() && self.minimum_fetch_interval_millis.is_none()
79    }
80}
81
82pub(crate) fn validate_fetch_timeout(value: u64) -> RemoteConfigResult<()> {
83    if value == 0 {
84        return Err(invalid_argument(
85            "fetch_timeout_millis must be greater than zero",
86        ));
87    }
88    Ok(())
89}
90
91pub(crate) fn validate_minimum_fetch_interval(_value: u64) -> RemoteConfigResult<()> {
92    // The JS SDK accepts zero to disable throttling; non-negative constraint is encoded in the type.
93    Ok(())
94}
95
96#[cfg(test)]
97mod tests {
98    use super::*;
99
100    #[test]
101    fn defaults_align_with_js_sdk() {
102        let defaults = RemoteConfigSettings::default();
103        assert_eq!(
104            defaults.fetch_timeout_millis(),
105            DEFAULT_FETCH_TIMEOUT_MILLIS
106        );
107        assert_eq!(
108            defaults.minimum_fetch_interval_millis(),
109            DEFAULT_MINIMUM_FETCH_INTERVAL_MILLIS
110        );
111    }
112
113    #[test]
114    fn new_validates_fetch_timeout() {
115        assert!(RemoteConfigSettings::new(1, 0).is_ok());
116        let err = RemoteConfigSettings::new(0, 0).unwrap_err();
117        assert_eq!(err.code_str(), "remote-config/invalid-argument");
118    }
119
120    #[test]
121    fn update_is_empty_when_no_values() {
122        let update = RemoteConfigSettingsUpdate::default();
123        assert!(update.is_empty());
124    }
125}