#!/usr/bin/env python import asyncio from websockets.server import serve adminId = "1234" BOAT_STATE_INCTRL = 1 BOAT_STATE_AVAILABLE = 0 BOAT_STATE_LOCKED = -1 boats = [] clients = [] async def echo_boats(client): """echo list of all not locked boats to client""" global boats data = "boats:" for boat in boats: if boat['state'] != BOAT_STATE_LOCKED: data += str(boat['id']) + ";" + str(boat['name']) + ";" if boat["state"] == BOAT_STATE_AVAILABLE: data += 'available:' elif boat["state"] == BOAT_STATE_INCTRL: data += 'inctrl:' await client['ws'].send(data) async def echo_locked_boats(client): """echo list of all locked boats to client""" global boats if client['id'] == adminId: data = "lockedBoats:" for boat in boats: if boat['state'] == BOAT_STATE_LOCKED: data += str(boat['id']) + ";" + str(boat['name']) + ";locked:" await client['ws'].send(data + '\n') async def echo_clients(client): """echo list of all clients to client""" if client['id'] == adminId: data = "clients:" for client in clients: data += str(client['id']) + ";" + str(client['boat']) + ";" + str(client['state']) + ":" await client['ws'].send(data + '\n') async def take_controll(client, boat): """let a client take controll a boat""" if client['boat'] is not None: client['boat']["state"] = BOAT_STATE_AVAILABLE client["boat"] = None for b in boats: if b['id'] == boat: if b['state'] == BOAT_STATE_AVAILABLE: b["state"] = BOAT_STATE_INCTRL print("take controll: " + str(client["id"]) + " -> " + b["name"]) client["boat"] = b await client['ws'].send("OK") return else: break await client['ws'].send("FAIL") async def free_boat(boat): """make boat available for next client""" for client in clients: if client["boat"]['id'] == boat: client["boat"] = None break for b in boats: if b['id'] == boat: if boat['state'] == BOAT_STATE_INCTRL: boat["state"] = BOAT_STATE_AVAILABLE break async def lock_boat(boat): """lock a boat so client can't take controll over it""" for client in clients: if client["boat"]['id'] == boat: client["boat"] = None break for b in boats: if b['id'] == int(boat): boat["state"] = BOAT_STATE_LOCKED break async def on_message(message, client): """handel for client messages""" data = message.replace('\n', '').split(';') if data[0] != client["id"]: print("invalid id: " + str(data[0]) + " != " + str(client["id"])) else: if data[1] == "boats": await echo_boats(client) elif data[1] == "ctrl": await take_controll(client, data[2]) elif data[1] == "end": await take_controll(client, -1) elif data[1] == "free": if client["id"] == adminId: await free_boat(data[2]) elif data[1] == "lock": if client["id"] == adminId: await lock_boat(data[2]) elif data[1] == "locked": await echo_locked_boats(client) elif data[1] == "kick": print("kick") elif data[1] == "clients": await echo_clients(client) elif data[1] == "d": if client['boat'] is None: print("WARN: controll cmd (" + client['id'] + ") to None: " + data[2]) else: print("INFO: controll cmd (" + client['id'] + ") to " + client['boat']['name'] + ": " + data[2]) await client['boat']['ws'].send("d:" + data[2] + "\n") else: print("WARN: invalid command (" + client['id'] + "): '" + data[1] + "'") async def new_client(clientId, ws): """handler for every new client connection""" client = { "id": clientId, "boat": None, "ws": ws, "state": "active" } print("new client connected: " + client['id']) for clie in clients: if clie['id'] == client['id']: clie['state'] = 'terminated' clients.append(client) if client['id'] == adminId: await echo_boats(client) await echo_locked_boats(client) await echo_clients(client) return client async def new_boat(boatId, name, ws): """handler for every new boat connection""" boat = { "id": boatId, "name": name, "ws": ws, "state": BOAT_STATE_AVAILABLE } print("new boat connected: " + boatId) for bo in boats: if bo['id'] == boat['id']: bo['state'] = 'terminated' boats.append(boat) return boat async def run(ws, path): """hadeler for every new websocket connection""" client = None async for message in ws: message = message.split(';') if len(message) == 3 and message[1] == "4675": client = await new_client(message[0], ws) if client is not None: async for message in ws: if client['state'] == 'active': await on_message(message, client) else: break break elif (len(message) == 3 and message[1] == "3440"): client = await new_boat(message[0], message[2], ws) if client is not None: async for message in ws: print("boat" + client['id'] + " says " + message) break async def main(): """main""" async with serve(run, "0.0.0.0", 8080): await asyncio.Future() asyncio.run(main())