Example #1
0
def sync_weibo():
	# query entities needed to sync
	entities = Entity.objects.filter(sync_timestamp1__range=(datetime.datetime.now(), datetime.datetime.now()+datetime.timedelta(minutes=5)), status1=1)
	for entity in entities:
		weibo_message = None
		if entity.type == Entity.GAME:
			weibo_message = weibo_message_builder.build_game_message(Game.objects.get(id=entity.id))
			logger.info('sync game %s to weibo' % weibo_message.entity_id)
		elif entity.type == Entity.REDIER:
			weibo_message = weibo_message_builder.build_redier_message(Redier.objects.get(id=entity.id))
			logger.info('sync redier %s to weibo' % weibo_message.entity_id)
		elif entity.type == Entity.COLLECTION:
			weibo_message = weibo_message_builder.build_collection_message(Collection.objects.get(id=entity.id))
			logger.info('sync collection %s to weibo' % weibo_message.entity_id)
		elif entity.type == Entity.PROBLEM:
			weibo_message = weibo_message_builder.build_problem_message(Problem.objects.get(id=entity.id))
			logger.info('sync problem %s to weibo' % weibo_message.entity_id)
		elif entity.type == Entity.PLAYER:
			weibo_message = weibo_message_builder.build_player_message(Player.objects.get(id=entity.id))
			logger.info('sync player %s to weibo' % weibo_message.entity_id)
		elif entity.type == Entity.PUZZLE:
			weibo_message = weibo_message_builder.build_puzzle_message(Puzzle.objects.get(id=entity.id))
			logger.info('sync puzzle %s to weibo' % weibo_message.entity_id)
		elif entity.type == Entity.NEWS:
			weibo_message = weibo_message_builder.build_news_message(News.objects.get(id=entity.id))
			logger.info('sync news %s to weibo' % weibo_message.entity_id)
		elif entity.type == Entity.EVALUATION:
			weibo_message = weibo_message_builder.build_evaluation_message(Evaluation.objects.get(id=entity.id))
			logger.info('sync evaluation %s to weibo' % weibo_message.entity_id)
		if weibo_message is not None:
			MessageSender.send_weibo(weibo_message)
		else:
			logger.info('nothing to sync to weibo')
Example #2
0
 def __init__(self):
     self._runner_process = None
     self._control_process = None
     self._watchdog = ProcessWatchdog(config.Watchdog.CHECK_INTERVAL)
     self.push_messages_receiver = PushMessageReceiver()
     self.config_builder = ConfigurationBuilder(
         config.Engine.CONFIGURATION_BUILDER)
     self.message_handler = MessageHandler(self)
     self.message_sender = MessageSender()
     self.message_router = MessageRouter(
         self.message_sender, self.message_handler.default_message_handler)
     self.state = ManagerState.EMPTY
     self._http_client = httpclient.HTTPClient()
     self._alert_registered = False
     self.obsi_id = getnode()  # A unique identifier of this OBSI
     self._engine_running = False
     self._engine_running_lock = locks.Lock()
     self._processing_graph_set = False
     self._engine_config_builder = None
     self._keep_alive_periodic_callback = None
     self._avg_cpu = 0
     self._avg_duration = 0
     self._supported_elements_types = []
     self._alert_messages_handler = None
     self._log_messages_handler = None
Example #3
0
def sync_web():
    #query entities needed to sync
    entities = Entity.objects.filter(
        sync_timestamp3__range=(datetime.datetime.now(),
                                datetime.datetime.now() +
                                datetime.timedelta(minutes=5)),
        status3=1)
    for entity in entities:
        web_message = None
        if entity.type == Entity.GAME:
            web_message = web_message_builder.build_game_message(
                Game.objects.get(id=entity.id))
            logger.info('sync game %s to web' % entity.id)
        if entity.type == Entity.NEWS:
            web_message = web_message_builder.build_news_message(
                News.objects.get(id=entity.id))
            logger.info('sync news %s to web' % entity.id)
        if entity.type == Entity.COLLECTION:
            web_message = web_message_builder.build_collection_message(
                Collection.objects.get(id=entity.id))
            logger.info('sync collection %s to web' % entity.id)
        if entity.type == Entity.PUZZLE:
            web_message = web_message_builder.build_puzzle_message(
                Puzzle.objects.get(id=entity.id))
            logger.info('sync puzzle %s to web' % entity.id)
        if entity.type == Entity.EVALUATION:
            web_message = web_message_builder.build_evaluation_message(
                Evaluation.objects.get(id=entity.id))
            logger.info('sync evaluation %s to web' % entity.id)
        if web_message is not None:
            MessageSender.send_web(web_message)
Example #4
0
def sync_weixin():
    #query weixin messages
    weixin_msgs = Weixin.objects.filter(
        sync_timestamp2__range=(datetime.datetime.now(),
                                datetime.datetime.now() +
                                datetime.timedelta(minutes=5)),
        status2=1)
    for msg in weixin_msgs:
        logger.info('sync msg %s to weixin' % msg.id)
        MessageSender.send_weixin(
            weixin_message_builder.build_weixin_message(msg))
def main():
    running = True
    message_queue = queue.Queue()

    print("Creating mqtt class..")
    mqtt_thread = MqttConnector()
    mqtt_thread.start()

    ## Start sensors
    temp_sensor = TemperatureSensor(message_queue)
    #ir_temp_sensor = IRTemperatureSensor(message_queue)
    #ir2_temp_sensor = IR2TemperatureSensor(message_queue)
    #gps_sensor = GpsSensor(message_queue)
    humidity_sensor = HumiditySensor(message_queue)
    pressure_sensor = PressureSensor(message_queue)
    orientation_sensor = OrientationSensor(message_queue)
    acceleration_sensor = AccelerationSensor(message_queue)
    imu_sensor = UDPReceiver(cfg.ip_imu, cfg.port_imu, message_queue, "IMU")
    seanav_sensor = UDPReceiver(cfg.ip_seanav, cfg.port_seanav, message_queue,
                                "SEANAV")

    temp_sensor.start()
    #ir_temp_sensor.start()
    #ir2_temp_sensor.start()
    #gps_sensor.start()
    humidity_sensor.start()
    pressure_sensor.start()
    orientation_sensor.start()
    acceleration_sensor.start()
    imu_sensor.start()
    seanav_sensor.start()

    ## Connect to databases
    db_handler = DBHandler(local=True, cloud=True)

    ## Wait for connected to server
    while not mqtt_thread.connected:
        continue

    print("Connected...")
    print("Start message sender")
    sender = MessageSender(message_queue, mqtt_thread, db_handler)
    sender.start()

    ## Keep from stopping program
    while (running):
        continue

    print("Program end")
 def connect_to_next_next_hop(self):
     ip, port = self.next_next_hop_info
     try:
         s = socket.create_connection((ip, port))
         self.sending_queue = queue.Queue(maxsize=0)
         self.message_sender = MessageSender(self.event_queue,
                                             self.sending_queue, s)
         self.message_sender.start()
         self.next_hop_info = self.next_next_hop_info
         # After we connect to a new client we have to check whether the dead client wasn't in posession
         # of token
         self.sending_queue.put(
             events.TokenReceivedQuestionEvent(self.last_token))
     except Exception as e:
         logger.error(e)
Example #7
0
def sync_weibo():
    # query entities needed to sync
    entities = Entity.objects.filter(
        sync_timestamp1__range=(datetime.datetime.now(),
                                datetime.datetime.now() +
                                datetime.timedelta(minutes=5)),
        status1=1)
    for entity in entities:
        weibo_message = None
        if entity.type == Entity.GAME:
            weibo_message = weibo_message_builder.build_game_message(
                Game.objects.get(id=entity.id))
            logger.info('sync game %s to weibo' % weibo_message.entity_id)
        elif entity.type == Entity.REDIER:
            weibo_message = weibo_message_builder.build_redier_message(
                Redier.objects.get(id=entity.id))
            logger.info('sync redier %s to weibo' % weibo_message.entity_id)
        elif entity.type == Entity.COLLECTION:
            weibo_message = weibo_message_builder.build_collection_message(
                Collection.objects.get(id=entity.id))
            logger.info('sync collection %s to weibo' %
                        weibo_message.entity_id)
        elif entity.type == Entity.PROBLEM:
            weibo_message = weibo_message_builder.build_problem_message(
                Problem.objects.get(id=entity.id))
            logger.info('sync problem %s to weibo' % weibo_message.entity_id)
        elif entity.type == Entity.PLAYER:
            weibo_message = weibo_message_builder.build_player_message(
                Player.objects.get(id=entity.id))
            logger.info('sync player %s to weibo' % weibo_message.entity_id)
        elif entity.type == Entity.PUZZLE:
            weibo_message = weibo_message_builder.build_puzzle_message(
                Puzzle.objects.get(id=entity.id))
            logger.info('sync puzzle %s to weibo' % weibo_message.entity_id)
        elif entity.type == Entity.NEWS:
            weibo_message = weibo_message_builder.build_news_message(
                News.objects.get(id=entity.id))
            logger.info('sync news %s to weibo' % weibo_message.entity_id)
        elif entity.type == Entity.EVALUATION:
            weibo_message = weibo_message_builder.build_evaluation_message(
                Evaluation.objects.get(id=entity.id))
            logger.info('sync evaluation %s to weibo' %
                        weibo_message.entity_id)
        if weibo_message is not None:
            MessageSender.send_weibo(weibo_message)
        else:
            logger.info('nothing to sync to weibo')
    def inner_next_hop_broken_event(self, _):
        # If we detect that the next hop connection is down we want to:
        # 1.Try to reconnect to the client
        # 2.If reconnect fails we want to connect to our next next hop
        # 3.When we succesfully connect to our next next hop we want to send recovery token question
        #   in case that the dead client was holding the token the moment he died
        ip, port = self.next_next_hop_info
        # If we are the only client left we reset the data to the initial state
        if ip == helpers.get_self_ip_address():
            self.critical_section = None
            self.next_hop_info = None
            self.next_next_hop_info = None
            if self.message_sender:
                self.message_sender.stop()
            self.sending_queue = None
            self.message_sender = None
            self.predecessor = None
            self.last_token = 0
            self.paint_queue.put({'type': DrawingQueueEvent.BOARD_OPEN})
            return

        def connect_to_next_next_hop(self):
            ip, port = self.next_next_hop_info
            try:
                s = socket.create_connection((ip, port))
                self.sending_queue = queue.Queue(maxsize=0)
                self.message_sender = MessageSender(self.event_queue,
                                                    self.sending_queue, s)
                self.message_sender.start()
                self.next_hop_info = self.next_next_hop_info
                # After we connect to a new client we have to check whether the dead client wasn't in posession
                # of token
                self.sending_queue.put(
                    events.TokenReceivedQuestionEvent(self.last_token))
            except Exception as e:
                logger.error(e)

        ip, port = self.next_hop_info
        try:
            s = socket.create_connection((ip, port))
            self.sending_queue = queue.Queue(maxsize=0)
            self.message_sender = MessageSender(self.event_queue,
                                                self.sending_queue, s)
            self.message_sender.start()
        except ConnectionRefusedError as e:
            logger.error(e)
            connect_to_next_next_hop(self)
