#!/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 = [] def onCMD(data): global boats, adminId print("command:" + str(data)) if (len(data) != 4): return if (data[1] != adminId): return boot = int(data[2]) if (boot >= 0 and boot <= 3): boats[boot] = data[3] print(boats) def sendData(data): global boats print("data to send: " + str(data)) async def echoBoats(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 echoLockedBoats(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 echoClients(client): global clients 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 takeControll(client, boat): global boats 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 freeBoat(boat): global boats, clients 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 lockBoat(boat): global boats, clients 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 onMessage(message, client): global boats 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 echoBoats(client) elif(data[1] == "ctrl"): await takeControll(client, data[2]) elif(data[1] == "end"): await takeControll(client, -1) elif(data[1] == "free"): if (client["id"] == adminId): await freeBoat(data[2]) elif(data[1] == "lock"): if (client["id"] == adminId): await lockBoat(data[2]) elif(data[1] == "locked"): await echoLockedBoats(client) elif(data[1] == "kick"): print("kick") elif(data[1] == "clients"): await echoClients(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 newClient(clientId, ws): 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 echoBoats(client) await echoLockedBoats(client) await echoClients(client) return client async def newBoat(boatId, name, ws): 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): client = None async for message in ws: message = message.split(';') if (len(message) == 3 and message[1] == "4675"): client = await newClient(message[0], ws) if (client is not None): break elif (len(message) == 3 and message[1] == "3440"): client = await newBoat(message[0], message[2], ws) if (client is not None): break async for message in ws: if (client['state'] == 'active'): await onMessage(message, client) else: break async def main(): async with serve(run, "0.0.0.0", 8080): await asyncio.Future() asyncio.run(main())