示例#1
0
    def onMessage(self, payload, isBinary):
        if isBinary:
            logger.warning(
                "Binary message received ({} bytes): ignoring".format(
                    len(payload)))
            return

        unicode_message = payload.decode('utf8', 'replace')

        try:
            message = json.loads(unicode_message)
        except json.JSONDecodeError:
            logger.exception(
                "Cannot load {}: ignoring".format(unicode_message))
            return

        # message could be validated here with something like pydantic

        logger.debug("{} >>> {}".format(self, message))

        try:
            if message["action"] == "publish":
                self.factory.publish(message["event"], message["channel"])

            elif message["action"] == "subscribe":
                self.subscribe(message["channel"])

        except Exception:
            logger.error(
                "Error while trying to process message={}: skipping".format(
                    message),
                exc_info=True)
示例#2
0
    def status(self, value):
        if value not in self.STATUSES:
            logger.error(
                "Unknown status {} (must be one of {}): skipping".format(
                    value, ", ".join(self.STATUSES)))
            return

        if self.status == value:
            logger.info("Status is already {}: skipping".format(value))
            return

        self._status = value

        if self.status == 'playing':
            category = ArduinoProtocol.PLAYING
            self.on_playing()
        elif self.status == 'success':
            category = ArduinoProtocol.SUCCESS
            self.on_success()
        else:
            # status is disabled
            category = ArduinoProtocol.DISABLED

        for port in self.authenticators.keys():
            self.send_serial({ArduinoProtocol.CATEGORY: category}, port)
示例#3
0
    def difficulty(self, value):
        if value not in self.available_difficulties:
            logger.error(
                "Unknown difficulty '{}' (must be one of {}): skipping".format(
                    value, ", ".join(self.available_difficulties)))

        self._difficulty = value
示例#4
0
    def process_event(self, event, channel):
        callbacks = self._get_callbacks(event, channel)

        for callback in callbacks:
            try:
                args, kwargs = self._get_args_for_callback(event, channel, callback)
            except ValueError:
                logger.error(
                    "Error while executing callback {}: ignoring".format(callback['callable'].__name__),
                    exc_info=True)
                continue

            callback['callable'](*args, **kwargs)
示例#5
0
    def status(self, value):
        if value not in self.STATUSES:
            logger.error(
                "Unknown status {} (must be one of {}): skipping".format(
                    value, ", ".join(self.STATUSES)))
            return

        if self.status == value:
            logger.info("Status is already {}: skipping".format(value))
            return

        self._status = value

        category = ArduinoProtocol.PLAYING if self.status == 'playing' else ArduinoProtocol.DISABLED
        self.send_serial({ArduinoProtocol.CATEGORY: category})
示例#6
0
 def event_reactivate_permanently(self, index: int):
     logger.info("Reactivating laser index={}".format(index))
     self.deactivated_lasers = [
         x for x in self.deactivated_lasers if x != index
     ]
     self.publish_deactivated_lasers()
     try:
         with open(self.config['deactivation_file'], 'w+') as fh:
             json.dump(self.deactivated_lasers, fh)
     except Exception:
         logger.error("Unable to make reactivation persistent",
                      exc_info=True)
     else:
         logger.info(
             "Laser index={} has been permanently reactivated (new deactivated list={})"
             .format(index, self.deactivated_lasers))
示例#7
0
    def send_serial(self, event, port=None):
        if port is None:
            if not self._serials:
                logger.error("No serial instance available: skipping")
                return

            serial = list(self._serials.values())[0]

        else:
            if port not in self._serials:
                logger.error("Port {} has no serial instance available: skipping".format(port))
                return

            serial = self._serials[port]

        serial.send_event(event)
示例#8
0
    def printer_serial_event(self, event: str):
        if event != 'Ok':
            logger.error("Unknown serial event '{}': skipping".format(event))
            return

        logger.info("Received Ok from printer: processing next instruction")
        self.printer_gcode_instructions.pop(
            0)  # This instruction is the one being acknowledged by the 'Ok'

        if not self.printer_gcode_instructions:
            logger.info("No more gcode instructions: going to idle state")
            return

        if self.printer_is_halted:
            logger.info("Printer is halted: waiting to resume")
            return

        next_instruction = self.printer_gcode_instructions[0]
        self.process_gcode_instruction(next_instruction)
