Beispiel #1
0
 def __init__(self,
              name: str,
              external_name: str,
              event_id: str,
              logic_func: Callable,
              parent: Thinker,
              tick=0.1,
              print_every_n=20,
              original_owner=''):
     super().__init__()
     self.logger = logging.getLogger(__name__ + '.' +
                                     self.__class__.__name__)
     self.name = name
     self.external_name = external_name
     self.id = event_id
     self.parent = parent
     self.original_owner = original_owner
     self.logic_func = logic_func
     self.print_every_n = print_every_n
     self.n = 0  # reserved for heartbeat events
     self.time = 0
     self.tick = tick  # in sec
     self.active = False
     self.paused = False
     self.counter_timeout = 0
     if self.parent:
         info_msg(self, 'CREATED', extra=f' of {self.parent.name}')
     else:
         info_msg(self, 'CREATED')
Beispiel #2
0
    def react_directed(self, msg: MessageExt):
        if self.parent.pyqtsignal_connected:
            # Convert MessageExt to MessageInt and emit it
            msg_int = msg.ext_to_int()
            self.parent.signal.emit(msg_int)
        msg_r = None
        if msg.com == MsgComExt.ALIVE.msg_name:
            if msg.sender_id in self.parent.connections:
                msg_r = None  # MsgGenerator.are_you_alive_reply(device=self.parent_logger, msg_i=msg)
        elif msg.com == MsgComExt.DO_IT.msg_name:
            if not self.parent.add_to_executor(self.parent.execute_com,
                                               msg=msg):
                self.logger.error(f'Adding to executor {msg.info} failed')
        elif msg.com == MsgComExt.DONE_IT.msg_name:
            if msg.reply_to in self.forwarded_messages:
                initial_msg: MessageExt = self.forwarded_messages[msg.reply_to]
                msg_r = msg.copy(receiver_id=initial_msg.sender_id,
                                 reply_to=initial_msg.id,
                                 sender_id=self.parent.id,
                                 forwarded_from=msg.sender_id)
                del self.forwarded_messages[msg.reply_to]
                info_msg(
                    self, 'INFO',
                    f'Msg {initial_msg.id} com {initial_msg.com} is deleted from forwarded messages'
                )
            else:
                pass  # TODO: at this moment Server does not do DO_IT command for itself, it only forwards
        elif msg.com == MsgComExt.WELCOME_INFO_SERVER.msg_name:
            self.react_first_welcome(msg)

        self.msg_out(msg_r)
def internal_hb_logic(event: ThinkerEvent):
    thinker: Thinker = event.parent
    device = thinker.parent
    full_heartbeat = False
    if device.type is DeviceType.SERVER:
        full_heartbeat = True  # Allows to send MsgComExt.HEARTBEAT_FULL only for Server
    info_msg(event, 'STARTED', extra=f' of {thinker.name}')
    while event.active:
        sleep(0.001)
        if not event.paused:
            event.n += 1
            if full_heartbeat and event.n % 3:
                # TODO: every n minutes changes session_key for safety...
                msg_heartbeat = device.generate_msg(
                    msg_com=MsgComExt.HEARTBEAT_FULL, event=event)
            else:
                msg_heartbeat = device.generate_msg(
                    msg_com=MsgComExt.HEARTBEAT, event=event)

            if device.pyqtsignal_connected and device.type is DeviceType.SERVER:
                msg = device.generate_msg(msg_com=MsgComInt.HEARTBEAT,
                                          event=event)
                device.signal.emit(msg)

            thinker.add_task_out(msg_heartbeat)
            sleep(event.tick)
Beispiel #4
0
 def stop(self):
     info_msg(self, 'STOPPING')
     self.active = False
     self.paused = True
     self.parent.device_status.messaging_on = self.active
     self.parent.device_status.messaging_paused = self.paused
     self._msg_out.clear()
