Exemplo n.º 1
0
    def __init__(self):
        super().__init__()
        self.handfrt = "iii"  # (int, int, int)  -> (message_length, command_id, version)
        self.head_len = struct.calcsize(self.handfrt)
        self.identifier = 0

        self.encode_ins = AesEncoder(GlobalObject().rpc_password, encode_type=GlobalObject().rpc_encode_type)
        self.version = 0

        self._buffer = b""    # 数据缓冲buffer
        self._head = None     # 消息头, list,   [message_length, command_id, version]
        self.transport = None
Exemplo n.º 2
0
 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!")
Exemplo n.º 3
0
    def process_data(self, data):
        if isinstance(data, str):
            data = bytes(data, encoding='utf8')
        self._buffer += data
        _buffer = b""
        if self._head is None:
            if len(self._buffer) < self.head_len:
                return

            self._head = struct.unpack(self.handfrt,
                                       self._buffer[:self.head_len])  # 包头
            self._buffer = self._buffer[self.head_len:]
        content_len = self._head[0] - self.head_len
        logger.info("here22222: {}".format(
            [content_len, len(self._buffer), self._head]))
        if len(self._buffer) >= content_len:
            data = self.encode_ins.decode(self._buffer[:content_len])  # 解密
            if not data:
                raise DataException()
            logger.debug("receive a message data: {}, {}".format(
                len(self._buffer), self._buffer[:100]))
            asyncio.ensure_future(self.message_handle(self._head[1],
                                                      self._head[2], data),
                                  loop=GlobalObject().loop)

            _buffer = self._buffer[content_len:]
            self._buffer = b""
            self._head = None
        logger.info("process_data: {}".format(
            [len(_buffer), len(self._buffer), self._buffer[:100]]))
        return _buffer
Exemplo n.º 4
0
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)
Exemplo n.º 5
0
 def connection_lost(self, exc):
     super().connection_lost(exc)
     WebsocketConnectionManager().remove_connection(self)
     SessionCache().del_cache(self.session_id)
     # client连接断开
     asyncio.ensure_future(websocket_route.call_target(
         CLIENT_OFFLINE, {}, session_id=self.session_id),
                           loop=GlobalObject().loop)
Exemplo n.º 6
0
async def rpc_message_handle(command_id, data):
    """
    接收到rpc消息处理
    :param command_id: int, 消息ID
    :param data: dict, 消息内容
    :return:
    """
    if not isinstance(data, dict):
        data = data.decode("utf-8") if isinstance(data, bytes) else data
        data = ujson.loads(data)
    logger.debug("rpc_message_handle:{}".format(
        [command_id, data, type(data),
         GlobalObject().id]))
    session_id = data.get("src", None)  # 消息最初来源于哪个proxy节点
    prev_node_type = data.get("prev", None)  # 该条消息是由哪类型的节点直接传过来的(即上游最近一个节点)
    to = data.get("to", None)
    info = data.get("data", {})
    if to:
        if to != GlobalObject().id:
            return await forwarding_next(command_id, info, session_id, to)
        else:
            return await local_handle(command_id, info, session_id)
    else:
        if GlobalObject().rpc_route:  # 配置了路由信息(一般只有route类型节点才会配置)
            next_node = -1
            for node, route in GlobalObject().rpc_route.get("special",
                                                            {}).items():
                if command_id in route:
                    next_node = node
                    break

            if -1 == next_node:
                for node, route in GlobalObject().rpc_route.get("range",
                                                                {}).items():
                    for r in route:
                        if r[0] <= command_id <= r[1]:
                            next_node = node
                            break
            logger.debug("rpc_message_handle:{}".format([
                next_node,
                GlobalObject().type, command_id,
                GlobalObject().rpc_route
            ]))
            if -1 == next_node:
                next_node = NodeType.ROUTE
            if next_node == GlobalObject(
            ).type or NodeType.ROUTE == prev_node_type and NodeType.ROUTE == next_node:
                # 如果下一个节点是自己或者该条消息是route路由节点传过来的,并且计算出来的下一个节点又是route节点,
                #   此时说明可能配置错误,防止递归,消息默认改为本地处理
                return await local_handle(command_id, info, session_id)
            else:
                return await push_message(next_node, command_id, info,
                                          session_id, to)
        else:  # 没有路由信息,则默认为本地处理
            return await local_handle(command_id, info, session_id)
