feat(api): Integrate uptime and reboot traffic stats into server API

This commit is contained in:
Whispering Wind
2025-08-19 23:39:01 +03:30
committed by GitHub
parent 6fa872b6c3
commit b3595c691b
2 changed files with 80 additions and 40 deletions

View File

@ -5,22 +5,35 @@ from pydantic import BaseModel
# It's better to chnage the underlying script to return bytes instead of changing it here
# Because of this problem we use str type instead of int as type
class ServerStatusResponse(BaseModel):
# disk_usage: int
# System Info
uptime: str
boot_time: str
cpu_usage: str
total_ram: str
ram_usage: str
total_ram: str
online_users: int
uploaded_traffic: str
downloaded_traffic: str
total_traffic: str
# Real-time Network
upload_speed: str
download_speed: str
tcp_connections: int
udp_connections: int
# Traffic Since Reboot
reboot_uploaded_traffic: str
reboot_downloaded_traffic: str
reboot_total_traffic: str
# User Traffic (All Time)
user_uploaded_traffic: str
user_downloaded_traffic: str
user_total_traffic: str
class ServerServicesStatusResponse(BaseModel):
hysteria_server: bool
hysteria_webpanel: bool
hysteria_iplimit: bool
# hysteria_singbox: bool
hysteria_normal_sub: bool
hysteria_telegram_bot: bool
hysteria_warp: bool

View File

@ -11,7 +11,7 @@ async def server_status_api():
Retrieve the server status.
This endpoint provides information about the current server status,
including CPU usage, RAM usage, online users, and traffic statistics.
including uptime, CPU usage, RAM usage, online users, and traffic statistics.
Returns:
ServerStatusResponse: A response model containing server status details.
@ -30,7 +30,6 @@ async def server_status_api():
def __parse_server_status(server_info: str) -> ServerStatusResponse:
# Initial data with default values
"""
Parse the server information provided by cli_api.server_info()
and return a ServerStatusResponse instance.
@ -45,57 +44,87 @@ def __parse_server_status(server_info: str) -> ServerStatusResponse:
ValueError: If the server information is invalid or incomplete.
"""
data = {
'uptime': 'N/A',
'boot_time': 'N/A',
'cpu_usage': '0%',
'total_ram': '0MB',
'ram_usage': '0MB',
'online_users': 0,
'uploaded_traffic': '0KB',
'downloaded_traffic': '0KB',
'total_traffic': '0KB'
'upload_speed': '0 B/s',
'download_speed': '0 B/s',
'tcp_connections': 0,
'udp_connections': 0,
'reboot_uploaded_traffic': '0 B',
'reboot_downloaded_traffic': '0 B',
'reboot_total_traffic': '0 B',
'user_uploaded_traffic': '0 B',
'user_downloaded_traffic': '0 B',
'user_total_traffic': '0 B'
}
# Example output(server_info) from cli_api.server_info():
# 📈 CPU Usage: 9.4%
# 📋 Total RAM: 3815MB
# 💻 Used RAM: 2007MB
# 👥 Online Users: 0
#
# 🔼 Uploaded Traffic: 0 KB
# 🔽 Downloaded Traffic: 0 KB
# 📊 Total Traffic: 0 KB
current_section = 'general'
for line in server_info.splitlines():
line = line.strip()
if not line:
continue
if 'Traffic Since Last Reboot' in line:
current_section = 'reboot'
continue
elif 'User Traffic (All Time)' in line:
current_section = 'user'
continue
key, _, value = line.partition(":")
key = key.strip().lower()
value = value.strip()
if not key or not value:
continue # Skip empty or malformed lines
continue
try:
if 'cpu usage' in key:
if 'uptime' in key:
uptime_part, _, boottime_part = value.partition('(')
data['uptime'] = uptime_part.strip()
data['boot_time'] = boottime_part.replace('since ', '').replace(')', '').strip()
elif 'cpu usage' in key:
data['cpu_usage'] = value
elif 'total ram' in key:
data['total_ram'] = value
elif 'used ram' in key:
data['ram_usage'] = value
parts = value.split('/')
if len(parts) == 2:
data['ram_usage'] = parts[0].strip()
data['total_ram'] = parts[1].strip()
elif 'online users' in key:
data['online_users'] = int(value)
elif 'uploaded traffic' in key:
value = value.replace(' ', '')
data['uploaded_traffic'] = value
elif "downloaded traffic" in key:
value = value.replace(' ', '')
data['downloaded_traffic'] = value
elif 'total traffic' in key:
value = value.replace(' ', '')
data["total_traffic"] = value
except ValueError as e:
elif 'upload speed' in key:
data['upload_speed'] = value
elif 'download speed' in key:
data['download_speed'] = value
elif 'tcp connections' in key:
data['tcp_connections'] = int(value)
elif 'udp connections' in key:
data['udp_connections'] = int(value)
elif 'total uploaded' in key or 'uploaded traffic' in key:
if current_section == 'reboot':
data['reboot_uploaded_traffic'] = value
elif current_section == 'user':
data['user_uploaded_traffic'] = value
elif 'total downloaded' in key or 'downloaded traffic' in key:
if current_section == 'reboot':
data['reboot_downloaded_traffic'] = value
elif current_section == 'user':
data['user_downloaded_traffic'] = value
elif 'combined traffic' in key or 'total traffic' in key:
if current_section == 'reboot':
data['reboot_total_traffic'] = value
elif current_section == 'user':
data['user_total_traffic'] = value
except (ValueError, IndexError) as e:
raise ValueError(f'Error parsing line \'{line}\': {e}')
# Validate required fields
try:
return ServerStatusResponse(**data) # type: ignore
return ServerStatusResponse(**data)
except Exception as e:
raise ValueError(f'Invalid or incomplete server info: {e}')
@ -141,8 +170,6 @@ def __parse_services_status(services_status: dict[str, bool]) -> ServerServicesS
parsed_services_status['hysteria_telegram_bot'] = status
elif 'hysteria-normal-sub' in service:
parsed_services_status['hysteria_normal_sub'] = status
# elif 'hysteria-singbox' in service:
# parsed_services_status['hysteria_singbox'] = status
elif 'wg-quick' in service:
parsed_services_status['hysteria_warp'] = status
return ServerServicesStatusResponse(**parsed_services_status)