-
Notifications
You must be signed in to change notification settings - Fork 2
Expand file tree
/
Copy pathcontext.rs
More file actions
163 lines (156 loc) · 5.43 KB
/
Copy pathcontext.rs
File metadata and controls
163 lines (156 loc) · 5.43 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
//! Execution Context
//!
//! This module provides the `ExecutionContext` wrapper around the Container for
//! dependency injection in command handlers. It offers a clean interface for
//! accessing services needed during command execution.
//!
//! ## Purpose
//!
//! The `ExecutionContext` serves as an abstraction layer between the Container
//! (which holds raw services) and command handlers (which need typed access).
//! This separation provides:
//!
//! - **Clean Interface**: Command handlers get strongly-typed service access
//! - **Thread Safety**: All services are properly wrapped for concurrent access
//! - **Future-Proofing**: Easy to add new services without changing handler signatures
//! - **Testing Support**: Easy to inject test doubles through Container
//!
//! ## Design
//!
//! ```text
//! Container (bootstrap) → ExecutionContext (dispatch) → Command Handlers
//!
//! Raw services Clean typed access Business logic
//! ```
//!
//! ## Usage Example
//!
//! ```rust,no_run
//! use torrust_tracker_deployer_lib::bootstrap::Container;
//! use torrust_tracker_deployer_lib::presentation::dispatch::ExecutionContext;
//! use std::sync::Arc;
//!
//! # fn example() -> Result<(), Box<dyn std::error::Error>> {
//! // Create execution context from container
//! let container = Container::new();
//! let context = ExecutionContext::new(Arc::new(container));
//!
//! // Command handlers access services through context
//! let user_output = context.user_output();
//! user_output.lock().unwrap().progress("Processing...");
//! # Ok(())
//! # }
//! ```
use std::sync::{Arc, Mutex};
use crate::bootstrap::Container;
use crate::presentation::user_output::UserOutput;
/// ### Design Consideration: Shared State Access
///
/// Currently, there is no shared mutable state in the system that requires `Arc<Mutex<T>>`
/// patterns. However, if shared state is needed in the future, it can be added to the
/// Container and accessed through standard Rust concurrency patterns:
///
/// # Examples
///
/// ```rust
/// use std::sync::Arc;
/// use torrust_tracker_deployer_lib::bootstrap::Container;
/// use torrust_tracker_deployer_lib::presentation::dispatch::ExecutionContext;
///
/// let container = Arc::new(Container::new());
/// let context = ExecutionContext::new(container);
///
/// // Access user output service
/// let user_output = context.user_output();
/// user_output.lock().unwrap().success("Operation completed");
/// ```
#[derive(Clone)]
pub struct ExecutionContext {
container: Arc<Container>,
}
impl ExecutionContext {
/// Create a new execution context from a container
///
/// # Arguments
///
/// * `container` - Application service container with initialized services
///
/// # Examples
///
/// ```rust,no_run
/// use torrust_tracker_deployer_lib::bootstrap::Container;
/// use torrust_tracker_deployer_lib::presentation::dispatch::ExecutionContext;
/// use std::sync::Arc;
///
/// # fn example() -> Result<(), Box<dyn std::error::Error>> {
/// let container = Container::new();
/// let context = ExecutionContext::new(Arc::new(container));
/// # Ok(())
/// # }
/// ```
#[must_use]
pub fn new(container: Arc<Container>) -> Self {
Self { container }
}
/// Get reference to the underlying container
///
/// Provides access to the raw container for cases where direct access
/// to container methods is needed.
///
/// # Examples
///
/// ```rust,no_run
/// use torrust_tracker_deployer_lib::bootstrap::Container;
/// use torrust_tracker_deployer_lib::presentation::dispatch::ExecutionContext;
/// use std::sync::Arc;
///
/// # fn example() -> Result<(), Box<dyn std::error::Error>> {
/// let container = Container::new();
/// let context = ExecutionContext::new(Arc::new(container));
///
/// let container_ref = context.container();
/// // Use container_ref as needed
/// # Ok(())
/// # }
/// ```
#[must_use]
pub fn container(&self) -> &Arc<Container> {
&self.container
}
/// Get shared reference to user output service
///
/// Returns the user output service for displaying messages, progress,
/// and results to users. The service is wrapped in `Arc<Mutex<T>>` for
/// thread-safe shared access.
///
/// # Examples
///
/// ```rust,no_run
/// use torrust_tracker_deployer_lib::bootstrap::Container;
/// use torrust_tracker_deployer_lib::presentation::dispatch::ExecutionContext;
/// use std::sync::Arc;
///
/// # fn example() -> Result<(), Box<dyn std::error::Error>> {
/// let container = Container::new();
/// let context = ExecutionContext::new(Arc::new(container));
///
/// let user_output = context.user_output();
/// user_output.lock().unwrap().success("Operation completed");
/// # Ok(())
/// # }
/// ```
#[must_use]
pub fn user_output(&self) -> Arc<Mutex<UserOutput>> {
self.container.user_output()
}
// TODO: Add more service accessors as Container expands
//
// Future services that will be added to Container and accessed here:
// - opentofu_client() -> Arc<dyn OpenTofuClient>
// - ansible_client() -> Arc<dyn AnsibleClient>
// - environment_repository() -> Arc<dyn EnvironmentRepository>
// - clock() -> Arc<dyn Clock>
//
// These will be added as the Container is expanded in future proposals
// to support the full dependency injection pattern.
}