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
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
//! Request-reply pattern helpers for web handler agents
//!
//! This module provides utilities for implementing the request-reply pattern
//! in acton-reactive agents that need to respond synchronously to web handler
//! requests. This pattern is commonly used when Axum extractors need to wait
//! for agent responses.
//!
//! # Why This Pattern?
//!
//! Axum extractors run synchronously (from the handler's perspective) but need
//! to communicate with asynchronous agents. The oneshot channel provides a way
//! to:
//! 1. Send a request to an agent
//! 2. Await the agent's response
//! 3. Return the result to the extractor
//!
//! The `Arc<Mutex<Option<...>>>` wrapping is required because:
//! - `Arc`: Messages must be cloneable for agent supervision/retry
//! - `Mutex`: Interior mutability to take the sender when responding
//! - `Option`: Allows taking ownership of the sender exactly once
//!
//! # Example Usage
//!
//! ```rust
//! use acton_reactive::prelude::*;
//! use crate::agents::request_reply::{create_request_reply, send_response, ResponseChannel};
//! use crate::auth::session::SessionId;
//!
//! #[derive(Clone, Debug)]
//! pub struct GetSessionRequest {
//! pub session_id: SessionId,
//! pub response_tx: ResponseChannel<Option<SessionData>>,
//! }
//!
//! impl GetSessionRequest {
//! pub fn new(session_id: SessionId) -> (Self, oneshot::Receiver<Option<SessionData>>) {
//! let (response_tx, rx) = create_request_reply();
//! let request = Self { session_id, response_tx };
//! (request, rx)
//! }
//! }
//!
//! // In the agent's message handler:
//! async fn handle_get_session(request: GetSessionRequest) {
//! let session = load_session(&request.session_id);
//! let _ = send_response(request.response_tx, session).await;
//! }
//! ```
use Arc;
use ;
/// Standard response channel type for web handler requests
///
/// This type wraps a oneshot sender in `Arc<Mutex<Option<...>>>` to satisfy
/// the requirements of acton-reactive message passing:
/// - `Arc`: Messages must be `Clone` for agent supervision/retry
/// - `Mutex`: Provides interior mutability to take ownership of the sender
/// - `Option`: Allows taking the sender exactly once when responding
///
/// # Type Parameter
///
/// * `T` - The type of value to send through the channel
pub type ResponseChannel<T> = ;
/// Create a request-reply pair with proper channel wrapping
///
/// This is a convenience function that creates both sides of a request-reply
/// communication pattern. The sender is wrapped in `Arc<Mutex<Option<...>>>`
/// for use in agent messages, while the receiver is returned directly for
/// awaiting the response.
///
/// # Returns
///
/// A tuple of `(ResponseChannel<T>, oneshot::Receiver<T>)` where:
/// - The `ResponseChannel` should be included in your request message
/// - The `Receiver` should be awaited by the web handler
///
/// # Example
///
/// ```rust
/// use crate::agents::request_reply::create_request_reply;
///
/// let (response_tx, rx) = create_request_reply();
/// let request = MyRequest {
/// data: "foo".to_string(),
/// response_tx,
/// };
///
/// // Send request to agent
/// agent_handle.send(request).await;
///
/// // Wait for response
/// let response = rx.await.expect("Agent dropped response channel");
/// ```
/// Send a response through a response channel
///
/// This function properly unwraps and uses the response channel to send a value
/// back to the waiting web handler. The channel is consumed after sending.
///
/// # Parameters
///
/// * `response_tx` - The response channel from the request
/// * `value` - The value to send back to the requester
///
/// # Returns
///
/// `Ok(())` if the response was successfully sent, or `Err(value)` if the
/// receiver was dropped (which typically means the web handler timed out or
/// the client disconnected).
///
/// # Errors
///
/// Returns `Err(value)` if:
/// - The receiver was dropped (client disconnected or handler timed out)
/// - The channel was already used
///
/// # Example
///
/// ```rust
/// use crate::agents::request_reply::send_response;
///
/// async fn handle_request(request: MyRequest) {
/// let result = perform_operation();
///
/// // Send response back to web handler
/// if send_response(request.response_tx, result).await.is_err() {
/// tracing::warn!("Client disconnected before receiving response");
/// }
/// }
/// ```
pub async