From 1dde34d266893cd24dced0074d73f1ac024faa3f Mon Sep 17 00:00:00 2001 From: jerick Date: Wed, 26 Nov 2025 16:35:23 -0500 Subject: [PATCH] skeleton webpage --- __pycache__/config.cpython-311.pyc | Bin 0 -> 462 bytes __pycache__/main.cpython-311.pyc | Bin 0 -> 4932 bytes cogs/__pycache__/assignments.cpython-311.pyc | Bin 0 -> 4105 bytes cogs/__pycache__/commands.cpython-311.pyc | Bin 0 -> 3483 bytes main.py | 60 +++++++++++++++- routes/faction.py | 31 ++++++++ .../__pycache__/ffscouter.cpython-311.pyc | Bin 0 -> 2313 bytes services/__pycache__/torn_api.cpython-311.pyc | Bin 0 -> 6504 bytes services/torn_api.py | 67 ++++++++++++++++-- static/dashboard.js | 0 static/styles.css | 0 templates/dashboard.html | 24 +++++++ 12 files changed, 175 insertions(+), 7 deletions(-) create mode 100644 __pycache__/config.cpython-311.pyc create mode 100644 __pycache__/main.cpython-311.pyc create mode 100644 cogs/__pycache__/assignments.cpython-311.pyc create mode 100644 cogs/__pycache__/commands.cpython-311.pyc create mode 100644 routes/faction.py create mode 100644 services/__pycache__/ffscouter.cpython-311.pyc create mode 100644 services/__pycache__/torn_api.cpython-311.pyc create mode 100644 static/dashboard.js create mode 100644 static/styles.css create mode 100644 templates/dashboard.html diff --git a/__pycache__/config.cpython-311.pyc b/__pycache__/config.cpython-311.pyc new file mode 100644 index 0000000000000000000000000000000000000000..4411a3c544e808f71b3c46f285cf5013e0083f27 GIT binary patch literal 462 zcmYjNO-tiY6uq&wRxvilDY_Y%VPMqFptu=D24eDRLo-R~hc%DDqm%a>qis`@SalbF zh5iHam&{IFhO7iv?gU-A@ws;09}@uY&n-YN z&x>B9SiTU}J_(RYdv?E5w>GeSWE>Ah>!Zg-9(df!=!}!OQcR~?R>LGpT_-hUrxG&J zPn%Q}wWV7o(Y3T>TkXdGhO8Kd)j=9jtBPqNBMXU@N>jDkE!22#5$l%0eUs~5#Yp9< z-r{Mb*8X`j4Wu-i`i@C7WGMCxJoEp+YgOHJ+93-<=a2=Sd*o=od(vlvD0DP7Vm*JD z31`3SMxH+)r`>>1FC2Cw_kjHJBggdz``+(w!}HhTR^O*5J@zAzd2x2?@H?lcoFEAI trO)wnGPiICQXNq0PE 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 EKly5qng9R* literal 0 HcmV?d00001 diff --git a/cogs/__pycache__/commands.cpython-311.pyc b/cogs/__pycache__/commands.cpython-311.pyc new file mode 100644 index 0000000000000000000000000000000000000000..256618d3ebaaf79b5f2cd2cf50d63010b79c039e GIT binary patch literal 3483 zcmds3|BDkx6rb5mHtSuCx_Wm}+qzo0yI9R>Efq>B)YDXuUTf8B8xEFrch2mYWaI4S z)HH>oN;yiQQlux;!u@0s|CYk0EHvy-g;HpLJA3`fpZaFMUA~G!e{%EkGV|s$FEj6b z_RajfeftQ4=RTP-OaY-kSSNatVPo?gG}e%gbX-OiT*R2QxiVMbi+m+fOkl*J50K8^ zL3)DVrDz^{$RqR^zQI!z^yEd96aHr19QH)btW?yhZsj;{PratAHc?2GRBkDYs%9Hz z)td;di_{=hy&Ml{p-2CR3p<-GG}aJ7MXaMDr{g=Q$a9D!I@SY-#~~cS4(_0bU6!Ko zOg!wb2cLQ-KGBC4pNUWQ;kW4mL@ecvo-^#(Fj`t7-T{KRBg6u{c^uRlYT_nR;^8I- zJsfqLJoKVqK?1=sp3Ctbf5o&tiBzdsE)!i*ZCll@5o&p(K{Bq_NuA^pUcw^fMY;{# zQAQa$3d&+@k>Ppz(d;`5mo1pKutcb#U0XO~YV``K+SbAuvP{Zmjdd2n%qlljs_2GQ zQ*EuJzycOD^Qr|ZAVj`)%M%sFs2aASH1>3CJ|9_utH?S4Y6Z1-kFO@a72Aj2T1~j( zf%g7M_M3Hl*#rpE;%!5RE%`QlH~#^39$`OhOVAFUr8r<;ax8#L@!VxZUv1*`n9tD+ z_N(KEFz<0Z_cjFh3w|E0@n6H+!GhiCX}vRrv708>?E^zP2mf0WcdR#l+kON_|J387 ze;qk~uCe!Xvo5QY$ZDAqRlg-i+0QqoR_(b*l&s@9H5VQnua}kyk_6@Qgz^nV(1o&BJhT8XG22p{|%`# z(}B%r*$)8v3qC98cWLb2k$cBhQ|(dduI`Q>b4Ho8rLnc?@28#pZ?~jVu5`*t50G|R zS}nB2G;riMaq?Gja{We2oN>h&N1SPAc70d+rgZ=H2S?m}N1chwfwVI7Zf4#QhYH;R zOZ%Vbg&$Lwc|tIQ zjxqB%sBQu!bZXWbJ3HyaEPEJmFnR7DcK4ldMw!Iqd9x**bfuF{dVstLc|LI_n6xq% z-ONQt94h_fVQ+3p|Yt@7#9fd&`h^BmO)uMeL2T=nGmS$1s8 zVR4t?Bv<9&=+@;MhFy}0Wg8VZ-*wr7`e7Yx94@E^oHnv;hCtv+uZw(+qpVO;#(=Pj z&+-^Az|J_I2Gq}9 z*Ws}vOl~x}v4243qru7EFUFoco z9x8tF=W-+Lrc+fbL{YpEMX8v2z0BHaMY&#A%fSfEumG@ad#Uh}ME5e&D@@5u9Rl?T z`A+>qm8O`LDHc5I7f>tlXM^LDQ^4#Aq-Ih*Pj1>l zoOZ!QW7&Wzk+)4+Rn(dh6cZK=kDoQK1_7Fa?pDyAith#qc#pmT1FR%kCa4V_W86lv f(=Bau-Went!W3q!9jxz8-#hxmANzL*!e7vThFmWP literal 0 HcmV?d00001 diff --git a/main.py b/main.py index 6b504f4..1d3e4fc 100644 --- a/main.py +++ b/main.py @@ -4,10 +4,54 @@ 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 + +from fastapi import FastAPI, Request, Form +from fastapi.responses import HTMLResponse +from fastapi.staticfiles import StaticFiles +from fastapi.templating import Jinja2Templates + +from services.torn_api import update_enemy_faction, update_friendly_faction + + + +app = FastAPI() + +templates = Jinja2Templates(directory="templates") +app.mount("/static", StaticFiles(directory="static"), name="static") + + +# ----------------------------- +# Dashboard page +# ----------------------------- +@app.get("/", response_class=HTMLResponse) +async def dashboard(request: Request): + print(">>> DASHBOARD ROUTE LOADED") + return templates.TemplateResponse("dashboard.html", {"request": request}) + + + +# ----------------------------- +# API Endpoints +# ----------------------------- +@app.post("/api/enemy") +async def api_enemy(faction_id: int, interval: int): + await update_enemy_faction(faction_id, interval) + return {"status": "enemy loop running", "id": faction_id, "interval": interval} + + +@app.post("/api/friendly") +async def api_friendly(faction_id: int, interval: int): + await update_friendly_faction(faction_id, interval) + return {"status": "friendly loop running", "id": faction_id, "interval": interval} + + +# Discord intents = discord.Intents.default() intents.message_content = True -# Global state + enrolled_attackers = [] enemy_queue = [] active_assignments = {} @@ -43,4 +87,16 @@ bot = HitDispatchBot(command_prefix="!", intents=intents) async def on_ready(): print(f"Logged in as {bot.user.name}") -bot.run("MTQ0Mjg3NjU3NTUzMDg3NzAxMQ.GNuHPr.UreuYD1B7YYjfsbfRcEbhFyjyqvhQDepRCN4kk") +TOKEN = "YOUR_DISCORD_TOKEN" + +async def start_bot(): + await bot.start(TOKEN) + +if __name__ == "__main__": + loop = asyncio.get_event_loop() + + # Start Discord bot in background + loop.create_task(start_bot()) + + # Run FastAPI (this will keep the loop alive) + uvicorn.run(app, host="127.0.0.1", port=8000) diff --git a/routes/faction.py b/routes/faction.py new file mode 100644 index 0000000..25268f8 --- /dev/null +++ b/routes/faction.py @@ -0,0 +1,31 @@ +from fastapi import APIRouter +from pydantic import BaseModel +import asyncio + +router = APIRouter() + +class FactionRequest(BaseModel): + faction_id: int + refresh_interval: int + +async def update_friendly_faction_loop(faction_id: int, interval: int): + while True: + print(f"Refreshing friendly faction {faction_id}") + # call your update_friendly_faction() here + await asyncio.sleep(interval) + +async def update_enemy_faction_loop(faction_id: int, interval: int): + while True: + print(f"Refreshing enemy faction {faction_id}") + # call your update_enemy_faction() here + await asyncio.sleep(interval) + +@router.post("/refresh/friendly") +async def refresh_friendly(data: FactionRequest): + asyncio.create_task(update_friendly_faction_loop(data.faction_id, data.refresh_interval)) + return {"status": "friendly loop started"} + +@router.post("/refresh/enemy") +async def refresh_enemy(data: FactionRequest): + asyncio.create_task(update_enemy_faction_loop(data.faction_id, data.refresh_interval)) + return {"status": "enemy loop started"} diff --git a/services/__pycache__/ffscouter.cpython-311.pyc b/services/__pycache__/ffscouter.cpython-311.pyc new file mode 100644 index 0000000000000000000000000000000000000000..02e0f28003600a221ec982b569649ea9120919a5 GIT binary patch literal 2313 zcmbVOO>7%Q6n?Y2j%zoGs-+9Cii%JcXvy@MEz z0l{cF;ED}n7_-o1*bqe>9jb)Z(C1(gecZ-pbu40>+iS7%#8O0C{TsjyWRN2_;HH*W zgs-8W^3>%;6mHjF;B}ZMmUdBn9~RV)wY-{B3r*hE%pj+<#(iR)meZyr=i0D5XKP&8 z0THb00IarVn^sN)Y%np?@@oAukJ>sqvMHM}$Z3Tp<_!d`%;%xuIq%sxb~?BhBG8P7 zYZsJ{)N!~#2#n(%WA$vvU{hYammuefK`UOYzb&&lzmDSw73L)6dWKQUHU+hGE)2o- zq{DPWPuX1PPEtSVu(W-8Ojp2wQ96NUY^}QDMW^k3=JideAQ9dbf$-lj6HNdGIWNDS87n+L>~ud zeFMT^sN)BZKllyzVYa6c{y$k0)jb0^J_h0KQweKpo?J}sdo z4EkMd%CXa~I&EZ_JoK3CI@fF1j@%@-Bbu@i{TSsO!MiGMgxe+|WV!3fFgq>K0e8}a zZA>0Ft``q6gveYq%TlhFKVGLX$}_HJ8N%RlZ)5@LI_r>2g6r6^7f~Rs>Rp>+G`slJ;ctLwo(l!P8_%&LjA zA9lR-eeXBDU+?^OXED_G#C-H6>n6j6Z3Xj(-YTH@pHnT=zsm0>#sB~S literal 0 HcmV?d00001 diff --git a/services/__pycache__/torn_api.cpython-311.pyc b/services/__pycache__/torn_api.cpython-311.pyc new file mode 100644 index 0000000000000000000000000000000000000000..29c497b20accdd6b35bf42d8802ecb4fdb9be290 GIT binary patch literal 6504 zcmd^DU2GKB6~41GyF2^;ZyVbpLv3s}aqL2AAqGN>e}WA$DK;T?>~5BwS$pl>+3n02 z2WQ-FMH)Ggr4W?XPD9jvNGK6e>xVw@2#M74IExl#HL4}lDpKjwB8Y@|>bW!fk4aLs zZ=Jbw?%%m*&OP^=bI+YWI2=|47sGePBo{*ez?ITvDi-el3kqw9MJy3VlX^}}5?b9b zX@J}iClk~pMc_U%ZcLaaO$qa)IYCd-&_=PwxFunov=YdGIEpo0CJ?#`kA6+sv{rLn ztDPmn4tSjKxZrWKH0NP0Fy6{}qbAn&7B%T(?VMrGUy{TUOJ;gBLB8zfcx_=%IFp}v=gL&pXuRQKTM z;7b#sp}zj{;S-~w;Q`e(apKg;s)oCGaxmT#<)p}L=u8+>Q3^}qQX?Cd!aW?%CC-JS z;fNGV^4)V{l3!}pI-)|16?IZLtwQP{cO4D3f%4KN0TJG43&J!&8Cix0lBj2W$Ntw)4 zjViMt*-*QHb>k?RngfmWi>2l@8NxxyR%%0tHCFS0hIJANWC3{L`!eWywXE-XLq$J; z+jn!A#*j>9O7N~I0HxZwp9g8>nH#@bGVf_ayHT}1BDH9EgPcH%1c4@CHNKC2-$#mU z+h=U8J2dIl|9u%zkVEL&yk z6Ev~Z;$hh)+tS2pvrKQzFL_GuMo6~Rj*ZpLX=@3rm9^E)-7ednsGps6)N((O)5*H( zIPI+a61D7*Eg4Hi>q<#>)ap;5)!)j*oaSmVSEdT}l~JsR^?dHFeG`GCZ50lgV12Cr z^T1{Jdajng!XKk$r{t(`&6UftMRu|cpEuU>Z;e3$@ivU!EfDJgr`WWVwlZ)HVUNa% zOwl7T2`+Jl6QC|66U=y0;JX;j=>dy0%f$qS6Qx)pEO9JzWK8E88XAiv7bH&T(jW(B6J!kjy z6qV^&YC0@(aZdB9;-R8y9rN6|L!)i@QOqI5S#jp@!VrqsDd)`RhwD1oU`&o4c#??_y3oG1>*B8Uz3+E_(2eWYrtV`a2yP&%=ZqLCt$S#8 zAra;u5r3oTdzT^c?PW}>+_U;?4!ylPH` z1#AtKSX?qLNYQ8agE482k0e<@&0S3vp_*bm3tT~`fOj0#9F8S1a#Tlu9ClY}j1xuJ zb_MKkR1@Bo7ev*V5@NihQg|;GXxu}JlAxNxsT6F;s!4ybYD~=u|QV zJ3a}vP)+&>m57SiP2*3o>Jo4aq&955xI!;wL_bKkad}C|DTqEcnmiypag;%|rtkM1+p3H;q zo>BdLt*CkX@3;MK+lMWeS`=S6rv?q46y2wC6LIp5Ri<9S3whZ-PsG$JNzoYLgsDG zl>>RZ|Bf^8-u%1sAGfVXKHPO_SLR68*_m^8e&u}Tmh%~<>+p47);XAS4z7@Qyn#Gu zfAr$f^;a?zS$|K?-;)n)TYL55tLrnFpJxNXTp*ZlYAINZUMo!3Yh5uF?8p-Mif*|@ zx2z9k>9!o*rf3OtG&*yX|0}Bb7S)^?*l1U%<}9@@N9|LneVZ1?N^ISiSyU`NSxZmO z(u1e}?8fd*+P-SJ(3K&s>`>^gEZvo(yP!}Yp;u$k$UV&b0Fz4FRwZqfw%{@$yL)A? zI0mlav)2Ar@`kbf$aBUUK@XI_a5O{ti%u^tKWFVHEnku(l)p3)xNO$St=9ey^Or#a z=wJ6X9c?0SHc>}g%{QMSfU1-f7Uyd=Q|ykB+sd)h&BTD9q}9=i6vF1E+WpcgE-a* z62bw{Ld0`nbkFSJA`0`o?0d)9Eue$meh{4luY7-Y;CBet)*d^`~}I=td=hlrFE6CcEzi59IZdP z)@rjF3L2LZS_FD>frm&}JJZ)kP`iRmjE9&to=m2gXi~tjY!|Z_j!76Oua`{qx+X{D zB1xVVnKPWU$Zgz}$qxKvbg`=eQIER^{MCID*>=PQ+gUjvaL9*-KFemMy#peb^s}8$e2-g2~u{ zF*QVNdUsuE-k8XG59hpx75ml+K-Pr8HAGa?O}j_&4s7%Sfpi^LAZ6`?Is2gUSOOS6 z#CRMcpa2_zt6?>*`0HCEA$pA-x5^lCcu? z2CwM>0+NQ1Bt0TDV0Eh8QN_jmKOknuYeOf82S*2vPdo`U0^XwlFTN69%0Dq{Amb=E zmr*0U1S55{I7)8`4FO<;6VOqEl*S@b%0fzDIfX@F?q32ag2kkPrR$ctOEGt8V41qT zXHaoYLAp7r=UI9>M^7vCGzQC|taEn`LQHy#l-~}aSIgJ_mYly+hsyNE(JXx^M;`*H z1Ta(rru0kr)}RvHCbVIl@X=ZSHsI7M&BkMA1iVi|c#!0yu^H`bD&X%;zqbTW zw}^K96h?8+I3~w2!A@B?hRI1FDybb-&m@y^eGj0<@t24{P0gIzCnR9ge1LJ`$#tI0s zYvWpWoz=2>5+}@rCv*Cfsf~f`&iw@hwR+;U5gnNy6%b?_d$sJkUen4|gs~H*DHIaXI;py`?TzdL^J=t0puzdhyVZp literal 0 HcmV?d00001 diff --git a/services/torn_api.py b/services/torn_api.py index cfbbd0e..e38fd8c 100644 --- a/services/torn_api.py +++ b/services/torn_api.py @@ -1,6 +1,7 @@ # services/torn_api.py import aiohttp import json +import asyncio from pathlib import Path from config import TORN_API_KEY, ENEMY_FACTION_ID, YOUR_FACTION_ID from .ffscouter import fetch_batch_stats @@ -8,6 +9,13 @@ from .ffscouter import fetch_batch_stats ENEMY_FILE = Path("data/enemy_faction.json") FRIENDLY_FILE = Path("data/friendly_faction.json") +# Track running tasks + current faction IDs +enemy_task = None +friendly_task = None + +current_enemy_id = None +current_friendly_id = None + async def fetch_and_save_faction(faction_id: int, file_path: Path) -> bool: """ @@ -59,10 +67,59 @@ async def fetch_and_save_faction(faction_id: int, file_path: Path) -> bool: return True -# Wrappers for clarity -async def update_enemy_faction() -> bool: - return await fetch_and_save_faction(ENEMY_FACTION_ID, ENEMY_FILE) -async def update_friendly_faction() -> bool: - return await fetch_and_save_faction(YOUR_FACTION_ID, FRIENDLY_FILE) +#Loop for the constant update of members and the stop function + +async def stop_task_if_running(task: asyncio.Task | None): + """Cancel an existing running task safely.""" + if task and not task.done(): + task.cancel() + try: + await task + except asyncio.CancelledError: + pass + +async def faction_loop(faction_id: int, file_path: Path, interval: int): + """ + Runs fetch_and_save_faction() in a loop forever, waiting `interval` + seconds between iterations. + """ + while True: + try: + await fetch_and_save_faction(faction_id, file_path) + except Exception as e: + print(f"Error during faction loop for {faction_id}: {e}") + + await asyncio.sleep(interval) + + + +#Functions to call the loop, maybe add one to just call once? +async def update_enemy_faction(new_faction_id: int, interval: int): + global enemy_task, current_enemy_id + + # If faction ID changes → stop old loop + if new_faction_id != current_enemy_id: + print(f"[ENEMY] Changing faction from {current_enemy_id} → {new_faction_id}") + await stop_task_if_running(enemy_task) + current_enemy_id = new_faction_id + + # Start new loop + enemy_task = asyncio.create_task( + faction_loop(new_faction_id, ENEMY_FILE, interval) + ) + + +async def update_friendly_faction(new_faction_id: int, interval: int): + global friendly_task, current_friendly_id + + if new_faction_id != current_friendly_id: + print(f"[FRIENDLY] Changing faction from {current_friendly_id} → {new_faction_id}") + await stop_task_if_running(friendly_task) + current_friendly_id = new_faction_id + + friendly_task = asyncio.create_task( + faction_loop(new_faction_id, FRIENDLY_FILE, interval) + ) + diff --git a/static/dashboard.js b/static/dashboard.js new file mode 100644 index 0000000..e69de29 diff --git a/static/styles.css b/static/styles.css new file mode 100644 index 0000000..e69de29 diff --git a/templates/dashboard.html b/templates/dashboard.html new file mode 100644 index 0000000..667d65a --- /dev/null +++ b/templates/dashboard.html @@ -0,0 +1,24 @@ + + + + War Dashboard + + + + +

War Dashboard

+ +
+

Enemy Faction

+ +
+ +
+

Friendly Faction

+ +
+ + + + +