Beispiel #5
0
 def send_msg(self, msg: MessageExt):
     try:
         crypted = str(int(msg.crypted)).encode('utf-8')
         msg_bytes = self.encrypt_with_session_key(msg)
         if msg.receiver_id == '':
             self.sockets[PUB_Socket_Server].send_multipart(
                 [msg_bytes, crypted])
         else:
             if msg.receiver_id in self._frontendpool:
                 self.sockets[FRONTEND_Server].send_multipart(
                     [msg.receiver_id.encode('utf-8'), msg_bytes, crypted])
                 info_msg(
                     self, 'INFO',
                     f'Msg {msg.id}, com {msg.com} is send from frontend to {msg.receiver_id}.'
                 )
             elif msg.receiver_id in self._backendpool:
                 self.sockets[BACKEND_Server].send_multipart(
                     [msg.receiver_id.encode('utf-8'), msg_bytes, crypted])
                 info_msg(
                     self, 'INFO',
                     f'Msg {msg.id}, com {msg.com} is send from backend to {msg.receiver_id}.'
                 )
             else:
                 error_logger(
                     self, self.send_msg,
                     f'ReceiverID {msg.receiver_id} is not present in Server pool.'
                 )
     except zmq.ZMQError as e:
         error_logger(self, self.send_msg, e)
Beispiel #6
0
 def run(self):
     info_msg(self, 'STARTING')
     self.active = True
     self.paused = False
     self.parent.device_status.messaging_on = self.active
     self.parent.device_status.messaging_paused = self.paused
     # Start send loop here
     self._send_loop_logic(await_time=0.1 / 1000.)
Beispiel #7
0
 def _start_messaging(self):
     """Start messaging part of Device"""
     info_msg(self, 'STARTING')
     self.thinker.start(
     )  # !!!Thinker must start before the messenger, always!!!!
     self.messenger.start()
     info_msg(self, 'STARTED')
     self.send_status_pyqt()
Beispiel #8
0
 def react_internal(self, event: ThinkerEvent):
     if 'heartbeat' in event.name:
         if event.counter_timeout > self.timeout:
             info_msg(
                 self, 'INFO',
                 'Service was away for too long...deleting info about service'
             )
             self.remove_device_from_connections(event.original_owner)
             self.parent.send_status_pyqt()
Beispiel #9
0
 def _check_size_limit(self):
     if self.size_limit is not None:
         while len(self) > self.size_limit:
             element = self.popitem(last=False)  # Remove first element
             if self.dict_parent:
                 info_msg(
                     self.dict_parent, 'INFO',
                     f'Limit size={self.size_limit} was exceeded for {self.name}, '
                     f'first element {element} was removed')
Beispiel #10
0
 def run(self):
     self.active = True
     self.paused = self.parent.paused
     try:
         self.time = time()
         info_msg(self, 'STARTING', extra=f' of {self.parent.name}')
         self.logic_func(self)
     except Exception as e:
         error_logger(self, self.run, f'{self.name}. Error: {e}')
     finally:
         info_msg(self, 'STOPPED', extra=f' of {self.parent.name}')
Beispiel #11
0
def internal_info_logic(event: ThinkerEvent):
    # TODO: why I need it?
    thinker: Thinker = event.parent
    device = thinker.parent
    info_msg(event,
             'STARTED',
             extra=f' of {thinker.name} with tick {event.tick}')
    while event.active:
        sleep(0.001)
        if not event.paused:
            sleep(event.tick)
