Skip to main content

hyperi_rustlib/output/
config.rs

1// Project:   hyperi-rustlib
2// File:      src/output/config.rs
3// Purpose:   File output sink configuration
4// Language:  Rust
5//
6// License:   BUSL-1.1
7// Copyright: (c) 2026 HYPERI PTY LIMITED
8
9//! Configuration for the file output sink.
10
11use std::path::PathBuf;
12
13use serde::{Deserialize, Serialize};
14
15use crate::io::{FileWriterConfig, RotationPeriod};
16
17/// File output sink configuration.
18///
19/// Writes raw NDJSON events to rotating files -- used for testing and
20/// bare-metal deployments where Kafka is not available.
21#[derive(Debug, Clone, Serialize, Deserialize)]
22#[serde(default)]
23pub struct FileOutputConfig {
24    /// Enable the file output sink.
25    pub enabled: bool,
26
27    /// Base directory for output files.
28    pub path: PathBuf,
29
30    /// Output filename (e.g. "events.ndjson").
31    pub filename: String,
32
33    /// File rotation period.
34    pub rotation: RotationPeriod,
35
36    /// Auto-cleanup files older than this many days.
37    pub max_age_days: u32,
38
39    /// Compress rotated files with flate2/gzip.
40    pub compress_rotated: bool,
41}
42
43impl Default for FileOutputConfig {
44    fn default() -> Self {
45        Self {
46            enabled: false,
47            path: PathBuf::from("/var/spool/dfe/output"),
48            filename: "events.ndjson".to_string(),
49            rotation: RotationPeriod::Hourly,
50            max_age_days: 7,
51            compress_rotated: true,
52        }
53    }
54}
55
56impl FileOutputConfig {
57    /// Convert to the shared `FileWriterConfig` for use with `NdjsonWriter`.
58    #[must_use]
59    pub fn to_writer_config(&self) -> FileWriterConfig {
60        FileWriterConfig {
61            path: self.path.clone(),
62            rotation: self.rotation,
63            max_age_days: self.max_age_days,
64            compress_rotated: self.compress_rotated,
65        }
66    }
67}
68
69#[cfg(test)]
70mod tests {
71    use super::*;
72
73    #[test]
74    fn test_defaults() {
75        let config = FileOutputConfig::default();
76        assert!(!config.enabled);
77        assert_eq!(config.path, PathBuf::from("/var/spool/dfe/output"));
78        assert_eq!(config.filename, "events.ndjson");
79        assert_eq!(config.rotation, RotationPeriod::Hourly);
80        assert_eq!(config.max_age_days, 7);
81        assert!(config.compress_rotated);
82    }
83
84    #[test]
85    fn test_serde_roundtrip() {
86        let config = FileOutputConfig {
87            enabled: true,
88            path: "/tmp/test-output".into(),
89            filename: "data.ndjson".into(),
90            rotation: RotationPeriod::Daily,
91            max_age_days: 30,
92            compress_rotated: false,
93        };
94        let json = serde_json::to_string(&config).expect("serialise");
95        let parsed: FileOutputConfig = serde_json::from_str(&json).expect("deserialise");
96        assert!(parsed.enabled);
97        assert_eq!(parsed.filename, "data.ndjson");
98        assert_eq!(parsed.rotation, RotationPeriod::Daily);
99    }
100}