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