Attaching Argodejo to a running nsmd GUI, including --load-session, should work now. Maybe some corner cases, but this is a good basis for testing. FYI There is a known bug with our own nsm-data client that needs further work.
self._queue=list()#Incoming OSC messages are buffered here.
#Status variables that are set by our callbacks
@ -320,15 +328,6 @@ class NsmServerControl(object):
self.dataStorage=None#Becomes DataStorage() every time a datastorage client does a broadcast announce.
self._addToNextSession=[]#A list of executables in PATH. Filled by new, waits for reply that session is created and then will send clientNew and clear the list.
#Hooks for api callbacks
self.sessionOpenReadyHook=sessionOpenReadyHook#nsmSessionName as parameter
self.sessionOpenLoadingHook=sessionOpenLoadingHook#nsmSessionName as parameter
self.sessionClosedHook=sessionClosedHook#no parameter. This is also "choose a session" mode
self.clientStatusHook=clientStatusHook#all client status is done via this single hook. GUIs need to check if they already know the client or not.
self.singleInstanceActivateWindowHook=singleInstanceActivateWindowHook#added to self.processSingleInstance() to listen for a message from another wannabe-instance
@ -387,7 +386,7 @@ class NsmServerControl(object):
#No further action required. GUI announce below this testing.
pass
else:
self._startNsmdOurselves(sessionRoot)#Session root can be a commandline parameter we forward to the server if we start it ourselves.
self._startNsmdOurselves(sessionRoot,startupSession)#Session root can be a commandline parameter we forward to the server if we start it ourselves. startupSession is an autoloader. Both are usually None.
self.singleInstanceActivateWindowHook=singleInstanceActivateWindowHook#added to self.processSingleInstance() to listen for a message from another wannabe-instance
self._receiverActive=True
logger.info("nsmservercontrol init is complete. Ready for event loop")
#Now an external event loop can add self.process
#Internal Methods
@ -457,6 +469,41 @@ class NsmServerControl(object):
self._receiverActive=True
logger.info("Resuming receiving async mode.")
def_forceProcessOnceToEmptyQueue(self):
"""Sometimes we want to make sure everything is processed until we continue. For example
raiseValueError("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")
@ -621,12 +679,19 @@ class NsmServerControl(object):
logger.warning(f"{executableName} must be just an executable file in your $PATH. We expected: {pathlib.Path(executableName).name} . We will not ask nsmd to add it as client")
returnFalse
@ -790,7 +856,11 @@ class NsmServerControl(object):
defclientRemove(self,clientId:str):
"""Client needs to be stopped already. We will do that and wait for an answer.
@ -962,7 +1037,7 @@ class NsmServerControl(object):
nsmSessionName,sessionPath=parameters
ifnotnsmSessionNameandnotsessionPath:#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.internalState["currentSession"]=None#sessionCloseHooked triggers rebuilding of the session list, which will not work when there is a current session.
self.sessionClosedHook()
else:
sessionPath=sessionPath.lstrip("/")
@ -975,21 +1050,29 @@ class NsmServerControl(object):
self.clientAdd(autoClientExecutableInPath)
self._addToNextSession=[]#reset
elifl==0:#Another way of "no session".
self.internalState["currentSession"]=None
self.internalState["currentSession"]=None#sessionCloseHooked triggers rebuilding of the session list, which will not work when there is a current session.
self.sessionClosedHook()
else:
raiseNotImplementedError(parameters)
def_initializeEmptyClient(self,clientId:str):
"""NSM reuses signals. It is quite possible that this will be called multiple times,
# logger.warning(f"We received a clientNew for ID {clientId} but no session open was received."
# "This would happen in an old nsmd version. If you see the GUI with an open session and a client list you can ignore this warning")
ifclientIdinself.internalState["clients"]:
return
logger.info(f"Creating new internal entry for client {clientId}")
client={
"clientId":clientId,#for convenience, included internally as well
"executable":None,#For dumb clients this is the same as reportedName.
"dumbClient":True,#Bool. Real nsm or just any old program? status "Ready" switches this.
"executable":None,#Every client announces to the GUI with the exectuable name. True nsm clients later overwrite with a pretty name which we save as "reportedName"
"reportedName":None,#str . The reported name is first the executable name, for status started. But for NSM clients it gets replaced with a reported name.
"label":None,#str
"lastStatus":None,#str
@ -1035,25 +1118,25 @@ class NsmServerControl(object):
@ -1421,7 +1504,6 @@ class NsmServerControl(object):
ifnotsessionFile.exists():
#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
@ -1440,7 +1522,10 @@ class NsmServerControl(object):
defexportSessionsAsDicts(self)->list:
"""Return a list of dicts of projects with additional information:
"""
logger.info("Exporting sessions to dict. Will call blocking list sessions next")
results=[]
#assert not self.internalState["currentSession"], self.internalState["currentSession"] #Do not request session list while in active session
parser.add_argument("-u","--url",action='store',dest="url",help="Force URL for the session. If there is already a running session we will connect to it. Otherwise we will start one there. Default is local host with random port. Example: osc.udp://myhost.localdomain:14294/")
parser.add_argument("--nsm-url",action='store',dest="url",help="Same as --url.")
parser.add_argument("-s","--session",action='store',dest="session",help="Session to open on startup. Overrides --continue")
parser.add_argument("-l","--load-session",action='store',dest="session",help="Session to open on startup, must exist. Overrides --continue")
parser.add_argument("-c","--continue",action='store_true',dest="continueLastSession",help="Autostart last active session.")
parser.add_argument("-i","--hide",action='store_true',dest="starthidden",help="Start GUI hidden in tray, only if tray available on system.")
parser.add_argument("--session-root",action='store',dest="sessionRoot",help="Root directory of all sessions. Defaults to '$HOME/NSM Sessions'")
@ -127,6 +127,10 @@ else:
}
ifPATHS["startupSession"]:
logger.warning("--continue ignored because --load-session was used.")
PATHS["continueLastSession"]=None#just in case. See --help string
logger.info("PATHS: {}".format(PATHS))
#Construct QAppliction before constantsAndCOnfigs, which has the fontDB
self.setText(self.parentController.clientsTreeWidgetColumns.index("lastStatus"),QtCore.QCoreApplication.translate("OpenSession","(command not found)"))
classClientTable(object):
"""Controls the QTreeWidget that holds loaded clients"""