Add websocket event stream for sim updates.

As a proof of concept this only covers the flight positions.
This commit is contained in:
Dan Albert
2022-02-16 01:28:10 -08:00
parent 350f08be2f
commit 21f7912458
14 changed files with 150 additions and 15 deletions

View File

@@ -1,2 +1,3 @@
from .dependencies import GameContext
from .eventstream import EventStream
from .server import Server

View File

@@ -1,6 +1,7 @@
from fastapi import FastAPI
from . import debuggeometries
from . import debuggeometries, eventstream
app = FastAPI()
app.include_router(debuggeometries.router)
app.include_router(eventstream.router)

View File

@@ -0,0 +1,2 @@
from .eventstream import EventStream
from .routes import router

View File

@@ -0,0 +1,29 @@
from asyncio import Queue
from game.sim.gameupdateevents import GameUpdateEvents
class EventStream:
_queue: Queue[GameUpdateEvents] = Queue()
@classmethod
def drain(cls) -> None:
while not cls._queue.empty():
cls._queue.get_nowait()
cls._queue.task_done()
@classmethod
async def put(cls, events: GameUpdateEvents) -> None:
await cls._queue.put(events)
@classmethod
def put_nowait(cls, events: GameUpdateEvents) -> None:
# The queue has infinite size so this should never need to block anyway. If for
# some reason the queue is full this will throw QueueFull.
cls._queue.put_nowait(events)
@classmethod
async def get(cls) -> GameUpdateEvents:
events = await cls._queue.get()
cls._queue.task_done()
return events

View File

@@ -0,0 +1,25 @@
from __future__ import annotations
from typing import TYPE_CHECKING
from uuid import UUID
from pydantic import BaseModel
from game.server.leaflet import LeafletLatLon
if TYPE_CHECKING:
from game import Game
from game.sim.gameupdateevents import GameUpdateEvents
class GameUpdateEventsJs(BaseModel):
updated_flights: dict[UUID, LeafletLatLon]
@classmethod
def from_events(cls, events: GameUpdateEvents, game: Game) -> GameUpdateEventsJs:
return GameUpdateEventsJs(
updated_flights={
f[0].id: game.theater.point_to_ll(f[1]).as_list()
for f in events.updated_flights
}
)

View File

@@ -0,0 +1,21 @@
from fastapi import APIRouter
from fastapi.encoders import jsonable_encoder
from starlette.websockets import WebSocket
from .eventstream import EventStream
from .models import GameUpdateEventsJs
from .. import GameContext
router = APIRouter()
@router.websocket("/eventstream")
async def event_stream(websocket: WebSocket) -> None:
await websocket.accept()
while True:
if not (events := await EventStream.get()).empty:
await websocket.send_json(
jsonable_encoder(
GameUpdateEventsJs.from_events(events, GameContext.get())
)
)