Beispiel #12
0
    def react_demand(self, msg: Message):
        data = msg.data
        cmd = data.com
        info_msg(self, 'REQUEST', extra=str(msg.short()))
        reply = True

        if msg.body.receiver_id != self.parent.id:
            if msg.body.receiver_id in self.parent.connections:
                msg_i = MsgGenerator.forward_msg(device=self.parent,
                                                 msg_i=msg)
            else:
                msg_i = [MsgGenerator.available_services_reply(device=self.parent, msg_i=msg),
                         MsgGenerator.error(device=self.parent,
                                            comments=f'service {data.info.service_id} is not available anymore',
                                            msg_i=msg)]

        else:
            if cmd == MsgGenerator.HELLO.mes_name:
                try:
                    device_info: DeviceInfoMes = data.info
                    connections = self.parent.connections
                    if data.info.type not in ('service', 'client'):
                        raise Exception(f'{self}:{device_info.type} is not known')

                    if device_info.device_id not in connections:
                        connections[device_info.device_id] = Connection(device_info=data.info)
                        if 'publisher' in device_info.public_sockets:
                            from communication.logic.logic_functions import external_hb_logic
                            self.parent.messenger.subscribe_sub(address=device_info.public_sockets['publisher'])
                            a = f'heartbeat:{data.info.name}'
                            self.register_event(name=f'heartbeat:{data.info.name}',
                                                logic_func=external_hb_logic,
                                                event_id=f'heartbeat:{data.info.device_id}',
                                                original_owner=device_info.device_id,
                                                start_now=True)
                        session_key = self.parent.messenger.gen_symmetric_key(device_info.device_id)
                        session_key_encrypted = self.parent.messenger.encrypt_with_public(session_key,
                                                                                          device_info.public_key)
                        msg_i = MsgGenerator.welcome_info(device=self.parent, msg_i=msg,
                                                          session_key=session_key_encrypted)
                        self.parent.send_status_pyqt(com='status_server_info_full')
                    else:
                        msg_i = MsgGenerator.welcome_info(device=self.parent, msg_i=msg)
                except Exception as e:
                    self.logger.error(e)
                    msg_i = MsgGenerator.error(device=self.parent, comments=repr(e), msg_i=msg)
            elif cmd == MsgGenerator.AVAILABLE_SERVICES_DEMAND.mes_name:
                msg_i = MsgGenerator.available_services_reply(device=self.parent, msg_i=msg)
            elif cmd == MsgGenerator.POWER_ON_DEMAND.mes_name:
                # TODO: service must be realized instead
                # Server here always replied the same way to all services
                comments = """"I always say, that power is ON, I hope the user have turned on power already"""
                msg_i = MsgGenerator.power_on_reply(self.parent, msg_i=msg, flag=True, comments=comments)
Beispiel #13
0
 def msg_out(self, msg_out: Union[MessageExt, List[MessageExt]]):
     if msg_out:
         if isinstance(msg_out, list):
             for msg in msg_out:
                 self.msg_out(msg)
         elif isinstance(msg_out, MessageExt):
             info_msg(self, 'INFO', msg_out.short())
             self.add_task_out(msg_out)
         else:
             error_logger(
                 self, self.msg_out,
                 f'Union[MessageExt, List[MessageExt]] was not passed to msg_out, but'
                 f'{msg_out}')
Beispiel #14
0
def pending_demands(event: ThinkerEvent):
    thinker: Thinker = event.parent
    demands_waiting_reply: MsgDict = thinker.demands_waiting_reply
    info_msg(event,
             'STARTED',
             extra=f' of {thinker.name} with tick {event.tick}')
    while event.active:
        sleep(0.001)
        if not event.paused and demands_waiting_reply:
            try:
                sleep(event.tick)
                for key, item in demands_waiting_reply.items():
                    pending: PendingReply = item
                    if (time() -
                            event.time) > event.tick and pending.attempt < 3:
                        pending.attempt += 1
                        info_msg(
                            event, 'INFO',
                            f'Msg {pending.message.id}, com {pending.message.com} waits '
                            f'{pending.attempt}.')
                    elif (time() -
                          event.time) > event.tick and pending.attempt >= 3:
                        try:
                            msg = pending.message
                            del demands_waiting_reply[key]
                            info_msg(event, 'INFO',
                                     f'Reply timeout for msg: {msg.short()}')
                            info_msg(event, 'INFO', f'Msg {msg.id} is deleted')
                        except KeyError:
                            error_logger(
                                event, pending_demands,
                                f'Cannot delete Msg {msg.id}, com {msg.com} from '
                                f'demand_waiting_reply')
            except ThinkerErrorReact as e:
                error_logger(event, pending_demands, e)
