diff --git a/core/cli_api.py b/core/cli_api.py index 06775d5..9198aa4 100644 --- a/core/cli_api.py +++ b/core/cli_api.py @@ -35,7 +35,7 @@ class Command(Enum): 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') 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') RESTORE_HYSTERIA2 = os.path.join(SCRIPT_DIR, 'hysteria2', 'restore.sh') 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 +# Next Update: # TODO: it's better to return json +# TODO: After json todo need fix Telegram Bot and WebPanel def server_info() -> str | None: '''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]: diff --git a/core/scripts/hysteria2/server_info.py b/core/scripts/hysteria2/server_info.py new file mode 100644 index 0000000..329dbc4 --- /dev/null +++ b/core/scripts/hysteria2/server_info.py @@ -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() diff --git a/core/scripts/hysteria2/server_info.sh b/core/scripts/hysteria2/server_info.sh deleted file mode 100644 index fd4375e..0000000 --- a/core/scripts/hysteria2/server_info.sh +++ /dev/null @@ -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 \ No newline at end of file