def __init__(self, app=None):

        self.client_data = ClientMainData()
        super(ClientMessageProcessor, self).__init__(self.client_data.domain)
        self.app = app
        self.auction_session_manager = AuctionSessionManager()
        self.logger = log().get_logger()
class HandleRemoveResourceRequestInterval(ScheduledTask):

    def __init__(self, stop_datetime: datetime, resource_request: ResourceRequest, seconds_to_start: float):
        """
        Method to create the task remove resource request interval
        :param stop_datetime: date and time when the resource request interval should be removed.
        :param resource_request: resource request that should be started.
        :param seconds_to_start: seconds for starting the task.
        """
        super(HandleRemoveResourceRequestInterval, self).__init__(seconds_to_start)
        self.stop_datetime = stop_datetime
        self.resource_request = resource_request
        self.seconds_to_start = seconds_to_start
        self.client_data = ClientMainData()
        self.auction_session_manager = AuctionSessionManager()
        self.agent_processor = AgentProcessor(self.client_data.domain, "")
        self.auction_manager = AuctionManager(self.client_data.domain)
        self.client_message_processor = ClientMessageProcessor()

    async def _run_specific(self):
        """
        Handles the removal of a resource request interval.
        """
        try:
            self.logger.info("in HandleRemoveResourceRequestInterval 1")
            interval = self.resource_request.get_interval_by_end_time(self.stop_datetime)

            # Gets the  auctions corresponding with this resource request interval
            session_id = interval.session

            session: AuctionSession = self.auction_session_manager.get_session(session_id)

            self.logger.info("in HandleRemoveResourceRequestInterval 2")

            remove_resource_request = RemoveResourceRequestInterval(session)
            await remove_resource_request.process_remove()

            # teardowns the session created.
            await self.client_message_processor.process_disconnect(session)

            self.logger.info("in HandleRemoveResourceRequestInterval 3")

            # remove the session from the session manager
            self.auction_session_manager.del_session(session.get_key())

            self.logger.info("ending HandleRemoveResourceRequestInterval")

        except Exception as e:
            self.logger.error('Error during remove resource request interval - Error:{0}'.format(str(e)))
 def __init__(self, start_datetime: datetime, resource_request: ResourceRequest, seconds_to_start: float):
     """
     Method to create the task
     :param start_datetime: date and time when the task should start
     :param seconds_to_start: seconds for starting the task.
     :param resource_request: resource request that should be started.
     """
     super(HandleActivateResourceRequestInterval, self).__init__(seconds_to_start)
     self.start_datetime = start_datetime
     self.resource_request = resource_request
     self.seconds_to_start = seconds_to_start
     self.client_data = ClientMainData()
     self.auction_session_manager = AuctionSessionManager()
     self.resource_request_manager = ResourceRequestManager(domain=self.client_data.domain)
     self.client_message_processor = ClientMessageProcessor()
 def __init__(self, session: AuctionSession):
     self.session_manager = AuctionSessionManager()
     self.session = session
     self.client_data = ClientMainData()
     self.client_message_processor = ClientMessageProcessor()
     self.agent_processor = AgentProcessor(self.client_data.domain, "")
     self.auction_manager = AuctionManager(self.client_data.domain)
     self.logger = log().get_logger()
    def __init__(self, request_process_key: str, bidding_objects: List[BiddingObject], seconds_to_start: float):
        """
        Handles the generation of new bidding objects

        :param request_process_key: process key where the bidding objects have been generated
        :param bidding_objects: bidding object list to include
        :param seconds_to_start: seconds to wait for running the task.
        """
        super(HandledAddGenerateBiddingObject, self).__init__(seconds_to_start)
        self.request_process_key = request_process_key
        self.bidding_objects = bidding_objects
        self.client_data = ClientMainData()
        self.agent_processor = AgentProcessor(self.client_data.domain, '')
        self.auction_session_manager = AuctionSessionManager()
        self.auction_manager = AuctionManager(self.client_data.domain)
        self.agent_template_container = AgentTemplateContainerManager()
        self.bidding_manager = BiddingObjectManager(self.client_data.domain)
        self.message_processor = ClientMessageProcessor()
