def receive_from_client(self, addr): try: msgs, e = recv_data(self.conns_to_clients[addr], addr) for msg in msgs: if msg['type'] == 'error_msg': warnings.warn('Пришло сообщение об ошибке от игрока {}\n' 'Сообщение:\n'.format(addr) + msg['msg']) elif msg['type'] == 'event': self.players_scenarios[addr].process_event( addr, msg['event']) else: warning_msg = "Сообщение неизвестного типа {} пришло "\ "от игрока {}.".format(repr(msg['type']), repr(addr)) warnings.warn(warning_msg) msg = { 'type': 'error_msg', 'error_class': 'ValueError', 'addr': addr, 'msg': warning_msg, 'event': msg['event'], } send_data_quite(self.conns_to_clients[addr], addr, msg) if e is not None: raise e except CorruptedMessageError as e: warnings.warn(e.message) except BlockingIOError: pass except ConnectionResetError as e: warnings.warn(e) warnings.warn(CONNECTION_RESET_ERROR_WARNING_TMPL.format(addr)) # FIXME # Непонятно когда возникает ошибка и потому не ясно следует ли # закрывать и удалять socket. self.conns_to_clients[addr].close() del self.conns_to_clients[addr] del self.players_scenarios[addr] self.main_frame.cube_canvas.release_player_cube(addr) except ConnectionAbortedError as e: warnings.warn(e) warnings.warn(CONNECTION_ABORTED_ERROR_WARNING_TMPL.format(addr)) # FIXME # Неустановлено, в каких случаях возникает эта ошибка. # Она наблюдалась при выключении клиента, тогда закрытие и # удаление сокета -- правильное рещение. Однако, я наблюдал эту же # ошибку временном отключении wifi. В последнем случаем удаление # сокета приводит к необходимости перезапуска клиентской части # приложения. self.conns_to_clients[addr].close() del self.conns_to_clients[addr] del self.players_scenarios[addr] self.main_frame.cube_canvas.release_player_cube(addr) except Exception as e: warnings.warn(e) warnings.warn( "Для исключения типа {} не был написан обработчик. Возможно, " "стоит это сделать.".format(type(e)))
def b1_motion(self, event): conn = self.get_root().conn_to_server msg = { 'type': 'event', 'event': { 'type': '<B1-Motion>', 'x': event.x, 'y': event.y } } send_data_quite(conn, self.server_addr, msg)
def button_release_1(self, event): conn = self.get_root().conn_to_server msg = { 'type': 'event', 'event': { 'type': '<ButtonRelease-1>', 'x': event.x, 'y': event.y } } send_data_quite(conn, self.server_addr, msg)
def warn_events_before_init(self, addr, event): warning_msg = "На сервер от игрока {} пришло сообщение до " \ "инициализации этого игрока.\nevent = {}".format(repr(addr), event) warnings.warn(warning_msg) msg = { 'type': 'error_msg', 'error_class': 'ValueError', 'addr': addr, 'msg': warning_msg, 'event': event, } send_data_quite(self.conns_to_clients[addr], addr, msg)
def button_1(self, event): conn = self.cube_canvas.get_root().conn_to_server msg = { 'type': 'event', 'event': { 'type': '<Button-1>', 'id': self.server_id, 'x': event.x, 'y': event.y } } send_data_quite(conn, self.server_addr, msg)
def init_player(self, addr): cubes = self.main_frame.cube_canvas.cubes for cube in cubes.values(): msg = { 'type': 'command', 'command': { "type": 'add_cube', "id": cube.id, "x": cube.x, "y": cube.y, "size": cube.size, "color": cube.color } } send_data_quite(self.conns_to_clients[addr], addr, msg) msg = {'type': 'command', 'command': {"type": 'bind_all'}} send_data_quite(self.conns_to_clients[addr], addr, msg)
def receive_from_server(self): try: msgs, e = recv_data(self.conn_to_server, self.server_addr) for msg in msgs: if msg['type'] == 'error_msg': warnings.warn( 'Пришло сообщение об ошибке от сервера\n' 'Сообщение:\n' + msg['msg'] ) elif msg['type'] == 'command': self.main_frame.process_server_command(msg['command']) else: warning_msg = "Сообщение неизвестного типа {} " \ "пришло от сервера.".format(repr(msg['type'])) warnings.warn(warning_msg) msg = { 'type': 'error_msg', 'error_class': 'ValueError', 'msg': warning_msg, 'event': msg['event'], } send_data_quite( self.get_root().conn_to_server, self.server_addr, msg) if e is not None: raise e except CorruptedMessageError as e: warnings.warn(e.message) except BlockingIOError: pass except ConnectionRefusedError as e: # Вероятно, сервер не запущен warnings.warn(e) except ConnectionResetError as e: self.conn_to_server.close() self.receive_from_server_job = None warnings.warn(e) return except OSError as e: warnings.warn(e) self.receive_from_server_job = self.after( DT_MS, self.receive_from_server)
def are_x_and_y_ok(self, addr, event): ok = not self.is_coord_missing(addr, event) if not (self.x <= event['x'] <= self.x + self.size and self.y <= event['y'] <= self.y + self.size): ok = False warning_msg = "У кубика с id {} разные координаты или размер " \ "в клиентской и серверной частях программы. В результате " \ "мышка не попадает по кубику из серверной части программы. " \ "Захват кубика не будет осуществлен.".format(self.id) warnings.warn(warning_msg) conn = self.cube_canvas.get_root().conns_to_clients[addr] msg = { 'type': 'error_msg', 'error_class': 'ValueError', 'addr': addr, 'msg': warning_msg, 'event': event, 'cube_coords_on_server': (self.x, self.y), 'cube_size_on_server': self.size } send_data_quite(conn, addr, msg) return ok
def is_coord_missing(self, addr, event): missing_coords = [] if 'x' not in event: missing_coords.append('x') if 'y' not in event: missing_coords.append('y') if missing_coords: warning_msg = "В описании события не хватает {}." \ "Захват кубика не будет осуществлен.".format( ' и '.join(map(repr, missing_coords)) ) warnings.warn(warning_msg) conn = self.cube_canvas.get_root().conns_to_clients[addr] msg = { 'type': 'error_msg', 'error_class': 'ValueError', 'addr': addr, 'msg': warning_msg, 'event': event } send_data_quite(conn, addr, msg) return bool(missing_coords)
def send_to_all_players(self, msg): for addr, conn in self.conns_to_clients.items(): send_data_quite(conn, addr, msg)
def is_id_address_eventtype_ok(self, addr, event): ok = True conn = self.get_root().conns_to_clients[addr] oblig_part = { 'type': 'error_msg', 'error_class': 'ValueError', 'addr': addr, 'event': event } if event['type'] == '<Button-1>': if 'id' not in event: ok = False warning_msg = "Без ключа 'id' могут быть только словари " \ "с описаниями событий типа <ButtonRelease-1> и " \ "<B1-Motion>. В то время как у данного события тип " \ "{}".format(event['type']) warnings.warn(warning_msg) msg = dict(**oblig_part, msg=warning_msg) send_data_quite(conn, addr, msg) if 'id' in event and addr in self.grabbed_cubes_ids: ok = False warning_msg = "Игрок {} не может схватить кубик с id " \ "{}, пока не отпустит кубик с id {}. Вероятно, или в " \ "или в серверной части программы ошибка. Такие ситуации " \ "не должны возникать".format( addr, event['id'], self.grabbed_cubes_ids[addr] ) warnings.warn(warning_msg) msg = dict(**oblig_part, msg=warning_msg, grabbed_id=self.grabbed_cubes_ids[addr]) send_data_quite(conn, addr, msg) if 'id' in event and event['id'] not in self.cubes: ok = False present_ids = list(self.cubes.keys()) warning_msg = "В canvas нет элемента с id {}. Или в " \ "клиентской, или в серверной части программы ошибка. \n" \ "id в наличии: {}\n".format(event['id'], present_ids) warnings.warn(warning_msg) msg = dict(**oblig_part, msg=warning_msg) send_data_quite(conn, addr, msg) elif event['type'] in ['<ButtonRelease-1>', '<B1-Motion>']: if 'id' in event: ok = False warning_msg = "Ключ id может быть только в словарях с " \ "описаниями событий типа <Button-1>. В то время как" \ "у данного события тип {}. Вероятно, в клиентской " \ "части программы неправильно реализовано составление " \ "сообщений данного типа".format(event['type']) warnings.warn(warning_msg) msg = dict(**oblig_part, msg=warning_msg) send_data_quite(conn, addr, msg) if addr not in self.grabbed_cubes_ids: ok = False warning_msg = "Адрес клиента, отправившего описание события " \ "типа <ButtonRelease-1> или <B1-Motion>, должен быть " \ "ключом словаря `self.grabbed_cubes_ids`." warnings.warn(warning_msg) msg = dict(**oblig_part, msg=warning_msg) send_data_quite(conn, addr, msg) else: ok = False warning_msg = "Только события типов {} поддерживаются, в то " \ "время как было принято описание события типа {}. Вероятно, " \ "в клиентской части программы допущена ошибка.".format( self.supported_incoming_event_types, event['type']) warnings.warn(warning_msg) msg = dict( **oblig_part, msg=warning_msg, supported_event_types=self.supported_incoming_event_types) send_data_quite(conn, addr, msg) return ok
def is_command_ok(self, command): if command['type'] not in self.supported_command_types: warning_msg = "Команда неизвестного типа {} " \ "пришла от сервера. Вероятно, в коде клиентской часть" \ "ошибка, так как входные сообщения неправильного типа " \ "должны фиксироваться в методе " \ "`CubeGameClient.receive_from_server()`".format( repr(command['type'])) warnings.warn(warning_msg) msg = { 'type': 'error_msg', 'error_class': 'ValueError', 'msg': warning_msg, 'command': command, } send_data_quite( self.get_root().conn_to_server, self.server_addr, msg) return False if set(command.keys()) != self.command_keys[command['type']]: warning_msg = "В словаре с описанием команды есть лишние ключи " \ "или не хватает ключей.\n" \ "excess: {}\n" \ "missing: {}\n" \ "command: {}".format( set(command.keys()) - self.command_keys[command['type']], self.command_keys[command['type']] - set(command.keys()), command ) warnings.warn(warning_msg) msg = { 'type': 'error_msg', 'error_class': 'ValueError', 'msg': warning_msg, 'command': command, } send_data_quite( self.get_root().conn_to_server, self.server_addr, msg) return False if command['type'] == 'add_cube': if not ( isinstance(command['id'], int) and isinstance(command['x'], (float, int)) and isinstance(command['y'], (float, int)) and isinstance(command['size'], (float, int)) and isinstance(command['color'], str) and command['id'] not in self.cubes_by_server_ids and command['size'] > 0 and command['color'] in colors.ALL_COLORS ): warning_msg = "Или значения, или типы значений в словаре с " \ "описанием команды неверны.\n" \ "command: {}\n" \ "Зарегистрированные у клиента " \ "id кубиков сервера: {}".format( command, self.cubes_by_server_ids) warnings.warn(warning_msg) msg = { 'type': 'error_msg', 'error_class': 'ValueError', 'msg': warning_msg, 'command': command, 'registered_server_cubes': list( self.cubes_by_server_ids) } send_data_quite( self.get_root().conn_to_server, self.server_addr, msg) return False elif command['type'] == 'coords': if not ( isinstance(command['id'], int) and isinstance(command['x1'], (float, int)) and isinstance(command['y1'], (float, int)) and isinstance(command['x2'], (float, int)) and isinstance(command['y2'], (float, int)) and command['id'] in self.cubes_by_server_ids ): warning_msg = "Или значения, или типы значений в словаре с " \ "описанием команды неверны." warnings.warn(warning_msg) msg = { 'type': 'error_msg', 'error_class': 'ValueError', 'msg': warning_msg, 'command': command, 'registered_server_cubes': list( self.cubes_by_server_ids) } send_data_quite( self.get_root().conn_to_server, self.server_addr, msg) return False return True