This commit is contained in:
Waylon Walker 2023-06-14 13:43:06 -05:00
parent 892a3c9a8a
commit 3f28a10b16
No known key found for this signature in database
GPG key ID: 66E2BF2B4190EFE4
5 changed files with 98 additions and 111 deletions

View file

@ -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:

View file

@ -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)

View file

@ -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 = """
<!DOCTYPE html>
<html>
<head>
<title>Learn SQL Model</title>
</head>
<body>
<h1>Learn SQL Model</h1>
<p>Join the game with the following command.
</p>
<p>
pipx run --spec git+https://github.com/WaylonWalker/learn-sql-model lsm game run
</p>
<p>
You can watch player data at <a href='/watch'>watch</a>
</p>
</body>
</html>
"""
# @app.sio.on("leave")
# def handle_leave(sid, *args, **kwargs):
# sm.emit("lobby", "User left")
@app.get("/")
async def get():
return HTMLResponse(html)

View file

@ -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 = """
<title>Chat</title>
</head>
<body>
<h1>WebSocket Chat</h1>
<form action="" onsubmit="sendMessage(event)">
<input type="text" id="messageText" autocomplete="off"/>
<button>Send</button>
</form>
<ul id='messages'>
</ul>
<h1>Heros Stream</h1>
<code id='messages'>
</code>
<script>
var ws = new WebSocket("ws://localhost:5000/ws");
var ws = new WebSocket("wss://learn-sql-model.fly.dev/ws/heros");
ws.onmessage = function(event) {
var messages = document.getElementById('messages')
var message = document.createElement('li')
var content = document.createTextNode(event.data)
message.appendChild(content)
messages.appendChild(message)
messages.innerHTML = event.data
};
function sendMessage(event) {
var input = document.getElementById("messageText")
ws.send(input.value)
input.value = ''
event.preventDefault()
}
</script>
</body>
</html>
@ -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,35 +71,18 @@ 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")
@ -119,33 +92,18 @@ async def websocket_endpoint_hero_echo(
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:
HeroDelete(id=hero.id).delete(session=session)
except Exception:
...
# 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())
except WebSocketDisconnect:
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")

View file

@ -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