Example #9
0
File: inbus.py Project: mlos/inbus
 def __init__(self, address=("127.0.0.1", 7222), buffer_size=65536):
     sock = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
     registry = Registry()
     self._message_receiver = MessageReceiver(
         IncomingMessageTranslator(
             [registry,
              Broadcaster(registry,
                          MessageSender(OutgoingMessageTranslator(), sock))
              ]), address, buffer_size)
def main(argv):

    client = MessageSender()
    client.connect_messaging_socket("18.214.123.134", 5050)
    client.send_message("test message")

    return
Example #11
0
def sync_web():
	#query entities needed to sync
	entities = Entity.objects.filter(sync_timestamp3__range=(datetime.datetime.now(), datetime.datetime.now()+datetime.timedelta(minutes=5)), status3=1)
	for entity in entities:
		web_message = None
		if entity.type == Entity.GAME:
			web_message = web_message_builder.build_game_message(Game.objects.get(id=entity.id))
			logger.info('sync game %s to web' % entity.id)
		if entity.type == Entity.NEWS:
			web_message = web_message_builder.build_news_message(News.objects.get(id=entity.id))
			logger.info('sync news %s to web' % entity.id)
		if entity.type == Entity.COLLECTION:
			web_message = web_message_builder.build_collection_message(Collection.objects.get(id=entity.id))
			logger.info('sync collection %s to web' % entity.id)
		if entity.type == Entity.PUZZLE:
			web_message = web_message_builder.build_puzzle_message(Puzzle.objects.get(id=entity.id))
			logger.info('sync puzzle %s to web' % entity.id)
		if entity.type == Entity.EVALUATION:
			web_message = web_message_builder.build_evaluation_message(Evaluation.objects.get(id=entity.id))
			logger.info('sync evaluation %s to web' % entity.id)
		if web_message is not None:
			MessageSender.send_web(web_message)
Example #12
0
 def __init__(self):
     self._runner_process = None
     self._control_process = None
     self._watchdog = ProcessWatchdog(config.Watchdog.CHECK_INTERVAL)
     self.push_messages_receiver = PushMessageReceiver()
     self.config_builder = ConfigurationBuilder(config.Engine.CONFIGURATION_BUILDER)
     self.message_handler = MessageHandler(self)
     self.message_sender = MessageSender()
     self.message_router = MessageRouter(self.message_sender, self.message_handler.default_message_handler)
     self.state = ManagerState.EMPTY
     self._http_client = httpclient.HTTPClient()
     self._alert_registered = False
     self.obsi_id = getnode()  # A unique identifier of this OBSI
     self._engine_running = False
     self._engine_running_lock = locks.Lock()
     self._processing_graph_set = False
     self._engine_config_builder = None
     self._keep_alive_periodic_callback = None
     self._avg_cpu = 0
     self._avg_duration = 0
     self._supported_elements_types = []
     self._alert_messages_handler = None
     self._log_messages_handler = None
Example #13
0
 def __init__(self, recipient_emails=()):
     self._read_offers_ids_from_db()
     self.message_sender = MessageSender(recipient_emails)
