Пример #1
0
 def _create_realm(self):
     realm_name = CONFIG["realm"]["name"]
     realm_address = "{}:{}".format(self.hostname, self.port)
     realm_id = RealmId(int(CONFIG["realm"]["id"]))
     self.realm = Realm(realm_name, realm_address, realm_id)
Пример #2
0
 def _create_realm(self):
     realm_name = CONFIG["realm"]["name"]
     realm_address = "{}:{}".format(self.hostname, self.port)
     realm_id = RealmId(int(CONFIG["realm"]["id"]))
     self.realm = Realm(realm_name, realm_address, realm_id)
Пример #3
0
class WorldServer(object):
    """ World server accepting connections from clients.

    At this point in development, it is the world server that creates and
    registers to the database the realm it hosts. In the long run though, it
    would probably be better to separate them and that a world server gets
    initialized with an already existing realm.
    """

    BACKLOG_SIZE = 64
    LOGIN_SERVER_HEARTBEAT_RATE = int(CONFIG["login"]["realm_heartbeat_time"])

    def __init__(self):
        self.hostname = CONFIG["realm"]["hostname"]
        self.port = int(CONFIG["realm"]["port"])
        self.realm = None
        self.population = RealmPopulation.LOW
        self._create_realm()

        self.login_server_socket = None
        self.clients_socket = None

        self.world_connections = []
        self.world_connections_lock = threading.Lock()
        self.object_manager = ObjectManager(self)
        self.chat_manager = ChatManager(self)

        self.shutdown_flag = threading.Event()

    def _create_realm(self):
        realm_name = CONFIG["realm"]["name"]
        realm_address = "{}:{}".format(self.hostname, self.port)
        realm_id = RealmId(int(CONFIG["realm"]["id"]))
        self.realm = Realm(realm_name, realm_address, realm_id)

    def start(self):
        LOG.info("Starting world server " + self.realm.name)
        self._listen_clients()

        simple_thread(self._handle_login_server_connection)
        self._accept_clients()

        self.shutdown_flag.set()
        self._stop_listen_clients()
        LOG.info("World server stopped.")

    #------------------------------
    # Clients connection
    #------------------------------

    def _listen_clients(self):
        self.clients_socket = socket.socket()
        self.clients_socket.settimeout(1)
        clients_address = (self.hostname, self.port)
        self.clients_socket.bind(clients_address)
        self.clients_socket.listen(WorldServer.BACKLOG_SIZE)

    def _stop_listen_clients(self):
        self.clients_socket.close()
        self.clients_socket = None

    def _accept_clients(self):
        """ Regularly try to access client while looking for interrupts. """
        try:
            while True:
                self._try_accept_client()
        except KeyboardInterrupt:
            LOG.info("KeyboardInterrupt received, stop accepting clients.")

    def _try_accept_client(self):
        """ Accept a client connection or timeout if there aren't any. """
        try:
            connection, address = self.clients_socket.accept()
            self._handle_client(connection, address)
        except socket.timeout:
            pass

    def _handle_client(self, connection, address):
        """ Start the threaded WorldConnection and add it to the local list. """
        LOG.info("Accepting client connection from " + str(address))
        world_connection = WorldConnection(self, connection)

        with self.world_connections_lock:
            self.world_connections.append(world_connection)

        simple_thread(world_connection.handle_connection)

    #------------------------------
    # Login server connection
    #------------------------------

    def _handle_login_server_connection(self):
        """ Update forever the realm state to the login server. """
        while not self.shutdown_flag.is_set():
            state_packet = self.realm.get_state_packet(
                RealmFlags.NORMAL, self.population
            )

            self._open_login_server_socket()
            if self.login_server_socket:
                self.login_server_socket.sendall(state_packet)
                self._close_login_server_socket()

            time.sleep(self.LOGIN_SERVER_HEARTBEAT_RATE)

    def _open_login_server_socket(self):
        """ Open the login server socket, or set it to None if it couldn't
        connect properly. """
        self.login_server_socket = socket.socket()
        login_server_address = ( CONFIG["login"]["realm_conn_hostname"]
                               , int(CONFIG["login"]["realm_conn_port"]) )
        try:
            self.login_server_socket.connect(login_server_address)
        except ConnectionError as exc:
            LOG.error("Couldn't join login server! " + str(exc))
            self.login_server_socket = None

    def _close_login_server_socket(self):
        self.login_server_socket.close()
        self.login_server_socket = None

    #------------------------------
    # Server utilities
    #------------------------------

    def broadcast(self, packet, state = None, guids = None):
        """ Send a WorldPacket to all eligible WorldConnection. """
        with self.world_connections_lock:
            for connection in self.world_connections:
                eligible = WorldServer._get_broadcast_eligibility(
                    connection, state, guids
                )
                if eligible:
                    connection.outgoing_queue.put(packet)

    @staticmethod
    def _get_broadcast_eligibility(connection, state, guids):
        """ Return whether a connection is eligible to receive a broadcast.

        If state is provided, send packet only WorldConnections in that state.
        If guids is provided, send packet only to players in that GUID list.
        """
        state_condition = ( state is None
                            or connection.state == state )
        guid_condition = ( guids is None
                           or ( connection.player
                                and connection.player.guid in guids ) )
        eligible = state_condition and guid_condition
        return eligible
