[Agent]实现获取系统基本信息接口 Rust版

目录

一、配置项目依赖

方式一:命令行快速添加依赖

bash 复制代码
cargo add sysinfo
cargo add chrono -F serde

方式二:手动写入Cargo.toml

toml 复制代码
anyhow = "1.0.102"
axum = "0.8.9"
chrono = { version = "0.4.44", features = ["serde"] }
serde = { version = "1.0.228", features = ["derive"] }
serde_json = "1.0.150"
sysinfo = "0.39.3"
tokio = { version = "1.52.3", features = ["full"] }
tower-http = { version = "0.6.11", features = ["trace"] }

二、定义数据模型

1.项目目录注册

src目录下新建data文件夹,创建system.rs数据模型文件,同步注册至lib.rs

src/lib.rs

rust 复制代码
/// http服务模块
pub mod app;
/// 数据模块
pub mod data;

src/data/mod.rs

rust 复制代码
...
/// 系统信息数据模型
pub mod system;
...

2. 系统基本信息数据模型

编辑src/system.rs文件,实现系统基本信息数据模型、CPU数据模型等

rust 复制代码
use serde::{Deserialize, Serialize};

/// 系统信息数据模型
#[derive(Debug, Clone, Serialize, Deserialize, PartialEq)]
pub struct SystemInfo {
    // 系统基本信息
    pub base: HostInfo,
    // CPU信息
    pub cpu: CpuInfo,
    // 内存信息
    pub mem: MemInfo,
    // 磁盘信息
    pub disks: Vec<DiskInfo>,
    // 网络信息
    pub networks: Vec<NetworkInfo>,

}

/// 系统基本信息数据模型
#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Eq)]
pub struct HostInfo {
    // 主机名
    pub host_name: String,
    // 系统架构
    pub arch: String,
    // 发行版本
    pub distro: String,
    // 内核版本
    pub kernel_version: String,
    // 运行时间
    pub up_time: String,
    // 启动时间
    pub boot_time: String,
}

/// CPU信息数据模型
#[derive(Debug, Clone, Serialize, Deserialize, PartialEq)]
pub struct CpuInfo {
    // CPU名称
    pub name: String,
    // CPU核心数
    pub cores: u64,
    // CPU逻辑核心数
    pub logical_cores: u64,
    // CPU频率
    pub frequency: u64,
    // CPU使用率
    pub usage: f64,
    // 每个逻辑CPU使用率 (%)
    pub logical_usage: Vec<f64>,
}

/// 内存信息数据模型
#[derive(Debug, Clone, Serialize, Deserialize, PartialEq)]
pub struct MemInfo {
    // 总内存
    pub total: u64,
    // 已使用内存
    pub used: u64,
    // 空闲内存
    pub free: u64,
    // 内存使用率 (%)
    pub usage: f64,
    // 交换内存
    pub swap_total: u64,
    // 已使用交换内存
    pub swap_used: u64,
    // 可用交换内存
    pub swap_free: u64,
    // 交换内存使用率 (%)
    pub swap_usage: f64,
}

/// 磁盘信息数据模型
#[derive(Debug, Clone, Serialize, Deserialize, PartialEq)]
pub struct DiskInfo {
    // 磁盘名称
    pub name: String,
    // 磁盘总容量
    pub total: u64,
    // 已使用容量
    pub used: u64,
    // 空闲容量
    pub free: u64,
    // 磁盘使用率 (%)
    pub usage: f64,
    // 总读取
    pub read_all: u64,
    // 总写入
    pub write_all: u64,
    // 挂载点
    pub mount_point: String,
    // 类型
    pub disk_type: String,
    // 读取速度
    pub read_speed: u64,
    // 写入速度
    pub write_speed: u64,
}

/// 网络信息数据模型
#[derive(Debug, Clone, Serialize, Deserialize, PartialEq)]
pub struct NetworkInfo {
    // 网络接口名称
    pub name: String,
    // 网络接口IP地址
    pub ip: String,
    // 网络接口MAC地址
    pub mac: String,
    // 下载速度
    pub download_speed: u64,
    // 上传速度
    pub upload_speed: u64,
}

3.统一导出数据模型(可选)

编辑src/system.rs,统一导出模型,可简化导入路径

rust 复制代码
/// 导出系统信息数据模型
pub use system::*;

三、实现基本信息获取

1.服务模块注册

src目录下新建service.rs文件和serivce文件夹,并注册到lib.rs

lib.rs

rust 复制代码
/// http服务模块
pub mod app;
/// 数据模块
pub mod data;
/// 服务模块
pub mod service;