Example #14
0
class Manager(object):
    def __init__(self):
        self._runner_process = None
        self._control_process = None
        self._watchdog = ProcessWatchdog(config.Watchdog.CHECK_INTERVAL)
        self.push_messages_receiver = PushMessageReceiver()
        self.config_builder = ConfigurationBuilder(config.Engine.CONFIGURATION_BUILDER)
        self.message_handler = MessageHandler(self)
        self.message_sender = MessageSender()
        self.message_router = MessageRouter(self.message_sender, self.message_handler.default_message_handler)
        self.state = ManagerState.EMPTY
        self._http_client = httpclient.HTTPClient()
        self._alert_registered = False
        self.obsi_id = getnode()  # A unique identifier of this OBSI
        self._engine_running = False
        self._engine_running_lock = locks.Lock()
        self._processing_graph_set = False
        self._engine_config_builder = None
        self._keep_alive_periodic_callback = None
        self._avg_cpu = 0
        self._avg_duration = 0
        self._supported_elements_types = []
        self._alert_messages_handler = None
        self._log_messages_handler = None

    def start(self):
        app_log.info("Starting components")
        self.state = ManagerState.INITIALIZING
        self._start_runner()
        self._start_control()
        self._start_watchdog()
        self._start_push_messages_receiver()
        self._start_configuration_builder()
        self._start_message_router()
        self._start_local_rest_server()
        app_log.info("All components active")
        self.state = ManagerState.INITIALIZED
        self._start_sending_keep_alive()
        self._send_hello_message()
        self._start_io_loop()

    def _start_runner(self):
        app_log.info("Starting EE Runner on port {port}".format(port=config.Runner.Rest.PORT))
        self._runner_process = _start_remote_rest_server(config.Runner.Rest.BIN, config.Runner.Rest.PORT,
                                                         config.Runner.Rest.DEBUG)
        if self._runner_process.is_running() and self._rest_server_listening(config.Runner.Rest.BASE_URI):
            app_log.info("EERunner REST Server running")
        else:
            app_log.error("EERunner REST Server not running")
            self.exit(1)
        if self._is_engine_supported(_get_full_uri(config.Runner.Rest.BASE_URI, config.Runner.Rest.Endpoints.ENGINES)):
            app_log.info("{engine} supported by EE Runner.".format(engine=config.Engine.NAME))
        else:
            app_log.error("{engine} is not supported by EE Runner".format(engine=config.Engine.NAME))
            self.exit(1)
        if self._set_engine(_get_full_uri(config.Runner.Rest.BASE_URI, config.Runner.Rest.Endpoints.ENGINES)):
            app_log.info("{engine} set".format(engine=config.Engine.NAME))
        else:
            app_log.error("{engine} not set by EERunner".format(engine=config.Engine.NAME))
            self.exit(1)
        if self._start_engine():
            app_log.info("{engine} started".format(engine=config.Engine.NAME))
        else:
            app_log.error("{engine} failed to start".format(engine=config.Engine.NAME))
            self.exit(1)
        self._engine_running = True
        self._alert_registered = self._register_alert_uri()
        app_log.info("Alert Registration status: {status}".format(status=self._alert_registered))

    def exit(self, exit_code):
        if self._runner_process:
            while self._runner_process.is_running():
                self._runner_process.kill()
        if self._control_process:
            while self._control_process.is_running():
                self._control_process.kill()

        exit(exit_code)

    def _rest_server_listening(self, base_uri):
        for _ in xrange(config.Manager.CONNECTION_RETRIES):
            try:
                self._http_client.fetch(base_uri)
                return True
            except httpclient.HTTPError:
                return True
            except KeyboardInterrupt:
                raise
            except socket.error:
                time.sleep(config.Manager.INTERVAL_BETWEEN_CONNECTION_TRIES)

        return False

    def _is_engine_supported(self, uri):
        engine_name = config.Engine.NAME
        try:
            response = self._http_client.fetch(uri)
            return engine_name in json_decode(response.body)
        except httpclient.HTTPError as e:
            app_log.error(e.response)
            return False

    def _set_engine(self, uri):
        engine_name = config.Engine.NAME
        try:
            self._http_client.fetch(uri, method="POST", body=json_encode(engine_name))
            return True
        except httpclient.HTTPError as e:
            app_log.error(e.response)
            return False

    def _start_engine(self):
        params = dict(processing_graph=config.Engine.BASE_EMPTY_CONFIG,
                      control_socket_type=config.Engine.CONTROL_SOCKET_TYPE,
                      control_socket_endpoint=config.Engine.CONTROL_SOCKET_ENDPOINT,
                      nthreads=config.Engine.NTHREADS,
                      push_messages_type=config.Engine.PUSH_MESSAGES_SOCKET_TYPE,
                      push_messages_endpoint=config.Engine.PUSH_MESSAGES_SOCKET_ENDPOINT,
                      push_messages_channel=config.Engine.PUSH_MESSAGES_CHANNEL)
        uri = _get_full_uri(config.Runner.Rest.BASE_URI, config.Runner.Rest.Endpoints.START)
        try:
            self._http_client.fetch(uri, method="POST", body=json_encode(params))
            return True
        except httpclient.HTTPError as e:
            app_log.error(e.response)
            return False

    def _register_alert_uri(self):
        uri = _get_full_uri(config.Runner.Rest.BASE_URI, config.Runner.Rest.Endpoints.REGISTER_ALERT_URL)
        alert_uri = _get_full_uri(config.RestServer.BASE_URI, config.RestServer.Endpoints.RUNNER_ALERT)
        try:
            self._http_client.fetch(uri, method='POST', body=url_escape(alert_uri))
            return True
        except httpclient.HTTPError as e:
            app_log.error(e.response)
            return False

    def _start_control(self):
        app_log.info("Starting EE Control on port {port}".format(port=config.Control.Rest.PORT))
        self._control_process = _start_remote_rest_server(config.Control.Rest.BIN, config.Control.Rest.PORT,
                                                          config.Control.Rest.DEBUG)
        if self._control_process.is_running() and self._rest_server_listening(config.Control.Rest.BASE_URI):
            app_log.info("EEControl REST Server running")
        else:
            app_log.error("EEControl REST Server not running")
            exit(1)
        if self._is_engine_supported(
                _get_full_uri(config.Control.Rest.BASE_URI, config.Control.Rest.Endpoints.ENGINES)):
            app_log.info("{engine} supported by EE Control".format(engine=config.Engine.NAME))
        else:
            app_log.error("{engine} is not supported by EE Control".format(engine=config.Engine.NAME))
            exit(1)
        if self._set_engine(_get_full_uri(config.Control.Rest.BASE_URI, config.Control.Rest.Endpoints.ENGINES)):
            app_log.info("{engine} set by EE Control".format(engine=config.Engine.NAME))
        else:
            app_log.error("{engine} not set by EE Control".format(engine=config.Engine.NAME))
            exit(1)
        if self._connect_control():
            app_log.info("EE Control client connected to engine")
        else:
            app_log.error("EE Control client couldn't connect to engine")
            exit(1)

    def _connect_control(self):
        params = dict(address=config.Control.SOCKET_ADDRESS, type=config.Control.SOCKET_TYPE)
        uri = _get_full_uri(config.Control.Rest.BASE_URI, config.Control.Rest.Endpoints.CONNECT)
        try:
            self._http_client.fetch(uri, method="POST", body=json_encode(params))
            return True
        except httpclient.HTTPError as e:
            app_log.error(e.response)
            return False

    def _start_watchdog(self):
        app_log.info("Starting ProcessWatchdog")
        self._watchdog.register_process(self._runner_process, self._process_died)
        self._watchdog.register_process(self._control_process, self._process_died)
        self._watchdog.start()

    @gen.coroutine
    def _process_died(self, process):
        if process == self._runner_process:
            app_log.error("EE Runner REST server has died")
            with (yield self._engine_running_lock.acquire()):
                self._engine_running = False
                # TODO: add recovering logic or at least send error
        elif process == self._control_process:
            app_log.error("EE Control REST server has died")
            # TODO: Add real handling
        else:
            app_log.error("Unknown process dies")

    def _start_push_messages_receiver(self):
        app_log.info("Starting PushMessagesReceiver and registering Alert handling")
        url = None  # this will force the message sender to use the URL based on the message type
        send_alert_messages = functools.partial(self.message_sender.send_push_messages, messages.Alert, self.obsi_id,
                                                url)
        self._alert_messages_handler = PushMessageHandler(send_alert_messages,
                                                          config.PushMessages.Alert.BUFFER_SIZE,
                                                          config.PushMessages.Alert.BUFFER_TIMEOUT)

        self.push_messages_receiver.register_message_handler('ALERT', self._alert_messages_handler.add)
        self.push_messages_receiver.connect(config.PushMessages.SOCKET_ADDRESS,
                                            config.PushMessages.SOCKET_FAMILY,
                                            config.PushMessages.RETRY_INTERVAL)

    def _start_configuration_builder(self):
        app_log.info("Starting EE Configuration Builder")
        try:
            uri = _get_full_uri(config.Control.Rest.BASE_URI, config.Control.Rest.Endpoints.SUPPORTED_ELEMENTS)
            response = self._http_client.fetch(uri)
            self._supported_elements_types = set(json_decode(response.body))
            supported_blocks = set(self.config_builder.supported_blocks())
            blocks_from_engine = set(self.config_builder.supported_blocks_from_supported_engine_elements_types(
                self._supported_elements_types))
            if supported_blocks != blocks_from_engine:
                app_log.warning("There is a mismatched between supported blocks by OBSI "
                                "and supported blocks by engine")

        except httpclient.HTTPError:
            app_log.error("Unable to connect to EE control in order to get a list of supported elements types")

    @gen.coroutine
    def _start_message_router(self):
        app_log.info("Starting MessageRouter")
        self._register_messages_handler()
        yield self.message_router.start()

    def _register_messages_handler(self):
        app_log.info("Registering handlers for messages")
        for message, handler in self.message_handler.registered_message_handlers.iteritems():
            self.message_router.register_message_handler(message, handler)

    def _start_local_rest_server(self):
        app_log.info("Starting local REST server on port {port}".format(port=config.RestServer.PORT))
        rest_server.start(self)

    def _start_sending_keep_alive(self):
        self._keep_alive_periodic_callback = PeriodicCallback(self._send_keep_alive, config.KeepAlive.INTERVAL)
        self._keep_alive_periodic_callback.start()

    @gen.coroutine
    def _send_keep_alive(self):
        received = yield self.message_sender.send_message_ignore_response(messages.KeepAlive(dpid=self.obsi_id))
        if not received:
            app_log.error('KeepAlive message received an error response from OBC')

    @gen.coroutine
    def _send_hello_message(self):
        app_log.info("Creating and sending Hello Message")
        while True:
            hello_message = messages.Hello(dpid=self.obsi_id, version=config.OPENBOX_VERSION,
                                           capabilities=self.get_capabilities())
            received = yield self.message_sender.send_message_ignore_response(hello_message)
            if received:
                break
            else:
                app_log.error("Hello message received an error response from OBC")
                yield gen.sleep(config.Manager.INTERVAL_BETWEEN_CONNECTION_TRIES)

    def get_capabilities(self):
        proto_messages = []
        if config.Engine.Capabilities.MODULE_INSTALLATION:
            proto_messages.append(messages.AddCustomModuleRequest.__name__)
        if config.Engine.Capabilities.MODULE_REMOVAL:
            proto_messages.append(messages.RemoveCustomModuleRequest.__name__)
        processing_blocks = self.config_builder.supported_blocks_from_supported_engine_elements_types(
            self._supported_elements_types)
        match_fields = self.config_builder.supported_match_fields()
        complex_match = self.config_builder.supported_complex_match()
        protocol_analyser_protocols = self.config_builder.supported_protocol_analyser_protocols()

        return dict(proto_messages=proto_messages, processing_blocks=processing_blocks,
                    match_fields=match_fields, complex_match=complex_match,
                    protocol_analyser_protocols=protocol_analyser_protocols)

    def _start_io_loop(self):
        app_log.info("Starting the IOLoop")
        IOLoop.current().start()

    @gen.coroutine
    def handle_runner_alert(self, errors):
        with (yield self._engine_running_lock.acquire()):
            self._engine_running = False
        app_log.error("Engine stopped working: {errors}".format(errors=errors))

    @gen.coroutine
    def get_engine_global_stats(self):
        client = httpclient.AsyncHTTPClient()
        memory_uri = _get_full_uri(config.Runner.Rest.BASE_URI, config.Runner.Rest.Endpoints.MEMORY)
        cpu_uri = _get_full_uri(config.Runner.Rest.BASE_URI, config.Runner.Rest.Endpoints.CPU)
        uptime_uri = _get_full_uri(config.Runner.Rest.BASE_URI, config.Runner.Rest.Endpoints.UPTIME)

        memory, cpu, uptime = yield [client.fetch(memory_uri), client.fetch(cpu_uri), client.fetch(uptime_uri)]
        memory, cpu, uptime = json_decode(memory.body), json_decode(cpu.body), json_decode(uptime.body)

        cpu_count = cpu['cpu_count']
        current_load = cpu['cpu_percent'] / 100.0 / cpu_count
        duration = cpu['measurement_time']
        self._avg_cpu = (current_load * duration + self._avg_cpu * self._avg_duration) / (duration + self._avg_duration)
        self._avg_duration += duration
        stats = dict(memory_rss=memory['rss'], memory_vms=memory['vms'], memory_percent=memory['percent'],
                     cpus=cpu_count, current_load=current_load, avg_load=self._avg_cpu,
                     avg_minutes=self._avg_duration / 60.0, uptime=uptime['uptime'])
        raise gen.Return(stats)

    @gen.coroutine
    def reset_engine_global_stats(self):
        self._avg_cpu = 0
        self._avg_duration = 0

    @gen.coroutine
    def read_block_value(self, block_name, handler_name):
        with (yield self._engine_running_lock.acquire()):
            if not self._engine_running:
                raise EngineNotRunningError()
        if not self._processing_graph_set or self._engine_config_builder is None:
            raise ProcessingGraphNotSetError()
        else:
            (engine_element_name,
             engine_handler_name,
             transform_function) = self._engine_config_builder.translate_block_read_handler(block_name,
                                                                                            handler_name)
            element = url_escape(engine_element_name)
            handler = url_escape(engine_handler_name)
            uri = _get_full_uri(config.Control.Rest.BASE_URI,
                                config.Control.Rest.Endpoints.HANDLER_PATTERN.format(element=element,
                                                                                     handler=handler))
            client = httpclient.AsyncHTTPClient()
            response = yield client.fetch(uri)
            raise gen.Return(transform_function(json_decode(response.body)))

    @gen.coroutine
    def write_block_value(self, block_name, handler_name, value):
        with (yield self._engine_running_lock):
            if not self._engine_running:
                raise EngineNotRunningError()
        if not self._processing_graph_set or self._engine_config_builder is None:
            raise ProcessingGraphNotSetError()
        else:
            (engine_element_name,
             engine_handler_name,
             transform_function) = self._engine_config_builder.translate_block_write_handler(block_name,
                                                                                             handler_name)
            uri = _get_full_uri(config.Control.Rest.BASE_URI,
                                config.Control.Rest.Endpoints.HANDLER_PATTERN.format(element=engine_element_name,
                                                                                     handler=engine_handler_name))
            body = json_encode(transform_function(value))
            client = httpclient.AsyncHTTPClient()
            yield client.fetch(uri, method='POST', body=body)
            raise gen.Return(True)

    @gen.coroutine
    def set_processing_graph(self, required_modules, blocks, connections):
        processing_graph = dict(requirements=required_modules, blocks=blocks, connections=connections)
        self._engine_config_builder = self.config_builder.engine_config_builder_from_dict(processing_graph,
                                                                                          config.Engine.REQUIREMENTS)
        engine_config = self._engine_config_builder.to_engine_config()
        app_log.debug("Setting processing graph to:\n%s" % engine_config)
        client = httpclient.AsyncHTTPClient()

        uri = _get_full_uri(config.Control.Rest.BASE_URI, config.Control.Rest.Endpoints.CONFIG)
        yield client.fetch(uri, method='POST', body=json_encode(engine_config))

        # make sure we are stable in the new config
        # the config is in the same URI but with a GET method
        response = yield client.fetch(uri)
        new_config = json_decode(response.body)
        if engine_config in new_config:
            self._processing_graph_set = True
        else:
            app_log.error("Unable to set processing graph")

    @gen.coroutine
    def set_parameters(self, params):
        config.KeepAlive.INTERVAL = params.get('keepalive_interval', config.KeepAlive.INTERVAL)
        config.PushMessages.Alert.BUFFER_SIZE = params.get('alert_messages_buffer_size',
                                                           config.PushMessages.Alert.BUFFER_SIZE)
        config.PushMessages.Alert.BUFFER_TIMEOUT = params.get('alert_messages_buffer_timeout',
                                                              config.PushMessages.Alert.BUFFER_TIMEOUT * 1000.0) / 1000.0
        config.PushMessages.Log.BUFFER_SIZE = params.get('log_messages_buffer_size',
                                                         config.PushMessages.Log.BUFFER_SIZE)
        config.PushMessages.Log.BUFFER_TIMEOUT = params.get('log_messages_buffer_timeout',
                                                            config.PushMessages.Log.BUFFER_TIMEOUT * 1000.0) / 1000.0
        old_server, old_port = config.PushMessages.Log.SERVER_ADDRESS, config.PushMessages.Log.SERVER_PORT
        config.PushMessages.Log.SERVER_ADDRESS = params.get('log_server_address',
                                                            config.PushMessages.Log.SERVER_ADDRESS)
        config.PushMessages.Log.SERVER_PORT = params.get('log_server_port', config.PushMessages.Log.SERVER_PORT)
        new_server, new_port = config.PushMessages.Log.SERVER_ADDRESS, config.PushMessages.Log.SERVER_PORT
        config.PushMessages.Log._SERVER_CHANGED = new_server != old_server or new_port != old_port

        self._update_components()

    def _update_components(self):
        # update keepalive
        if self._keep_alive_periodic_callback:
            self._keep_alive_periodic_callback.stop()
            self._start_sending_keep_alive()

        # update alert push messages
        if self._alert_messages_handler:
            self._alert_messages_handler.buffer_size = config.PushMessages.Alert.BUFFER_SIZE
            self._alert_messages_handler.buffer_timeout = config.PushMessages.Alert.BUFFER_TIMEOUT

        # update log push messages
        if config.PushMessages.Log.SERVER_PORT and config.PushMessages.Log.SERVER_PORT:
            url = "http://{host}:{port}/message/Log".format(host=config.PushMessages.Log.SERVER_ADDRESS,
                                                            port=config.PushMessages.Log.SERVER_PORT)
            send_log_messages = functools.partial(self.message_sender.send_push_messages, messages.Log,
                                                  self.obsi_id, url)
            if config.PushMessages.Log._SERVER_CHANGED:
                # better close it and make it start over
                if self._log_messages_handler:
                    self._log_messages_handler.close()
                self.push_messages_receiver.unregister_message_handler('LOG')
                self._log_messages_handler = PushMessageHandler(send_log_messages,
                                                                config.PushMessages.Log.BUFFER_SIZE,
                                                                config.PushMessages.Log.BUFFER_TIMEOUT)
                self.push_messages_receiver.register_message_handler('LOG', self._log_messages_handler.add)
        if self._log_messages_handler:
            self._log_messages_handler.buffer_size = config.PushMessages.Log.BUFFER_SIZE
            self._log_messages_handler.buffer_timeout = config.PushMessages.Log.BUFFER_TIMEOUT

    def get_parameters(self, parameters):
        result = dict(keepalive_interval=int(config.KeepAlive.INTERVAL),
                      alert_messages_buffer_size=config.PushMessages.Alert.BUFFER_SIZE,
                      alert_messages_buffer_timeout=int(config.PushMessages.Alert.BUFFER_TIMEOUT * 1000),
                      log_messages_buffer_size=config.PushMessages.Log.BUFFER_SIZE,
                      log_messages_buffer_timeout=int(config.PushMessages.Log.BUFFER_TIMEOUT * 1000),
                      log_server_address=config.PushMessages.Log.SERVER_ADDRESS,
                      log_server_port=config.PushMessages.Log.SERVER_PORT)
        if not parameters:
            # an empty list means they want all of them
            return result
        else:
            try:
                partial = {}
                for parameter in parameters:
                    partial[parameter] = result[parameter]

                return partial
            except KeyError as e:
                raise UnknownRequestedParameter("Request unknown parameter {parm}".format(parm=e.message))

    @gen.coroutine
    def add_custom_module(self, name, content, content_type, encoding, translation):
        if content:
            if encoding.lower() != 'base64':
                raise UnsupportedModuleDataEncoding("Unknown encoding '{enc}' for module content".format(enc=encoding))
            yield self._install_package(name, content, encoding.lower())
            yield self._update_running_config_with_package(name)
            yield self._update_supported_elements()
            self.config_builder.add_custom_module(name, translation)

    @gen.coroutine
    def _install_package(self, name, content, encoding):
        package = dict(name=name, data=content, encoding=encoding)
        client = httpclient.AsyncHTTPClient()
        uri = _get_full_uri(config.Runner.Rest.BASE_URI, config.Runner.Rest.Endpoints.INSTALL)
        yield client.fetch(uri, method='POST', body=json_encode(package))

    @gen.coroutine
    def _update_running_config_with_package(self, name):
        client = httpclient.AsyncHTTPClient()
        uri = _get_full_uri(config.Control.Rest.BASE_URI, config.Control.Rest.Endpoints.LOADED_PACKAGES)
        yield client.fetch(uri, method='POST', body=json_encode(name))

    @gen.coroutine
    def _update_supported_elements(self):
        client = httpclient.AsyncHTTPClient()
        uri = _get_full_uri(config.Control.Rest.BASE_URI, config.Control.Rest.Endpoints.SUPPORTED_ELEMENTS)
        response = yield client.fetch(uri)
        self._supported_elements_types = set(json_decode(response.body))
