1use crate::{Error, driver::lock};
5use base_http::body::{BodyError, BodyFrame, BodyReader, ReadableBody};
6use base_scheduler::Cancellation;
7use event_listener::Event;
8use std::sync::{Arc, Mutex};
9
10#[derive(Clone, Copy, PartialEq, Eq)]
11enum State {
12 Reading,
13 Complete,
14 Abandoned,
15}
16
17pub(crate) struct Consumption {
18 state: Mutex<State>,
19 changed: Event,
20 cancellation: Cancellation,
21}
22impl Consumption {
23 pub fn new(cancellation: Cancellation) -> Arc<Self> {
24 Arc::new(Self {
25 state: Mutex::new(State::Reading),
26 changed: Event::new(),
27 cancellation,
28 })
29 }
30 pub(crate) fn complete(&self) {
31 let mut state = lock(&self.state);
32 if *state == State::Reading {
33 *state = State::Complete;
34 }
35 drop(state);
36 self.changed.notify(usize::MAX);
37 }
38 fn abandon(&self) {
39 let mut state = lock(&self.state);
40 if *state != State::Reading {
41 return;
42 }
43 *state = State::Abandoned;
44 drop(state);
45 self.cancellation.cancel();
46 self.changed.notify(usize::MAX);
47 }
48 pub async fn wait(&self) -> Result<(), Error> {
49 loop {
50 event_listener::listener!(self.changed => listener);
51 match *lock(&self.state) {
52 State::Complete => return Ok(()),
53 State::Abandoned => return Err(Error::Abandoned),
54 State::Reading => {}
55 }
56 listener.await;
57 }
58 }
59}
60
61pub struct ResponseBody {
66 pub(crate) reader: BodyReader,
67 pub(crate) consumption: Arc<Consumption>,
68 pub(crate) length: Option<u64>,
69 pub(crate) trailers: bool,
70}
71impl ReadableBody for ResponseBody {
72 type Data = Vec<u8>;
73 type Error = BodyError;
74 fn is_ready(&self) -> bool {
75 self.reader.is_ready()
76 }
77 fn is_empty(&self) -> bool {
78 self.reader.is_empty()
79 }
80 fn length(&self) -> Option<u64> {
81 self.length
82 }
83 fn may_have_trailers(&self) -> bool {
84 self.trailers
85 }
86 fn close(&mut self, error: Option<BodyError>) {
87 self.consumption.abandon();
88 self.reader.close(error);
89 }
90 async fn read(&mut self, cancellation: &Cancellation) -> Result<BodyFrame<Vec<u8>>, BodyError> {
91 let frame = self.reader.read(cancellation).await?;
92 if frame.is_end() {
93 self.consumption.complete();
94 }
95 Ok(frame)
96 }
97}
98impl Drop for ResponseBody {
99 fn drop(&mut self) {
100 self.consumption.abandon();
101 }
102}
103
104#[cfg(test)]
105mod tests {
106 use super::*;
107 use futures_lite::future::block_on;
108
109 #[test]
110 fn abandonment_is_final_and_cancels_the_exchange() {
111 let cancellation = Cancellation::new();
112 let consumption = Consumption::new(cancellation.clone());
113 consumption.abandon();
114 assert!(cancellation.is_cancelled());
115 consumption.complete();
117 let error = block_on(consumption.wait()).unwrap_err();
118 assert_eq!(error.to_string(), "HTTP client response abandoned");
119 }
120}