Atoring just updates on the SecopInteractor does not work properly, as these updates depend on what the clients have already. As updates are polled internall anyway, store onm each client the state of the parameters it has looked up already and emit changes values only.
115 lines
3.8 KiB
Python
115 lines
3.8 KiB
Python
import sys
|
|
import time
|
|
import uuid
|
|
|
|
ONEYEAR = 366 * 24 * 3600
|
|
|
|
|
|
def get_abs_time(times):
|
|
"""Gets the absolute times for the given potential relative times.
|
|
|
|
If a given timestamp is less than one year, then the value is
|
|
relative (to now, rounded up to a full second) and converted
|
|
into an absolute timestamp
|
|
|
|
Parameters :
|
|
times([(float)]) : an array of unix timestamps or relative duration (< 1 year) as floats
|
|
|
|
Returns :
|
|
[(float)] : an array of absolute unix timestamps as floats
|
|
"""
|
|
now = int(time.time() + 0.999)
|
|
return [t + now if t < ONEYEAR else t for t in times]
|
|
|
|
|
|
class Logger(object):
|
|
def __init__(self, logpath):
|
|
self.terminal = sys.stdout
|
|
self.log = open(logpath, "a")
|
|
|
|
def write(self, message):
|
|
self.terminal.write(message)
|
|
self.log.write(message)
|
|
|
|
def flush(self):
|
|
pass
|
|
|
|
|
|
class HandlerBase:
|
|
def __init__(self):
|
|
self.handlers = {k[2:]: getattr(self, k) for k in dir(type(self)) if k.startswith('w_')}
|
|
|
|
|
|
class Client(HandlerBase):
|
|
dictionary = {} # dict (kind, uri) of node
|
|
|
|
def __init__(self, server, streams, instrument_name, device_name):
|
|
super().__init__()
|
|
self.id = uuid.uuid4().hex[0:15]
|
|
self.nodes = {}
|
|
self.node_map = {}
|
|
self.update_filter = set() # modules to be updated
|
|
self.cache = {} # a dict to store the current state of all values
|
|
if streams:
|
|
for uri in streams:
|
|
urisplit = uri.rsplit('://')
|
|
kind = urisplit[0] if len(urisplit) == 2 else 'secop'
|
|
|
|
node = self.dictionary.get((kind, uri))
|
|
|
|
if node is None:
|
|
|
|
def change_callback(dictionary=self.dictionary, kind_uri=(kind, uri)):
|
|
dictionary.pop(kind_uri, None)
|
|
|
|
node = server.interactor_classes[kind](uri, self.node_map, change_callback)
|
|
|
|
self.dictionary[kind, uri] = node
|
|
else:
|
|
node.update_node_map(self.node_map)
|
|
self.nodes[uri] = node
|
|
self.server = server
|
|
self.instrument_name = instrument_name
|
|
self.device_name = device_name # do not know if this is needed
|
|
|
|
def poll(self):
|
|
updates = sum((n.get_updates(self.cache, self.update_filter) for n in self.nodes.values()), start=[])
|
|
result = [dict(type='update', updates=updates)] if updates else []
|
|
graph_updates = self.handlers.get('graphpoll', type(None))()
|
|
if graph_updates:
|
|
result.append(graph_updates)
|
|
return result
|
|
|
|
def w_getblock(self, path):
|
|
path = path.split(',')[-1] # TODO: why this?
|
|
if path == "main": # TODO: change to "-main-"?
|
|
components = []
|
|
for node in self.nodes.values():
|
|
node.add_main_components(components)
|
|
return dict(type='draw', path='main', title='modules', components=components)
|
|
node = self.node_map[path]
|
|
return dict(type='draw', path=path, title=path, components=node.get_components(path))
|
|
|
|
def w_updateblock(self, path):
|
|
if path == 'main': # TODO: change to "-main-"?
|
|
self.update_filter.add('') # ready to accept updates for main block
|
|
else:
|
|
self.update_filter.add(path)
|
|
return dict(type='accept-block')
|
|
|
|
def w_console(self): # TODO: check if still used
|
|
return dict(type='accept-console')
|
|
|
|
def w_sendcommand(self, command):
|
|
result = None
|
|
for node in self.nodes.values():
|
|
result = node.handle_command(command)
|
|
if result is not None:
|
|
break
|
|
if isinstance(result, dict):
|
|
return dict(type='accept-command', result=result)
|
|
return dict(type='accept-command')
|
|
|
|
def info(self):
|
|
return ["na"]
|