openzeppelin_relayer/bootstrap/
initialize_app_state.rs1use crate::{
6 config::{RepositoryStorageType, ServerConfig},
7 jobs::{self, Queue},
8 models::{AppState, DefaultAppState},
9 repositories::{
10 ApiKeyRepositoryStorage, NetworkRepositoryStorage, NotificationRepositoryStorage,
11 PluginRepositoryStorage, RelayerRepositoryStorage, SignerRepositoryStorage,
12 TransactionCounterRepositoryStorage, TransactionRepositoryStorage,
13 },
14 utils::initialize_redis_connection,
15};
16use actix_web::web;
17use color_eyre::Result;
18use std::sync::Arc;
19use tracing::warn;
20
21pub struct RepositoryCollection {
22 pub relayer: Arc<RelayerRepositoryStorage>,
23 pub transaction: Arc<TransactionRepositoryStorage>,
24 pub signer: Arc<SignerRepositoryStorage>,
25 pub notification: Arc<NotificationRepositoryStorage>,
26 pub network: Arc<NetworkRepositoryStorage>,
27 pub transaction_counter: Arc<TransactionCounterRepositoryStorage>,
28 pub plugin: Arc<PluginRepositoryStorage>,
29 pub api_key: Arc<ApiKeyRepositoryStorage>,
30}
31
32pub async fn initialize_repositories(config: &ServerConfig) -> eyre::Result<RepositoryCollection> {
40 let repositories = match config.repository_storage_type {
41 RepositoryStorageType::InMemory => RepositoryCollection {
42 relayer: Arc::new(RelayerRepositoryStorage::new_in_memory()),
43 transaction: Arc::new(TransactionRepositoryStorage::new_in_memory()),
44 signer: Arc::new(SignerRepositoryStorage::new_in_memory()),
45 notification: Arc::new(NotificationRepositoryStorage::new_in_memory()),
46 network: Arc::new(NetworkRepositoryStorage::new_in_memory()),
47 transaction_counter: Arc::new(TransactionCounterRepositoryStorage::new_in_memory()),
48 plugin: Arc::new(PluginRepositoryStorage::new_in_memory()),
49 api_key: Arc::new(ApiKeyRepositoryStorage::new_in_memory()),
50 },
51 RepositoryStorageType::Redis => {
52 if config.storage_encryption_key.is_none() {
53 warn!("⚠️ Storage encryption key is not set. Please set the STORAGE_ENCRYPTION_KEY environment variable.");
54 return Err(eyre::eyre!("Storage encryption key is not set. Please set the STORAGE_ENCRYPTION_KEY environment variable."));
55 }
56
57 let connection_manager = initialize_redis_connection(config).await?;
58
59 RepositoryCollection {
60 relayer: Arc::new(RelayerRepositoryStorage::new_redis(
61 connection_manager.clone(),
62 config.redis_key_prefix.clone(),
63 )?),
64 transaction: Arc::new(TransactionRepositoryStorage::new_redis(
65 connection_manager.clone(),
66 config.redis_key_prefix.clone(),
67 )?),
68 signer: Arc::new(SignerRepositoryStorage::new_redis(
69 connection_manager.clone(),
70 config.redis_key_prefix.clone(),
71 )?),
72 notification: Arc::new(NotificationRepositoryStorage::new_redis(
73 connection_manager.clone(),
74 config.redis_key_prefix.clone(),
75 )?),
76 network: Arc::new(NetworkRepositoryStorage::new_redis(
77 connection_manager.clone(),
78 config.redis_key_prefix.clone(),
79 )?),
80 transaction_counter: Arc::new(TransactionCounterRepositoryStorage::new_redis(
81 connection_manager.clone(),
82 config.redis_key_prefix.clone(),
83 )?),
84 plugin: Arc::new(PluginRepositoryStorage::new_redis(
85 connection_manager.clone(),
86 config.redis_key_prefix.clone(),
87 )?),
88 api_key: Arc::new(ApiKeyRepositoryStorage::new_redis(
89 connection_manager,
90 config.redis_key_prefix.clone(),
91 )?),
92 }
93 }
94 };
95
96 Ok(repositories)
97}
98
99pub async fn initialize_app_state(
111 server_config: Arc<ServerConfig>,
112) -> Result<web::ThinData<DefaultAppState>> {
113 let repositories = initialize_repositories(&server_config).await?;
114
115 let queue = Queue::setup().await?;
116 let job_producer = Arc::new(jobs::JobProducer::new(queue.clone()));
117
118 let app_state = web::ThinData(AppState {
119 relayer_repository: repositories.relayer,
120 transaction_repository: repositories.transaction,
121 signer_repository: repositories.signer,
122 network_repository: repositories.network,
123 notification_repository: repositories.notification,
124 transaction_counter_store: repositories.transaction_counter,
125 job_producer,
126 plugin_repository: repositories.plugin,
127 api_key_repository: repositories.api_key,
128 });
129
130 Ok(app_state)
131}
132
133#[cfg(test)]
134mod tests {
135 use super::*;
136 use crate::{
137 config::RepositoryStorageType,
138 repositories::{ApiKeyRepositoryTrait, Repository},
139 utils::mocks::mockutils::{
140 create_mock_api_key, create_mock_network, create_mock_relayer, create_mock_signer,
141 create_test_server_config,
142 },
143 };
144 use std::sync::Arc;
145
146 #[tokio::test]
147 async fn test_initialize_repositories_in_memory() {
148 let config = create_test_server_config(RepositoryStorageType::InMemory);
149 let result = initialize_repositories(&config).await;
150
151 assert!(result.is_ok());
152 let repositories = result.unwrap();
153
154 assert!(Arc::strong_count(&repositories.relayer) >= 1);
156 assert!(Arc::strong_count(&repositories.transaction) >= 1);
157 assert!(Arc::strong_count(&repositories.signer) >= 1);
158 assert!(Arc::strong_count(&repositories.notification) >= 1);
159 assert!(Arc::strong_count(&repositories.network) >= 1);
160 assert!(Arc::strong_count(&repositories.transaction_counter) >= 1);
161 assert!(Arc::strong_count(&repositories.plugin) >= 1);
162 assert!(Arc::strong_count(&repositories.api_key) >= 1);
163 }
164
165 #[tokio::test]
166 async fn test_repository_collection_functionality() {
167 let config = create_test_server_config(RepositoryStorageType::InMemory);
168 let repositories = initialize_repositories(&config).await.unwrap();
169
170 let relayer = create_mock_relayer("test-relayer".to_string(), false);
172 let signer = create_mock_signer();
173 let network = create_mock_network();
174 let api_key = create_mock_api_key();
175
176 repositories.relayer.create(relayer.clone()).await.unwrap();
178 repositories.signer.create(signer.clone()).await.unwrap();
179 repositories.network.create(network.clone()).await.unwrap();
180 repositories.api_key.create(api_key.clone()).await.unwrap();
181
182 let retrieved_relayer = repositories
183 .relayer
184 .get_by_id("test-relayer".to_string())
185 .await
186 .unwrap();
187 let retrieved_signer = repositories
188 .signer
189 .get_by_id("test".to_string())
190 .await
191 .unwrap();
192 let retrieved_network = repositories
193 .network
194 .get_by_id("test".to_string())
195 .await
196 .unwrap();
197 let retrieved_api_key = repositories
198 .api_key
199 .get_by_id("test-api-key")
200 .await
201 .unwrap();
202
203 assert_eq!(retrieved_relayer.id, "test-relayer");
204 assert_eq!(retrieved_signer.id, "test");
205 assert_eq!(retrieved_network.id, "test");
206 assert_eq!(retrieved_api_key.unwrap().id, "test-api-key");
207 }
208
209 #[tokio::test]
210 async fn test_initialize_app_state_repository_error() {
211 let mut config = create_test_server_config(RepositoryStorageType::Redis);
212 config.redis_url = "redis://invalid_url".to_string();
213
214 let result = initialize_app_state(Arc::new(config)).await;
215
216 assert!(result.is_err());
218 let error = result.unwrap_err();
219 assert!(error.to_string().contains("Redis") || error.to_string().contains("connection"));
220 }
221}