From 7f74a525f600b51b27a2b5b4ae55a8d01b5e7db8 Mon Sep 17 00:00:00 2001 From: Nils <> Date: Fri, 26 Jun 2020 14:25:44 +0200 Subject: [PATCH] Fix startup when connecting to a running nsmd. Session path was switch with its name, which is the same when starting our own server --- engine/nsmservercontrol.py | 49 +++++++++++++++++++++++--------------- 1 file changed, 30 insertions(+), 19 deletions(-) diff --git a/engine/nsmservercontrol.py b/engine/nsmservercontrol.py index 7e03838..4fcc104 100644 --- a/engine/nsmservercontrol.py +++ b/engine/nsmservercontrol.py @@ -344,7 +344,7 @@ class NsmServerControl(object): "/nsm/gui/client/pid" : self._reactCallback_clientPid, "/nsm/gui/client/dirty" : self._reactCallback_clientDirty, "/nsm/gui/server/message" : self._reactCallback_serverMessage, - "/nsm/gui/gui_announce" : self._reactCallback_guiAnnounce, + "/nsm/gui/gui_announce" : self._reactCallback_guiAnnounce, #we rarely receive that, especially not in init. "/nsm/server/list" : self._reactCallback_serverList, "/nsm/server/broadcast" : self._reactCallback_broadcast, } @@ -395,7 +395,7 @@ class NsmServerControl(object): logger.info("nsmd is ready @ {}".format(self.nsmOSCUrl)) #Tell nsmd that we are a GUI and want to receive general messages async, not only after we request something - self.sessionRoot = self._initial_announce() #Triggers "hi" and session root + self.sessionRoot = self._initial_announce() #Triggers "hi" and session root self.internalState["sessionRoot"] = self.sessionRoot atexit.register(self.quit) #mostly does stuff when we started nsmd ourself @@ -579,9 +579,10 @@ class NsmServerControl(object): then we get the session root. We wait for session root and then clean 'hi' from the queue. Returns session root as pathlib-path.""" - resultArguments = self._blockingRequest(path="/nsm/gui/gui_announce", arguments=[], answerPath="/nsm/gui/session/root", answerArguments=[]) - if len(self._queue) == 1 and self._queue[0].oscpath == "/nsm/gui/gui_announce" and self._queue[0].params == ["hi"]: - self._queue.clear() + resultArguments = self._blockingRequest(path="/nsm/gui/gui_announce", arguments=[], answerPath="/nsm/gui/session/root", answerArguments=[]) + if len(self._queue) == 1 and self._queue[0].oscpath == "/nsm/gui/gui_announce" and self._queue[0].params == ["hi"]: + logger.info("Got 'hi'. We are now the registered nsmd GUI as per our initial /nsm/gui/gui_announce") + self._queue.clear() else: logging.error(f"For ValueError below: {[(m.oscpath, m.params) for m in self._queue]}") raise ValueError("We were expecting a clean _queue with only 'hi' as leftover, but instead there were unhandled messages. see print above. Better abort than a wrong program state") @@ -833,9 +834,9 @@ class NsmServerControl(object): #Callbacks def _reactCallback_guiAnnounce(self, parameters:list): - """Acknowledge""" + """This should not happen, but let's keep it in in case of edge-case multi GUI scenarios""" assert parameters == ["hi"], parameters - logger.info("We got acknowledged as current nsmd GUI.") + logger.info("We got an unexpected 'hi', as if requesting gui_announce. Our own initial GUI announce as received and processed silently earlier already.") def _reactCallback_error(self, parameters:list): logger.error(parameters) @@ -940,27 +941,35 @@ class NsmServerControl(object): def _reactCallback_activeSessionChanged(self, parameters:list): - """This is called when the session has already changed. - Shortly before we receive /nsm/gui/session/session which indicates the attempt to create, - I guess! :) + """We receive this trough /nsm/gui/session/name + This is called when the session has already changed. + This also happens when you connect to a headless nsmd with a running session. + + We expect two parameters: [session name, session path] both of which could be "". + If we start nsmd ourselves into an empty state we expect session name to be empty + + Shortly before we received /nsm/gui/session/session which indicates the attempt to create a + new one, I guess! :) - If you want to react to the attempt to open a session you need to use /nsm/gui/server/message ["Opening session FOO"] - OR creating a new session, after which nsmd will open that session without a message. + If you want to react to the attempt to open a session you need to use + /nsm/gui/server/message ["Opening session FOO"] OR creating a new session, after which nsmd + will open that session without a message. Empty string is "No session" or "Choose A Session" mode. """ l = len(parameters) if l == 2: - shortName, nsmSessionName = parameters - if not shortName and not nsmSessionName: #No session loaded. We are in session-choosing mode. + nsmSessionName, sessionPath = parameters + if not nsmSessionName and not sessionPath: #No session loaded. We are in session-choosing mode. + logger.info("Session closed or never started. Choose-A-Session mode.") self.internalState["currentSession"] = None self.sessionClosedHook() else: - nsmSessionName = nsmSessionName.lstrip("/") - logger.info(f"Current Session changed. We are now {shortName} under {nsmSessionName}") + sessionPath = sessionPath.lstrip("/") + logger.info(f"Current Session changed. We are now {nsmSessionName} in {sessionPath}") self.internalState["currentSession"] = nsmSessionName #This is after the session, received after all programs have loaded. - #We have a counterpart as message reaction that signals the attempt to load. + #We have a counterpart-message reaction that signals the attempt to load. self.sessionOpenReadyHook(self.sessionAsDict(nsmSessionName)) #notify the api->UI for autoClientExecutableInPath in self._addToNextSession: self.clientAdd(autoClientExecutableInPath) @@ -1411,8 +1420,10 @@ class NsmServerControl(object): sessionFile = pathlib.Path(basePath, "session.nsm") if not sessionFile.exists(): - logger.info("Got wrong session directory from nsmd. Race condition after delete? Project: " + repr(sessionFile)) - return None + #This is a reason to let the program exit. + print (nsmSessionName) + logger.error("Got wrong session directory from nsmd. Race condition after delete? In any case a breaking error (please report). Quitting. Project was: " + repr(sessionFile)) + sysexit() #return None switch to return None to let it crash and see the python traceback timestamp = datetime.fromtimestamp(sessionFile.stat().st_mtime).isoformat(sep=" ", timespec='minutes') entry["lastSavedDate"] = timestamp