Initial commit: Teen Patti live monitor with analytics

Live dashboard with real-time WebSocket updates, analytics page with
time-filtered stats, ClickHouse storage, and Caddy reverse proxy.
This commit is contained in:
2026-02-21 22:36:40 +05:00
commit 85f44e6a22
16 changed files with 3780 additions and 0 deletions

61
app/main.py Normal file
View File

@@ -0,0 +1,61 @@
"""
Entry point — starts all async tasks concurrently:
1. StreamKar WebSocket client (anonymous, captures user bets)
2. Game state HTTP poller (authenticated, captures full game state)
3. aiohttp web server (serves dashboard, pushes events to browsers)
"""
import asyncio
import logging
import signal
from .server import WebServer
from .streamkar_ws import StreamKarWSClient
from .game_poller import GamePoller
logging.basicConfig(
level=logging.INFO,
format="%(asctime)s [%(name)s] %(levelname)s: %(message)s",
datefmt="%H:%M:%S",
)
log = logging.getLogger(__name__)
async def main():
server = WebServer()
ws_client = StreamKarWSClient(broadcast_fn=server.broadcast)
poller = GamePoller(broadcast_fn=server.broadcast, push_refresh_fn=server.push_refresh)
loop = asyncio.get_event_loop()
def shutdown():
log.info("Shutting down...")
ws_client.stop()
poller.stop()
for task in asyncio.all_tasks(loop):
task.cancel()
for sig in (signal.SIGINT, signal.SIGTERM):
loop.add_signal_handler(sig, shutdown)
log.info("Starting Teen Patti Live Monitor")
log.info("Dashboard: http://localhost:8765")
tasks = [
asyncio.create_task(server.run(), name="web_server"),
asyncio.create_task(poller.run(), name="game_poller"),
asyncio.create_task(ws_client.run(), name="ws_client"),
]
try:
await asyncio.gather(*tasks)
except asyncio.CancelledError:
pass
except Exception as e:
log.error("Fatal: %s", e)
finally:
log.info("Stopped.")
if __name__ == "__main__":
asyncio.run(main())