Skip to main content

moonpool_sim/runner/
context.rs

1//! Simulation context for workloads.
2//!
3//! [`SimContext`] is the single entry point for workloads to access simulation
4//! infrastructure: providers, topology, shared state, and shutdown signaling.
5//!
6//! # Usage
7//!
8//! ```ignore
9//! use moonpool_sim::SimContext;
10//!
11//! async fn my_workload(ctx: &SimContext) -> SimulationResult<()> {
12//!     let server_ip = ctx.peer("server").expect("server not found");
13//!     let stream = ctx.network().connect(&server_ip).await?;
14//!     ctx.state().publish("connected", true);
15//!     Ok(())
16//! }
17//! ```
18
19use crate::chaos::state_handle::StateHandle;
20use crate::network::SimNetworkProvider;
21use crate::providers::{SimProviders, SimRandomProvider, SimTimeProvider};
22use crate::storage::SimStorageProvider;
23
24use moonpool_core::{Providers, TokioTaskProvider};
25
26use super::topology::WorkloadTopology;
27
28/// Simulation context provided to workloads.
29///
30/// Wraps all simulation infrastructure into a single, non-generic struct.
31/// For code generic over `P: Providers`, pass `ctx.providers()`.
32pub struct SimContext {
33    providers: SimProviders,
34    topology: WorkloadTopology,
35    state: StateHandle,
36}
37
38impl SimContext {
39    /// Create a new simulation context.
40    pub fn new(providers: SimProviders, topology: WorkloadTopology, state: StateHandle) -> Self {
41        Self {
42            providers,
43            topology,
44            state,
45        }
46    }
47
48    /// Get the full providers bundle for passing to generic code.
49    pub fn providers(&self) -> &SimProviders {
50        &self.providers
51    }
52
53    /// Get the simulated network provider.
54    pub fn network(&self) -> &SimNetworkProvider {
55        self.providers.network()
56    }
57
58    /// Get the simulated time provider.
59    pub fn time(&self) -> &SimTimeProvider {
60        self.providers.time()
61    }
62
63    /// Get the task provider.
64    pub fn task(&self) -> &TokioTaskProvider {
65        self.providers.task()
66    }
67
68    /// Get the seeded random provider.
69    pub fn random(&self) -> &SimRandomProvider {
70        self.providers.random()
71    }
72
73    /// Get the simulated storage provider.
74    pub fn storage(&self) -> &SimStorageProvider {
75        self.providers.storage()
76    }
77
78    /// Get this workload's IP address.
79    pub fn my_ip(&self) -> &str {
80        &self.topology.my_ip
81    }
82
83    /// Find a peer's IP address by workload name.
84    pub fn peer(&self, name: &str) -> Option<String> {
85        self.topology.get_peer_by_name(name)
86    }
87
88    /// Get all peers as (name, ip) pairs.
89    pub fn peers(&self) -> Vec<(String, String)> {
90        self.topology
91            .peer_names
92            .iter()
93            .zip(self.topology.peer_ips.iter())
94            .map(|(name, ip)| (name.clone(), ip.clone()))
95            .collect()
96    }
97
98    /// Get the shutdown cancellation token.
99    pub fn shutdown(&self) -> &tokio_util::sync::CancellationToken {
100        &self.topology.shutdown_signal
101    }
102
103    /// Get the shared state handle for cross-workload communication.
104    pub fn state(&self) -> &StateHandle {
105        &self.state
106    }
107}