Refactor: Implement server stats in Python
This commit is contained in:
@ -35,7 +35,7 @@ class Command(Enum):
|
|||||||
TRAFFIC_STATUS = 'traffic.py' # won't be called directly (it's a python module)
|
TRAFFIC_STATUS = 'traffic.py' # won't be called directly (it's a python module)
|
||||||
UPDATE_GEO = os.path.join(SCRIPT_DIR, 'hysteria2', 'update_geo.py')
|
UPDATE_GEO = os.path.join(SCRIPT_DIR, 'hysteria2', 'update_geo.py')
|
||||||
LIST_USERS = os.path.join(SCRIPT_DIR, 'hysteria2', 'list_users.sh')
|
LIST_USERS = os.path.join(SCRIPT_DIR, 'hysteria2', 'list_users.sh')
|
||||||
SERVER_INFO = os.path.join(SCRIPT_DIR, 'hysteria2', 'server_info.sh')
|
SERVER_INFO = os.path.join(SCRIPT_DIR, 'hysteria2', 'server_info.py')
|
||||||
BACKUP_HYSTERIA2 = os.path.join(SCRIPT_DIR, 'hysteria2', 'backup.py')
|
BACKUP_HYSTERIA2 = os.path.join(SCRIPT_DIR, 'hysteria2', 'backup.py')
|
||||||
RESTORE_HYSTERIA2 = os.path.join(SCRIPT_DIR, 'hysteria2', 'restore.sh')
|
RESTORE_HYSTERIA2 = os.path.join(SCRIPT_DIR, 'hysteria2', 'restore.sh')
|
||||||
INSTALL_TELEGRAMBOT = os.path.join(SCRIPT_DIR, 'telegrambot', 'runbot.py')
|
INSTALL_TELEGRAMBOT = os.path.join(SCRIPT_DIR, 'telegrambot', 'runbot.py')
|
||||||
@ -368,10 +368,12 @@ def traffic_status(no_gui=False, display_output=True):
|
|||||||
return data
|
return data
|
||||||
|
|
||||||
|
|
||||||
|
# Next Update:
|
||||||
# TODO: it's better to return json
|
# TODO: it's better to return json
|
||||||
|
# TODO: After json todo need fix Telegram Bot and WebPanel
|
||||||
def server_info() -> str | None:
|
def server_info() -> str | None:
|
||||||
'''Retrieves server information.'''
|
'''Retrieves server information.'''
|
||||||
return run_cmd(['bash', Command.SERVER_INFO.value])
|
return run_cmd(['python3', Command.SERVER_INFO.value])
|
||||||
|
|
||||||
|
|
||||||
def get_ip_address() -> tuple[str | None, str | None]:
|
def get_ip_address() -> tuple[str | None, str | None]:
|
||||||
|
|||||||
122
core/scripts/hysteria2/server_info.py
Normal file
122
core/scripts/hysteria2/server_info.py
Normal file
@ -0,0 +1,122 @@
|
|||||||
|
#!/usr/bin/env python3
|
||||||
|
|
||||||
|
import sys
|
||||||
|
import json
|
||||||
|
from hysteria2_api import Hysteria2Client
|
||||||
|
import time
|
||||||
|
from init_paths import *
|
||||||
|
from paths import *
|
||||||
|
|
||||||
|
|
||||||
|
def get_secret() -> str:
|
||||||
|
if not CONFIG_FILE.exists():
|
||||||
|
print("Error: config.json file not found!", file=sys.stderr)
|
||||||
|
sys.exit(1)
|
||||||
|
|
||||||
|
with CONFIG_FILE.open() as f:
|
||||||
|
data = json.load(f)
|
||||||
|
|
||||||
|
secret = data.get("trafficStats", {}).get("secret")
|
||||||
|
if not secret:
|
||||||
|
print("Error: secret not found in config.json!", file=sys.stderr)
|
||||||
|
sys.exit(1)
|
||||||
|
|
||||||
|
return secret
|
||||||
|
|
||||||
|
|
||||||
|
def convert_bytes(bytes_val: int) -> str:
|
||||||
|
units = [("TB", 1 << 40), ("GB", 1 << 30), ("MB", 1 << 20), ("KB", 1 << 10)]
|
||||||
|
for unit, factor in units:
|
||||||
|
if bytes_val >= factor:
|
||||||
|
return f"{bytes_val / factor:.2f} {unit}"
|
||||||
|
return f"{bytes_val} B"
|
||||||
|
|
||||||
|
|
||||||
|
def get_cpu_usage(interval: float = 0.1) -> float:
|
||||||
|
def read_cpu_times():
|
||||||
|
with open("/proc/stat") as f:
|
||||||
|
line = f.readline()
|
||||||
|
fields = list(map(int, line.strip().split()[1:]))
|
||||||
|
idle, total = fields[3], sum(fields)
|
||||||
|
return idle, total
|
||||||
|
|
||||||
|
idle1, total1 = read_cpu_times()
|
||||||
|
time.sleep(interval)
|
||||||
|
idle2, total2 = read_cpu_times()
|
||||||
|
|
||||||
|
idle_delta = idle2 - idle1
|
||||||
|
total_delta = total2 - total1
|
||||||
|
cpu_usage = 100.0 * (1 - idle_delta / total_delta) if total_delta else 0.0
|
||||||
|
return round(cpu_usage, 1)
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
def get_memory_usage() -> tuple[int, int]:
|
||||||
|
with open("/proc/meminfo") as f:
|
||||||
|
lines = f.readlines()
|
||||||
|
|
||||||
|
mem_total = int(next(line for line in lines if "MemTotal" in line).split()[1]) // 1024
|
||||||
|
mem_available = int(next(line for line in lines if "MemAvailable" in line).split()[1]) // 1024
|
||||||
|
mem_used = mem_total - mem_available
|
||||||
|
|
||||||
|
return mem_total, mem_used
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
def get_online_user_count(secret: str) -> int:
|
||||||
|
try:
|
||||||
|
client = Hysteria2Client(
|
||||||
|
base_url=API_BASE_URL,
|
||||||
|
secret=secret
|
||||||
|
)
|
||||||
|
online_users = client.get_online_clients()
|
||||||
|
return sum(1 for user in online_users.values() if user.is_online)
|
||||||
|
except Exception as e:
|
||||||
|
print(f"Error getting online users: {e}", file=sys.stderr)
|
||||||
|
return 0
|
||||||
|
|
||||||
|
|
||||||
|
def get_total_traffic() -> tuple[int, int]:
|
||||||
|
if not USERS_FILE.exists():
|
||||||
|
return 0, 0
|
||||||
|
|
||||||
|
try:
|
||||||
|
with USERS_FILE.open() as f:
|
||||||
|
users = json.load(f)
|
||||||
|
|
||||||
|
total_upload = 0
|
||||||
|
total_download = 0
|
||||||
|
|
||||||
|
for user_data in users.values():
|
||||||
|
total_upload += int(user_data.get("upload_bytes", 0) or 0)
|
||||||
|
total_download += int(user_data.get("download_bytes", 0) or 0)
|
||||||
|
|
||||||
|
return total_upload, total_download
|
||||||
|
except Exception as e:
|
||||||
|
print(f"Error parsing traffic data: {e}", file=sys.stderr)
|
||||||
|
return 0, 0
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
def main():
|
||||||
|
secret = get_secret()
|
||||||
|
|
||||||
|
cpu_usage = get_cpu_usage()
|
||||||
|
mem_total, mem_used = get_memory_usage()
|
||||||
|
online_users = get_online_user_count(secret)
|
||||||
|
|
||||||
|
print(f"📈 CPU Usage: {cpu_usage}")
|
||||||
|
print(f"📋 Total RAM: {mem_total}MB")
|
||||||
|
print(f"💻 Used RAM: {mem_used}MB")
|
||||||
|
print(f"👥 Online Users: {online_users}")
|
||||||
|
print()
|
||||||
|
|
||||||
|
total_upload, total_download = get_total_traffic()
|
||||||
|
|
||||||
|
print(f"🔼 Uploaded Traffic: {convert_bytes(total_upload)}")
|
||||||
|
print(f"🔽 Downloaded Traffic: {convert_bytes(total_download)}")
|
||||||
|
print(f"📊 Total Traffic: {convert_bytes(total_upload + total_download)}")
|
||||||
|
|
||||||
|
|
||||||
|
if __name__ == "__main__":
|
||||||
|
main()
|
||||||
@ -1,63 +0,0 @@
|
|||||||
#!/bin/bash
|
|
||||||
|
|
||||||
source /etc/hysteria/core/scripts/path.sh
|
|
||||||
|
|
||||||
get_secret() {
|
|
||||||
[ ! -f "$CONFIG_FILE" ] && { echo "Error: config.json file not found!" >&2; exit 1; }
|
|
||||||
|
|
||||||
local secret=$(jq -r '.trafficStats.secret' "$CONFIG_FILE")
|
|
||||||
|
|
||||||
[ "$secret" = "null" ] || [ -z "$secret" ] && {
|
|
||||||
echo "Error: secret not found in config.json!" >&2
|
|
||||||
exit 1
|
|
||||||
}
|
|
||||||
|
|
||||||
echo "$secret"
|
|
||||||
}
|
|
||||||
|
|
||||||
convert_bytes() {
|
|
||||||
local bytes=$1
|
|
||||||
if (( bytes < 1048576 )); then
|
|
||||||
printf "%.2f KB" "$(echo "scale=2; $bytes / 1024" | bc)"
|
|
||||||
elif (( bytes < 1073741824 )); then
|
|
||||||
printf "%.2f MB" "$(echo "scale=2; $bytes / 1048576" | bc)"
|
|
||||||
elif (( bytes < 1099511627776 )); then
|
|
||||||
printf "%.2f GB" "$(echo "scale=2; $bytes / 1073741824" | bc)"
|
|
||||||
else
|
|
||||||
printf "%.2f TB" "$(echo "scale=2; $bytes / 1099511627776" | bc)"
|
|
||||||
fi
|
|
||||||
}
|
|
||||||
|
|
||||||
cpu_usage=$(top -bn1 | grep "Cpu(s)" | sed "s/.*, *\([0-9.]*\)%* id.*/\1/" | awk '{print 100 - $1"%"}')
|
|
||||||
|
|
||||||
mem_stats=$(free -m)
|
|
||||||
mem_total=$(echo "$mem_stats" | awk '/Mem:/ {print $2}')
|
|
||||||
mem_used=$(echo "$mem_stats" | awk '/Mem:/ {print $3}')
|
|
||||||
|
|
||||||
secret=$(get_secret)
|
|
||||||
online_users=$(curl -s -H "Authorization: $secret" "$ONLINE_API_URL")
|
|
||||||
online_user_count=$(echo "$online_users" | jq 'add // 0')
|
|
||||||
|
|
||||||
echo "📈 CPU Usage: $cpu_usage"
|
|
||||||
echo "📋 Total RAM: ${mem_total}MB"
|
|
||||||
echo "💻 Used RAM: ${mem_used}MB"
|
|
||||||
echo "👥 Online Users: $online_user_count"
|
|
||||||
echo
|
|
||||||
|
|
||||||
if [ -f "$USERS_FILE" ]; then
|
|
||||||
read total_upload total_download <<< $(jq -r '
|
|
||||||
reduce .[] as $user (
|
|
||||||
{"up": 0, "down": 0};
|
|
||||||
.up += (($user.upload_bytes | numbers) // 0) |
|
|
||||||
.down += (($user.download_bytes | numbers) // 0)
|
|
||||||
) | "\(.up) \(.down)"' "$USERS_FILE" 2>/dev/null || echo "0 0")
|
|
||||||
|
|
||||||
total_upload=${total_upload:-0}
|
|
||||||
total_download=${total_download:-0}
|
|
||||||
|
|
||||||
echo "🔼 Uploaded Traffic: $(convert_bytes "$total_upload")"
|
|
||||||
echo "🔽 Downloaded Traffic: $(convert_bytes "$total_download")"
|
|
||||||
|
|
||||||
total_traffic=$((total_upload + total_download))
|
|
||||||
echo "📊 Total Traffic: $(convert_bytes "$total_traffic")"
|
|
||||||
fi
|
|
||||||
Reference in New Issue
Block a user