107 lines
2.6 KiB
Python
107 lines
2.6 KiB
Python
#!/usr/bin/env python
|
|
|
|
# WS server example that synchronizes state across clients
|
|
|
|
import os
|
|
import asyncio
|
|
import json
|
|
import logging
|
|
import websockets
|
|
import processor
|
|
import random
|
|
import time
|
|
import state
|
|
import tornado.ioloop
|
|
import tornado.web
|
|
|
|
logging.basicConfig()
|
|
|
|
USERS = set()
|
|
|
|
def state_event(state):
|
|
return json.dumps({
|
|
"type": "state",
|
|
"payload": {**state}
|
|
})
|
|
|
|
def options_event():
|
|
return json.dumps({
|
|
"type": "options",
|
|
"payload": {
|
|
**processor.get_options()
|
|
}
|
|
})
|
|
|
|
def users_event():
|
|
return json.dumps({"type": "users", "count": len(USERS)})
|
|
|
|
|
|
async def notify_state(old_state, new_state):
|
|
if USERS: # asyncio.wait doesn't accept an empty list
|
|
message = state_event(new_state)
|
|
await asyncio.wait([user.send(message) for user in USERS])
|
|
|
|
async def notify_users():
|
|
if USERS: # asyncio.wait doesn't accept an empty list
|
|
message = users_event()
|
|
await asyncio.wait([user.send(message) for user in USERS])
|
|
|
|
|
|
async def register(websocket):
|
|
USERS.add(websocket)
|
|
await notify_users()
|
|
|
|
|
|
async def unregister(websocket):
|
|
USERS.remove(websocket)
|
|
await notify_users()
|
|
|
|
|
|
async def ws_handler(websocket, path):
|
|
# register(websocket) sends user_event() to websocket
|
|
await register(websocket)
|
|
try:
|
|
await websocket.send(state_event(state.get_data()))
|
|
await websocket.send(options_event())
|
|
async for message in websocket:
|
|
data = json.loads(message)
|
|
if data["type"] == "mutation":
|
|
asyncio.create_task(state.propagate(data["payload"]))
|
|
else:
|
|
logging.error("unsupported event: {}", data)
|
|
finally:
|
|
await unregister(websocket)
|
|
|
|
async def serve_ws():
|
|
state.register_on_change_callback(notify_state)
|
|
await state.inc_initialized()
|
|
start_server = websockets.serve(ws_handler, "0.0.0.0", 6789)
|
|
await start_server
|
|
|
|
async def tick():
|
|
while True:
|
|
logging.warning("tick")
|
|
await asyncio.sleep(1)
|
|
|
|
async def serve_http():
|
|
settings={
|
|
"static_path": os.path.join(os.path.dirname(__file__), "frontend"),
|
|
"static_url_prefix": "/",
|
|
"static_handler_args": dict(default_filename="index.html")
|
|
}
|
|
app = tornado.web.Application(
|
|
[ (r"/(.*)", tornado.web.StaticFileHandler, dict(path=settings['static_path'], default_filename="index.html")) ],
|
|
**settings)
|
|
app.listen(8888)
|
|
|
|
async def main():
|
|
random.seed(time.time())
|
|
await asyncio.gather(
|
|
tick(),
|
|
serve_ws(),
|
|
serve_http(),
|
|
processor.main(["192.168.178.123", "192.168.178.124"]),
|
|
)
|
|
|
|
asyncio.run(main())
|