devin15/cursor2api-rust
0
1use crate::{2 app::{3 constant::{4 AUTHORIZATION_BEARER_PREFIX, CONTENT_TYPE_TEXT_HTML_WITH_UTF8,5 CONTENT_TYPE_TEXT_PLAIN_WITH_UTF8, ROUTE_LOGS_PATH,6 },7 lazy::AUTH_TOKEN,8 model::{AppConfig, AppState, PageContent, RequestLog},9 },10 common::{models::ApiStatus, utils::extract_token},11};12use axum::{13 body::Body,14 extract::State,15 http::{16 header::{AUTHORIZATION, CONTENT_TYPE},17 HeaderMap, StatusCode,18 },19 response::{IntoResponse, Response},20 Json,21};22use chrono::Local;23use std::sync::Arc;24use tokio::sync::Mutex;25 26// 日志处理27pub async fn handle_logs() -> impl IntoResponse {28 match AppConfig::get_page_content(ROUTE_LOGS_PATH).unwrap_or_default() {29 PageContent::Default => Response::builder()30 .header(CONTENT_TYPE, CONTENT_TYPE_TEXT_HTML_WITH_UTF8)31 .body(Body::from(32 include_str!("../../../static/logs.min.html").to_string(),33 ))34 .unwrap(),35 PageContent::Text(content) => Response::builder()36 .header(CONTENT_TYPE, CONTENT_TYPE_TEXT_PLAIN_WITH_UTF8)37 .body(Body::from(content.clone()))38 .unwrap(),39 PageContent::Html(content) => Response::builder()40 .header(CONTENT_TYPE, CONTENT_TYPE_TEXT_HTML_WITH_UTF8)41 .body(Body::from(content.clone()))42 .unwrap(),43 }44}45 46pub async fn handle_logs_post(47 State(state): State<Arc<Mutex<AppState>>>,48 headers: HeaderMap,49) -> Result<Json<LogsResponse>, StatusCode> {50 let auth_token = AUTH_TOKEN.as_str();51 52 // 获取认证头53 let auth_header = headers54 .get(AUTHORIZATION)55 .and_then(|h| h.to_str().ok())56 .and_then(|h| h.strip_prefix(AUTHORIZATION_BEARER_PREFIX))57 .ok_or(StatusCode::UNAUTHORIZED)?;58 59 let state = state.lock().await;60 61 // 如果是管理员token,返回所有日志62 if auth_header == auth_token {63 return Ok(Json(LogsResponse {64 status: ApiStatus::Success,65 total: state.total_requests,66 active: Some(state.active_requests),67 error: Some(state.error_requests),68 logs: state.request_logs.clone(),69 timestamp: Local::now().to_string(),70 }));71 }72 73 // 解析 token74 let token_part = extract_token(auth_header).ok_or(StatusCode::UNAUTHORIZED)?;75 76 // 否则筛选出token匹配的日志77 let filtered_logs: Vec<RequestLog> = state78 .request_logs79 .iter()80 .filter(|log| log.token_info.token == token_part)81 .cloned()82 .collect();83 84 // 如果没有匹配的日志,返回未授权错误85 if filtered_logs.is_empty() {86 return Err(StatusCode::UNAUTHORIZED);87 }88 89 Ok(Json(LogsResponse {90 status: ApiStatus::Success,91 total: filtered_logs.len() as u64,92 active: None,93 error: None,94 logs: filtered_logs,95 timestamp: Local::now().to_string(),96 }))97}98 99#[derive(serde::Serialize)]100pub struct LogsResponse {101 pub status: ApiStatus,102 pub total: u64,103 #[serde(skip_serializing_if = "Option::is_none")]104 pub active: Option<u64>,105 #[serde(skip_serializing_if = "Option::is_none")]106 pub error: Option<u64>,107 pub logs: Vec<RequestLog>,108 pub timestamp: String,109}110 