- FastAPI REST API with JWT auth - aiogram 3 Telegram bot with admin middleware - APScheduler daily tasks (expiry, reminders, revoke, sync) - SQLAlchemy 2 async ORM with Alembic migrations - Jinja2 admin panel (Dashboard, Users, Payments, Servers, Tariffs) - VPN provider abstraction with MockProvider - Stats service with revenue/subscription analytics - Docker Compose (PostgreSQL + Redis + app) - Healthcheck endpoint
72 lines
2.4 KiB
Python
72 lines
2.4 KiB
Python
from datetime import datetime, timezone
|
|
|
|
from loguru import logger
|
|
|
|
from app.models.server import Server, ServerProtocol
|
|
from app.repositories.server import ServerRepository
|
|
|
|
|
|
class ServerService:
|
|
def __init__(self, server_repo: ServerRepository):
|
|
self.server_repo = server_repo
|
|
|
|
async def create(
|
|
self,
|
|
name: str,
|
|
host: str,
|
|
port: int,
|
|
protocol: ServerProtocol,
|
|
location: str,
|
|
country_code: str,
|
|
max_users: int = 100,
|
|
) -> Server:
|
|
existing = await self.server_repo.get_by_name(name)
|
|
if existing is not None:
|
|
raise ValueError(f"Server already exists: {name}")
|
|
|
|
server = await self.server_repo.create(
|
|
name=name,
|
|
host=host,
|
|
port=port,
|
|
protocol=protocol,
|
|
location=location,
|
|
country_code=country_code.upper(),
|
|
max_users=max_users,
|
|
)
|
|
|
|
logger.info("Server created: id={} name={} proto={}", server.id, name, protocol.value)
|
|
return server
|
|
|
|
async def get_by_id(self, server_id: int) -> Server | None:
|
|
return await self.server_repo.get(server_id)
|
|
|
|
async def get_active(self) -> list[Server]:
|
|
return await self.server_repo.get_active()
|
|
|
|
async def get_by_protocol(self, protocol: ServerProtocol) -> list[Server]:
|
|
return await self.server_repo.get_by_protocol(protocol)
|
|
|
|
async def get_least_loaded(self, protocol: ServerProtocol) -> Server | None:
|
|
return await self.server_repo.get_least_loaded(protocol)
|
|
|
|
async def update_load(self, server_id: int, load_percent: int) -> Server | None:
|
|
load = max(0, min(100, load_percent))
|
|
return await self.server_repo.update(server_id, load_percent=load)
|
|
|
|
async def mark_online(self, server_id: int) -> Server | None:
|
|
return await self.server_repo.update(server_id, is_active=True)
|
|
|
|
async def mark_offline(self, server_id: int) -> Server | None:
|
|
server = await self.server_repo.update(server_id, is_active=False)
|
|
if server:
|
|
logger.warning("Server marked offline: id={} name={}", server_id, server.name)
|
|
return server
|
|
|
|
async def update(
|
|
self, server_id: int, **kwargs
|
|
) -> Server | None:
|
|
return await self.server_repo.update(server_id, **kwargs)
|
|
|
|
async def get_count(self) -> int:
|
|
return await self.server_repo.count_active()
|