feat: add Rust backend — workspace with section executables
Cargo workspace with four crates: - nixpanel-common: shared SectionRequest/SectionResponse types - nixpanel-api: main Axum HTTP server (JWT auth, DB, routing) - nixpanel-services: section binary for systemctl start/stop/restart - nixpanel-sysinfo: section binary for CPU/RAM/disk/OS/version reads nixpanel-api features: - POST /api/auth/login — Argon2id verification, HS256 JWT - GET /api/dashboard — real account counts + sysinfo + versions - GET /api/services — live systemctl status via section binary - POST /api/services/:name/:action — start/stop/restart - GET /api/accounts — list from MariaDB - POST /api/accounts — create account + system user Section binaries are UPX-compressed after build. DB schema auto-migrated on first start; admin user seeded from /opt/nixpanel/.admin_user + .admin_pass files. Frontend changes: - nixserver/src/api.ts + App.tsx wired to real API (JWT stored in localStorage, real data in dashboard/services/accounts) - nixclient/src/api.ts added - Both vite configs get /api proxy to localhost:4000 for dev - install.sh updated to copy + compress all section binaries
This commit is contained in:
@@ -0,0 +1,54 @@
|
||||
use axum::{extract::State, Json};
|
||||
use serde::Serialize;
|
||||
|
||||
use crate::{auth::Claims, error::AppError, section, state::AppState};
|
||||
|
||||
#[derive(Serialize)]
|
||||
pub struct DashboardStats {
|
||||
pub accounts: i64,
|
||||
pub domains: i64,
|
||||
pub databases: i64,
|
||||
pub email_accounts: i64,
|
||||
}
|
||||
|
||||
#[derive(Serialize)]
|
||||
pub struct DashboardResponse {
|
||||
pub stats: DashboardStats,
|
||||
pub sysinfo: serde_json::Value,
|
||||
pub versions: serde_json::Value,
|
||||
}
|
||||
|
||||
pub async fn get_dashboard(
|
||||
claims: Claims,
|
||||
State(state): State<AppState>,
|
||||
) -> Result<Json<DashboardResponse>, AppError> {
|
||||
// DB counts
|
||||
let accounts = sqlx::query_scalar!("SELECT COUNT(*) FROM accounts")
|
||||
.fetch_one(&state.db).await?.unwrap_or(0);
|
||||
let domains = sqlx::query_scalar!("SELECT COUNT(*) FROM domains")
|
||||
.fetch_one(&state.db).await?.unwrap_or(0);
|
||||
let databases = sqlx::query_scalar!("SELECT COUNT(*) FROM account_databases")
|
||||
.fetch_one(&state.db).await?.unwrap_or(0);
|
||||
let email_accounts = sqlx::query_scalar!("SELECT COUNT(*) FROM email_accounts")
|
||||
.fetch_one(&state.db).await?.unwrap_or(0);
|
||||
|
||||
// Section binaries
|
||||
let bin_dir = &state.config.bin_dir;
|
||||
|
||||
let sysinfo_resp = section::call(bin_dir, "nixpanel-sysinfo", "stats", serde_json::Value::Null)
|
||||
.unwrap_or_else(|_| nixpanel_common::SectionResponse::err("sysinfo unavailable"));
|
||||
|
||||
let versions_resp = section::call(bin_dir, "nixpanel-sysinfo", "versions", serde_json::Value::Null)
|
||||
.unwrap_or_else(|_| nixpanel_common::SectionResponse::err("versions unavailable"));
|
||||
|
||||
Ok(Json(DashboardResponse {
|
||||
stats: DashboardStats {
|
||||
accounts,
|
||||
domains,
|
||||
databases,
|
||||
email_accounts,
|
||||
},
|
||||
sysinfo: sysinfo_resp.data.unwrap_or(serde_json::Value::Null),
|
||||
versions: versions_resp.data.unwrap_or(serde_json::Value::Null),
|
||||
}))
|
||||
}
|
||||
Reference in New Issue
Block a user