Beispiel #15
0
 def run(self):
     super().run()
     try:
         info_msg(self, 'STARTED')
         self._receive_msgs()
     except zmq.error.ZMQError as e:  # Bad kind of error!
         error_logger(self, self.run, e)
         self.stop()
     finally:
         for _, soc in self.sockets.items():
             soc.close()
         self.context.destroy()
         self.active = False
         self.paused = True
         info_msg(self, 'STOPPED')
Beispiel #16
0
 def _stop_messaging(self):
     """Stop messaging part of Device"""
     info_msg(self, 'STOPPING')
     stop_msg = self.generate_msg(msg_com=MsgComExt.SHUTDOWN,
                                  reason='normal_shutdown')
     self.thinker.msg_out(stop_msg)
     sleep(0.1)
     self.thinker.pause()
     self.messenger.pause()
     self.thinker.stop()
     self.messenger.stop()
     self.send_status_pyqt()
     self.device_status.messaging_paused = False
     self.device_status.messaging_on = False
     info_msg(self, 'STOPPED')
Beispiel #17
0
    def react_reply(self, msg: Message):
        data = msg.data
        info_msg(self, 'REPLY_IN', extra=str(msg.short()))

        if msg.reply_to in self.demands_pending_answer:
            del self.demands_pending_answer[msg.reply_to]
            self.logger.info(f'react_reply: Msg {msg.reply_to} reply is obtained')

        if data.com == MsgGenerator.WELCOME_INFO.mes_name:
            if data.info.device_id in self.parent.connections:
                self.logger.info(f'Server {data.info.device_id} is active. Handshake was undertaken')
                connection: Connection = self.parent.connections[data.info.device_id]
                connection.device_info = data.info
                session_key = self.parent.messenger.decrypt_with_private(data.info.session_key)
                self.parent.messenger.fernet = self.parent.messenger.create_fernet(session_key)
Beispiel #18
0
 def remove_device_from_connections(self, device_id):
     # TODO: the service_info is not deleted from _frontend sockets or backend sockets
     connections = self.parent.connections
     if device_id in connections:
         info_msg(self, 'INFO',
                  f'Procedure to delete {device_id} is started')
         for key, event in list(self.events.items()):
             if event.original_owner == device_id:
                 self.unregister_event(key)
         del self.parent.connections[device_id]
         info_msg(self, 'INFO', f'Device {device_id} is deleted')
     else:
         error_logger(
             self, self.remove_device_from_connections,
             f'remove_device_from_connections: Wrong device_id {device_id} is passed'
         )
Beispiel #19
0
def task_in_reaction(event: ThinkerEvent):
    thinker: Thinker = event.parent
    tasks_in: MsgDict = thinker.tasks_in
    info_msg(event,
             'STARTED',
             extra=f' of {thinker.name} with tick {event.tick}')
    exclude_msgs = [
        MsgComExt.HEARTBEAT.msg_name, MsgComExt.HEARTBEAT_FULL.msg_name
    ]
    while event.active:
        sleep(
            0.001
        )  # Any small interruption is necessary not to overuse processor time
        if not event.paused and tasks_in:
            try:
                msg: MessageExt = tasks_in.popitem(last=False)[1]
                thinker.msg_counter += 1
                react = True
                if msg.com not in exclude_msgs:
                    info_msg(event, 'INFO', f'Received: {msg.short()}')

                if msg.reply_to == '' and msg.receiver_id != '':  # If message is not a reply, it must be a demand one
                    thinker.add_demand_waiting_reply(msg)
                    info_msg(
                        event, 'INFO',
                        f'Expect a reply to {msg.id} com={msg.com}. Adding to waiting list.'
                    )

                elif msg.reply_to != '':
                    if msg.reply_to in thinker.demands_waiting_reply:
                        # TODO: should it have else clause or not?
                        msg_awaited: MessageExt = thinker.demands_waiting_reply[
                            msg.reply_to].message
                        del thinker.demands_waiting_reply[msg.reply_to]
                        info_msg(
                            event, 'INFO',
                            f'REPLY to Msg {msg.reply_to} {msg_awaited.com} is obtained.'
                        )
                    else:
                        react = False
                        info_msg(
                            event, 'INFO',
                            f'Reply to msg {msg.reply_to} arrived too late.')
                if react:
                    thinker.react_external(msg)
            except (ThinkerErrorReact, KeyError) as e:
                error_logger(event, task_in_reaction, f'{e}: {msg.short()}')
