| 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<String>, |
| } |
|
|
| #[derive(Serialize)] |
| pub struct PlayResponse { |
| pub url: String, |
| pub expires_in: u64, |
| } |
|
|
| pub fn routes() -> Router<Arc<AppState>> { |
| 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<Arc<AppState>>, |
| headers: HeaderMap, |
| Json(req): Json<PlayRequest>, |
| ) -> Result<Json<PlayResponse>, (StatusCode, Json<serde_json::Value>)> { |
| 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<Arc<AppState>>, |
| Json(_req): Json<DeliverRequest>, |
| ) -> Result<Json<serde_json::Value>, (StatusCode, Json<serde_json::Value>)> { |
| 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<crate::auth::ClientSubKey>, |
| } |
|
|
| async fn keys_handler( |
| State(_state): State<Arc<AppState>>, |
| ) -> Result<Json<KeyInfo>, (StatusCode, Json<serde_json::Value>)> { |
| Err((StatusCode::NOT_IMPLEMENTED, Json(serde_json::json!({"error": "Not implemented"})))) |
| } |
|
|
| async fn stats_handler( |
| State(_state): State<Arc<AppState>>, |
| ) -> Result<Json<serde_json::Value>, (StatusCode, Json<serde_json::Value>)> { |
| Err((StatusCode::NOT_IMPLEMENTED, Json(serde_json::json!({"error": "Not implemented"})))) |
| } |
|
|