rama_http/layer/traffic_writer/
response.rs1use super::{WriterMode, write_headers_body_flags};
2use crate::io::write_http_response;
3use crate::{Body, Request, Response, StreamingBody, body::util::BodyExt};
4use rama_core::bytes::Bytes;
5use rama_core::error::{BoxError, ErrorContext};
6use rama_core::extensions::{Extension, ExtensionsRef};
7use rama_core::rt::Executor;
8use rama_core::telemetry::tracing::{self, Instrument};
9use rama_core::{Layer, Service};
10use rama_utils::macros::define_inner_service_accessors;
11use std::fmt::Debug;
12use std::sync::Arc;
13use tokio::io::{AsyncWrite, stderr, stdout};
14use tokio::sync::mpsc::{Sender, UnboundedSender, channel, unbounded_channel};
15
16#[derive(Clone)]
18pub struct ResponseWriterLayer<W> {
19 writer: W,
20}
21
22impl<W> Debug for ResponseWriterLayer<W> {
23 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
24 f.debug_struct("ResponseWriterLayer")
25 .field("writer", &format_args!("{}", std::any::type_name::<W>()))
26 .finish()
27 }
28}
29
30impl<W> ResponseWriterLayer<W> {
31 pub const fn new(writer: W) -> Self {
33 Self { writer }
34 }
35}
36
37pub trait ResponseWriter: Send + Sync + 'static {
39 fn write_response(&self, res: Response) -> impl Future<Output = ()> + Send + '_;
41}
42
43#[derive(Debug, Clone, Default, Extension)]
45#[extension(tags(http))]
46#[non_exhaustive]
47pub struct DoNotWriteResponse;
48
49impl DoNotWriteResponse {
50 #[must_use]
52 pub const fn new() -> Self {
53 Self
54 }
55}
56
57impl ResponseWriterLayer<UnboundedSender<Response>> {
58 pub fn writer_unbounded<W>(executor: &Executor, mut writer: W, mode: Option<WriterMode>) -> Self
61 where
62 W: AsyncWrite + Unpin + Send + Sync + 'static,
63 {
64 let (tx, mut rx) = unbounded_channel();
65 let (write_headers, write_body) = write_headers_body_flags(mode);
66
67 let span =
68 tracing::trace_root_span!("TrafficWriter::response::unbounded", otel.kind = "consumer");
69
70 executor.spawn_task(
71 async move {
72 while let Some(res) = rx.recv().await {
73 if let Err(err) =
74 write_http_response(&mut writer, res, write_headers, write_body).await
75 {
76 tracing::error!("failed to write http response to writer: {err:?}")
77 }
78 }
79 }
80 .instrument(span),
81 );
82
83 Self { writer: tx }
84 }
85
86 #[must_use]
89 pub fn stdout_unbounded(executor: &Executor, mode: Option<WriterMode>) -> Self {
90 Self::writer_unbounded(executor, stdout(), mode)
91 }
92
93 #[must_use]
96 pub fn stderr_unbounded(executor: &Executor, mode: Option<WriterMode>) -> Self {
97 Self::writer_unbounded(executor, stderr(), mode)
98 }
99}
100
101impl ResponseWriterLayer<Sender<Response>> {
102 pub fn writer<W>(
105 executor: &Executor,
106 mut writer: W,
107 buffer_size: usize,
108 mode: Option<WriterMode>,
109 ) -> Self
110 where
111 W: AsyncWrite + Unpin + Send + Sync + 'static,
112 {
113 let (tx, mut rx) = channel(buffer_size);
114 let (write_headers, write_body) = write_headers_body_flags(mode);
115
116 let span =
117 tracing::trace_root_span!("TrafficWriter::response::bounded", otel.kind = "consumer");
118
119 executor.spawn_task(
120 async move {
121 while let Some(res) = rx.recv().await {
122 if let Err(err) =
123 write_http_response(&mut writer, res, write_headers, write_body).await
124 {
125 tracing::error!("failed to write http response to writer: {err:?}")
126 }
127 }
128 }
129 .instrument(span),
130 );
131 Self { writer: tx }
132 }
133
134 #[must_use]
137 pub fn stdout(executor: &Executor, buffer_size: usize, mode: Option<WriterMode>) -> Self {
138 Self::writer(executor, stdout(), buffer_size, mode)
139 }
140
141 #[must_use]
144 pub fn stderr(executor: &Executor, buffer_size: usize, mode: Option<WriterMode>) -> Self {
145 Self::writer(executor, stderr(), buffer_size, mode)
146 }
147}
148
149impl<S, W: Clone> Layer<S> for ResponseWriterLayer<W> {
150 type Service = ResponseWriterService<S, W>;
151
152 fn layer(&self, inner: S) -> Self::Service {
153 ResponseWriterService {
154 inner,
155 writer: self.writer.clone(),
156 }
157 }
158
159 fn into_layer(self, inner: S) -> Self::Service {
160 ResponseWriterService {
161 inner,
162 writer: self.writer,
163 }
164 }
165}
166
167#[derive(Clone)]
171pub struct ResponseWriterService<S, W> {
172 inner: S,
173 writer: W,
174}
175
176impl<S, W> ResponseWriterService<S, W> {
177 pub const fn new(writer: W, inner: S) -> Self {
179 Self { inner, writer }
180 }
181
182 define_inner_service_accessors!();
183}
184
185impl<S: Debug, W> Debug for ResponseWriterService<S, W> {
186 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
187 f.debug_struct("ResponseWriterService")
188 .field("inner", &self.inner)
189 .field("writer", &format_args!("{}", std::any::type_name::<W>()))
190 .finish()
191 }
192}
193
194impl<S> ResponseWriterService<S, UnboundedSender<Response>> {
195 pub fn writer_unbounded<W>(
198 executor: &Executor,
199 writer: W,
200 mode: Option<WriterMode>,
201 inner: S,
202 ) -> Self
203 where
204 W: AsyncWrite + Unpin + Send + Sync + 'static,
205 {
206 let layer = ResponseWriterLayer::writer_unbounded(executor, writer, mode);
207 layer.into_layer(inner)
208 }
209
210 pub fn stdout_unbounded(executor: &Executor, mode: Option<WriterMode>, inner: S) -> Self {
213 Self::writer_unbounded(executor, stdout(), mode, inner)
214 }
215
216 pub fn stderr_unbounded(executor: &Executor, mode: Option<WriterMode>, inner: S) -> Self {
219 Self::writer_unbounded(executor, stderr(), mode, inner)
220 }
221}
222
223impl<S> ResponseWriterService<S, Sender<Response>> {
224 pub fn writer<W>(
227 executor: &Executor,
228 writer: W,
229 buffer_size: usize,
230 mode: Option<WriterMode>,
231 inner: S,
232 ) -> Self
233 where
234 W: AsyncWrite + Unpin + Send + Sync + 'static,
235 {
236 let layer = ResponseWriterLayer::writer(executor, writer, buffer_size, mode);
237 layer.into_layer(inner)
238 }
239
240 pub fn stdout(
243 executor: &Executor,
244 buffer_size: usize,
245 mode: Option<WriterMode>,
246 inner: S,
247 ) -> Self {
248 Self::writer(executor, stdout(), buffer_size, mode, inner)
249 }
250
251 pub fn stderr(
254 executor: &Executor,
255 buffer_size: usize,
256 mode: Option<WriterMode>,
257 inner: S,
258 ) -> Self {
259 Self::writer(executor, stderr(), buffer_size, mode, inner)
260 }
261}
262
263impl<S, W> ResponseWriterService<S, W> {}
264
265impl<S, W, ReqBody, ResBody> Service<Request<ReqBody>> for ResponseWriterService<S, W>
266where
267 S: Service<Request<ReqBody>, Output = Response<ResBody>, Error: Into<BoxError>>,
268 W: ResponseWriter,
269 ReqBody: Send + 'static,
270 ResBody: StreamingBody<Data = Bytes, Error: Into<BoxError>> + Send + Sync + 'static,
271{
272 type Output = Response;
273 type Error = BoxError;
274
275 async fn serve(&self, req: Request<ReqBody>) -> Result<Self::Output, Self::Error> {
276 let do_not_print_response: Option<Arc<DoNotWriteResponse>> = req.extensions().get_arc();
277 let resp = self.inner.serve(req).await.into_box_error()?;
278 let resp = if do_not_print_response.is_some() {
279 resp.map(Body::new)
280 } else {
281 let (parts, body) = resp.into_parts();
282 let body_bytes = body
283 .collect()
284 .await
285 .context("printer prepare: collect response body")?
286 .to_bytes();
287 let resp: rama_http_types::Response<Body> =
288 Response::from_parts(parts.clone(), Body::from(body_bytes.clone()));
289 self.writer.write_response(resp).await;
290 Response::from_parts(parts, Body::from(body_bytes))
291 };
292 Ok(resp)
293 }
294}
295
296impl ResponseWriter for Sender<Response> {
297 async fn write_response(&self, res: Response) {
298 if let Err(err) = self.send(res).await {
299 tracing::error!("failed to send response to channel: {err:?}")
300 }
301 }
302}
303
304impl ResponseWriter for UnboundedSender<Response> {
305 async fn write_response(&self, res: Response) {
306 if let Err(err) = self.send(res) {
307 tracing::error!("failed to send response to unbounded channel: {err:?}")
308 }
309 }
310}
311
312impl<F, Fut> ResponseWriter for F
313where
314 F: Fn(Response) -> Fut + Send + Sync + 'static,
315 Fut: Future<Output = ()> + Send + 'static,
316{
317 async fn write_response(&self, res: Response) {
318 self(res).await
319 }
320}