Example #15
0
class Manager(object):
    def __init__(self):
        self._runner_process = None
        self._control_process = None
        self._watchdog = ProcessWatchdog(config.Watchdog.CHECK_INTERVAL)
        self.push_messages_receiver = PushMessageReceiver()
        self.config_builder = ConfigurationBuilder(
            config.Engine.CONFIGURATION_BUILDER)
        self.message_handler = MessageHandler(self)
        self.message_sender = MessageSender()
        self.message_router = MessageRouter(
            self.message_sender, self.message_handler.default_message_handler)
        self.state = ManagerState.EMPTY
        self._http_client = httpclient.HTTPClient()
        self._alert_registered = False
        self.obsi_id = getnode()  # A unique identifier of this OBSI
        self._engine_running = False
        self._engine_running_lock = locks.Lock()
        self._processing_graph_set = False
        self._engine_config_builder = None
        self._keep_alive_periodic_callback = None
        self._avg_cpu = 0
        self._avg_duration = 0
        self._supported_elements_types = []
        self._alert_messages_handler = None
        self._log_messages_handler = None

    def start(self):
        app_log.info("Starting components")
        self.state = ManagerState.INITIALIZING
        self._start_runner()
        self._start_control()
        self._start_watchdog()
        self._start_push_messages_receiver()
        self._start_configuration_builder()
        self._start_message_router()
        self._start_local_rest_server()
        app_log.info("All components active")
        self.state = ManagerState.INITIALIZED
        self._start_sending_keep_alive()
        self._send_hello_message()
        self._start_io_loop()

    def _start_runner(self):
        app_log.info("Starting EE Runner on port {port}".format(
            port=config.Runner.Rest.PORT))
        self._runner_process = _start_remote_rest_server(
            config.Runner.Rest.BIN, config.Runner.Rest.PORT,
            config.Runner.Rest.DEBUG)
        if self._runner_process.is_running() and self._rest_server_listening(
                config.Runner.Rest.BASE_URI):
            app_log.info("EERunner REST Server running")
        else:
            app_log.error("EERunner REST Server not running")
            self.exit(1)
        if self._is_engine_supported(
                _get_full_uri(config.Runner.Rest.BASE_URI,
                              config.Runner.Rest.Endpoints.ENGINES)):
            app_log.info("{engine} supported by EE Runner.".format(
                engine=config.Engine.NAME))
        else:
            app_log.error("{engine} is not supported by EE Runner".format(
                engine=config.Engine.NAME))
            self.exit(1)
        if self._set_engine(
                _get_full_uri(config.Runner.Rest.BASE_URI,
                              config.Runner.Rest.Endpoints.ENGINES)):
            app_log.info("{engine} set".format(engine=config.Engine.NAME))
        else:
            app_log.error("{engine} not set by EERunner".format(
                engine=config.Engine.NAME))
            self.exit(1)
        if self._start_engine():
            app_log.info("{engine} started".format(engine=config.Engine.NAME))
        else:
            app_log.error(
                "{engine} failed to start".format(engine=config.Engine.NAME))
            self.exit(1)
        self._engine_running = True
        self._alert_registered = self._register_alert_uri()
        app_log.info("Alert Registration status: {status}".format(
            status=self._alert_registered))

    def exit(self, exit_code):
        if self._runner_process:
            while self._runner_process.is_running():
                self._runner_process.kill()
        if self._control_process:
            while self._control_process.is_running():
                self._control_process.kill()

        exit(exit_code)

    def _rest_server_listening(self, base_uri):
        for _ in xrange(config.Manager.CONNECTION_RETRIES):
            try:
                self._http_client.fetch(base_uri)
                return True
            except httpclient.HTTPError:
                return True
            except KeyboardInterrupt:
                raise
            except socket.error:
                time.sleep(config.Manager.INTERVAL_BETWEEN_CONNECTION_TRIES)

        return False

    def _is_engine_supported(self, uri):
        engine_name = config.Engine.NAME
        try:
            response = self._http_client.fetch(uri)
            return engine_name in json_decode(response.body)
        except httpclient.HTTPError as e:
            app_log.error(e.response)
            return False

    def _set_engine(self, uri):
        engine_name = config.Engine.NAME
        try:
            self._http_client.fetch(uri,
                                    method="POST",
                                    body=json_encode(engine_name))
            return True
        except httpclient.HTTPError as e:
            app_log.error(e.response)
            return False

    def _start_engine(self):
        params = dict(
            processing_graph=config.Engine.BASE_EMPTY_CONFIG,
            control_socket_type=config.Engine.CONTROL_SOCKET_TYPE,
            control_socket_endpoint=config.Engine.CONTROL_SOCKET_ENDPOINT,
            nthreads=config.Engine.NTHREADS,
            push_messages_type=config.Engine.PUSH_MESSAGES_SOCKET_TYPE,
            push_messages_endpoint=config.Engine.PUSH_MESSAGES_SOCKET_ENDPOINT,
            push_messages_channel=config.Engine.PUSH_MESSAGES_CHANNEL)
        uri = _get_full_uri(config.Runner.Rest.BASE_URI,
                            config.Runner.Rest.Endpoints.START)
        try:
            self._http_client.fetch(uri,
                                    method="POST",
                                    body=json_encode(params))
            return True
        except httpclient.HTTPError as e:
            app_log.error(e.response)
            return False

    def _register_alert_uri(self):
        uri = _get_full_uri(config.Runner.Rest.BASE_URI,
                            config.Runner.Rest.Endpoints.REGISTER_ALERT_URL)
        alert_uri = _get_full_uri(config.RestServer.BASE_URI,
                                  config.RestServer.Endpoints.RUNNER_ALERT)
        try:
            self._http_client.fetch(uri,
                                    method='POST',
                                    body=url_escape(alert_uri))
            return True
        except httpclient.HTTPError as e:
            app_log.error(e.response)
            return False

    def _start_control(self):
        app_log.info("Starting EE Control on port {port}".format(
            port=config.Control.Rest.PORT))
        self._control_process = _start_remote_rest_server(
            config.Control.Rest.BIN, config.Control.Rest.PORT,
            config.Control.Rest.DEBUG)
        if self._control_process.is_running() and self._rest_server_listening(
                config.Control.Rest.BASE_URI):
            app_log.info("EEControl REST Server running")
        else:
            app_log.error("EEControl REST Server not running")
            exit(1)
        if self._is_engine_supported(
                _get_full_uri(config.Control.Rest.BASE_URI,
                              config.Control.Rest.Endpoints.ENGINES)):
            app_log.info("{engine} supported by EE Control".format(
                engine=config.Engine.NAME))
        else:
            app_log.error("{engine} is not supported by EE Control".format(
                engine=config.Engine.NAME))
            exit(1)
        if self._set_engine(
                _get_full_uri(config.Control.Rest.BASE_URI,
                              config.Control.Rest.Endpoints.ENGINES)):
            app_log.info(
                "{engine} set by EE Control".format(engine=config.Engine.NAME))
        else:
            app_log.error("{engine} not set by EE Control".format(
                engine=config.Engine.NAME))
            exit(1)
        if self._connect_control():
            app_log.info("EE Control client connected to engine")
        else:
            app_log.error("EE Control client couldn't connect to engine")
            exit(1)

    def _connect_control(self):
        params = dict(address=config.Control.SOCKET_ADDRESS,
                      type=config.Control.SOCKET_TYPE)
        uri = _get_full_uri(config.Control.Rest.BASE_URI,
                            config.Control.Rest.Endpoints.CONNECT)
        try:
            self._http_client.fetch(uri,
                                    method="POST",
                                    body=json_encode(params))
            return True
        except httpclient.HTTPError as e:
            app_log.error(e.response)
            return False

    def _start_watchdog(self):
        app_log.info("Starting ProcessWatchdog")
        self._watchdog.register_process(self._runner_process,
                                        self._process_died)
        self._watchdog.register_process(self._control_process,
                                        self._process_died)
        self._watchdog.start()

    @gen.coroutine
    def _process_died(self, process):
        if process == self._runner_process:
            app_log.error("EE Runner REST server has died")
            with (yield self._engine_running_lock.acquire()):
                self._engine_running = False
                # TODO: add recovering logic or at least send error
        elif process == self._control_process:
            app_log.error("EE Control REST server has died")
            # TODO: Add real handling
        else:
            app_log.error("Unknown process dies")

    def _start_push_messages_receiver(self):
        app_log.info(
            "Starting PushMessagesReceiver and registering Alert handling")
        url = None  # this will force the message sender to use the URL based on the message type
        send_alert_messages = functools.partial(
            self.message_sender.send_push_messages, messages.Alert,
            self.obsi_id, url)
        self._alert_messages_handler = PushMessageHandler(
            send_alert_messages, config.PushMessages.Alert.BUFFER_SIZE,
            config.PushMessages.Alert.BUFFER_TIMEOUT)

        self.push_messages_receiver.register_message_handler(
            'ALERT', self._alert_messages_handler.add)
        self.push_messages_receiver.connect(config.PushMessages.SOCKET_ADDRESS,
                                            config.PushMessages.SOCKET_FAMILY,
                                            config.PushMessages.RETRY_INTERVAL)

    def _start_configuration_builder(self):
        app_log.info("Starting EE Configuration Builder")
        try:
            uri = _get_full_uri(
                config.Control.Rest.BASE_URI,
                config.Control.Rest.Endpoints.SUPPORTED_ELEMENTS)
            response = self._http_client.fetch(uri)
            self._supported_elements_types = set(json_decode(response.body))
            supported_blocks = set(self.config_builder.supported_blocks())
            blocks_from_engine = set(
                self.config_builder.
                supported_blocks_from_supported_engine_elements_types(
                    self._supported_elements_types))
            if supported_blocks != blocks_from_engine:
                app_log.warning(
                    "There is a mismatched between supported blocks by OBSI "
                    "and supported blocks by engine")

        except httpclient.HTTPError:
            app_log.error(
                "Unable to connect to EE control in order to get a list of supported elements types"
            )

    @gen.coroutine
    def _start_message_router(self):
        app_log.info("Starting MessageRouter")
        self._register_messages_handler()
        yield self.message_router.start()

    def _register_messages_handler(self):
        app_log.info("Registering handlers for messages")
        for message, handler in self.message_handler.registered_message_handlers.iteritems(
        ):
            self.message_router.register_message_handler(message, handler)

    def _start_local_rest_server(self):
        app_log.info("Starting local REST server on port {port}".format(
            port=config.RestServer.PORT))
        rest_server.start(self)

    def _start_sending_keep_alive(self):
        self._keep_alive_periodic_callback = PeriodicCallback(
            self._send_keep_alive, config.KeepAlive.INTERVAL)
        self._keep_alive_periodic_callback.start()

    @gen.coroutine
    def _send_keep_alive(self):
        received = yield self.message_sender.send_message_ignore_response(
            messages.KeepAlive(dpid=self.obsi_id))
        if not received:
            app_log.error(
                'KeepAlive message received an error response from OBC')

    @gen.coroutine
    def _send_hello_message(self):
        app_log.info("Creating and sending Hello Message")
        while True:
            hello_message = messages.Hello(
                dpid=self.obsi_id,
                version=config.OPENBOX_VERSION,
                capabilities=self.get_capabilities())
            received = yield self.message_sender.send_message_ignore_response(
                hello_message)
            if received:
                break
            else:
                app_log.error(
                    "Hello message received an error response from OBC")
                yield gen.sleep(
                    config.Manager.INTERVAL_BETWEEN_CONNECTION_TRIES)

    def get_capabilities(self):
        proto_messages = []
        if config.Engine.Capabilities.MODULE_INSTALLATION:
            proto_messages.append(messages.AddCustomModuleRequest.__name__)
        if config.Engine.Capabilities.MODULE_REMOVAL:
            proto_messages.append(messages.RemoveCustomModuleRequest.__name__)
        processing_blocks = self.config_builder.supported_blocks_from_supported_engine_elements_types(
            self._supported_elements_types)
        match_fields = self.config_builder.supported_match_fields()
        complex_match = self.config_builder.supported_complex_match()
        protocol_analyser_protocols = self.config_builder.supported_protocol_analyser_protocols(
        )

        return dict(proto_messages=proto_messages,
                    processing_blocks=processing_blocks,
                    match_fields=match_fields,
                    complex_match=complex_match,
                    protocol_analyser_protocols=protocol_analyser_protocols)

    def _start_io_loop(self):
        app_log.info("Starting the IOLoop")
        IOLoop.current().start()

    @gen.coroutine
    def handle_runner_alert(self, errors):
        with (yield self._engine_running_lock.acquire()):
            self._engine_running = False
        app_log.error("Engine stopped working: {errors}".format(errors=errors))

    @gen.coroutine
    def get_engine_global_stats(self):
        client = httpclient.AsyncHTTPClient(
            request_timeout=config.Manager.REQUEST_TIMEOUT)
        memory_uri = _get_full_uri(config.Runner.Rest.BASE_URI,
                                   config.Runner.Rest.Endpoints.MEMORY)
        cpu_uri = _get_full_uri(config.Runner.Rest.BASE_URI,
                                config.Runner.Rest.Endpoints.CPU)
        uptime_uri = _get_full_uri(config.Runner.Rest.BASE_URI,
                                   config.Runner.Rest.Endpoints.UPTIME)

        memory, cpu, uptime = yield [
            client.fetch(memory_uri),
            client.fetch(cpu_uri),
            client.fetch(uptime_uri)
        ]
        memory, cpu, uptime = json_decode(memory.body), json_decode(
            cpu.body), json_decode(uptime.body)

        cpu_count = cpu['cpu_count']
        current_load = cpu['cpu_percent'] / 100.0 / cpu_count
        duration = cpu['measurement_time']
        self._avg_cpu = (current_load * duration + self._avg_cpu *
                         self._avg_duration) / (duration + self._avg_duration)
        self._avg_duration += duration
        stats = dict(memory_rss=memory['rss'],
                     memory_vms=memory['vms'],
                     memory_percent=memory['percent'],
                     cpus=cpu_count,
                     current_load=current_load,
                     avg_load=self._avg_cpu,
                     avg_minutes=self._avg_duration / 60.0,
                     uptime=uptime['uptime'])
        raise gen.Return(stats)

    @gen.coroutine
    def reset_engine_global_stats(self):
        self._avg_cpu = 0
        self._avg_duration = 0

    @gen.coroutine
    def read_block_value(self, block_name, handler_name):
        with (yield self._engine_running_lock.acquire()):
            if not self._engine_running:
                raise EngineNotRunningError()
        if not self._processing_graph_set or self._engine_config_builder is None:
            raise ProcessingGraphNotSetError()
        else:
            (engine_element_name, engine_handler_name, transform_function
             ) = self._engine_config_builder.translate_block_read_handler(
                 block_name, handler_name)
            element = url_escape(engine_element_name)
            handler = url_escape(engine_handler_name)
            uri = _get_full_uri(
                config.Control.Rest.BASE_URI,
                config.Control.Rest.Endpoints.HANDLER_PATTERN.format(
                    element=element, handler=handler))
            client = httpclient.AsyncHTTPClient(
                request_timeout=config.Manager.REQUEST_TIMEOUT)
            response = yield client.fetch(uri)
            raise gen.Return(transform_function(json_decode(response.body)))

    @gen.coroutine
    def write_block_value(self, block_name, handler_name, value):
        with (yield self._engine_running_lock):
            if not self._engine_running:
                raise EngineNotRunningError()
        if not self._processing_graph_set or self._engine_config_builder is None:
            raise ProcessingGraphNotSetError()
        else:
            (engine_element_name, engine_handler_name, transform_function
             ) = self._engine_config_builder.translate_block_write_handler(
                 block_name, handler_name)
            uri = _get_full_uri(
                config.Control.Rest.BASE_URI,
                config.Control.Rest.Endpoints.HANDLER_PATTERN.format(
                    element=engine_element_name, handler=engine_handler_name))
            body = json_encode(transform_function(value))
            client = httpclient.AsyncHTTPClient(
                request_timeout=config.Manager.REQUEST_TIMEOUT)
            yield client.fetch(uri, method='POST', body=body)
            raise gen.Return(True)

    @gen.coroutine
    def set_processing_graph(self, required_modules, blocks, connections):
        processing_graph = dict(requirements=required_modules,
                                blocks=blocks,
                                connections=connections)
        self._engine_config_builder = self.config_builder.engine_config_builder_from_dict(
            processing_graph, config.Engine.REQUIREMENTS)
        engine_config = self._engine_config_builder.to_engine_config()
        app_log.debug("Setting processing graph to:\n%s" % engine_config)
        client = httpclient.AsyncHTTPClient(
            request_timeout=config.Manager.REQUEST_TIMEOUT)

        uri = _get_full_uri(config.Control.Rest.BASE_URI,
                            config.Control.Rest.Endpoints.CONFIG)
        yield client.fetch(uri, method='POST', body=json_encode(engine_config))

        # make sure we are stable in the new config
        # the config is in the same URI but with a GET method
        response = yield client.fetch(uri)
        new_config = json_decode(response.body)
        if engine_config in new_config:
            self._processing_graph_set = True
        else:
            app_log.error("Unable to set processing graph")

    @gen.coroutine
    def set_parameters(self, params):
        config.KeepAlive.INTERVAL = params.get('keepalive_interval',
                                               config.KeepAlive.INTERVAL)
        config.PushMessages.Alert.BUFFER_SIZE = params.get(
            'alert_messages_buffer_size',
            config.PushMessages.Alert.BUFFER_SIZE)
        config.PushMessages.Alert.BUFFER_TIMEOUT = params.get(
            'alert_messages_buffer_timeout',
            config.PushMessages.Alert.BUFFER_TIMEOUT * 1000.0) / 1000.0
        config.PushMessages.Log.BUFFER_SIZE = params.get(
            'log_messages_buffer_size', config.PushMessages.Log.BUFFER_SIZE)
        config.PushMessages.Log.BUFFER_TIMEOUT = params.get(
            'log_messages_buffer_timeout',
            config.PushMessages.Log.BUFFER_TIMEOUT * 1000.0) / 1000.0
        old_server, old_port = config.PushMessages.Log.SERVER_ADDRESS, config.PushMessages.Log.SERVER_PORT
        config.PushMessages.Log.SERVER_ADDRESS = params.get(
            'log_server_address', config.PushMessages.Log.SERVER_ADDRESS)
        config.PushMessages.Log.SERVER_PORT = params.get(
            'log_server_port', config.PushMessages.Log.SERVER_PORT)
        new_server, new_port = config.PushMessages.Log.SERVER_ADDRESS, config.PushMessages.Log.SERVER_PORT
        config.PushMessages.Log._SERVER_CHANGED = new_server != old_server or new_port != old_port

        self._update_components()

    def _update_components(self):
        # update keepalive
        if self._keep_alive_periodic_callback:
            self._keep_alive_periodic_callback.stop()
            self._start_sending_keep_alive()

        # update alert push messages
        if self._alert_messages_handler:
            self._alert_messages_handler.buffer_size = config.PushMessages.Alert.BUFFER_SIZE
            self._alert_messages_handler.buffer_timeout = config.PushMessages.Alert.BUFFER_TIMEOUT

        # update log push messages
        if config.PushMessages.Log.SERVER_PORT and config.PushMessages.Log.SERVER_PORT:
            url = "http://{host}:{port}/message/Log".format(
                host=config.PushMessages.Log.SERVER_ADDRESS,
                port=config.PushMessages.Log.SERVER_PORT)
            send_log_messages = functools.partial(
                self.message_sender.send_push_messages, messages.Log,
                self.obsi_id, url)
            if config.PushMessages.Log._SERVER_CHANGED:
                # better close it and make it start over
                if self._log_messages_handler:
                    self._log_messages_handler.close()
                self.push_messages_receiver.unregister_message_handler('LOG')
                self._log_messages_handler = PushMessageHandler(
                    send_log_messages, config.PushMessages.Log.BUFFER_SIZE,
                    config.PushMessages.Log.BUFFER_TIMEOUT)
                self.push_messages_receiver.register_message_handler(
                    'LOG', self._log_messages_handler.add)
        if self._log_messages_handler:
            self._log_messages_handler.buffer_size = config.PushMessages.Log.BUFFER_SIZE
            self._log_messages_handler.buffer_timeout = config.PushMessages.Log.BUFFER_TIMEOUT

    def get_parameters(self, parameters):
        result = dict(
            keepalive_interval=int(config.KeepAlive.INTERVAL),
            alert_messages_buffer_size=config.PushMessages.Alert.BUFFER_SIZE,
            alert_messages_buffer_timeout=int(
                config.PushMessages.Alert.BUFFER_TIMEOUT * 1000),
            log_messages_buffer_size=config.PushMessages.Log.BUFFER_SIZE,
            log_messages_buffer_timeout=int(
                config.PushMessages.Log.BUFFER_TIMEOUT * 1000),
            log_server_address=config.PushMessages.Log.SERVER_ADDRESS,
            log_server_port=config.PushMessages.Log.SERVER_PORT)
        if not parameters:
            # an empty list means they want all of them
            return result
        else:
            try:
                partial = {}
                for parameter in parameters:
                    partial[parameter] = result[parameter]

                return partial
            except KeyError as e:
                raise UnknownRequestedParameter(
                    "Request unknown parameter {parm}".format(parm=e.message))

    @gen.coroutine
    def add_custom_module(self, name, content, content_type, encoding,
                          translation):
        if content:
            if encoding.lower() != 'base64':
                raise UnsupportedModuleDataEncoding(
                    "Unknown encoding '{enc}' for module content".format(
                        enc=encoding))
            yield self._install_package(name, content, encoding.lower())
            yield self._update_running_config_with_package(name)
            yield self._update_supported_elements()
            self.config_builder.add_custom_module(name, translation)

    @gen.coroutine
    def _install_package(self, name, content, encoding):
        package = dict(name=name, data=content, encoding=encoding)
        client = httpclient.AsyncHTTPClient(
            request_timeout=config.Manager.REQUEST_TIMEOUT)
        uri = _get_full_uri(config.Runner.Rest.BASE_URI,
                            config.Runner.Rest.Endpoints.INSTALL)
        yield client.fetch(uri, method='POST', body=json_encode(package))

    @gen.coroutine
    def _update_running_config_with_package(self, name):
        client = httpclient.AsyncHTTPClient(
            request_timeout=config.Manager.REQUEST_TIMEOUT)
        uri = _get_full_uri(config.Control.Rest.BASE_URI,
                            config.Control.Rest.Endpoints.LOADED_PACKAGES)
        yield client.fetch(uri, method='POST', body=json_encode(name))

    @gen.coroutine
    def _update_supported_elements(self):
        client = httpclient.AsyncHTTPClient(
            request_timeout=config.Manager.REQUEST_TIMEOUT)
        uri = _get_full_uri(config.Control.Rest.BASE_URI,
                            config.Control.Rest.Endpoints.SUPPORTED_ELEMENTS)
        response = yield client.fetch(uri)
        self._supported_elements_types = set(json_decode(response.body))
