Skip to main content

armature_core/
streaming.rs

1//! Streaming HTTP Responses
2//!
3//! This module provides support for streaming HTTP responses, enabling efficient
4//! delivery of large data sets, real-time data, and chunked transfers.
5//!
6//! # Features
7//!
8//! - Chunked transfer encoding
9//! - Async stream-based response bodies
10//! - JSON array streaming (NDJSON)
11//! - Text/line streaming
12//! - Binary data streaming
13//! - Progress callbacks
14//!
15//! # Examples
16//!
17//! ## Basic Streaming
18//!
19//! ```ignore
20//! use armature_core::streaming::{StreamingResponse, ByteStream};
21//!
22//! async fn stream_data() -> StreamingResponse {
23//!     let (stream, sender) = ByteStream::new();
24//!
25//!     tokio::spawn(async move {
26//!         for i in 0..100 {
27//!             sender.send(format!("chunk {}\n", i).into_bytes()).await;
28//!         }
29//!     });
30//!
31//!     StreamingResponse::new(stream)
32//!         .content_type("text/plain")
33//! }
34//! ```
35//!
36//! ## JSON Streaming (NDJSON)
37//!
38//! ```ignore
39//! use armature_core::streaming::{StreamingResponse, JsonStream};
40//!
41//! async fn stream_json() -> StreamingResponse {
42//!     let (stream, sender) = JsonStream::new();
43//!
44//!     tokio::spawn(async move {
45//!         for user in load_users() {
46//!             sender.send_json(&user).await;
47//!         }
48//!     });
49//!
50//!     StreamingResponse::ndjson(stream)
51//! }
52//! ```
53
54use crate::{Error, HttpResponse};
55use bytes::Bytes;
56use futures_util::Stream;
57use serde::Serialize;
58use std::collections::HashMap;
59use std::pin::Pin;
60use std::sync::Arc;
61use std::sync::atomic::{AtomicBool, AtomicU64, AtomicUsize, Ordering};
62use std::task::{Context, Poll};
63use std::time::Duration;
64use tokio::sync::mpsc;
65
66// ============================================================================
67// Streaming Body Types
68// ============================================================================
69
70/// A chunk of streaming data.
71#[derive(Debug, Clone)]
72pub enum StreamChunk {
73    /// Raw bytes
74    Bytes(Bytes),
75    /// End of stream
76    End,
77    /// Error occurred
78    Error(String),
79}
80
81impl From<Vec<u8>> for StreamChunk {
82    fn from(v: Vec<u8>) -> Self {
83        StreamChunk::Bytes(Bytes::from(v))
84    }
85}
86
87impl From<Bytes> for StreamChunk {
88    fn from(b: Bytes) -> Self {
89        StreamChunk::Bytes(b)
90    }
91}
92
93impl From<String> for StreamChunk {
94    fn from(s: String) -> Self {
95        StreamChunk::Bytes(Bytes::from(s))
96    }
97}
98
99impl From<&str> for StreamChunk {
100    fn from(s: &str) -> Self {
101        StreamChunk::Bytes(Bytes::from(s.to_owned()))
102    }
103}
104
105// ============================================================================
106// Byte Stream
107// ============================================================================
108
109/// A stream of raw bytes for streaming responses.
110///
111/// # Example
112///
113/// ```
114/// use armature_core::streaming::ByteStream;
115///
116/// # tokio_test::block_on(async {
117/// let (stream, sender) = ByteStream::new();
118///
119/// // Send data in background
120/// tokio::spawn(async move {
121///     sender.send(b"Hello, ".to_vec()).await.ok();
122///     sender.send(b"World!".to_vec()).await.ok();
123///     sender.close().await;
124/// });
125/// # });
126/// ```
127pub struct ByteStream {
128    receiver: mpsc::Receiver<StreamChunk>,
129}
130
131/// Sender half of a byte stream.
132pub struct ByteStreamSender {
133    sender: mpsc::Sender<StreamChunk>,
134    bytes_sent: Arc<AtomicU64>,
135}
136
137impl ByteStream {
138    /// Create a new byte stream with default buffer size (64).
139    pub fn new() -> (Self, ByteStreamSender) {
140        Self::with_buffer_size(64)
141    }
142
143    /// Create a new byte stream with custom buffer size.
144    pub fn with_buffer_size(size: usize) -> (Self, ByteStreamSender) {
145        let (sender, receiver) = mpsc::channel(size);
146        let bytes_sent = Arc::new(AtomicU64::new(0));
147        (Self { receiver }, ByteStreamSender { sender, bytes_sent })
148    }
149}
150
151impl Default for ByteStream {
152    fn default() -> Self {
153        let (stream, _) = Self::new();
154        stream
155    }
156}
157
158impl Stream for ByteStream {
159    type Item = Result<Bytes, Error>;
160
161    fn poll_next(mut self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Option<Self::Item>> {
162        match Pin::new(&mut self.receiver).poll_recv(cx) {
163            Poll::Ready(Some(chunk)) => match chunk {
164                StreamChunk::Bytes(bytes) => Poll::Ready(Some(Ok(bytes))),
165                StreamChunk::End => Poll::Ready(None),
166                StreamChunk::Error(e) => Poll::Ready(Some(Err(Error::Internal(e)))),
167            },
168            Poll::Ready(None) => Poll::Ready(None),
169            Poll::Pending => Poll::Pending,
170        }
171    }
172}
173
174impl ByteStreamSender {
175    /// Send bytes to the stream.
176    pub async fn send(&self, data: impl Into<Vec<u8>>) -> Result<(), Error> {
177        let bytes = data.into();
178        let len = bytes.len() as u64;
179        self.sender
180            .send(StreamChunk::Bytes(Bytes::from(bytes)))
181            .await
182            .map_err(|e| Error::Internal(format!("Failed to send to stream: {}", e)))?;
183        self.bytes_sent.fetch_add(len, Ordering::Relaxed);
184        Ok(())
185    }
186
187    /// Send bytes from a Bytes object.
188    pub async fn send_bytes(&self, bytes: Bytes) -> Result<(), Error> {
189        let len = bytes.len() as u64;
190        self.sender
191            .send(StreamChunk::Bytes(bytes))
192            .await
193            .map_err(|e| Error::Internal(format!("Failed to send to stream: {}", e)))?;
194        self.bytes_sent.fetch_add(len, Ordering::Relaxed);
195        Ok(())
196    }
197
198    /// Send a string to the stream.
199    pub async fn send_str(&self, s: &str) -> Result<(), Error> {
200        self.send(s.as_bytes().to_vec()).await
201    }
202
203    /// Signal an error to the stream.
204    pub async fn send_error(&self, error: impl Into<String>) -> Result<(), Error> {
205        self.sender
206            .send(StreamChunk::Error(error.into()))
207            .await
208            .map_err(|e| Error::Internal(format!("Failed to send error: {}", e)))
209    }
210
211    /// Close the stream.
212    pub async fn close(&self) {
213        let _ = self.sender.send(StreamChunk::End).await;
214    }
215
216    /// Get the total bytes sent so far.
217    pub fn bytes_sent(&self) -> u64 {
218        self.bytes_sent.load(Ordering::Relaxed)
219    }
220
221    /// Check if the receiver has been dropped.
222    pub fn is_closed(&self) -> bool {
223        self.sender.is_closed()
224    }
225}
226
227// ============================================================================
228// JSON Stream (NDJSON)
229// ============================================================================
230
231/// A stream for sending JSON objects as newline-delimited JSON (NDJSON).
232///
233/// Each JSON object is serialized and followed by a newline character.
234/// This format is compatible with tools like `jq` and is easy to parse.
235///
236/// # Example
237///
238/// ```
239/// use armature_core::streaming::JsonStream;
240/// use serde::Serialize;
241///
242/// #[derive(Serialize)]
243/// struct User { id: u64, name: String }
244///
245/// # tokio_test::block_on(async {
246/// let (stream, sender) = JsonStream::new();
247///
248/// tokio::spawn(async move {
249///     sender.send_json(&User { id: 1, name: "Alice".into() }).await.ok();
250///     sender.send_json(&User { id: 2, name: "Bob".into() }).await.ok();
251///     sender.close().await;
252/// });
253/// # });
254/// ```
255pub struct JsonStream {
256    inner: ByteStream,
257}
258
259/// Sender half of a JSON stream.
260pub struct JsonStreamSender {
261    inner: ByteStreamSender,
262    items_sent: Arc<AtomicU64>,
263}
264
265impl JsonStream {
266    /// Create a new JSON stream.
267    pub fn new() -> (Self, JsonStreamSender) {
268        Self::with_buffer_size(64)
269    }
270
271    /// Create a new JSON stream with custom buffer size.
272    pub fn with_buffer_size(size: usize) -> (Self, JsonStreamSender) {
273        let (stream, sender) = ByteStream::with_buffer_size(size);
274        let items_sent = Arc::new(AtomicU64::new(0));
275        (
276            Self { inner: stream },
277            JsonStreamSender {
278                inner: sender,
279                items_sent,
280            },
281        )
282    }
283
284    /// Get the inner byte stream.
285    pub fn into_inner(self) -> ByteStream {
286        self.inner
287    }
288}
289
290impl Default for JsonStream {
291    fn default() -> Self {
292        let (stream, _) = Self::new();
293        stream
294    }
295}
296
297impl Stream for JsonStream {
298    type Item = Result<Bytes, Error>;
299
300    fn poll_next(mut self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Option<Self::Item>> {
301        Pin::new(&mut self.inner).poll_next(cx)
302    }
303}
304
305impl JsonStreamSender {
306    /// Send a JSON-serializable value.
307    pub async fn send_json<T: Serialize>(&self, value: &T) -> Result<(), Error> {
308        let json = serde_json::to_string(value).map_err(|e| Error::Serialization(e.to_string()))?;
309        self.inner.send(format!("{}\n", json)).await?;
310        self.items_sent.fetch_add(1, Ordering::Relaxed);
311        Ok(())
312    }
313
314    /// Send a raw JSON string (must be valid JSON).
315    pub async fn send_raw(&self, json: &str) -> Result<(), Error> {
316        self.inner.send(format!("{}\n", json.trim())).await?;
317        self.items_sent.fetch_add(1, Ordering::Relaxed);
318        Ok(())
319    }
320
321    /// Signal an error as a JSON object.
322    pub async fn send_error(&self, error: impl Into<String>) -> Result<(), Error> {
323        let error_json = serde_json::json!({
324            "error": error.into()
325        });
326        self.send_json(&error_json).await
327    }
328
329    /// Close the stream.
330    pub async fn close(&self) {
331        self.inner.close().await;
332    }
333
334    /// Get the total items sent so far.
335    pub fn items_sent(&self) -> u64 {
336        self.items_sent.load(Ordering::Relaxed)
337    }
338
339    /// Check if the receiver has been dropped.
340    pub fn is_closed(&self) -> bool {
341        self.inner.is_closed()
342    }
343}
344
345// ============================================================================
346// Text/Line Stream
347// ============================================================================
348
349/// A stream for sending text lines.
350///
351/// Each message is followed by a newline character.
352pub struct TextStream {
353    inner: ByteStream,
354}
355
356/// Sender half of a text stream.
357pub struct TextStreamSender {
358    inner: ByteStreamSender,
359    lines_sent: Arc<AtomicU64>,
360}
361
362impl TextStream {
363    /// Create a new text stream.
364    pub fn new() -> (Self, TextStreamSender) {
365        Self::with_buffer_size(64)
366    }
367
368    /// Create a new text stream with custom buffer size.
369    pub fn with_buffer_size(size: usize) -> (Self, TextStreamSender) {
370        let (stream, sender) = ByteStream::with_buffer_size(size);
371        let lines_sent = Arc::new(AtomicU64::new(0));
372        (
373            Self { inner: stream },
374            TextStreamSender {
375                inner: sender,
376                lines_sent,
377            },
378        )
379    }
380
381    /// Get the inner byte stream.
382    pub fn into_inner(self) -> ByteStream {
383        self.inner
384    }
385}
386
387impl Default for TextStream {
388    fn default() -> Self {
389        let (stream, _) = Self::new();
390        stream
391    }
392}
393
394impl Stream for TextStream {
395    type Item = Result<Bytes, Error>;
396
397    fn poll_next(mut self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Option<Self::Item>> {
398        Pin::new(&mut self.inner).poll_next(cx)
399    }
400}
401
402impl TextStreamSender {
403    /// Send a line of text (newline is added automatically).
404    pub async fn send_line(&self, line: &str) -> Result<(), Error> {
405        self.inner.send(format!("{}\n", line)).await?;
406        self.lines_sent.fetch_add(1, Ordering::Relaxed);
407        Ok(())
408    }
409
410    /// Send raw text (no newline added).
411    pub async fn send(&self, text: &str) -> Result<(), Error> {
412        self.inner.send(text.as_bytes().to_vec()).await
413    }
414
415    /// Close the stream.
416    pub async fn close(&self) {
417        self.inner.close().await;
418    }
419
420    /// Get the total lines sent so far.
421    pub fn lines_sent(&self) -> u64 {
422        self.lines_sent.load(Ordering::Relaxed)
423    }
424
425    /// Check if the receiver has been dropped.
426    pub fn is_closed(&self) -> bool {
427        self.inner.is_closed()
428    }
429}
430
431// ============================================================================
432// Streaming Response
433// ============================================================================
434
435/// A streaming HTTP response.
436///
437/// Unlike `HttpResponse` which buffers the entire body, `StreamingResponse`
438/// sends data as it becomes available using chunked transfer encoding.
439///
440/// # Examples
441///
442/// ## Basic Usage
443///
444/// ```ignore
445/// use armature_core::streaming::{StreamingResponse, ByteStream};
446///
447/// let (stream, sender) = ByteStream::new();
448///
449/// // Spawn task to produce data
450/// tokio::spawn(async move {
451///     for i in 0..10 {
452///         sender.send(format!("Line {}\n", i)).await.ok();
453///         tokio::time::sleep(Duration::from_millis(100)).await;
454///     }
455///     sender.close().await;
456/// });
457///
458/// StreamingResponse::new(stream)
459///     .status(200)
460///     .content_type("text/plain")
461/// ```
462pub struct StreamingResponse {
463    /// HTTP status code
464    pub status: u16,
465    /// Response headers
466    pub headers: HashMap<String, String>,
467    /// The stream body
468    body: StreamBody,
469}
470
471/// The body of a streaming response.
472pub enum StreamBody {
473    /// A byte stream
474    Bytes(ByteStream),
475    /// A JSON stream
476    Json(JsonStream),
477    /// A text stream
478    Text(TextStream),
479    /// An empty body
480    Empty,
481}
482
483impl StreamingResponse {
484    /// Create a new streaming response from a byte stream.
485    pub fn new(stream: ByteStream) -> Self {
486        Self {
487            status: 200,
488            headers: HashMap::new(),
489            body: StreamBody::Bytes(stream),
490        }
491    }
492
493    /// Create a new NDJSON streaming response.
494    pub fn ndjson(stream: JsonStream) -> Self {
495        let mut response = Self {
496            status: 200,
497            headers: HashMap::new(),
498            body: StreamBody::Json(stream),
499        };
500        response.headers.insert(
501            "Content-Type".to_string(),
502            "application/x-ndjson".to_string(),
503        );
504        response
505    }
506
507    /// Create a new text streaming response.
508    pub fn text(stream: TextStream) -> Self {
509        let mut response = Self {
510            status: 200,
511            headers: HashMap::new(),
512            body: StreamBody::Text(stream),
513        };
514        response.headers.insert(
515            "Content-Type".to_string(),
516            "text/plain; charset=utf-8".to_string(),
517        );
518        response
519    }
520
521    /// Create an empty streaming response.
522    pub fn empty() -> Self {
523        Self {
524            status: 200,
525            headers: HashMap::new(),
526            body: StreamBody::Empty,
527        }
528    }
529
530    /// Set the HTTP status code.
531    pub fn status(mut self, status: u16) -> Self {
532        self.status = status;
533        self
534    }
535
536    /// Set the Content-Type header.
537    pub fn content_type(mut self, content_type: impl Into<String>) -> Self {
538        self.headers
539            .insert("Content-Type".to_string(), content_type.into());
540        self
541    }
542
543    /// Add a header.
544    pub fn header(mut self, key: impl Into<String>, value: impl Into<String>) -> Self {
545        self.headers.insert(key.into(), value.into());
546        self
547    }
548
549    /// Set Cache-Control to no-cache (recommended for streams).
550    pub fn no_cache(mut self) -> Self {
551        self.headers.insert(
552            "Cache-Control".to_string(),
553            "no-cache, no-store, must-revalidate".to_string(),
554        );
555        self
556    }
557
558    /// Enable CORS for the response.
559    pub fn cors(mut self, origin: impl Into<String>) -> Self {
560        self.headers
561            .insert("Access-Control-Allow-Origin".to_string(), origin.into());
562        self
563    }
564
565    /// Set X-Content-Type-Options to nosniff.
566    pub fn nosniff(mut self) -> Self {
567        self.headers
568            .insert("X-Content-Type-Options".to_string(), "nosniff".to_string());
569        self
570    }
571
572    /// Get the stream body, consuming the response.
573    pub fn into_body(self) -> StreamBody {
574        self.body
575    }
576
577    /// Check if this is an empty response.
578    pub fn is_empty(&self) -> bool {
579        matches!(self.body, StreamBody::Empty)
580    }
581}
582
583impl Default for StreamingResponse {
584    fn default() -> Self {
585        Self::empty()
586    }
587}
588
589// ============================================================================
590// Stream Iterators
591// ============================================================================
592
593/// Stream items from an async iterator.
594///
595/// # Example
596///
597/// ```ignore
598/// use armature_core::streaming::stream_iter;
599///
600/// let items = vec![1, 2, 3, 4, 5];
601/// let (stream, _) = stream_iter(items.into_iter(), |i| format!("{}\n", i));
602/// ```
603pub fn stream_iter<I, T, F>(iter: I, transform: F) -> (ByteStream, tokio::task::JoinHandle<()>)
604where
605    I: Iterator<Item = T> + Send + 'static,
606    T: Send + 'static,
607    F: Fn(T) -> Vec<u8> + Send + 'static,
608{
609    let (stream, sender) = ByteStream::new();
610    let items: Vec<T> = iter.collect(); // Collect to avoid iterator lifetime issues
611    let handle = tokio::spawn(async move {
612        for item in items {
613            if sender.send(transform(item)).await.is_err() {
614                break;
615            }
616        }
617        sender.close().await;
618    });
619    (stream, handle)
620}
621
622/// Stream items from an async iterator with delays.
623pub fn stream_iter_with_delay<I, T, F>(
624    iter: I,
625    transform: F,
626    delay: Duration,
627) -> (ByteStream, tokio::task::JoinHandle<()>)
628where
629    I: Iterator<Item = T> + Send + 'static,
630    T: Send + 'static,
631    F: Fn(T) -> Vec<u8> + Send + 'static,
632{
633    let (stream, sender) = ByteStream::new();
634    let items: Vec<T> = iter.collect(); // Collect to avoid iterator lifetime issues
635    let handle = tokio::spawn(async move {
636        for item in items {
637            if sender.send(transform(item)).await.is_err() {
638                break;
639            }
640            tokio::time::sleep(delay).await;
641        }
642        sender.close().await;
643    });
644    (stream, handle)
645}
646
647/// Stream JSON items from an iterator.
648pub fn stream_json_iter<I, T>(iter: I) -> (JsonStream, tokio::task::JoinHandle<()>)
649where
650    I: Iterator<Item = T> + Send + 'static,
651    T: Serialize + Send + Sync + 'static,
652{
653    let (stream, sender) = JsonStream::new();
654    let items: Vec<T> = iter.collect(); // Collect to avoid iterator lifetime issues
655    let handle = tokio::spawn(async move {
656        for item in items {
657            if sender.send_json(&item).await.is_err() {
658                break;
659            }
660        }
661        sender.close().await;
662    });
663    (stream, handle)
664}
665
666// ============================================================================
667// Stream from Reader
668// ============================================================================
669
670/// Stream data from an async reader (e.g., file, network).
671///
672/// # Example
673///
674/// ```ignore
675/// use tokio::fs::File;
676/// use armature_core::streaming::stream_reader;
677///
678/// let file = File::open("large_file.bin").await?;
679/// let (stream, _) = stream_reader(file, 8192);  // 8KB chunks
680/// ```
681pub fn stream_reader<R>(reader: R, chunk_size: usize) -> (ByteStream, tokio::task::JoinHandle<()>)
682where
683    R: tokio::io::AsyncRead + Unpin + Send + 'static,
684{
685    use tokio::io::AsyncReadExt;
686
687    let (stream, sender) = ByteStream::new();
688    let handle = tokio::spawn(async move {
689        let mut reader = reader;
690        let mut buffer = vec![0u8; chunk_size];
691
692        loop {
693            match reader.read(&mut buffer).await {
694                Ok(0) => break, // EOF
695                Ok(n) => {
696                    if sender.send(buffer[..n].to_vec()).await.is_err() {
697                        break;
698                    }
699                }
700                Err(e) => {
701                    let _ = sender.send_error(e.to_string()).await;
702                    break;
703                }
704            }
705        }
706        sender.close().await;
707    });
708    (stream, handle)
709}
710
711// ============================================================================
712// Progress Tracking
713// ============================================================================
714
715/// A wrapper that tracks progress of a stream.
716pub struct ProgressStream {
717    inner: ByteStream,
718    bytes_received: Arc<AtomicU64>,
719    callback: Option<Box<dyn Fn(u64) + Send + Sync>>,
720}
721
722impl ProgressStream {
723    /// Create a new progress tracking stream.
724    pub fn new(inner: ByteStream) -> Self {
725        Self {
726            inner,
727            bytes_received: Arc::new(AtomicU64::new(0)),
728            callback: None,
729        }
730    }
731
732    /// Set a callback to be called on each chunk received.
733    pub fn on_progress<F>(mut self, callback: F) -> Self
734    where
735        F: Fn(u64) + Send + Sync + 'static,
736    {
737        self.callback = Some(Box::new(callback));
738        self
739    }
740
741    /// Get the total bytes received so far.
742    pub fn bytes_received(&self) -> u64 {
743        self.bytes_received.load(Ordering::Relaxed)
744    }
745}
746
747impl Stream for ProgressStream {
748    type Item = Result<Bytes, Error>;
749
750    fn poll_next(mut self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Option<Self::Item>> {
751        match Pin::new(&mut self.inner).poll_next(cx) {
752            Poll::Ready(Some(Ok(bytes))) => {
753                let len = bytes.len() as u64;
754                let total = self.bytes_received.fetch_add(len, Ordering::Relaxed) + len;
755                if let Some(ref callback) = self.callback {
756                    callback(total);
757                }
758                Poll::Ready(Some(Ok(bytes)))
759            }
760            other => other,
761        }
762    }
763}
764
765// ============================================================================
766// Conversion to HttpResponse
767// ============================================================================
768
769impl StreamingResponse {
770    /// Collect the entire stream into an HttpResponse.
771    ///
772    /// This buffers the entire response body, defeating the purpose of streaming.
773    /// Only use when you need to convert to a buffered response.
774    pub async fn into_buffered(mut self) -> Result<HttpResponse, Error> {
775        use futures_util::StreamExt;
776
777        let mut body = Vec::new();
778
779        match &mut self.body {
780            StreamBody::Bytes(stream) => {
781                while let Some(chunk) = stream.next().await {
782                    body.extend_from_slice(&chunk?);
783                }
784            }
785            StreamBody::Json(stream) => {
786                while let Some(chunk) = stream.next().await {
787                    body.extend_from_slice(&chunk?);
788                }
789            }
790            StreamBody::Text(stream) => {
791                while let Some(chunk) = stream.next().await {
792                    body.extend_from_slice(&chunk?);
793                }
794            }
795            StreamBody::Empty => {}
796        }
797
798        let mut response = HttpResponse::new(self.status);
799        response.headers = self.headers.into();
800        response.body = Bytes::from(body);
801        Ok(response)
802    }
803}
804
805// ============================================================================
806// Tests
807// ============================================================================
808
809#[cfg(test)]
810mod tests {
811    use super::*;
812    use futures_util::StreamExt;
813
814    #[test]
815    fn test_backpressure_concurrent_acks_do_not_underflow() {
816        // Regression test: concurrent over-acks used to double-subtract and
817        // wrap buffer_level to ~usize::MAX, pausing the controller forever.
818        let controller = Arc::new(BackpressureController::new(BackpressureConfig::default()));
819        controller.record_send(100);
820
821        let handles: Vec<_> = (0..4)
822            .map(|_| {
823                let c = Arc::clone(&controller);
824                std::thread::spawn(move || {
825                    for _ in 0..1000 {
826                        c.record_ack(64);
827                    }
828                })
829            })
830            .collect();
831        for h in handles {
832            h.join().unwrap();
833        }
834
835        assert_eq!(controller.buffer_level(), 0);
836        assert!(!controller.is_paused());
837    }
838
839    #[tokio::test]
840    async fn test_backpressure_wait_if_paused_resumes() {
841        let config = BackpressureConfig::new()
842            .high_watermark(10)
843            .low_watermark(2);
844        let controller = Arc::new(BackpressureController::new(config));
845
846        // Exceed high watermark to pause
847        controller.record_send(20);
848        assert!(controller.is_paused());
849
850        let waiter = {
851            let c = Arc::clone(&controller);
852            tokio::spawn(async move {
853                c.wait_if_paused().await;
854            })
855        };
856
857        // Ack below low watermark to resume; the waiter must wake up
858        tokio::task::yield_now().await;
859        controller.record_ack(20);
860
861        tokio::time::timeout(std::time::Duration::from_secs(1), waiter)
862            .await
863            .expect("wait_if_paused should resume after ack")
864            .unwrap();
865        assert!(!controller.is_paused());
866    }
867
868    #[tokio::test]
869    async fn test_byte_stream() {
870        let (mut stream, sender) = ByteStream::new();
871
872        tokio::spawn(async move {
873            sender.send(b"hello".to_vec()).await.unwrap();
874            sender.send(b" world".to_vec()).await.unwrap();
875            sender.close().await;
876        });
877
878        let mut result = Vec::new();
879        while let Some(chunk) = stream.next().await {
880            result.extend_from_slice(&chunk.unwrap());
881        }
882
883        assert_eq!(result, b"hello world");
884    }
885
886    #[tokio::test]
887    async fn test_json_stream() {
888        let (mut stream, sender) = JsonStream::new();
889
890        #[derive(Serialize)]
891        struct Item {
892            id: u64,
893        }
894
895        tokio::spawn(async move {
896            sender.send_json(&Item { id: 1 }).await.unwrap();
897            sender.send_json(&Item { id: 2 }).await.unwrap();
898            sender.close().await;
899        });
900
901        let mut result = Vec::new();
902        while let Some(chunk) = stream.next().await {
903            result.extend_from_slice(&chunk.unwrap());
904        }
905
906        let result_str = String::from_utf8(result).unwrap();
907        assert!(result_str.contains("{\"id\":1}"));
908        assert!(result_str.contains("{\"id\":2}"));
909    }
910
911    #[tokio::test]
912    async fn test_text_stream() {
913        let (mut stream, sender) = TextStream::new();
914
915        tokio::spawn(async move {
916            sender.send_line("line 1").await.unwrap();
917            sender.send_line("line 2").await.unwrap();
918            sender.close().await;
919        });
920
921        let mut result = Vec::new();
922        while let Some(chunk) = stream.next().await {
923            result.extend_from_slice(&chunk.unwrap());
924        }
925
926        let result_str = String::from_utf8(result).unwrap();
927        assert_eq!(result_str, "line 1\nline 2\n");
928    }
929
930    #[tokio::test]
931    async fn test_streaming_response() {
932        let (stream, sender) = ByteStream::new();
933
934        tokio::spawn(async move {
935            sender.send(b"test data".to_vec()).await.unwrap();
936            sender.close().await;
937        });
938
939        let response = StreamingResponse::new(stream)
940            .status(200)
941            .content_type("text/plain")
942            .no_cache();
943
944        assert_eq!(response.status, 200);
945        assert_eq!(
946            response.headers.get("Content-Type"),
947            Some(&"text/plain".to_string())
948        );
949    }
950
951    #[tokio::test]
952    async fn test_stream_iter() {
953        let items = vec![1, 2, 3];
954        let (mut stream, _) = stream_iter(items.into_iter(), |i| format!("{}", i).into_bytes());
955
956        let mut result = Vec::new();
957        while let Some(chunk) = stream.next().await {
958            result.extend_from_slice(&chunk.unwrap());
959        }
960
961        assert_eq!(String::from_utf8(result).unwrap(), "123");
962    }
963
964    #[tokio::test]
965    async fn test_bytes_sent_tracking() {
966        let (stream, sender) = ByteStream::new();
967
968        sender.send(b"hello".to_vec()).await.unwrap();
969        assert_eq!(sender.bytes_sent(), 5);
970
971        sender.send(b" world".to_vec()).await.unwrap();
972        assert_eq!(sender.bytes_sent(), 11);
973
974        // Keep stream alive until we're done
975        drop(stream);
976    }
977
978    #[tokio::test]
979    async fn test_json_items_sent_tracking() {
980        let (stream, sender) = JsonStream::new();
981
982        #[derive(Serialize)]
983        struct Item {
984            id: u64,
985        }
986
987        sender.send_json(&Item { id: 1 }).await.unwrap();
988        assert_eq!(sender.items_sent(), 1);
989
990        sender.send_json(&Item { id: 2 }).await.unwrap();
991        assert_eq!(sender.items_sent(), 2);
992
993        // Keep stream alive until we're done
994        drop(stream);
995    }
996
997    #[tokio::test]
998    async fn test_streaming_response_into_buffered() {
999        let (stream, sender) = ByteStream::new();
1000
1001        tokio::spawn(async move {
1002            sender.send(b"buffered".to_vec()).await.unwrap();
1003            sender.close().await;
1004        });
1005
1006        let response = StreamingResponse::new(stream)
1007            .status(200)
1008            .content_type("text/plain");
1009
1010        let buffered = response.into_buffered().await.unwrap();
1011        assert_eq!(buffered.status, 200);
1012        assert_eq!(buffered.body, Bytes::from_static(b"buffered"));
1013    }
1014
1015    #[test]
1016    fn test_stream_chunk_from() {
1017        let from_vec: StreamChunk = vec![1, 2, 3].into();
1018        assert!(matches!(from_vec, StreamChunk::Bytes(_)));
1019
1020        let from_string: StreamChunk = "hello".to_string().into();
1021        assert!(matches!(from_string, StreamChunk::Bytes(_)));
1022
1023        let from_str: StreamChunk = "world".into();
1024        assert!(matches!(from_str, StreamChunk::Bytes(_)));
1025    }
1026
1027    // Advanced streaming tests
1028
1029    #[test]
1030    fn test_backpressure_config() {
1031        let config = BackpressureConfig::new()
1032            .high_watermark(100)
1033            .low_watermark(20)
1034            .strategy(BackpressureStrategy::PauseResume);
1035
1036        assert_eq!(config.high_watermark, 100);
1037        assert_eq!(config.low_watermark, 20);
1038    }
1039
1040    #[test]
1041    fn test_chunk_optimizer_default() {
1042        let optimizer = ChunkOptimizer::default();
1043        assert_eq!(optimizer.min_chunk, DEFAULT_MIN_CHUNK);
1044        assert_eq!(optimizer.max_chunk, DEFAULT_MAX_CHUNK);
1045    }
1046
1047    #[test]
1048    fn test_chunk_optimizer_sizing() {
1049        let optimizer = ChunkOptimizer::new(512, 8192);
1050
1051        assert_eq!(optimizer.optimal_chunk_size(100), 512); // Below min
1052        assert_eq!(optimizer.optimal_chunk_size(1000), 1000); // In range
1053        assert_eq!(optimizer.optimal_chunk_size(10000), 8192); // Above max
1054    }
1055
1056    #[test]
1057    fn test_streaming_stats() {
1058        let stats = streaming_stats();
1059        let _ = stats.streams_created();
1060        let _ = stats.chunks_sent();
1061        let _ = stats.bytes_sent();
1062    }
1063
1064    #[tokio::test]
1065    async fn test_streaming_body_builder() {
1066        let (body, handle) = StreamingBodyBuilder::new()
1067            .chunk_size(1024)
1068            .build_with_sender();
1069
1070        tokio::spawn(async move {
1071            handle.send(b"test data".to_vec()).await.ok();
1072            handle.close().await;
1073        });
1074
1075        let mut total = 0;
1076        let mut body = body;
1077        while let Some(chunk) = body.next().await {
1078            total += chunk.unwrap().len();
1079        }
1080        assert_eq!(total, 9);
1081    }
1082
1083    #[test]
1084    fn test_rate_limiter() {
1085        let limiter = StreamRateLimiter::new(1024); // 1KB/s
1086        assert_eq!(limiter.bytes_per_sec, 1024);
1087    }
1088
1089    // Advanced chunk optimization tests
1090
1091    #[test]
1092    fn test_chunk_content_type_detection() {
1093        assert_eq!(
1094            ChunkContentType::from_mime("application/json"),
1095            ChunkContentType::Json
1096        );
1097        assert_eq!(
1098            ChunkContentType::from_mime("text/html"),
1099            ChunkContentType::Html
1100        );
1101        assert_eq!(
1102            ChunkContentType::from_mime("text/event-stream"),
1103            ChunkContentType::RealTime
1104        );
1105        assert_eq!(
1106            ChunkContentType::from_mime("video/mp4"),
1107            ChunkContentType::Media
1108        );
1109        assert_eq!(
1110            ChunkContentType::from_mime("application/octet-stream"),
1111            ChunkContentType::Binary
1112        );
1113    }
1114
1115    #[test]
1116    fn test_chunk_content_type_recommendations() {
1117        let realtime = ChunkContentType::RealTime;
1118        assert!(realtime.recommended_chunk_size() < CHUNK_SMALL);
1119
1120        let media = ChunkContentType::Media;
1121        assert!(media.recommended_chunk_size() >= CHUNK_TCP_OPTIMAL);
1122
1123        let binary = ChunkContentType::Binary;
1124        assert!(binary.recommended_chunk_size() >= CHUNK_LARGE);
1125    }
1126
1127    #[test]
1128    fn test_network_condition_from_rtt() {
1129        assert_eq!(
1130            NetworkCondition::from_rtt_ms(5),
1131            NetworkCondition::Excellent
1132        );
1133        assert_eq!(NetworkCondition::from_rtt_ms(30), NetworkCondition::Good);
1134        assert_eq!(NetworkCondition::from_rtt_ms(80), NetworkCondition::Fair);
1135        assert_eq!(NetworkCondition::from_rtt_ms(300), NetworkCondition::Poor);
1136        assert_eq!(
1137            NetworkCondition::from_rtt_ms(1000),
1138            NetworkCondition::Terrible
1139        );
1140    }
1141
1142    #[test]
1143    fn test_network_condition_multipliers() {
1144        assert!(NetworkCondition::Excellent.chunk_multiplier() > 1.0);
1145        assert!((NetworkCondition::Good.chunk_multiplier() - 1.0).abs() < 0.01);
1146        assert!(NetworkCondition::Poor.chunk_multiplier() < 1.0);
1147    }
1148
1149    #[test]
1150    fn test_adaptive_chunk_optimizer() {
1151        let optimizer = AdaptiveChunkOptimizer::new(ChunkContentType::Json);
1152
1153        // Default conditions
1154        let size = optimizer.optimal_size();
1155        assert!(size >= optimizer.min_chunk);
1156        assert!(size <= optimizer.max_chunk);
1157    }
1158
1159    #[test]
1160    fn test_adaptive_optimizer_rtt_adaptation() {
1161        let optimizer = AdaptiveChunkOptimizer::new(ChunkContentType::Binary);
1162
1163        // Record poor network conditions
1164        for _ in 0..5 {
1165            optimizer.record_rtt(300);
1166        }
1167
1168        let poor_size = optimizer.optimal_size();
1169
1170        // Record excellent conditions
1171        for _ in 0..10 {
1172            optimizer.record_rtt(5);
1173        }
1174
1175        let good_size = optimizer.optimal_size();
1176
1177        // Good conditions should allow larger chunks
1178        assert!(good_size >= poor_size);
1179    }
1180
1181    #[test]
1182    fn test_chunked_encoding_optimizer() {
1183        let optimizer = ChunkedEncodingOptimizer::new();
1184
1185        // Small data - single chunk
1186        let plan = optimizer.optimal_for_data(500);
1187        assert_eq!(plan.num_chunks, 1);
1188        assert_eq!(plan.chunk_size, 500);
1189
1190        // Data larger than max_chunk - multiple chunks
1191        let large_data = optimizer.max_chunk * 3;
1192        let plan = optimizer.optimal_for_data(large_data);
1193        assert!(plan.num_chunks > 1);
1194        assert!(plan.efficiency > 0.99);
1195    }
1196
1197    #[test]
1198    fn test_chunked_encoding_efficiency() {
1199        // Small chunks have lower efficiency
1200        let small_eff = ChunkedEncodingOptimizer::chunk_efficiency(100);
1201        let large_eff = ChunkedEncodingOptimizer::chunk_efficiency(16384);
1202
1203        assert!(large_eff > small_eff);
1204        assert!(large_eff > 0.99); // Large chunks very efficient
1205    }
1206
1207    #[test]
1208    fn test_chunked_encoding_create_chunks() {
1209        let optimizer = ChunkedEncodingOptimizer::new().target_chunk(100);
1210
1211        let data = vec![0u8; 350];
1212        let chunks = optimizer.create_chunks(&data);
1213
1214        // Should create multiple chunks
1215        assert!(chunks.len() >= 3);
1216
1217        // Total size should match
1218        let total: usize = chunks.iter().map(|c| c.len()).sum();
1219        assert_eq!(total, 350);
1220    }
1221
1222    #[test]
1223    fn test_chunk_stats() {
1224        let stats = chunk_stats();
1225        let _ = stats.chunks_created();
1226        let _ = stats.bytes_chunked();
1227        let _ = stats.average_chunk_size();
1228        let _ = stats.average_rtt();
1229    }
1230}
1231
1232// ============================================================================
1233// Advanced Streaming Features
1234// ============================================================================
1235
1236// Default chunk sizes
1237/// Minimum chunk size (4KB)
1238pub const DEFAULT_MIN_CHUNK: usize = 4 * 1024;
1239/// Default chunk size (16KB)
1240pub const DEFAULT_CHUNK_SIZE: usize = 16 * 1024;
1241/// Maximum chunk size (64KB)
1242pub const DEFAULT_MAX_CHUNK: usize = 64 * 1024;
1243
1244// ============================================================================
1245// Backpressure Handling
1246// ============================================================================
1247
1248/// Strategy for handling backpressure when consumer is slow.
1249#[derive(Debug, Clone, Copy, PartialEq, Eq, Default)]
1250pub enum BackpressureStrategy {
1251    /// Pause production when buffer is full (default)
1252    #[default]
1253    PauseResume,
1254    /// Drop oldest chunks when buffer is full
1255    DropOldest,
1256    /// Drop newest chunks when buffer is full
1257    DropNewest,
1258    /// Block producer until space is available
1259    Block,
1260    /// Error when buffer is full
1261    Error,
1262}
1263
1264/// Configuration for backpressure handling.
1265#[derive(Debug, Clone)]
1266pub struct BackpressureConfig {
1267    /// High watermark - pause when buffer exceeds this
1268    pub high_watermark: usize,
1269    /// Low watermark - resume when buffer drops below this
1270    pub low_watermark: usize,
1271    /// Backpressure strategy
1272    pub strategy: BackpressureStrategy,
1273    /// Maximum buffer size (for DropOldest/DropNewest)
1274    pub max_buffer: usize,
1275}
1276
1277impl Default for BackpressureConfig {
1278    fn default() -> Self {
1279        Self {
1280            high_watermark: 64,
1281            low_watermark: 16,
1282            strategy: BackpressureStrategy::PauseResume,
1283            max_buffer: 256,
1284        }
1285    }
1286}
1287
1288impl BackpressureConfig {
1289    /// Create new configuration.
1290    pub fn new() -> Self {
1291        Self::default()
1292    }
1293
1294    /// Set high watermark.
1295    pub fn high_watermark(mut self, watermark: usize) -> Self {
1296        self.high_watermark = watermark;
1297        self
1298    }
1299
1300    /// Set low watermark.
1301    pub fn low_watermark(mut self, watermark: usize) -> Self {
1302        self.low_watermark = watermark;
1303        self
1304    }
1305
1306    /// Set backpressure strategy.
1307    pub fn strategy(mut self, strategy: BackpressureStrategy) -> Self {
1308        self.strategy = strategy;
1309        self
1310    }
1311
1312    /// Set maximum buffer size.
1313    pub fn max_buffer(mut self, size: usize) -> Self {
1314        self.max_buffer = size;
1315        self
1316    }
1317}
1318
1319/// Backpressure controller for flow control with slow clients.
1320///
1321/// Manages the flow of data to slow consumers by tracking buffer levels
1322/// and pausing/resuming production based on watermarks.
1323///
1324/// # Example
1325///
1326/// ```rust,ignore
1327/// use armature_core::streaming::{BackpressureController, BackpressureConfig};
1328///
1329/// let config = BackpressureConfig::new()
1330///     .high_watermark(100)
1331///     .low_watermark(20);
1332///
1333/// let mut controller = BackpressureController::new(config);
1334///
1335/// // Producer loop
1336/// loop {
1337///     // Wait if backpressure is applied
1338///     controller.wait_if_paused().await;
1339///
1340///     // Check if we can send
1341///     if controller.can_send() {
1342///         // Send data...
1343///         controller.record_send(chunk_size);
1344///     }
1345/// }
1346///
1347/// // Consumer acknowledged data
1348/// controller.record_ack(bytes_consumed);
1349/// ```
1350#[derive(Debug)]
1351pub struct BackpressureController {
1352    config: BackpressureConfig,
1353    /// Current buffer level (bytes pending)
1354    buffer_level: AtomicUsize,
1355    /// Whether production is paused
1356    is_paused: AtomicBool,
1357    /// Notification for resume
1358    resume_notify: Arc<tokio::sync::Notify>,
1359    /// Statistics
1360    stats: BackpressureStats,
1361}
1362
1363/// Statistics for backpressure monitoring.
1364#[derive(Debug, Default)]
1365pub struct BackpressureStats {
1366    /// Total bytes sent
1367    pub bytes_sent: AtomicU64,
1368    /// Total bytes acknowledged
1369    pub bytes_acked: AtomicU64,
1370    /// Number of times paused
1371    pub pause_count: AtomicU64,
1372    /// Number of times resumed
1373    pub resume_count: AtomicU64,
1374    /// Number of dropped chunks (if using drop strategy)
1375    pub dropped_chunks: AtomicU64,
1376    /// Number of dropped bytes
1377    pub dropped_bytes: AtomicU64,
1378}
1379
1380impl BackpressureController {
1381    /// Create a new backpressure controller.
1382    pub fn new(config: BackpressureConfig) -> Self {
1383        Self {
1384            config,
1385            buffer_level: AtomicUsize::new(0),
1386            is_paused: AtomicBool::new(false),
1387            resume_notify: Arc::new(tokio::sync::Notify::new()),
1388            stats: BackpressureStats::default(),
1389        }
1390    }
1391
1392    /// Create with default configuration.
1393    pub fn default_controller() -> Self {
1394        Self::new(BackpressureConfig::default())
1395    }
1396
1397    /// Check if data can be sent without blocking.
1398    #[inline]
1399    pub fn can_send(&self) -> bool {
1400        !self.is_paused.load(Ordering::Acquire)
1401    }
1402
1403    /// Check if currently paused.
1404    #[inline]
1405    pub fn is_paused(&self) -> bool {
1406        self.is_paused.load(Ordering::Acquire)
1407    }
1408
1409    /// Get current buffer level.
1410    #[inline]
1411    pub fn buffer_level(&self) -> usize {
1412        self.buffer_level.load(Ordering::Acquire)
1413    }
1414
1415    /// Get buffer utilization (0.0 - 1.0+).
1416    pub fn buffer_utilization(&self) -> f64 {
1417        let level = self.buffer_level() as f64;
1418        let max = self.config.max_buffer as f64;
1419        level / max
1420    }
1421
1422    /// Record data being sent (increases buffer level).
1423    pub fn record_send(&self, bytes: usize) {
1424        let new_level = self.buffer_level.fetch_add(bytes, Ordering::AcqRel) + bytes;
1425        self.stats
1426            .bytes_sent
1427            .fetch_add(bytes as u64, Ordering::Relaxed);
1428
1429        // Check if we should pause
1430        if new_level >= self.config.high_watermark && !self.is_paused.swap(true, Ordering::AcqRel) {
1431            self.stats.pause_count.fetch_add(1, Ordering::Relaxed);
1432        }
1433    }
1434
1435    /// Record data being acknowledged by consumer (decreases buffer level).
1436    pub fn record_ack(&self, bytes: usize) {
1437        // Saturating subtraction via fetch_update: a plain fetch_sub of
1438        // `bytes.min(buffer_level())` races with concurrent acks and can
1439        // wrap the level to ~usize::MAX, pausing the controller forever.
1440        let old_level = self
1441            .buffer_level
1442            .fetch_update(Ordering::AcqRel, Ordering::Acquire, |level| {
1443                Some(level.saturating_sub(bytes))
1444            })
1445            .expect("fetch_update closure never returns None");
1446        let new_level = old_level.saturating_sub(bytes);
1447        self.stats
1448            .bytes_acked
1449            .fetch_add(bytes as u64, Ordering::Relaxed);
1450
1451        // Check if we should resume
1452        if new_level <= self.config.low_watermark && self.is_paused.swap(false, Ordering::AcqRel) {
1453            self.stats.resume_count.fetch_add(1, Ordering::Relaxed);
1454            self.resume_notify.notify_waiters();
1455        }
1456    }
1457
1458    /// Wait until not paused (for async producers).
1459    pub async fn wait_if_paused(&self) {
1460        loop {
1461            // Create the Notified future before re-checking the paused flag:
1462            // checking first would lose a wakeup that fires between the check
1463            // and the await, leaving the producer parked forever.
1464            let notified = self.resume_notify.notified();
1465            if !self.is_paused() {
1466                return;
1467            }
1468            notified.await;
1469        }
1470    }
1471
1472    /// Try to send data, handling backpressure according to strategy.
1473    ///
1474    /// Returns:
1475    /// - `Ok(true)` if data was accepted
1476    /// - `Ok(false)` if data was dropped (drop strategies)
1477    /// - `Err` if strategy is Error and buffer is full
1478    pub fn try_send(&self, bytes: usize) -> Result<bool, BackpressureError> {
1479        let current = self.buffer_level();
1480
1481        match self.config.strategy {
1482            BackpressureStrategy::PauseResume => {
1483                if current < self.config.max_buffer {
1484                    self.record_send(bytes);
1485                    Ok(true)
1486                } else {
1487                    // Will be unblocked when consumer catches up
1488                    Ok(false)
1489                }
1490            }
1491            BackpressureStrategy::Block => {
1492                // Always accept, let wait_if_paused handle blocking
1493                self.record_send(bytes);
1494                Ok(true)
1495            }
1496            BackpressureStrategy::DropOldest | BackpressureStrategy::DropNewest => {
1497                if current + bytes > self.config.max_buffer {
1498                    self.stats.dropped_chunks.fetch_add(1, Ordering::Relaxed);
1499                    self.stats
1500                        .dropped_bytes
1501                        .fetch_add(bytes as u64, Ordering::Relaxed);
1502                    Ok(false)
1503                } else {
1504                    self.record_send(bytes);
1505                    Ok(true)
1506                }
1507            }
1508            BackpressureStrategy::Error => {
1509                if current + bytes > self.config.max_buffer {
1510                    Err(BackpressureError::BufferFull {
1511                        current,
1512                        max: self.config.max_buffer,
1513                    })
1514                } else {
1515                    self.record_send(bytes);
1516                    Ok(true)
1517                }
1518            }
1519        }
1520    }
1521
1522    /// Reset the controller state.
1523    pub fn reset(&self) {
1524        self.buffer_level.store(0, Ordering::Release);
1525        self.is_paused.store(false, Ordering::Release);
1526        self.resume_notify.notify_waiters();
1527    }
1528
1529    /// Get statistics.
1530    pub fn stats(&self) -> &BackpressureStats {
1531        &self.stats
1532    }
1533
1534    /// Get a snapshot of current state.
1535    pub fn snapshot(&self) -> BackpressureSnapshot {
1536        BackpressureSnapshot {
1537            buffer_level: self.buffer_level(),
1538            is_paused: self.is_paused(),
1539            utilization: self.buffer_utilization(),
1540            bytes_sent: self.stats.bytes_sent.load(Ordering::Relaxed),
1541            bytes_acked: self.stats.bytes_acked.load(Ordering::Relaxed),
1542            pause_count: self.stats.pause_count.load(Ordering::Relaxed),
1543            dropped_chunks: self.stats.dropped_chunks.load(Ordering::Relaxed),
1544        }
1545    }
1546}
1547
1548/// Snapshot of backpressure state.
1549#[derive(Debug, Clone)]
1550pub struct BackpressureSnapshot {
1551    pub buffer_level: usize,
1552    pub is_paused: bool,
1553    pub utilization: f64,
1554    pub bytes_sent: u64,
1555    pub bytes_acked: u64,
1556    pub pause_count: u64,
1557    pub dropped_chunks: u64,
1558}
1559
1560/// Error when backpressure buffer is full.
1561#[derive(Debug, Clone)]
1562pub enum BackpressureError {
1563    BufferFull { current: usize, max: usize },
1564}
1565
1566impl std::fmt::Display for BackpressureError {
1567    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
1568        match self {
1569            Self::BufferFull { current, max } => {
1570                write!(f, "Backpressure buffer full: {} / {} bytes", current, max)
1571            }
1572        }
1573    }
1574}
1575
1576impl std::error::Error for BackpressureError {}
1577
1578// ============================================================================
1579// Chunk Optimization
1580// ============================================================================
1581
1582/// Optimizes chunk sizes for efficient streaming.
1583#[derive(Debug, Clone)]
1584pub struct ChunkOptimizer {
1585    /// Minimum chunk size
1586    pub min_chunk: usize,
1587    /// Maximum chunk size
1588    pub max_chunk: usize,
1589    /// Target latency in milliseconds
1590    pub target_latency_ms: u64,
1591    /// Observed throughput (bytes/sec)
1592    throughput: Arc<AtomicU64>,
1593    /// Chunk count
1594    chunk_count: Arc<AtomicU64>,
1595}
1596
1597impl ChunkOptimizer {
1598    /// Create a new chunk optimizer.
1599    pub fn new(min_chunk: usize, max_chunk: usize) -> Self {
1600        Self {
1601            min_chunk,
1602            max_chunk,
1603            target_latency_ms: 50, // 50ms default
1604            throughput: Arc::new(AtomicU64::new(0)),
1605            chunk_count: Arc::new(AtomicU64::new(0)),
1606        }
1607    }
1608
1609    /// Create with target latency.
1610    pub fn with_target_latency(mut self, ms: u64) -> Self {
1611        self.target_latency_ms = ms;
1612        self
1613    }
1614
1615    /// Calculate optimal chunk size based on available data.
1616    #[inline]
1617    pub fn optimal_chunk_size(&self, available: usize) -> usize {
1618        available.clamp(self.min_chunk, self.max_chunk)
1619    }
1620
1621    /// Record a chunk being sent for throughput tracking.
1622    pub fn record_chunk(&self, size: usize) {
1623        self.throughput.fetch_add(size as u64, Ordering::Relaxed);
1624        self.chunk_count.fetch_add(1, Ordering::Relaxed);
1625    }
1626
1627    /// Get total bytes sent.
1628    pub fn total_bytes(&self) -> u64 {
1629        self.throughput.load(Ordering::Relaxed)
1630    }
1631
1632    /// Get total chunks sent.
1633    pub fn total_chunks(&self) -> u64 {
1634        self.chunk_count.load(Ordering::Relaxed)
1635    }
1636
1637    /// Get average chunk size.
1638    pub fn average_chunk_size(&self) -> usize {
1639        self.total_bytes()
1640            .checked_div(self.total_chunks())
1641            .map(|v| v as usize)
1642            .unwrap_or(self.min_chunk)
1643    }
1644}
1645
1646impl Default for ChunkOptimizer {
1647    fn default() -> Self {
1648        Self::new(DEFAULT_MIN_CHUNK, DEFAULT_MAX_CHUNK)
1649    }
1650}
1651
1652// ============================================================================
1653// Advanced Chunk Size Optimization
1654// ============================================================================
1655
1656/// Chunk size presets for different content types.
1657pub const CHUNK_TINY: usize = 512;
1658/// Small chunk for real-time data (1KB)
1659pub const CHUNK_SMALL: usize = 1024;
1660/// Medium chunk for mixed content (8KB)
1661pub const CHUNK_MEDIUM: usize = 8 * 1024;
1662/// Large chunk for bulk transfers (32KB)
1663pub const CHUNK_LARGE: usize = 32 * 1024;
1664/// Extra large chunk for static files (128KB)
1665pub const CHUNK_XLARGE: usize = 128 * 1024;
1666/// Optimal for TCP window (64KB - typical MSS multiple)
1667pub const CHUNK_TCP_OPTIMAL: usize = 64 * 1024;
1668
1669/// Content type categories for chunk optimization.
1670#[derive(Debug, Clone, Copy, PartialEq, Eq)]
1671pub enum ChunkContentType {
1672    /// Real-time event streams (SSE, WebSocket-like)
1673    RealTime,
1674    /// JSON data
1675    Json,
1676    /// HTML content
1677    Html,
1678    /// Plain text
1679    Text,
1680    /// Binary data (images, files)
1681    Binary,
1682    /// Streaming media (video, audio)
1683    Media,
1684    /// Unknown/generic
1685    Unknown,
1686}
1687
1688impl ChunkContentType {
1689    /// Detect content type from MIME type string.
1690    pub fn from_mime(mime: &str) -> Self {
1691        let mime_lower = mime.to_lowercase();
1692        if mime_lower.contains("text/event-stream") || mime_lower.contains("x-ndjson") {
1693            Self::RealTime
1694        } else if mime_lower.contains("json") {
1695            Self::Json
1696        } else if mime_lower.contains("html") {
1697            Self::Html
1698        } else if mime_lower.contains("text/") {
1699            Self::Text
1700        } else if mime_lower.contains("application/octet-stream")
1701            || mime_lower.contains("image/")
1702            || mime_lower.contains("font/")
1703        {
1704            Self::Binary
1705        } else if mime_lower.contains("video/") || mime_lower.contains("audio/") {
1706            Self::Media
1707        } else {
1708            Self::Unknown
1709        }
1710    }
1711
1712    /// Get recommended chunk size for this content type.
1713    pub fn recommended_chunk_size(&self) -> usize {
1714        match self {
1715            Self::RealTime => CHUNK_TINY,        // 512B - minimize latency
1716            Self::Json => CHUNK_MEDIUM,          // 8KB - balance latency/throughput
1717            Self::Html => CHUNK_MEDIUM,          // 8KB - good for progressive rendering
1718            Self::Text => CHUNK_SMALL,           // 1KB - line-oriented
1719            Self::Binary => CHUNK_LARGE,         // 32KB - maximize throughput
1720            Self::Media => CHUNK_TCP_OPTIMAL,    // 64KB - optimal for streaming
1721            Self::Unknown => DEFAULT_CHUNK_SIZE, // 16KB - safe default
1722        }
1723    }
1724
1725    /// Get minimum chunk size for this content type.
1726    pub fn min_chunk_size(&self) -> usize {
1727        match self {
1728            Self::RealTime => 64,         // Can send very small updates
1729            Self::Json => CHUNK_SMALL,    // At least one object
1730            Self::Html => CHUNK_SMALL,    // At least one tag
1731            Self::Text => 128,            // At least one line
1732            Self::Binary => CHUNK_MEDIUM, // Worth the overhead
1733            Self::Media => CHUNK_MEDIUM,  // Minimize fragmentation
1734            Self::Unknown => CHUNK_SMALL, // Conservative
1735        }
1736    }
1737
1738    /// Get maximum chunk size for this content type.
1739    pub fn max_chunk_size(&self) -> usize {
1740        match self {
1741            Self::RealTime => CHUNK_SMALL, // Keep latency low
1742            Self::Json => CHUNK_LARGE,     // Single objects can be large
1743            Self::Html => CHUNK_LARGE,     // Full pages
1744            Self::Text => CHUNK_MEDIUM,    // Not too large
1745            Self::Binary => CHUNK_XLARGE,  // Large files
1746            Self::Media => CHUNK_XLARGE,   // Video frames
1747            Self::Unknown => CHUNK_LARGE,  // Safe default
1748        }
1749    }
1750}
1751
1752/// Network condition estimate for adaptive chunking.
1753#[derive(Debug, Clone, Copy, PartialEq, Eq)]
1754pub enum NetworkCondition {
1755    /// Excellent (< 10ms RTT, > 100 Mbps)
1756    Excellent,
1757    /// Good (< 50ms RTT, > 10 Mbps)
1758    Good,
1759    /// Fair (< 100ms RTT, > 1 Mbps)
1760    Fair,
1761    /// Poor (< 500ms RTT, > 100 Kbps)
1762    Poor,
1763    /// Terrible (> 500ms RTT)
1764    Terrible,
1765    /// Unknown conditions
1766    Unknown,
1767}
1768
1769impl NetworkCondition {
1770    /// Estimate condition from RTT in milliseconds.
1771    pub fn from_rtt_ms(rtt_ms: u64) -> Self {
1772        match rtt_ms {
1773            0..=10 => Self::Excellent,
1774            11..=50 => Self::Good,
1775            51..=100 => Self::Fair,
1776            101..=500 => Self::Poor,
1777            _ => Self::Terrible,
1778        }
1779    }
1780
1781    /// Estimate condition from throughput in bytes/sec.
1782    pub fn from_throughput(bytes_per_sec: u64) -> Self {
1783        match bytes_per_sec {
1784            x if x > 12_500_000 => Self::Excellent, // > 100 Mbps
1785            x if x > 1_250_000 => Self::Good,       // > 10 Mbps
1786            x if x > 125_000 => Self::Fair,         // > 1 Mbps
1787            x if x > 12_500 => Self::Poor,          // > 100 Kbps
1788            _ => Self::Terrible,
1789        }
1790    }
1791
1792    /// Get recommended chunk size multiplier.
1793    pub fn chunk_multiplier(&self) -> f32 {
1794        match self {
1795            Self::Excellent => 2.0, // Larger chunks, fewer round trips
1796            Self::Good => 1.0,      // Default sizes
1797            Self::Fair => 0.75,     // Slightly smaller
1798            Self::Poor => 0.5,      // Smaller chunks, faster feedback
1799            Self::Terrible => 0.25, // Very small, prevent timeouts
1800            Self::Unknown => 1.0,   // Default
1801        }
1802    }
1803}
1804
1805/// Advanced chunk size optimizer with adaptive sizing.
1806#[derive(Debug)]
1807pub struct AdaptiveChunkOptimizer {
1808    /// Content type for optimization
1809    content_type: ChunkContentType,
1810    /// Current network condition estimate
1811    network_condition: std::sync::atomic::AtomicU8,
1812    /// Base chunk size
1813    base_chunk: usize,
1814    /// Minimum allowed chunk
1815    min_chunk: usize,
1816    /// Maximum allowed chunk
1817    max_chunk: usize,
1818    /// RTT samples (circular buffer of last 16)
1819    rtt_samples: std::sync::Mutex<RttTracker>,
1820    /// Throughput tracker
1821    throughput_tracker: ThroughputTracker,
1822    /// Bytes sent
1823    bytes_sent: AtomicU64,
1824    /// Chunks sent
1825    chunks_sent: AtomicU64,
1826}
1827
1828impl AdaptiveChunkOptimizer {
1829    /// Create a new adaptive optimizer.
1830    pub fn new(content_type: ChunkContentType) -> Self {
1831        Self {
1832            min_chunk: content_type.min_chunk_size(),
1833            max_chunk: content_type.max_chunk_size(),
1834            base_chunk: content_type.recommended_chunk_size(),
1835            content_type,
1836            network_condition: std::sync::atomic::AtomicU8::new(NetworkCondition::Unknown as u8),
1837            rtt_samples: std::sync::Mutex::new(RttTracker::new()),
1838            throughput_tracker: ThroughputTracker::new(),
1839            bytes_sent: AtomicU64::new(0),
1840            chunks_sent: AtomicU64::new(0),
1841        }
1842    }
1843
1844    /// Create from MIME type.
1845    pub fn from_mime(mime: &str) -> Self {
1846        Self::new(ChunkContentType::from_mime(mime))
1847    }
1848
1849    /// Create with custom bounds.
1850    pub fn with_bounds(mut self, min: usize, max: usize) -> Self {
1851        self.min_chunk = min;
1852        self.max_chunk = max;
1853        self
1854    }
1855
1856    /// Set base chunk size.
1857    pub fn with_base_chunk(mut self, base: usize) -> Self {
1858        self.base_chunk = base;
1859        self
1860    }
1861
1862    /// Calculate optimal chunk size.
1863    #[inline]
1864    pub fn optimal_size(&self) -> usize {
1865        let condition = self.current_condition();
1866        let multiplier = condition.chunk_multiplier();
1867        let optimal = (self.base_chunk as f32 * multiplier) as usize;
1868        optimal.clamp(self.min_chunk, self.max_chunk)
1869    }
1870
1871    /// Calculate optimal chunk size for given data.
1872    #[inline]
1873    pub fn optimal_for_data(&self, data_len: usize) -> usize {
1874        let optimal = self.optimal_size();
1875        // Don't create tiny final chunks
1876        if data_len <= optimal * 3 / 2 {
1877            data_len // Send all at once
1878        } else {
1879            optimal
1880        }
1881    }
1882
1883    /// Record RTT sample for adaptive sizing.
1884    pub fn record_rtt(&self, rtt_ms: u64) {
1885        let mut tracker = self.rtt_samples.lock().unwrap();
1886        tracker.add_sample(rtt_ms);
1887        let avg_rtt = tracker.average();
1888        let condition = NetworkCondition::from_rtt_ms(avg_rtt);
1889        self.network_condition
1890            .store(condition as u8, Ordering::Relaxed);
1891        CHUNK_STATS.record_rtt_sample(rtt_ms);
1892    }
1893
1894    /// Record throughput sample.
1895    pub fn record_throughput(&self, bytes: usize, duration_ms: u64) {
1896        let Some(bytes_per_sec) = (bytes as u64 * 1000).checked_div(duration_ms) else {
1897            return;
1898        };
1899        self.throughput_tracker.record(bytes_per_sec);
1900        // Update condition based on throughput too
1901        let throughput_condition = NetworkCondition::from_throughput(bytes_per_sec);
1902        let rtt_condition = self.current_condition();
1903        // Use worse of the two estimates
1904        let combined = if (throughput_condition as u8) > (rtt_condition as u8) {
1905            throughput_condition
1906        } else {
1907            rtt_condition
1908        };
1909        self.network_condition
1910            .store(combined as u8, Ordering::Relaxed);
1911    }
1912
1913    /// Record a chunk being sent.
1914    pub fn record_chunk(&self, size: usize) {
1915        self.bytes_sent.fetch_add(size as u64, Ordering::Relaxed);
1916        self.chunks_sent.fetch_add(1, Ordering::Relaxed);
1917        CHUNK_STATS.record_chunk(size);
1918    }
1919
1920    /// Get current network condition estimate.
1921    pub fn current_condition(&self) -> NetworkCondition {
1922        let val = self.network_condition.load(Ordering::Relaxed);
1923        match val {
1924            0 => NetworkCondition::Excellent,
1925            1 => NetworkCondition::Good,
1926            2 => NetworkCondition::Fair,
1927            3 => NetworkCondition::Poor,
1928            4 => NetworkCondition::Terrible,
1929            _ => NetworkCondition::Unknown,
1930        }
1931    }
1932
1933    /// Get average RTT.
1934    pub fn average_rtt(&self) -> u64 {
1935        self.rtt_samples.lock().unwrap().average()
1936    }
1937
1938    /// Get estimated throughput (bytes/sec).
1939    pub fn estimated_throughput(&self) -> u64 {
1940        self.throughput_tracker.average()
1941    }
1942
1943    /// Get total bytes sent.
1944    pub fn bytes_sent(&self) -> u64 {
1945        self.bytes_sent.load(Ordering::Relaxed)
1946    }
1947
1948    /// Get total chunks sent.
1949    pub fn chunks_sent(&self) -> u64 {
1950        self.chunks_sent.load(Ordering::Relaxed)
1951    }
1952
1953    /// Get average chunk size.
1954    pub fn average_chunk_size(&self) -> usize {
1955        self.bytes_sent()
1956            .checked_div(self.chunks_sent())
1957            .map(|v| v as usize)
1958            .unwrap_or(self.base_chunk)
1959    }
1960
1961    /// Get content type.
1962    pub fn content_type(&self) -> ChunkContentType {
1963        self.content_type
1964    }
1965}
1966
1967/// Circular buffer for RTT tracking.
1968#[derive(Debug)]
1969struct RttTracker {
1970    samples: [u64; 16],
1971    index: usize,
1972    count: usize,
1973}
1974
1975impl RttTracker {
1976    fn new() -> Self {
1977        Self {
1978            samples: [0; 16],
1979            index: 0,
1980            count: 0,
1981        }
1982    }
1983
1984    fn add_sample(&mut self, rtt_ms: u64) {
1985        self.samples[self.index] = rtt_ms;
1986        self.index = (self.index + 1) % 16;
1987        if self.count < 16 {
1988            self.count += 1;
1989        }
1990    }
1991
1992    fn average(&self) -> u64 {
1993        if self.count == 0 {
1994            return 50; // Default assumption
1995        }
1996        let sum: u64 = self.samples[..self.count].iter().sum();
1997        sum / self.count as u64
1998    }
1999}
2000
2001/// Throughput tracking.
2002#[derive(Debug)]
2003struct ThroughputTracker {
2004    samples: std::sync::Mutex<Vec<u64>>,
2005    max_samples: usize,
2006}
2007
2008impl ThroughputTracker {
2009    fn new() -> Self {
2010        Self {
2011            samples: std::sync::Mutex::new(Vec::with_capacity(16)),
2012            max_samples: 16,
2013        }
2014    }
2015
2016    fn record(&self, bytes_per_sec: u64) {
2017        let mut samples = self.samples.lock().unwrap();
2018        if samples.len() >= self.max_samples {
2019            samples.remove(0);
2020        }
2021        samples.push(bytes_per_sec);
2022    }
2023
2024    fn average(&self) -> u64 {
2025        let samples = self.samples.lock().unwrap();
2026        if samples.is_empty() {
2027            return 0;
2028        }
2029        let sum: u64 = samples.iter().sum();
2030        sum / samples.len() as u64
2031    }
2032}
2033
2034// ============================================================================
2035// HTTP Chunked Encoding Optimizer
2036// ============================================================================
2037
2038/// Optimizes chunks specifically for HTTP chunked transfer encoding.
2039///
2040/// HTTP chunked encoding has overhead per chunk:
2041/// - Chunk size in hex + CRLF (variable, typically 1-8 bytes)
2042/// - Chunk data
2043/// - CRLF (2 bytes)
2044///
2045/// Total overhead per chunk: ~4-10 bytes
2046#[derive(Debug, Clone)]
2047pub struct ChunkedEncodingOptimizer {
2048    /// Minimum chunk to justify encoding overhead
2049    pub min_chunk: usize,
2050    /// Target chunk size
2051    pub target_chunk: usize,
2052    /// Maximum chunk size
2053    pub max_chunk: usize,
2054    /// Overhead threshold (minimum efficiency %)
2055    pub min_efficiency: f32,
2056}
2057
2058impl ChunkedEncodingOptimizer {
2059    /// Create a new optimizer.
2060    pub fn new() -> Self {
2061        Self::default()
2062    }
2063
2064    /// Set target chunk size.
2065    pub fn target_chunk(mut self, size: usize) -> Self {
2066        self.target_chunk = size;
2067        self
2068    }
2069
2070    /// Set minimum efficiency (0.0-1.0).
2071    pub fn min_efficiency(mut self, efficiency: f32) -> Self {
2072        self.min_efficiency = efficiency.clamp(0.5, 1.0);
2073        self
2074    }
2075
2076    /// Calculate overhead for a chunk size.
2077    #[inline]
2078    pub fn chunk_overhead(chunk_size: usize) -> usize {
2079        // hex size + CRLF + data + CRLF
2080        let hex_digits = if chunk_size == 0 {
2081            1
2082        } else {
2083            (chunk_size as f64).log(16.0).floor() as usize + 1
2084        };
2085        hex_digits + 4 // hex + CRLF + CRLF
2086    }
2087
2088    /// Calculate efficiency for a chunk size.
2089    #[inline]
2090    pub fn chunk_efficiency(chunk_size: usize) -> f32 {
2091        if chunk_size == 0 {
2092            return 0.0;
2093        }
2094        let overhead = Self::chunk_overhead(chunk_size);
2095        chunk_size as f32 / (chunk_size + overhead) as f32
2096    }
2097
2098    /// Calculate optimal chunk size for given data.
2099    pub fn optimal_for_data(&self, data_len: usize) -> ChunkingPlan {
2100        if data_len == 0 {
2101            return ChunkingPlan {
2102                chunk_size: 0,
2103                num_chunks: 0,
2104                final_chunk: 0,
2105                efficiency: 1.0,
2106            };
2107        }
2108
2109        // If data fits in one chunk efficiently, send it all
2110        if data_len <= self.max_chunk {
2111            let eff = Self::chunk_efficiency(data_len);
2112            if eff >= self.min_efficiency {
2113                return ChunkingPlan {
2114                    chunk_size: data_len,
2115                    num_chunks: 1,
2116                    final_chunk: 0,
2117                    efficiency: eff,
2118                };
2119            }
2120        }
2121
2122        // Calculate number of chunks at target size
2123        let target = self.target_chunk.min(data_len);
2124        let num_chunks = data_len / target;
2125        let remainder = data_len % target;
2126
2127        // Avoid tiny final chunk
2128        let (chunk_size, final_chunk) = if remainder > 0 && remainder < self.min_chunk {
2129            // Redistribute to avoid tiny chunk
2130            let adjusted_chunks = num_chunks;
2131            let adjusted_size = data_len / adjusted_chunks;
2132            let adjusted_remainder = data_len % adjusted_chunks;
2133            (adjusted_size, adjusted_remainder)
2134        } else {
2135            (target, remainder)
2136        };
2137
2138        let total_chunks = if final_chunk > 0 {
2139            num_chunks + 1
2140        } else {
2141            num_chunks
2142        };
2143        let total_overhead = total_chunks * Self::chunk_overhead(chunk_size);
2144        let efficiency = data_len as f32 / (data_len + total_overhead) as f32;
2145
2146        ChunkingPlan {
2147            chunk_size,
2148            num_chunks: total_chunks,
2149            final_chunk,
2150            efficiency,
2151        }
2152    }
2153
2154    /// Create chunks from data following the optimal plan.
2155    pub fn create_chunks(&self, data: &[u8]) -> Vec<Bytes> {
2156        let plan = self.optimal_for_data(data.len());
2157        if plan.num_chunks == 0 {
2158            return vec![];
2159        }
2160
2161        let mut chunks = Vec::with_capacity(plan.num_chunks);
2162        let mut offset = 0;
2163
2164        for i in 0..plan.num_chunks {
2165            let size = if i == plan.num_chunks - 1 && plan.final_chunk > 0 {
2166                plan.final_chunk
2167            } else {
2168                plan.chunk_size
2169            };
2170            chunks.push(Bytes::copy_from_slice(&data[offset..offset + size]));
2171            offset += size;
2172        }
2173
2174        chunks
2175    }
2176}
2177
2178impl Default for ChunkedEncodingOptimizer {
2179    fn default() -> Self {
2180        Self {
2181            min_chunk: CHUNK_SMALL,           // 1KB minimum
2182            target_chunk: DEFAULT_CHUNK_SIZE, // 16KB target
2183            max_chunk: CHUNK_XLARGE,          // 128KB max
2184            min_efficiency: 0.99,             // 99% efficiency
2185        }
2186    }
2187}
2188
2189/// Plan for chunking data.
2190#[derive(Debug, Clone, Copy)]
2191pub struct ChunkingPlan {
2192    /// Size of each chunk (except possibly final)
2193    pub chunk_size: usize,
2194    /// Total number of chunks
2195    pub num_chunks: usize,
2196    /// Size of final chunk (0 if evenly divisible)
2197    pub final_chunk: usize,
2198    /// Overall efficiency (data / total bytes)
2199    pub efficiency: f32,
2200}
2201
2202impl ChunkingPlan {
2203    /// Get total overhead in bytes.
2204    pub fn total_overhead(&self) -> usize {
2205        self.num_chunks * ChunkedEncodingOptimizer::chunk_overhead(self.chunk_size)
2206    }
2207}
2208
2209// ============================================================================
2210// Global Chunk Statistics
2211// ============================================================================
2212
2213/// Global statistics for chunk optimization.
2214#[derive(Debug, Default)]
2215pub struct ChunkStats {
2216    /// Total chunks created
2217    chunks_created: AtomicU64,
2218    /// Total bytes chunked
2219    bytes_chunked: AtomicU64,
2220    /// RTT samples recorded
2221    rtt_samples: AtomicU64,
2222    /// Total RTT sum (for averaging)
2223    rtt_sum: AtomicU64,
2224}
2225
2226impl ChunkStats {
2227    fn record_chunk(&self, size: usize) {
2228        self.chunks_created.fetch_add(1, Ordering::Relaxed);
2229        self.bytes_chunked.fetch_add(size as u64, Ordering::Relaxed);
2230    }
2231
2232    fn record_rtt_sample(&self, rtt_ms: u64) {
2233        self.rtt_samples.fetch_add(1, Ordering::Relaxed);
2234        self.rtt_sum.fetch_add(rtt_ms, Ordering::Relaxed);
2235    }
2236
2237    /// Get total chunks created.
2238    pub fn chunks_created(&self) -> u64 {
2239        self.chunks_created.load(Ordering::Relaxed)
2240    }
2241
2242    /// Get total bytes chunked.
2243    pub fn bytes_chunked(&self) -> u64 {
2244        self.bytes_chunked.load(Ordering::Relaxed)
2245    }
2246
2247    /// Get average chunk size.
2248    pub fn average_chunk_size(&self) -> usize {
2249        self.bytes_chunked()
2250            .checked_div(self.chunks_created())
2251            .map(|v| v as usize)
2252            .unwrap_or(0)
2253    }
2254
2255    /// Get average RTT.
2256    pub fn average_rtt(&self) -> u64 {
2257        self.rtt_sum
2258            .load(Ordering::Relaxed)
2259            .checked_div(self.rtt_samples.load(Ordering::Relaxed))
2260            .unwrap_or(0)
2261    }
2262}
2263
2264/// Global chunk statistics.
2265static CHUNK_STATS: ChunkStats = ChunkStats {
2266    chunks_created: AtomicU64::new(0),
2267    bytes_chunked: AtomicU64::new(0),
2268    rtt_samples: AtomicU64::new(0),
2269    rtt_sum: AtomicU64::new(0),
2270};
2271
2272/// Get global chunk statistics.
2273pub fn chunk_stats() -> &'static ChunkStats {
2274    &CHUNK_STATS
2275}
2276
2277// ============================================================================
2278// Streaming Body Builder
2279// ============================================================================
2280
2281/// Fluent builder for streaming response bodies.
2282///
2283/// # Example
2284///
2285/// ```rust,ignore
2286/// let (body, handle) = StreamingBodyBuilder::new()
2287///     .chunk_size(8192)
2288///     .backpressure(BackpressureConfig::new().high_watermark(100))
2289///     .build_with_sender();
2290///
2291/// // Send data
2292/// handle.send(data).await?;
2293/// handle.close().await;
2294/// ```
2295pub struct StreamingBodyBuilder {
2296    chunk_size: usize,
2297    buffer_size: usize,
2298    backpressure: BackpressureConfig,
2299    content_type: Option<String>,
2300    rate_limit: Option<u64>,
2301}
2302
2303impl StreamingBodyBuilder {
2304    /// Create a new builder.
2305    pub fn new() -> Self {
2306        Self {
2307            chunk_size: DEFAULT_CHUNK_SIZE,
2308            buffer_size: 64,
2309            backpressure: BackpressureConfig::default(),
2310            content_type: None,
2311            rate_limit: None,
2312        }
2313    }
2314
2315    /// Set chunk size.
2316    pub fn chunk_size(mut self, size: usize) -> Self {
2317        self.chunk_size = size;
2318        self
2319    }
2320
2321    /// Set buffer size (number of chunks).
2322    pub fn buffer_size(mut self, size: usize) -> Self {
2323        self.buffer_size = size;
2324        self
2325    }
2326
2327    /// Set backpressure configuration.
2328    pub fn backpressure(mut self, config: BackpressureConfig) -> Self {
2329        self.backpressure = config;
2330        self
2331    }
2332
2333    /// Set content type.
2334    pub fn content_type(mut self, content_type: impl Into<String>) -> Self {
2335        self.content_type = Some(content_type.into());
2336        self
2337    }
2338
2339    /// Set rate limit in bytes per second.
2340    pub fn rate_limit(mut self, bytes_per_sec: u64) -> Self {
2341        self.rate_limit = Some(bytes_per_sec);
2342        self
2343    }
2344
2345    /// Build a byte stream with sender handle.
2346    pub fn build_with_sender(self) -> (ByteStream, StreamingHandle) {
2347        let (stream, sender) = ByteStream::with_buffer_size(self.buffer_size);
2348        let handle = StreamingHandle {
2349            sender,
2350            chunk_size: self.chunk_size,
2351            rate_limiter: self.rate_limit.map(StreamRateLimiter::new),
2352            stats: Arc::new(StreamingHandleStats::default()),
2353        };
2354        STREAMING_STATS.record_stream_created();
2355        (stream, handle)
2356    }
2357
2358    /// Build as a streaming response.
2359    pub fn build_response(self) -> (StreamingResponse, StreamingHandle) {
2360        let content_type = self.content_type.clone();
2361        let (stream, handle) = self.build_with_sender();
2362        let mut response = StreamingResponse::new(stream);
2363        if let Some(ct) = content_type {
2364            response = response.content_type(ct);
2365        }
2366        (response, handle)
2367    }
2368}
2369
2370impl Default for StreamingBodyBuilder {
2371    fn default() -> Self {
2372        Self::new()
2373    }
2374}
2375
2376/// Handle for sending data to a streaming body.
2377pub struct StreamingHandle {
2378    sender: ByteStreamSender,
2379    chunk_size: usize,
2380    rate_limiter: Option<StreamRateLimiter>,
2381    stats: Arc<StreamingHandleStats>,
2382}
2383
2384impl StreamingHandle {
2385    /// Send data to the stream.
2386    pub async fn send(&self, data: impl Into<Vec<u8>>) -> Result<(), Error> {
2387        let data = data.into();
2388        let len = data.len();
2389
2390        // Apply rate limiting if configured
2391        if let Some(ref limiter) = self.rate_limiter {
2392            limiter.wait_for_capacity(len).await;
2393        }
2394
2395        self.sender.send(data).await?;
2396        self.stats.record_send(len);
2397        STREAMING_STATS.record_chunk_sent(len);
2398        Ok(())
2399    }
2400
2401    /// Send bytes.
2402    pub async fn send_bytes(&self, bytes: Bytes) -> Result<(), Error> {
2403        let len = bytes.len();
2404
2405        if let Some(ref limiter) = self.rate_limiter {
2406            limiter.wait_for_capacity(len).await;
2407        }
2408
2409        self.sender.send_bytes(bytes).await?;
2410        self.stats.record_send(len);
2411        STREAMING_STATS.record_chunk_sent(len);
2412        Ok(())
2413    }
2414
2415    /// Send a chunk of data, splitting if necessary.
2416    pub async fn send_chunked(&self, data: &[u8]) -> Result<(), Error> {
2417        for chunk in data.chunks(self.chunk_size) {
2418            self.send(chunk.to_vec()).await?;
2419        }
2420        Ok(())
2421    }
2422
2423    /// Send an error.
2424    pub async fn send_error(&self, error: impl Into<String>) -> Result<(), Error> {
2425        self.sender.send_error(error).await
2426    }
2427
2428    /// Close the stream.
2429    pub async fn close(&self) {
2430        self.sender.close().await;
2431    }
2432
2433    /// Check if the receiver has been dropped.
2434    pub fn is_closed(&self) -> bool {
2435        self.sender.is_closed()
2436    }
2437
2438    /// Get bytes sent.
2439    pub fn bytes_sent(&self) -> u64 {
2440        self.stats.bytes_sent.load(Ordering::Relaxed)
2441    }
2442
2443    /// Get chunks sent.
2444    pub fn chunks_sent(&self) -> u64 {
2445        self.stats.chunks_sent.load(Ordering::Relaxed)
2446    }
2447}
2448
2449/// Statistics for a streaming handle.
2450#[derive(Debug, Default)]
2451struct StreamingHandleStats {
2452    bytes_sent: AtomicU64,
2453    chunks_sent: AtomicU64,
2454}
2455
2456impl StreamingHandleStats {
2457    fn record_send(&self, len: usize) {
2458        self.bytes_sent.fetch_add(len as u64, Ordering::Relaxed);
2459        self.chunks_sent.fetch_add(1, Ordering::Relaxed);
2460    }
2461}
2462
2463// ============================================================================
2464// Rate Limiting
2465// ============================================================================
2466
2467/// Rate limiter for streaming data.
2468pub struct StreamRateLimiter {
2469    /// Bytes per second limit
2470    pub bytes_per_sec: u64,
2471    /// Bytes sent in current window
2472    bytes_in_window: AtomicU64,
2473    /// Window start time
2474    window_start: std::sync::Mutex<std::time::Instant>,
2475}
2476
2477impl StreamRateLimiter {
2478    /// Create a new rate limiter.
2479    pub fn new(bytes_per_sec: u64) -> Self {
2480        Self {
2481            bytes_per_sec,
2482            bytes_in_window: AtomicU64::new(0),
2483            window_start: std::sync::Mutex::new(std::time::Instant::now()),
2484        }
2485    }
2486
2487    /// Wait until capacity is available for sending.
2488    pub async fn wait_for_capacity(&self, bytes: usize) {
2489        loop {
2490            // Check current window
2491            let now = std::time::Instant::now();
2492            let elapsed = {
2493                let start = self.window_start.lock().unwrap();
2494                now.duration_since(*start)
2495            };
2496
2497            // Reset window if more than 1 second has passed
2498            if elapsed.as_secs() >= 1 {
2499                self.bytes_in_window.store(0, Ordering::Relaxed);
2500                *self.window_start.lock().unwrap() = now;
2501            }
2502
2503            let current = self.bytes_in_window.load(Ordering::Relaxed);
2504            if current + bytes as u64 <= self.bytes_per_sec {
2505                self.bytes_in_window
2506                    .fetch_add(bytes as u64, Ordering::Relaxed);
2507                return;
2508            }
2509
2510            // Wait until next window
2511            let remaining = Duration::from_secs(1).saturating_sub(elapsed);
2512            if !remaining.is_zero() {
2513                tokio::time::sleep(remaining.min(Duration::from_millis(10))).await;
2514            }
2515        }
2516    }
2517}
2518
2519// ============================================================================
2520// Global Streaming Statistics
2521// ============================================================================
2522
2523/// Global statistics for streaming operations.
2524#[derive(Debug, Default)]
2525pub struct StreamingStats {
2526    /// Streams created
2527    streams_created: AtomicU64,
2528    /// Total chunks sent
2529    chunks_sent: AtomicU64,
2530    /// Total bytes sent
2531    bytes_sent: AtomicU64,
2532}
2533
2534impl StreamingStats {
2535    /// Create new stats.
2536    pub fn new() -> Self {
2537        Self::default()
2538    }
2539
2540    fn record_stream_created(&self) {
2541        self.streams_created.fetch_add(1, Ordering::Relaxed);
2542    }
2543
2544    fn record_chunk_sent(&self, len: usize) {
2545        self.chunks_sent.fetch_add(1, Ordering::Relaxed);
2546        self.bytes_sent.fetch_add(len as u64, Ordering::Relaxed);
2547    }
2548
2549    /// Get streams created.
2550    pub fn streams_created(&self) -> u64 {
2551        self.streams_created.load(Ordering::Relaxed)
2552    }
2553
2554    /// Get chunks sent.
2555    pub fn chunks_sent(&self) -> u64 {
2556        self.chunks_sent.load(Ordering::Relaxed)
2557    }
2558
2559    /// Get bytes sent.
2560    pub fn bytes_sent(&self) -> u64 {
2561        self.bytes_sent.load(Ordering::Relaxed)
2562    }
2563
2564    /// Get average chunk size.
2565    pub fn average_chunk_size(&self) -> usize {
2566        self.bytes_sent()
2567            .checked_div(self.chunks_sent())
2568            .map(|v| v as usize)
2569            .unwrap_or(0)
2570    }
2571}
2572
2573/// Global streaming statistics.
2574static STREAMING_STATS: StreamingStats = StreamingStats {
2575    streams_created: AtomicU64::new(0),
2576    chunks_sent: AtomicU64::new(0),
2577    bytes_sent: AtomicU64::new(0),
2578};
2579
2580/// Get global streaming statistics.
2581pub fn streaming_stats() -> &'static StreamingStats {
2582    &STREAMING_STATS
2583}