Merge pull request #126 from ReturnFI/beta
feat(api): integrated Hysteria2-API package for traffic file management
This commit is contained in:
@ -1,3 +1,7 @@
|
|||||||
📄 Improve user page and display user information
|
## [1.5.0] - 2025-04-11
|
||||||
|
### Added
|
||||||
|
- Integrated Hysteria2-API package (https://github.com/ReturnFI/Hysteria2-API)
|
||||||
|
- Added support for managing traffic file via API
|
||||||
|
|
||||||
Thanks to @SeyedHashtag for their contribution!💖
|
### Changed
|
||||||
|
- Refactored traffic-related logic to use the new API package
|
||||||
|
|||||||
@ -1,13 +1,13 @@
|
|||||||
#!/usr/bin/env python3
|
#!/usr/bin/env python3
|
||||||
import subprocess
|
|
||||||
import json
|
import json
|
||||||
import os
|
import os
|
||||||
|
import json
|
||||||
|
from hysteria2_api import Hysteria2Client
|
||||||
|
|
||||||
# Define static variables for paths and URLs
|
# Define static variables for paths and URLs
|
||||||
CONFIG_FILE = '/etc/hysteria/config.json'
|
CONFIG_FILE = '/etc/hysteria/config.json'
|
||||||
USERS_FILE = '/etc/hysteria/users.json'
|
USERS_FILE = '/etc/hysteria/users.json'
|
||||||
TRAFFIC_API_URL = 'http://127.0.0.1:25413/traffic?clear=1'
|
API_BASE_URL = 'http://127.0.0.1:25413'
|
||||||
ONLINE_API_URL = 'http://127.0.0.1:25413/online'
|
|
||||||
|
|
||||||
def traffic_status():
|
def traffic_status():
|
||||||
green = '\033[0;32m'
|
green = '\033[0;32m'
|
||||||
@ -15,8 +15,10 @@ def traffic_status():
|
|||||||
NC = '\033[0m'
|
NC = '\033[0m'
|
||||||
|
|
||||||
try:
|
try:
|
||||||
secret = subprocess.check_output(['jq', '-r', '.trafficStats.secret', CONFIG_FILE]).decode().strip()
|
with open(CONFIG_FILE, 'r') as config_file:
|
||||||
except subprocess.CalledProcessError as e:
|
config = json.load(config_file)
|
||||||
|
secret = config.get('trafficStats', {}).get('secret')
|
||||||
|
except (json.JSONDecodeError, FileNotFoundError) as e:
|
||||||
print(f"Error: Failed to read secret from {CONFIG_FILE}. Details: {e}")
|
print(f"Error: Failed to read secret from {CONFIG_FILE}. Details: {e}")
|
||||||
return
|
return
|
||||||
|
|
||||||
@ -24,29 +26,16 @@ def traffic_status():
|
|||||||
print("Error: Secret not found in config.json")
|
print("Error: Secret not found in config.json")
|
||||||
return
|
return
|
||||||
|
|
||||||
try:
|
client = Hysteria2Client(base_url=API_BASE_URL, secret=secret)
|
||||||
response = subprocess.check_output(['curl', '-s', '-H', f'Authorization: {secret}', TRAFFIC_API_URL]).decode().strip()
|
|
||||||
except subprocess.CalledProcessError as e:
|
|
||||||
print(f"Error: Failed to fetch traffic data. Details: {e}")
|
|
||||||
return
|
|
||||||
|
|
||||||
try:
|
try:
|
||||||
online_response = subprocess.check_output(['curl', '-s', '-H', f'Authorization: {secret}', ONLINE_API_URL]).decode().strip()
|
traffic_stats = client.get_traffic_stats(clear=True)
|
||||||
except subprocess.CalledProcessError as e:
|
|
||||||
print(f"Error: Failed to fetch online status data. Details: {e}")
|
online_status = client.get_online_clients()
|
||||||
|
except Exception as e:
|
||||||
|
print(f"Error communicating with Hysteria2 API: {e}")
|
||||||
return
|
return
|
||||||
|
|
||||||
if not online_response:
|
|
||||||
print("No online data available.")
|
|
||||||
return
|
|
||||||
|
|
||||||
response_dict = {}
|
|
||||||
if response and response != "{}":
|
|
||||||
response_dict = json.loads(response)
|
|
||||||
|
|
||||||
online_dict = json.loads(online_response)
|
|
||||||
|
|
||||||
# Load the current users.json data
|
|
||||||
users_data = {}
|
users_data = {}
|
||||||
if os.path.exists(USERS_FILE):
|
if os.path.exists(USERS_FILE):
|
||||||
try:
|
try:
|
||||||
@ -59,32 +48,28 @@ def traffic_status():
|
|||||||
for user in users_data:
|
for user in users_data:
|
||||||
users_data[user]["status"] = "Offline"
|
users_data[user]["status"] = "Offline"
|
||||||
|
|
||||||
for user, online_status in online_dict.items():
|
for user_id, status in online_status.items():
|
||||||
if user in users_data:
|
if user_id in users_data:
|
||||||
users_data[user]["status"] = "Online" if online_status == 1 else "Offline"
|
users_data[user_id]["status"] = "Online" if status.is_online else "Offline"
|
||||||
else:
|
else:
|
||||||
users_data[user] = {
|
users_data[user_id] = {
|
||||||
"upload_bytes": 0,
|
"upload_bytes": 0,
|
||||||
"download_bytes": 0,
|
"download_bytes": 0,
|
||||||
"status": "Online" if online_status == 1 else "Offline"
|
"status": "Online" if status.is_online else "Offline"
|
||||||
}
|
}
|
||||||
|
|
||||||
for user, traffic_info in response_dict.items():
|
for user_id, stats in traffic_stats.items():
|
||||||
tx_bytes = traffic_info.get('tx', 0)
|
if user_id in users_data:
|
||||||
rx_bytes = traffic_info.get('rx', 0)
|
users_data[user_id]["upload_bytes"] = users_data[user_id].get("upload_bytes", 0) + stats.upload_bytes
|
||||||
|
users_data[user_id]["download_bytes"] = users_data[user_id].get("download_bytes", 0) + stats.download_bytes
|
||||||
if user in users_data:
|
|
||||||
users_data[user]["upload_bytes"] = users_data[user].get("upload_bytes", 0) + tx_bytes
|
|
||||||
users_data[user]["download_bytes"] = users_data[user].get("download_bytes", 0) + rx_bytes
|
|
||||||
else:
|
else:
|
||||||
online_status = online_dict.get(user, 0)
|
online = user_id in online_status and online_status[user_id].is_online
|
||||||
users_data[user] = {
|
users_data[user_id] = {
|
||||||
"upload_bytes": tx_bytes,
|
"upload_bytes": stats.upload_bytes,
|
||||||
"download_bytes": rx_bytes,
|
"download_bytes": stats.download_bytes,
|
||||||
"status": "Online" if online_status == 1 else "Offline"
|
"status": "Online" if online else "Offline"
|
||||||
}
|
}
|
||||||
|
|
||||||
# Save the updated data back to users.json
|
|
||||||
with open(USERS_FILE, 'w') as users_file:
|
with open(USERS_FILE, 'w') as users_file:
|
||||||
json.dump(users_data, users_file, indent=4)
|
json.dump(users_data, users_file, indent=4)
|
||||||
|
|
||||||
|
|||||||
@ -20,6 +20,7 @@ requests==2.32.3
|
|||||||
typing_extensions==4.12.2
|
typing_extensions==4.12.2
|
||||||
urllib3==2.3.0
|
urllib3==2.3.0
|
||||||
yarl==1.18.3
|
yarl==1.18.3
|
||||||
|
hysteria2-api==0.1.2
|
||||||
|
|
||||||
# webpanel
|
# webpanel
|
||||||
annotated-types==0.7.0
|
annotated-types==0.7.0
|
||||||
|
|||||||
Reference in New Issue
Block a user