use axum::{ Router, routing::{get, post}, extract::State, Json, http::{StatusCode, HeaderMap}, }; use serde::{Deserialize, Serialize}; use std::sync::Arc; use crate::AppState; use crate::rate_limit::RateLimitResult; use crate::hf_router::HfError; #[derive(Deserialize)] pub struct PlayRequest { pub repo_id: String, pub path: String, #[serde(rename = "type")] pub req_type: Option, } #[derive(Serialize)] pub struct PlayResponse { pub url: String, pub expires_in: u64, } pub fn routes() -> Router> { Router::new() .route("/play", post(play_handler)) .route("/play/bot", post(play_handler)) .route("/play/tma", post(play_handler)) .route("/play/channel", post(play_handler)) .route("/deliver", post(deliver_handler)) .route("/keys", get(keys_handler)) .route("/stats", get(stats_handler)) } async fn play_handler( State(state): State>, headers: HeaderMap, Json(req): Json, ) -> Result, (StatusCode, Json)> { let api_key = headers .get("authorization") .and_then(|v| v.to_str().ok()) .and_then(|v| v.strip_prefix("Bearer ")) .ok_or_else(|| { (StatusCode::UNAUTHORIZED, Json(serde_json::json!({"error": "Missing Authorization header"}))) })?; let client = state.auth.validate(api_key).await .ok_or_else(|| { (StatusCode::UNAUTHORIZED, Json(serde_json::json!({"error": "Invalid API key"}))) })?; if !client.active { return Err((StatusCode::FORBIDDEN, Json(serde_json::json!({"error": "Client account is suspended"})))); } let rate_result = state.rate_limiter.check_and_increment( &client.id, client.rate_limit_per_minute, client.monthly_limit, ); match rate_result { RateLimitResult::MinuteExceeded => { return Err((StatusCode::TOO_MANY_REQUESTS, Json(serde_json::json!({ "error": "Rate limit exceeded", "limit": "per_minute" })))); } RateLimitResult::MonthlyExceeded => { return Err((StatusCode::TOO_MANY_REQUESTS, Json(serde_json::json!({ "error": "Monthly quota exceeded", "limit": "monthly" })))); } RateLimitResult::Ok => {} } let resolve_result = state.hf_router.resolve(&req.repo_id, &req.path, req.req_type.as_deref()).await .map_err(|e| { let (code, msg) = match e { HfError::NotFound => (StatusCode::NOT_FOUND, "File not found on Hugging Face".to_string()), HfError::RateLimited => (StatusCode::TOO_MANY_REQUESTS, "HF API rate limited".to_string()), HfError::Network(s) => (StatusCode::BAD_GATEWAY, format!("HF network error: {}", s)), HfError::NoRedirect(s) => (StatusCode::BAD_GATEWAY, format!("HF redirect error: {}", s)), }; (code, Json(serde_json::json!({"error": msg}))) })?; Ok(Json(PlayResponse { url: resolve_result.url, expires_in: resolve_result.expires_in, })) } #[derive(Deserialize)] pub struct DeliverRequest { pub user_id: i64, pub chat_id: i64, pub repo_id: String, pub path: String, } async fn deliver_handler( State(_state): State>, Json(_req): Json, ) -> Result, (StatusCode, Json)> { Err((StatusCode::NOT_IMPLEMENTED, Json(serde_json::json!({"error": "Not implemented"})))) } #[derive(Serialize)] pub struct KeyInfo { pub client_id: String, pub plan: String, pub keys: Vec, } async fn keys_handler( State(_state): State>, ) -> Result, (StatusCode, Json)> { Err((StatusCode::NOT_IMPLEMENTED, Json(serde_json::json!({"error": "Not implemented"})))) } async fn stats_handler( State(_state): State>, ) -> Result, (StatusCode, Json)> { Err((StatusCode::NOT_IMPLEMENTED, Json(serde_json::json!({"error": "Not implemented"})))) }