class MessageServer: """ parent class of all the servers with messenger """ def __init__(self, messenger_name): self.server_messenger = Messenger(messenger_name) def get_message(self): return self.server_messenger.get_message() def put_message(self, msg): self.server_messenger.put_message(msg) def send_message_content(self, content, target_message_server): self.server_messenger.send_message_content( content, target_message_server.server_messenger) def handle_message(self, msg): raise NotImplementedError('please implement function "handle_message"')
class Daemon: """ Application entry point. Initializes the application. :param python_version str: the current major python version """ def __init__(self, python_version): self.python_version = python_version self.set_chrome_path() self.set_actions() self.messenger = Messenger(self.python_version) self.is_running = False def set_actions(self): """Defines the different messages from the addon that will be handled.""" self.actions = {} self.actions[ACTIONS['VERSION']] = self.send_version self.actions[ACTIONS['COLORS']] = self.send_colorscheme self.actions[ACTIONS['CSS_ENABLE']] = self.send_enable_css_response self.actions[ACTIONS['CSS_DISABLE']] = self.send_disable_css_response def set_chrome_path(self): """Tries to set the path to the chrome directory.""" self.chrome_path = custom_css.get_firefox_chrome_path() def check_chrome_path(self, action): """ Checks if the path to the 'chrome' directory was found and sends a message if it was not. :return: if chrome_path is set :rType: bool """ if not self.chrome_path: self.messenger.send_message( Message(action, 'Could not find path to chrome folder', success=False)) return False else: return True def check_target(self, message): """ Checks if the message received specifies a target, or the message is invalid. :param message object: the decoded message :return: if message has key 'target' with a valid value :rType: bool """ if 'target' in message and len(message['target']) > 0: return message['target'] logging.error('%s: target was not specified' % message['action']) self.send_invalid_action() return False def send_version(self, message): """Sends the current daemon version to the addon.""" self.messenger.send_message(Message(ACTIONS['VERSION'], DAEMON_VERSION)) def send_colorscheme(self, message): """Sends the current colorscheme to the addon.""" (success, data) = fetcher.get_colorscheme(PYWAL_COLORS_PATH, BG_LIGHT_MODIFIER) self.messenger.send_message( Message(ACTIONS['COLORS'], data, success=success)) def send_invalid_action(self): """Sends an action to the addon indicating that the action sent was invalid""" self.messenger.send_message( Message(ACTIONS['INVALID_ACTION'], {}, success=False)) def send_output(self, message): """ Sends an output message to the addon that will be displayed in the 'Debugging output' area. :param message str: the message to send to the addon """ self.messenger.send_message(Message(ACTIONS['OUTPUT'], message)) def send_enable_css_response(self, message): """ Tries to enable a custom CSS file and sends the result to the addon. :param target string: the name of the CSS file to enable/disable """ action = ACTIONS['CSS_ENABLE'] target = self.check_target(message) if target is not False: if self.check_chrome_path(action): (success, message) = custom_css.enable_custom_css( self.chrome_path, target) self.messenger.send_message( Message(action, message, success=success)) def send_disable_css_response(self, message): """ Tries to disable a custom CSS file and sends the result to the addon. :param target string: the name of the CSS file to enable/disable """ action = ACTIONS['CSS_DISABLE'] target = self.check_target(message) if target is not False: if self.check_chrome_path(action): (success, message) = custom_css.disable_custom_css( self.chrome_path, target) self.messenger.send_message( Message(action, message, success=success)) def handle_message(self, message): """ Handles the incoming messages and does the appropriate action. :param message object: the decoded message """ try: action = message['action'] if action in self.actions: self.actions[action](message) else: logging.debug('%s: no such action' % action) self.send_invalid_action() except KeyError: logging.error('action was not defined') self.send_invalid_action() def socket_thread_worker(self): """The socket server thread worker.""" while True: message = self.socket_server.get_message() if message == 'update': logging.debug('Update triggered from external script') self.send_colorscheme() def start_socket_server(self): """Starts the socket server and creates the socket thread.""" success = self.socket_server.start() if success == True: if self.python_version == 3: # We use daemon=True so that the thread will exit when the daemon exits. # https://docs.python.org/2/library/threading.html#threading.Thread.daemon self.socket_thread = Thread(target=self.socket_thread_worker, daemon=True) else: self.socket_thread = Thread(target=self.socket_thread_worker) self.socket_thread.start() def start(self): """Starts the daemon and listens for incoming messages.""" self.is_running = True try: while True: message = self.messenger.get_message() logging.debug('Received message from addon: %s' % message) self.handle_message(message) except KeyboardInterrupt: return def close(self): """Application cleanup.""" self.socket_server.close() self.is_running = False logging.debug('Cleanup')