115 lines
2.4 KiB
Python
115 lines
2.4 KiB
Python
import asyncio
|
|
from collections import deque
|
|
from json import dumps
|
|
from logging import getLogger
|
|
from threading import Thread
|
|
|
|
import websockets
|
|
|
|
from adventure.models import Actor, Room, World
|
|
from adventure.state import snapshot_world, world_json
|
|
|
|
logger = getLogger(__name__)
|
|
|
|
connected = set()
|
|
recent_events = deque(maxlen=10)
|
|
recent_world = None
|
|
|
|
|
|
async def handler(websocket):
|
|
logger.info("Client connected")
|
|
connected.add(websocket)
|
|
|
|
try:
|
|
if recent_world:
|
|
await websocket.send(recent_world)
|
|
|
|
for message in recent_events:
|
|
await websocket.send(message)
|
|
except Exception:
|
|
logger.exception("Failed to send recent messages to new client")
|
|
|
|
while True:
|
|
try:
|
|
message = await websocket.recv()
|
|
print(message)
|
|
except websockets.ConnectionClosedOK:
|
|
break
|
|
|
|
connected.remove(websocket)
|
|
logger.info("Client disconnected")
|
|
|
|
|
|
socket_thread = None
|
|
static_thread = None
|
|
|
|
|
|
def server_json(obj):
|
|
if isinstance(obj, Actor):
|
|
return obj.name
|
|
|
|
if isinstance(obj, Room):
|
|
return obj.name
|
|
|
|
return world_json(obj)
|
|
|
|
|
|
def send_and_append(message):
|
|
json_message = dumps(message, default=server_json)
|
|
recent_events.append(json_message)
|
|
websockets.broadcast(connected, json_message)
|
|
return json_message
|
|
|
|
|
|
def launch_server():
|
|
global socket_thread, static_thread
|
|
|
|
def run_sockets():
|
|
asyncio.run(server_main())
|
|
|
|
socket_thread = Thread(target=run_sockets)
|
|
socket_thread.start()
|
|
|
|
|
|
async def server_main():
|
|
async with websockets.serve(handler, "", 8001):
|
|
logger.info("Server started")
|
|
await asyncio.Future() # run forever
|
|
|
|
|
|
def server_system(world: World, step: int):
|
|
global recent_world
|
|
json_state = {
|
|
**snapshot_world(world, step),
|
|
"type": "world",
|
|
}
|
|
recent_world = send_and_append(json_state)
|
|
|
|
|
|
def server_result(room: Room, actor: Actor, action: str):
|
|
json_action = {
|
|
"actor": actor,
|
|
"result": action,
|
|
"room": room,
|
|
"type": "result",
|
|
}
|
|
send_and_append(json_action)
|
|
|
|
|
|
def server_action(room: Room, actor: Actor, message: str):
|
|
json_input = {
|
|
"actor": actor,
|
|
"input": message,
|
|
"room": room,
|
|
"type": "action",
|
|
}
|
|
send_and_append(json_input)
|
|
|
|
|
|
def server_event(message: str):
|
|
json_broadcast = {
|
|
"message": message,
|
|
"type": "event",
|
|
}
|
|
send_and_append(json_broadcast)
|