|
23 | 23 | from app.db.crud.user import get_user |
24 | 24 | from app.db.models import Node, NodeStatus |
25 | 25 | from app.models.admin import AdminDetails |
26 | | -from app.models.node import NodeCreate, NodeModify, NodeNotification, NodeResponse, UsageTable |
| 26 | +from app.models.node import NodeCreate, NodeModify, NodeNotification, NodeResponse, UsageTable, UserIPList, UserIPListAll |
27 | 27 | from app.models.stats import NodeRealtimeStats, NodeStatsList, NodeUsageStatsList, Period |
28 | 28 | from app.node import core_users, node_manager |
29 | 29 | from app.operation import BaseOperation |
@@ -416,25 +416,55 @@ async def get_user_online_stats_by_node(self, db: AsyncSession, node_id: Node, u |
416 | 416 |
|
417 | 417 | async def get_user_ip_list_by_node( |
418 | 418 | self, db: AsyncSession, node_id: Node, username: str |
419 | | - ) -> dict[int, dict[str, int]]: |
| 419 | + ) -> UserIPList: |
420 | 420 | db_user = await get_user(db, username=username) |
421 | 421 | if db_user is None: |
422 | 422 | await self.raise_error(message="User not found", code=404) |
423 | 423 |
|
424 | | - node = await node_manager.get_node(node_id) |
| 424 | + email = f"{db_user.id}.{db_user.username}" |
| 425 | + ips = await self._get_node_user_ip_list_safe(node_id, email) |
425 | 426 |
|
426 | | - if node is None: |
427 | | - await self.raise_error(message="Node not found", code=404) |
| 427 | + if ips is None: |
| 428 | + await self.raise_error(message="Node not found or unavailable", code=404) |
| 429 | + |
| 430 | + return UserIPList(ips=ips) |
| 431 | + |
| 432 | + async def get_user_ip_list_all_nodes(self, db: AsyncSession, username: str) -> UserIPListAll: |
| 433 | + db_user = await get_user(db, username=username) |
| 434 | + if db_user is None: |
| 435 | + await self.raise_error(message="User not found", code=404) |
| 436 | + |
| 437 | + nodes = await node_manager.get_healthy_nodes() |
| 438 | + email = f"{db_user.id}.{db_user.username}" |
| 439 | + |
| 440 | + ip_list_tasks = {id: asyncio.create_task(self._get_node_user_ip_list_safe(id, email)) for id, _ in nodes} |
| 441 | + |
| 442 | + await asyncio.gather(*ip_list_tasks.values(), return_exceptions=True) |
| 443 | + |
| 444 | + results = {} |
| 445 | + for node_id, task in ip_list_tasks.items(): |
| 446 | + if task.exception() or task.result() is None: |
| 447 | + results[node_id] = None |
| 448 | + else: |
| 449 | + results[node_id] = UserIPList(ips=task.result()) |
| 450 | + |
| 451 | + return UserIPListAll(nodes=results) |
428 | 452 |
|
| 453 | + async def _get_node_user_ip_list_safe(self, node_id: int, email: str) -> dict[str, int] | None: |
| 454 | + """Wrapper method that returns None instead of raising exceptions""" |
429 | 455 | try: |
430 | | - stats = await node.get_user_online_ip_list(email=f"{db_user.id}.{db_user.username}") |
431 | | - except NodeAPIError as e: |
432 | | - await self.raise_error(message=e.detail, code=e.code) |
| 456 | + node = await node_manager.get_node(node_id) |
| 457 | + if node is None: |
| 458 | + return None |
433 | 459 |
|
434 | | - if stats is None: |
435 | | - await self.raise_error(message="Stats not found", code=404) |
| 460 | + stats = await node.get_user_online_ip_list(email=email) |
| 461 | + if stats is None: |
| 462 | + return None |
436 | 463 |
|
437 | | - return {node_id: stats.ips} |
| 464 | + return stats.ips |
| 465 | + except Exception as e: |
| 466 | + logger.error(f"Error getting IP list for user {email} on node {node_id}: {e}") |
| 467 | + return None |
438 | 468 |
|
439 | 469 | async def sync_node_users(self, db: AsyncSession, node_id: int, flush_users: bool = False) -> NodeResponse: |
440 | 470 | db_node = await self.get_validated_node(db, node_id=node_id) |
|
0 commit comments