@ -24,7 +24,7 @@ import logging; logger = logging.getLogger("nsm-data"); logger.info("import")
URL="https://www.laborejo.org/agordejo/nsm-data"
HARD_LIMIT = 512 # no single message longer than this
VERSION= 1.0
VERSION= 1.1
#In case the user tries to run this standalone.
import argparse
@ -90,13 +90,15 @@ class DataClient(object):
loggingLevel = "error", #"info" for development or debugging, "error" for production. default is error.
)
#Add custom callbacks. They all receive _IncomingMessage(data)
#Add custom callbacks. They all receive _IncomingMessage(data)
self.nsmClient.reactions["/agordejo/datastorage/setclientoverridename"] = self.setClientOverrideName
self.nsmClient.reactions["/agordejo/datastorage/getclientoverridename"] = self.getClientOverrideName
self.nsmClient.reactions["/agordejo/datastorage/getall"] = self.getAll
self.nsmClient.reactions["/agordejo/datastorage/getdescription"] = self.getDescription
self.nsmClient.reactions["/agordejo/datastorage/setdescription"] = self.setDescription
#self.nsmClient.reactions["/agordejo/datastorage/read"] = self.reactRead
self.nsmClient.reactions["/agordejo/datastorage/setdescription"] = self.setDescription
self.nsmClient.reactions["/agordejo/datastorage/gettimelinemaximum"] = self.getTimelineMaximum
self.nsmClient.reactions["/agordejo/datastorage/settimelinemaximum"] = self.setTimelineMaximum
#self.nsmClient.reactions["/agordejo/datastorage/read"] = self.reactRead #generic key/value storage
#self.nsmClient.reactions["/agordejo/datastorage/readall"] = self.reactReadAll
#self.nsmClient.reactions["/agordejo/datastorage/create"] = self.reactCreate
#self.nsmClient.reactions["/agordejo/datastorage/update"] = self.reactUpdate
@ -110,8 +112,11 @@ class DataClient(object):
sleep(0.05) #20fps update cycle
def getAll(self, msg):
"""A complete data dumb, intended to use once after startup.
Will split into multiple reply messages, if needed"""
"""A complete data dump, intended to use once after startup.
Will split into multiple reply messages, if needed.
Our mirror datastructure in nsmservercontrol.py calls that on init.
"""
senderHost, senderPort = msg.params
path = "/agordejo/datastorage/reply/getall"
encoded = json.dumps(self.data)
@ -133,10 +138,10 @@ class DataClient(object):
def setDescription(self, msg):
"""
Answers with descriptionId and index when data was received and saved.
Answers with descriptionId and index when data was received and saved.
The GUI needs to buffer this a bit. Don't send every char as single message.
This is for multi-part messages
Index is 0 based,
chunk is part of a simple string, not json.
@ -148,8 +153,8 @@ class DataClient(object):
if not self._descriptionId == descriptionId:
self._descriptionId = descriptionId
self._descriptionStringArray.clear()
self._descriptionStringArray[index] = chunk
buildString = "".join([v for k,v in sorted(self._descriptionStringArray.items())])
self._descriptionStringArray[index] = chunk
buildString = "".join([v for k,v in sorted(self._descriptionStringArray.items())])
self.data["description"] = buildString
self.nsmClient.announceSaveStatus(False)
@ -158,7 +163,7 @@ class DataClient(object):
for the GUI/host to use the original name!"""
clientId, senderHost, senderPort = msg.params
path = "/agordejo/datastorage/reply/getclient"
if clientId in self.data["clientOverrideNames"]:
if clientId in self.data["clientOverrideNames"]:
name = self.data["clientOverrideNames"][clientId]
else:
logger.info(f"We were instructed to read client {clientId}, but it does not exist")
@ -167,7 +172,7 @@ class DataClient(object):
self.nsmClient.send(path, listOfParameters, host=senderHost, port=senderPort)
def setClientOverrideName(self, msg):
"""We accept empty string as a name to remove the name override.
"""We accept empty string as a name to remove the name override.
"""
clientId, jsonValue = msg.params
name = json.loads(jsonValue)[:HARD_LIMIT]
@ -179,6 +184,32 @@ class DataClient(object):
del self.data["clientOverrideNames"][clientId]
self.nsmClient.announceSaveStatus(False)
def getTimelineMaximum(self, msg):
"""
In minutes
If the GUI supports global jack transport controls this can be used to remember
the users setting for the maximum timeline duration. JACKs own data is without an upper
bound."""
senderHost, senderPort = msg.params
path = "/agordejo/datastorage/reply/gettimelinemaximum"
if "timelineMaximumDuration" in self.data:
numericValue = self.data["timelineMaximumDuration"]
else:
logger.info(f"We were instructed to read the timeline maximum duration, but it does not exist yet")
numericValue = 5# minutes.
listOfParameters = [json.dumps(numericValue)]
self.nsmClient.send(path, listOfParameters, host=senderHost, port=senderPort)
def setTimelineMaximum(self, msg):
"""In minutes"""
jsonValue = msg.params[0] #list of 1
numericValue = json.loads(jsonValue)
if numericValue <= 1:
numericValue = 1
self.data["timelineMaximumDuration"] = numericValue
self.nsmClient.announceSaveStatus(False)
#Generic Functions. Not in use and not ready.
#Callback Reactions to OSC. They all receive _IncomingMessage(data)
def reactReadAll(self, msg):
@ -249,10 +280,15 @@ class DataClient(object):
self.data = None
logger.error("Will not load or save because: " + e.__repr__())
if not self.data:
self.data = {"clientOverrideNames":{}, "description":""}
#Version 1.1 save file updates
if self.data:
if not "timelineMaximumDuration" in self.data:
self.data["timelineMaximumDuration"] = 5 #5 minutes as sensible default
else:
self.data = {"clientOverrideNames":{}, "description":"", " timelineMaximumDuration":5} #5 minutes as sensible default
logger.info("New/Open complete")
#TODO: send data
#Data is not send here. Instead the gui calls the getAll message later.
def openFromJson(self, absoluteJsonFilePath):
with open(absoluteJsonFilePath, "r", encoding="utf-8") as f:
@ -264,7 +300,7 @@ class DataClient(object):
logger.error(error)
if result and "version" in result and "origin" in result and result["origin"] == URL:
if result["version"] > = VERSION:
if result["version"] < = VERSION:
assert type(result) is dict, (result, type(result))
logger.info("Loading file from json complete")
return result
@ -285,8 +321,8 @@ class DataClient(object):
Leave that in for documentation.
"""
pass
#def broadcastCallbackFunction(self, ourPath, sessionName, ourClientNameUnderNSM, messagePath, listOfArguments):
# print (__file__, "broadcast")