Enhance the bot's architecture by introducing sharding capabilities, allowing for better scalability and performance. Update environment files to include sharding options, and modify the bot's core logic to handle shard connections and latencies. Implement shard-specific logging and API synchronization, ensuring that only the primary shard performs certain tasks. Update API schemas and routes to reflect shard information, improving the overall status reporting and monitoring of the bot's performance across multiple shards.
138 lines
5.4 KiB
Python
138 lines
5.4 KiB
Python
# ╔══════════════════════════════════════════════════════════════════╗
|
|
# ║ ║
|
|
# ║ +-+-+-+-+-+-+-+-+ ║
|
|
# ║ |H|e|x|a|H|o|s|t| ║
|
|
# ║ +-+-+-+-+-+-+-+-+ ║
|
|
# ║ ║
|
|
# ║ © 2026 HexaHost — All Rights Reserved ║
|
|
# ║ ║
|
|
# ║ discord ── https://discord.gg/hexahost ║
|
|
# ║ github ── https://github.com/theoneandonlymace ║
|
|
# ║ ║
|
|
# ╚══════════════════════════════════════════════════════════════════╝
|
|
from utils.db_paths import db_path
|
|
|
|
from fastapi import APIRouter, Depends, HTTPException
|
|
from api.dependencies import get_bot
|
|
from api.schemas import AdminStats, AdminNodeStatus, AdminConfig, AdminConfigUpdate
|
|
from typing import TYPE_CHECKING, List
|
|
import os
|
|
import aiosqlite
|
|
|
|
if TYPE_CHECKING:
|
|
from core.axiom import Axiom
|
|
|
|
router = APIRouter()
|
|
|
|
CONFIG_DB = db_path("admin_config.db")
|
|
|
|
async def init_db():
|
|
async with aiosqlite.connect(CONFIG_DB) as db:
|
|
await db.execute("CREATE TABLE IF NOT EXISTS config (key TEXT PRIMARY KEY, value TEXT)")
|
|
# Default values
|
|
await db.execute("INSERT OR IGNORE INTO config (key, value) VALUES ('maintenance_mode', 'false')")
|
|
await db.execute("INSERT OR IGNORE INTO config (key, value) VALUES ('global_notification', '')")
|
|
await db.commit()
|
|
|
|
import psutil
|
|
import time
|
|
|
|
@router.get("/stats", response_model=AdminStats)
|
|
async def get_admin_stats(bot: "Axiom" = Depends(get_bot)):
|
|
# Calculate DB size and shard info
|
|
total_size: float = 0.0
|
|
db_count = 0
|
|
db_dir = "db"
|
|
if os.path.exists(db_dir):
|
|
for f in os.listdir(db_dir):
|
|
if f.endswith(".db"):
|
|
total_size += float(os.path.getsize(os.path.join(db_dir, f)))
|
|
db_count += 1
|
|
|
|
mb_size = total_size / (1024 * 1024)
|
|
db_size_str = f"{mb_size:.2f} MB"
|
|
if mb_size > 1024:
|
|
db_size_str = f"{(mb_size / 1024):.2f} GB"
|
|
|
|
# System Metrics
|
|
process = psutil.Process(os.getpid())
|
|
# Use a non-blocking interval check or global state for CPU
|
|
cpu_usage = psutil.cpu_percent()
|
|
ram_raw = process.memory_info().rss
|
|
ram_mb = ram_raw / (1024 * 1024)
|
|
|
|
total_commands = len(bot.commands)
|
|
loaded_cogs = len(bot.cogs or {})
|
|
|
|
# Node Healths
|
|
nodes = [
|
|
AdminNodeStatus(
|
|
name="Primary API Cluster",
|
|
status="Healthy",
|
|
load=f"CPU: {cpu_usage}% | RAM: {ram_mb:.1f}MB",
|
|
icon="Globe"
|
|
),
|
|
AdminNodeStatus(
|
|
name="Database Shards",
|
|
status="Healthy" if db_count > 0 else "Warning",
|
|
load=f"{db_count} SQLite DBs | {db_size_str}",
|
|
icon="Database"
|
|
),
|
|
AdminNodeStatus(
|
|
name="Bot Microservices",
|
|
status="Healthy" if bot.is_ready() else "Booting",
|
|
load=f"{loaded_cogs} Modules",
|
|
icon="Cpu"
|
|
),
|
|
AdminNodeStatus(
|
|
name="Auth Sockets",
|
|
status="Healthy",
|
|
load=(
|
|
f"Shards: {bot.shard_count or 1} | "
|
|
f"Latency: {round(bot.latency * 1000)}ms"
|
|
+ (
|
|
" | "
|
|
+ ", ".join(f"s{sid}:{round(lat * 1000)}ms" for sid, lat in bot.latencies)
|
|
if bot.latencies and len(bot.latencies) > 1
|
|
else ""
|
|
)
|
|
),
|
|
icon="Lock"
|
|
)
|
|
]
|
|
|
|
total_members = sum(g.member_count or 0 for g in bot.guilds)
|
|
|
|
return AdminStats(
|
|
total_users=str(total_members),
|
|
active_servers=str(len(bot.guilds)),
|
|
api_latency=f"{round(bot.latency * 1000, 2)}ms",
|
|
db_size=db_size_str,
|
|
nodes=nodes
|
|
)
|
|
|
|
@router.get("/config", response_model=AdminConfig)
|
|
async def get_admin_config():
|
|
await init_db()
|
|
async with aiosqlite.connect(CONFIG_DB) as db:
|
|
async with db.execute("SELECT value FROM config WHERE key = 'maintenance_mode'") as cursor:
|
|
mm = await cursor.fetchone()
|
|
async with db.execute("SELECT value FROM config WHERE key = 'global_notification'") as cursor:
|
|
gn = await cursor.fetchone()
|
|
|
|
return AdminConfig(
|
|
maintenance_mode=mm[0].lower() == 'true' if mm else False,
|
|
global_notification=gn[0] if gn else None
|
|
)
|
|
|
|
@router.patch("/config")
|
|
async def patch_admin_config(data: AdminConfigUpdate):
|
|
await init_db()
|
|
async with aiosqlite.connect(CONFIG_DB) as db:
|
|
if data.maintenance_mode is not None:
|
|
await db.execute("UPDATE config SET value = ? WHERE key = 'maintenance_mode'", (str(data.maintenance_mode).lower(),))
|
|
if data.global_notification is not None:
|
|
await db.execute("UPDATE config SET value = ? WHERE key = 'global_notification'", (data.global_notification,))
|
|
await db.commit()
|
|
return {"status": "success"}
|