From 28fefafa6f8c239541cf8c534a5ae5e59e58b14b Mon Sep 17 00:00:00 2001 From: itdominator <1itdominator@gmail.com> Date: Wed, 10 Dec 2025 19:27:06 -0600 Subject: [PATCH] Fixed IPC issues; cleaned up arg passthrough flow --- src/solarfm/__main__.py | 6 ++- src/solarfm/app.py | 46 +++++++++++-------- src/solarfm/core/controller.py | 34 ++++++++------ .../core/mixins/signals/ipc_signals_mixin.py | 2 +- src/solarfm/core/window.py | 11 ++--- src/solarfm/utils/ipc_server.py | 37 ++++++++------- src/solarfm/utils/settings_manager/manager.py | 31 +++++++++---- .../settings_manager/start_check_mixin.py | 2 +- 8 files changed, 96 insertions(+), 73 deletions(-) diff --git a/src/solarfm/__main__.py b/src/solarfm/__main__.py index e0d5563..0ce080f 100644 --- a/src/solarfm/__main__.py +++ b/src/solarfm/__main__.py @@ -25,7 +25,6 @@ def limit_memory(maxsize): def main(args, unknownargs): setproctitle(f'{app_name}') - # limit_memory(248 * (1024 * 1024 * 42)) if args.debug == "true": settings_manager.set_debug(True) @@ -34,7 +33,9 @@ def main(args, unknownargs): settings_manager.set_trace_debug(True) settings_manager.do_dirty_start_check() - Application(args, unknownargs) + + app = Application() + app.run() @@ -52,6 +53,7 @@ if __name__ == "__main__": # Read arguments (If any...) args, unknownargs = parser.parse_known_args() + settings_manager.set_starting_args( args, unknownargs ) try: faulthandler.enable() # For better debug info diff --git a/src/solarfm/app.py b/src/solarfm/app.py index b8510be..b59826f 100644 --- a/src/solarfm/app.py +++ b/src/solarfm/app.py @@ -19,40 +19,48 @@ class AppLaunchException(Exception): class Application: """ docstring for Application. """ - def __init__(self, args, unknownargs): + def __init__(self): super(Application, self).__init__() - if not settings_manager.is_trace_debug(): - self.load_ipc(args, unknownargs) - self.setup_debug_hook() - Window(args, unknownargs).main() - def load_ipc(self, args, unknownargs): - ipc_server = IPCServer() + def run(self): + if not settings_manager.is_trace_debug(): + if not self.load_ipc(): + return + + win = Window() + win.start() + + def load_ipc(self): + args, \ + unknownargs = settings_manager.get_starting_args() + ipc_server = IPCServer() + self.ipc_realization_check(ipc_server) + if ipc_server.is_ipc_alive: + return True - if not ipc_server.is_ipc_alive: - for arg in unknownargs + [args.new_tab,]: - if os.path.isfile(arg): - message = f"FILE|{arg}" - ipc_server.send_ipc_message(message) + logger.warning(f"{app_name} IPC Server Exists: Have sent path(s) to it and closing...") + for arg in unknownargs + [args.new_tab,]: + if os.path.isfile(arg): + message = f"FILE|{arg}" + ipc_server.send_ipc_message(message) + + if os.path.isdir(arg): + message = f"DIR|{arg}" + ipc_server.send_ipc_message(message) + + return False - raise AppLaunchException(f"{app_name} IPC Server Exists: Have sent path(s) to it and closing...") def ipc_realization_check(self, ipc_server): try: ipc_server.create_ipc_listener() except Exception as e: - print(e) ipc_server.send_test_ipc_message() - try: - ipc_server.create_ipc_listener() - except Exception as e: - ... - def setup_debug_hook(self): try: # kill -SIGUSR2 from Linux/Unix or SIGBREAK signal from Windows diff --git a/src/solarfm/core/controller.py b/src/solarfm/core/controller.py index 049bd71..b991ce2 100644 --- a/src/solarfm/core/controller.py +++ b/src/solarfm/core/controller.py @@ -36,26 +36,14 @@ from .ui_mixin import UIMixin class Controller(UIMixin, SignalsMixins, Controller_Data): """ Controller coordinates the mixins and is somewhat the root hub of it all. """ - def __init__(self, args, unknownargs): + def __init__(self): self._setup_controller_data() self._setup_styling() self._setup_signals() self._subscribe_to_events() self._load_widgets() - - if args.no_plugins == "false": - self.plugins_controller.pre_launch_plugins() - - self._generate_file_views(self.fm_controller_data) - - if args.no_plugins == "false": - self.plugins_controller.post_launch_plugins() - - for arg in unknownargs + [args.new_tab,]: - if os.path.isdir(arg): - message = f"FILE|{arg}" - event_system.emit("post_file_to_ipc", message) + self._load_plugins_and_files() def _setup_styling(self): @@ -69,7 +57,7 @@ class Controller(UIMixin, SignalsMixins, Controller_Data): 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_dir_from_ipc", self.handle_dir_from_ipc) event_system.subscribe("generate_file_views", self._generate_file_views) event_system.subscribe("clear_notebooks", self.clear_notebooks) @@ -113,6 +101,22 @@ class Controller(UIMixin, SignalsMixins, Controller_Data): FileExistsWidget() SaveLoadWidget() + def _load_plugins_and_files(self): + args, unknownargs = settings_manager.get_starting_args() + + if args.no_plugins == "false": + self.plugins_controller.pre_launch_plugins() + + self._generate_file_views(self.fm_controller_data) + + if args.no_plugins == "false": + self.plugins_controller.post_launch_plugins() + + for arg in unknownargs + [args.new_tab,]: + if os.path.isdir(arg): + message = f"FILE|{arg}" + event_system.emit("post_file_to_ipc", message) + def _shutting_down(self): if not settings_manager.is_trace_debug(): self.fm_controller.save_state() diff --git a/src/solarfm/core/mixins/signals/ipc_signals_mixin.py b/src/solarfm/core/mixins/signals/ipc_signals_mixin.py index 6f6b085..ca29b6d 100644 --- a/src/solarfm/core/mixins/signals/ipc_signals_mixin.py +++ b/src/solarfm/core/mixins/signals/ipc_signals_mixin.py @@ -13,7 +13,7 @@ class IPCSignalsMixin: def print_to_console(self, message=None): print(message) - def handle_file_from_ipc(self, path): + def handle_dir_from_ipc(self, path): window = self.builder.get_object("main_window") window.deiconify() window.show() diff --git a/src/solarfm/core/window.py b/src/solarfm/core/window.py index 92341b1..2b6015a 100644 --- a/src/solarfm/core/window.py +++ b/src/solarfm/core/window.py @@ -22,9 +22,8 @@ class ControllerStartException(Exception): class Window(Gtk.ApplicationWindow): """docstring for Window.""" - def __init__(self, args, unknownargs): + def __init__(self): Gtk.ApplicationWindow.__init__(self) - # super(Window, self).__init__() settings_manager.set_main_window(self) @@ -33,7 +32,7 @@ class Window(Gtk.ApplicationWindow): self._setup_styling() self._setup_signals() self._subscribe_to_events() - self._load_widgets(args, unknownargs) + self._load_widgets() self._set_window_data() self._set_size_constraints() @@ -56,11 +55,11 @@ class Window(Gtk.ApplicationWindow): event_system.subscribe("tear_down", self._tear_down) event_system.subscribe("load_interactive_debug", self._load_interactive_debug) - def _load_widgets(self, args, unknownargs): + def _load_widgets(self): if settings_manager.is_debug(): self.set_interactive_debugging(True) - self._controller = Controller(args, unknownargs) + self._controller = Controller() if not self._controller: raise ControllerStartException("Controller exited and doesn't exist...") @@ -120,5 +119,5 @@ class Window(Gtk.ApplicationWindow): settings_manager.clear_pid() Gtk.main_quit() - def main(self): + def start(self): Gtk.main() \ No newline at end of file diff --git a/src/solarfm/utils/ipc_server.py b/src/solarfm/utils/ipc_server.py index f1cfa23..4559dc2 100644 --- a/src/solarfm/utils/ipc_server.py +++ b/src/solarfm/utils/ipc_server.py @@ -5,7 +5,6 @@ from multiprocessing.connection import Client from multiprocessing.connection import Listener # Lib imports -from gi.repository import GLib # Application imports from .singleton import Singleton @@ -14,7 +13,7 @@ from .singleton import Singleton class IPCServer(Singleton): """ Create a listener so that other SolarFM instances send requests back to existing instance. """ - def __init__(self, ipc_address: str = '127.0.0.1', conn_type: str = "local_network_unsecured"): + def __init__(self, ipc_address: str = '127.0.0.1', conn_type: str = "socket"): self.is_ipc_alive = False self._ipc_port = 0 # Use 0 to let Listener chose port self._ipc_address = ipc_address @@ -43,30 +42,29 @@ class IPCServer(Singleton): if os.path.exists(self._ipc_address) and settings_manager.is_dirty_start(): os.unlink(self._ipc_address) - listener = Listener(address = self._ipc_address, family = "AF_UNIX", authkey = self._ipc_authkey) - + listener = Listener(self._ipc_address, family = "AF_UNIX", authkey = self._ipc_authkey) elif "unsecured" not in self._conn_type: listener = Listener((self._ipc_address, self._ipc_port), authkey = self._ipc_authkey) else: listener = Listener((self._ipc_address, self._ipc_port)) self.is_ipc_alive = True - # self._run_ipc_loop(listener) - GLib.Thread("", self._run_ipc_loop, listener) + self._run_ipc_loop(listener) - # @daemon_threaded + @daemon_threaded def _run_ipc_loop(self, listener) -> None: while True: try: conn = listener.accept() start_time = time.perf_counter() - GLib.idle_add(self._handle_ipc_message, *(conn, start_time,)) - - conn = None - start_time = None + self._handle_ipc_message(conn, start_time) + except EOFError as e: + logger.debug( repr(e) ) except Exception as e: logger.debug( repr(e) ) + finally: + conn.close() listener.close() @@ -80,27 +78,28 @@ class IPCServer(Singleton): if file: event_system.emit_and_await("handle_file_from_ipc", file) - msg = None - file = None + conn.close() + break + + if "DIR|" in msg: + file = msg.split("DIR|")[1].strip() + if file: + event_system.emit_and_await("handle_dir_from_ipc", file) + conn.close() break - if msg in ['close connection', 'close server']: - msg = None + if msg in ['close connection', 'close server', 'Empty Data...']: conn.close() break # NOTE: Not perfect but insures we don't lock up the connection for too long. end_time = time.perf_counter() if (end_time - start_time) > self._ipc_timeout: - msg = None - end_time = None conn.close() break - return False - def send_ipc_message(self, message: str = "Empty Data...") -> None: try: diff --git a/src/solarfm/utils/settings_manager/manager.py b/src/solarfm/utils/settings_manager/manager.py index 2be6222..46ee2dc 100644 --- a/src/solarfm/utils/settings_manager/manager.py +++ b/src/solarfm/utils/settings_manager/manager.py @@ -87,17 +87,18 @@ class SettingsManager(StartCheckMixin, Singleton): print( f"Settings: {self._CONTEXT_MENU}\n\t\t{repr(e)}" ) - self.settings: Settings = None - self._main_window = None - self._main_window_w = 1670 - self._main_window_h = 830 - self._builder = None - self.PAINT_BG_COLOR = (0, 0, 0, 0.0) - - self._trace_debug = False - self._debug = False - self._dirty_start = False + self.settings: Settings = None + self._main_window = None + self._main_window_w = 1670 + self._main_window_h = 830 + self._builder = None + self.PAINT_BG_COLOR = (0, 0, 0, 0.0) + self._trace_debug = False + self._debug = False + self._dirty_start = False + self._passed_in_file: bool = False + self._starting_files: list = [] def register_signals_to_builder(self, classes=None, builder=None): handlers = {} @@ -143,6 +144,12 @@ class SettingsManager(StartCheckMixin, Singleton): def get_trash_info_path(self) -> str: return self._TRASH_INFO_PATH def get_plugins_path(self) -> str: return self._PLUGINS_PATH + def get_starting_args(self): + return self.args, self.unknownargs + + def set_is_starting_with_file(self, is_passed_in_file: bool = False): + self._passed_in_file = is_passed_in_file + def is_trace_debug(self) -> bool: return self._trace_debug def is_debug(self) -> bool: return self._debug @@ -153,6 +160,10 @@ class SettingsManager(StartCheckMixin, Singleton): def set_main_window_min_width(self, width = 720): self.settings.config.main_window_min_width = width def set_main_window_min_height(self, height = 480): self.settings.config.main_window_min_height = height + def set_starting_args(self, args, unknownargs): + self.args = args + self.unknownargs = unknownargs + def set_trace_debug(self, trace_debug: bool): self._trace_debug = trace_debug diff --git a/src/solarfm/utils/settings_manager/start_check_mixin.py b/src/solarfm/utils/settings_manager/start_check_mixin.py index 6fc8208..824b056 100644 --- a/src/solarfm/utils/settings_manager/start_check_mixin.py +++ b/src/solarfm/utils/settings_manager/start_check_mixin.py @@ -29,7 +29,7 @@ class StartCheckMixin: pid = f.readline().strip() if pid not in ("", None): if self.is_pid_alive( int(pid) ): - print("PID file exists and PID is alive... Letting downstream errors (sans debug args) handle app closure propigation.") + print("PID file exists and PID is alive...") return self._write_new_pid()