1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
|
use std::{
pin::Pin,
task::{Context, Poll},
};
use axum::{
extract::Request,
http::StatusCode,
response::{IntoResponse, Response},
};
use tower::{Layer, Service};
use crate::{app::App, error::Internal};
#[derive(Clone)]
pub struct Required(pub App);
impl Required {
pub fn with_fallback<F>(self, fallback: F) -> WithFallback<F> {
let Self(app) = self;
WithFallback { app, fallback }
}
}
impl<S> Layer<S> for Required {
type Service = Middleware<S, Unavailable>;
fn layer(&self, inner: S) -> Self::Service {
let Self(app) = self.clone();
Middleware {
inner,
app,
fallback: Unavailable,
}
}
}
#[derive(Clone)]
pub struct WithFallback<F> {
app: App,
fallback: F,
}
impl<S, F> Layer<S> for WithFallback<F>
where
Self: Clone,
{
type Service = Middleware<S, F>;
fn layer(&self, inner: S) -> Self::Service {
let Self { app, fallback } = self.clone();
Middleware {
inner,
app,
fallback,
}
}
}
#[derive(Clone)]
pub struct Middleware<S, F> {
inner: S,
app: App,
fallback: F,
}
impl<S, F> Service<Request> for Middleware<S, F>
where
Self: Clone,
S: Service<Request, Response = Response> + Send + 'static,
S::Future: Send,
F: IntoResponse + Clone + Send + 'static,
{
type Response = S::Response;
type Error = S::Error;
type Future = Pin<Box<dyn Future<Output = Result<Self::Response, Self::Error>> + Send>>;
fn poll_ready(&mut self, ctx: &mut Context<'_>) -> Poll<Result<(), Self::Error>> {
self.inner.poll_ready(ctx)
}
fn call(&mut self, req: Request) -> Self::Future {
let Self {
mut inner,
app,
fallback,
} = self.clone();
Box::pin(async move {
match app.setup().completed().await {
Ok(true) => inner.call(req).await,
Ok(false) => Ok(fallback.into_response()),
Err(error) => Ok(Internal::from(error).into_response()),
}
})
}
}
#[derive(Clone)]
pub struct Unavailable;
impl IntoResponse for Unavailable {
fn into_response(self) -> Response {
(
StatusCode::SERVICE_UNAVAILABLE,
"initial setup not completed",
)
.into_response()
}
}
|