Пример #4
0
class WorldServer(object):
    """ World server accepting connections from clients.

    At this point in development, it is the world server that creates and
    registers to the database the realm it hosts. In the long run though, it
    would probably be better to separate them and that a world server gets
    initialized with an already existing realm.
    """

    BACKLOG_SIZE = 64
    LOGIN_SERVER_HEARTBEAT_RATE = int(CONFIG["login"]["realm_heartbeat_time"])

    def __init__(self):
        self.hostname = CONFIG["realm"]["hostname"]
        self.port = int(CONFIG["realm"]["port"])
        self.realm = None
        self.population = RealmPopulation.LOW
        self._create_realm()

        self.login_server_socket = None
        self.clients_socket = None

        self.world_connections = []
        self.world_connections_lock = threading.Lock()
        self.object_manager = ObjectManager(self)
        self.chat_manager = ChatManager(self)

        self.shutdown_flag = threading.Event()

    def _create_realm(self):
        realm_name = CONFIG["realm"]["name"]
        realm_address = "{}:{}".format(self.hostname, self.port)
        realm_id = RealmId(int(CONFIG["realm"]["id"]))
        self.realm = Realm(realm_name, realm_address, realm_id)

    def start(self):
        LOG.info("Starting world server " + self.realm.name)
        self._listen_clients()

        simple_thread(self._handle_login_server_connection)
        self._accept_clients()

        self.shutdown_flag.set()
        self._stop_listen_clients()
        LOG.info("World server stopped.")

    #------------------------------
    # Clients connection
    #------------------------------

    def _listen_clients(self):
        self.clients_socket = socket.socket()
        self.clients_socket.settimeout(1)
        clients_address = (self.hostname, self.port)
        self.clients_socket.bind(clients_address)
        self.clients_socket.listen(WorldServer.BACKLOG_SIZE)

    def _stop_listen_clients(self):
        self.clients_socket.close()
        self.clients_socket = None

    def _accept_clients(self):
        """ Regularly try to access client while looking for interrupts. """
        try:
            while True:
                self._try_accept_client()
        except KeyboardInterrupt:
            LOG.info("KeyboardInterrupt received, stop accepting clients.")

    def _try_accept_client(self):
        """ Accept a client connection or timeout if there aren't any. """
        try:
            connection, address = self.clients_socket.accept()
            self._handle_client(connection, address)
        except socket.timeout:
            pass

    def _handle_client(self, connection, address):
        """ Start the threaded WorldConnection and add it to the local list. """
        address_string = str(address[0]) + ":" + str(address[1])
        LOG.info("Accepting client connection from " + address_string)
        world_connection = WorldConnection(self, connection)

        with self.world_connections_lock:
            self.world_connections.append(world_connection)

        simple_thread(world_connection.handle_connection)

    #------------------------------
    # Login server connection
    #------------------------------

    def _handle_login_server_connection(self):
        """ Update forever the realm state to the login server. """
        while not self.shutdown_flag.is_set():
            state_packet = self.realm.get_state_packet(RealmFlags.NORMAL,
                                                       self.population)

            self._open_login_server_socket()
            if self.login_server_socket:
                self.login_server_socket.sendall(state_packet)
                self._close_login_server_socket()

            time.sleep(self.LOGIN_SERVER_HEARTBEAT_RATE)

    def _open_login_server_socket(self):
        """ Open the login server socket, or set it to None if it couldn't
        connect properly. """
        self.login_server_socket = socket.socket()
        login_server_address = (CONFIG["login"]["realm_conn_hostname"],
                                int(CONFIG["login"]["realm_conn_port"]))
        try:
            self.login_server_socket.connect(login_server_address)
        except ConnectionError as exc:
            LOG.error("Couldn't join login server! " + str(exc))
            self.login_server_socket = None

    def _close_login_server_socket(self):
        self.login_server_socket.close()
        self.login_server_socket = None

    #------------------------------
    # Server utilities
    #------------------------------

    def broadcast(self, packet, state=None, guids=None):
        """ Send a WorldPacket to all eligible WorldConnection. """
        with self.world_connections_lock:
            for connection in self.world_connections:
                eligible = WorldServer._get_broadcast_eligibility(
                    connection, state, guids)
                if eligible:
                    connection.outgoing_queue.put(packet)

    @staticmethod
    def _get_broadcast_eligibility(connection, state, guids):
        """ Return whether a connection is eligible to receive a broadcast.

        If state is provided, send packet only WorldConnections in that state.
        If guids is provided, send packet only to players in that GUID list.
        """
        state_condition = (state is None or connection.state == state)
        guid_condition = (guids is None
                          or (connection.player
                              and connection.player.guid in guids))
        eligible = state_condition and guid_condition
        return eligible