class HandleActivateSession(ScheduledTask):

    def __init__(self, seconds_to_start: float, session_key: str):
        super(HandleActivateSession, self).__init__(seconds_to_start)
        self.session_key = session_key
        self.auction_session_manager = AuctionSessionManager()

    async def _run_specific(self):
        try:
            session = self.auction_session_manager.get_session(self.session_key)
            session.set_state(SessionState.SS_ACTIVE)
        except Exception as e:
            self.logger.error(str(e))
class HandleResourceRequestTeardown(ImmediateTask):
    """
    This class handles the action to teardown the server's session.
    """

    def __init__(self, session_key: str):
        super(HandleResourceRequestTeardown, self).__init__()
        self.session_key = session_key
        self.session_manager = AuctionSessionManager()

    async def _run_specific(self, **kwargs):
        try:

            session = self.session_manager.get_session(self.session_key)
            remove_resource_request = RemoveResourceRequestInterval(session)
            await remove_resource_request.process_remove()

        except ValueError as e:
            # This means that the session does not have bidding objects associated
            pass
Пример #8
0
 def _initialize_managers(self):
     """
     Initializes managers used.
     :return:
     """
     self.logger.debug("Starting _initialize_managers")
     self.auction_manager = AuctionManager(self.domain)
     self.database_manager = DataBaseManager(
         Config().get_config_param('DataBase', 'Type'),
         Config().get_config_param('DataBase', 'Host'),
         Config().get_config_param('DataBase', 'User'),
         Config().get_config_param('DataBase', 'Password'),
         Config().get_config_param('DataBase', 'Port'),
         Config().get_config_param('DataBase', 'DbName'),
         Config().get_config_param('DataBase', 'MinSize'),
         Config().get_config_param('DataBase', 'MaxSize'))
     self.bidding_object_manager = BiddingObjectManager(self.domain)
     self.resource_request_manager = ResourceRequestManager(self.domain)
     self.auction_session_manager = AuctionSessionManager()
     self.logger.debug("Ending _initialize_managers")
