<commit_before>import queue
import logging
from distutils.version import LooseVersion

from kivy.clock import Clock

import mpf.core.bcp.bcp_socket_client as bcp
from mpfmc._version import __bcp_version__
from mpfmc.core.bcp_server import BCPServer


class BcpProcessor(object):
    def __init__(self, mc):
        self.mc = mc
        self.log = logging.getLogger('BcpProcessor')

        self.receive_queue = queue.Queue()
        self.sending_queue = queue.Queue()

        if self.mc.options['bcp']:
            self.mc.events.add_handler('init_done', self._start_socket_thread)
            self.enabled = True
        else:
            self.enabled = False

        self.bcp_commands = {'error': self._bcp_error,
                             'goodbye': self._bcp_goodbye,
                             'hello': self._bcp_hello,
                             'machine_variable': self._bcp_machine_variable,
                             'mode_start': self._bcp_mode_start,
                             'mode_stop': self._bcp_mode_stop,
                             'player_added': self._bcp_player_add,
                             'player_turn_start': self._bcp_player_turn_start,
                             'player_variable': self._bcp_player_variable,
                             'reset': self._bcp_reset,
                             'switch': self._bcp_switch,
                             'trigger': self._bcp_trigger,
                             }

        self.mc.events.add_handler('client_connected', self._client_connected)

        Clock.schedule_interval(self._get_from_queue, 0)

    def _client_connected(self, **kwargs):
        del kwargs
        self.send("monitor_machine_vars")
        self.send("monitor_player_vars")
        self.register_trigger("ball_started")
        self.register_trigger("ball_ended")
        self.register_trigger("player_add_success")
        self.register_trigger("player_turn_start")
        self.register_trigger("master_volume_increase")
        self.register_trigger("master_volume_decrease")

    def register_trigger(self, event):
        """Register a trigger for events from MPF."""
        self.send("register_trigger", event=event)

    def _start_socket_thread(self):
        self.socket_thread = BCPServer(self.mc, self.receive_queue,
                                       self.sending_queue)
        self.socket_thread.daemon = True
        self.socket_thread.start()

    def send(self, bcp_command, callback=None, rawbytes=None, **kwargs):
        """Sends a BCP command to the connected pinball controller.

        Note that if the BCP server is not running, this method will just throw
        the BCP away. (It will still call the callback in that case.

        Args:
            bcp_command: String of the BCP command name.
            callback: Optional callback method that will be called when the
                command is sent.
            **kwargs: Optional additional kwargs will be added to the BCP
                command string.

        """
        if self.enabled:
            if not self.mc.bcp_client_connected:
                raise AssertionError("Not connected to MPF.")

            self.sending_queue.put(
                (bcp.encode_command_string(bcp_command, **kwargs), rawbytes))

        if callback:
            callback()

    def receive_bcp_message(self, msg):
        """Receives an incoming BCP message to be processed.

        Note this method is intended for testing. Usually BCP messages are
        handled by the BCP Server thread, but for test purposes it's possible
        to run mpf-mc without the BCP Server, so in that case you can use this
        method to send BCP messages into the mpf-mc.

        Args:
            msg: A string of the BCP message (in the standard BCP format:
                command?param1=value1&param2=value2...

        """
        cmd, kwargs = bcp.decode_command_string(msg)
        self.receive_queue.put((cmd, kwargs))

    def _get_from_queue(self, dt):
        """Gets and processes all queued up incoming BCP commands."""
        del dt

        while not self.receive_queue.empty():
            cmd, kwargs = self.receive_queue.get(False)
            self._process_command(cmd, **kwargs)

    def _process_command(self, bcp_command, **kwargs):
        self.log.debug("Processing command: %s %s", bcp_command, kwargs)

        # Can't use try/except KeyError here becasue there could be a KeyError
        # in the callback which we don't want it to swallow.
        if bcp_command in self.bcp_commands:
            self.bcp_commands[bcp_command](**kwargs)
        else:
            self.log.warning("Received invalid BCP command: %s", bcp_command[:9])
            # self.send('error',message='invalid command', command=bcp_command)

    def _bcp_hello(self, **kwargs):
        """Processes an incoming BCP 'hello' command."""
        try:
            if LooseVersion(kwargs['version']) == (
                    LooseVersion(__bcp_version__)):
                self.send('hello', version=__bcp_version__)
            else:
                self.send('hello', version='unknown protocol version')
        except KeyError:
            self.log.warning("Received invalid 'version' parameter with 'hello'")

    def _bcp_goodbye(self, **kwargs):
        """Processes an incoming BCP 'goodbye' command."""
        # if self.config['mpf-mc']['exit_on_disconnect']:
        #     self.socket_thread.sending_thread.stop()
        #     sys.exit()

        pass  # todo

    def _bcp_mode_start(self, name=None, priority=0, **kwargs):
        """Processes an incoming BCP 'mode_start' command."""
        del kwargs

        if not name:
            return
            # todo raise error

        if name == 'game':
            self.mc.game_start()

        if name in self.mc.modes:
            self.mc.modes[name].start(priority=int(priority))

    def _bcp_mode_stop(self, name, **kwargs):
        """Processes an incoming BCP 'mode_stop' command."""
        del kwargs
        if not name:
            return
            # todo raise error

        if name == 'game':
            self.mc.game_end()

        if name in self.mc.modes:
            self.mc.modes[name].stop()

    def _bcp_error(self, **kwargs):
        """Processes an incoming BCP 'error' command."""
        del kwargs
        self.log.warning('Received error command from client')

    def _bcp_player_add(self, player_num, **kwargs):
        """Processes an incoming BCP 'player_add' command."""
        del kwargs
        self.mc.add_player(int(player_num))

    # pylint: disable-msg=too-many-arguments
    def _bcp_player_variable(self, name, value, prev_value, change, player_num,
                             **kwargs):
        """Processes an incoming BCP 'player_variable' command."""
        del prev_value
        del change
        del kwargs
        self.mc.update_player_var(name, value, int(player_num))

    def _bcp_machine_variable(self, name, value, change=True, prev_value=None,
                              **kwargs):
        """Processes an incoming BCP 'machine_variable' command."""
        del kwargs
        self.mc.set_machine_var(name, value, change, prev_value)

    def _bcp_player_turn_start(self, player_num, **kwargs):
        """Processes an incoming BCP 'player_turn_start' command."""
        del kwargs
        self.mc.player_start_turn(int(player_num))

    def _bcp_trigger(self, name, **kwargs):
        """Processes an incoming BCP 'trigger' command."""
        self.mc.events.post(name, **kwargs)

    def _bcp_switch(self, name, state, **kwargs):
        """Processes an incoming BCP 'switch' command."""
        del kwargs
        if int(state):
            self.mc.events.post('switch_' + name + '_active')
            '''event: switch_(name)_active
            desc: Posted on MPF-MC only (e.g. not in MPF) when the MC receives
            a BCP "switch" active command. Useful for video modes and graphical
            menu navigation. Note that this is not posted for every switch all
            the time, rather, only for switches that have been configured to
            send events to BCP.
            '''
        else:
            self.mc.events.post('switch_' + name + '_inactive')
            '''event: switch_(name)_inactive
            desc: Posted on MPF-MC only (e.g. not in MPF) when the MC receives
            a BCP "switch" inactive command. Useful for video modes and graphical
            menu navigation. Note that this is not posted for every switch all
            the time, rather, only for switches that have been configured to
            send events to BCP.
            '''

    def _bcp_reset(self, **kwargs):
        del kwargs
        self.mc.reset()
