Skip to content

Commit f0a1039

Browse files
committed
feat(node): count
1 parent e6e1a99 commit f0a1039

File tree

6 files changed

+28
-12
lines changed

6 files changed

+28
-12
lines changed

app/db/crud/node.py

Lines changed: 10 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -71,7 +71,7 @@ async def get_nodes(
7171
limit: int | None = None,
7272
ids: list[int] | None = None,
7373
search: str | None = None,
74-
) -> list[Node]:
74+
) -> tuple[list[Node], int]:
7575
"""
7676
Retrieves nodes based on optional status, enabled, id, and search filters.
7777
@@ -86,7 +86,9 @@ async def get_nodes(
8686
search (str | None): Optional search term to match node names.
8787
8888
Returns:
89-
List[Node]: A list of Node objects matching the criteria.
89+
tuple: A tuple containing:
90+
- list[Node]: A list of Node objects matching the criteria.
91+
- int: The total count of nodes matching the filters (before offset/limit).
9092
"""
9193
query = select(Node)
9294

@@ -111,6 +113,11 @@ async def get_nodes(
111113
like_expression = f"%{search_value}%"
112114
query = query.where(or_(Node.name.ilike(like_expression), Node.api_key.ilike(like_expression)))
113115

116+
# Get count before applying offset/limit
117+
count_query = select(func.count()).select_from(query.subquery())
118+
count = (await db.execute(count_query)).scalar_one()
119+
120+
# Apply pagination
114121
if offset:
115122
query = query.offset(offset)
116123
if limit:
@@ -120,7 +127,7 @@ async def get_nodes(
120127
for node in db_nodes:
121128
await load_node_attrs(node)
122129

123-
return db_nodes
130+
return db_nodes, count
124131

125132

126133
async def get_limited_nodes(db: AsyncSession) -> list[Node]:

app/jobs/node_checker.py

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,7 @@
1010
from app.utils.logger import get_logger
1111
from app.operation.node import NodeOperation
1212
from app.operation import OperatorType
13-
from app.db.crud.node import get_limited_nodes
13+
from app.db.crud.node import get_limited_nodes, get_nodes
1414

1515
from config import JOB_CORE_HEALTH_CHECK_INTERVAL, JOB_CHECK_NODE_LIMITS_INTERVAL
1616

@@ -161,7 +161,7 @@ async def node_health_check():
161161
Cron job that checks health of all enabled nodes.
162162
"""
163163
async with GetDB() as db:
164-
db_nodes = await node_operator.get_db_nodes(db=db, enabled=True)
164+
db_nodes, _ = await get_nodes(db=db, enabled=True)
165165
dict_nodes = await node_manager.get_nodes()
166166

167167
check_tasks = [process_node_health_check(db_node, dict_nodes.get(db_node.id)) for db_node in db_nodes]
@@ -173,7 +173,7 @@ async def initialize_nodes():
173173
logger.info("Starting nodes' cores...")
174174

175175
async with GetDB() as db:
176-
db_nodes = await node_operator.get_db_nodes(db=db, enabled=True)
176+
db_nodes, _ = await get_nodes(db=db, enabled=True)
177177

178178
if not db_nodes:
179179
logger.warning("Attention: You have no node, you need to have at least one node")

app/models/node.py

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -200,6 +200,11 @@ class NodeResponse(Node):
200200
model_config = ConfigDict(from_attributes=True)
201201

202202

203+
class NodesResponse(BaseModel):
204+
nodes: list[NodeResponse]
205+
total: int
206+
207+
203208
class NodeNotification(BaseModel):
204209
"""Lightweight node model for sending notifications without database fetch."""
205210

app/operation/node.py

Lines changed: 6 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -29,6 +29,7 @@
2929
NodeModify,
3030
NodeNotification,
3131
NodeResponse,
32+
NodesResponse,
3233
UsageTable,
3334
UserIPList,
3435
UserIPListAll,
@@ -54,8 +55,8 @@ async def get_db_nodes(
5455
status: NodeStatus | list[NodeStatus] | None = None,
5556
ids: list[int] | None = None,
5657
search: str | None = None,
57-
) -> list[Node]:
58-
return await get_nodes(
58+
) -> NodesResponse:
59+
db_nodes, count = await get_nodes(
5960
db=db,
6061
core_id=core_id,
6162
offset=offset,
@@ -65,6 +66,8 @@ async def get_db_nodes(
6566
ids=ids,
6667
search=search,
6768
)
69+
node_responses = [NodeResponse.model_validate(node) for node in db_nodes]
70+
return NodesResponse(nodes=node_responses, total=count)
6871

6972
@staticmethod
7073
async def _update_single_node_status(
@@ -442,7 +445,7 @@ async def restart_node(self, db: AsyncSession, node_id: Node, admin: AdminDetail
442445
logger.info(f'Node "{node_id}" restarted by admin "{admin.username}"')
443446

444447
async def restart_all_node(self, db: AsyncSession, admin: AdminDetails, core_id: int | None = None) -> None:
445-
nodes: list[Node] = await self.get_db_nodes(db, core_id, enabled=True)
448+
nodes, _ = await get_nodes(db, core_id=core_id, enabled=True)
446449
await self.connect_nodes_bulk(db, nodes)
447450
logger.info(f'All nodes restarted by admin "{admin.username}"')
448451

app/routers/node.py

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,7 @@
99
from app.db import AsyncSession, get_db
1010
from app.db.models import NodeStatus
1111
from app.models.admin import AdminDetails
12-
from app.models.node import NodeCreate, NodeModify, NodeResponse, NodeSettings, UsageTable, UserIPList, UserIPListAll
12+
from app.models.node import NodeCreate, NodeModify, NodeResponse, NodesResponse, NodeSettings, UsageTable, UserIPList, UserIPListAll
1313
from app.models.stats import NodeRealtimeStats, NodeStatsList, NodeUsageStatsList, Period
1414
from app.operation import OperatorType
1515
from app.operation.node import NodeOperation
@@ -43,7 +43,7 @@ async def get_usage(
4343
)
4444

4545

46-
@router.get("s", response_model=list[NodeResponse])
46+
@router.get("s", response_model=NodesResponse)
4747
async def get_nodes(
4848
core_id: int | None = None,
4949
offset: int | None = None,

app/telegram/handlers/admin/main_menu.py

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -39,7 +39,8 @@ async def reload_data(event: CallbackQuery, db: AsyncSession, admin: AdminDetail
3939
@router.callback_query(IsAdminSUDO(), AdminPanel.Callback.filter(AdminPanelAction.sync_users == F.action))
4040
async def sync_users(event: CallbackQuery, db: AsyncSession, admin: AdminDetails):
4141
await event.answer(Texts.syncing)
42-
for node in await node_operator.get_db_nodes(db):
42+
nodes_response = await node_operator.get_db_nodes(db)
43+
for node in nodes_response.nodes:
4344
await node_operator.sync_node_users(db, node.id, flush_users=True)
4445
try:
4546
stats = await system_operator.get_system_stats(db, admin)

0 commit comments

Comments
 (0)