Example #16
0
def sync_weixin():
	#query weixin messages
	weixin_msgs = Weixin.objects.filter(sync_timestamp2__range=(datetime.datetime.now(), datetime.datetime.now()+datetime.timedelta(minutes=5)), status2=1)
	for msg in weixin_msgs:
		logger.info('sync msg %s to weixin' % msg.id)
		MessageSender.send_weixin(weixin_message_builder.build_weixin_message(msg))
    def handle_new_client_request(self, event):
        # At first we want to receive information to properly connect as new predecessor after sending init_data
        message_size = event.data['connection'].recv(8)
        message_size = int.from_bytes(message_size, byteorder='big')
        message = b''
        while len(message) < message_size:
            packet = event.data['connection'].recv(message_size - len(message))
            if not packet:
                return None
            message += packet
        client_request = json.loads(message.decode('utf-8'))

        first_client = not self.next_hop_info
        # When we detect a new client connecting we want to;
        # 1.Send him the initial data over the connection we already established
        # 2.Connect to him as a predecessor

        # Gather the initial board state (only the coloured spots)
        marked_spots = [(x, y) for x in range(len(self.board_state))
                        for y in range(len(self.board_state[x]))
                        if self.board_state[x][y] == 1]
        # If we have next hop information we send it, if we do not have we are the first client so we send our
        # information as the first hop information
        next_hop = (helpers.get_self_ip_address(),
                    config.getint(
                        'NewPredecessorListener',
                        'Port')) if first_client else self.next_hop_info
        # If we are the first client next next hop is None
        response = events.NewClientResponseEvent(next_hop,
                                                 self.next_next_hop_info,
                                                 marked_spots,
                                                 self.critical_section)
        message = helpers.event_to_message(response)
        message_size = (len(message)).to_bytes(8, byteorder='big')
        event.data['connection'].send(message_size)
        event.data['connection'].send(message)

        try:
            message = event.data['connection'].recv(8)
        except Exception as ex:
            if message == b'':
                # Only case when we have a succesfull read of 0 bytes is when other socket shutdowns normally
                pass
            else:
                logger.error(ex)
                #Client did not initializ correctly so we abort the process
                return
        # If we are not the first client we have to update our next next hop to our previous next hop
        if not first_client:
            self.next_next_hop_info = self.next_hop_info
        else:
            # If we are the first client we update our next next hop info to self address
            self.next_next_hop_info = (helpers.get_self_ip_address(),
                                       config.getint('NewPredecessorListener',
                                                     'Port'))

        # We stop current message sender if it exists
        if self.message_sender:
            self.message_sender.stop()

        # We update our next hop info with the newest client request
        self.next_hop_info = client_request['data']['address']
        ip, port = self.next_hop_info
        # We establish a new connection and a new message sender
        connection = socket.create_connection((ip, port), 100)
        self.sending_queue = queue.Queue(maxsize=0)
        self.message_sender = MessageSender(self.event_queue,
                                            self.sending_queue, connection)
        self.message_sender.start()
        if first_client and self.last_token != None:
            # If we are the first client we start passing of the token
            self.sending_queue.put(events.TokenPassEvent(self.last_token))