<commit_msg>prevent bcp_processor from trying to start twice<commit_after>import queue
import logging
from distutils.version import LooseVersion

from kivy.clock import Clock

import mpf.core.bcp.bcp_socket_client as bcp
from mpfmc._version import __bcp_version__
from mpfmc.core.bcp_server import BCPServer


class BcpProcessor(object):
    def __init__(self, mc):
        self.mc = mc
        self.log = logging.getLogger('BcpProcessor')

        self.socket_thread = None
        self.receive_queue = queue.Queue()
        self.sending_queue = queue.Queue()

        if self.mc.options['bcp']:
            self.mc.events.add_handler('init_done', self._start_socket_thread)
            self.enabled = True
        else:
            self.enabled = False

        self.bcp_commands = {'error': self._bcp_error,
                             'goodbye': self._bcp_goodbye,
                             'hello': self._bcp_hello,
                             'machine_variable': self._bcp_machine_variable,
                             'mode_start': self._bcp_mode_start,
                             'mode_stop': self._bcp_mode_stop,
                             'player_added': self._bcp_player_add,
                             'player_turn_start': self._bcp_player_turn_start,
                             'player_variable': self._bcp_player_variable,
                             'reset': self._bcp_reset,
                             'switch': self._bcp_switch,
                             'trigger': self._bcp_trigger,
                             }

        self.mc.events.add_handler('client_connected', self._client_connected)

        Clock.schedule_interval(self._get_from_queue, 0)

    def _client_connected(self, **kwargs):
        del kwargs
        self.send("monitor_machine_vars")
        self.send("monitor_player_vars")
        self.register_trigger("ball_started")
        self.register_trigger("ball_ended")
        self.register_trigger("player_add_success")
        self.register_trigger("player_turn_start")
        self.register_trigger("master_volume_increase")
        self.register_trigger("master_volume_decrease")

    def register_trigger(self, event):
        """Register a trigger for events from MPF."""
        self.send("register_trigger", event=event)

    def _start_socket_thread(self):

        if self.socket_thread:
            return

        self.socket_thread = BCPServer(self.mc, self.receive_queue,
                                       self.sending_queue)
        self.socket_thread.daemon = True
        self.socket_thread.start()

        self.mc.events.remove_handler(self._start_socket_thread)

    def send(self, bcp_command, callback=None, rawbytes=None, **kwargs):
        """Sends a BCP command to the connected pinball controller.

        Note that if the BCP server is not running, this method will just throw
        the BCP away. (It will still call the callback in that case.

        Args:
            bcp_command: String of the BCP command name.
            callback: Optional callback method that will be called when the
                command is sent.
            **kwargs: Optional additional kwargs will be added to the BCP
                command string.

        """
        if self.enabled:
            if not self.mc.bcp_client_connected:
                raise AssertionError("Not connected to MPF.")

            self.sending_queue.put(
                (bcp.encode_command_string(bcp_command, **kwargs), rawbytes))

        if callback:
            callback()

    def receive_bcp_message(self, msg):
        """Receives an incoming BCP message to be processed.

        Note this method is intended for testing. Usually BCP messages are
        handled by the BCP Server thread, but for test purposes it's possible
        to run mpf-mc without the BCP Server, so in that case you can use this
        method to send BCP messages into the mpf-mc.

        Args:
            msg: A string of the BCP message (in the standard BCP format:
                command?param1=value1&param2=value2...

        """
        cmd, kwargs = bcp.decode_command_string(msg)
        self.receive_queue.put((cmd, kwargs))

    def _get_from_queue(self, dt):
        """Gets and processes all queued up incoming BCP commands."""
        del dt

        while not self.receive_queue.empty():
            cmd, kwargs = self.receive_queue.get(False)
            self._process_command(cmd, **kwargs)

    def _process_command(self, bcp_command, **kwargs):
        self.log.debug("Processing command: %s %s", bcp_command, kwargs)

        # Can't use try/except KeyError here becasue there could be a KeyError
        # in the callback which we don't want it to swallow.
        if bcp_command in self.bcp_commands:
            self.bcp_commands[bcp_command](**kwargs)
        else:
            self.log.warning("Received invalid BCP command: %s", bcp_command[:9])
            # self.send('error',message='invalid command', command=bcp_command)

    def _bcp_hello(self, **kwargs):
        """Processes an incoming BCP 'hello' command."""
        try:
            if LooseVersion(kwargs['version']) == (
                    LooseVersion(__bcp_version__)):
                self.send('hello', version=__bcp_version__)
            else:
                self.send('hello', version='unknown protocol version')
        except KeyError:
            self.log.warning("Received invalid 'version' parameter with 'hello'")

    def _bcp_goodbye(self, **kwargs):
        """Processes an incoming BCP 'goodbye' command."""
        # if self.config['mpf-mc']['exit_on_disconnect']:
        #     self.socket_thread.sending_thread.stop()
        #     sys.exit()

        pass  # todo

    def _bcp_mode_start(self, name=None, priority=0, **kwargs):
        """Processes an incoming BCP 'mode_start' command."""
        del kwargs

        if not name:
            return
            # todo raise error

        if name == 'game':
            self.mc.game_start()

        if name in self.mc.modes:
            self.mc.modes[name].start(priority=int(priority))

    def _bcp_mode_stop(self, name, **kwargs):
        """Processes an incoming BCP 'mode_stop' command."""
        del kwargs
        if not name:
            return
            # todo raise error

        if name == 'game':
            self.mc.game_end()

        if name in self.mc.modes:
            self.mc.modes[name].stop()

    def _bcp_error(self, **kwargs):
        """Processes an incoming BCP 'error' command."""
        del kwargs
        self.log.warning('Received error command from client')

    def _bcp_player_add(self, player_num, **kwargs):
        """Processes an incoming BCP 'player_add' command."""
        del kwargs
        self.mc.add_player(int(player_num))

    # pylint: disable-msg=too-many-arguments
    def _bcp_player_variable(self, name, value, prev_value, change, player_num,
                             **kwargs):
        """Processes an incoming BCP 'player_variable' command."""
        del prev_value
        del change
        del kwargs
        self.mc.update_player_var(name, value, int(player_num))

    def _bcp_machine_variable(self, name, value, change=True, prev_value=None,
                              **kwargs):
        """Processes an incoming BCP 'machine_variable' command."""
        del kwargs
        self.mc.set_machine_var(name, value, change, prev_value)

    def _bcp_player_turn_start(self, player_num, **kwargs):
        """Processes an incoming BCP 'player_turn_start' command."""
        del kwargs
        self.mc.player_start_turn(int(player_num))

    def _bcp_trigger(self, name, **kwargs):
        """Processes an incoming BCP 'trigger' command."""
        self.mc.events.post(name, **kwargs)

    def _bcp_switch(self, name, state, **kwargs):
        """Processes an incoming BCP 'switch' command."""
        del kwargs
        if int(state):
            self.mc.events.post('switch_' + name + '_active')
            '''event: switch_(name)_active
            desc: Posted on MPF-MC only (e.g. not in MPF) when the MC receives
            a BCP "switch" active command. Useful for video modes and graphical
            menu navigation. Note that this is not posted for every switch all
            the time, rather, only for switches that have been configured to
            send events to BCP.
            '''
        else:
            self.mc.events.post('switch_' + name + '_inactive')
            '''event: switch_(name)_inactive
            desc: Posted on MPF-MC only (e.g. not in MPF) when the MC receives
            a BCP "switch" inactive command. Useful for video modes and graphical
            menu navigation. Note that this is not posted for every switch all
            the time, rather, only for switches that have been configured to
            send events to BCP.
            '''

    def _bcp_reset(self, **kwargs):
        del kwargs
        self.mc.reset()

{'fraction_non_alphanumeric': 0.09398857659899339, 'fraction_numerical': 0.0007917208618447096, 'mean_word_length': 2.1040898718623837, 'pattern_counts': {'":': 0, '<': 3, '<?xml version=': 0, '>': 3, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 2, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '636005', 'n_tokens_mistral': 4944, 'n_tokens_neox': 4828, 'n_words': 1364}