Update logging, update event system, update plugin structure

This commit is contained in:
itdominator 2022-06-14 23:03:04 -05:00
parent ee086f67f4
commit 793621745a
10 changed files with 164 additions and 103 deletions

View File

@ -1,5 +1,5 @@
# Python imports # Python imports
import sys, threading, subprocess, time import os, threading, subprocess, time
# Gtk imports # Gtk imports
import gi import gi
@ -9,45 +9,74 @@ from gi.repository import Gtk
# Application imports # Application imports
# NOTE: Threads will not die with parent's destruction
def threaded(fn): def threaded(fn):
def wrapper(*args, **kwargs): def wrapper(*args, **kwargs):
threading.Thread(target=fn, args=args, kwargs=kwargs, daemon=False).start() threading.Thread(target=fn, args=args, kwargs=kwargs, daemon=False).start()
return wrapper return wrapper
# NOTE: Insure threads die with parent's destruction
def daemon_threaded(fn):
def wrapper(*args, **kwargs):
threading.Thread(target=fn, args=args, kwargs=kwargs, daemon=True).start()
return wrapper
class Plugin: class Plugin:
def __init__(self, builder, event_system): def __init__(self, builder, event_system):
self._plugin_name = "Example Plugin" self.SCRIPT_PTH = os.path.dirname(os.path.realpath(__file__))
self._builder = builder self._plugin_name = "Example Plugin"
self._event_system = event_system self._plugin_author = "John Doe"
self._message = None self._plugin_version = "0.0.1"
self._time_out = 5
button = Gtk.Button(label=self._plugin_name) self._builder = builder
button.connect("button-release-event", self._do_action) self._event_system = event_system
self._event_sleep_time = .5
self._event_message = None
plugin_list = self._builder.get_object("plugin_socket") button = Gtk.Button(label=self._plugin_name)
button.connect("button-release-event", self.send_message)
# self._module_event_observer() # NOTE: Enable if you want the plugin to watch for events sent to it
plugin_list = self._builder.get_object("plugin_socket")
plugin_list.add(button) plugin_list.add(button)
plugin_list.show_all() plugin_list.show_all()
@threaded def send_message(self, widget=None, eve=None):
def _do_action(self, widget=None, eve=None):
message = "Hello, World!" message = "Hello, World!"
self._event_system.push_gui_event(["some_type", "display_message", ("warning", message, None)]) self._event_system.push_gui_event([self._plugin_name, "display_message", ("warning", message, None)])
def set_message(self, data):
self._message = data
def get_plugin_name(self): def get_plugin_name(self):
return self._plugin_name return self._plugin_name
def get_plugin_author(self):
return self._plugin_author
def get_plugin_version(self):
return self._plugin_version
def get_socket_id(self): def get_socket_id(self):
return self._socket_id return self._socket_id
def _run_timeout(self): @daemon_threaded
timeout = 0 def _module_event_observer(self):
while not self._message and timeout < self._time_out: while True:
time.sleep(1) time.sleep(self._event_sleep_time)
timeout += 1 event = self._event_system.read_module_event()
if event:
try:
if event[0] is self._plugin_name:
target_id, method_target, data = self._event_system.consume_module_event()
if not method_target:
self._event_message = data
else:
method = getattr(self.__class__, f"{method_target}")
data = method(*(self, *parameters))
except Exception as e:
print(repr(e))

View File