service.rs

rust 复制代码
/// 基本信息模块
pub mod system;

2.系统信息服务实现

编辑src/system/system.rs文件,实现系统基本信息数据、CPU数据等

rust 复制代码
use std::{env::consts::ARCH, fs::read_to_string, process::Output, thread::sleep, time::Duration, vec};

use chrono::{Local, TimeZone};
use sysinfo::{DiskUsage, Disks, Networks, System};
use tokio::{ time::Instant};

use crate::data::{CpuInfo, DiskInfo, HostInfo, MemInfo, NetworkInfo, SystemInfo};

pub trait SystemInfoService {
    /// 获取CPU信息
     fn cpu_info(&self) -> CpuInfo;
    /// 获取内存信息
     fn memory_info(&self) -> MemInfo;
    /// 获取磁盘信息
     fn disk_info(&self) -> Vec<DiskInfo>;
    /// 获取网络信息
     fn network_info(&self) -> Vec<NetworkInfo>;
    /// 获取所有信息
    fn all(&self) -> impl Future<Output = SystemInfo>;
    /// 获取主机信息
    fn host_info(&self) -> HostInfo;
}

#[derive(Debug, Clone, Copy)]
pub struct DefaultSystemInfo;

impl SystemInfoService for DefaultSystemInfo {
    /// 获取CPU信息
    fn cpu_info(&self) -> CpuInfo {
        let mut sys = System::new_all();
        sys.refresh_cpu_all();
        sleep(sysinfo::MINIMUM_CPU_UPDATE_INTERVAL);
        sys.refresh_cpu_all();
        // 所有逻辑核心信息
        let golbal_cpu = sys.cpus();
        // 取第一个逻辑核心信息
        let first_cpu = golbal_cpu.first().unwrap();
        // CPU名称
        let name = first_cpu.brand().to_string();
        // 逻辑核心数
        let logical_cores = golbal_cpu.len() as u64;
        // CPU频率
        let frequency = first_cpu.frequency() / 1000;
        // 总使用率
        let usage = sys.global_cpu_usage() as f64;
        // 逻辑使用率
        let logical_usage = golbal_cpu.iter().map(|s| s.cpu_usage() as f64).collect::<Vec<f64>>();
        CpuInfo {
            name,
            logical_cores,
            frequency,
            usage,
            logical_usage,
        }
    }

    /// 获取内存信息
    fn memory_info(&self) -> MemInfo {
        let mut sys = System::new_all();
        sys.refresh_memory();
        // 总内存
        let total = sys.total_memory();
        // 已用内存
        let used = sys.used_memory();
        // 空闲内存
        let free = sys.free_memory();
        // 内存使用率
        let usage = if total > 0 {
            (used as f64 / total as f64) * 100.0
        } else {
            0.0
        };

        // 交换区总大小
        let swap_total = sys.total_swap();
        // 交换区已用大小
        let swap_used = sys.used_swap();
        // 交换区空闲大小
        let swap_free = sys.free_swap();
        // 交换区使用率
        let swap_usage = if swap_total > 0 {
            (swap_used as f64 / swap_total as f64) * 100.00
        } else {
            0.000
        };

        MemInfo {
            total,
            used,
            free,
            usage,
            swap_total,
            swap_used,
            swap_free,
            swap_usage,
        }
    }

    /// 获取磁盘信息
    fn disk_info(&self) -> Vec<DiskInfo> {
        let disks_first = Disks::new_with_refreshed_list();
        let start_time = Instant::now();
        // 收集初始数据
        let start_data = disks_first.list().iter().map(|d| {
            (d.name().to_string_lossy().to_string(), d.usage())
        }).collect::<Vec<(String, DiskUsage)>>();
        sleep(Duration::from_secs(1));
        // 刷新磁盘数据
        let disks_now = Disks::new_with_refreshed_list();
        // 计算耗时
        let dur_ms =start_time.elapsed().as_millis() as u64;
        // 收集当前数据
        let mut res = Vec::new();
        for disk in disks_now.list() {
            // 获取磁盘名称、总空间、可用空间、使用空间、使用率、挂载点和文件系统类型
            let name = disk.name().to_string_lossy().to_string();
            let total = disk.total_space();
            let free = disk.available_space();
            let used = total.saturating_sub(free);
            let usage = if total > 0 {used as f64 / total as f64 * 100.0} else {0.0};
            let mount_point = disk.mount_point().to_string_lossy().to_string();
            let disk_type = disk.file_system().to_string_lossy().to_string();

            // 获取当前磁盘IO信息
            let curr_io = disk.usage();
            // 获取上一次磁盘IO信息
            let pre = start_data.iter().find(|(n, _)| n == &name).map(|(_, u)| u).copied().unwrap_or(DiskUsage { total_written_bytes: 0, written_bytes: 0, total_read_bytes: 0, read_bytes: 0 });
            // 计算磁盘IO速度
            let read_all = curr_io.total_read_bytes;
            let write_all = curr_io.total_written_bytes;
            let delta_read = curr_io.read_bytes.saturating_sub(pre.read_bytes);
            let delta_write = curr_io.written_bytes.saturating_sub(pre.written_bytes);
            let read_speed = if dur_ms > 0 {delta_read * 1000 / dur_ms} else {0};
            let write_speed = if dur_ms > 0 {delta_write * 1000 / dur_ms} else {0};

            res.push(DiskInfo {
                name,
                total,
                free,
                used,
                usage,
                read_speed,
                write_speed,
                read_all,
                write_all,
                mount_point,
                disk_type,
            });
        }

        res
    }