Example #18
0
from message_sender import MessageSender

if __name__ == '__main__':
    ms = MessageSender('config.ini')
    ms.test_message()
    # ms.send_messages()
    def __init__(self,
                 event_queue,
                 paint_queue,
                 time_offset,
                 init_data=None,
                 init_connection=None):
        super(ModelThread, self).__init__()

        # Queues
        self.event_queue = event_queue
        self.paint_queue = paint_queue

        #Event handling
        self.handlers = {}
        self.initialize_handlers()

        # Unique uuid identifying clients in the network
        self.uuid = uuid.uuid4().hex
        # Flag indicating weather we want to enter critical section when the token comes
        self.want_to_enter_critical_section = False
        # Information about critical section like the timestamp and client uuid which is in the section
        self.critical_section = None
        # Time offset between ntp server and local time
        self.time_offset = time_offset
        # Value of the last token we have received
        self.last_token = None

        # Initial board state
        self.board_state = [[
            0 for _ in range(config.getint('Tkinter', 'CanvasY'))
        ] for _ in range(config.getint('Tkinter', 'CanvasX'))]

        # If we are the first client
        if not init_data:
            self.next_hop_info = None
            self.next_next_hop_info = None
            self.sending_queue = None
            self.message_sender = None
            self.predecessor = None
            self.last_token = 0
        else:
            self.next_hop_info = init_data['next_hop']
            if not init_data['next_next_hop']:
                # If there is no next_next_hop init data in the response we are the second client so we set
                # next next hop as our address
                self.next_next_hop_info = (helpers.get_self_ip_address(),
                                           config.getint(
                                               'NewPredecessorListener',
                                               'Port'))
            else:
                # If there are more thant two clients we set the value from the response
                self.next_next_hop_info = init_data['next_next_hop']

            # Address of our predecessor
            self.predecessor = init_connection.getsockname()

            # We initialize connection to our next hop and we start sending queue
            ip, port = init_data['next_hop']
            s = socket.create_connection((ip, port))
            self.sending_queue = queue.Queue(maxsize=0)
            self.message_sender = MessageSender(self.event_queue,
                                                self.sending_queue, s)
            self.message_sender.start()
            self.initialize_board(init_data['board_state'])
            if init_data['critical_section_state']:
                self.critical_section = init_data['critical_section_state']
                self.paint_queue.put({'type': DrawingQueueEvent.BOARD_CLOSED})

            # We signal that client has initialized properly
            init_connection.shutdown(1)
            init_connection.close()

        # We start a dummy message sender event which will create dummy messages to detect connection breaks
        self.dummy_message_sender = DummyMessageSender(self.event_queue,
                                                       self.uuid)
        self.dummy_message_sender.start()