Beispiel #20
0
    def react_reply(self,  msg: Message):
        data = msg.data
        cmd = data.com
        info_msg(self, 'REPLY_IN', extra=str(msg.short()))
        reply = False

        if msg.body.receiver_id != self.parent.id:
            msg_i = MsgGenerator.forward_msg(device=self.parent,
                                             msg_i=msg)
            if msg.reply_to in self.demands_pending_answer:
                del self.demands_pending_answer[msg.reply_to]
                self.logger.info(f'react_reply: Msg: {msg.reply_to} reply is obtained and forwarded to intial demander')
            reply = True

        else:
            pass
        self.msg_out(reply, msg_i)
Beispiel #21
0
 def react_forward(self, msg: MessageExt):
     if msg.receiver_id in self.parent.connections:
         info_msg(
             self, 'INFO',
             f'Msg id={msg.id}, com={msg.com} is forwarded to {msg.receiver_id}'
         )
         msg_r = msg.copy(sender_id=self.parent.id,
                          forwarded_from=msg.sender_id)
         self.add_to_forwarded(msg_forwarded=msg_r, msg_arrived=msg)
     else:
         msg_r = [
             self.parent.generate_msg(msg_com=MsgComExt.AVAILABLE_SERVICES,
                                      receiver_id=msg.sender_id,
                                      reply_to=msg.id),
             self.parent.generate_msg(
                 msg_com=MsgComExt.ERROR,
                 comments=f'service {msg.receiver_id} is not available',
                 receiver_id=msg.sender_id,
                 reply_to=msg.id)
         ]
     self.msg_out(msg_r)
Beispiel #22
0
def task_out_reaction(event: ThinkerEvent):
    thinker: Thinker = event.parent
    tasks_out: MsgDict = thinker.tasks_out
    demand_waiting_reply: MsgDict = thinker.demands_waiting_reply
    info_msg(event,
             'STARTED',
             extra=f' of {thinker.name} with tick {event.tick}')
    while event.active:
        sleep(0.001)
        if not event.paused and tasks_out:
            try:
                msg: MessageExt = tasks_out.popitem(last=False)[1]
                react = True
                if msg.receiver_id != '' and msg.reply_to == '':
                    # If msg is not reply, than add to pending demand
                    info_msg(
                        event, 'INFO',
                        f'Msg id={msg.id}, com {msg.com} is considered to get a reply'
                    )
                    thinker.add_demand_waiting_reply(msg)

                elif msg.reply_to != '':
                    if msg.reply_to in demand_waiting_reply:
                        msg_awaited: MessageExt = thinker.demands_waiting_reply[
                            msg.reply_to].message
                        del demand_waiting_reply[msg.reply_to]
                        info_msg(
                            event, 'INFO',
                            f'Msg id={msg.reply_to} {msg_awaited.com} is deleted from '
                            f'demand_waiting_reply')
                if react:
                    thinker.parent.messenger.add_msg_out(msg)
            except (ThinkerErrorReact, KeyError) as e:
                error_logger(event, task_out_reaction, f'{e}: {msg.short()}')
Beispiel #23
0
    def send_msg(self, msg: MessageExt):
        try:
            crypted = str(int(msg.crypted)).encode('utf-8')
            msg_bytes = self.encrypt_with_session_key(msg)

            if msg.receiver_id != '':
                self.sockets[DEALER_Socket].send_multipart(
                    [msg_bytes, crypted])
                info_msg(
                    self, 'INFO',
                    f'Msg {msg.id}, msg_com {msg.com} is send to {msg.receiver_id}.'
                )
            else:
                if self.pub_option:
                    self.sockets[PUB_Socket].send_multipart(
                        [msg_bytes, crypted])
                else:
                    info_msg(
                        self, 'INFO',
                        f'Publisher socket is not available for {self.name}.')
        except zmq.ZMQError as e:
            error_logger(self, self.send_msg, e)
