1use crate::cache::RefreshTrigger;
2use axum::{
3 body::Body,
4 extract::State,
5 http::{header, Request, StatusCode},
6 response::IntoResponse,
7 routing::post,
8 Router,
9};
10use std::sync::Arc;
11
12#[derive(Clone)]
13pub struct ControlState {
14 refresh_trigger: RefreshTrigger,
15 auth_token: Option<String>,
16}
17
18impl ControlState {
19 pub fn new(refresh_trigger: RefreshTrigger, auth_token: Option<String>) -> Self {
20 Self {
21 refresh_trigger,
22 auth_token,
23 }
24 }
25}
26
27async fn refresh_cache_handler(
29 State(state): State<Arc<ControlState>>,
30 req: Request<Body>,
31) -> Result<impl IntoResponse, StatusCode> {
32 if let Some(required_token) = &state.auth_token {
34 let auth_header = req
35 .headers()
36 .get(header::AUTHORIZATION)
37 .and_then(|h| h.to_str().ok());
38
39 let expected = format!("Bearer {}", required_token);
40
41 if auth_header != Some(expected.as_str()) {
42 tracing::warn!("Unauthorized refresh-cache attempt");
43 return Err(StatusCode::UNAUTHORIZED);
44 }
45 }
46
47 state.refresh_trigger.trigger();
49 tracing::info!("Cache refresh triggered via control endpoint");
50
51 Ok((StatusCode::OK, "Cache refresh triggered"))
52}
53
54pub fn create_control_router(
56 refresh_trigger: RefreshTrigger,
57 auth_token: Option<String>,
58) -> Router {
59 let state = Arc::new(ControlState::new(refresh_trigger, auth_token));
60
61 Router::new()
62 .route("/refresh-cache", post(refresh_cache_handler))
63 .with_state(state)
64}