import discord from discord.ext import commands from config import ALLOWED_CHANNEL_ID, HIT_CHECK_INTERVAL, REASSIGN_DELAY from cogs.assignments import Assignments from cogs.commands import HitCommands import asyncio import uvicorn import json from pathlib import Path from fastapi import FastAPI, Request from fastapi.responses import HTMLResponse from fastapi.staticfiles import StaticFiles from fastapi.templating import Jinja2Templates from pydantic import BaseModel from services.torn_api import populate_friendly, populate_enemy, start_friendly_status_loop, start_enemy_status_loop # ============================================================ # FastAPI Setup # ============================================================ app = FastAPI() templates = Jinja2Templates(directory="templates") app.mount("/static", StaticFiles(directory="static"), name="static") # ============================================================ # Dashboard Webpage # ============================================================ @app.get("/", response_class=HTMLResponse) async def dashboard(request: Request): print(">>> DASHBOARD ROUTE LOADED") return templates.TemplateResponse("dashboard.html", {"request": request}) # ============================================================ # Pydantic model for JSON POST input # ============================================================ class FactionRequest(BaseModel): faction_id: int interval: int # ----------------------------- # Populate endpoints (populate JSON once) # ----------------------------- @app.post("/api/populate_friendly") async def api_populate_friendly(data: FactionRequest): from services.torn_api import populate_friendly await populate_friendly(data.faction_id) return {"status": "friendly populated", "id": data.faction_id} @app.post("/api/populate_enemy") async def api_populate_enemy(data: FactionRequest): from services.torn_api import populate_enemy await populate_enemy(data.faction_id) return {"status": "enemy populated", "id": data.faction_id} # ----------------------------- # Start status refresh loops # ----------------------------- @app.post("/api/start_friendly_status") async def api_start_friendly_status(data: FactionRequest): from services.torn_api import start_friendly_status_loop await start_friendly_status_loop(data.faction_id, data.interval) return {"status": "friendly status loop started", "id": data.faction_id, "interval": data.interval} @app.post("/api/start_enemy_status") async def api_start_enemy_status(data: FactionRequest): from services.torn_api import start_enemy_status_loop await start_enemy_status_loop(data.faction_id, data.interval) return {"status": "enemy status loop started", "id": data.faction_id, "interval": data.interval} # ============================= # Member JSON endpoints # ============================= @app.get("/api/friendly_members") async def get_friendly_members(): path = Path("data/friendly_faction.json") if not path.exists(): return [] with open(path, "r", encoding="utf-8") as f: return json.load(f) @app.get("/api/enemy_members") async def get_enemy_members(): path = Path("data/enemy_faction.json") if not path.exists(): return [] with open(path, "r", encoding="utf-8") as f: return json.load(f) # ============================================================ # Discord Bot Setup # ============================================================ intents = discord.Intents.default() intents.message_content = True enrolled_attackers = [] enemy_queue = [] active_assignments = {} round_robin_index = 0 class HitDispatchBot(commands.Bot): async def setup_hook(self): await self.add_cog( Assignments( self, enemy_queue=enemy_queue, active_assignments=active_assignments, enrolled_attackers=enrolled_attackers, hit_check=HIT_CHECK_INTERVAL, reassign_delay=REASSIGN_DELAY, ) ) await self.add_cog( HitCommands( self, enrolled_attackers=enrolled_attackers, enemy_queue=enemy_queue ) ) async def cog_check(self, ctx): return ctx.channel.id == ALLOWED_CHANNEL_ID bot = HitDispatchBot(command_prefix="!", intents=intents) @bot.event async def on_ready(): print(f"Logged in as {bot.user.name}") TOKEN = "YOUR_DISCORD_TOKEN" async def start_bot(): await bot.start(TOKEN) # ============================================================ # Main Entry Point # ============================================================ if __name__ == "__main__": loop = asyncio.get_event_loop() # Start Discord bot in background loop.create_task(start_bot()) # Run FastAPI app — keeps loop alive uvicorn.run(app, host="127.0.0.1", port=8000)