示例#9
0
    def __init__(self, *args, **kwargs):
        self._difficulty = None

        super(LaserMaze, self).__init__(*args, **kwargs)

        self.laser_prefix = self.config['laser_prefix']

        self.default_difficulty = self.config['default_difficulty']
        self.difficulty_settings = self.config['difficulty_settings']

        try:
            with open(self.config['deactivation_file'], "r") as fh:
                self.deactivated_lasers = json.loads(fh.read())
        except Exception:
            logger.error("Unable to load deactivation file", exc_info=True)
            self.deactivated_lasers = []
        self.laser_alarm_counters = {}

        reactor.callLater(3, self.init_arduino)
示例#10
0
    def event_deactivate_permanently(self, index: int):
        if index in self.deactivated_lasers:
            logger.info(
                "Laser index={} is already deactivated: skipping".format(
                    index))

        else:
            logger.info("Deactivating laser index={}".format(index))
            self.deactivated_lasers = sorted(self.deactivated_lasers + [index])
            self.publish_deactivated_lasers()
            try:
                with open(self.config['deactivation_file'], 'w+') as fh:
                    json.dump(self.deactivated_lasers, fh)
            except Exception:
                logger.error("Unable to make deactivation persistent",
                             exc_info=True)
            else:
                logger.info(
                    "Laser index={} has been permanently deactivated (new deactivated list={})"
                    .format(index, self.deactivated_lasers))
示例#11
0
    def onMessage(self, payload, isBinary):
        if isBinary:
            logger.warning("Binary message received ({} bytes): ignoring".format(len(payload)))
            return

        unicode_message = payload.decode('utf8', 'replace')

        try:
            message = json.loads(unicode_message)
        except json.JSONDecodeError:
            logger.warning("Cannot load {}: ignoring".format(unicode_message))
            return

        # message could be validated here with something like pydantic

        try:
            logger.info("{} <<< {}".format(message['channel'], message['event']))

            self.factory.process_event(message['event'], message['channel'])
        except Exception:
            logger.error("Error while trying to process message={}".format(message), exc_info=True)
示例#12
0
    def _get_callback_inspection_data(self, callable):
        callback_parameters = inspect.signature(callable).parameters
        inspection_data = {
            'callable': callable,
            'channel': callable.channel,
            'filter': callable.filter,
            'pass_channel': False,
            'variable_kwargs': False,
            'kwargs': {},
        }

        # This inspection is not 100% proof. Positional only arguments or cases that I would not think about can mess
        # with this logic, but at least it covers a lot of cases.

        for param in callback_parameters.values():
            if param.kind == param.POSITIONAL_ONLY:
                if not inspection_data['pass_channel']:
                    inspection_data['pass_channel'] = True
                else:
                    logger.error(
                        "Multiple positional only parameters detected in {}. Only one for the channel is "
                        "supported.".format(callable.__name__))

            elif param.kind == param.VAR_KEYWORD:
                # If there is one variable keyword argument in the signature, we don't need to check if some event
                # fields need to be popped, we already know we can pass all kwargs
                inspection_data['variable_kwargs'] = True

            elif param.kind == param.POSITIONAL_OR_KEYWORD:
                inspection_data['kwargs'][param.name] = {
                    'required': param.default is param.empty,
                    'annotation': ... if param.annotation is param.empty else param.annotation
                }

            else:
                # Only inspect._ParameterKind.VAR_POSITIONAL left, but variable positional arguments are not used
                pass

        return inspection_data
示例#13
0
 def clientConnectionFailed(self, connector, reason):
     logger.error('Connection failed. Reason: {}'.format(reason))
     ReconnectingClientFactory.clientConnectionFailed(self, connector, reason)
示例#14
0
 def clientConnectionLost(self, connector, reason):
     logger.error('Connection lost (reason={})'.format(reason))
     ReconnectingClientFactory.clientConnectionLost(self, connector, reason)
示例#15
0
 def log_published_error(self, message):
     logger.error(message)
     self.publish({'hostname': socket.gethostname(), 'log': message}, 'error')