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