@ -1,5 +1,5 @@
# Python imports # Python imports
import os, sys, threading, subprocess, time import os, threading, subprocess, time
# Gtk imports # Gtk imports
import gi import gi
@ -9,49 +9,78 @@ from gi.repository import Gtk
# Application imports # Application imports
# NOTE: Threads will not die with parent's destruction
def threaded(fn): def threaded(fn):
def wrapper(*args, **kwargs): def wrapper(*args, **kwargs):
threading.Thread(target=fn, args=args, kwargs=kwargs, daemon=False).start() threading.Thread(target=fn, args=args, kwargs=kwargs, daemon=False).start()
return wrapper return wrapper
# NOTE: Insure threads die with parent's destruction
def daemon_threaded(fn):
def wrapper(*args, **kwargs):
threading.Thread(target=fn, args=args, kwargs=kwargs, daemon=True).start()
return wrapper
class Plugin: class Plugin:
def __init__(self, builder, event_system): def __init__(self, fm_builder, fm_event_system):
self._plugin_name = "Youtube Download" self.SCRIPT_PTH = os.path.dirname(os.path.realpath(__file__))
self._builder = builder self._plugin_name = "Youtube Download"
self._event_system = event_system self._plugin_author = "ITDominator"
self._message = None self._plugin_version = "0.0.1"
self._time_out = 5
self.SCRIPT_PTH = os.path.dirname(os.path.realpath(__file__)) self._fm_builder = fm_builder
self._fm_event_system = fm_event_system
self._event_sleep_time = .5
self._fm_event_message = None
button = Gtk.Button(label=self._plugin_name)
button = Gtk.Button(label=self._plugin_name)
button.connect("button-release-event", self._do_download) button.connect("button-release-event", self._do_download)
plugin_list = self._builder.get_object("plugin_socket") self._module_event_observer()
plugin_list = self._fm_builder.get_object("plugin_socket")
plugin_list.add(button) plugin_list.add(button)
plugin_list.show_all() plugin_list.show_all()
@daemon_threaded
def _module_event_observer(self):
while True:
time.sleep(self._event_sleep_time)
event = self._fm_event_system.read_module_event()
if event:
try:
if event[0] is self._plugin_name:
target_id, method_target, data = self._fm_event_system.consume_module_event()
if not method_target:
self._fm_event_message = data
else:
method = getattr(self.__class__, f"{method_target}")
data = method(*(self, *parameters))
except Exception as e:
print(repr(e))
@threaded @threaded
def _do_download(self, widget=None, eve=None): def _do_download(self, widget=None, eve=None):
self._event_system.push_gui_event([self._plugin_name, "get_current_state", ()]) self._fm_event_system.push_gui_event([self._plugin_name, "get_current_state", ()])
self._run_timeout() while not self._fm_event_message:
pass
if self._message: state = self._fm_event_message
state = self._message subprocess.Popen([f'{self.SCRIPT_PTH}/download.sh' , state.tab.get_current_directory()])
subprocess.Popen([f'{self.SCRIPT_PTH}/download.sh' , state.tab.get_current_directory()]) self._fm_event_message = None
self._message = None
def set_message(self, data):
self._message = data
def get_plugin_name(self): def get_plugin_name(self):
return self._plugin_name return self._plugin_name
def _run_timeout(self): def get_plugin_author(self):
timeout = 0 return self._plugin_author
while not self._message and timeout < self._time_out:
time.sleep(1) def get_plugin_version(self):
timeout += 1 return self._plugin_version

View File

@ -15,17 +15,17 @@ class EventSystem(IPCServer):
def __init__(self): def __init__(self):
super(EventSystem, self).__init__() super(EventSystem, self).__init__()
# NOTE: The format used is list of [type, target, (data,)] Where: # NOTE: The format used is list of ['who', target, (data,)] Where:
# type is useful context for control flow, # who is the sender or target ID and is used for context and control flow,
# target is the method to call, # method_target is the method to call,
# data is the method parameters to give # data is the method parameters OR message data to give
# Where data may be any kind of data # Where data may be any kind of data
self._gui_events = [] self._gui_events = []
self._module_events = [] self._module_events = []
# Makeshift fake "events" type system FIFO # Makeshift "events" system FIFO
def _pop_gui_event(self) -> None: def _pop_gui_event(self) -> None:
if len(self._gui_events) > 0: if len(self._gui_events) > 0:
return self._gui_events.pop(0) return self._gui_events.pop(0)
@ -42,20 +42,20 @@ class EventSystem(IPCServer):
self._gui_events.append(event) self._gui_events.append(event)
return None return None
raise Exception("Invald event format! Please do: [type, target, (data,)]") raise Exception("Invald event format! Please do: ['sender_id': str, method_target: method, (data,): any]")
def push_module_event(self, event: list) -> None: def push_module_event(self, event: list) -> None:
if len(event) == 3: if len(event) == 3:
self._module_events.append(event) self._module_events.append(event)
return None return None
raise Exception("Invald event format! Please do: [type, target, (data,)]") raise Exception("Invald event format! Please do: ['target_id': str, method_target: method, (data,): any]")
def read_gui_event(self) -> list: def read_gui_event(self) -> list:
return self._gui_events[0] return self._gui_events[0] if self._gui_events else None
def read_module_event(self) -> list: def read_module_event(self) -> list:
return self._module_events[0] return self._module_events[0] if self._module_events else None
def consume_gui_event(self) -> list: def consume_gui_event(self) -> list:
return self._pop_gui_event() return self._pop_gui_event()
@ -69,6 +69,6 @@ class EventSystem(IPCServer):
# __builtins__.update({"event_system": Builtins()}) # __builtins__.update({"event_system": Builtins()})
builtins.app_name = "SolarFM" builtins.app_name = "SolarFM"
builtins.event_system = EventSystem() builtins.event_system = EventSystem()
builtins.event_sleep_time = 0.2 builtins.event_sleep_time = 0.05
builtins.trace_debug = False builtins.trace_debug = False
builtins.debug = False builtins.debug = False