Beispiel #24
0
    def __init__(self, parent):
        from devices.devices import Device
        Thinker.n_instance += 1
        self.logger = logging.getLogger(__name__ + '.' +
                                        self.__class__.__name__)
        self.name = f'{self.__class__.__name__}:{parent.name}:{Thinker.n_instance}'
        self.id = f'{self.name}:{unique_id(self.name)}'
        self.parent: Device = parent
        self.msg_counter = 0
        self.events = Events_Dict()
        msg_dict_size_limit = 10000
        self._tasks_in = MsgDict(name='tasks_in',
                                 size_limit=msg_dict_size_limit,
                                 dict_parent=self)
        self.tasks_in_test = MsgDict(name='tasks_in_test',
                                     size_limit=msg_dict_size_limit,
                                     dict_parent=self)
        self._tasks_out = MsgDict(name='tasks_out',
                                  size_limit=msg_dict_size_limit,
                                  dict_parent=self)
        self.tasks_out_test = MsgDict(name='tasks_out_test',
                                      size_limit=msg_dict_size_limit,
                                      dict_parent=self)
        self._demands_waiting_reply = MsgDict(name='demands_waiting_reply',
                                              size_limit=msg_dict_size_limit,
                                              dict_parent=self)
        # TODO: add slow thread to track after forwarded messages
        self._forwarded = MsgDict(name='forwarded_messages',
                                  size_limit=msg_dict_size_limit,
                                  dict_parent=self)
        self.paused = False

        info_msg(self, 'CREATING')
        try:
            self.timeout = int(self.parent.get_general_settings()['timeout'])
            pending_demands_tick = float(
                self.parent.get_general_settings()['pending_demands']) / 1000.
        except KeyError as e:
            error_logger(self, self.__init__, e)
            self.timeout = 10
            pending_demands_tick = 0.2
        try:
            from communication.logic.logic_functions import (task_in_reaction,
                                                             task_out_reaction,
                                                             pending_demands)
            self.register_event(name='task_in_reaction',
                                logic_func=task_in_reaction,
                                tick=None)
            self.register_event(name='task_out_reaction',
                                logic_func=task_out_reaction,
                                tick=None)
            self.register_event(name='demands_waiting_reply',
                                logic_func=pending_demands,
                                tick=pending_demands_tick)
            info_msg(self, 'CREATED')
        except (ThinkerEventError, ThinkerEventFuncError, TypeError) as e:
            error_logger(self, self.register_event, e)
            info_msg(self, 'NOT CREATED')
            raise ThinkerError(str(e))
Beispiel #25
0
 def react_first_welcome(self, msg: MessageExt):
     msg_r = None
     try:
         messenger = self.parent.messenger
         info: WelcomeInfoServer = msg.info
         # Decrypt public_key of device crypted on device side with public key of Server
         info.session_key = messenger.decrypt_with_private(info.session_key)
         server_connection = self.connections[msg.sender_id]
         # TODO: Actually check AccessLevel and Permission using password checksum
         server_connection.session_key = info.session_key
         server_connection.access_level = AccessLevel.FULL
         server_connection.permission = Permission.GRANTED
         self.parent.send_status_pyqt()
         info_msg(
             self, 'INFO',
             f'Handshake with Server is accomplished. Session_key is obtained.'
         )
     except Exception as e:  # TODO: change Exception to something reasonable
         msg_r = self.parent.generate_msg(msg_com=MsgComExt.ERROR,
                                          comments=f'{e}',
                                          receiver_id=msg.sender_id,
                                          reply_to=msg.id)
     self.msg_out(msg_r)
