Skip to main content

codetether_agent/rlm/oracle/storage/manager/
mod.rs

1//! Core storage manager definition and constructors.
2//!
3//! [`OracleTraceStorage`] owns the local spool directory and an
4//! optional remote backend. Construction is via
5//! [`from_env_or_vault`](OracleTraceStorage::from_env_or_vault).
6//!
7//! # Examples
8//!
9//! ```ignore
10//! let storage = OracleTraceStorage::from_env_or_vault().await;
11//! ```
12
13mod internals;
14mod persist;
15
16use super::helpers::default_spool_dir;
17use super::remote::{MinioOracleRemote, OracleRemote};
18use crate::bus::s3_sink::BusS3SinkConfig;
19use std::path::PathBuf;
20use std::sync::Arc;
21
22pub(in super::super) const DEFAULT_MAX_SPOOL_BYTES: u64 = 500 * 1024 * 1024;
23
24/// Coordinates local-spool-first persistence with optional
25/// upload to a MinIO/S3 remote backend.
26///
27/// Every trace is atomically written to the spool directory.
28/// If a remote is configured, the record is uploaded and the
29/// local copy removed on success.
30///
31/// # Examples
32///
33/// ```ignore
34/// let storage = OracleTraceStorage::from_env_or_vault().await;
35/// let result = storage.persist_result(&oracle_result).await?;
36/// ```
37pub struct OracleTraceStorage {
38    pub(in super::super) spool_dir: PathBuf,
39    pub(in super::super) max_spool_bytes: u64,
40    pub(in super::super) remote: Option<Arc<dyn OracleRemote>>,
41}
42
43impl OracleTraceStorage {
44    /// Build from environment variables and Vault-backed MinIO
45    /// credentials, falling back to local-only mode on failure.
46    ///
47    /// # Examples
48    ///
49    /// ```ignore
50    /// let storage = OracleTraceStorage::from_env_or_vault().await;
51    /// ```
52    pub async fn from_env_or_vault() -> Self {
53        let spool_dir = default_spool_dir();
54        let max = std::env::var("CODETETHER_ORACLE_SPOOL_MAX_BYTES")
55            .ok()
56            .and_then(|v| v.parse().ok())
57            .unwrap_or(DEFAULT_MAX_SPOOL_BYTES);
58        let remote = match BusS3SinkConfig::from_env_or_vault().await {
59            Ok(cfg) => match MinioOracleRemote::from_bus_config(cfg) {
60                Ok(r) => Some(Arc::new(r) as Arc<dyn OracleRemote>),
61                Err(e) => {
62                    tracing::warn!(error = %e, "Remote init failed");
63                    None
64                }
65            },
66            Err(e) => {
67                tracing::warn!(error = %e, "Remote not configured");
68                None
69            }
70        };
71        Self {
72            spool_dir,
73            max_spool_bytes: max,
74            remote,
75        }
76    }
77
78    /// Construct with injected dependencies for testing.
79    #[cfg(test)]
80    pub(in super::super) fn new_for_test(
81        spool_dir: PathBuf,
82        max_spool_bytes: u64,
83        remote: Option<Arc<dyn OracleRemote>>,
84    ) -> Self {
85        Self {
86            spool_dir,
87            max_spool_bytes,
88            remote,
89        }
90    }
91}