Skip to content

Commit f2eb8dd

Browse files
committed
refactor: use xml for state artifacts instead of json
1 parent a178ca0 commit f2eb8dd

9 files changed

Lines changed: 81 additions & 52 deletions

File tree

Cargo.lock

Lines changed: 19 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

Cargo.toml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -29,6 +29,7 @@ nix = { version = "0.29", features = ["process", "signal", "user", "sched", "res
2929
regex = "1.7"
3030
reqwest = { version = "0.11", features = ["blocking"] }
3131
serde = { version = "1.0", features = ["derive"] }
32+
serde-xml-rs = "0.6"
3233
serde_json = "1.0"
3334
serde_yaml = "0.9"
3435
sha2 = "0.10"

docs/docs/how-it-works/state.md

Lines changed: 11 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -19,26 +19,31 @@ Runtime files systemg uses to track services.
1919
├── sysg.pid # Supervisor PID
2020
├── control.sock # Unix socket for IPC
2121
├── config_hint # Last config path
22-
├── pid.json # Service → PID mapping
23-
├── state.json # Service metadata
22+
├── pid.xml # Service → PID mapping
23+
├── state.xml # Service metadata
2424
└── logs/ # Service output
2525
```
2626

2727
## Key files
2828

29-
### pid.json
29+
### pid.xml
3030

3131
Maps services to process IDs:
3232

33-
```json
34-
{"services": {"web": 67235, "db": 67236}}
33+
```xml
34+
<PidFile>
35+
<services>
36+
<web>67235</web>
37+
<db>67236</db>
38+
</services>
39+
</PidFile>
3540
```
3641

3742
### config_hint
3843

3944
Stores the last config path so you don't need `--config` on every command.
4045

41-
### state.json
46+
### state.xml
4247

4348
Tracks service status, restart counts, and exit codes.
4449

src/constants.rs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -106,14 +106,14 @@ impl Ord for DaemonLock {
106106

107107
/// Name of the PID file stored in the state directory.
108108
/// Contains mappings of service names to process IDs.
109-
pub const PID_FILE_NAME: &str = "pid.json";
109+
pub const PID_FILE_NAME: &str = "pid.xml";
110110

111111
/// Lock file suffix for PID file to ensure exclusive access.
112112
pub const PID_LOCK_SUFFIX: &str = ".lock";
113113

114114
/// Name of the service state file stored in the state directory.
115115
/// Contains the current state and metadata for all managed services.
116-
pub const STATE_FILE_NAME: &str = "state.json";
116+
pub const STATE_FILE_NAME: &str = "state.xml";
117117

118118
// ============================================================================
119119
// Shell Execution Constants

src/cron.rs

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@ use chrono::{Local, Utc};
1212
use chrono_tz::Tz;
1313
use cron::Schedule;
1414
use serde::{Deserialize, Serialize};
15+
use serde_xml_rs;
1516
use tracing::{debug, info, warn};
1617

1718
use crate::{
@@ -472,7 +473,7 @@ pub struct CronStateFile {
472473
impl CronStateFile {
473474
/// Returns the path to the cron state file.
474475
fn path() -> PathBuf {
475-
runtime::state_dir().join("cron_state.json")
476+
runtime::state_dir().join("cron_state.xml")
476477
}
477478

478479
/// Saves the cron state to disk.
@@ -481,7 +482,7 @@ impl CronStateFile {
481482
if let Some(parent) = path.parent() {
482483
fs::create_dir_all(parent)?;
483484
}
484-
let data = serde_json::to_string_pretty(self).map_err(std::io::Error::other)?;
485+
let data = serde_xml_rs::to_string(self).map_err(std::io::Error::other)?;
485486

486487
use std::io::Write;
487488
let mut file = fs::File::create(&path)?;
@@ -498,7 +499,7 @@ impl CronStateFile {
498499
}
499500

500501
let raw = fs::read_to_string(path)?;
501-
let state = serde_json::from_str(&raw)
502+
let state = serde_xml_rs::from_str(&raw)
502503
.map_err(|err| std::io::Error::new(std::io::ErrorKind::InvalidData, err))?;
503504
Ok(state)
504505
}

src/daemon.rs

Lines changed: 29 additions & 27 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,7 @@ use std::{
2020
use fs2::FileExt;
2121
use reqwest::blocking::Client;
2222
use serde::{Deserialize, Serialize, de::Error as _};
23+
use serde_xml_rs;
2324
use serde_yaml;
2425
use sysinfo::{ProcessesToUpdate, System};
2526
use tracing::{debug, error, info, trace, warn};
@@ -179,7 +180,7 @@ impl PidFile {
179180
return Ok(Self::default());
180181
}
181182
let contents = fs::read_to_string(path)?;
182-
let pid_data = serde_json::from_str::<Self>(&contents)?;
183+
let pid_data = serde_xml_rs::from_str::<Self>(&contents)?;
183184
Ok(pid_data)
184185
}
185186

@@ -199,7 +200,7 @@ impl PidFile {
199200

200201
let path = Self::path();
201202
let contents = fs::read_to_string(&path)?;
202-
let pid_data = serde_json::from_str::<Self>(&contents)?;
203+
let pid_data = serde_xml_rs::from_str::<Self>(&contents)?;
203204
Ok(pid_data)
204205
}
205206

@@ -209,7 +210,7 @@ impl PidFile {
209210

210211
let path = Self::path();
211212
fs::create_dir_all(path.parent().unwrap())?;
212-
fs::write(&path, serde_json::to_string_pretty(self)?)?;
213+
fs::write(&path, serde_xml_rs::to_string(self)?)?;
213214
Ok(())
214215
}
215216

@@ -230,7 +231,7 @@ impl PidFile {
230231
let path = Self::path();
231232
if path.exists() {
232233
let contents = fs::read_to_string(&path)?;
233-
*self = serde_json::from_str::<Self>(&contents)?;
234+
*self = serde_xml_rs::from_str::<Self>(&contents)?;
234235
}
235236

236237
self.services.insert(service.to_string(), pid);
@@ -239,7 +240,7 @@ impl PidFile {
239240
}
240241

241242
fs::create_dir_all(path.parent().unwrap())?;
242-
fs::write(&path, serde_json::to_string_pretty(self)?)?;
243+
fs::write(&path, serde_xml_rs::to_string(self)?)?;
243244
Ok(())
244245
}
245246

@@ -250,15 +251,15 @@ impl PidFile {
250251
let path = Self::path();
251252
if path.exists() {
252253
let contents = fs::read_to_string(&path)?;
253-
*self = serde_json::from_str::<Self>(&contents)?;
254+
*self = serde_xml_rs::from_str::<Self>(&contents)?;
254255
}
255256

256257
if self.services.remove(service).is_none() {
257258
return Err(PidFileError::ServiceNotFound);
258259
}
259260

260261
fs::create_dir_all(path.parent().unwrap())?;
261-
fs::write(&path, serde_json::to_string_pretty(self)?)?;
262+
fs::write(&path, serde_xml_rs::to_string(self)?)?;
262263
Ok(())
263264
}
264265

@@ -269,15 +270,15 @@ impl PidFile {
269270
let path = Self::path();
270271
if path.exists() {
271272
let contents = fs::read_to_string(&path)?;
272-
*self = serde_json::from_str::<Self>(&contents)?;
273+
*self = serde_xml_rs::from_str::<Self>(&contents)?;
273274
}
274275

275276
if self.services.remove(service).is_none() {
276277
return Err(PidFileError::ServiceNotFound);
277278
}
278279
self.service_groups.remove(service);
279280
fs::create_dir_all(path.parent().unwrap())?;
280-
fs::write(&path, serde_json::to_string_pretty(self)?)?;
281+
fs::write(&path, serde_xml_rs::to_string(self)?)?;
281282
Ok(())
282283
}
283284

@@ -296,7 +297,7 @@ impl PidFile {
296297
let path = Self::path();
297298
if path.exists() {
298299
let contents = fs::read_to_string(&path)?;
299-
*self = serde_json::from_str::<Self>(&contents)?;
300+
*self = serde_xml_rs::from_str::<Self>(&contents)?;
300301
}
301302

302303
let child_pid = metadata.pid;
@@ -312,7 +313,7 @@ impl PidFile {
312313
self.spawn_metadata.insert(child_pid, metadata);
313314

314315
fs::create_dir_all(path.parent().unwrap())?;
315-
fs::write(&path, serde_json::to_string_pretty(self)?)?;
316+
fs::write(&path, serde_xml_rs::to_string(self)?)?;
316317
Ok(())
317318
}
318319

@@ -326,15 +327,15 @@ impl PidFile {
326327
let path = Self::path();
327328
if path.exists() {
328329
let contents = fs::read_to_string(&path)?;
329-
*self = serde_json::from_str::<Self>(&contents)?;
330+
*self = serde_xml_rs::from_str::<Self>(&contents)?;
330331
}
331332

332333
if let Some(metadata) = self.spawn_metadata.get_mut(&child_pid) {
333334
metadata.last_exit = Some(exit.clone());
334335
}
335336

336337
fs::create_dir_all(path.parent().unwrap())?;
337-
fs::write(&path, serde_json::to_string_pretty(self)?)?;
338+
fs::write(&path, serde_xml_rs::to_string(self)?)?;
338339
Ok(())
339340
}
340341

@@ -345,7 +346,7 @@ impl PidFile {
345346
let path = Self::path();
346347
if path.exists() {
347348
let contents = fs::read_to_string(&path)?;
348-
*self = serde_json::from_str::<Self>(&contents)?;
349+
*self = serde_xml_rs::from_str::<Self>(&contents)?;
349350
}
350351

351352
if let Some(parent_pid) = self.parent_map.remove(&child_pid)
@@ -360,7 +361,7 @@ impl PidFile {
360361
self.spawn_metadata.remove(&child_pid);
361362

362363
fs::create_dir_all(path.parent().unwrap())?;
363-
fs::write(&path, serde_json::to_string_pretty(self)?)?;
364+
fs::write(&path, serde_xml_rs::to_string(self)?)?;
364365
Ok(())
365366
}
366367

@@ -373,13 +374,13 @@ impl PidFile {
373374
let path = Self::path();
374375
if path.exists() {
375376
let contents = fs::read_to_string(&path)?;
376-
*self = serde_json::from_str::<Self>(&contents)?;
377+
*self = serde_xml_rs::from_str::<Self>(&contents)?;
377378
}
378379

379380
let removed = self.remove_spawn_subtree_in_memory(root_pid);
380381

381382
fs::create_dir_all(path.parent().unwrap())?;
382-
fs::write(&path, serde_json::to_string_pretty(self)?)?;
383+
fs::write(&path, serde_xml_rs::to_string(self)?)?;
383384

384385
Ok(removed)
385386
}
@@ -616,7 +617,7 @@ impl ServiceStateFile {
616617
}
617618

618619
let contents = fs::read_to_string(path)?;
619-
let state = serde_json::from_str::<Self>(&contents)?;
620+
let state = serde_xml_rs::from_str::<Self>(&contents)?;
620621
Ok(state)
621622
}
622623

@@ -626,7 +627,7 @@ impl ServiceStateFile {
626627
if let Some(parent) = path.parent() {
627628
fs::create_dir_all(parent)?;
628629
}
629-
fs::write(&path, serde_json::to_string_pretty(self)?)?;
630+
fs::write(&path, serde_xml_rs::to_string(self)?)?;
630631
Ok(())
631632
}
632633

@@ -2573,13 +2574,14 @@ impl Daemon {
25732574
)))
25742575
})?;
25752576

2576-
let state: BlueGreenState = serde_json::from_str(&content).map_err(|source| {
2577-
ProcessManagerError::ConfigParseError(serde_yaml::Error::custom(format!(
2578-
"Failed parsing blue/green state '{}': {}",
2579-
path.display(),
2580-
source
2581-
)))
2582-
})?;
2577+
let state: BlueGreenState =
2578+
serde_xml_rs::from_str(&content).map_err(|source| {
2579+
ProcessManagerError::ConfigParseError(serde_yaml::Error::custom(format!(
2580+
"Failed parsing blue/green state '{}': {}",
2581+
path.display(),
2582+
source
2583+
)))
2584+
})?;
25832585

25842586
if state.active_slot_index > 1 {
25852587
return Err(Self::config_error(format!(
@@ -2602,7 +2604,7 @@ impl Daemon {
26022604
if let Some(parent) = path.parent() {
26032605
fs::create_dir_all(parent)?;
26042606
}
2605-
let content = serde_json::to_string(&BlueGreenState { active_slot_index })
2607+
let content = serde_xml_rs::to_string(&BlueGreenState { active_slot_index })
26062608
.map_err(|source| {
26072609
ProcessManagerError::ConfigParseError(serde_yaml::Error::custom(
26082610
source.to_string(),

src/error.rs

Lines changed: 5 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
//! Error handling for systemg.
2+
use serde_xml_rs;
23
use thiserror::Error;
34

45
/// Defines all possible errors that can occur in the process manager.
@@ -145,9 +146,9 @@ pub enum PidFileError {
145146
#[error("Failed to read PID file: {0}")]
146147
ReadError(#[from] std::io::Error),
147148

148-
/// Error writing to a PID file.
149+
/// Error parsing XML PID file.
149150
#[error("Failed to parse PID file: {0}")]
150-
ParseError(#[from] serde_json::Error),
151+
ParseError(#[from] serde_xml_rs::Error),
151152

152153
/// Error writing to a PID file.
153154
#[error("Service not found in PID file")]
@@ -161,9 +162,9 @@ pub enum ServiceStateError {
161162
#[error("Failed to read service state file: {0}")]
162163
ReadError(#[from] std::io::Error),
163164

164-
/// Error parsing JSON contents of the state file.
165+
/// Error parsing XML contents of the state file.
165166
#[error("Failed to parse service state file: {0}")]
166-
ParseError(#[from] serde_json::Error),
167+
ParseError(#[from] serde_xml_rs::Error),
167168

168169
/// Attempted to update or remove a non-existent service entry.
169170
#[error("Service not found in state file")]

0 commit comments

Comments
 (0)