Files
Nexus/server/infrastructure/database/server_repo.py
T
Your Name 938d26927f P1/P2: 后端安全与稳定性修复
- Agent per-server API Key认证 (agent.py)
- JWT updated_at校验与会话超时 (auth_jwt.py)
- 服务器凭据Fernet加密存储+密码脱敏 (servers.py)
- WebSSH服务器级授权检查 (webssh.py)
- Config同步去重+回滚机制 (sync_engine_v2.py)
- DB层分页offset/limit (server_repo.py)
- session.py logger修复 + @property死代码清理
- 心跳刷入rollback误用修复 (heartbeat_flush.py)

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
2026-05-22 22:28:57 +08:00

99 lines
3.4 KiB
Python

"""Nexus — Server Repository (Async SQLAlchemy implementation)
Concrete implementation of ServerRepository protocol.
"""
from datetime import datetime, timezone
from typing import Optional, List, Tuple
from sqlalchemy import select, update, delete, func
from sqlalchemy.ext.asyncio import AsyncSession
from server.domain.models import Server
class ServerRepositoryImpl:
"""Async SQLAlchemy implementation of Server data access"""
def __init__(self, session: AsyncSession):
self.session = session
async def get_by_id(self, id: int) -> Optional[Server]:
result = await self.session.execute(select(Server).where(Server.id == id))
return result.scalar_one_or_none()
async def get_all(self) -> List[Server]:
result = await self.session.execute(select(Server).order_by(Server.id))
return list(result.scalars().all())
async def get_paginated(
self,
category: Optional[str] = None,
offset: int = 0,
limit: int = 50,
) -> Tuple[List[Server], int]:
"""Get paginated server list with total count.
Returns (servers, total_count) — DB-level pagination for 2000+ servers.
"""
# Base query
base_query = select(Server)
if category:
base_query = base_query.where(Server.category == category)
# Count query
count_query = select(func.count(Server.id))
if category:
count_query = count_query.where(Server.category == category)
count_result = await self.session.execute(count_query)
total = count_result.scalar_one() or 0
# Paginated data query
data_query = base_query.order_by(Server.id).offset(offset).limit(limit)
result = await self.session.execute(data_query)
servers = list(result.scalars().all())
return servers, total
async def get_by_category(self, category: str) -> List[Server]:
result = await self.session.execute(
select(Server).where(Server.category == category).order_by(Server.id)
)
return list(result.scalars().all())
async def get_online(self) -> List[Server]:
result = await self.session.execute(
select(Server).where(Server.is_online == True).order_by(Server.id)
)
return list(result.scalars().all())
async def create(self, server: Server) -> Server:
self.session.add(server)
await self.session.commit()
await self.session.refresh(server)
return server
async def update(self, server: Server) -> Server:
await self.session.commit()
await self.session.refresh(server)
return server
async def delete(self, id: int) -> bool:
server = await self.get_by_id(id)
if server:
await self.session.delete(server)
await self.session.commit()
return True
return False
async def update_heartbeat(self, id: int, is_online: bool, system_info: str, agent_version: str) -> None:
"""Update server online status from Agent heartbeat"""
await self.session.execute(
update(Server)
.where(Server.id == id)
.values(
is_online=is_online,
last_heartbeat=datetime.now(timezone.utc),
system_info=system_info,
agent_version=agent_version,
)
)
await self.session.commit()