1use crate::{ResponseMetadata, Status, future::cancellable};
24use base_scheduler::Cancellation;
25use std::{error::Error, fmt, future::Future};
26
27pub trait InterimHandler: Send {
29 type Error: Error + Send + Sync + 'static;
30 fn on_interim_response(
31 &mut self,
32 response: ResponseMetadata,
33 cancellation: &Cancellation,
34 ) -> impl Future<Output = Result<(), Self::Error>> + Send;
35}
36
37impl<F, Fut, E> InterimHandler for F
38where
39 F: FnMut(ResponseMetadata) -> Fut + Send,
40 Fut: Future<Output = Result<(), E>> + Send,
41 E: Error + Send + Sync + 'static,
42{
43 type Error = E;
44 async fn on_interim_response(
45 &mut self,
46 response: ResponseMetadata,
47 _: &Cancellation,
48 ) -> Result<(), E> {
49 self(response).await
50 }
51}
52
53#[derive(Debug)]
55pub enum InterimError<E> {
56 InvalidStatus(Status),
57 Finished,
58 Cancelled,
59 Handler(E),
60}
61
62impl<E: fmt::Display> fmt::Display for InterimError<E> {
63 fn fmt(&self, formatter: &mut fmt::Formatter<'_>) -> fmt::Result {
64 match self {
65 Self::InvalidStatus(status) => write!(formatter, "{status} is not an interim response"),
66 Self::Finished => formatter.write_str("interim responses have finished"),
67 Self::Cancelled => formatter.write_str("interim response cancelled"),
68 Self::Handler(error) => error.fmt(formatter),
69 }
70 }
71}
72impl<E: Error + 'static> Error for InterimError<E> {
73 fn source(&self) -> Option<&(dyn Error + 'static)> {
74 match self {
75 Self::Handler(error) => error.source(),
76 _ => None,
77 }
78 }
79}
80
81pub struct InterimResponses<H> {
90 handler: H,
91 finished: bool,
92}
93
94impl<H> InterimResponses<H> {
95 pub fn new(handler: H) -> Self {
96 Self {
97 handler,
98 finished: false,
99 }
100 }
101 pub fn finish(&mut self) {
102 self.finished = true;
103 }
104 pub fn is_finished(&self) -> bool {
105 self.finished
106 }
107 pub fn into_inner(self) -> H {
108 self.handler
109 }
110}
111
112impl<H: InterimHandler> InterimResponses<H> {
113 pub async fn send_interim_response(
114 &mut self,
115 response: ResponseMetadata,
116 cancellation: &Cancellation,
117 ) -> Result<(), InterimError<H::Error>> {
118 cancellation.check().map_err(|_| InterimError::Cancelled)?;
119 if self.finished {
120 return Err(InterimError::Finished);
121 }
122 if !response.status.is_informational() || response.status.is_final() {
123 return Err(InterimError::InvalidStatus(response.status));
124 }
125 self.finished = true;
126 cancellable(
127 self.handler.on_interim_response(response, cancellation),
128 cancellation,
129 )
130 .await
131 .map_err(|_| InterimError::Cancelled)?
132 .map_err(InterimError::Handler)?;
133 self.finished = false;
134 Ok(())
135 }
136}
137
138#[cfg(test)]
139mod tests {
140 use super::*;
141 use std::io;
142
143 #[test]
144 fn handler_errors_are_transparent() {
145 let error = InterimError::Handler(crate::body::BodyError::new(io::Error::other(
146 "observer failed",
147 )));
148 assert_eq!(error.to_string(), "body failed");
149 assert_eq!(error.source().unwrap().to_string(), "observer failed");
150 }
151}