90 lines
2.6 KiB
Python
Executable File
90 lines
2.6 KiB
Python
Executable File
#!/usr/bin/env python
|
|
|
|
import asyncio
|
|
import json
|
|
import websockets
|
|
|
|
|
|
def log_message_error(error, message_text):
|
|
print(f"[E] {error}")
|
|
print(f" Message: {message_text}")
|
|
|
|
|
|
async def parse_client_message(websocket, message_text):
|
|
"""Parse a message (JSON object) from a client."""
|
|
|
|
try:
|
|
# Parse JSON
|
|
message = json.loads(message_text)
|
|
|
|
# Handle message types
|
|
if message['action'] == 'init':
|
|
await handle_client_init(websocket, message)
|
|
else:
|
|
log_message_error(f"Unknown action '{message['action']}'", message_text)
|
|
except json.decoder.JSONDecodeError as e:
|
|
log_message_error(f"JSON decode error: {e}", message_text)
|
|
except KeyError as e:
|
|
log_message_error(f"Missing key {e} in JSON message", message_text)
|
|
|
|
|
|
async def handle_client_init(websocket, message):
|
|
"""Handle client 'init' message."""
|
|
|
|
# TODO input check for nickname
|
|
|
|
print(f"< init: chat_id='{message['chat_id']}', nickname='{message['nickname']}'")
|
|
await send_client_init_response(websocket)
|
|
await send_client_previous_messages(websocket)
|
|
|
|
|
|
async def send_client_init_response(websocket):
|
|
"""Send an init response message to a newly connected client."""
|
|
|
|
response = json.dumps({
|
|
"type": "init"
|
|
})
|
|
print(f"> {response}")
|
|
await websocket.send(response)
|
|
|
|
|
|
async def send_client_previous_messages(websocket):
|
|
"""Sends previously written chat messages to a newly connected client."""
|
|
|
|
# For now: send test messages
|
|
for i in range(1, 4):
|
|
testmsg = json.dumps({
|
|
"type": "message",
|
|
"from": "Alice",
|
|
"text": f"Message number {i}, hello!"
|
|
})
|
|
print(f"> {testmsg}")
|
|
await websocket.send(testmsg)
|
|
|
|
|
|
async def client_handler(websocket, path):
|
|
"""Handle client connection."""
|
|
|
|
print(f"++ New client {websocket.remote_address}")
|
|
try:
|
|
# Read and parse messages until connection is closed
|
|
async for message_text in websocket:
|
|
await parse_client_message(websocket, message_text)
|
|
except websockets.exceptions.ConnectionClosed:
|
|
# Ignore ConnectionClosed exceptions because we handle this in finally
|
|
pass
|
|
finally:
|
|
print(f"-- Client connection closed {websocket.remote_address}")
|
|
|
|
# Create WebSocket listener
|
|
start_server = websockets.serve(client_handler, '0.0.0.0', 32715)
|
|
|
|
try:
|
|
asyncio.get_event_loop().run_until_complete(start_server)
|
|
asyncio.get_event_loop().run_forever()
|
|
except KeyboardInterrupt:
|
|
print("[received SIGINT]")
|
|
pass
|
|
finally:
|
|
print("Exiting...")
|