#![allow(non_snake_case)]
use crate::fs::RiFileSystem;
use crate::log::{RiLogConfig, RiLogger};
use crate::config::RiConfigManager;
use crate::hooks::RiHookBus;
use crate::core::RiResult;
use crate::observability::RiMetricsRegistry;
use std::sync::Arc;
#[derive(Clone)]
pub struct ServiceContextInner {
pub fs: RiFileSystem,
pub logger: Arc<RiLogger>,
pub config: Arc<RiConfigManager>,
pub hooks: Arc<RiHookBus>,
pub metrics_registry: Option<Arc<RiMetricsRegistry>>,
}
impl ServiceContextInner {
pub fn new(fs: RiFileSystem, logger: RiLogger, config: RiConfigManager, hooks: RiHookBus, metrics_registry: Option<Arc<RiMetricsRegistry>>) -> Self {
ServiceContextInner {
fs,
logger: Arc::new(logger),
config: Arc::new(config),
hooks: Arc::new(hooks),
metrics_registry
}
}
}
#[cfg_attr(feature = "pyo3", pyo3::prelude::pyclass)]
#[derive(Clone)]
pub struct RiServiceContext {
inner: ServiceContextInner,
}
impl RiServiceContext {
pub fn new_with(fs: RiFileSystem, logger: RiLogger, config: RiConfigManager, hooks: RiHookBus, metrics_registry: Option<Arc<RiMetricsRegistry>>) -> Self {
let inner = ServiceContextInner::new(fs, logger, config, hooks, metrics_registry);
RiServiceContext { inner }
}
pub fn new_default() -> RiResult<Self> {
let config = RiConfigManager::new_default();
let cfg = config.config();
let project_root = std::env::current_dir()
.map_err(|e| crate::core::RiError::Other(format!("detect project root failed: {e}")))?;
let app_data_root = if let Some(root_str) = cfg.get_str("fs.app_data_root") {
project_root.join(root_str)
} else {
project_root.join(".dms")
};
let fs = RiFileSystem::new_with_roots(project_root, app_data_root);
let log_config = RiLogConfig::from_config(&cfg);
let logger = RiLogger::new(&log_config, fs.clone());
let hooks = RiHookBus::new();
Ok(RiServiceContext::new_with(fs, logger, config, hooks, None))
}
pub fn fs(&self) -> &RiFileSystem {
&self.inner.fs
}
pub fn logger(&self) -> &RiLogger {
self.inner.logger.as_ref()
}
pub fn config(&self) -> Arc<RiConfigManager> {
self.inner.config.clone()
}
pub fn hooks(&self) -> Arc<RiHookBus> {
self.inner.hooks.clone()
}
pub fn hooks_mut(&mut self) -> &mut RiHookBus {
Arc::get_mut(&mut self.inner.hooks).expect("Cannot get mutable reference to hooks - shared ownership")
}
pub fn config_mut(&mut self) -> &mut RiConfigManager {
Arc::get_mut(&mut self.inner.config).expect("Cannot get mutable reference to config - shared ownership")
}
pub fn fs_mut(&mut self) -> &mut RiFileSystem {
&mut self.inner.fs
}
pub fn logger_mut(&mut self) -> &mut RiLogger {
Arc::get_mut(&mut self.inner.logger).expect("Cannot get mutable reference to logger - shared ownership")
}
pub fn metrics_registry(&self) -> Option<Arc<RiMetricsRegistry>> {
self.inner.metrics_registry.clone()
}
}
#[cfg(feature = "pyo3")]
#[pyo3::prelude::pymethods]
impl RiServiceContext {
#[new]
fn py_new() -> pyo3::PyResult<Self> {
match Self::new_default() {
Ok(ctx) => Ok(ctx),
Err(err) => Err(pyo3::exceptions::PyRuntimeError::new_err(format!("Failed to create service context: {err}"))),
}
}
#[pyo3(name = "fs")]
fn fs_py(&self) -> crate::fs::RiFileSystem {
self.inner.fs.clone()
}
#[pyo3(name = "logger")]
fn logger_py(&self) -> crate::log::RiLogger {
(*self.inner.logger).clone()
}
#[pyo3(name = "config")]
fn config_py(&self) -> crate::config::RiConfigManager {
(*self.inner.config).clone()
}
#[pyo3(name = "metrics_registry")]
fn metrics_registry_py(&self) -> Option<crate::observability::RiMetricsRegistry> {
self.inner.metrics_registry.as_ref().map(|r| (**r).clone())
}
#[pyo3(name = "hooks")]
fn hooks_py(&self) -> crate::hooks::RiHookBus {
crate::hooks::RiHookBus::new()
}
}