Files
seweb/base.py
Markus Zolliker 62823899bb change update mechanism
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.
2026-03-20 11:49:00 +01:00

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"]