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 {
64 pub(crate) reader: BodyReader,
65 pub(crate) consumption: Arc<Consumption>,
66 pub(crate) length: Option<u64>,
67 pub(crate) trailers: bool,
68}
69impl ReadableBody for ResponseBody {
70 type Data = Vec<u8>;
71 type Error = BodyError;
72 fn is_ready(&self) -> bool {
73 self.reader.is_ready()
74 }
75 fn is_empty(&self) -> bool {
76 self.reader.is_empty()
77 }
78 fn length(&self) -> Option<u64> {
79 self.length
80 }
81 fn may_have_trailers(&self) -> bool {
82 self.trailers
83 }
84 fn close(&mut self, error: Option<BodyError>) {
85 self.consumption.abandon();
86 self.reader.close(error);
87 }
88 async fn read(&mut self, cancellation: &Cancellation) -> Result<BodyFrame<Vec<u8>>, BodyError> {
89 let frame = self.reader.read(cancellation).await?;
90 if frame.is_end() {
91 self.consumption.complete();
92 }
93 Ok(frame)
94 }
95}
96impl Drop for ResponseBody {
97 fn drop(&mut self) {
98 self.consumption.abandon();
99 }
100}
101
102#[cfg(test)]
103mod tests {
104 use super::*;
105 use futures_lite::future::block_on;
106
107 #[test]
108 fn abandonment_is_final_and_cancels_the_exchange() {
109 let cancellation = Cancellation::new();
110 let consumption = Consumption::new(cancellation.clone());
111 consumption.abandon();
112 assert!(cancellation.is_cancelled());
113 consumption.complete();
115 let error = block_on(consumption.wait()).unwrap_err();
116 assert_eq!(error.to_string(), "HTTP client response abandoned");
117 }
118}