use rs_store::{DispatchOp, FnReducer, MiddlewareFn, MiddlewareFnFactory, StoreBuilder};
use std::sync::atomic::{AtomicU64, AtomicUsize};
use std::sync::Arc;
use std::time::Instant;
pub struct Metrics {
pub action_count: AtomicUsize,
pub action_executed: AtomicU64,
}
impl Metrics {
pub fn new() -> Self {
Self {
action_count: AtomicUsize::new(0),
action_executed: AtomicU64::new(0),
}
}
pub fn action_executed<Action>(
&self,
_action: Option<&Action>,
_duration: std::time::Duration,
) {
self.action_count.fetch_add(1, std::sync::atomic::Ordering::Relaxed);
self.action_executed.fetch_add(_duration.as_secs(), std::sync::atomic::Ordering::Relaxed);
}
}
#[allow(private_bounds)] #[allow(dead_code)]
pub struct MetricsMiddleware<State, Action>
where
State: Send + Sync + Clone,
Action: Send + Sync + Clone + std::fmt::Debug + 'static,
{
metrics: Arc<Metrics>,
name: String,
_phantom: std::marker::PhantomData<(State, Action)>,
}
#[allow(private_bounds)] impl<State, Action> MetricsMiddleware<State, Action>
where
State: Send + Sync + Clone,
Action: Send + Sync + Clone + std::fmt::Debug + 'static,
{
pub fn new(name: String) -> Self {
Self {
metrics: Arc::new(Metrics::new()),
name,
_phantom: std::marker::PhantomData,
}
}
}
impl<State, Action> MiddlewareFnFactory<State, Action> for MetricsMiddleware<State, Action>
where
State: Send + Sync + Clone + 'static,
Action: Send + Sync + Clone + std::fmt::Debug + 'static,
{
fn create(&self, inner: MiddlewareFn<State, Action>) -> MiddlewareFn<State, Action> {
let metrics = self.metrics.clone();
Arc::new(move |state: &State, action: &Action| {
let start_time = Instant::now();
let result = inner(state, action);
let duration = start_time.elapsed();
metrics.action_executed(Some(action), duration);
#[cfg(feature = "store-log")]
eprintln!(
"[MetricsMiddleware] Action executed: {:?}, Duration: {:?}",
action, duration
);
result
})
}
}
pub fn main() {
let metrics_middleware: MetricsMiddleware<String, String> =
MetricsMiddleware::new("example_metrics".to_string());
let reducer = Box::new(FnReducer::from(|state: &String, action: &String| {
let new_state = format!("{} + {}", state, action);
DispatchOp::Dispatch(new_state, vec![])
}));
let store_result = StoreBuilder::new("initial_state".to_string())
.with_reducer(reducer)
.with_middleware(Arc::new(metrics_middleware))
.build();
let store = store_result.unwrap();
store.dispatch("action_1".to_string()).unwrap();
store.stop().unwrap();
}