class ClientMessageProcessor(AuctionMessageProcessor, metaclass=Singleton):
    """
    This class takes care of agents' communications.
    """

    def __init__(self, app=None):

        self.client_data = ClientMainData()
        super(ClientMessageProcessor, self).__init__(self.client_data.domain)
        self.app = app
        self.auction_session_manager = AuctionSessionManager()
        self.logger = log().get_logger()

    async def websocket_shutdown(self, server_connection: ServerConnection):
        """
        Disconnects the websocket from the server

        :param server_connection: server to disconnect
        :return:
        """
        self.logger.info('starting server connection shutdown - key {0}'.format(server_connection.key))

        # Close open sockets
        if server_connection.session:
            session = server_connection.session
            if not session.closed:
                ws = server_connection.web_socket
                if not ws.closed:
                    await ws.close(code=WSCloseCode.GOING_AWAY,
                                   message='Client shutdown')
                await session.close()

        self.logger.info('server connection shutdown ended - key {0}'.format(server_connection.key))

    async def _connection_established(self, session):
        """
        Sleeps until the session is acknowledged or a timeout is reached.

        :param session: session to be acknowledged
        :raises Connection error when not acknowledged
        """
        timeout = self.TIMEOUT_SYN
        while timeout > 0:
            if session.server_connection.get_state() == ServerConnectionState.ESTABLISHED:
                break
            await asyncio.sleep(0.01)
            timeout = timeout - 10

        if timeout <= 0:
            # teardown the web socket connection
            await self.websocket_shutdown(session.server_connection)

            # Raise an exception to inform the error when connecting to the server.
            raise ConnectionError("The connection could not be established")

    async def connect(self) -> AuctionSession:
        """
        Connects a server, occurs per every resource request interval activation.
        """
        self.logger.debug('in client message processor connect')
        if self.client_data.use_ipv6:
            session = self.auction_session_manager.create_agent_session(self.client_data.ip_address6,
                                                                        self.client_data.destination_address6,
                                                                        self.client_data.source_port,
                                                                        self.client_data.destination_port,
                                                                        self.client_data.protocol)
        else:
            session = self.auction_session_manager.create_agent_session(self.client_data.ip_address4,
                                                                        self.client_data.destination_address4,
                                                                        self.client_data.source_port,
                                                                        self.client_data.destination_port,
                                                                        self.client_data.protocol)

        server_connection = ServerConnection(session.get_key())

        try:
            await self.websocket_connect(self.client_data.use_ipv6,
                                         self.client_data.destination_address4,
                                         self.client_data.destination_address6,
                                         self.client_data.destination_port,
                                         server_connection)

            server_connection.set_auction_session(session)
            task = asyncio.ensure_future(self.websocket_read(server_connection))
            server_connection.set_task(task)

        except ClientConnectorError as e:
            self.logger.error('error connecting the server {0}'.format(str(e)))
            raise e

        # we need to wait until the connection is ready
        seq_nbr = session.get_next_message_id()

        message = self.build_syn_message(seq_nbr)

        str_msg = message.get_message()

        await self.send_message(server_connection, str_msg)
        server_connection.set_state(ServerConnectionState.SYN_SENT)
        session.add_pending_message(message)
        session.set_server_connection(server_connection)

        await self._connection_established(session)

        return session

    async def _disconnect_socket(self, server_connection: ServerConnection):
        """
        disconnects a session from the server.

        :param server_connection: server connection being used.
        :return:
        """
        self.logger.debug("Starting _disconnect_socket - nbr references:{0}".format(
            str(server_connection.get_reference())))

        server_connection.delete_reference()
        if server_connection.get_reference() <= 0:
            # the shutdown of the websocket also finishes the task.
            await self.websocket_shutdown(server_connection)
            self.logger.debug("sent socket shutdown to the server")

        self.logger.debug("Ending _disconnect_socket")

    async def handle_syn_ack_message(self, server_connection: ServerConnection,
                                     ipap_message: IpapMessage):
        """
        Establishes the session
        :param server_connection: websocket and aiohttp session created for the connection
        :param ipap_message: message sent from the server.
        :return:
        """
        self.logger.debug("Starting handle_syn_ack_message")
        # verifies ack sequence number
        ack_seqno = ipap_message.get_ackseqno()

        self.logger.debug("ack_seqno:{0}".format(str(ack_seqno)))

        # verifies the connection state
        if server_connection.state == ServerConnectionState.SYN_SENT:
            try:
                server_connection.get_auction_session().confirm_message(ack_seqno)

                # send the ack message establishing the session.
                syn_ack_message = self.build_ack_message(server_connection.get_auction_session().get_next_message_id(),
                                                         ipap_message.get_seqno())
                msg = syn_ack_message.get_message()
                await self.send_message(server_connection, msg)

                # puts the connection as established.
                server_connection.set_state(ServerConnectionState.ESTABLISHED)

                self.logger.info("Connection established with server")

            except ValueError:
                self.logger.error("Invalid ack nbr from the server, the session is going to be teardown")
                await self._disconnect_socket(server_connection)
                self.auction_session_manager.del_session(server_connection.get_auction_session().get_key())

        else:
            # The server is not in syn sent state, so ignore the message
            self.logger.info("a message with syn and ack was received, but the session \
                                is not in SYN_SENT. Ignoring the message")

        self.logger.debug("Ending handle_syn_ack_message")

    async def send_ack_disconnect(self, server_connection: ServerConnection,
                                  ipap_message: IpapMessage):
        """
        Sends the ack disconnect message.

        :param server_connection: websocket and aiohttp session created for the connection
        :param ipap_message: message sent from the server.
        :return:
        """
        self.logger.debug("Starting send_ack_disconnect")
        # verifies ack sequence number
        ack_seqno = ipap_message.get_ackseqno()

        try:

            server_connection.get_auction_session().confirm_message(ack_seqno)

        except ValueError:
            # nothing was expected to be acknowledged
            pass

        # verifies the connection state
        if server_connection.state == ServerConnectionState.ESTABLISHED:

            self.logger.debug("starting to disconnect from server connection state established")
            message = self.build_ack_message(server_connection.get_auction_session().get_next_message_id(),
                                             ipap_message.get_seqno())

            print('message ack disconnect id:', message.get_seqno())
            await self.send_message(server_connection, message.get_message())

            self.logger.debug("disconnecting - before putting close_wait ")
            # server_connection.set_state(ServerConnectionState.CLOSE_WAIT)
            self.logger.debug("disconnecting - after putting close_wait ")

            from auction_client.auction_client_handler import HandleResourceRequestTeardown
            handle_tear_down = HandleResourceRequestTeardown(server_connection.get_auction_session().get_key())
            await handle_tear_down.start()

            self.logger.debug("disconnecting - after removing resource request ")

            message = self.build_fin_message(server_connection.get_auction_session().get_next_message_id(), 0)
            server_connection.get_auction_session().add_pending_message(message)
            print('message fin message id:', message.get_seqno())
            await self.send_message(server_connection, message.get_message())

            self.logger.debug("disconnecting - after sending fin message ")

            server_connection.set_state(ServerConnectionState.LAST_ACK)

            self.logger.debug("ending to disconnect from server connection state established")

        # verifies the connection state
        elif server_connection.get_state() == ServerConnectionState.FIN_WAIT_2:

            # send the ack message establishing the session.
            message = self.build_ack_message(server_connection.get_auction_session().get_next_message_id(),
                                             ipap_message.get_seqno())

            print('message fin wait ack id:', message.get_seqno())
            await self.send_message(server_connection, message.get_message())

            await self._disconnect_socket(server_connection)
            self.auction_session_manager.del_session(server_connection.get_auction_session().get_key())
            server_connection.set_state(ServerConnectionState.CLOSED)

        else:
            # The server is not in syn sent state, so ignore the message
            self.logger.info("A msg with fin state was received,but the server is not in fin_wait state, ignoring it")

        self.logger.debug("Ending  send_ack_disconnect- new state {0}".format(str(server_connection.get_state())))

    async def handle_ack(self, server_connection: ServerConnection,
                         ipap_message: IpapMessage):
        """
        The agent received a message witn the ack flag active, it can be a auction message or a disconnect
        message

        :param server_connection: websocket and aiohttp session created for the connection
        :param ipap_message: message sent from the server.
        """
        self.logger.debug('start method handle_ack')
        # verifies ack sequence number
        ack_seqno = ipap_message.get_ackseqno()

        # verifies the connection state
        if server_connection.state == ServerConnectionState.FIN_WAIT_1:
            try:
                server_connection.get_auction_session().confirm_message(ack_seqno)
                server_connection.set_state(ServerConnectionState.FIN_WAIT_2)

            except ValueError:
                self.logger.info("A msg with ack nbr not expected was received, ignoring it")

        else:
            from auction_client.auction_client_handler import HandleAuctionMessage
            when = 0
            handle_auction_message = HandleAuctionMessage(server_connection, ipap_message, when)
            handle_auction_message.start()

        self.logger.debug('End method handle_ack -new state: {0}'.format(str(server_connection.get_state())))

    async def process_message(self, server_connection: ServerConnection, msg: str):
        """
        Processes a message arriving from an agent.

        :param server_connection: websocket and aiohttp session created for the connection
        :param msg: message received
        """
        try:

            ipap_message = self.is_auction_message(msg)

        except ValueError as e:
            # invalid message, we do not send anything for the moment
            self.logger.error("Invalid message from agent - Received msg: {0} - Error: {1}".format(msg, str(e)))
            return

        syn = ipap_message.get_syn()
        ack = ipap_message.get_ack()
        fin = ipap_message.get_fin()

        if syn and ack:
            await self.handle_syn_ack_message(server_connection, ipap_message)

        elif fin:
            await self.send_ack_disconnect(server_connection, ipap_message)

        elif ack and (not fin and not syn):
            await self.handle_ack(server_connection, ipap_message)

        else:
            from auction_client.auction_client_handler import HandleAuctionMessage
            handle_auction_message = HandleAuctionMessage(server_connection, ipap_message, 0)
            handle_auction_message.start()

    async def process_disconnect(self, session: AuctionSession):
        """
        Teardowns the connection established for a particular session.

        :param session: session to teardown
        :return:
        """
        self.logger.debug('Starting to disconnect')

        # verifies the connection state
        if session.server_connection.state == ServerConnectionState.ESTABLISHED:

            # send the ack message establishing the session.
            message = self.build_fin_message(session.get_next_message_id(), 0)

            session.add_pending_message(message)
            await self.send_message(session.server_connection, message.get_message())

            session.server_connection.set_state(ServerConnectionState.FIN_WAIT_1)

        else:
            # The connection is not in establised state, so generate an error
            raise ValueError("Error the connection for session key {0} is not established".format(session.get_key()))

        self.logger.debug('Ending disconnect')

    async def send_message(self, server_connection: ServerConnection, message: str):
        """
        Sends the message for an agent

        :param server_connection: Server connection where we are going to sendthe message
        :param message: message to be send
        """
        self.logger.debug("start method send message")

        await server_connection.web_socket.send_str(message)

        self.logger.debug("end method send message")

    async def websocket_connect(self, use_ipv6: bool, destination_address4: ip_address,
                                destination_address6: ip_address,
                                destination_port: int, server_connection: ServerConnection):
        """
        Creates a web socket for a server connection

        :param use_ipv6: if it uses ipv 6 or not
        :param destination_address4: destination ipv6 address
        :param destination_address6: destination ipv4 address
        :param destination_port: destination port
        :param server_connection: Server connection object to be updated.
        """
        session = ClientSession()

        if use_ipv6:
            destin_ip_address = str(destination_address6)
        else:
            destin_ip_address = str(destination_address4)

        # TODO: CONNECT USING A DNS
        http_address = 'http://{ip}:{port}/{resource}'.format(ip=destin_ip_address,
                                                              port=str(destination_port),
                                                              resource='websockets')
        try:

            ws = await session.ws_connect(http_address)
            server_connection.set_web_socket(session, ws)

        except ClientConnectorError as e:
            # Close the session to clean up connections.
            await session.close()
            raise e

    async def websocket_read(self, server_connection: ServerConnection):
        """
        Reads the websocket that is related with the server connection

        :param server_connection:  server connection to read the websocket.
        :return:
        """
        try:
            async for msg in server_connection.web_socket:
                if msg.type == WSMsgType.TEXT:
                    await self.process_message(server_connection, msg.data)

                elif msg.type == WSMsgType.CLOSED:
                    self.logger.error("websocket closed by the server.")
                    print("websocket closed by the server.")
                    break

                elif msg.type == WSMsgType.ERROR:
                    self.logger.error("websocket error received.")
                    print("websocket error received.")
                    break

        except ClientConnectorError as e:
            self.logger.error("Error during server connection - error:{0}".format(str(e)))
            os.kill(os.getpid(), signal.SIGINT)
 def __init__(self, session_key: str):
     super(HandleResourceRequestTeardown, self).__init__()
     self.session_key = session_key
     self.session_manager = AuctionSessionManager()