Exemplo n.º 7
0
    def config(self, config):
        """

        :param config:
        :return:
        """
        host = config.get("host")
        self.host = host
        ws_port = config.get("websocket", {}).get("port", 0)  # web_socket port
        web_port = config.get("http", {}).get("port", 0)  # web httpserver port
        rpc_port = config.get("rpc", {}).get("port", 0)  # rpcserver port
        remote_ports = config.get("remote_ports", [])  # remote_ports list
        if "mongo" == config.get("available_way", "local") and config.get(
                "mongo_uri", ""):
            # 如果高可用使用的是MongoDB存储配置方式
            remote_ports = AvailServerConfig.get_instance(
                uri=config.get("mongo_uri"))
        GlobalObject().update_remote_ports(remote_ports)
        api_path = config.get("api_path", "")
        if api_path:
            __import__(api_path)

        GlobalObject().loop = self.loop

        GlobalObject().init_from_config(config)

        if ws_port and self.socket_handler:  # websocketserver port start
            GlobalObject().ws_server = self.loop.run_until_complete(
                websockets.serve(self.socket_handler,
                                 self.host,
                                 ws_port,
                                 create_protocol=WebSocketProtocol))

        if web_port and self.web_handler:  # web httpserver port  start
            GlobalObject().http_server = self.loop.run_until_complete(
                self.start_web(web_port))

        if rpc_port:
            GlobalObject().rpc_server = self.loop.run_until_complete(
                self.loop.create_server(RpcProtocol, self.host, rpc_port))

        if remote_ports:
            for rp in remote_ports:
                host = rp.get("host", "")
                port = rp.get("port", 0)
                s_type = NodeType.get_type(rp.get('type'))
                if host and port:
                    RpcConnectionManager().add_type_node(s_type, host, port)
                    RpcConnectionManager().store_connection(host, port, None)
                    if not RpcConnectionManager().get_connection(host, port):
                        remote_serv = self.loop.create_connection(
                            RpcPushProtocol, host=host, port=port)
                        try:
                            self.loop.run_until_complete(remote_serv)
                        except ConnectionRefusedError:
                            logger.debug("config all conns:{}".format(
                                RpcConnectionManager().conns))
                            logger.info("connecting to {}:{} failed!".format(
                                host, port))
Exemplo n.º 8
0
    def __init__(self,
                 ws_handler,
                 ws_server,
                 *,
                 origins=None,
                 extensions=None,
                 subprotocols=None,
                 extra_headers=None,
                 **kwds):
        self.handfrt = "iii"  # (int, int, int)  -> (message_length, command_id, version)
        self.head_len = struct.calcsize(self.handfrt)
        self.seq = None
        self.session_id = ""

        self.encode_ins = AesEncoder(
            GlobalObject().rpc_password,
            encode_type=GlobalObject().rpc_encode_type)
        self.version = 0

        self._buffer = b""  # 数据缓冲buffer
        self._head = None  # 消息头, list,   [message_length, command_id, version]
        self.transport = None
        super().__init__(ws_handler, ws_server, **kwds)
Exemplo n.º 9
0
 def run(self):
     try:
         self.loop.run_forever()
     finally:
         pending = asyncio.Task.all_tasks()
         for task in pending:
             task.cancel()
             with suppress(asyncio.CancelledError):
                 self.loop.run_until_complete(task)
         if GlobalObject().http_server:
             GlobalObject().http_server.close()
             self.loop.run_until_complete(
                 GlobalObject().http_server.wait_closed())
         if GlobalObject().rpc_server:
             GlobalObject().rpc_server.close()
             self.loop.run_until_complete(
                 GlobalObject().rpc_server.wait_closed())
         if GlobalObject().ws_server:
             GlobalObject().ws_server.close()
             self.loop.run_until_complete(
                 GlobalObject().ws_server.wait_closed())
         self.loop.close()
Exemplo n.º 10
0
 def pack(self, data, command_id, session_id=None, to=None):
     """
     打包消息, 用於傳輸
     :param data:  傳輸數據
     :param command_id:  消息ID
     :return:
     """
     data = ujson.dumps({
         "src": session_id,
         "to": to,
         "data": data,
         "prev": GlobalObject().type
     })
     data = self.encode_ins.encode(data)
     length = data.__len__() + self.head_len
     head = struct.pack(self.handfrt, length, command_id, self.version)
     return head + data
