|
|
|
#! /usr/bin/env python3
|
|
|
|
# -*- coding: utf-8 -*-
|
|
|
|
"""
|
|
|
|
Copyright 2020, Nils Hilbricht, Germany ( https://www.hilbricht.net )
|
|
|
|
|
|
|
|
The Non-Session-Manager by Jonathan Moore Liles <male@tuxfamily.org>: http://non.tuxfamily.org/nsm/
|
|
|
|
With help from code fragments from https://github.com/attwad/python-osc ( DO WHAT THE FUCK YOU WANT TO PUBLIC LICENSE v2 )
|
|
|
|
|
|
|
|
API documentation: http://non.tuxfamily.org/nsm/API.html
|
|
|
|
|
|
|
|
This file is part of the Laborejo Software Suite ( https://www.laborejo.org ),
|
|
|
|
more specifically its template base application.
|
|
|
|
|
|
|
|
The Template Base Application is free software: you can redistribute it and/or modify
|
|
|
|
it under the terms of the GNU General Public License as published by
|
|
|
|
the Free Software Foundation, either version 3 of the License, or
|
|
|
|
(at your option) any later version.
|
|
|
|
|
|
|
|
This program is distributed in the hope that it will be useful,
|
|
|
|
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
|
|
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
|
|
GNU General Public License for more details.
|
|
|
|
|
|
|
|
You should have received a copy of the GNU General Public License
|
|
|
|
along with this program. If not, see <http://www.gnu.org/licenses/>.
|
|
|
|
"""
|
|
|
|
|
|
|
|
#Standard Library
|
|
|
|
import logging
|
|
|
|
import threading
|
|
|
|
from time import sleep
|
|
|
|
import cmd
|
|
|
|
from pprint import pprint
|
|
|
|
import sys
|
|
|
|
|
|
|
|
from nsmservercontrol import NsmServerControl
|
|
|
|
|
|
|
|
class NSMCmd(cmd.Cmd):
|
|
|
|
intro = "Welcome to the NSM commandline tester. Type help or ? to list commands.\nThere is no prompt, just type.\n"
|
|
|
|
prompt = ""
|
|
|
|
file = None #?
|
|
|
|
|
|
|
|
lastClientId = None
|
|
|
|
|
|
|
|
def _clientId(self, arg):
|
|
|
|
if arg:
|
|
|
|
NSMCmd.lastClientId = arg
|
|
|
|
return arg
|
|
|
|
elif NSMCmd.lastClientId:
|
|
|
|
return NSMCmd.lastClientId
|
|
|
|
else:
|
|
|
|
return arg
|
|
|
|
|
|
|
|
def do_announce(self, arg):
|
|
|
|
"""Announce ourselves as GUI. This is sent automatically at program start,
|
|
|
|
but nsmd only remembers the last GUI that announces. Calling announce takes back control"""
|
|
|
|
nsmServerControl.gui_announce()
|
|
|
|
|
|
|
|
def do_ping(self, arg):
|
|
|
|
"""Ping the server"""
|
|
|
|
nsmServerControl.ping()
|
|
|
|
|
|
|
|
def do_broadcast(self, arg):
|
|
|
|
"""Send a message too all clients in the current session, except ourselves"""
|
|
|
|
args = arg.split()
|
|
|
|
path = args[0]
|
|
|
|
arguments = args[1:]
|
|
|
|
nsmServerControl.broadcast(path, arguments)
|
|
|
|
|
|
|
|
def do_listSessions(self, arg):
|
|
|
|
"""Request a list of projects, or sessions, from the server."""
|
|
|
|
nsmServerControl.list()
|
|
|
|
print ("Now call 'status'")
|
|
|
|
#This won't work because when we get back control from list the data is not here yet.
|
|
|
|
#print(nsmServerControl.internalState["sessions"])
|
|
|
|
|
|
|
|
def do_saveSessions(self, arg):
|
|
|
|
"""Save currently open session"""
|
|
|
|
nsmServerControl.save()
|
|
|
|
|
|
|
|
def do_closeSession(self, arg):
|
|
|
|
"""Close currently open session"""
|
|
|
|
nsmServerControl.close()
|
|
|
|
|
|
|
|
def do_abortSession(self, arg):
|
|
|
|
"""Close without saving!"""
|
|
|
|
nsmServerControl.abort()
|
|
|
|
|
|
|
|
def do_liftLockedSession(self, arg):
|
|
|
|
"""Remove the .lock file from a session. Use with caution. Intended for crash recovery.
|
|
|
|
Does nothing if not locked."""
|
|
|
|
nsmServerControl.forceLiftLock(arg)
|
|
|
|
|
|
|
|
def do_quitServer(self, arg):
|
|
|
|
"""Gracefully shut down the server, which will save. Then exit to OS."""
|
|
|
|
#nsmServerControl.quit() #We don't need that. Called by @atexit
|
|
|
|
quit()
|
|
|
|
|
|
|
|
def do_addClient(self, arg):
|
|
|
|
"""Add one client to current session. Executable must be in $PATH"""
|
|
|
|
nsmServerControl.clientAdd(arg)
|
|
|
|
|
|
|
|
def do_openSession(self, arg):
|
|
|
|
"""Open an existing session with a name as shown by the list command"""
|
|
|
|
nsmServerControl.open(arg)
|
|
|
|
|
|
|
|
def do_newSession(self, arg):
|
|
|
|
"""Saves the current session and creates a new session."""
|
|
|
|
nsmServerControl.new(arg)
|
|
|
|
|
|
|
|
def do_duplicateSession(self, arg):
|
|
|
|
"""Saves the current session, closes it and opens a copy of it with the given name."""
|
|
|
|
nsmServerControl.duplicate(arg)
|
|
|
|
|
|
|
|
def do_copySession(self, arg):
|
|
|
|
"""Copy a session with our internal methods. Does not use nsm duplicate and can operate
|
|
|
|
at any time at any session, locked or not."""
|
|
|
|
nsmSessionName, newName = arg.split()
|
|
|
|
nsmServerControl.copySession(nsmSessionName, newName)
|
|
|
|
|
|
|
|
def do_hideClient(self, arg):
|
|
|
|
"""Instruct a client to hide its GUI. Will do nothing if client does not support it"""
|
|
|
|
arg = self._clientId(arg)
|
|
|
|
nsmServerControl.clientHide(arg)
|
|
|
|
|
|
|
|
def do_showClient(self, arg):
|
|
|
|
"""Instruct a client to show its GUI again. Will do nothing if client does not support it"""
|
|
|
|
arg = self._clientId(arg)
|
|
|
|
nsmServerControl.clientShow(arg)
|
|
|
|
|
|
|
|
def do_removeClient(self, arg):
|
|
|
|
"""Remove a stopped client from a running session"""
|
|
|
|
arg = self._clientId(arg)
|
|
|
|
nsmServerControl.clientRemove(arg)
|
|
|
|
|
|
|
|
def do_stopClient(self, arg):
|
|
|
|
"""Stop a client in a running session"""
|
|
|
|
arg = self._clientId(arg)
|
|
|
|
nsmServerControl.clientStop(arg)
|
|
|
|
|
|
|
|
def do_resumeClient(self, arg):
|
|
|
|
"""Resume a previously stopped client"""
|
|
|
|
arg = self._clientId(arg)
|
|
|
|
nsmServerControl.clientResume(arg)
|
|
|
|
|
|
|
|
def do_saveClient(self, arg):
|
|
|
|
"""instruct a specific client to save"""
|
|
|
|
arg = self._clientId(arg)
|
|
|
|
nsmServerControl.clientSave(arg)
|
|
|
|
|
|
|
|
def do_allClientsShow(self, arg):
|
|
|
|
"""Call clientShow for all clients"""
|
|
|
|
nsmServerControl.allClientsShow()
|
|
|
|
|
|
|
|
def do_allClientsHide(self, arg):
|
|
|
|
"""Call clientHide for all clients"""
|
|
|
|
nsmServerControl.allClientsHide()
|
|
|
|
|
|
|
|
def do_deleteSession(self, arg):
|
|
|
|
"""Delete a session directory. This is a destructive operation without undo"""
|
|
|
|
nsmServerControl.deleteSession(arg)
|
|
|
|
|
|
|
|
def do_renameSession(self, arg):
|
|
|
|
"""Rename a non-open session. Arguments: nsmSessionName (from listSessions) newName"""
|
|
|
|
nsmSessionName, newName = arg.split()
|
|
|
|
nsmServerControl.renameSession(nsmSessionName, newName)
|
|
|
|
|
|
|
|
#Internal, not requests for nsm
|
|
|
|
def do_status(self, arg):
|
|
|
|
"""show internal status. Does not query nsm for any updates or live data.
|
|
|
|
Therefore can be out of date, e.g. after program start there are no listed
|
|
|
|
sessions. call listSessions first."""
|
|
|
|
pprint(nsmServerControl.internalState)
|
|
|
|
|
|
|
|
def do_loggingInfo(self, arg):
|
|
|
|
"""Set logging level to very verbose"""
|
|
|
|
logging.basicConfig(level=logging.INFO)
|
|
|
|
|
|
|
|
def do_loggingWarning(self, arg):
|
|
|
|
"""Set logging level to warnings and errors"""
|
|
|
|
logging.basicConfig(level=logging.WARNING)
|
|
|
|
|
|
|
|
def do_loggingError(self, arg):
|
|
|
|
"""Set logging level to only errors"""
|
|
|
|
logging.basicConfig(level=logging.ERROR)
|
|
|
|
|
|
|
|
#def default(self, arg):
|
|
|
|
# nsmServerControl.send(arg)
|
|
|
|
|
|
|
|
|
|
|
|
def run_receivingServer():
|
|
|
|
"""Run forever
|
|
|
|
http://sebastiandahlgren.se/2014/06/27/running-a-method-as-a-background-thread-in-python/
|
|
|
|
"""
|
|
|
|
while True:
|
|
|
|
nsmServerControl.process()
|
|
|
|
sleep(0.001)
|
|
|
|
|
|
|
|
def nothing(*args):
|
|
|
|
pass
|
|
|
|
|
|
|
|
if __name__ == '__main__':
|
|
|
|
logging.basicConfig(level=logging.INFO) #development
|
|
|
|
|
|
|
|
try:
|
|
|
|
URL = sys.argv[1]
|
|
|
|
print ("Start with URL", sys.argv[1])
|
|
|
|
except:
|
|
|
|
URL = None
|
|
|
|
|
|
|
|
nsmServerControl = NsmServerControl(useCallbacks=True,sessionOpenReadyHook=nothing,sessionOpenLoadingHook=nothing,sessionClosedHook=nothing,clientStatusHook=nothing,singleInstanceActivateWindowHook=nothing, dataClientNamesHook=nothing, dataClientDescriptionHook=nothing, parameterNsmOSCUrl=URL)
|
|
|
|
thread = threading.Thread(target=run_receivingServer, args=())
|
|
|
|
thread.daemon = True # Daemonize thread
|
|
|
|
thread.start() # Start the execution
|
|
|
|
|
|
|
|
NSMCmd().cmdloop()
|