class HandleActivateResourceRequestInterval(ScheduledTask):

    def __init__(self, start_datetime: datetime, resource_request: ResourceRequest, seconds_to_start: float):
        """
        Method to create the task
        :param start_datetime: date and time when the task should start
        :param seconds_to_start: seconds for starting the task.
        :param resource_request: resource request that should be started.
        """
        super(HandleActivateResourceRequestInterval, self).__init__(seconds_to_start)
        self.start_datetime = start_datetime
        self.resource_request = resource_request
        self.seconds_to_start = seconds_to_start
        self.client_data = ClientMainData()
        self.auction_session_manager = AuctionSessionManager()
        self.resource_request_manager = ResourceRequestManager(domain=self.client_data.domain)
        self.client_message_processor = ClientMessageProcessor()

    async def _run_specific(self):
        """
        Handles the activation of a resource request interval.
        :return:
        """
        session = None
        try:
            # for now we request to any resource,
            # a protocol to spread resources available must be implemented
            resource_id = "ANY"
            interval = self.resource_request.get_interval_by_start_time(self.start_datetime)

            # Gets an ask message for the resource
            message = self.resource_request_manager.get_ipap_message(self.resource_request,
                                                                     self.start_datetime, resource_id,
                                                                     self.client_data.use_ipv6,
                                                                     str(self.client_data.ip_address4),
                                                                     str(self.client_data.ip_address6),
                                                                     self.client_data.source_port)

            # Create a new session for sending the request
            session = await self.client_message_processor.connect()

            if session is not None:
                # Gets the new message id
                message_id = session.get_next_message_id()
                message.set_seqno(message_id)
                message.set_ack_seq_no(0)

                self.logger.info("new session with interval {0}".format(interval.start.strftime("%d/%m/%Y %H:%M:%S")))
                session.set_resource_request_interval(interval)
                session.set_start(interval.start)
                session.set_stop(interval.stop)

                # Add the session in the session container
                self.auction_session_manager.add_session(session)

                # Add the pending message.
                session.add_pending_message(message)

                # Sends the message to destination
                await self.client_message_processor.send_message(session.get_server_connnection(),
                                                                 message.get_message())

                # Assign the new session to the interval.
                interval.session = session.get_key()

                self.logger.debug("ending ok HandleActivateResourceRequestInterval")

            else:
                self.logger.error("the session could not be established")

        except Exception as e:
            self.logger.error('Error during handle activate resource request - Error: {0}'.format(str(e)))
            if session:
                await self.client_message_processor.process_disconnect(session)
                try:
                    self.auction_session_manager.del_session(session.get_key())
                except ValueError:
                    pass