Beispiel #26
0
 def run(self):
     super().run()
     try:
         for adr in self.addresses[PUB_Socket_Server]:
             self.subscribe_sub(address=adr)
         msg = self._wait_server_hb()
         if self.active:
             self.connect()
             self.parent.thinker.react_heartbeat_full(msg)
             info_msg(self, 'STARTED')
             self._receive_msgs()
     except (zmq.error.ZMQError, MessengerError) as e:  # Bad type of error
         error_logger(self, self.run, e)
         self.stop()
     finally:
         self.sockets[DEALER_Socket].close()
         if self.sockets[SUB_Socket]:
             self.sockets[SUB_Socket].close()
         if self.sockets[PUB_Socket]:
             self.sockets[PUB_Socket].close()
         self.context.destroy()
         self.active = False
         self.paused = True
         info_msg(self, 'STOPPED')
Beispiel #27
0
    def __init__(self, name: str, addresses: Dict[str, str], parent: Device,
                 pub_option: bool, **kwargs):
        """

        :param name: user-friendly name
        :param addresses:
        :param parent: Device, messenger can function without parent_logger Device as well
        :param pub_option: tell weather there is a publisher socket
        :param kwargs:
        """

        super().__init__()
        self._attempts_to_restart_sub = 1  # restart subscriber
        self._are_you_alive_send = False
        Messenger.n_instance += 1
        self.logger = logging.getLogger(
            f'{__name__}.{self.__class__.__name__}')
        self.name = f'{self.__class__.__name__}:{Messenger.n_instance}:{name}:{get_local_ip()}'
        self.id: DeviceId = parent.id
        self.parent: Device = parent
        try:
            self._polling_time = int(
                self.parent.get_general_settings()['polling']) / 1000.
        except AttributeError:
            self._polling_time = 1
        self.active = False
        self.paused = True
        self._msg_out = MsgDict(name=f'msg_out:{self.id}',
                                size_limit=1000,
                                dict_parent=self)
        # ZMQ sockets, communication info
        self.sockets = {}
        self.public_sockets = {}
        self.addresses = {}
        self.pub_option = pub_option
        self._gen_rsa_keys()

        try:
            info_msg(self, 'INITIALIZING')
            self._verify_addresses(addresses)
            self._create_sockets()
            info_msg(self, 'INITIALIZED')
        except (WrongAddress, zmq.ZMQError) as e:
            info_msg(self, 'NOT INITIALIZED')
            raise MessengerError(str(e))
Beispiel #28
0
 def _wait_server_hb(self) -> MessageExt:
     if FRONTEND_Server not in self.addresses or BACKEND_Server not in self.addresses:
         wait = True
     else:
         wait = False
     i = 0
     msg_out = None
     while wait and self.active:
         if i > 100:
             info_msg(
                 self, 'INFO',
                 f'{self.name} could not connect to server, no sockets, '
                 f'try to restart {self.parent.name}')
             i = 0
         i += 1
         sockets = dict(self.poller.poll(100))
         if self.sockets[SUB_Socket] in sockets:
             mes, crypted = self.sockets[SUB_Socket].recv_multipart()
             # TODO: decrypt message safely with try except
             msg: MessageExt = MessageExt.bytes_to_msg(mes)
             # TODO: first heartbeat could be received only from server! make it safe
             if msg.com == MsgComExt.HEARTBEAT_FULL.msg_name:
                 try:
                     info: HeartBeatFull = msg.info
                     sockets = info.device_public_sockets
                     if FRONTEND_Server in sockets and BACKEND_Server in sockets:
                         #TODO: need to check if it true SERVER using password or certificate
                         info_msg(self, 'INFO', f'{msg.short()}')
                         info_msg(
                             self, 'INFO',
                             f'Info from Server is obtained for messenger operation.'
                         )
                         self.addresses[FRONTEND_Server] = sockets[
                             BACKEND_Server]
                         self.addresses[BACKEND_Server] = sockets[
                             BACKEND_Server]
                         msg_out = msg
                         break
                     else:
                         raise MessengerError(
                             f'Not all sockets are sent to {self.name}')
                 except (AttributeError, Exception
                         ) as e:  # IN case when short Heartbeat arrived
                     pass
     return msg_out
