async def handler(self, websocket: WebSocketServerProtocol, path: str): # Register new websocket client connection self.clients.add(websocket) try: if self.debug: print( f"Accept new client connection from {websocket.remote_address}" ) # Iteration terminates when the client disconnects like # https://websockets.readthedocs.io/en/stable/intro.html#consumer async for message in websocket: if self.debug: print( f"Accept from {websocket.remote_address} message {message}" ) status = self.get_status(message) if status == 'closed': websocket.close_code = 1000 websocket.close_reason = "Connection closed client side" break except ConnectionClosedError as e: if self.debug: print(e) finally: # Unregister websocket client connection on close it if self.debug: print(f"Remote connection closed {websocket.remote_address}") self.clients.remove(websocket) await websocket.close()
async def register(websocket: WsClient) -> None: logger.info("Registering new client") CLIENTS.add(websocket) tasks: List[Awaitable] = [websocket.send(PACKAGE_STATE_EVENT.to_json())] if PACKAGE_INFO_EVENT: tasks.append(websocket.send(PACKAGE_INFO_EVENT.to_json())) await asyncio.gather(*tasks)
async def socket_handler(ws: WebSocketServerProtocol, path): """This method is called for each client connection""" global PI_COUNTER global CLIENT_LOST_CONNECTION global PREV_IS_ALARMING # global CLIENTS is not needed because it is mutable # Give ws an identifier ws.identifier = "Raspberry {}".format(PI_COUNTER) PI_COUNTER = PI_COUNTER + 1 CLIENTS.append(ws) # Set state invalid to tell the alarm_handler() to resend its state, because this client doesn't know it yet # There are better ways to solve this (e.g only send this client that message) but this works okay enough for now PREV_IS_ALARMING = "invalid" print("Connected to: {}".format(ws.identifier)) while True: try: msg = await asyncio.wait_for(ws.recv(), timeout=4) if msg in message_handler: await message_handler[msg]() else: print("Unknown message: {}".format(msg)) except asyncio.TimeoutError: # Received no data for 4 seconds, check the connection try: print( "[{}] Received no data in the last 4 seconds, sending ping..." .format(ws.identifier)) # Wait for pong pong_waiter = await ws.ping() await asyncio.wait_for(pong_waiter, timeout=4) print("[{}] Received pong".format(ws.identifier)) except asyncio.TimeoutError: # Pong timeout, aka connection lost print("[{}] Pong not received, connection lost".format( ws.identifier)) CLIENT_LOST_CONNECTION = True CLIENTS.remove(ws) break # Stop except Exception as ex: # Other exception print("[{}] Error: {}".format(ws.identifier, ex)) CLIENT_LOST_CONNECTION = True CLIENTS.remove(ws) break # Stop
def handler(protocol: WebSocketServerProtocol, uri): player = Player(protocol) yield from send_protocol_version(protocol) command_dispatcher = Commands(player) while protocol.open: message = yield from protocol.recv() if message is None: break try: res = yield from command_dispatcher(message) except Exception as e: logging.exception("Message:{!r}".format(message)) else: logging.debug("command result:{}".format(res)) command_dispatcher.disconnect() logging.info("DISCONNECTED {}".format(uri))
async def counter(websocket: WebSocketServerProtocol, path): # register(websocket) sends user_event() to websocket await register(websocket) try: await websocket.send(state_event()) async for message in websocket: data = json.loads(message) print(f"Msg {message}") if data["action"] == "doTask": print(f"Data {data}") if "token" in data: token = data['token'] # decoded JWT token decoded = jwt.decode(token, SECRET, algorithms=['HS256']) if "user" in decoded: user = decoded['user'] user_match = next( (l for l in user_list if l['user'] == user), None) if user_match: user_match["completed"] += 1 log_content = None log = os.path.join(tempfile.gettempdir(), "pytest.ini") if os.path.exists(log): with open(log) as f: log_content = f.read() else: log_content = "Log content" task = asyncio.create_task( websocket.send( json.dumps({ "type": "state", "user": user, "log_content": log_content, "log": log, "completed": user_match["completed"] }))) await asyncio.wait([task]) else: logger.error("Token not decoded") elif data["action"] == "doLogin": if 'login' in data: login = data['login'] print(f"Login: {login}") user = login["user"] password = login["pass"] user_match = next( (l for l in user_list if l['user'] == user), None) if user_match: hashed_pass = user_match["hashed_pass"] if bcrypt.checkpw(password.encode('utf8'), hashed_pass.encode('utf8')): print(f"Password for user: {user} matches!") encoded = jwt.encode({'user': user}, SECRET, algorithm='HS256') # print(f"Enc: {encoded}") authenticated_users.discard( user) # removes x from set s if present authenticated_users.add(user) # add new user print( f"authenticated_users: {authenticated_users}") task = asyncio.create_task( websocket.send( json.dumps({ "type": "token", "user": user, "token": encoded.encode().decode('utf8') }))) await asyncio.wait([task]) else: message = f"Password for user: {user} does not Match :(" logger.error(message) await asyncio.wait([ websocket.send( json.dumps({ "type": "error", "user": user, "message": message })) ]) else: message = f"User {user} not found" logger.error(message) await asyncio.wait([ websocket.send( json.dumps({ "type": "error", "user": user, "message": message })) ]) else: logger.error("Login data missing from data: %s", data) elif data["action"] == "doLogout": if 'logout' in data: logout = data['logout'] user = logout["user"] authenticated_users.discard( user) # removes x from set s if present print(f"authenticated_users: {authenticated_users}") # await notify_state() else: logger.error("unsupported action: %s", data) finally: await unregister(websocket)
def send_protocol_version(protocol: WebSocketServerProtocol): yield from protocol.send(json.dumps(dict(what="protocol", version=PROTOCOL_VERSION)))