Backend: Server connection/config/admins DB queries, server API routes with auth-gated endpoints (overview, config CRUD, admin management). Frontend: Server store wired to API, dashboard fetches server data on mount with live status indicators, uptime formatting, and server config display. Logout now redirects to /login. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
155 lines
4.5 KiB
Rust
155 lines
4.5 KiB
Rust
use std::sync::Arc;
|
|
|
|
use axum::{
|
|
extract::State,
|
|
routing::{get, post, put},
|
|
Json, Router,
|
|
};
|
|
|
|
use crate::db;
|
|
use crate::middleware::auth::AuthUser;
|
|
use crate::models::error::{ApiError, ApiResult};
|
|
use crate::AppState;
|
|
|
|
pub fn router() -> Router<Arc<AppState>> {
|
|
Router::new()
|
|
.route("/", get(get_server_overview))
|
|
.route("/connection", get(get_connection))
|
|
.route("/config", get(get_config))
|
|
.route("/config", put(update_config))
|
|
.route("/command", post(send_command))
|
|
.route("/admins", get(get_admins))
|
|
.route("/start", post(start_server))
|
|
.route("/stop", post(stop_server))
|
|
.route("/restart", post(restart_server))
|
|
}
|
|
|
|
/// GET /api/servers — returns combined server overview (connection + config)
|
|
async fn get_server_overview(
|
|
auth: AuthUser,
|
|
State(state): State<Arc<AppState>>,
|
|
) -> ApiResult<Json<serde_json::Value>> {
|
|
let license_id = auth.license_id.ok_or(ApiError::LicenseInvalid)?;
|
|
|
|
let connection = db::servers::get_server_connection(&state.db, license_id)
|
|
.await
|
|
.map_err(|e| ApiError::Internal(e.to_string()))?;
|
|
|
|
let config = db::servers::get_server_config(&state.db, license_id)
|
|
.await
|
|
.map_err(|e| ApiError::Internal(e.to_string()))?;
|
|
|
|
Ok(Json(serde_json::json!({
|
|
"connection": connection,
|
|
"config": config,
|
|
})))
|
|
}
|
|
|
|
/// GET /api/servers/connection
|
|
async fn get_connection(
|
|
auth: AuthUser,
|
|
State(state): State<Arc<AppState>>,
|
|
) -> ApiResult<Json<serde_json::Value>> {
|
|
let license_id = auth.license_id.ok_or(ApiError::LicenseInvalid)?;
|
|
|
|
let connection = db::servers::get_server_connection(&state.db, license_id)
|
|
.await
|
|
.map_err(|e| ApiError::Internal(e.to_string()))?;
|
|
|
|
Ok(Json(serde_json::json!({ "connection": connection })))
|
|
}
|
|
|
|
/// GET /api/servers/config
|
|
async fn get_config(
|
|
auth: AuthUser,
|
|
State(state): State<Arc<AppState>>,
|
|
) -> ApiResult<Json<serde_json::Value>> {
|
|
let license_id = auth.license_id.ok_or(ApiError::LicenseInvalid)?;
|
|
|
|
let config = db::servers::get_server_config(&state.db, license_id)
|
|
.await
|
|
.map_err(|e| ApiError::Internal(e.to_string()))?;
|
|
|
|
Ok(Json(serde_json::json!({ "config": config })))
|
|
}
|
|
|
|
#[derive(serde::Deserialize)]
|
|
struct UpdateConfigRequest {
|
|
server_name: Option<String>,
|
|
max_players: Option<i32>,
|
|
world_size: Option<i32>,
|
|
current_seed: Option<i32>,
|
|
}
|
|
|
|
/// PUT /api/servers/config
|
|
async fn update_config(
|
|
auth: AuthUser,
|
|
State(state): State<Arc<AppState>>,
|
|
Json(body): Json<UpdateConfigRequest>,
|
|
) -> ApiResult<Json<serde_json::Value>> {
|
|
let license_id = auth.license_id.ok_or(ApiError::LicenseInvalid)?;
|
|
|
|
db::servers::update_server_config(
|
|
&state.db,
|
|
license_id,
|
|
body.server_name.as_deref(),
|
|
body.max_players,
|
|
body.world_size,
|
|
body.current_seed,
|
|
)
|
|
.await
|
|
.map_err(|e| ApiError::Internal(e.to_string()))?;
|
|
|
|
Ok(Json(serde_json::json!({ "message": "Config updated" })))
|
|
}
|
|
|
|
/// GET /api/servers/admins
|
|
async fn get_admins(
|
|
auth: AuthUser,
|
|
State(state): State<Arc<AppState>>,
|
|
) -> ApiResult<Json<serde_json::Value>> {
|
|
let license_id = auth.license_id.ok_or(ApiError::LicenseInvalid)?;
|
|
|
|
let admins = db::servers::get_game_admins(&state.db, license_id)
|
|
.await
|
|
.map_err(|e| ApiError::Internal(e.to_string()))?;
|
|
|
|
Ok(Json(serde_json::json!({ "admins": admins })))
|
|
}
|
|
|
|
/// POST /api/servers/command
|
|
async fn send_command(
|
|
_auth: AuthUser,
|
|
State(_state): State<Arc<AppState>>,
|
|
) -> ApiResult<Json<serde_json::Value>> {
|
|
// TODO: Route command through PanelAdapter or NATS to game server
|
|
Err(ApiError::BadRequest("Server command not yet implemented".to_string()))
|
|
}
|
|
|
|
/// POST /api/servers/start
|
|
async fn start_server(
|
|
_auth: AuthUser,
|
|
State(_state): State<Arc<AppState>>,
|
|
) -> ApiResult<Json<serde_json::Value>> {
|
|
// TODO: Route through PanelAdapter
|
|
Err(ApiError::BadRequest("Server start not yet implemented".to_string()))
|
|
}
|
|
|
|
/// POST /api/servers/stop
|
|
async fn stop_server(
|
|
_auth: AuthUser,
|
|
State(_state): State<Arc<AppState>>,
|
|
) -> ApiResult<Json<serde_json::Value>> {
|
|
// TODO: Route through PanelAdapter
|
|
Err(ApiError::BadRequest("Server stop not yet implemented".to_string()))
|
|
}
|
|
|
|
/// POST /api/servers/restart
|
|
async fn restart_server(
|
|
_auth: AuthUser,
|
|
State(_state): State<Arc<AppState>>,
|
|
) -> ApiResult<Json<serde_json::Value>> {
|
|
// TODO: Route through PanelAdapter
|
|
Err(ApiError::BadRequest("Server restart not yet implemented".to_string()))
|
|
}
|