Files
SenSu/services/web_panel/utils/system_info.py
T

94 lines
3.5 KiB
Python

#!/usr/bin/env python3
# -*- coding: utf-8 -*-
import os
import time
import platform
import logging
from typing import Dict, Any
logger = logging.getLogger(__name__)
def _is_android() -> bool:
"""检测是否为 Android 环境 (Termux 等)"""
return (
'ANDROID_ROOT' in os.environ or
os.path.exists('/system/bin/getprop') or
platform.release().lower().find('android') != -1
)
class SystemInfoCollector:
def __init__(self):
self.is_android = 'ANDROID_ROOT' in os.environ or os.path.exists('/system/bin/getprop')
self.psutil = None
if not self.is_android:
try:
import psutil
self.psutil = psutil
except ImportError as e:
logger.debug(f"psutil not available: {e}")
else:
logger.info("🤖 Android 平台识别,启用原生采集")
def get_all(self):
return {
"platform": {
"system": platform.system(),
"machine": platform.machine(),
"python": platform.python_version()
},
"cpu": self._get_cpu(),
"memory": self._get_memory(),
"network": self._get_network()
}
def _get_cpu(self):
if self.psutil:
return {
"percent": self.psutil.cpu_percent(interval=0.1),
"cores": self.psutil.cpu_count(),
"load_avg": os.getloadavg() if hasattr(os, 'getloadavg') else [0,0,0]
}
# Android 估算:负载率 = (1分钟负载 / 核心数) * 100
try:
load = os.getloadavg() if hasattr(os, "getloadavg") else [0.0, 0.0, 0.0]
cores = os.cpu_count() or 1
percent = min(100.0, (load[0] / cores) * 100)
return {"percent": round(percent, 1), "cores": cores, "load_avg": load}
except Exception as e:
logger.error(f"System info collection error: {e}", exc_info=True)
return {"percent": 0, "cores": 0, "load_avg": [0,0,0]}
def _get_memory(self):
if self.psutil:
m = self.psutil.virtual_memory()
return {"total_gb": round(m.total/1073741824, 1), "used_gb": round(m.used/1073741824, 1), "percent": m.percent}
try:
mem = {}
with open('/proc/meminfo') as f:
for line in f:
parts = line.split()
if len(parts) >= 2: mem[parts[0].rstrip(':')] = int(parts[1]) * 1024
t, a = mem.get('MemTotal', 1), mem.get('MemAvailable', mem.get('MemFree', 0))
return {"total_gb": round(t/1073741824, 1), "used_gb": round((t-a)/1073741824, 1), "percent": round(((t-a)/t)*100, 1)}
except Exception as e:
logger.warning(f"Memory info failed: {e}")
return {"total_gb": 0, "used_gb": 0, "percent": 0}
def _get_network(self):
if self.psutil:
io = self.psutil.net_io_counters()
return {"rx": round(io.bytes_recv/1048576, 1), "tx": round(io.bytes_sent/1048576, 1)}
# Android 解析 /proc/net/dev
try:
rx = 0
with open('/proc/net/dev', 'r') as f:
for line in f:
if ':' in line and 'lo' not in line: # 排除 lo 回环
parts = line.split(':')[1].split()
rx += int(parts[0]) # RX bytes
return {"rx": round(rx/1048576, 1), "tx": 0}
except Exception as e:
logger.warning(f"Network info failed: {e}")
return {"rx": 0, "tx": 0}