openzeppelin_relayer/models/
app_state.rs

1//! This module defines the `AppState` struct, which encapsulates the application's state.
2//! It includes various repositories and services necessary for the application's operation.
3//! The `AppState` provides methods to access these components in a thread-safe manner.
4use std::sync::Arc;
5
6use actix_web::web::ThinData;
7
8use crate::{
9    jobs::{JobProducer, JobProducerTrait},
10    models::{
11        NetworkRepoModel, NotificationRepoModel, RelayerRepoModel, SignerRepoModel,
12        TransactionRepoModel,
13    },
14    repositories::{
15        NetworkRepository, NetworkRepositoryStorage, NotificationRepositoryStorage,
16        PluginRepositoryStorage, PluginRepositoryTrait, RelayerRepository,
17        RelayerRepositoryStorage, Repository, SignerRepositoryStorage,
18        TransactionCounterRepositoryStorage, TransactionCounterTrait, TransactionRepository,
19        TransactionRepositoryStorage,
20    },
21};
22
23/// Represents the application state, holding various repositories and services
24/// required for the application's operation.
25#[derive(Clone, Debug)]
26pub struct AppState<
27    J: JobProducerTrait + Send + Sync + 'static,
28    RR: RelayerRepository + Repository<RelayerRepoModel, String> + Send + Sync + 'static,
29    TR: TransactionRepository + Repository<TransactionRepoModel, String> + Send + Sync + 'static,
30    NR: NetworkRepository + Repository<NetworkRepoModel, String> + Send + Sync + 'static,
31    NFR: Repository<NotificationRepoModel, String> + Send + Sync + 'static,
32    SR: Repository<SignerRepoModel, String> + Send + Sync + 'static,
33    TCR: TransactionCounterTrait + Send + Sync + 'static,
34    PR: PluginRepositoryTrait + Send + Sync + 'static,
35> {
36    /// Repository for managing relayer data.
37    pub relayer_repository: Arc<RR>,
38    /// Repository for managing transaction data.
39    pub transaction_repository: Arc<TR>,
40    /// Repository for managing signer data.
41    pub signer_repository: Arc<SR>,
42    /// Repository for managing notification data.
43    pub notification_repository: Arc<NFR>,
44    /// Repository for managing network data.
45    pub network_repository: Arc<NR>,
46    /// Store for managing transaction counters.
47    pub transaction_counter_store: Arc<TCR>,
48    /// Producer for managing job creation and execution.
49    pub job_producer: Arc<J>,
50    /// Repository for managing plugins.
51    pub plugin_repository: Arc<PR>,
52}
53
54/// type alias for the app state wrapped in a ThinData to avoid clippy warnings
55pub type ThinDataAppState<J, RR, TR, NR, NFR, SR, TCR, PR> =
56    ThinData<AppState<J, RR, TR, NR, NFR, SR, TCR, PR>>;
57
58pub type DefaultAppState = AppState<
59    JobProducer,
60    RelayerRepositoryStorage,
61    TransactionRepositoryStorage,
62    NetworkRepositoryStorage,
63    NotificationRepositoryStorage,
64    SignerRepositoryStorage,
65    TransactionCounterRepositoryStorage,
66    PluginRepositoryStorage,
67>;
68
69impl<
70        J: JobProducerTrait,
71        RR: RelayerRepository + Repository<RelayerRepoModel, String> + Send + Sync + 'static,
72        TR: TransactionRepository + Repository<TransactionRepoModel, String> + Send + Sync + 'static,
73        NR: NetworkRepository + Repository<NetworkRepoModel, String> + Send + Sync + 'static,
74        NFR: Repository<NotificationRepoModel, String> + Send + Sync + 'static,
75        SR: Repository<SignerRepoModel, String> + Send + Sync + 'static,
76        TCR: TransactionCounterTrait + Send + Sync + 'static,
77        PR: PluginRepositoryTrait + Send + Sync + 'static,
78    > AppState<J, RR, TR, NR, NFR, SR, TCR, PR>
79{
80    /// Returns a clone of the relayer repository.
81    ///
82    /// # Returns
83    ///
84    /// An `Arc` pointing to the `RelayerRepositoryStorage`.
85    pub fn relayer_repository(&self) -> Arc<RR> {
86        self.relayer_repository.clone()
87    }
88
89    /// Returns a clone of the transaction repository.
90    ///
91    /// # Returns
92    ///
93    /// An `Arc` pointing to the `Arc<TransactionRepositoryStorage>`.
94    pub fn transaction_repository(&self) -> Arc<TR> {
95        Arc::clone(&self.transaction_repository)
96    }
97
98    /// Returns a clone of the signer repository.
99    ///
100    /// # Returns
101    ///
102    /// An `Arc` pointing to the `InMemorySignerRepository`.
103    pub fn signer_repository(&self) -> Arc<SR> {
104        Arc::clone(&self.signer_repository)
105    }
106
107    /// Returns a clone of the notification repository.
108    ///
109    /// # Returns
110    ///
111    /// An `Arc` pointing to the `InMemoryNotificationRepository`.
112    pub fn notification_repository(&self) -> Arc<NFR> {
113        Arc::clone(&self.notification_repository)
114    }
115
116    /// Returns a clone of the network repository.
117    ///
118    /// # Returns
119    ///
120    /// An `Arc` pointing to the `InMemoryNetworkRepository`.
121    pub fn network_repository(&self) -> Arc<NR> {
122        Arc::clone(&self.network_repository)
123    }
124
125    /// Returns a clone of the transaction counter store.
126    ///
127    /// # Returns
128    ///
129    /// An `Arc` pointing to the `InMemoryTransactionCounter`.
130    pub fn transaction_counter_store(&self) -> Arc<TCR> {
131        Arc::clone(&self.transaction_counter_store)
132    }
133
134    /// Returns a clone of the job producer.
135    ///
136    /// # Returns
137    ///
138    /// An `Arc` pointing to the `JobProducer`.
139    pub fn job_producer(&self) -> Arc<J> {
140        Arc::clone(&self.job_producer)
141    }
142
143    /// Returns a clone of the plugin repository.
144    ///
145    /// # Returns
146    ///
147    /// An `Arc` pointing to the `InMemoryPluginRepository`.
148    pub fn plugin_repository(&self) -> Arc<PR> {
149        Arc::clone(&self.plugin_repository)
150    }
151}
152
153#[cfg(test)]
154mod tests {
155    use crate::{jobs::MockJobProducerTrait, repositories::TransactionRepositoryStorage};
156
157    use super::*;
158    use std::sync::Arc;
159
160    fn create_test_app_state() -> AppState<
161        MockJobProducerTrait,
162        RelayerRepositoryStorage,
163        TransactionRepositoryStorage,
164        NetworkRepositoryStorage,
165        NotificationRepositoryStorage,
166        SignerRepositoryStorage,
167        TransactionCounterRepositoryStorage,
168        PluginRepositoryStorage,
169    > {
170        // Create a mock job producer
171        let mut mock_job_producer = MockJobProducerTrait::new();
172
173        // Set up expectations for the mock
174        mock_job_producer
175            .expect_produce_transaction_request_job()
176            .returning(|_, _| Box::pin(async { Ok(()) }));
177
178        mock_job_producer
179            .expect_produce_submit_transaction_job()
180            .returning(|_, _| Box::pin(async { Ok(()) }));
181
182        mock_job_producer
183            .expect_produce_check_transaction_status_job()
184            .returning(|_, _| Box::pin(async { Ok(()) }));
185
186        mock_job_producer
187            .expect_produce_send_notification_job()
188            .returning(|_, _| Box::pin(async { Ok(()) }));
189
190        AppState {
191            relayer_repository: Arc::new(RelayerRepositoryStorage::new_in_memory()),
192            transaction_repository: Arc::new(TransactionRepositoryStorage::new_in_memory()),
193            signer_repository: Arc::new(SignerRepositoryStorage::new_in_memory()),
194            notification_repository: Arc::new(NotificationRepositoryStorage::new_in_memory()),
195            network_repository: Arc::new(NetworkRepositoryStorage::new_in_memory()),
196            transaction_counter_store: Arc::new(
197                TransactionCounterRepositoryStorage::new_in_memory(),
198            ),
199            job_producer: Arc::new(mock_job_producer),
200            plugin_repository: Arc::new(PluginRepositoryStorage::new_in_memory()),
201        }
202    }
203
204    #[test]
205    fn test_relayer_repository_getter() {
206        let app_state = create_test_app_state();
207        let repo1 = app_state.relayer_repository();
208        let repo2 = app_state.relayer_repository();
209
210        // Verify that we get a new Arc pointing to the same underlying data
211        assert!(Arc::ptr_eq(&repo1, &repo2));
212        assert!(Arc::ptr_eq(&repo1, &app_state.relayer_repository));
213    }
214
215    #[test]
216    fn test_transaction_repository_getter() {
217        let app_state = create_test_app_state();
218        let repo1 = app_state.transaction_repository();
219        let repo2 = app_state.transaction_repository();
220
221        assert!(Arc::ptr_eq(&repo1, &repo2));
222        assert!(Arc::ptr_eq(&repo1, &app_state.transaction_repository));
223    }
224
225    #[test]
226    fn test_signer_repository_getter() {
227        let app_state = create_test_app_state();
228        let repo1 = app_state.signer_repository();
229        let repo2 = app_state.signer_repository();
230
231        assert!(Arc::ptr_eq(&repo1, &repo2));
232        assert!(Arc::ptr_eq(&repo1, &app_state.signer_repository));
233    }
234
235    #[test]
236    fn test_notification_repository_getter() {
237        let app_state = create_test_app_state();
238        let repo1 = app_state.notification_repository();
239        let repo2 = app_state.notification_repository();
240
241        assert!(Arc::ptr_eq(&repo1, &repo2));
242        assert!(Arc::ptr_eq(&repo1, &app_state.notification_repository));
243    }
244
245    #[test]
246    fn test_transaction_counter_store_getter() {
247        let app_state = create_test_app_state();
248        let store1 = app_state.transaction_counter_store();
249        let store2 = app_state.transaction_counter_store();
250
251        assert!(Arc::ptr_eq(&store1, &store2));
252        assert!(Arc::ptr_eq(&store1, &app_state.transaction_counter_store));
253    }
254
255    #[test]
256    fn test_job_producer_getter() {
257        let app_state = create_test_app_state();
258        let producer1 = app_state.job_producer();
259        let producer2 = app_state.job_producer();
260
261        assert!(Arc::ptr_eq(&producer1, &producer2));
262        assert!(Arc::ptr_eq(&producer1, &app_state.job_producer));
263    }
264
265    #[test]
266    fn test_plugin_repository_getter() {
267        let app_state = create_test_app_state();
268        let store1 = app_state.plugin_repository();
269        let store2 = app_state.plugin_repository();
270
271        assert!(Arc::ptr_eq(&store1, &store2));
272        assert!(Arc::ptr_eq(&store1, &app_state.plugin_repository));
273    }
274}