class HandledAddGenerateBiddingObject(ScheduledTask):

    def __init__(self, request_process_key: str, bidding_objects: List[BiddingObject], seconds_to_start: float):
        """
        Handles the generation of new bidding objects

        :param request_process_key: process key where the bidding objects have been generated
        :param bidding_objects: bidding object list to include
        :param seconds_to_start: seconds to wait for running the task.
        """
        super(HandledAddGenerateBiddingObject, self).__init__(seconds_to_start)
        self.request_process_key = request_process_key
        self.bidding_objects = bidding_objects
        self.client_data = ClientMainData()
        self.agent_processor = AgentProcessor(self.client_data.domain, '')
        self.auction_session_manager = AuctionSessionManager()
        self.auction_manager = AuctionManager(self.client_data.domain)
        self.agent_template_container = AgentTemplateContainerManager()
        self.bidding_manager = BiddingObjectManager(self.client_data.domain)
        self.message_processor = ClientMessageProcessor()

    async def _run_specific(self, **kwargs):
        try:
            # Gets the session
            session_key = self.agent_processor.get_session_for_request(self.request_process_key)
            session: AuctionSession = self.auction_session_manager.get_session(session_key)

            # Inserts the objects in the bidding object container
            for bidding_object in self.bidding_objects:
                self.logger.info("it is going to send bidding object: {0}".format(bidding_object.get_key()))
                bidding_object.set_process_request_key(self.request_process_key)
                interval: ResourceRequestInterval = session.get_resource_request_interval()
                bidding_object.set_resource_request_key(interval.get_resource_request_key())

                await self.bidding_manager.add_bidding_object(bidding_object)
                i = 0
                num_options = len(bidding_object.options)
                for option_name in sorted(bidding_object.options.keys()):
                    interval = bidding_object.calculate_interval(option_name)
                    when = (interval.start - datetime.now()).total_seconds()
                    handle_activate = HandleActivateBiddingObject(bidding_object, when)
                    handle_activate.start()
                    bidding_object.add_task(handle_activate)

                    if i < num_options - 1:
                        when = (interval.stop - datetime.now()).total_seconds()
                        handle_inactivate = HandleInactivateBiddingObject(bidding_object, when)
                        bidding_object.add_task(handle_inactivate)
                        handle_inactivate.start()
                    else:
                        when = (interval.stop - datetime.now()).total_seconds()
                        handle_remove = HandleRemoveBiddingObject(bidding_object, when)
                        bidding_object.add_task(handle_remove)
                        handle_remove.start()

                    i = i + 1

            # Gets the server domain from the request process
            server_domain = self.agent_processor.get_server_domain(self.request_process_key)

            # Builds and sends the message
            template_container = self.agent_template_container.get_template_container(server_domain)
            ipap_message = self.bidding_manager.get_ipap_message(self.bidding_objects, template_container)
            ipap_message.set_seqno(session.get_next_message_id())
            ipap_message.set_ack_seq_no(0)
            session.add_pending_message(ipap_message)
            await self.message_processor.send_message(session.get_server_connnection(), ipap_message.get_message())

            for bidding_object in self.bidding_objects:
                self.logger.info("after sending bidding object: {0}".format(bidding_object.get_key()))

        except Exception as e:
            self.logger.error(str(e))
 def __init__(self, seconds_to_start: float, session_key: str):
     super(HandleActivateSession, self).__init__(seconds_to_start)
     self.session_key = session_key
     self.auction_session_manager = AuctionSessionManager()