Skip to main content

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}