    /// 获取网络信息
    fn network_info(&self) -> Vec<NetworkInfo> {
        // 获取当前网络信息
        let net1 = Networks::new_with_refreshed_list();
        // 获取网络信息
        let prev = net1.list().iter()
            .map(|(k, v)|(k.clone(), v.total_received(), v.total_transmitted()))
            .collect::<Vec<(String, u64,u64)>>();
        // 等待1秒
        sleep(Duration::from_secs(1));
        // 再次获取网络信息
        let net2 = Networks::new_with_refreshed_list();
        // 初始化网络信息
        let mut list: Vec<NetworkInfo> = vec![];
        for (name, data) in net2.list() {
            // 获取上一次网络信息
            let (pre_down, pre_up) = prev.iter().find(|(n, _, _)| n == name)
                .map(|(_,d, u)|(*d, *u)).unwrap_or((0,0));
            // 计算网络信息变化
            let down = data.total_received().saturating_sub(pre_down);
            let up =  data.total_transmitted().saturating_sub(pre_up);
            // 保存网络信息
            list.push(NetworkInfo{
                name: name.to_string(),
                ip: data.ip_networks().first().map(|x|x.to_string()).unwrap_or_default(),
                mac: data.mac_address().to_string(),
                download_speed: down,
                upload_speed: up,
            });
        }
        list
    }

    /// 获取所有系统信息
    async fn all(&self) -> SystemInfo {
        
        let s = self.clone();
        let host = tokio::task::spawn_blocking({
            move || s.host_info()
        });
        let cpu = tokio::task::spawn_blocking({
            move || s.cpu_info()
        });
        let mem = tokio::task::spawn_blocking({
            move || s.memory_info()
        });
        let disk = tokio::task::spawn_blocking({
            move || s.disk_info()
        });
        let net = tokio::task::spawn_blocking({
            move || s.network_info()
        });

        // 等待全部完成(只等最慢的那个 ~1s)
        let (host, cpu, mem, disk, net) = tokio::join!(host, cpu, mem, disk, net);

        SystemInfo {
            base: host.unwrap_or_default(),
            cpu: cpu.unwrap_or_default(),
            mem: mem.unwrap_or_default(),
            disks: disk.unwrap_or_default(),
            networks: net.unwrap_or_default(),
        }
    }

    /// 获取系统基本信息
    fn host_info(&self) -> HostInfo {
        // 获取主机名、架构和发行版信息
        let host_name = System::host_name().unwrap_or_default();
        let arch = System::cpu_arch();
        let distro = cfg_select! {
            unix => read_to_string("/etc/os-release")
                .ok()
                .and_then(|txt| {
                    txt.lines()
                        .find_map(|line| {
                        line.strip_prefix(r#"PRETTY_NAME=""#).and_then(
                            |s| s.strip_suffix('"')
                        ).map(|s| s.to_string())
                    })
                })
                .unwrap_or_else(|| {
                    System::long_os_version().unwrap_or_default()
                })
            ,
            _ => System::long_os_version().unwrap_or_default(),
        };
        // 获取内核版本、启动时间、运行时间
        let kernel_version = System::kernel_version().unwrap_or_default();
        let up_time =(|s: i64| {
            let dur = chrono::Duration::seconds(s);
            let days = dur.num_days();
            let hour = dur.num_hours() % 24;
            let min = dur.num_minutes() % 60;
            let sec = dur.num_seconds() % 60;
            match (days >0, hour > 0, min > 0) {
                (true, true ,true) => format!("{}天{:02}时{:02}分{:02}秒", days, hour, min, sec),
                (false, true, true) => format!("{:02}时{:02}分{:02}秒", hour,min, sec),
                (false, false, true) => format!("{:02}分{:02}秒", min, sec),
                (false, false, false) => format!("{:02}秒", sec),
                _ => format!("{}天{:02}时{:02}分{:02}秒", days, hour, min, sec),
            }
        })(System::uptime() as i64);
        let boot_time = (|s: i64| {
            Local.timestamp_opt(s, 0).unwrap().format("%Y-%m-%d %H:%M:%S").to_string()
        })(System::boot_time() as i64);

        HostInfo {
            host_name,
            arch,
            distro,
            kernel_version,
            up_time,
            boot_time,
        }
    }
}

