From 41cf802e3feea2365d1efc15102819f276d829b0 Mon Sep 17 00:00:00 2001 From: Nils <> Date: Mon, 11 Apr 2022 14:54:01 +0200 Subject: [PATCH] Shift testing for second agordejo gui to the start of the program to work with the new auto-detection --- engine/api.py | 2 +- engine/nsmservercontrol.py | 36 +++++++++++++++++++++++++++--------- engine/start.py | 28 ++++++++++++++++++++++++++++ qtgui/mainwindow.py | 1 + 4 files changed, 57 insertions(+), 10 deletions(-) diff --git a/engine/api.py b/engine/api.py index 5644284..7027f29 100644 --- a/engine/api.py +++ b/engine/api.py @@ -196,7 +196,7 @@ def startEngine(): #Start Event Loop Processing eventLoop.fastConnect(nsmServerControl.process) eventLoop.fastConnect(jackClient._setPlaybackSeconds) - eventLoop.slowConnect(nsmServerControl.processSingleInstance) + eventLoop.slowConnect(nsmServerControl.listenToAnotherInstanceAttempt) #Send initial data #The decision if we are already in a session on startup or in "choose a session mode" is handled by callbacks diff --git a/engine/nsmservercontrol.py b/engine/nsmservercontrol.py index 758e30f..c899430 100644 --- a/engine/nsmservercontrol.py +++ b/engine/nsmservercontrol.py @@ -377,14 +377,19 @@ class NsmServerControl(object): self.nsmOSCUrl = o.netloc.split(":")[0], o.port else: envResult = self._getNsmOSCUrlFromEnvironment() + print(2) if envResult: #In case there is no actual nsmd running but there still was a NSM_URL env var, e.g. over the network, use this. #There is a corner case that the env is local but the user chose to ignore the GUI way (nsmd 1.6.0) to proivde us directly with a specific URL. self.nsmOSCUrl = envResult else: #This is the default case. User just starts the GUI. The other modes are concious decisions to either start with URL as parameter or in an NSM environment. - #But now we need to test if the user accidentaly opened a second GUI, which would start a second server. + #We need to test if the user accidentaly opened a second GUI, which would start a second server. self._setupAndTestForSingleInstance() #This might quit the whole program and we will never see the next line. + #TODO: there is a corner case: 1) manually start nsmd locally 2) start agordejo first time and connect to running nsmd 3) start 2nd agordejo and connect to the same server. + #it will not prevent it. But we need it because all other scenarios prevent agordejo multiple times for actual different servers, which is of course wanted. + #Better let something uncorrect slip than to prevent legit usecases! + #The important check here is to see if Agordejo, with internal nsmd, was started twice or not. Which works. That's all. self.nsmOSCUrl = self._generateFreeNsmOSCUrl() assert self.nsmOSCUrl @@ -422,7 +427,7 @@ class NsmServerControl(object): self.dataClientNamesHook = dataClientNamesHook self.dataClientDescriptionHook = dataClientDescriptionHook self.dataClientTimelineMaximumDurationChangedHook = dataClientTimelineMaximumDurationChangedHook - self.singleInstanceActivateWindowHook = singleInstanceActivateWindowHook #added to self.processSingleInstance() to listen for a message from another wannabe-instance + self.singleInstanceActivateWindowHook = singleInstanceActivateWindowHook #added to self.listenToAnotherInstanceAttempt() to listen for a message from another wannabe-instance self._receiverActive = True logger.info("nsmservercontrol init is complete. Ready for event loop") @@ -430,22 +435,28 @@ class NsmServerControl(object): #Internal Methods def _setupAndTestForSingleInstance(self): - """on program startup trigger this if there is already another instance of us running. - This socket is only + """ + On program startup trigger this if there is already another instance of us running. + This is before anything NSM was done. """ self.singleInstanceSocket = socket.socket(socket.AF_UNIX, socket.SOCK_STREAM) logger.info("Testing if another non-specific Agordejo is running.") try: - ## Create an abstract socket, by prefixing it with null. + # This is for the first agordejo instance, when no other is running. We set up + # a socket and listen throughout the runtime of our instance. + # + # Create an abstract socket, by prefixing it with null. # this relies on a feature only in linux, when current process quits, the # socket will be deleted. self.singleInstanceSocket.bind('\0' + "agordejo") self.singleInstanceSocket.listen(1) self.singleInstanceSocket.setblocking(False) logger.info("No other non-specific Agordejo found. Starting GUI") - #Continue in self.processSingleInstance() + #Continue in self.listenToAnotherInstanceAttempt() return True except socket.error: + # This is for the 2nd agordejo instance that has detected there is already another + # instance running. We will exit here before anything related to NSM has happened. logger.error("GUI for this nsmd server already running. Informing the existing application to show itself.") self.singleInstanceSocket.connect('\0' + "agordejo") self.singleInstanceSocket.send("agordejoactivate".encode()); @@ -454,10 +465,17 @@ class NsmServerControl(object): #print ("not executed") return False - def processSingleInstance(self): - """Tests our unix socket for an incoming signal. + def listenToAnotherInstanceAttempt(self): + """ + This is for the agordejo instance that keeps running. We inform the GUI via hook + to show info to the user that a 2nd instance wanted to start. + + Tests our unix socket for an incoming signal. if received forward to the engine->gui - Can be added to a slower event loop, so it is not in self.process""" + + Must be added to an event loop, so will only start once the program has started. + Can be added to a slower event loop, so it is not in self.process + """ if self.singleInstanceSocket: try: connection, client_address = self.singleInstanceSocket.accept() #This blocks and waits for a message diff --git a/engine/start.py b/engine/start.py index 8ea5174..3c94338 100644 --- a/engine/start.py +++ b/engine/start.py @@ -223,6 +223,34 @@ def checkJackOrExit(prettyName): exitWithMessage("JACK Audio Connection Kit is not running. Please start it.") +def isAnotherAgordejoInstanceRunning()->bool: + import socket + tempSocket = socket.socket(socket.AF_UNIX, socket.SOCK_STREAM) + try: + # This is for the first agordejo instance, when no other is running. We set up + # a socket and listen throughout the runtime of our instance. + # + # Create an abstract socket, by prefixing it with null. + # this relies on a feature only in linux, when current process quits, the + # socket will be deleted. + tempSocket.bind('\0' + "agordejo") + tempSocket.listen(1) + tempSocket.setblocking(False) + return False + except socket.error: + # This is for the 2nd agordejo instance that has detected there is already another + # instance running. We will exit here before anything related to NSM has happened. + tempSocket.connect('\0' + "agordejo") + tempSocket.send("agordejoactivate".encode()); + tempSocket.close() + return True + + +def checkAgordejoOrExit(): + if (not args.url) and isAnotherAgordejoInstanceRunning(): + exitWithMessage("Another Agordejo instance is already running. Informing it of our start attempt.") + +checkAgordejoOrExit() checkJackOrExit(METADATA["name"]) try: diff --git a/qtgui/mainwindow.py b/qtgui/mainwindow.py index bb670c4..19c0b4a 100644 --- a/qtgui/mainwindow.py +++ b/qtgui/mainwindow.py @@ -166,6 +166,7 @@ class MainWindow(QtWidgets.QMainWindow): #nsmd 1.6.0 xdgVersionChange(self.qtApp) #may present a blocking dialog, may do nothing. + #If another Agordejo is running, and no --nsm-url was set, we will never reach this point. checkForRunningNsmd(self.qtApp, PATHS) #may present a blocking dialog, may do nothing. Injects nsm url into PATHS #Api Callbacks