View File

@ -17,7 +17,7 @@ class Application(EventSystem):
def __init__(self, args, unknownargs): def __init__(self, args, unknownargs):
if not trace_debug: if not trace_debug:
event_system.create_ipc_listener() event_system.create_ipc_listener()
time.sleep(0.1) time.sleep(0.05)
if not event_system.is_ipc_alive: if not event_system.is_ipc_alive:
if unknownargs: if unknownargs:

View File

@ -1,5 +1,5 @@
# Python imports # Python imports
import os, gc, threading, time, shlex import os, gc, threading, time
# Lib imports # Lib imports
import gi import gi
@ -14,7 +14,14 @@ from .signals.keyboard_signals_mixin import KeyboardSignalsMixin
from .controller_data import Controller_Data from .controller_data import Controller_Data
# NOTE: Threads will not die with parent's destruction
def threaded(fn): def threaded(fn):
def wrapper(*args, **kwargs):
threading.Thread(target=fn, args=args, kwargs=kwargs, daemon=False).start()
return wrapper
# NOTE: Insure threads die with parent's destruction
def daemon_threaded(fn):
def wrapper(*args, **kwargs): def wrapper(*args, **kwargs):
threading.Thread(target=fn, args=args, kwargs=kwargs, daemon=True).start() threading.Thread(target=fn, args=args, kwargs=kwargs, daemon=True).start()
return wrapper return wrapper
@ -62,20 +69,20 @@ class Controller(UIMixin, KeyboardSignalsMixin, IPCSignalsMixin, ExceptionHookMi
event = event_system.consume_gui_event() event = event_system.consume_gui_event()
if event: if event:
try: try:
type, target, data = event sender_id, method_target, parameters = event
if type: if sender_id:
method = getattr(self.__class__, "handle_gui_event_and_set_message") method = getattr(self.__class__, "handle_gui_event_and_return_message")
GLib.idle_add(method, *(self, type, target, data)) GLib.idle_add(method, *(self, sender_id, method_target, parameters))
else: else:
method = getattr(self.__class__, target) method = getattr(self.__class__, method_target)
GLib.idle_add(method, *(self, *data,)) GLib.idle_add(method, *(self, *parameters,))
except Exception as e: except Exception as e:
print(repr(e)) print(repr(e))
def handle_gui_event_and_set_message(self, type, target, parameters): def handle_gui_event_and_return_message(self, sender, method_target, parameters):
method = getattr(self.__class__, f"{target}") method = getattr(self.__class__, f"{method_target}")
data = method(*(self, *parameters)) data = method(*(self, *parameters))
self.plugins.send_message_to_plugin(type, data) event_system.push_module_event([sender, None, data])
def save_load_session(self, action="save_session"): def save_load_session(self, action="save_session"):
wid, tid = self.fm_controller.get_active_wid_and_tid() wid, tid = self.fm_controller.get_active_wid_and_tid()
@ -110,7 +117,7 @@ class Controller(UIMixin, KeyboardSignalsMixin, IPCSignalsMixin, ExceptionHookMi
def load_session(self, session_json): def load_session(self, session_json):
if debug: if debug:
print(f"Session Data: {session_json}") self.logger.debug(f"Session Data: {session_json}")
self.ctrl_down = False self.ctrl_down = False
self.shift_down = False self.shift_down = False
@ -186,5 +193,4 @@ class Controller(UIMixin, KeyboardSignalsMixin, IPCSignalsMixin, ExceptionHookMi
def open_terminal(self, widget=None, eve=None): def open_terminal(self, widget=None, eve=None):
wid, tid = self.fm_controller.get_active_wid_and_tid() wid, tid = self.fm_controller.get_active_wid_and_tid()
tab = self.get_fm_window(wid).get_tab_by_id(tid) tab = self.get_fm_window(wid).get_tab_by_id(tid)
dir = tab.get_current_directory() tab.execute([f"{tab.terminal_app}"], start_dir=tab.get_current_directory())
tab.execute([f"{tab.terminal_app}"], start_dir=shlex.quote(dir))

View File

@ -45,7 +45,7 @@ class WidgetFileActionMixin:
watcher = tab.get_dir_watcher() watcher = tab.get_dir_watcher()
watcher.cancel() watcher.cancel()
if debug: if debug:
print(f"Watcher Is Cancelled: {watcher.is_cancelled()}") self.logger.debug(f"Watcher Is Cancelled: {watcher.is_cancelled()}")
cur_dir = tab.get_current_directory() cur_dir = tab.get_current_directory()
@ -64,7 +64,7 @@ class WidgetFileActionMixin:
Gio.FileMonitorEvent.RENAMED, Gio.FileMonitorEvent.MOVED_IN, Gio.FileMonitorEvent.RENAMED, Gio.FileMonitorEvent.MOVED_IN,
Gio.FileMonitorEvent.MOVED_OUT]: Gio.FileMonitorEvent.MOVED_OUT]:
if debug: if debug:
print(eve_type) self.logger.debug(eve_type)
if eve_type in [Gio.FileMonitorEvent.MOVED_IN, Gio.FileMonitorEvent.MOVED_OUT]: if eve_type in [Gio.FileMonitorEvent.MOVED_IN, Gio.FileMonitorEvent.MOVED_OUT]:
self.update_on_soft_lock_end(data[0]) self.update_on_soft_lock_end(data[0])
@ -85,7 +85,6 @@ class WidgetFileActionMixin:
if (current_time - last_update_time) > 0.6: if (current_time - last_update_time) > 0.6:
lock = False lock = False
self.soft_update_lock.pop(tab_widget, None) self.soft_update_lock.pop(tab_widget, None)
GLib.idle_add(self.update_on_soft_lock_end, *(tab_widget,)) GLib.idle_add(self.update_on_soft_lock_end, *(tab_widget,))
@ -427,10 +426,10 @@ class WidgetFileActionMixin:
start = "-copy" start = "-copy"
if debug: if debug:
print(f"Path: {full_path}") self.logger.debug(f"Path: {full_path}")
print(f"Base Path: {base_path}") self.logger.debug(f"Base Path: {base_path}")
print(f'Name: {file_name}') self.logger.debug(f'Name: {file_name}')
print(f"Extension: {extension}") self.logger.debug(f"Extension: {extension}")
i = 2 i = 2
while target.query_exists(): while target.query_exists():

View File

@ -12,6 +12,8 @@ from gi.repository import Gtk, Gio
class Plugin: class Plugin:
name: str = None name: str = None
author: str = None
version: str = None
module: str = None module: str = None
reference: type = None reference: type = None
@ -61,6 +63,9 @@ class Plugins:
plugin_reference = app.Plugin(self._builder, event_system) plugin_reference = app.Plugin(self._builder, event_system)
plugin = Plugin() plugin = Plugin()
plugin.name = plugin_reference.get_plugin_name() plugin.name = plugin_reference.get_plugin_name()
plugin.author = plugin_reference.get_plugin_author()
plugin.version = plugin_reference.get_plugin_version()
plugin.module = path plugin.module = path
plugin.reference = plugin_reference plugin.reference = plugin_reference
@ -74,10 +79,3 @@ class Plugins:
def reload_plugins(self, file: str = None) -> None: def reload_plugins(self, file: str = None) -> None:
print(f"Reloading plugins... stub.") print(f"Reloading plugins... stub.")
def send_message_to_plugin(self, target: str , data: type) -> None:
print("Trying to send message to plugin...")
for plugin in self._plugin_collection:
if target in plugin.name:
print('Found plugin; posting message...')
plugin.reference.set_message(data)

View File

@ -59,7 +59,7 @@ class Launcher:
app_info.launch_uris_async(uris) app_info.launch_uris_async(uris)
def remux_video(self, hash, file): def remux_video(self, hash, file):
remux_vid_pth = self.REMUX_FOLDER + "/" + hash + ".mp4" remux_vid_pth = "{self.REMUX_FOLDER}/{hash}.mp4"
self.logger.debug(remux_vid_pth) self.logger.debug(remux_vid_pth)
if not os.path.isfile(remux_vid_pth): if not os.path.isfile(remux_vid_pth):

View File

@ -5,39 +5,39 @@ import os, logging
class Logger: class Logger:
def __init__(self, config_path: str): """
self._CONFIG_PATH = config_path Create a new logging object and return it.
:note:
def get_logger(self, loggerName: str = "NO_LOGGER_NAME_PASSED", createFile: bool = True) -> logging.Logger: NOSET # Don't know the actual log level of this... (defaulting or literally none?)
""" Log Levels (From least to most)
Create a new logging object and return it.
:note:
NOSET # Don't know the actual log level of this... (defaulting or literally none?)
Log Levels (From least to most)
Type Value Type Value
CRITICAL 50 CRITICAL 50
ERROR 40 ERROR 40
WARNING 30 WARNING 30
INFO 20 INFO 20
DEBUG 10 DEBUG 10
:param loggerName: Sets the name of the logger object. (Used in log lines) :param loggerName: Sets the name of the logger object. (Used in log lines)
:param createFile: Whether we create a log file or just pump to terminal :param createFile: Whether we create a log file or just pump to terminal
:return: the logging object we created :return: the logging object we created
""" """
globalLogLvl = logging.DEBUG # Keep this at highest so that handlers can filter to their desired levels def __init__(self, config_path: str, _ch_log_lvl = logging.CRITICAL, _fh_log_lvl = logging.INFO):
chLogLevel = logging.CRITICAL # Prety musch the only one we change ever self._CONFIG_PATH = config_path
fhLogLevel = logging.DEBUG self.global_lvl = logging.DEBUG # Keep this at highest so that handlers can filter to their desired levels
self.ch_log_lvl = _ch_log_lvl # Prety much the only one we ever change
self.fh_log_lvl = _fh_log_lvl
def get_logger(self, loggerName: str = "NO_LOGGER_NAME_PASSED", createFile: bool = True) -> logging.Logger:
log = logging.getLogger(loggerName) log = logging.getLogger(loggerName)
log.setLevel(globalLogLvl) log.setLevel(self.global_lvl)
# Set our log output styles # Set our log output styles
fFormatter = logging.Formatter('[%(asctime)s] %(pathname)s:%(lineno)d %(levelname)s - %(message)s', '%m-%d %H:%M:%S') fFormatter = logging.Formatter('[%(asctime)s] %(pathname)s:%(lineno)d %(levelname)s - %(message)s', '%m-%d %H:%M:%S')
cFormatter = logging.Formatter('%(pathname)s:%(lineno)d] %(levelname)s - %(message)s') cFormatter = logging.Formatter('%(pathname)s:%(lineno)d] %(levelname)s - %(message)s')
ch = logging.StreamHandler() ch = logging.StreamHandler()
ch.setLevel(level=chLogLevel) ch.setLevel(level=self.ch_log_lvl)
ch.setFormatter(cFormatter) ch.setFormatter(cFormatter)
log.addHandler(ch) log.addHandler(ch)
@ -49,7 +49,7 @@ class Logger:
os.mkdir(folder) os.mkdir(folder)
fh = logging.FileHandler(file) fh = logging.FileHandler(file)
fh.setLevel(level=fhLogLevel) fh.setLevel(level=self.fh_log_lvl)
fh.setFormatter(fFormatter) fh.setFormatter(fFormatter)
log.addHandler(fh) log.addHandler(fh)

View File

@ -59,7 +59,7 @@ class Settings:
self._keybindings.configure(keybindings) self._keybindings.configure(keybindings)
self._main_window = None self._main_window = None
self._logger = Logger(self._CONFIG_PATH).get_logger() self._logger = Logger(self._CONFIG_PATH, _fh_log_lvl=20).get_logger()
self._builder = Gtk.Builder() self._builder = Gtk.Builder()
self._builder.add_from_file(self._GLADE_FILE) self._builder.add_from_file(self._GLADE_FILE)