class ModelThread(threading.Thread):
    def __init__(self,
                 event_queue,
                 paint_queue,
                 time_offset,
                 init_data=None,
                 init_connection=None):
        super(ModelThread, self).__init__()

        # Queues
        self.event_queue = event_queue
        self.paint_queue = paint_queue

        #Event handling
        self.handlers = {}
        self.initialize_handlers()

        # Unique uuid identifying clients in the network
        self.uuid = uuid.uuid4().hex
        # Flag indicating weather we want to enter critical section when the token comes
        self.want_to_enter_critical_section = False
        # Information about critical section like the timestamp and client uuid which is in the section
        self.critical_section = None
        # Time offset between ntp server and local time
        self.time_offset = time_offset
        # Value of the last token we have received
        self.last_token = None

        # Initial board state
        self.board_state = [[
            0 for _ in range(config.getint('Tkinter', 'CanvasY'))
        ] for _ in range(config.getint('Tkinter', 'CanvasX'))]

        # If we are the first client
        if not init_data:
            self.next_hop_info = None
            self.next_next_hop_info = None
            self.sending_queue = None
            self.message_sender = None
            self.predecessor = None
            self.last_token = 0
        else:
            self.next_hop_info = init_data['next_hop']
            if not init_data['next_next_hop']:
                # If there is no next_next_hop init data in the response we are the second client so we set
                # next next hop as our address
                self.next_next_hop_info = (helpers.get_self_ip_address(),
                                           config.getint(
                                               'NewPredecessorListener',
                                               'Port'))
            else:
                # If there are more thant two clients we set the value from the response
                self.next_next_hop_info = init_data['next_next_hop']

            # Address of our predecessor
            self.predecessor = init_connection.getsockname()

            # We initialize connection to our next hop and we start sending queue
            ip, port = init_data['next_hop']
            s = socket.create_connection((ip, port))
            self.sending_queue = queue.Queue(maxsize=0)
            self.message_sender = MessageSender(self.event_queue,
                                                self.sending_queue, s)
            self.message_sender.start()
            self.initialize_board(init_data['board_state'])
            if init_data['critical_section_state']:
                self.critical_section = init_data['critical_section_state']
                self.paint_queue.put({'type': DrawingQueueEvent.BOARD_CLOSED})

            # We signal that client has initialized properly
            init_connection.shutdown(1)
            init_connection.close()

        # We start a dummy message sender event which will create dummy messages to detect connection breaks
        self.dummy_message_sender = DummyMessageSender(self.event_queue,
                                                       self.uuid)
        self.dummy_message_sender.start()

    def run(self):
        while True:
            (e) = self.event_queue.get()
            handler_function = self.handlers[type(e).__name__]
            handler_function(e)

    def initialize_board(self, board_state):
        for counter in (len(board_state)):
            x_coord, y_coord = board_state[counter]
            try:
                self.board_state[x_coord][y_coord] = 1
            except IndexError:
                return
        self.paint_queue.put({
            'type': DrawingQueueEvent.DRAWING,
            'data': (board_state, 1)
        })

    def initialize_handlers(self):
        # Inner Handlers
        self.handlers[
            'InnerNewClientRequestEvent'] = self.handle_new_client_request
        self.handlers[
            'InnerNewPredecessorRequestEvent'] = self.handle_new_predecessor_request_event
        self.handlers[
            'InnerDrawingInformationEvent'] = self.handle_inner_draw_information_event
        self.handlers[
            'InnerWantToEnterCriticalSection'] = self.inner_handle_want_to_enter_critical_section_event
        self.handlers[
            'InnerLeavingCriticalSection'] = self.inner_leaving_critical_section_event
        self.handlers['InnerNextHopBroken'] = self.inner_next_hop_broken_event

        # Outter handlers
        self.handlers[
            'DrawingInformationEvent'] = self.handle_drawing_information_event
        self.handlers[
            'EnteredCriticalSectionEvent'] = self.handle_entering_critical_section
        self.handlers[
            'LeavingCriticalSectionEvent'] = self.handle_leaving_critical_section
        self.handlers['TokenPassEvent'] = self.handle_token_pass_event
        self.handlers['NewNextNextHop'] = self.handle_new_next_next_hop_event
        self.handlers[
            'TokenReceivedQuestionEvent'] = self.handle_token_received_question_event
        self.handlers['DummyMessageEvent'] = self.handle_dummy_message_event

    ############################################################################################
    #
    #                                      Inner Event handlers
    ############################################################################################
    def handle_inner_draw_information_event(self, event):
        def draw_points(event):
            color = event.data['color']
            points = event.data['points']
            try:
                for point in points:
                    x, y = point
                    self.board_state[x][y] = color
            except IndexError as e:
                return

            self.paint_queue.put({
                'type': DrawingQueueEvent.DRAWING,
                'data': (points, color)
            })
            if (self.sending_queue):
                self.sending_queue.put(
                    events.DrawingInformationEvent(
                        self.uuid, helpers.get_current_timestamp(), points,
                        color))

        if not self.critical_section:
            draw_points(event)
        elif self.critical_section['timestamp'] > event.data['timestamp']:
            draw_points(event)
        elif self.critical_section['client_uuid'] == self.uuid:
            draw_points(event)
        elif self.critical_section['client_uuid'] != self.uuid:
            pass

    def inner_handle_want_to_enter_critical_section_event(self, _):
        self.want_to_enter_critical_section = True

    def inner_leaving_critical_section_event(self, _):
        self.critical_section = None
        self.paint_queue.put({"type": DrawingQueueEvent.BOARD_OPEN})
        if self.sending_queue:
            self.sending_queue.put(
                events.LeavingCriticalSectionEvent(
                    helpers.get_current_timestamp(), self.uuid))
            self.sending_queue.put(events.TokenPassEvent(self.last_token))
        else:
            self.event_queue.put(
                events.LeavingCriticalSectionEvent(
                    helpers.get_current_timestamp(), self.uuid))
            self.event_queue.put(events.TokenPassEvent(self.last_token))

    def inner_next_hop_broken_event(self, _):
        # If we detect that the next hop connection is down we want to:
        # 1.Try to reconnect to the client
        # 2.If reconnect fails we want to connect to our next next hop
        # 3.When we succesfully connect to our next next hop we want to send recovery token question
        #   in case that the dead client was holding the token the moment he died
        ip, port = self.next_next_hop_info
        # If we are the only client left we reset the data to the initial state
        if ip == helpers.get_self_ip_address():
            self.critical_section = None
            self.next_hop_info = None
            self.next_next_hop_info = None
            if self.message_sender:
                self.message_sender.stop()
            self.sending_queue = None
            self.message_sender = None
            self.predecessor = None
            self.last_token = 0
            self.paint_queue.put({'type': DrawingQueueEvent.BOARD_OPEN})
            return

        def connect_to_next_next_hop(self):
            ip, port = self.next_next_hop_info
            try:
                s = socket.create_connection((ip, port))
                self.sending_queue = queue.Queue(maxsize=0)
                self.message_sender = MessageSender(self.event_queue,
                                                    self.sending_queue, s)
                self.message_sender.start()
                self.next_hop_info = self.next_next_hop_info
                # After we connect to a new client we have to check whether the dead client wasn't in posession
                # of token
                self.sending_queue.put(
                    events.TokenReceivedQuestionEvent(self.last_token))
            except Exception as e:
                logger.error(e)

        ip, port = self.next_hop_info
        try:
            s = socket.create_connection((ip, port))
            self.sending_queue = queue.Queue(maxsize=0)
            self.message_sender = MessageSender(self.event_queue,
                                                self.sending_queue, s)
            self.message_sender.start()
        except ConnectionRefusedError as e:
            logger.error(e)
            connect_to_next_next_hop(self)

    ############################################################################################
    #
    #                                      Event handlers
    ############################################################################################
    def handle_new_client_request(self, event):
        # At first we want to receive information to properly connect as new predecessor after sending init_data
        message_size = event.data['connection'].recv(8)
        message_size = int.from_bytes(message_size, byteorder='big')
        message = b''
        while len(message) < message_size:
            packet = event.data['connection'].recv(message_size - len(message))
            if not packet:
                return None
            message += packet
        client_request = json.loads(message.decode('utf-8'))

        first_client = not self.next_hop_info
        # When we detect a new client connecting we want to;
        # 1.Send him the initial data over the connection we already established
        # 2.Connect to him as a predecessor

        # Gather the initial board state (only the coloured spots)
        marked_spots = [(x, y) for x in range(len(self.board_state))
                        for y in range(len(self.board_state[x]))
                        if self.board_state[x][y] == 1]
        # If we have next hop information we send it, if we do not have we are the first client so we send our
        # information as the first hop information
        next_hop = (helpers.get_self_ip_address(),
                    config.getint(
                        'NewPredecessorListener',
                        'Port')) if first_client else self.next_hop_info
        # If we are the first client next next hop is None
        response = events.NewClientResponseEvent(next_hop,
                                                 self.next_next_hop_info,
                                                 marked_spots,
                                                 self.critical_section)
        message = helpers.event_to_message(response)
        message_size = (len(message)).to_bytes(8, byteorder='big')
        event.data['connection'].send(message_size)
        event.data['connection'].send(message)

        try:
            message = event.data['connection'].recv(8)
        except Exception as ex:
            if message == b'':
                # Only case when we have a succesfull read of 0 bytes is when other socket shutdowns normally
                pass
            else:
                logger.error(ex)
                #Client did not initializ correctly so we abort the process
                return
        # If we are not the first client we have to update our next next hop to our previous next hop
        if not first_client:
            self.next_next_hop_info = self.next_hop_info
        else:
            # If we are the first client we update our next next hop info to self address
            self.next_next_hop_info = (helpers.get_self_ip_address(),
                                       config.getint('NewPredecessorListener',
                                                     'Port'))

        # We stop current message sender if it exists
        if self.message_sender:
            self.message_sender.stop()

        # We update our next hop info with the newest client request
        self.next_hop_info = client_request['data']['address']
        ip, port = self.next_hop_info
        # We establish a new connection and a new message sender
        connection = socket.create_connection((ip, port), 100)
        self.sending_queue = queue.Queue(maxsize=0)
        self.message_sender = MessageSender(self.event_queue,
                                            self.sending_queue, connection)
        self.message_sender.start()
        if first_client and self.last_token != None:
            # If we are the first client we start passing of the token
            self.sending_queue.put(events.TokenPassEvent(self.last_token))

    def handle_drawing_information_event(self, event):
        def draw_point(event):
            points = event.data['points']
            color = event.data['color']
            try:
                for point in points:
                    x, y = point
                    self.board_state[x][y] = color
            except IndexError:
                return

            self.paint_queue.put({
                'type': DrawingQueueEvent.DRAWING,
                'data': (points, color)
            })
            if self.sending_queue:
                self.sending_queue.put(event)

        if event.data['client_uuid'] == self.uuid:
            return
        if not self.critical_section:
            draw_point(event)
        elif self.critical_section['timestamp'] > event.data['timestamp']:
            draw_point(event)
        elif self.critical_section['client_uuid'] == event.data['client_uuid']:
            draw_point(event)
        elif self.critical_section['client_uuid'] != event.data['client_uuid']:
            pass

    def handle_new_predecessor_request_event(self, event):
        # The moment we have a new predecessor this means that the client before our predecessor
        # has a new next next hop address (which is our address) and our predecessor has new next next hop (which is
        # our next hop)
        self.predecessor = event.data['client_address']
        self_address = (helpers.get_self_ip_address(),
                        config.getint('NewPredecessorListener', 'Port'))
        # Special case if we have only 2 nodes left
        if self.predecessor[0] == self.next_hop_info[0]:
            self.sending_queue.put(
                events.NewNextNextHop(self.predecessor, self_address))
            self.next_next_hop_info = (helpers.get_self_ip_address(),
                                       config.getint('NewPredecessorListener',
                                                     'Port'))
        else:
            # We send information to predecessor of our predecessor about his new next next hop address
            self.sending_queue.put(
                events.NewNextNextHop(self_address, self.predecessor))
            # We send information to our predecessor about his new next next hop
            self.sending_queue.put(
                events.NewNextNextHop(self.next_hop_info, self_address))

    def handle_entering_critical_section(self, event):
        data = event.data
        if (data['client_uuid']) == self.uuid:
            return
        self.critical_section = {
            'timestamp': data['timestamp'],
            'client_uuid': data['client_uuid']
        }
        self.paint_queue.put({'type': DrawingQueueEvent.BOARD_CLOSED})
        self.sending_queue.put(event)

    def handle_leaving_critical_section(self, event):
        data = event.data
        if (data['client_uuid']) == self.uuid:
            return

        if self.critical_section and self.critical_section[
                'client_uuid'] == event.data['client_uuid']:
            self.paint_queue.put({'type': DrawingQueueEvent.BOARD_OPEN})
            self.critical_section = None

        self.sending_queue.put(event)

    def handle_token_pass_event(self, event):
        token = event.data['token'] + 1
        self.last_token = token

        if self.critical_section:
            # If we have received the token and the critical section exists we unvalidate critical secion info
            self.critical_section = None
            self.paint_queue.put({'type': DrawingQueueEvent.BOARD_OPEN})

        if self.want_to_enter_critical_section:
            timestamp = helpers.get_current_timestamp()
            self.critical_section = {
                'timestamp': timestamp,
                'client_uuid': self.uuid
            }
            leave_critical_section_deamon = CriticalSectionLeaver(
                self.event_queue)
            leave_critical_section_deamon.start()
            self.want_to_enter_critical_section = False
            self.paint_queue.put({'type': DrawingQueueEvent.BOARD_CONTROLLED})
            self.sending_queue.put(
                events.EnteredCriticalSectionEvent(timestamp, self.uuid))
        else:
            if self.sending_queue:
                self.sending_queue.put(events.TokenPassEvent(token))

    def handle_new_next_next_hop_event(self, event):
        post_destination_ip, _ = event.data['destination_next_hop']
        next_hop_ip, _ = self.next_hop_info

        # We are the recipient of the message
        if post_destination_ip == next_hop_ip:
            self.next_next_hop_info = event.data['new_address']
        else:
            self.sending_queue.put(event)

    def handle_token_received_question_event(self, event):
        # We check weather the last token we received is greater than
        # the token from the request
        # If it is, this means that the disconnected client was not in posession of the token when he disconnected
        # If it was we have to unvalidate critial secion information and send token further

        if self.last_token > event.data['token'] + 1:
            return
        else:
            self.critical_section = None
            self.paint_queue.put({'type': DrawingQueueEvent.BOARD_OPEN})
            token = event.data['token'] + 1 if event.data[
                'token'] else self.last_token + 1
            self.sending_queue.put(events.TokenPassEvent(token))

    def handle_dummy_message_event(self, event):
        if self.uuid != event.data['uuid']:
            return
        else:
            if self.sending_queue:
                self.sending_queue.put(event)