四、实现获取基本信息接口

1.接口模块注册

src目录下新建api.rs文件和api文件夹,并注册到lib.rs

lib.rs

rust 复制代码
/// http服务模块
pub mod app;
/// 数据模块
pub mod data;
/// 服务模块
pub mod service;
/// 接口模块
pub mod api;

api.rs

rust 复制代码
/// 系统基本信息
pub mod system;

2.接口路由实现

编辑src/api/system.rs文件,实现所有相关接口

rust 复制代码
use axum::{Json, Router, routing::get};

use crate::{data::{CpuInfo, DiskInfo, HostInfo, NetworkInfo, Resp, SystemInfo}, service::system::{DefaultSystemService, SystemInfoService}};

/// 注册路由
pub fn register_system_url() -> Router {
    Router::new()
        .route("/all", get(get_all))
        .route("/host", get(get_host))
        .route("/cpu", get(get_cpu))
        .route("/base", get(get_base))
        .route("/net", get(get_net))
        .route("/disk", get(get_disk))
}


/// 获取所有系统信息
async fn get_all() -> Json<Resp<SystemInfo>>  {
    let serv = DefaultSystemService::default();
    Json(Resp::ok(Some(serv.all().await)))
}

/// 获取主机信息
async fn get_host() -> Json<Resp<HostInfo>> {
    let serv = DefaultSystemService::default();
    Json(Resp::ok(Some(serv.host_info())))
}

/// 获取CPU信息
async fn get_cpu() -> Json<Resp<CpuInfo>> {
    let serv = DefaultSystemService::default();
    Json(Resp::ok(Some(serv.cpu_info())))
}

/// 获取基础信息
async fn get_base() -> Json<Resp<HostInfo>> {
    let serv = DefaultSystemService::default();
    Json(Resp::ok(Some(serv.host_info())))
}

/// 获取网络信息
async fn get_net() -> Json<Resp<Vec<NetworkInfo>>> {
    let serv = DefaultSystemService::default();
    Json(Resp::ok(Some(serv.network_info())))
}

/// 获取磁盘信息
async fn get_disk() -> Json<Resp<Vec<DiskInfo>>> {
    let serv = DefaultSystemService::default();
    Json(Resp::ok(Some(serv.disk_info())))
}
相关推荐
Java面试题总结2 小时前
AgentScope Harness 深度实战:让Java智能体从“Demo可用”走向“生产可用”
java·开发语言·wpf
玖釉-2 小时前
Vulkan 中 Shader 的 vert、frag、mesh、comp 全面解析:作用、关系、特点与工程实践
开发语言·c++·windows·算法·图形渲染
小宇子2B3 小时前
Copy 明明比 Clone 便宜,为什么 Rust 偏偏要求你「先实现 Clone」?
rust
陕西企来客3 小时前
2026 西安 GEO 优化技术解析:前沿技术与行业规范深度企来客科技行业白皮书声明
开发语言·搜索引擎·php
AI科技星3 小时前
基于光速螺旋第一性原理:$G,\varepsilon_0,\alpha$引电统一完整推导+严谨证明+高精度数值全维度分析
c语言·开发语言·网络·量子计算·agi
淘矿人3 小时前
DeepSeek V4对决Claude 4.8:AI模型终极横评
java·开发语言·人工智能·python·sql·php·pygame
小宇子2B4 小时前
一个 Vec 在内存里到底长什么样:从真实地址看 move 为什么不要钱
rust
skywalk81634 小时前
你希望的「多路捕获」语法是哪种形式?具体而言,「捕获 类型为 e」指的是什么?
开发语言·编程
两年半的个人练习生^_^4 小时前
JMM 进阶:彻底理解 volatile 实现原理
java·开发语言