增加一些功能

This commit is contained in:
jiangcuo 2025-04-16 03:28:14 +08:00
parent 4717a41c33
commit 958a90a615
2 changed files with 286 additions and 6 deletions

View File

@ -19,3 +19,6 @@ wmi = "0.15.2"
regex = "1.11.1"
chrono = "0.4.40"
netuser-rs = { git = "https://github.com/secur30nly/netuser-rs.git"}
sysinfo = "0.29.10"
hostname = "0.3.1"
local-ip-address = "0.5.6"

View File

@ -21,6 +21,10 @@ use wmi::{COMLibrary, WMIConnection, Variant, FilterValue};
use std::collections::HashMap;
use regex;
use netuser_rs;
use sysinfo::{System, SystemExt, CpuExt, NetworkExt};
use std::net::{IpAddr, Ipv4Addr};
use hostname;
use local_ip_address::{local_ip, local_ipv6, list_afinet_netifas};
fn is_admin() -> bool {
unsafe {
@ -136,8 +140,8 @@ struct VirtualMachine {
name: String,
state: String,
status: String,
cpu_cores: u32,
memory_mb: u64,
cores: u32,
memory: u64,
}
#[derive(Debug, Serialize, Deserialize, Clone)]
@ -165,6 +169,20 @@ struct Snapshot {
creation_time: String,
}
#[derive(Debug, Serialize, Deserialize, Clone)]
struct HostInfo {
hostname: String,
cpu_model: String,
cpu_cores: usize,
cpu_usage: f32,
memory_total: f64,
memory_used: f64,
memory_usage: f32,
ip_addresses: Vec<String>,
os_info: String,
uptime: u64,
}
// 获取WMI连接
fn get_wmi_connection() -> Result<WMIConnection> {
let com_lib = COMLibrary::new()?;
@ -269,10 +287,10 @@ async fn list_vm() -> Result<String> {
};
// 获取CPU核心数
let cpu_cores = get_vm_cpu_cores(&wmi_con, &vm_id)?;
let cores = get_vm_cpu_cores(&wmi_con, &vm_id)?;
// 获取内存大小
let memory_mb = get_vm_memory(&wmi_con, &vm_id)?;
let memory = get_vm_memory(&wmi_con, &vm_id)?;
// 创建VM对象
vms.push(VirtualMachine {
@ -280,8 +298,8 @@ async fn list_vm() -> Result<String> {
name: vm.get("ElementName").and_then(variant_to_string).unwrap_or_default(),
state,
status: vm.get("Status").and_then(variant_to_string).unwrap_or_default(),
cpu_cores,
memory_mb,
cores,
memory,
});
}
@ -1248,6 +1266,259 @@ async fn delete_snapshot_handler(query: web::Query<std::collections::HashMap<Str
}
}
async fn pause_vm(vmid: &str) -> Result<String> {
// 使用PowerShell的Suspend-VM命令暂停虚拟机
let output = Command::new("powershell.exe")
.args(["-Command", &format!("Get-VM -Id '{}' | Suspend-VM -Confirm:$false", vmid)])
.output()?;
if output.status.success() {
Ok("已暂停".to_string())
} else {
let error = String::from_utf8_lossy(&output.stderr);
Ok(format!("暂停失败: {}", error))
}
}
async fn resume_vm(vmid: &str) -> Result<String> {
// 使用PowerShell的Resume-VM命令恢复虚拟机
let output = Command::new("powershell.exe")
.args(["-Command", &format!("Get-VM -Id '{}' | Resume-VM", vmid)])
.output()?;
if output.status.success() {
Ok("已恢复".to_string())
} else {
let error = String::from_utf8_lossy(&output.stderr);
Ok(format!("恢复失败: {}", error))
}
}
async fn reset_vm(vmid: &str) -> Result<String> {
// 使用PowerShell的Restart-VM命令重启虚拟机
let output = Command::new("powershell.exe")
.args(["-Command", &format!("Get-VM -Id '{}' | Restart-VM -Force -Confirm:$false", vmid)])
.output()?;
if output.status.success() {
Ok("已重启".to_string())
} else {
let error = String::from_utf8_lossy(&output.stderr);
Ok(format!("重启失败: {}", error))
}
}
async fn pause_vm_handler(query: web::Query<std::collections::HashMap<String, String>>, req: actix_web::HttpRequest, config: web::Data<Config>) -> impl Responder {
let key = req.headers().get("Key").and_then(|v| v.to_str().ok());
if key != Some(&config.key) {
return HttpResponse::Unauthorized().json(serde_json::json!({ "error": "Key error" }));
}
let vmid = query.get("VMID");
match vmid {
Some(id) => {
if let Ok(true) = check_vmid(id).await {
match pause_vm(id).await {
Ok(result) => HttpResponse::Ok().body(result),
Err(e) => HttpResponse::InternalServerError().json(serde_json::json!({
"error": format!("Failed to pause VM: {}", e)
})),
}
} else {
HttpResponse::BadRequest().json(serde_json::json!({ "error": "Invalid VMID" }))
}
},
None => HttpResponse::BadRequest().json(serde_json::json!({ "error": "Need VMID" })),
}
}
async fn resume_vm_handler(query: web::Query<std::collections::HashMap<String, String>>, req: actix_web::HttpRequest, config: web::Data<Config>) -> impl Responder {
let key = req.headers().get("Key").and_then(|v| v.to_str().ok());
if key != Some(&config.key) {
return HttpResponse::Unauthorized().json(serde_json::json!({ "error": "Key error" }));
}
let vmid = query.get("VMID");
match vmid {
Some(id) => {
if let Ok(true) = check_vmid(id).await {
match resume_vm(id).await {
Ok(result) => HttpResponse::Ok().body(result),
Err(e) => HttpResponse::InternalServerError().json(serde_json::json!({
"error": format!("Failed to resume VM: {}", e)
})),
}
} else {
HttpResponse::BadRequest().json(serde_json::json!({ "error": "Invalid VMID" }))
}
},
None => HttpResponse::BadRequest().json(serde_json::json!({ "error": "Need VMID" })),
}
}
async fn reset_vm_handler(query: web::Query<std::collections::HashMap<String, String>>, req: actix_web::HttpRequest, config: web::Data<Config>) -> impl Responder {
let key = req.headers().get("Key").and_then(|v| v.to_str().ok());
if key != Some(&config.key) {
return HttpResponse::Unauthorized().json(serde_json::json!({ "error": "Key error" }));
}
let vmid = query.get("VMID");
match vmid {
Some(id) => {
if let Ok(true) = check_vmid(id).await {
match reset_vm(id).await {
Ok(result) => HttpResponse::Ok().body(result),
Err(e) => HttpResponse::InternalServerError().json(serde_json::json!({
"error": format!("Failed to reset VM: {}", e)
})),
}
} else {
HttpResponse::BadRequest().json(serde_json::json!({ "error": "Invalid VMID" }))
}
},
None => HttpResponse::BadRequest().json(serde_json::json!({ "error": "Need VMID" })),
}
}
async fn get_host_info() -> Result<String> {
// 初始化系统信息
let mut sys = System::new_all();
sys.refresh_all();
// 获取主机名
let hostname = match hostname::get() {
Ok(name) => name.to_string_lossy().to_string(),
Err(_) => "未知主机名".to_string(),
};
// 获取CPU信息
let cpu_model = if !sys.cpus().is_empty() {
sys.cpus()[0].brand().to_string()
} else {
"未知CPU型号".to_string()
};
let cpu_cores = sys.cpus().len();
// 计算CPU平均使用率并取整到两位小数
let cpu_usage = if !sys.cpus().is_empty() {
let mut total = 0.0;
for cpu in sys.cpus() {
total += cpu.cpu_usage();
}
let avg = total / (cpu_cores as f32);
(avg * 100.0).round() / 100.0 // 保留两位小数
} else {
0.0
};
// 获取内存信息并转换为GB (sysinfo返回的是KB)
let memory_total_kb = sys.total_memory();
let memory_used_kb = sys.used_memory();
// 直接转换为MB以后GB确保使用浮点数除法以保留精度
let memory_total_gb = (memory_total_kb as f64) / (1024.0 * 1024.0 * 1024.0);
let memory_used_gb = (memory_used_kb as f64) / (1024.0 * 1024.0 * 1024.0);
// 四舍五入到两位小数
let memory_total_gb = (memory_total_gb * 100.0).round() / 100.0;
let memory_used_gb = (memory_used_gb * 100.0).round() / 100.0;
// 计算内存使用率并取整到两位小数
let memory_usage = if memory_total_kb > 0 {
let usage = (memory_used_kb as f32 / memory_total_kb as f32) * 100.0;
(usage * 100.0).round() / 100.0 // 保留两位小数
} else {
0.0
};
// 获取IP地址列表
let mut ip_addresses = Vec::new();
// 使用local_ip_address库获取本地IP地址
match local_ip() {
Ok(ip) => {
ip_addresses.push(format!("主IP地址:{}", ip));
},
Err(e) => {
ip_addresses.push(format!("无法获取IPv4地址: {}", e));
}
}
// 使用local_ip_address库获取本地IPv6地址
match local_ipv6() {
Ok(ip) => {
ip_addresses.push(format!("主IPv6地址:{}", ip));
},
Err(_) => {
// IPv6可能不可用忽略错误
}
}
// 获取所有网络接口和IP地址
match list_afinet_netifas() {
Ok(if_list) => {
for (iface, ip) in if_list {
// 跳过回环接口
if iface.to_lowercase().contains("loopback") {
continue;
}
ip_addresses.push(format!("{}:{}", iface, ip));
}
},
Err(e) => {
ip_addresses.push(format!("无法获取网络接口列表: {}", e));
}
}
// 使用sysinfo获取网络接口流量信息
for (interface_name, network) in sys.networks() {
// 跳过回环接口
if interface_name == "lo" || interface_name.contains("loopback") {
continue;
}
}
// 获取操作系统信息
let os_info = format!("{} {}", sys.name().unwrap_or_default(), sys.os_version().unwrap_or_default());
// 获取系统运行时间
let uptime = sys.uptime();
// 构建主机信息结构
let host_info = HostInfo {
hostname,
cpu_model,
cpu_cores,
cpu_usage,
memory_total: memory_total_gb,
memory_used: memory_used_gb,
memory_usage,
ip_addresses,
os_info,
uptime,
};
// 转换为JSON
let json = serde_json::to_string(&host_info)?;
Ok(json)
}
async fn get_host_info_handler(req: actix_web::HttpRequest, config: web::Data<Config>) -> impl Responder {
let key = req.headers().get("Key").and_then(|v| v.to_str().ok());
if key != Some(&config.key) {
return HttpResponse::Unauthorized().json(serde_json::json!({ "error": "Key error" }));
}
match get_host_info().await {
Ok(result) => HttpResponse::Ok().body(result),
Err(e) => HttpResponse::InternalServerError().json(serde_json::json!({
"error": format!("Failed to get host info: {}", e)
})),
}
}
#[actix_web::main]
async fn main() -> std::io::Result<()> {
// 检查管理员权限
@ -1292,8 +1563,12 @@ async fn main() -> std::io::Result<()> {
.route("/api2/DeleteSnapShot", web::post().to(delete_snapshot_handler))
.route("/api2/StopVM", web::post().to(stop_vm_handler))
.route("/api2/StartVM", web::post().to(start_vm_handler))
.route("/api2/PauseVM", web::post().to(pause_vm_handler))
.route("/api2/ResumeVM", web::post().to(resume_vm_handler))
.route("/api2/ResetVM", web::post().to(reset_vm_handler))
.route("/api2/ListVM", web::get().to(list_vm_handler))
.route("/api2/GetTicket", web::post().to(get_vm_ticket_handler))
.route("/api2/GetHostInfo", web::get().to(get_host_info_handler))
});
let server = if tls_enabled {
@ -1323,3 +1598,5 @@ async fn main() -> std::io::Result<()> {
server.run().await
}