2024-12-10 19:49:11 +08:00
|
|
|
|
from dataclasses import dataclass
|
2024-09-07 16:17:29 +08:00
|
|
|
|
import os
|
2024-12-10 19:49:11 +08:00
|
|
|
|
from pathlib import Path
|
2024-09-07 01:25:42 +08:00
|
|
|
|
import platform
|
2024-09-07 16:17:29 +08:00
|
|
|
|
import subprocess
|
2024-09-07 01:25:42 +08:00
|
|
|
|
|
|
|
|
|
|
import cpuinfo
|
|
|
|
|
|
import nonebot
|
2024-09-07 16:17:29 +08:00
|
|
|
|
from nonebot.utils import run_sync
|
2024-12-10 19:49:11 +08:00
|
|
|
|
import psutil
|
|
|
|
|
|
from pydantic import BaseModel
|
2024-09-07 01:25:42 +08:00
|
|
|
|
|
2024-09-07 16:17:29 +08:00
|
|
|
|
from zhenxun.configs.config import BotConfig
|
2024-12-10 19:49:11 +08:00
|
|
|
|
from zhenxun.services.log import logger
|
2024-09-07 01:25:42 +08:00
|
|
|
|
from zhenxun.utils.http_utils import AsyncHttpx
|
|
|
|
|
|
|
|
|
|
|
|
BAIDU_URL = "https://www.baidu.com/"
|
|
|
|
|
|
GOOGLE_URL = "https://www.google.com/"
|
|
|
|
|
|
|
|
|
|
|
|
VERSION_FILE = Path() / "__version__"
|
2024-09-07 16:17:29 +08:00
|
|
|
|
ARM_KEY = "aarch64"
|
2024-09-07 01:25:42 +08:00
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
@dataclass
|
|
|
|
|
|
class CPUInfo:
|
2025-01-07 14:36:22 +08:00
|
|
|
|
core: int | None
|
2024-09-07 01:25:42 +08:00
|
|
|
|
"""CPU 物理核心数"""
|
|
|
|
|
|
usage: float
|
|
|
|
|
|
"""CPU 占用百分比,取值范围(0,100]"""
|
|
|
|
|
|
freq: float
|
|
|
|
|
|
"""CPU 的时钟速度(单位:GHz)"""
|
|
|
|
|
|
|
|
|
|
|
|
@classmethod
|
|
|
|
|
|
def get_cpu_info(cls):
|
|
|
|
|
|
cpu_core = psutil.cpu_count(logical=False)
|
2024-09-07 16:17:29 +08:00
|
|
|
|
cpu_usage = psutil.cpu_percent(interval=0.1)
|
|
|
|
|
|
if _cpu_freq := psutil.cpu_freq():
|
|
|
|
|
|
cpu_freq = round(_cpu_freq.current / 1000, 2)
|
|
|
|
|
|
else:
|
|
|
|
|
|
cpu_freq = 0
|
2024-09-07 01:25:42 +08:00
|
|
|
|
return CPUInfo(core=cpu_core, usage=cpu_usage, freq=cpu_freq)
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
@dataclass
|
|
|
|
|
|
class RAMInfo:
|
|
|
|
|
|
"""RAM 信息(单位:GB)"""
|
|
|
|
|
|
|
|
|
|
|
|
total: float
|
|
|
|
|
|
"""RAM 总量"""
|
|
|
|
|
|
usage: float
|
|
|
|
|
|
"""当前 RAM 占用量/GB"""
|
|
|
|
|
|
|
|
|
|
|
|
@classmethod
|
|
|
|
|
|
def get_ram_info(cls):
|
|
|
|
|
|
ram_total = round(psutil.virtual_memory().total / (1024**3), 2)
|
|
|
|
|
|
ram_usage = round(psutil.virtual_memory().used / (1024**3), 2)
|
|
|
|
|
|
|
|
|
|
|
|
return RAMInfo(total=ram_total, usage=ram_usage)
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
@dataclass
|
|
|
|
|
|
class SwapMemory:
|
|
|
|
|
|
"""Swap 信息(单位:GB)"""
|
|
|
|
|
|
|
|
|
|
|
|
total: float
|
|
|
|
|
|
"""Swap 总量"""
|
|
|
|
|
|
usage: float
|
|
|
|
|
|
"""当前 Swap 占用量/GB"""
|
|
|
|
|
|
|
|
|
|
|
|
@classmethod
|
|
|
|
|
|
def get_swap_info(cls):
|
|
|
|
|
|
swap_total = round(psutil.swap_memory().total / (1024**3), 2)
|
|
|
|
|
|
swap_usage = round(psutil.swap_memory().used / (1024**3), 2)
|
|
|
|
|
|
|
|
|
|
|
|
return SwapMemory(total=swap_total, usage=swap_usage)
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
@dataclass
|
|
|
|
|
|
class DiskInfo:
|
|
|
|
|
|
"""硬盘信息"""
|
|
|
|
|
|
|
|
|
|
|
|
total: float
|
|
|
|
|
|
"""硬盘总量"""
|
|
|
|
|
|
usage: float
|
|
|
|
|
|
"""当前硬盘占用量/GB"""
|
|
|
|
|
|
|
|
|
|
|
|
@classmethod
|
|
|
|
|
|
def get_disk_info(cls):
|
|
|
|
|
|
disk_total = round(psutil.disk_usage("/").total / (1024**3), 2)
|
|
|
|
|
|
disk_usage = round(psutil.disk_usage("/").used / (1024**3), 2)
|
|
|
|
|
|
|
|
|
|
|
|
return DiskInfo(total=disk_total, usage=disk_usage)
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
class SystemInfo(BaseModel):
|
|
|
|
|
|
"""系统信息"""
|
|
|
|
|
|
|
|
|
|
|
|
cpu: CPUInfo
|
|
|
|
|
|
"""CPU信息"""
|
|
|
|
|
|
ram: RAMInfo
|
|
|
|
|
|
"""RAM信息"""
|
|
|
|
|
|
swap: SwapMemory
|
|
|
|
|
|
"""SWAP信息"""
|
|
|
|
|
|
disk: DiskInfo
|
|
|
|
|
|
"""DISK信息"""
|
|
|
|
|
|
|
|
|
|
|
|
def get_system_info(self):
|
|
|
|
|
|
return {
|
2024-09-07 16:17:29 +08:00
|
|
|
|
"cpu_info": f"{self.cpu.usage}% - {self.cpu.freq}Ghz "
|
|
|
|
|
|
f"[{self.cpu.core} core]",
|
|
|
|
|
|
"cpu_process": self.cpu.usage,
|
2024-09-07 01:25:42 +08:00
|
|
|
|
"ram_info": f"{self.ram.usage} / {self.ram.total} GB",
|
2024-09-07 01:50:24 +08:00
|
|
|
|
"ram_process": (
|
|
|
|
|
|
0 if self.ram.total == 0 else (self.ram.usage / self.ram.total * 100)
|
|
|
|
|
|
),
|
2024-09-07 01:25:42 +08:00
|
|
|
|
"swap_info": f"{self.swap.usage} / {self.swap.total} GB",
|
2024-09-07 01:50:24 +08:00
|
|
|
|
"swap_process": (
|
|
|
|
|
|
0 if self.swap.total == 0 else (self.swap.usage / self.swap.total * 100)
|
|
|
|
|
|
),
|
2024-09-07 01:25:42 +08:00
|
|
|
|
"disk_info": f"{self.disk.usage} / {self.disk.total} GB",
|
2024-09-07 01:50:24 +08:00
|
|
|
|
"disk_process": (
|
|
|
|
|
|
0 if self.disk.total == 0 else (self.disk.usage / self.disk.total * 100)
|
|
|
|
|
|
),
|
2024-09-07 01:25:42 +08:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
@run_sync
|
2024-09-07 16:17:29 +08:00
|
|
|
|
def __build_status() -> SystemInfo:
|
2024-09-07 01:25:42 +08:00
|
|
|
|
"""获取 `CPU` `RAM` `SWAP` `DISK` 信息"""
|
|
|
|
|
|
cpu = CPUInfo.get_cpu_info()
|
|
|
|
|
|
ram = RAMInfo.get_ram_info()
|
|
|
|
|
|
swap = SwapMemory.get_swap_info()
|
|
|
|
|
|
disk = DiskInfo.get_disk_info()
|
|
|
|
|
|
|
2024-09-07 16:17:29 +08:00
|
|
|
|
return SystemInfo(cpu=cpu, ram=ram, swap=swap, disk=disk)
|
2024-09-07 01:25:42 +08:00
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
async def __get_network_info():
|
|
|
|
|
|
"""网络请求"""
|
|
|
|
|
|
baidu, google = True, True
|
|
|
|
|
|
try:
|
|
|
|
|
|
await AsyncHttpx.get(BAIDU_URL, timeout=5)
|
|
|
|
|
|
except Exception as e:
|
|
|
|
|
|
logger.warning("自检:百度无法访问...", e=e)
|
|
|
|
|
|
baidu = False
|
|
|
|
|
|
try:
|
|
|
|
|
|
await AsyncHttpx.get(GOOGLE_URL, timeout=5)
|
|
|
|
|
|
except Exception as e:
|
|
|
|
|
|
logger.warning("自检:谷歌无法访问...", e=e)
|
|
|
|
|
|
google = False
|
|
|
|
|
|
return baidu, google
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
def __get_version() -> str | None:
|
|
|
|
|
|
"""获取版本信息"""
|
2024-09-07 01:50:24 +08:00
|
|
|
|
if VERSION_FILE.exists():
|
|
|
|
|
|
with open(VERSION_FILE, encoding="utf-8") as f:
|
|
|
|
|
|
if text := f.read():
|
|
|
|
|
|
return text.split(":")[-1]
|
|
|
|
|
|
return None
|
2024-09-07 01:25:42 +08:00
|
|
|
|
|
|
|
|
|
|
|
2024-09-07 16:17:29 +08:00
|
|
|
|
def __get_arm_cpu():
|
|
|
|
|
|
env = os.environ.copy()
|
|
|
|
|
|
env["LC_ALL"] = "en_US.UTF-8"
|
|
|
|
|
|
cpu_info = subprocess.check_output(["lscpu"], env=env).decode()
|
|
|
|
|
|
model_name = ""
|
|
|
|
|
|
cpu_freq = 0
|
|
|
|
|
|
for line in cpu_info.splitlines():
|
|
|
|
|
|
if "Model name" in line:
|
|
|
|
|
|
model_name = line.split(":")[1].strip()
|
|
|
|
|
|
if "CPU MHz" in line:
|
|
|
|
|
|
cpu_freq = float(line.split(":")[1].strip())
|
|
|
|
|
|
return model_name, cpu_freq
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
def __get_arm_oracle_cpu_freq():
|
|
|
|
|
|
cpu_freq = subprocess.check_output(
|
|
|
|
|
|
["dmidecode", "-s", "processor-frequency"]
|
|
|
|
|
|
).decode()
|
|
|
|
|
|
return round(float(cpu_freq.split()[0]) / 1000, 2)
|
|
|
|
|
|
|
|
|
|
|
|
|
2024-09-07 01:25:42 +08:00
|
|
|
|
async def get_status_info() -> dict:
|
|
|
|
|
|
"""获取信息"""
|
|
|
|
|
|
data = await __build_status()
|
2024-09-07 16:17:29 +08:00
|
|
|
|
|
|
|
|
|
|
system = platform.uname()
|
|
|
|
|
|
if system.machine == ARM_KEY and not (
|
|
|
|
|
|
cpuinfo.get_cpu_info().get("brand_raw") and data.cpu.freq
|
|
|
|
|
|
):
|
|
|
|
|
|
model_name, cpu_freq = __get_arm_cpu()
|
|
|
|
|
|
if not data.cpu.freq:
|
|
|
|
|
|
data.cpu.freq = cpu_freq or __get_arm_oracle_cpu_freq()
|
|
|
|
|
|
data = data.get_system_info()
|
|
|
|
|
|
data["brand_raw"] = model_name
|
|
|
|
|
|
else:
|
|
|
|
|
|
data = data.get_system_info()
|
|
|
|
|
|
data["brand_raw"] = cpuinfo.get_cpu_info().get("brand_raw", "Unknown")
|
|
|
|
|
|
|
2024-09-07 01:25:42 +08:00
|
|
|
|
baidu, google = await __get_network_info()
|
|
|
|
|
|
data["baidu"] = "#8CC265" if baidu else "red"
|
|
|
|
|
|
data["google"] = "#8CC265" if google else "red"
|
2024-09-07 16:17:29 +08:00
|
|
|
|
|
2024-09-07 01:25:42 +08:00
|
|
|
|
data["system"] = f"{system.system} {system.release}"
|
|
|
|
|
|
data["version"] = __get_version()
|
|
|
|
|
|
data["plugin_count"] = len(nonebot.get_loaded_plugins())
|
|
|
|
|
|
data["nickname"] = BotConfig.self_nickname
|
|
|
|
|
|
return data
|