feat: reorganize to one flake one rust project
This commit is contained in:
parent
5183130427
commit
e8b60519e7
23 changed files with 792 additions and 2144 deletions
|
|
@ -23,6 +23,8 @@ pub struct AppState {
|
|||
pub webhooks: Vec<WebhookTarget>,
|
||||
pub retry_attempts: u32,
|
||||
pub retry_base_delay_secs: u64,
|
||||
pub webhook_last_request: std::sync::atomic::AtomicU64,
|
||||
pub webhook_tokens: std::sync::atomic::AtomicU32,
|
||||
}
|
||||
|
||||
fn unix_now() -> u64 {
|
||||
|
|
@ -32,6 +34,9 @@ fn unix_now() -> u64 {
|
|||
.as_secs()
|
||||
}
|
||||
|
||||
const WEBHOOK_RATE_LIMIT: u32 = 10;
|
||||
const WEBHOOK_RATE_WINDOW_SECS: u64 = 60;
|
||||
|
||||
pub async fn post_webhook(
|
||||
State(state): State<Arc<AppState>>,
|
||||
headers: HeaderMap,
|
||||
|
|
@ -41,6 +46,22 @@ pub async fn post_webhook(
|
|||
return StatusCode::UNAUTHORIZED;
|
||||
}
|
||||
|
||||
// Simple rate limiting: reset tokens every window, reject if exhausted
|
||||
let now = unix_now();
|
||||
let last = state.webhook_last_request.load(std::sync::atomic::Ordering::Relaxed);
|
||||
if now.saturating_sub(last) >= WEBHOOK_RATE_WINDOW_SECS {
|
||||
state.webhook_tokens.store(WEBHOOK_RATE_LIMIT, std::sync::atomic::Ordering::Relaxed);
|
||||
state.webhook_last_request.store(now, std::sync::atomic::Ordering::Relaxed);
|
||||
}
|
||||
let remaining = state.webhook_tokens.fetch_update(
|
||||
std::sync::atomic::Ordering::Relaxed,
|
||||
std::sync::atomic::Ordering::Relaxed,
|
||||
|n| if n > 0 { Some(n - 1) } else { None },
|
||||
);
|
||||
if remaining.is_err() {
|
||||
return StatusCode::TOO_MANY_REQUESTS;
|
||||
}
|
||||
|
||||
let Some(status) = DoorStatus::from_str(&body.status) else {
|
||||
return StatusCode::BAD_REQUEST;
|
||||
};
|
||||
|
|
@ -148,17 +169,16 @@ pub async fn get_image(State(state): State<Arc<AppState>>) -> impl IntoResponse
|
|||
let db = state.db.clone();
|
||||
let status = tokio::task::spawn_blocking(move || {
|
||||
let conn = db.blocking_lock();
|
||||
db::get_current_status_str(&conn)
|
||||
db::get_current_status(&conn)
|
||||
})
|
||||
.await
|
||||
.expect("db task panicked")
|
||||
.ok()
|
||||
.flatten();
|
||||
.unwrap_or(DoorStatus::Offline);
|
||||
|
||||
let image = match status.as_deref() {
|
||||
Some("open") => OPEN_PNG,
|
||||
Some("closed") => CLOSED_PNG,
|
||||
_ => OFFLINE_PNG,
|
||||
let image = match status {
|
||||
DoorStatus::Open => OPEN_PNG,
|
||||
DoorStatus::Closed => CLOSED_PNG,
|
||||
DoorStatus::Offline => OFFLINE_PNG,
|
||||
};
|
||||
([(header::CONTENT_TYPE, "image/png"), (header::CACHE_CONTROL, "public, max-age=5")], image)
|
||||
}
|
||||
|
|
@ -167,17 +187,16 @@ pub async fn get_badge(State(state): State<Arc<AppState>>) -> impl IntoResponse
|
|||
let db = state.db.clone();
|
||||
let status = tokio::task::spawn_blocking(move || {
|
||||
let conn = db.blocking_lock();
|
||||
db::get_current_status_str(&conn)
|
||||
db::get_current_status(&conn)
|
||||
})
|
||||
.await
|
||||
.expect("db task panicked")
|
||||
.ok()
|
||||
.flatten();
|
||||
.unwrap_or(DoorStatus::Offline);
|
||||
|
||||
let (label, color) = match status.as_deref() {
|
||||
Some("open") => ("open", "#57f287"),
|
||||
Some("closed") => ("closed", "#ed4245"),
|
||||
_ => ("offline", "#99aab5"),
|
||||
let (label, color) = match status {
|
||||
DoorStatus::Open => ("open", "#57f287"),
|
||||
DoorStatus::Closed => ("closed", "#ed4245"),
|
||||
DoorStatus::Offline => ("offline", "#99aab5"),
|
||||
};
|
||||
|
||||
let label_width = 70u32;
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue