From 3f28a10b16082887ba11918c32857037914d2a6a Mon Sep 17 00:00:00 2001 From: "Waylon S. Walker" Date: Wed, 14 Jun 2023 13:43:06 -0500 Subject: [PATCH] wip --- client.py | 12 ++- client_sender.py | 6 +- learn_sql_model/api/app.py | 33 +++++--- learn_sql_model/api/websocket.py | 126 +++++++++++-------------------- learn_sql_model/cli/dashboard.py | 32 +++++--- 5 files changed, 98 insertions(+), 111 deletions(-) diff --git a/client.py b/client.py index 7437da2..1866c2d 100644 --- a/client.py +++ b/client.py @@ -3,12 +3,15 @@ import time from rich.console import Console from websocket import create_connection -from learn_sql_model.models.hero import Hero +from learn_sql_model.config import get_config +from learn_sql_model.models.hero import Heros + +config = get_config() def connect(): - id = 1 - url = f"ws://localhost:5000/ws/{id}" + url = f"ws://{config.api_client.url.replace('https://', '')}/ws/heros" + # url = f"ws://localhost:5000/ws/heros" Console().log(f"connecting to: {url}") ws = create_connection(url) Console().log(f"connected to: {url}") @@ -23,7 +26,8 @@ def watch(ws): try: data.append(ws.recv()) if data[-1].startswith("{"): - Console().log(Hero.parse_raw(data[-1])) + # Console().log(data[-1]) + Console().log(Heros.parse_raw(data[-1])) else: Console().log(data[-1]) except Exception as e: diff --git a/client_sender.py b/client_sender.py index 7809f4c..21c07db 100644 --- a/client_sender.py +++ b/client_sender.py @@ -3,8 +3,10 @@ import time from rich.console import Console from websocket import create_connection -id = 1 -url = f"ws://localhost:5000/ws/{id}" +from learn_sql_model.config import get_config + +config = get_config() +url = f"ws://{config.api_client.url.replace('https://', '')}/ws/heros" Console().log(f"connecting to: {url}") ws = create_connection(url) diff --git a/learn_sql_model/api/app.py b/learn_sql_model/api/app.py index 5d82280..7e3b5a8 100644 --- a/learn_sql_model/api/app.py +++ b/learn_sql_model/api/app.py @@ -1,25 +1,38 @@ from fastapi import FastAPI +from fastapi.responses import HTMLResponse from learn_sql_model.api.hero import hero_router from learn_sql_model.api.user import user_router from learn_sql_model.api.websocket import web_socket_router -# from fastapi_socketio import SocketManager - - app = FastAPI() -# socket_manager = SocketManager(app=app) app.include_router(hero_router) app.include_router(user_router) app.include_router(web_socket_router) -# @app.sio.on("join") -# def handle_join(sid, *args, **kwargs): -# app.sio.emit("lobby", "User joined") +html = """ + + + + Learn SQL Model + + +

Learn SQL Model

+

Join the game with the following command. +

+

+ pipx run --spec git+https://github.com/WaylonWalker/learn-sql-model lsm game run +

+

+ You can watch player data at watch +

+ + +""" -# @app.sio.on("leave") -# def handle_leave(sid, *args, **kwargs): -# sm.emit("lobby", "User left") +@app.get("/") +async def get(): + return HTMLResponse(html) diff --git a/learn_sql_model/api/websocket.py b/learn_sql_model/api/websocket.py index a066176..962399c 100644 --- a/learn_sql_model/api/websocket.py +++ b/learn_sql_model/api/websocket.py @@ -1,16 +1,13 @@ -from contextlib import contextmanager - from fastapi import APIRouter, Depends, WebSocket, WebSocketDisconnect from fastapi.responses import HTMLResponse -from sqlalchemy import create_engine -from sqlalchemy.orm import scoped_session, sessionmaker +from rich.console import Console from sqlmodel import Session from websockets.exceptions import ConnectionClosed from learn_sql_model.api.websocket_connection_manager import manager -from learn_sql_model.config import get_config, get_session +from learn_sql_model.config import get_session from learn_sql_model.console import console -from learn_sql_model.models.hero import HeroUpdate, Heros +from learn_sql_model.models.hero import HeroDelete, HeroUpdate, Heros web_socket_router = APIRouter() @@ -21,28 +18,15 @@ html = """ Chat -

WebSocket Chat

-
- - -
- +

Heros Stream