Beispiel #29
0
def external_hb_logic(event: ThinkerEvent):
    """
    This event function is designed to track after external events, e.g., heartbeat of a Server
    If event is timeout, than counter_timeout += 1
    Every cycle event is being send to Thinker.react_internal, where Thinker decides what should be done, e.g.,
    counter_timeout reached certain value
    Every event.print_every_n the information of event is printed out in console
    :param event: ThinkerEvent
    :return: None
    """
    thinker: Thinker = event.parent
    info_msg(event,
             'STARTED',
             extra=f' of {thinker.name} with tick {event.tick}')
    counter = 0
    while event.active:
        sleep(0.001)
        if not event.paused:
            sleep(event.tick)
            if (time() - event.time) >= event.tick:
                event.counter_timeout += 1
            else:
                event.counter_timeout = 0

            if event.counter_timeout % 3 == 0 and event.counter_timeout != 0:
                info_msg(event, 'INFO',
                         f'{event.name} timeout {event.counter_timeout}')

            counter += 1
            event.parent.react_internal(event)

            if counter % event.print_every_n == 0:
                counter = 0
                info_msg(event, 'INFO', extra=f'{event.name}: {event.n}')
        else:
            sleep(0.05)
            event.time = time()
Beispiel #30
0
    def __init__(self,
                 name: str,
                 db_path: Path,
                 cls_parts: Dict[str, Any],
                 type: DeviceType,
                 parent: QObject = None,
                 db_command: str = '',
                 logger_new=True,
                 test=False,
                 **kwargs):
        super().__init__()
        Device.n_instance += 1
        self.available_public_functions_names = list(
            cmd.name for cmd in self.available_public_functions())
        self.config = configurationSD(self)
        self.connections: Dict[DeviceId, Connection] = {}
        self.cls_parts: Dict[str, Union[ThinkerInter, MessengerInter,
                                        ExecutorInter]] = cls_parts
        self.device_status: DeviceStatus = DeviceStatus(*[False] * 5)
        self.db_path = db_path
        self.name: str = name
        self._main_executor = ThreadPoolExecutor(max_workers=100)
        self.parent: QObject = parent
        self.type: DeviceType = type
        self.test = test

        if logger_new:
            self.logger = initialize_logger(app_folder / 'LOG',
                                            file_name=__name__ + '.' +
                                            self.__class__.__name__)
            if test:
                self.logger.setLevel(logging.ERROR)
        else:
            self.logger = logging.getLogger(__name__ + '.' +
                                            self.__class__.__name__)

        if 'id' not in kwargs:
            self.id: DeviceId = f'{name}:{unique_id(name)}'
        else:
            self.id: DeviceId = kwargs['id']

        try:
            assert len(self.cls_parts) == 2
            for key, item in self.cls_parts.items():
                assert key in ['Messenger', 'Thinker']
                assert isclass(item)
        except AssertionError as e:
            self.logger.error(e)
            raise e

        try:
            pyqtslot: Callable = kwargs['pyqtslot']
            self._connect_pyqtslot_signal(pyqtslot)
        except KeyError:
            self.pyqtsignal_connected = False
            self.logger.info(f'pyqtsignal is set to False')

        # config is set here
        try:
            db_conn = db_create_connection(self.db_path)
            res, comments = db_execute_select(db_conn, db_command)
            db_conn.close()
            self.config.add_config(self.name, config_text=res)

            from communication.messaging.messengers import Messenger
            from communication.logic.thinkers_logic import Thinker

            if 'pub_option' not in kwargs:
                kwargs['pub_option'] = True

            self.messenger: Messenger = self.cls_parts['Messenger'](
                name=self.name,
                addresses=self.get_addresses(),
                parent=self,
                pub_option=kwargs['pub_option'])
            self.thinker: Thinker = self.cls_parts['Thinker'](parent=self)
        except (sq3.Error, KeyError, MessengerError) as e:
            self.logger.error(e)
            raise DeviceError(str(e))

        info_msg(self, 'CREATED')