async def send_message(self, node_name, command_id, data, session_id=None, to=None): """ 向指定连接发送消息 :param node_name: string :param command_id: int :param message: :return: """ if node_name not in self.conns.keys(): logger.warn("can not find connection {}".format(node_name)) return if ConnectionStatus.ESTABLISHED != self.conns[node_name]["status"]: # 连接断开状态 logger.warn("connection is unavailable {}".format(node_name)) for reconnect_times in range(3): await asyncio.sleep(5) if ConnectionStatus.ESTABLISHED == self.conns[node_name]["status"]: break if 2 == reconnect_times: logger.error("exceed max reconnect times {}".format(node_name)) return # if not isinstance(data, str): # data = ujson.dumps(data) # print(data, data.encode("utf8"), type(data)) await self.conns[node_name]["conn"].send_message(command_id, data, session_id=session_id , to=to) logger.debug("rpcserver send {0}".format(data)) return 1
def find_available_node(next_node_type, to=None): """ 寻找一个可用的节点,如果没有,则异步等待直到找到为止 :param next_node_type: :param to: string, node name :return: connect node object id """ logger.debug("find_available_node:{}".format( [next_node_type, to, RpcConnectionManager().conns])) while True: if to and to in RpcConnectionManager().conns.keys() and ConnectionStatus.ESTABLISHED == \ RpcConnectionManager().conns[to]["status"]: # 如果明确传输的目标,且和目标节点有直接可用的rpc连接,则直接通过该连接发送消息; next_node = to else: if not next_node_type or NodeType.ROUTE == next_node_type: # 选取一个可用的route节点 next_node = RpcConnectionManager().get_available_connection( NodeType.ROUTE) else: next_node = RpcConnectionManager().get_available_connection( next_node_type) if not next_node: # 如果没有可用的next_node_type类型对应的节点, 则转发往路由节点 next_node = RpcConnectionManager( ).get_available_connection(NodeType.ROUTE) if not next_node: logger.error("all route node dead!!!") # print("eeeeeeeee:", next_node_type, to, next_node) raise Exception() time.sleep(1) continue return next_node
async def push_message(next_node_type, command_id, message, session_id=None, to=None): """ 向其他节点推送消息 :param next_node_type: int, 接下来发往的节点类型 :param command_id: int :param message: string, 消息内容 :param session_id: string, 会话ID() :param to: string, 消息最终发往哪里,为空时则根据消息ID发送 :return: None """ if next_node_type == GlobalObject().type: # 参数错误,自己给自己发消息 logger.error("send_message:", next_node_type, command_id, message, session_id, to) raise Exception() next_node = SessionCache().get_node(session_id, next_node_type) if not next_node: next_node = find_available_node(next_node_type, to=to) SessionCache().add_cache(session_id, node_type=next_node_type, node_id=next_node) logger.debug("push_message:{}".format( [next_node, command_id, message, session_id, to])) await call_remote_service(next_node, command_id, message, session_id=session_id, to=to)
async def update_remote_rpc_config(self): """ 更新远程rpc连接 :param server_type: int, 待更新的服务节点类型 :param addr_info: dict, {host: port1, host2: port2, ...} :return: """ for server_type, addr_info in GlobalObject().remote_ports.items(): remote_names = [ RpcConnectionManager.gen_node_name(k, v) for k, v in addr_info.items() ] for r in RpcConnectionManager().conns.keys(): if r not in remote_names: if RpcConnectionManager( ).conns[r]["status"] == ConnectionStatus.ESTABLISHED: RpcConnectionManager( ).conns[r]["conn"].transport.close() RpcConnectionManager().conns.pop(r) for k, v in addr_info.items(): name = RpcConnectionManager.gen_node_name(k, v) if name not in RpcConnectionManager().conns.keys() \ or RpcConnectionManager().conns[name]["status"] != ConnectionStatus.ESTABLISHED: RpcConnectionManager().add_type_node(server_type, k, v) RpcConnectionManager().store_connection(k, v, None) try: await self.loop.create_connection(RpcPushProtocol, host=k, port=v) logger.info("success connect to {}:{}".format(k, v)) except ConnectionRefusedError as e: logger.error("try connect to {}:{} failed!")
def param_check(self, **kwargs): # 参数验证 act_params = kwargs.get("act_params") if 1 != len(act_params): # 同时只允许有一个玩家发生暗杠操作 logger.debug(u"act_an_gang_error:%s", str(act_params)) return seat_id = list(act_params.keys())[0] params = act_params[seat_id] # TODO 此处需要接受参数 用户选择暗杠牌值 used_card = params.get("used_card")[0] # card_val = self.game_data.last_chu_card_val if not used_card: logger.error("an_gang params error: %s", str([seat_id, params])) return hand_card = self.players[seat_id].hand_card if 4 != hand_card.hand_card_info[Card.cal_card_type(used_card)][ Card.cal_card_digit(used_card)]: logger.error("an_gang params error: %s", str([seat_id, params])) return self.seat_id = seat_id self.used_card = used_card return 1
def set_user_point(self, change_num): self.point += change_num ret, info = MUser.update_user_point(self.user_id, change_num) if self.point != info.get("point", ""): logger.error("set_user_point error! ({0}, {1})".format( self.user_id, change_num)) return self.point
def notify_web_server_restart(): url = "http://127.0.0.1:8889/mj/restart_delete_room_info" params = {} r = requests.get(url, params) if r.status_code != 200: logger.error("web server left_room error paras = %s" % params) print("delete error!!") return data = json.loads(r.text) if data.get("ret"): raise Exception("web server left_room error ret = %s" % data.get("ret")) print("delete success!!")
def execute(self, act_params={}): """ 执行点杠 :param act_params: :return: """ logger.debug(u"点杠: %s", str(act_params)) for step in self.game_config.player_act_step.get(Act.DIAN_GANG): for name, cfg in step.items(): ret = self.step_handlers.get(name)(act_params=act_params, config_params=cfg) if not ret: logger.error("step:%s", step) return return 1
def decode_aes(self, msg): try: decode_msg = unpad(self.aes_obj.decrypt(msg)) except Exception as e: logger.error("decode_aes error {}".format([msg])) return None msg_len = len(decode_msg) if msg_len == 0: return decode_msg try: json.loads(decode_msg) except ValueError: return None return decode_msg
def execute(self): """ 定庄 :return: """ logger.debug(u"定庄: %s", str([])) dice = [] if -1 == self.game_data.banker_seat_id: # 初始时 dice = self.get_random_dice() self.game_data.banker_seat_id = (dice[0] + dice[1] - 1) % self.max_player_num else: if not self.game_data.hu_player_static: # 上局为流局/荒庄, 则随机定庄 dice = self.get_random_dice() self.game_data.banker_seat_id = (dice[0] + dice[1] - 1) % self.max_player_num else: source = -1 for seat_id, params in self.game_data.hu_player_static.items(): self.game_data.banker_seat_id = seat_id source = params.get("source", -1) if 1 < len(self.game_data.hu_player_static): # 一炮多响, 点炮的人做庄 if -1 == source: logger.error("gen_banker error: %s", str(self.game_data.hu_player_static)) raise Exception() self.game_data.banker_seat_id = source # 重置胡牌相关信息 self.game_data.reset_hu_static() notify_all_desk_player(self.desk_id, message_ids.PUSH_GEN_BANK, data={ "bank_seat_id": self.game_data.banker_seat_id, "dice": dice }) # 清理上一局信息 self.game_data.reset_game_data() # 洗牌 self.card_dealer.shuffle_card() # 将庄家位置存入game_data self.game_data.last_chu_card_seat_id = self.game_data.banker_seat_id
def execute(self, act_params={}): """ 执行吃牌 :param act_params: :return: """ logger.debug(u"吃牌: %s", str(act_params)) print("CHI EXECUTE self.game_config.player_act_step=", self.game_config.player_act_step) print("CHI_step=", self.game_config.player_act_step.get(Act.CHI)) for step in self.game_config.player_act_step.get(Act.CHI): for name, cfg in step.items(): ret = self.step_handlers.get(name)(act_params=act_params, config_params=cfg) if not ret: logger.error("step:%s", step) return return 1
def param_check(self, seat_id, params, config_params): # 参数验证 hook_seat_id = params.get("hook_seat_id", -1) if not self.game_data.last_chu_card_val: logger.error("dian_hu params error: %s", str([seat_id, params])) return hand_card_vals = self.players[seat_id].hand_card.hand_card_vals # if 1 != len(hand_card_vals) % 3 or not self.players[seat_id].can_hu_result: if 1 != len(hand_card_vals) % 3: logger.error("dian_hu params error: %s", str([seat_id, params])) return self.seat_id = seat_id self.hook_seat_id = hook_seat_id self.hand_card = self.game_data.players[seat_id].hand_card self.dian_hu_card = self.game_data.last_chu_card_val return 1
def param_check(self, **kwargs): # 参数验证 act_params = kwargs.get("act_params") if 1 != len(act_params): # 同时只允许有一个玩家发生自摸操作 logger.debug(u"act_zimo_error:%s", str(act_params)) return seat_id = list(act_params.keys())[0] params = act_params[seat_id] hand_card_vals = self.players[seat_id].hand_card.hand_card_vals # if 2 != len(hand_card_vals) % 3 or not self.players[seat_id].can_hu_result: if 2 != len(hand_card_vals) % 3: logger.error("dian_hu params error: %s", str([seat_id, params])) return self.seat_id = seat_id self.hand_card = self.players[seat_id].hand_card return 1
def param_check(self, **kwargs): # 参数验证 act_params = kwargs.get("act_params") if 1 != len(act_params): # 同时只允许有一个玩家发生吃牌操作 logger.debug(u"act_ting_error:%s", str(act_params)) return seat_id = list(act_params.keys())[0] params = act_params[seat_id] chu_card = params.get("chu_card") if 0 > seat_id or seat_id >= self.max_player_num or chu_card not in self.players[ seat_id].can_ting_info.keys(): logger.error("ting params error: %s", str([seat_id, params])) return self.chu_card_val = chu_card self.seat_id = seat_id return 1
def execute(self, act_params={}): """ 执行自摸 :param act_params: :return: """ logger.debug(u"自摸胡牌: %s", str(act_params)) for step in self.game_config.player_act_step.get(Act.ZI_MO): for name, cfg in step.items(): ret = self.step_handlers.get(name)(act_params=act_params, config_params=cfg) if not ret: logger.error("step:%s", step) return self.settle(settle_type_list=[SettleType.HU]) if self.game_config.is_hu_end: # 当回合胡牌后结束当局游戏 self.end_game() return 1
async def call_target(command_id, data, session_id): """ 调用注册的消息处理 :param command_id: :param data: :param session_id: :return: """ obj = RegisterEvent.events.get(command_id, None) obj = obj if obj else RegisterEvent.events.get(DEFAULT_ID, None) # 如果没有,则进入默认消息处理 if not obj: logger.error("command_id {} not register!".format(command_id)) return handler = obj.get("handler")(data, command_id, session_id) ret = await handler.execute() logger.debug("local call target result={}".format(ret)) if ret and obj.get("need_return"): # 空消息不做推送 to, _ = session_id.split("_") await push_message(None, command_id, ret, session_id, to)
def param_check(self, **kwargs): # 参数验证 act_params = kwargs.get("act_params") if 1 != len(act_params): # 同时只允许有一个玩家发生点杠操作 logger.debug(u"act_diangang_error:%s", str(act_params)) return seat_id = list(act_params.keys())[0] params = act_params[seat_id] card_val = self.game_data.last_chu_card_val if not card_val or -1 == self.game_data.last_chu_card_seat_id: logger.error("dian_gang params error: %s", str([seat_id, params])) return hand_card = self.players[seat_id].hand_card if 3 != hand_card.hand_card_info[Card.cal_card_type(card_val)][Card.cal_card_digit(card_val)]: logger.error("dian_gang params error: %s", str([seat_id, params])) return self.seat_id = seat_id self.hand_card = self.game_data.players[seat_id].hand_card return 1
def execute(self, act_params={}): """ 执行点炮胡牌 :param act_params: :return: """ logger.debug(u"点炮胡牌: %s", str(act_params)) for seat_id, params in act_params.items(): for step in self.game_config.player_act_step.get(Act.DIAN_HU): for name, cfg in step.items(): ret = self.step_handlers.get(name)(seat_id=seat_id, params=params, config_params=cfg) if not ret: logger.error("step:%s", step) return if not self.game_config.has_tong_pao: # 如果不能通炮胡,则只取第一个胡牌的玩家 break self.settle(settle_type_list=[SettleType.HU]) if self.game_config.is_hu_end: # 当回合胡牌后结束当局游戏 self.end_game() return 1
async def execute(self, *args, **kwargs): logger.info("login_handler:{} {}".format(args, kwargs)) user_id = self.params.get("user_id", -1) passwd = self.params.get("passwd", "") if -1 == user_id or not passwd: return {} login_result = route_ins.login(user_id=user_id, passwd=passwd, new_sessionid=self.session_id, data=self.params) print("login_result:", login_result) if 200 == login_result.get('code'): info = login_result.get("info") old_session = info.get("old_session") if old_session and self.session_id != old_session: # 踢掉之前用户 to, _ = old_session.split("_") data = error_response(USER_LOGIN_OTHER_DEVICE) await push_message(NodeType.PROXY, USER_LOGIN_OTHER_DEVICE, data, old_session, to) return login_result else: logger.error("process_login: unknown error:%s", str(login_result)) return login_result
def param_check(self, **kwargs): # 参数验证 act_params = kwargs.get("act_params") # if 1 != len(act_params): # # 同时只允许有一个玩家发生补杠牌操作 # logger.debug(u"act_bugang_error:%s", str(act_params)) # return seat_id = list(act_params.keys())[0] params = act_params[seat_id] # TODO 此处需要接受参数 用户选择暗杠牌值 used_card = params.get("used_card")[0] if not used_card: logger.error("bu_gang card_val is none error: %s", str([self.seat_id, params])) return hand_card = self.players[seat_id].hand_card if 1 != used_card and [used_card, used_card, used_card] not in hand_card.peng_card_vals: logger.error("bu_gang card_val not in peng_card_val error: %s", str([self.seat_id, params])) return self.bugang_cardval = used_card self.seat_id = seat_id return 1
def execute(self, seat_id, card_num=1, is_last=False): """ 执行摸牌 :param seat_id: :param card_num: :param is_last: :return: """ logger.debug(u"摸牌: %s", str([seat_id, card_num, is_last])) print("### sid=%s draw_card len=%s hand-card =%s ," % (seat_id, len(self.players[seat_id].hand_card.hand_card_vals), self.players[seat_id].hand_card.hand_card_vals)) for step in self.game_config.draw_card_step: for name, cfg in step.items(): ret = self.step_handlers.get(name)(seat_id=seat_id, card_num=card_num, is_last=is_last, config_params=cfg) if not ret: logger.error("step:%s", step) return elif ret != 1: return 0 return 1
async def schedule(self): # 定时rpc断线重连 while True: await asyncio.sleep(3) # logger.info("start new schedule task~") # print("schedule:", RpcConnectionManager().type_dict, RpcConnectionManager().conns) for node_type, name_lst in RpcConnectionManager().type_dict.items( ): for name in name_lst: if name not in RpcConnectionManager().conns.keys()\ or ConnectionStatus.ESTABLISHED != RpcConnectionManager().conns[name]["status"]: host = RpcConnectionManager().conns[name]["host"] port = RpcConnectionManager().conns[name]["port"] try: logger.debug("try to reconnect:{}".format( [name, host, port])) await self.loop.create_connection(RpcPushProtocol, host=host, port=port) logger.info("success connect to {}:{}".format( host, port)) except ConnectionRefusedError as e: logger.error( "schedule try connect to {}:{} failed!")
def param_check(self, **kwargs): # 参数验证 act_params = kwargs.get("act_params") if 1 != len(act_params): # 同时只允许有一个玩家发生吃牌操作 logger.debug(u"act_chi_error:%s", str(act_params)) return seat_id = list(act_params.keys())[0] params = act_params[seat_id] card_val = self.game_data.last_chu_card_val used_cards = params.get("used_card", []) # 接受三张牌,用户吃的牌, 出去被吃的牌做处理 if card_val not in used_cards: logger.error("chi card val not in used_cards params error: %s", str([seat_id, params])) return used_cards.remove(card_val) if not card_val or 2 != len(used_cards): logger.error("chi params error: %s", str([seat_id, params])) return hand_card_vals = self.players[seat_id].hand_card.hand_card_vals if used_cards[0] not in hand_card_vals or used_cards[ 1] not in hand_card_vals: logger.error("chi params error: %s", str([seat_id, params])) return cards = [card_val, used_cards[0], used_cards[1]] cards.sort() if not self.card_analyse.shun(cards): logger.error("chi params error: %s", str([seat_id, params])) return self.used_cards = used_cards self.chi_group = cards self.seat_id = seat_id return 1
def connection_lost(self, error): if error: logger.error('ERROR: {}'.format(error)) else: logger.debug('closing') super().connection_lost(error)