mirror of
https://github.com/dcs-retribution/dcs-retribution.git
synced 2025-11-10 15:41:24 +00:00
Add websocket event stream for sim updates.
As a proof of concept this only covers the flight positions.
This commit is contained in:
@@ -1,2 +1,3 @@
|
||||
from .dependencies import GameContext
|
||||
from .eventstream import EventStream
|
||||
from .server import Server
|
||||
|
||||
@@ -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)
|
||||
|
||||
2
game/server/eventstream/__init__.py
Normal file
2
game/server/eventstream/__init__.py
Normal file
@@ -0,0 +1,2 @@
|
||||
from .eventstream import EventStream
|
||||
from .routes import router
|
||||
29
game/server/eventstream/eventstream.py
Normal file
29
game/server/eventstream/eventstream.py
Normal 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
|
||||
25
game/server/eventstream/models.py
Normal file
25
game/server/eventstream/models.py
Normal 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
|
||||
}
|
||||
)
|
||||
21
game/server/eventstream/routes.py
Normal file
21
game/server/eventstream/routes.py
Normal 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())
|
||||
)
|
||||
)
|
||||
Reference in New Issue
Block a user