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
import sys, threading, subprocess, time
import os, threading, subprocess, time
# Gtk imports
import gi
@ -9,45 +9,74 @@ from gi.repository import Gtk
# Application imports
# NOTE: Threads will not die with parent's destruction
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):
threading.Thread(target=fn, args=args, kwargs=kwargs, daemon=True).start()
return wrapper
class Plugin:
def __init__(self, builder, event_system):
self._plugin_name = "Example Plugin"
self._builder = builder
self._event_system = event_system
self._message = None
self._time_out = 5
self.SCRIPT_PTH = os.path.dirname(os.path.realpath(__file__))
self._plugin_name = "Example Plugin"
self._plugin_author = "John Doe"
self._plugin_version = "0.0.1"
button = Gtk.Button(label=self._plugin_name)
button.connect("button-release-event", self._do_action)
self._builder = builder
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.show_all()
@threaded
def _do_action(self, widget=None, eve=None):
def send_message(self, widget=None, eve=None):
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):
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):
return self._socket_id
def _run_timeout(self):
timeout = 0
while not self._message and timeout < self._time_out:
time.sleep(1)
timeout += 1
@daemon_threaded
def _module_event_observer(self):
while True:
time.sleep(self._event_sleep_time)
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
import os, sys, threading, subprocess, time
import os, threading, subprocess, time
# Gtk imports
import gi
@ -9,49 +9,78 @@ from gi.repository import Gtk
# Application imports
# NOTE: Threads will not die with parent's destruction
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):
threading.Thread(target=fn, args=args, kwargs=kwargs, daemon=True).start()
return wrapper
class Plugin:
def __init__(self, builder, event_system):
self._plugin_name = "Youtube Download"
self._builder = builder
self._event_system = event_system
self._message = None
self._time_out = 5
def __init__(self, fm_builder, fm_event_system):
self.SCRIPT_PTH = os.path.dirname(os.path.realpath(__file__))
self._plugin_name = "Youtube Download"
self._plugin_author = "ITDominator"
self._plugin_version = "0.0.1"
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)
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.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
def _do_download(self, widget=None, eve=None):
self._event_system.push_gui_event([self._plugin_name, "get_current_state", ()])
self._run_timeout()
self._fm_event_system.push_gui_event([self._plugin_name, "get_current_state", ()])
while not self._fm_event_message:
pass
if self._message:
state = self._message
subprocess.Popen([f'{self.SCRIPT_PTH}/download.sh' , state.tab.get_current_directory()])
self._message = None
state = self._fm_event_message
subprocess.Popen([f'{self.SCRIPT_PTH}/download.sh' , state.tab.get_current_directory()])
self._fm_event_message = None
def set_message(self, data):
self._message = data
def get_plugin_name(self):
return self._plugin_name
def _run_timeout(self):
timeout = 0
while not self._message and timeout < self._time_out:
time.sleep(1)
timeout += 1
def get_plugin_author(self):
return self._plugin_author
def get_plugin_version(self):
return self._plugin_version

View File

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

View File

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

View File

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

View File

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

View File

@ -12,6 +12,8 @@ from gi.repository import Gtk, Gio
class Plugin:
name: str = None
author: str = None
version: str = None
module: str = None
reference: type = None
@ -61,6 +63,9 @@ class Plugins:
plugin_reference = app.Plugin(self._builder, event_system)
plugin = Plugin()
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.reference = plugin_reference
@ -74,10 +79,3 @@ class Plugins:
def reload_plugins(self, file: str = None) -> None:
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)
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)
if not os.path.isfile(remux_vid_pth):

View File

@ -5,39 +5,39 @@ import os, logging
class Logger:
def __init__(self, config_path: str):
self._CONFIG_PATH = config_path
def get_logger(self, loggerName: str = "NO_LOGGER_NAME_PASSED", createFile: bool = True) -> logging.Logger:
"""
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)
"""
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
CRITICAL 50
ERROR 40
WARNING 30
INFO 20
DEBUG 10
: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 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
: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
chLogLevel = logging.CRITICAL # Prety musch the only one we change ever
fhLogLevel = logging.DEBUG
def __init__(self, config_path: str, _ch_log_lvl = logging.CRITICAL, _fh_log_lvl = logging.INFO):
self._CONFIG_PATH = config_path
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.setLevel(globalLogLvl)
log.setLevel(self.global_lvl)
# Set our log output styles
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')
ch = logging.StreamHandler()
ch.setLevel(level=chLogLevel)
ch.setLevel(level=self.ch_log_lvl)
ch.setFormatter(cFormatter)
log.addHandler(ch)
@ -49,7 +49,7 @@ class Logger:
os.mkdir(folder)
fh = logging.FileHandler(file)
fh.setLevel(level=fhLogLevel)
fh.setLevel(level=self.fh_log_lvl)
fh.setFormatter(fFormatter)
log.addHandler(fh)

View File

@ -59,7 +59,7 @@ class Settings:
self._keybindings.configure(keybindings)
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.add_from_file(self._GLADE_FILE)