Download codex-rs/app-server-daemon/src/settings.rs from SaylorTwift/codex: direct link, hf CLI and curl.
- Browser
- Download file 6.13 kB
-
https://huggingface.co/SaylorTwift/codex/resolve/main/codex-rs/app-server-daemon/src/settings.rs
- Command line
-
hf download hf://SaylorTwift/codex/codex-rs/app-server-daemon/src/settings.rs
-
curl -L -o settings.rs https://huggingface.co/SaylorTwift/codex/resolve/main/codex-rs/app-server-daemon/src/settings.rs
6.13 kB
| use std::path::Path; | |
| use std::time::Duration; | |
| use anyhow::Context; | |
| use anyhow::Result; | |
| use anyhow::ensure; | |
| use serde::Deserialize; | |
| use serde::de::DeserializeOwned; | |
| use serde_json::Map; | |
| use serde_json::Value; | |
| use tokio::fs; | |
| pub(crate) const DEFAULT_UPDATE_INTERVAL_MINUTES: u32 = 60; | |
| pub(crate) const DEFAULT_SHUTDOWN_GRACE_SECONDS: u32 = 60; | |
| pub(crate) const MAX_SHUTDOWN_GRACE_SECONDS: u32 = 5 * 60; | |
| pub(crate) struct DaemonSettings { | |
| pub(crate) remote_control_enabled: bool, | |
| pub(crate) auto_update_enabled: bool, | |
| pub(crate) update_interval_minutes: u32, | |
| pub(crate) shutdown_grace_seconds: u32, | |
| } | |
| impl Default for DaemonSettings { | |
| fn default() -> Self { | |
| Self { | |
| remote_control_enabled: false, | |
| auto_update_enabled: true, | |
| update_interval_minutes: DEFAULT_UPDATE_INTERVAL_MINUTES, | |
| shutdown_grace_seconds: DEFAULT_SHUTDOWN_GRACE_SECONDS, | |
| } | |
| } | |
| } | |
| struct StopSettings { | |
| shutdown_grace_seconds: Option<u32>, | |
| } | |
| struct StoredSettings { | |
| remote_control_enabled: bool, | |
| shutdown_grace_seconds: u32, | |
| updater: UpdaterSettings, | |
| } | |
| impl Default for StoredSettings { | |
| fn default() -> Self { | |
| Self { | |
| remote_control_enabled: false, | |
| shutdown_grace_seconds: DEFAULT_SHUTDOWN_GRACE_SECONDS, | |
| updater: UpdaterSettings::default(), | |
| } | |
| } | |
| } | |
| pub(crate) struct UpdaterSettings { | |
| pub(crate) auto_update_enabled: bool, | |
| pub(crate) update_interval_minutes: u32, | |
| } | |
| impl Default for UpdaterSettings { | |
| fn default() -> Self { | |
| Self { | |
| auto_update_enabled: default_auto_update_enabled(), | |
| update_interval_minutes: default_update_interval_minutes(), | |
| } | |
| } | |
| } | |
| fn default_auto_update_enabled() -> bool { | |
| true | |
| } | |
| fn default_update_interval_minutes() -> u32 { | |
| DEFAULT_UPDATE_INTERVAL_MINUTES | |
| } | |
| fn default_shutdown_grace_seconds() -> u32 { | |
| DEFAULT_SHUTDOWN_GRACE_SECONDS | |
| } | |
| fn validate_shutdown_grace(seconds: u32) -> Result<()> { | |
| ensure!( | |
| seconds <= MAX_SHUTDOWN_GRACE_SECONDS, | |
| "shutdown grace must be between 0 and {MAX_SHUTDOWN_GRACE_SECONDS} seconds" | |
| ); | |
| Ok(()) | |
| } | |
| impl UpdaterSettings { | |
| pub(crate) async fn load(settings_file: &Path) -> Result<Self> { | |
| let settings: StoredSettings = read_settings(settings_file).await?; | |
| validate_shutdown_grace(settings.shutdown_grace_seconds)?; | |
| let settings = settings.updater; | |
| settings.validate()?; | |
| Ok(settings) | |
| } | |
| pub(crate) fn validate(&self) -> Result<()> { | |
| ensure!( | |
| self.update_interval_minutes > 0, | |
| "update interval must be positive" | |
| ); | |
| Ok(()) | |
| } | |
| pub(crate) fn update_interval(&self, minute: Duration) -> Duration { | |
| minute * self.update_interval_minutes | |
| } | |
| } | |
| impl DaemonSettings { | |
| pub(crate) async fn load(path: &Path) -> Result<Self> { | |
| let settings: StoredSettings = read_settings(path).await?; | |
| settings.updater.validate()?; | |
| validate_shutdown_grace(settings.shutdown_grace_seconds)?; | |
| Ok(Self { | |
| remote_control_enabled: settings.remote_control_enabled, | |
| auto_update_enabled: settings.updater.auto_update_enabled, | |
| update_interval_minutes: settings.updater.update_interval_minutes, | |
| shutdown_grace_seconds: settings.shutdown_grace_seconds, | |
| }) | |
| } | |
| pub(crate) async fn load_for_stop(path: &Path) -> Self { | |
| // Stop must work even when settings are unreadable or partially edited. | |
| let shutdown_grace_seconds = read_settings::<StopSettings>(path) | |
| .await | |
| .ok() | |
| .and_then(|settings| settings.shutdown_grace_seconds) | |
| .filter(|&seconds| seconds <= MAX_SHUTDOWN_GRACE_SECONDS) | |
| .unwrap_or(DEFAULT_SHUTDOWN_GRACE_SECONDS); | |
| Self { | |
| shutdown_grace_seconds, | |
| ..Self::default() | |
| } | |
| } | |
| pub(crate) async fn save(&self, path: &Path) -> Result<()> { | |
| if let Some(parent) = path.parent() { | |
| fs::create_dir_all(parent).await.with_context(|| { | |
| format!( | |
| "failed to create daemon settings directory {}", | |
| parent.display() | |
| ) | |
| })?; | |
| } | |
| let mut settings: Map<String, Value> = read_settings(path).await?; | |
| settings.insert( | |
| "remoteControlEnabled".to_string(), | |
| Value::Bool(self.remote_control_enabled), | |
| ); | |
| let contents = | |
| serde_json::to_vec_pretty(&settings).context("failed to serialize settings")?; | |
| let temporary_path = path.with_extension("tmp"); | |
| fs::write(&temporary_path, contents) | |
| .await | |
| .with_context(|| { | |
| format!( | |
| "failed to write daemon settings {}", | |
| temporary_path.display() | |
| ) | |
| })?; | |
| fs::rename(&temporary_path, path) | |
| .await | |
| .with_context(|| format!("failed to replace daemon settings {}", path.display())) | |
| } | |
| } | |
| async fn read_settings<T: DeserializeOwned + Default>(path: &Path) -> Result<T> { | |
| let contents = match fs::read_to_string(path).await { | |
| Ok(contents) => contents, | |
| Err(err) if err.kind() == std::io::ErrorKind::NotFound => return Ok(T::default()), | |
| Err(err) => { | |
| return Err(err).with_context(|| format!("failed to read settings {}", path.display())); | |
| } | |
| }; | |
| serde_json::from_str(&contents) | |
| .with_context(|| format!("failed to parse settings {}", path.display())) | |
| } | |
| mod tests; | |