In effect addeed socket recovery logic; removed endpoint registery

This commit is contained in:
itdominator 2023-10-18 21:23:45 -05:00
parent 153cc450d9
commit 6fe4db7c63
15 changed files with 144 additions and 128 deletions

View File

@ -7,12 +7,12 @@ import sys
# Application imports # Application imports
from utils.event_system import EventSystem from utils.event_system import EventSystem
from utils.endpoint_registry import EndpointRegistry
from utils.keybindings import Keybindings from utils.keybindings import Keybindings
from utils.logger import Logger from utils.logger import Logger
from utils.settings_manager.manager import SettingsManager from utils.settings_manager.manager import SettingsManager
# NOTE: Threads WILL NOT die with parent's destruction. # NOTE: Threads WILL NOT die with parent's destruction.
def threaded_wrapper(fn): def threaded_wrapper(fn):
def wrapper(*args, **kwargs): def wrapper(*args, **kwargs):
@ -39,7 +39,6 @@ def sizeof_fmt_def(num, suffix="B"):
builtins.app_name = "SolarFM" builtins.app_name = "SolarFM"
builtins.keybindings = Keybindings() builtins.keybindings = Keybindings()
builtins.event_system = EventSystem() builtins.event_system = EventSystem()
builtins.endpoint_registry = EndpointRegistry()
builtins.settings_manager = SettingsManager() builtins.settings_manager = SettingsManager()
settings_manager.load_settings() settings_manager.load_settings()
@ -52,7 +51,7 @@ builtins.logger = Logger(settings_manager.get_home_config_path(), \
builtins.threaded = threaded_wrapper builtins.threaded = threaded_wrapper
builtins.daemon_threaded = daemon_threaded_wrapper builtins.daemon_threaded = daemon_threaded_wrapper
builtins.sizeof_fmt = sizeof_fmt_def builtins.sizeof_fmt = sizeof_fmt_def
builtins.event_sleep_time = 0.05
def custom_except_hook(exc_type, exc_value, exc_traceback): def custom_except_hook(exc_type, exc_value, exc_traceback):
@ -62,5 +61,4 @@ def custom_except_hook(exc_type, exc_value, exc_traceback):
logger.error("Uncaught exception", exc_info=(exc_type, exc_value, exc_traceback)) logger.error("Uncaught exception", exc_info=(exc_type, exc_value, exc_traceback))
sys.excepthook = custom_except_hook sys.excepthook = custom_except_hook

View File

@ -25,7 +25,7 @@ class Application(IPCServer):
try: try:
self.create_ipc_listener() self.create_ipc_listener()
except Exception: except Exception:
... self.socket_realization_check()
if not self.is_ipc_alive: if not self.is_ipc_alive:
for arg in unknownargs + [args.new_tab,]: for arg in unknownargs + [args.new_tab,]:
@ -35,6 +35,16 @@ class Application(IPCServer):
raise AppLaunchException(f"{app_name} IPC Server Exists: Will send path(s) to it and close...") raise AppLaunchException(f"{app_name} IPC Server Exists: Will send path(s) to it and close...")
self.setup_debug_hook()
Window(args, unknownargs)
def socket_realization_check(self):
self.send_test_ipc_message()
self.create_ipc_listener()
def setup_debug_hook(self):
try: try:
# kill -SIGUSR2 <pid> from Linux/Unix or SIGBREAK signal from Windows # kill -SIGUSR2 <pid> from Linux/Unix or SIGBREAK signal from Windows
signal.signal( signal.signal(
@ -44,5 +54,3 @@ class Application(IPCServer):
except ValueError: except ValueError:
# Typically: ValueError: signal only works in main thread # Typically: ValueError: signal only works in main thread
... ...
Window(args, unknownargs)

View File

@ -65,9 +65,11 @@ class Controller(UIMixin, SignalsMixins, Controller_Data):
FileSystemActions() FileSystemActions()
def _subscribe_to_events(self): def _subscribe_to_events(self):
event_system.subscribe("shutting_down", self._shutting_down)
event_system.subscribe("handle_file_from_ipc", self.handle_file_from_ipc) event_system.subscribe("handle_file_from_ipc", self.handle_file_from_ipc)
event_system.subscribe("generate_file_views", self._generate_file_views) event_system.subscribe("generate_file_views", self._generate_file_views)
event_system.subscribe("clear_notebooks", self.clear_notebooks) event_system.subscribe("clear_notebooks", self.clear_notebooks)
event_system.subscribe("set_window_title", self._set_window_title) event_system.subscribe("set_window_title", self._set_window_title)
event_system.subscribe("unset_selected_files_views", self._unset_selected_files_views) event_system.subscribe("unset_selected_files_views", self._unset_selected_files_views)
event_system.subscribe("get_current_state", self.get_current_state) event_system.subscribe("get_current_state", self.get_current_state)
@ -107,6 +109,10 @@ class Controller(UIMixin, SignalsMixins, Controller_Data):
FileExistsWidget() FileExistsWidget()
SaveLoadWidget() SaveLoadWidget()
def _shutting_down(self):
if not settings_manager.is_trace_debug():
self.fm_controller.save_state()
def reload_plugins(self, widget=None, eve=None): def reload_plugins(self, widget=None, eve=None):
self.plugins.reload_plugins() self.plugins.reload_plugins()
@ -162,28 +168,22 @@ class Controller(UIMixin, SignalsMixins, Controller_Data):
event_system.emit("tear_down") event_system.emit("tear_down")
@endpoint_registry.register(rule="go_home")
def go_home(self, widget=None, eve=None): def go_home(self, widget=None, eve=None):
self.builder.get_object("go_home").released() self.builder.get_object("go_home").released()
@endpoint_registry.register(rule="refresh_tab")
def refresh_tab(self, widget=None, eve=None): def refresh_tab(self, widget=None, eve=None):
self.builder.get_object("refresh_tab").released() self.builder.get_object("refresh_tab").released()
@endpoint_registry.register(rule="go_up")
def go_up(self, widget=None, eve=None): def go_up(self, widget=None, eve=None):
self.builder.get_object("go_up").released() self.builder.get_object("go_up").released()
@endpoint_registry.register(rule="grab_focus_path_entry")
def grab_focus_path_entry(self, widget=None, eve=None): def grab_focus_path_entry(self, widget=None, eve=None):
self.builder.get_object("path_entry").grab_focus() self.builder.get_object("path_entry").grab_focus()
@endpoint_registry.register(rule="tggl_top_main_menubar")
def tggl_top_main_menubar(self, widget=None, eve=None): def tggl_top_main_menubar(self, widget=None, eve=None):
top_main_menubar = self.builder.get_object("top_main_menubar") top_main_menubar = self.builder.get_object("top_main_menubar")
top_main_menubar.hide() if top_main_menubar.is_visible() else top_main_menubar.show() top_main_menubar.hide() if top_main_menubar.is_visible() else top_main_menubar.show()
@endpoint_registry.register(rule="open_terminal")
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)

View File

@ -1,7 +1,6 @@
# Python imports # Python imports
import os import os
import subprocess import subprocess
from dataclasses import dataclass
# Lib imports # Lib imports
import gi import gi
@ -9,55 +8,13 @@ gi.require_version('Gtk', '3.0')
from gi.repository import Gtk from gi.repository import Gtk
# Application imports # Application imports
from .sfm_builder import SFMBuilder
from .widgets.dialogs.message_widget import MessageWidget from .widgets.dialogs.message_widget import MessageWidget
from .widgets.dialogs.user_pass_widget import UserPassWidget from .widgets.dialogs.user_pass_widget import UserPassWidget
from shellfm.windows.controller import WindowController from utils.types.state import State
from plugins.plugins_controller import PluginsController from plugins.plugins_controller import PluginsController
from shellfm.windows.controller import WindowController
@dataclass(slots=True)
class State:
fm_controller: any = None
notebooks: any = None
wid: int = None
tid: int = None
tab: type = None
icon_grid: gi.overrides.Gtk.IconView = None
store: gi.overrides.Gtk.ListStore = None
uris: [] = None
uris_raw: [] = None
selected_files: [] = None
to_copy_files: [] = None
to_cut_files: [] = None
message_dialog: type = None
user_pass_dialog: type = None
class SFMBuilder(Gtk.Builder):
"""docstring for SFMBuilder."""
def __init__(self):
super(SFMBuilder, self).__init__()
self.objects = {}
def get_object(self, id: str, use_gtk: bool = True) -> any:
if not use_gtk:
return self.objects[id]
return super(SFMBuilder, self).get_object(id)
def expose_object(self, id: str, object: any, use_gtk: bool = True) -> None:
if not use_gtk:
self.objects[id] = object
else:
super(SFMBuilder, self).expose_object(id, object)
def dereference_object(self, id: str) -> None:
del self.objects[id]

View File

@ -85,7 +85,7 @@ class WindowMixin(TabMixin):
self.set_window_title() self.set_window_title()
if eve.type == Gdk.EventType.BUTTON_RELEASE and eve.button == 1: # l-click if eve.type == Gdk.EventType.BUTTON_RELEASE and eve.button == 1: # l-click
if self.ctrl_down: if eve.state & Gdk.ModifierType.CONTROL_MASK:
self.dnd_left_primed = 0 self.dnd_left_primed = 0
if self.single_click_open: # FIXME: need to find a way to pass the model index if self.single_click_open: # FIXME: need to find a way to pass the model index

View File

@ -0,0 +1,33 @@
# Python imports
# Lib imports
import gi
gi.require_version('Gtk', '3.0')
from gi.repository import Gtk
# Application imports
class SFMBuilder(Gtk.Builder):
"""docstring for SFMBuilder."""
def __init__(self):
super(SFMBuilder, self).__init__()
self.objects = {}
def get_object(self, id: str, use_gtk: bool = True) -> any:
if not use_gtk:
return self.objects[id]
return super(SFMBuilder, self).get_object(id)
def expose_object(self, id: str, object: any, use_gtk: bool = True) -> None:
if not use_gtk:
self.objects[id] = object
else:
super(SFMBuilder, self).expose_object(id, object)
def dereference_object(self, id: str) -> None:
del self.objects[id]

View File

@ -77,7 +77,7 @@ class UIMixin(PaneMixin, WindowMixin):
scroll_win = notebook.get_children()[-1] scroll_win = notebook.get_children()[-1]
icon_grid = scroll_win.get_children()[0] icon_grid = scroll_win.get_children()[0]
self._focus_last_visible_notebook(icon_grid) # self._focus_last_visible_notebook(icon_grid)
except UIMixinException as e: except UIMixinException as e:
logger.info("\n: The saved session might be missing window data! :\nLocation: ~/.config/solarfm/session.json\nFix: Back it up and delete it to reset.\n") logger.info("\n: The saved session might be missing window data! :\nLocation: ~/.config/solarfm/session.json\nFix: Back it up and delete it to reset.\n")
logger.debug(repr(e)) logger.debug(repr(e))

View File

@ -80,7 +80,7 @@ class WindowMixin(TabMixin):
self.set_window_title() self.set_window_title()
if eve.type == Gdk.EventType.BUTTON_RELEASE and eve.button == 1: # l-click if eve.type == Gdk.EventType.BUTTON_RELEASE and eve.button == 1: # l-click
if self.ctrl_down: if eve.state & Gdk.ModifierType.CONTROL_MASK:
self.dnd_left_primed = 0 self.dnd_left_primed = 0
if self.single_click_open: # FIXME: need to find a way to pass the model index if self.single_click_open: # FIXME: need to find a way to pass the model index

View File

@ -20,8 +20,6 @@ class IconGridWidget(Gtk.IconView):
def __init__(self): def __init__(self):
super(IconGridWidget, self).__init__() super(IconGridWidget, self).__init__()
# self._store = None
self._setup_styling() self._setup_styling()
self._setup_signals() self._setup_signals()
self._set_up_dnd() self._set_up_dnd()

View File

@ -88,11 +88,7 @@ class Window(Gtk.ApplicationWindow):
cr.set_operator(cairo.OPERATOR_OVER) cr.set_operator(cairo.OPERATOR_OVER)
def _tear_down(self, widget=None, eve=None): def _tear_down(self, widget = None, eve = None):
if not settings_manager.is_trace_debug(): event_system.emit("shutting_down")
self._controller.fm_controller.save_state()
settings_manager.clear_pid() settings_manager.clear_pid()
time.sleep(event_sleep_time)
Gtk.main_quit() Gtk.main_quit()

View File

@ -24,32 +24,12 @@ class PluginBase:
self._event_system = None self._event_system = None
def set_fm_event_system(self, fm_event_system): def run(self):
""" """
Requests Key: 'pass_fm_events': "true" Must define regardless if needed and can 'pass' if plugin doesn't need it.
Must define in plugin if "pass_fm_events" is set to "true" string. Is intended to be used to setup internal signals or custom Gtk Builders/UI logic.
""" """
self._event_system = fm_event_system raise PluginBaseException("Method hasn't been overriden...")
def set_ui_object_collection(self, ui_objects):
"""
Requests Key: "pass_ui_objects": [""]
Request reference to a UI component. Will be passed back as array to plugin.
Must define in plugin if set and an array of valid glade UI IDs is given.
"""
self._ui_objects = ui_objects
def clear_children(self, widget: type) -> None:
""" Clear children of a gtk widget. """
for child in widget.get_children():
widget.remove(child)
def subscribe_to_events(self):
self._event_system.subscribe("update_state_info_plugins", self._update_fm_state_info)
def _update_fm_state_info(self, state):
self._fm_state = state
def generate_reference_ui_element(self): def generate_reference_ui_element(self):
""" """
@ -59,12 +39,26 @@ class PluginBase:
""" """
raise PluginBaseException("Method hasn't been overriden...") raise PluginBaseException("Method hasn't been overriden...")
def run(self): def set_ui_object_collection(self, ui_objects):
""" """
Must define regardless if needed and can 'pass' if plugin doesn't need it. Requests Key: "pass_ui_objects": [""]
Is intended to be used to setup internal signals or custom Gtk Builders/UI logic. Request reference to a UI component. Will be passed back as array to plugin.
Must define in plugin if set and an array of valid glade UI IDs is given.
""" """
raise PluginBaseException("Method hasn't been overriden...") self._ui_objects = ui_objects
def set_fm_event_system(self, fm_event_system):
"""
Requests Key: 'pass_fm_events': "true"
Must define in plugin if "pass_fm_events" is set to "true" string.
"""
self._event_system = fm_event_system
def subscribe_to_events(self):
self._event_system.subscribe("update_state_info_plugins", self._update_fm_state_info)
def _update_fm_state_info(self, state):
self._fm_state = state
def _connect_builder_signals(self, caller_class, builder): def _connect_builder_signals(self, caller_class, builder):
classes = [caller_class] classes = [caller_class]
@ -94,3 +88,9 @@ class PluginBase:
reload_package_recursive(path, module_dict[path.stem].__dict__) reload_package_recursive(path, module_dict[path.stem].__dict__)
reload_package_recursive(Path(plugin_path).parent, module_dict_main["module_dict_main"]) reload_package_recursive(Path(plugin_path).parent, module_dict_main["module_dict_main"])
def clear_children(self, widget: type) -> None:
""" Clear children of a gtk widget. """
for child in widget.get_children():
widget.remove(child)

View File

@ -1,22 +0,0 @@
# Python imports
# Lib imports
# Application imports
from .singleton import Singleton
class EndpointRegistry(Singleton):
def __init__(self):
self._endpoints = {}
def register(self, rule, **options):
def decorator(f):
self._endpoints[rule] = f
return f
return decorator
def get_endpoints(self):
return self._endpoints

View File

@ -43,13 +43,13 @@ class IPCServer(Singleton):
if os.path.exists(self._ipc_address) and settings.is_dirty_start(): if os.path.exists(self._ipc_address) and settings.is_dirty_start():
os.unlink(self._ipc_address) os.unlink(self._ipc_address)
listener = Listener(address=self._ipc_address, family="AF_UNIX", authkey=self._ipc_authkey) listener = Listener(address = self._ipc_address, family = "AF_UNIX", authkey = self._ipc_authkey)
elif "unsecured" not in self._conn_type: elif "unsecured" not in self._conn_type:
listener = Listener((self._ipc_address, self._ipc_port), authkey=self._ipc_authkey) listener = Listener((self._ipc_address, self._ipc_port), authkey = self._ipc_authkey)
else: else:
listener = Listener((self._ipc_address, self._ipc_port)) listener = Listener((self._ipc_address, self._ipc_port))
self.is_ipc_alive = True self.is_ipc_alive = True
self._run_ipc_loop(listener) self._run_ipc_loop(listener)
@ -61,15 +61,14 @@ class IPCServer(Singleton):
start_time = time.perf_counter() start_time = time.perf_counter()
GLib.idle_add(self._handle_ipc_message, *(conn, start_time,)) GLib.idle_add(self._handle_ipc_message, *(conn, start_time,))
except Exception as e: except Exception as e:
... logger.debug( repr(e) )
listener.close() listener.close()
def _handle_ipc_message(self, conn, start_time) -> None: def _handle_ipc_message(self, conn, start_time) -> None:
while True: while True:
msg = conn.recv() msg = conn.recv()
if settings_manager.is_debug(): logger.debug(msg)
print(msg)
if "FILE|" in msg: if "FILE|" in msg:
file = msg.split("FILE|")[1].strip() file = msg.split("FILE|")[1].strip()
@ -103,6 +102,25 @@ class IPCServer(Singleton):
conn.send(message) conn.send(message)
conn.close() conn.close()
except ConnectionRefusedError as e: except ConnectionRefusedError as e:
print("Connection refused...") logger.error("Connection refused...")
except Exception as e: except Exception as e:
print(repr(e)) logger.error( repr(e) )
def send_test_ipc_message(self, message: str = "Empty Data...") -> None:
try:
if self._conn_type == "socket":
conn = Client(address=self._ipc_address, family="AF_UNIX", authkey=self._ipc_authkey)
elif "unsecured" not in self._conn_type:
conn = Client((self._ipc_address, self._ipc_port), authkey=self._ipc_authkey)
else:
conn = Client((self._ipc_address, self._ipc_port))
conn.send(message)
conn.close()
except ConnectionRefusedError as e:
if self._conn_type == "socket":
logger.error("IPC Socket no longer valid.... Removing.")
os.unlink(self._ipc_address)
except Exception as e:
logger.error( repr(e) )

View File

@ -0,0 +1,3 @@
"""
Utils module
"""

View File

@ -0,0 +1,27 @@
# Python imports
from dataclasses import dataclass
# Lib imports
from gi.overrides.Gtk import IconView
from gi.overrides.Gtk import ListStore
# Application imports
@dataclass(slots=True)
class State:
fm_controller: any = None
notebooks: any = None
wid: int = None
tid: int = None
tab: type = None
icon_grid: IconView = None
store: ListStore = None
uris: list = None
uris_raw: list = None
selected_files: list = None
to_copy_files: list = None
to_cut_files: list = None
message_dialog: type = None
user_pass_dialog: type = None