+ + @@ -54,18 +38,24 @@ async def get(): return HTMLResponse(html) -@web_socket_router.websocket("/ws/{id}") -async def websocket_endpoint_connect(websocket: WebSocket, id: int): - await manager.connect(websocket, id) +@web_socket_router.websocket("/ws/{channel}") +async def websocket_endpoint_connect( + websocket: WebSocket, + channel: str, + session: Session = Depends(get_session), +): + Console().log(f"Client #{id} connecting") + await manager.connect(websocket, channel) + heros = Heros.list(session=session) + await websocket.send_text(heros.json()) + try: while True: - data = await websocket.receive_text() - await websocket.send_text(f"[gold]You Said: {data}") - await manager.broadcast(f"[blue]USER: {data}", id) + await websocket.receive_text() except WebSocketDisconnect: manager.disconnect(websocket, id) - await manager.broadcast(f"Client #{id} left the chat", id) + await manager.broadcast(f"Client #{channel} left the chat", channel) @web_socket_router.websocket("/ws") @@ -81,71 +71,39 @@ async def websocket_endpoint(websocket: WebSocket): await manager.broadcast(f"Client #{id} left the chat", id) -@contextmanager -def db_session(db_url): - """Creates a context with an open SQLAlchemy session.""" - engine = create_engine(db_url, convert_unicode=True) - connection = engine.connect() - db_session = scoped_session( - sessionmaker(autocommit=False, autoflush=True, bind=engine) - ) - yield db_session - db_session.close() - connection.close() - - @web_socket_router.websocket("/wsecho") async def websocket_endpoint_hero_echo( websocket: WebSocket, session: Session = Depends(get_session), ): - config = get_config() await websocket.accept() last_heros = None - try: - with config.database.engine.connect() as con: - while True: - data = await websocket.receive_text() - hero = HeroUpdate.parse_raw(data) - # heros = con.execute("SELECT * FROM hero").fetchall() - # heros = Heros.parse_obj({"heros": heros}) - heros = Heros.list(session=session) - if heros != last_heros: - await manager.broadcast(heros.json(), "heros") - last_heros = heros - hero.update(session=session) - console.print(heros) - await websocket.send_text(heros.json()) - - except WebSocketDisconnect: - print("disconnected") - except ConnectionClosed: - print("connection closed") - - -@web_socket_router.websocket("/ws-heros'") -async def websocket_endpoint_heros( - websocket: WebSocket, - session: Session = Depends(get_session), -): - await manager.connect(websocket, "heros") - await websocket.accept() - try: while True: - ... - # data = await websocket.receive_text() - # hero = HeroUpdate.parse_raw(data) - # heros = con.execute("SELECT * FROM hero").fetchall() - # heros = Heros.parse_obj({"heros": heros}) - # hero.update(session=session) - # console.print(heros) - # await websocket.send_text(heros.json()) + data = await websocket.receive_text() + hero = HeroUpdate.parse_raw(data) + heros = Heros.list(session=session) + if heros != last_heros: + await manager.broadcast(heros.json(), "heros") + last_heros = heros + hero.update(session=session) + console.print(heros) + await websocket.send_text(heros.json()) except WebSocketDisconnect: + try: + HeroDelete(id=hero.id).delete(session=session) + except Exception: + ... + heros = Heros.list(session=session) + await manager.broadcast(heros.json(), "heros") print("disconnected") - manager.disconnect(websocket, "heros") except ConnectionClosed: - manager.disconnect(websocket, "heros") + try: + HeroDelete(id=hero.id).delete(session=session) + except Exception: + ... + heros = Heros.list(session=session) + await manager.broadcast(heros.json(), "heros") print("connection closed") diff --git a/learn_sql_model/cli/dashboard.py b/learn_sql_model/cli/dashboard.py index f9d925e..cb3f53b 100644 --- a/learn_sql_model/cli/dashboard.py +++ b/learn_sql_model/cli/dashboard.py @@ -2,9 +2,9 @@ from textual.app import App, ComposeResult from textual.containers import ScrollableContainer from textual.widgets import Footer, Header, Static import typer +from websocket import create_connection from learn_sql_model.cli.common import verbose_callback -from learn_sql_model.models.hero import Heros dashboard_app = typer.Typer() @@ -24,16 +24,8 @@ class HeroName(Static): """A stopwatch widget.""" -class DashboardApp(App): - """A Textual app to manage stopwatches.""" - - BINDINGS = [("d", "toggle_dark", "Toggle dark mode")] - - def compose(self) -> ComposeResult: - """Create child widgets for the app.""" - yield Header() - yield Footer() - yield ScrollableContainer(*[HeroName(hero.name) for hero in Heros.list().heros]) +class HerosDisplay(Static): + """A stopwatch widget.""" @property def ws(self): @@ -48,6 +40,24 @@ class DashboardApp(App): connect() return self._ws + def compose(self) -> ComposeResult: + """Create child widgets of a stopwatch.""" + for hero in self.heros: + yield HeroName(hero.name) + + +class DashboardApp(App): + """A Textual app to manage stopwatches.""" + + BINDINGS = [("d", "toggle_dark", "Toggle dark mode")] + # heros = reactive(Heros.list()) + + def compose(self) -> ComposeResult: + """Create child widgets for the app.""" + yield Header() + yield Footer() + yield ScrollableContainer(HerosDisplay()) + def action_toggle_dark(self) -> None: """An action to toggle dark mode.""" self.dark = not self.dark