allsource_core/infrastructure/di/container.rs
1//! Service Container implementation
2//!
3//! Holds all repository instances and provides factory methods for use cases.
4//!
5//! Note: Stateless use cases (unit structs with no constructor) are not included
6//! in the container - they should be used directly via their static methods.
7
8use crate::application::use_cases::{
9 AppendForkEventUseCase,
10 BranchForkUseCase,
11 CheckAccessUseCase,
12 CleanupExpiredForksUseCase,
13 CleanupExpiredTokensUseCase,
14 ConfirmTransactionUseCase,
15 // Article use cases (with state)
16 CreateArticleUseCase,
17 // Fork use cases (with state)
18 CreateForkUseCase,
19 DiscardForkUseCase,
20 GetForkUseCase,
21 // Access use cases (with state)
22 GrantFreeAccessUseCase,
23 // Payment use cases (with state)
24 InitiatePaymentUseCase,
25 MergeForkUseCase,
26 QueryForkEventsUseCase,
27 RefundTransactionUseCase,
28 // Creator use cases (with state)
29 RegisterCreatorUseCase,
30 RevokeAccessUseCase,
31 UpdateArticleUseCase,
32 UpdateCreatorUseCase,
33 UpdateForkUseCase,
34 ValidateTokenUseCase,
35};
36use crate::{
37 application::services::consumer::ConsumerRegistry,
38 domain::repositories::{
39 AccessTokenRepository, ArticleRepository, AuditEventRepository, CreatorRepository,
40 EventStreamRepository, ForkRepository, TenantRepository, TransactionRepository,
41 },
42 infrastructure::{
43 persistence::SystemMetadataStore, repositories::EventSourcedConfigRepository,
44 },
45};
46use std::sync::Arc;
47
48/// Service container that holds all repository instances and provides factory methods for use cases.
49///
50/// The container uses `Arc` for thread-safe sharing of repository instances across use cases.
51/// All repositories are stored as trait objects, allowing for easy substitution with mock
52/// implementations during testing.
53///
54/// # Design Principles
55///
56/// 1. **Singleton Repositories**: Repository instances are created once and shared across all use cases
57/// 2. **Factory Methods**: Use cases are created on-demand with their dependencies injected
58/// 3. **Thread Safety**: All repositories are wrapped in `Arc` for concurrent access
59/// 4. **Testability**: Repositories can be swapped with mocks via the builder
60///
61/// # Stateless Use Cases
62///
63/// Some use cases are stateless (unit structs with static methods). These are NOT included
64/// in the container and should be used directly:
65/// - `PublishArticleUseCase::execute(article)`
66/// - `ArchiveArticleUseCase::execute(article)`
67/// - `DeleteArticleUseCase::execute(article)`
68/// - `RestoreArticleUseCase::execute(article)`
69/// - `RecordArticlePurchaseUseCase::execute(article, amount)`
70/// - `ExtendAccessUseCase::execute(token, days)`
71/// - And others...
72///
73/// # Example
74///
75/// ```rust,ignore
76/// let container = ContainerBuilder::new()
77/// .with_in_memory_repositories()
78/// .build();
79///
80/// // Get use cases with dependencies injected
81/// let register_creator = container.register_creator_use_case();
82/// let initiate_payment = container.initiate_payment_use_case();
83/// ```
84#[derive(Clone)]
85pub struct ServiceContainer {
86 // Paywall domain repositories
87 creator_repository: Arc<dyn CreatorRepository>,
88 article_repository: Arc<dyn ArticleRepository>,
89 transaction_repository: Arc<dyn TransactionRepository>,
90 access_token_repository: Arc<dyn AccessTokenRepository>,
91 fork_repository: Arc<dyn ForkRepository>,
92 // Core event sourcing repository
93 event_stream_repository: Arc<dyn EventStreamRepository>,
94
95 // System metadata repositories (event-sourced, optional for backward compatibility)
96 pub(super) tenant_repository: Option<Arc<dyn TenantRepository>>,
97 pub(super) audit_repository: Option<Arc<dyn AuditEventRepository>>,
98 pub(super) config_repository: Option<Arc<EventSourcedConfigRepository>>,
99 pub(super) system_store: Option<Arc<SystemMetadataStore>>,
100 pub(super) consumer_registry: Option<Arc<ConsumerRegistry>>,
101}
102
103impl ServiceContainer {
104 /// Creates a new service container with the provided repositories.
105 ///
106 /// Prefer using `ContainerBuilder` for a more fluent API.
107 pub fn new(
108 creator_repository: Arc<dyn CreatorRepository>,
109 article_repository: Arc<dyn ArticleRepository>,
110 transaction_repository: Arc<dyn TransactionRepository>,
111 access_token_repository: Arc<dyn AccessTokenRepository>,
112 fork_repository: Arc<dyn ForkRepository>,
113 event_stream_repository: Arc<dyn EventStreamRepository>,
114 ) -> Self {
115 Self {
116 creator_repository,
117 article_repository,
118 transaction_repository,
119 access_token_repository,
120 fork_repository,
121 event_stream_repository,
122 tenant_repository: None,
123 audit_repository: None,
124 config_repository: None,
125 system_store: None,
126 consumer_registry: None,
127 }
128 }
129
130 // =========================================================================
131 // Repository Accessors
132 // =========================================================================
133
134 /// Returns the creator repository instance.
135 pub fn creator_repository(&self) -> Arc<dyn CreatorRepository> {
136 self.creator_repository.clone()
137 }
138
139 /// Returns the article repository instance.
140 pub fn article_repository(&self) -> Arc<dyn ArticleRepository> {
141 self.article_repository.clone()
142 }
143
144 /// Returns the transaction repository instance.
145 pub fn transaction_repository(&self) -> Arc<dyn TransactionRepository> {
146 self.transaction_repository.clone()
147 }
148
149 /// Returns the access token repository instance.
150 pub fn access_token_repository(&self) -> Arc<dyn AccessTokenRepository> {
151 self.access_token_repository.clone()
152 }
153
154 /// Returns the fork repository instance.
155 pub fn fork_repository(&self) -> Arc<dyn ForkRepository> {
156 self.fork_repository.clone()
157 }
158
159 /// Returns the event stream repository instance.
160 pub fn event_stream_repository(&self) -> Arc<dyn EventStreamRepository> {
161 self.event_stream_repository.clone()
162 }
163
164 // =========================================================================
165 // System Metadata Repository Accessors
166 // =========================================================================
167
168 /// Returns the event-sourced tenant repository, if configured.
169 ///
170 /// Returns `None` when system metadata is not configured (in-memory mode).
171 pub fn tenant_repository(&self) -> Option<Arc<dyn TenantRepository>> {
172 self.tenant_repository.clone()
173 }
174
175 /// Returns the event-sourced audit repository, if configured.
176 ///
177 /// Returns `None` when system metadata is not configured (in-memory mode).
178 pub fn audit_repository(&self) -> Option<Arc<dyn AuditEventRepository>> {
179 self.audit_repository.clone()
180 }
181
182 /// Returns the event-sourced config repository, if configured.
183 ///
184 /// Returns `None` when system metadata is not configured (in-memory mode).
185 pub fn config_repository(&self) -> Option<Arc<EventSourcedConfigRepository>> {
186 self.config_repository.clone()
187 }
188
189 /// Returns the system metadata store, if configured.
190 ///
191 /// Returns `None` when system metadata is not configured (in-memory mode).
192 pub fn system_store(&self) -> Option<Arc<SystemMetadataStore>> {
193 self.system_store.clone()
194 }
195
196 /// Returns the durable consumer registry, if configured.
197 pub fn consumer_registry(&self) -> Option<Arc<ConsumerRegistry>> {
198 self.consumer_registry.clone()
199 }
200
201 /// Returns true if event-sourced system repositories are configured.
202 pub fn has_system_repositories(&self) -> bool {
203 self.system_store.is_some()
204 }
205
206 // =========================================================================
207 // Creator Use Case Factories
208 // =========================================================================
209
210 /// Creates a new `RegisterCreatorUseCase` with injected dependencies.
211 pub fn register_creator_use_case(&self) -> RegisterCreatorUseCase {
212 RegisterCreatorUseCase::new(self.creator_repository.clone())
213 }
214
215 /// Creates a new `UpdateCreatorUseCase` with injected dependencies.
216 pub fn update_creator_use_case(&self) -> UpdateCreatorUseCase {
217 UpdateCreatorUseCase::new(self.creator_repository.clone())
218 }
219
220 // =========================================================================
221 // Article Use Case Factories
222 // =========================================================================
223
224 /// Creates a new `CreateArticleUseCase` with injected dependencies.
225 pub fn create_article_use_case(&self) -> CreateArticleUseCase {
226 CreateArticleUseCase::new(self.article_repository.clone())
227 }
228
229 /// Creates a new `UpdateArticleUseCase` with injected dependencies.
230 pub fn update_article_use_case(&self) -> UpdateArticleUseCase {
231 UpdateArticleUseCase::new(self.article_repository.clone())
232 }
233
234 // Note: PublishArticleUseCase, ArchiveArticleUseCase, DeleteArticleUseCase,
235 // RestoreArticleUseCase, and RecordArticlePurchaseUseCase are stateless.
236 // Use them directly: e.g., PublishArticleUseCase::execute(article)
237
238 // =========================================================================
239 // Payment Use Case Factories
240 // =========================================================================
241
242 /// Creates a new `InitiatePaymentUseCase` with injected dependencies.
243 pub fn initiate_payment_use_case(&self) -> InitiatePaymentUseCase {
244 InitiatePaymentUseCase::new(
245 self.transaction_repository.clone(),
246 self.article_repository.clone(),
247 self.creator_repository.clone(),
248 )
249 }
250
251 /// Creates a new `ConfirmTransactionUseCase` with injected dependencies.
252 pub fn confirm_transaction_use_case(&self) -> ConfirmTransactionUseCase {
253 ConfirmTransactionUseCase::new(
254 self.transaction_repository.clone(),
255 self.access_token_repository.clone(),
256 self.article_repository.clone(),
257 self.creator_repository.clone(),
258 )
259 }
260
261 /// Creates a new `RefundTransactionUseCase` with injected dependencies.
262 pub fn refund_transaction_use_case(&self) -> RefundTransactionUseCase {
263 RefundTransactionUseCase::new(
264 self.transaction_repository.clone(),
265 self.access_token_repository.clone(),
266 )
267 }
268
269 // Note: FailTransactionUseCase, DisputeTransactionUseCase, ResolveDisputeUseCase,
270 // and ListTransactionsUseCase are stateless. Use them directly.
271
272 // =========================================================================
273 // Access Token Use Case Factories
274 // =========================================================================
275
276 /// Creates a new `GrantFreeAccessUseCase` with injected dependencies.
277 pub fn grant_free_access_use_case(&self) -> GrantFreeAccessUseCase {
278 GrantFreeAccessUseCase::new(
279 self.access_token_repository.clone(),
280 self.article_repository.clone(),
281 )
282 }
283
284 /// Creates a new `ValidateTokenUseCase` with injected dependencies.
285 pub fn validate_token_use_case(&self) -> ValidateTokenUseCase {
286 ValidateTokenUseCase::new(self.access_token_repository.clone())
287 }
288
289 /// Creates a new `RevokeAccessUseCase` with injected dependencies.
290 pub fn revoke_access_use_case(&self) -> RevokeAccessUseCase {
291 RevokeAccessUseCase::new(self.access_token_repository.clone())
292 }
293
294 /// Creates a new `CheckAccessUseCase` with injected dependencies.
295 pub fn check_access_use_case(&self) -> CheckAccessUseCase {
296 CheckAccessUseCase::new(self.access_token_repository.clone())
297 }
298
299 /// Creates a new `CleanupExpiredTokensUseCase` with injected dependencies.
300 pub fn cleanup_expired_tokens_use_case(&self) -> CleanupExpiredTokensUseCase {
301 CleanupExpiredTokensUseCase::new(self.access_token_repository.clone())
302 }
303
304 // Note: ExtendAccessUseCase, RecordAccessUseCase, and ListAccessTokensUseCase
305 // are stateless. Use them directly.
306
307 // =========================================================================
308 // Fork Use Case Factories
309 // =========================================================================
310
311 /// Creates a new `CreateForkUseCase` with injected dependencies.
312 pub fn create_fork_use_case(&self) -> CreateForkUseCase {
313 CreateForkUseCase::new(self.fork_repository.clone())
314 }
315
316 /// Creates a new `UpdateForkUseCase` with injected dependencies.
317 pub fn update_fork_use_case(&self) -> UpdateForkUseCase {
318 UpdateForkUseCase::new(self.fork_repository.clone())
319 }
320
321 /// Creates a new `MergeForkUseCase` with injected dependencies.
322 pub fn merge_fork_use_case(&self) -> MergeForkUseCase {
323 MergeForkUseCase::new(self.fork_repository.clone())
324 }
325
326 /// Creates a new `DiscardForkUseCase` with injected dependencies.
327 pub fn discard_fork_use_case(&self) -> DiscardForkUseCase {
328 DiscardForkUseCase::new(self.fork_repository.clone())
329 }
330
331 /// Creates a new `GetForkUseCase` with injected dependencies.
332 pub fn get_fork_use_case(&self) -> GetForkUseCase {
333 GetForkUseCase::new(self.fork_repository.clone())
334 }
335
336 /// Creates a new `AppendForkEventUseCase` with injected dependencies.
337 pub fn append_fork_event_use_case(&self) -> AppendForkEventUseCase {
338 AppendForkEventUseCase::new(self.fork_repository.clone())
339 }
340
341 /// Creates a new `QueryForkEventsUseCase` with injected dependencies.
342 pub fn query_fork_events_use_case(&self) -> QueryForkEventsUseCase {
343 QueryForkEventsUseCase::new(self.fork_repository.clone())
344 }
345
346 /// Creates a new `BranchForkUseCase` with injected dependencies.
347 pub fn branch_fork_use_case(&self) -> BranchForkUseCase {
348 BranchForkUseCase::new(self.fork_repository.clone())
349 }
350
351 /// Creates a new `CleanupExpiredForksUseCase` with injected dependencies.
352 pub fn cleanup_expired_forks_use_case(&self) -> CleanupExpiredForksUseCase {
353 CleanupExpiredForksUseCase::new(self.fork_repository.clone())
354 }
355
356 // Note: ListForksUseCase is stateless. Use it directly.
357}
358
359impl std::fmt::Debug for ServiceContainer {
360 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
361 f.debug_struct("ServiceContainer")
362 .field("creator_repository", &"Arc<dyn CreatorRepository>")
363 .field("article_repository", &"Arc<dyn ArticleRepository>")
364 .field("transaction_repository", &"Arc<dyn TransactionRepository>")
365 .field("access_token_repository", &"Arc<dyn AccessTokenRepository>")
366 .field("fork_repository", &"Arc<dyn ForkRepository>")
367 .field("event_stream_repository", &"Arc<dyn EventStreamRepository>")
368 .field(
369 "system_repositories",
370 &if self.has_system_repositories() {
371 "event-sourced"
372 } else {
373 "not configured"
374 },
375 )
376 .finish()
377 }
378}