fix: reduce node usage to 2 API calls to avoid 429 rate limit

Per-node queries (8+ calls) hit Remnawave rate limit. Switch back to
single get_bandwidth_stats_user call with %Y-%m-%d date format (same
as traffic_monitoring_service). Add response logging to debug format.
Also optimize panel-info to use accessible-nodes instead of all-nodes.
This commit is contained in:
Fringg
2026-02-07 06:36:38 +03:00
parent b94e3edf80
commit f00a051bb3

View File

@@ -622,16 +622,16 @@ async def get_user_panel_info(
panel_user = panel_users[0]
# Resolve last connected node name
# Resolve last connected node name via accessible nodes (lighter than get_all_nodes)
last_node_name = None
last_node_uuid = None
if panel_user.user_traffic and panel_user.user_traffic.last_connected_node_uuid:
last_node_uuid = panel_user.user_traffic.last_connected_node_uuid
try:
nodes = await api.get_all_nodes()
for node in nodes:
accessible = await api.get_user_accessible_nodes(panel_user.uuid)
for node in accessible:
if node.uuid == last_node_uuid:
last_node_name = node.name
last_node_name = node.node_name
break
except Exception:
logger.warning(f'Failed to resolve node name for user {user_id}')
@@ -684,52 +684,58 @@ async def get_user_node_usage(
end_date = datetime.utcnow()
start_date = end_date - timedelta(days=days)
start_str = start_date.strftime('%Y-%m-%d')
end_str = end_date.strftime('%Y-%m-%d')
async with service.get_api_client() as api:
# Get user's accessible nodes
# Get user's accessible nodes (1 API call)
accessible_nodes = await api.get_user_accessible_nodes(user.remnawave_uuid)
if not accessible_nodes:
return UserNodeUsageResponse(items=[], period_days=days)
node_name_map = {n.uuid: n.node_name for n in accessible_nodes}
# Query per-node usage via legacy endpoint (proven format)
start_str = start_date.isoformat() + 'Z'
end_str = end_date.isoformat() + 'Z'
# Get user bandwidth stats (1 API call)
stats = await api.get_bandwidth_stats_user(user.remnawave_uuid, start_str, end_str)
logger.info(f'Bandwidth stats for user {user_id}: type={type(stats).__name__}, value={str(stats)[:500]}')
node_bytes: dict[str, int] = {}
if isinstance(stats, list):
for entry in stats:
nid = entry.get('nodeUuid') or entry.get('node_uuid', '')
total = entry.get('total', 0) or entry.get('totalBytes', 0)
if nid:
node_bytes[nid] = node_bytes.get(nid, 0) + int(total)
elif isinstance(stats, dict):
for key, val in stats.items():
if isinstance(val, dict):
total = val.get('total', 0) or val.get('totalBytes', 0)
node_bytes[key] = int(total)
elif isinstance(val, (int, float)):
node_bytes[key] = int(val)
# Build items from accessible nodes
items = []
for node in accessible_nodes:
try:
node_stats = await api.get_bandwidth_stats_node_users_legacy(
node.uuid, start_str, end_str,
items.append(
UserNodeUsageItem(
node_uuid=node.uuid,
node_name=node.node_name,
country_code=node.country_code,
total_bytes=node_bytes.get(node.uuid, 0),
)
# Find our user in node's user list
user_bytes = 0
if isinstance(node_stats, list):
for entry in node_stats:
if entry.get('userUuid') == user.remnawave_uuid:
user_bytes = entry.get('total', 0) or entry.get('totalBytes', 0)
break
)
# Add any nodes from stats not in accessible nodes
for nid, total in node_bytes.items():
if nid not in node_name_map:
items.append(
UserNodeUsageItem(
node_uuid=node.uuid,
node_name=node.node_name,
country_code=node.country_code,
total_bytes=user_bytes,
)
)
except Exception:
logger.warning(f'Failed to get stats for node {node.uuid} user {user_id}')
items.append(
UserNodeUsageItem(
node_uuid=node.uuid,
node_name=node.node_name,
country_code=node.country_code,
total_bytes=0,
node_uuid=nid,
node_name=nid[:8],
country_code='',
total_bytes=total,
)
)
# Sort by traffic descending
items.sort(key=lambda x: x.total_bytes, reverse=True)
return UserNodeUsageResponse(items=items, period_days=days)
except Exception as e: