add http API, channel-driven life loop, predefined diary timer

- Extract http.rs: unified HTTP server with /api/timers and gitea webhook
- Life loop: select! on interval tick + mpsc channel for force-fire
- Predefined diary timer (cron 22:55 daily), auto-registered on startup
- BufferOutput for system timers (chat_id=0), no TG message
- state: ensure_timer(), get_timer()
- context.md: add blog and Hugo docs for AI
This commit is contained in:
Fam Zheng
2026-04-10 22:58:39 +01:00
parent 9d2d2af33f
commit c2be8e6930
6 changed files with 311 additions and 116 deletions

View File

@@ -151,27 +151,13 @@ pub struct WebhookState {
pub bot_user: String,
}
pub async fn start_webhook_server(config: &GiteaConfig, bot_user: String) {
pub fn webhook_router(config: &GiteaConfig, bot_user: String) -> axum::Router<()> {
let gitea = GiteaClient::new(config);
let state = Arc::new(WebhookState {
gitea,
bot_user,
});
let state = Arc::new(WebhookState { gitea, bot_user });
let app = axum::Router::new()
axum::Router::new()
.route("/webhook/gitea", post(handle_webhook))
.with_state(state);
let addr = format!("0.0.0.0:{}", config.webhook_port);
info!("gitea webhook server listening on {addr}");
let listener = tokio::net::TcpListener::bind(&addr)
.await
.unwrap_or_else(|e| panic!("bind {addr}: {e}"));
if let Err(e) = axum::serve(listener, app).await {
error!("webhook server error: {e}");
}
.with_state(state)
}
async fn handle_webhook(