easyremote/crates/server/src/handlers/admin.rs
2026-01-04 18:15:07 +08:00

276 lines
8.0 KiB
Rust

//! 管理员处理器
use axum::{
extract::{Path, Query, State},
http::StatusCode,
response::IntoResponse,
Json,
};
use serde::Serialize;
use std::sync::Arc;
use crate::models::{
ApiResponse, DeviceResponse, PaginatedResponse, PaginationParams, SessionResponse,
StatsResponse, UserResponse,
};
use crate::services::{
auth::UserRepository,
device::DeviceRepository,
session::SessionRepository,
AppState,
};
use super::{api_error, AdminUser};
/// 服务器配置响应
#[derive(Debug, Serialize)]
pub struct ServerConfigResponse {
pub version: String,
pub http_port: u16,
pub stun_port: u16,
pub stun_enabled: bool,
pub stun_servers: Vec<String>,
pub turn_port: u16,
pub turn_enabled: bool,
pub turn_server: Option<String>,
pub turn_username: String,
pub turn_realm: String,
pub jwt_expiry_hours: i64,
pub database_type: String,
}
/// 获取所有用户
pub async fn list_users(
State(state): State<Arc<AppState>>,
_admin: AdminUser,
Query(params): Query<PaginationParams>,
) -> impl IntoResponse {
let repo = UserRepository::new(&state.db);
match repo.find_all(params.offset(), params.limit()).await {
Ok((users, total)) => {
let items: Vec<UserResponse> = users.into_iter().map(Into::into).collect();
let total_pages = ((total as f64) / (params.limit() as f64)).ceil() as u32;
let response = PaginatedResponse {
items,
total,
page: params.page.unwrap_or(1),
limit: params.limit(),
total_pages,
};
(StatusCode::OK, Json(ApiResponse::ok(response))).into_response()
}
Err(e) => api_error(StatusCode::INTERNAL_SERVER_ERROR, e.to_string()),
}
}
/// 删除用户
pub async fn delete_user(
State(state): State<Arc<AppState>>,
_admin: AdminUser,
Path(user_id): Path<String>,
) -> impl IntoResponse {
let repo = UserRepository::new(&state.db);
match repo.delete(&user_id).await {
Ok(_) => (StatusCode::OK, Json(ApiResponse::ok("用户已删除"))).into_response(),
Err(e) => api_error(StatusCode::INTERNAL_SERVER_ERROR, e.to_string()),
}
}
/// 获取所有设备(包含绑定用户信息)
pub async fn list_all_devices(
State(state): State<Arc<AppState>>,
_admin: AdminUser,
Query(params): Query<PaginationParams>,
) -> impl IntoResponse {
let repo = DeviceRepository::new(&state.db);
match repo.find_all_with_username(params.offset(), params.limit()).await {
Ok((devices, total)) => {
let items: Vec<DeviceResponse> = devices.into_iter().map(Into::into).collect();
let total_pages = ((total as f64) / (params.limit() as f64)).ceil() as u32;
let response = PaginatedResponse {
items,
total,
page: params.page.unwrap_or(1),
limit: params.limit(),
total_pages,
};
(StatusCode::OK, Json(ApiResponse::ok(response))).into_response()
}
Err(e) => api_error(StatusCode::INTERNAL_SERVER_ERROR, e.to_string()),
}
}
/// 获取所有会话
pub async fn list_all_sessions(
State(state): State<Arc<AppState>>,
_admin: AdminUser,
Query(params): Query<PaginationParams>,
) -> impl IntoResponse {
let repo = SessionRepository::new(&state.db);
match repo.find_all(params.offset(), params.limit()).await {
Ok((sessions, total)) => {
let items: Vec<SessionResponse> = sessions.into_iter().map(Into::into).collect();
let total_pages = ((total as f64) / (params.limit() as f64)).ceil() as u32;
let response = PaginatedResponse {
items,
total,
page: params.page.unwrap_or(1),
limit: params.limit(),
total_pages,
};
(StatusCode::OK, Json(ApiResponse::ok(response))).into_response()
}
Err(e) => api_error(StatusCode::INTERNAL_SERVER_ERROR, e.to_string()),
}
}
/// 获取统计信息
pub async fn get_stats(
State(state): State<Arc<AppState>>,
_admin: AdminUser,
) -> impl IntoResponse {
let user_repo = UserRepository::new(&state.db);
let device_repo = DeviceRepository::new(&state.db);
let session_repo = SessionRepository::new(&state.db);
let total_users = user_repo.find_all(0, 1).await.map(|(_, t)| t).unwrap_or(0);
let (_, total_devices) = device_repo.find_all(0, 1).await.unwrap_or((vec![], 0));
let online_devices = device_repo.count_online().await.unwrap_or(0);
let active_sessions = session_repo.count_active().await.unwrap_or(0);
let (_, total_sessions) = session_repo.find_all(0, 1).await.unwrap_or((vec![], 0));
let response = StatsResponse {
total_users,
total_devices,
online_devices,
active_sessions,
total_sessions,
};
(StatusCode::OK, Json(ApiResponse::ok(response))).into_response()
}
/// 获取服务器配置
pub async fn get_server_config(
State(state): State<Arc<AppState>>,
_admin: AdminUser,
) -> impl IntoResponse {
let config = &state.config;
// 获取 TURN 服务器地址
let turn_server = if config.enable_local_turn {
let host = config.public_ip.as_deref().unwrap_or("localhost");
Some(format!("turn:{}:{}", host, config.turn_port))
} else {
config.turn_server.clone()
};
let response = ServerConfigResponse {
version: env!("CARGO_PKG_VERSION").to_string(),
http_port: config.port,
stun_port: config.stun_port,
stun_enabled: config.enable_local_stun,
stun_servers: config.stun_servers.clone(),
turn_port: config.turn_port,
turn_enabled: config.enable_local_turn,
turn_server,
turn_username: config.turn_username.clone(),
turn_realm: config.turn_realm.clone(),
jwt_expiry_hours: config.jwt_expiry / 3600,
database_type: "SQLite".to_string(),
};
(StatusCode::OK, Json(ApiResponse::ok(response))).into_response()
}
/// 环境配置响应
#[derive(Debug, Serialize)]
pub struct EnvConfigResponse {
pub content: String,
}
/// 环境配置请求
#[derive(Debug, serde::Deserialize)]
pub struct EnvConfigRequest {
pub content: String,
}
/// 获取环境配置文件
pub async fn get_env_config(
_admin: AdminUser,
) -> impl IntoResponse {
let env_path = std::path::Path::new(".env");
let content = if env_path.exists() {
std::fs::read_to_string(env_path).unwrap_or_default()
} else {
// 返回默认配置模板
generate_default_env_config()
};
let response = EnvConfigResponse { content };
(StatusCode::OK, Json(ApiResponse::ok(response))).into_response()
}
/// 保存环境配置文件
pub async fn save_env_config(
_admin: AdminUser,
Json(req): Json<EnvConfigRequest>,
) -> impl IntoResponse {
let env_path = std::path::Path::new(".env");
match std::fs::write(env_path, &req.content) {
Ok(_) => {
tracing::info!("Environment config saved");
(StatusCode::OK, Json(ApiResponse::ok("配置已保存"))).into_response()
}
Err(e) => {
tracing::error!("Failed to save env config: {}", e);
api_error(StatusCode::INTERNAL_SERVER_ERROR, format!("保存失败: {}", e))
}
}
}
/// Generate default environment config
fn generate_default_env_config() -> String {
r#"# EasyRemote Server Configuration
# Server Settings
HOST=0.0.0.0
PORT=8080
# STUN Server Settings
ENABLE_LOCAL_STUN=true
STUN_PORT=3478
# TURN Server Settings
ENABLE_LOCAL_TURN=true
TURN_PORT=3479
TURN_USERNAME=easyremote
TURN_PASSWORD=easyremote123
TURN_REALM=easyremote
# Public IP (optional, for generating correct STUN/TURN URLs)
# PUBLIC_IP=your.public.ip
# Database Settings
DATABASE_URL=sqlite:easyremote.db?mode=rwc
# JWT Settings
# JWT_SECRET=your-secret-key-here
JWT_EXPIRY=86400
# Log Level
RUST_LOG=info,tower_http=debug
"#.to_string()
}