Exemplo n.º 11
0
    def execute(self, *args, **kwargs):
        """
        用户准备/取消准备
        :param args:
        :param kwargs:
        :return:
        """
        print("readddddddddddy:", self.params)
        validator = UserReadyValidator(handler=self)

        if 1 == validator.ready.data:
            validator.user.set_status(UserStatus.READY)
        else:
            validator.user.set_status(UserStatus.UNREADY)
        print("readddddddddddy2222222:", self.params)
        data = {"user_id": validator.user.user_id, "nick": validator.user.nick_name,
                "ready": validator.ready.data, "seat_id": validator.user.seat_id}
        validator.desk.notify_desk_some_user(PUSH_USER_READY, data, [validator.user.user_id])

        response_data = {"ready": validator.ready.data}
        validator.desk.notify_player(validator.user.seat_id, USER_READY, response_data)
        print("readddddddddddy222222233333:", self.params)
        # 当所有玩家都准备好时,默认触发游戏开始
        all_ready = 1
        for u in validator.desk.users:
            if not u or u.status == UserStatus.UNREADY:
                all_ready = 0
                break
        print("allllllllllll_ready:", all_ready)
        if all_ready:
            # 通知web服务器记录是否开始
            user_ids = []
            for i in validator.desk.users:
                user_ids.append(i.user_id)
            ret = notify_web_server_match_room_start_game(user_ids,
                                              validator.session_id.data,
                                              room_name=GlobalObject().name,
                                              room_type=validator.desk.room_type)
            print("readddddddddddy222222244444444:", self.params)
            if ret.get("ret") == 0:
                validator.desk.start_game()
            else:
                raise Exception("start game error ret=%s" % ret)

        return {"need_push": 0}
Exemplo n.º 12
0
async def local_handle(command_id, data, session_id):
    """
    无需转发, 本节点处理的消息
    :param command_id:
    :param data:
    :param session_id:
    :return: None
    """
    if NodeType.PROXY == GlobalObject().type:
        # proxy类型节点收到rpc消息后会通过websocket推送给客户端
        seq = int(session_id.split("_")[-1])
        client = WebsocketConnectionManager().get_websocket(seq)
        if not isinstance(data, str):
            data = ujson.dumps(data)
        logger.debug("local_handle:{}".format([data, command_id, client]))
        await client.send_message(data, command_id)
        return
    else:
        await call_target(command_id, data, session_id=session_id)
Exemplo n.º 13
0
def push_msg(message_id, data, session_list, code=200):
    """
    主动向客户端推送消息
    :param message_id:
    :param data: json串
    :param session_list:
    :return:
    """
    for session in session_list:
        to, _ = session.split("_")
        if code == 200:
            msg = success_response(data)
        else:
            print("push_msg data=", data)
            raise Exception()
            msg = error_response(USER_LOGIN_OTHER_DEVICE)

        asyncio.ensure_future(push_message(NodeType.PROXY, message_id, msg,
                                           session, to),
                              loop=GlobalObject().loop)
Exemplo n.º 14
0
 async def websocket_handler(self, websocket, path):
     logger.debug("websocket_handler: {}, {}".format(
         websocket.remote_address, path))
     while True:
         try:
             data = await asyncio.wait_for(
                 websocket.recv(), timeout=GlobalObject().ws_timeout)
             logger.debug('websocketserver received {!r}'.format(data))
             # await websocket.send("hello")
             while data:  # 解决TCP粘包问题
                 data = await websocket.process_data(data, websocket)
         except asyncio.TimeoutError:
             logger.info("{} connection timeout!".format(
                 websocket.remote_address))
             await websocket.close()
         except ConnectionClosed as e:
             logger.info("{} connection lose ({}, {})".format(
                 websocket.remote_address, e.code, e.reason))
             return 0
         except DataException as e:
             logger.info("data decrypt error!")
             await websocket.close()
             return 0
Exemplo n.º 15
0
 def gen_node_name(host, port):
     return GlobalObject.gen_id(host, port)
Exemplo n.º 16
0
 def call_later(cls, interval, callback_func, *args, **kwargs):
     return asyncio.ensure_future(cls.run(interval, callback_func, *args,
                                          **kwargs),
                                  loop=GlobalObject().loop)
Exemplo n.º 17
0
 def connection_open(self):
     super().connection_open()
     self.seq = WebSocketProtocol.gen_new_seq()
     self.session_id = "{}_{}".format(GlobalObject().id, self.seq)
     WebsocketConnectionManager().store_connection(self.seq, self)