make Graphics work again

as base for Mathis work
This commit is contained in:
l_samenv
2024-07-11 10:05:17 +02:00
parent 3fd8bc6bf3
commit 91be383803
7 changed files with 123 additions and 112 deletions

170
seaweb.py
View File

@@ -37,14 +37,13 @@ def guess_mimetype(filename):
mimetype = 'text/css'
elif filename.endswith('.ico'):
mimetype = 'image/x-icon'
print('mimetype', mimetype)
else:
mimetype = 'text/html'
return mimetype
#class SeawebException(Exception):
# pass
# SSE 'protocol' is described here: http://mzl.la/UPFyxY
def to_json_sse(msg):
txt = json.dumps(msg, separators=(',',': '))
@@ -60,12 +59,14 @@ def get_update(path=None):
# Client Adress: socket.getfqdn(flask.request.remote_addr)
client = instrument.newClient()
client.remote_info = circularlog.strtm() + " " + socket.getfqdn(flask.request.remote_addr.split(':')[-1])
@flask.stream_with_context
def generator():
logging.info('UPDATE %s %s', client.id, socket.getfqdn(flask.request.remote_addr.split(':')[-1]))
#msg = dict(type='id', id=client.id, title=instrument.title);
#yield to_json_sse(msg)
msg = dict(type='id', id=client.id, instrument=instrument.title, device=instrument.device);
yield to_json_sse(msg)
try:
lastmsg = time.time()
while True:
@@ -113,7 +114,7 @@ def show_clients():
c = instrument.clients[id]
result += c.remote_info + " " + "; ".join(c.info()) + "<br>"
return result
@app.route('/getblock')
@app.route('/updateblock')
@app.route('/sendcommand')
@@ -220,7 +221,8 @@ def sea_request_reply(socket, command, tmo=5):
socket.busy = False
return data
class SeaGroup(object):
class SeaGroup:
def __init__(self):
self.version = 0
self.components = []
@@ -228,8 +230,9 @@ class SeaGroup(object):
self.lastpoll = 0
self.lastreq = 0
self.empty_values = {}
class Instrument(object):
class Instrument:
def remove(self, client):
try:
del self.clients[client.id]
@@ -240,6 +243,7 @@ class Instrument(object):
self.clients[client.id] = client
return client
class SeaInstrument(Instrument):
# convert SEA layout tag like "-W" to more meaningful name.
# the code: 0: modifier, 1: enum name, 2: input element
@@ -265,10 +269,11 @@ class SeaInstrument(Instrument):
def __init__(self, inst_name, instrument_config):
self.host_port = hostport_split(instrument_config['sea'])
self.inst_name = inst_name
self.title = inst_name
self.clients = {}
self.logger_dir = instrument_config.get('logger_dir','')
test_day = instrument_config.get('test_day', None)
self.test_day = [int(x) for x in test_day.split('-')] if test_day else None
self.test_day = [int(x) for x in test_day.split('-')] if test_day else None
self.seaspy = tcp_lineserver.LineClient(self.host_port, ['Spy 007'], True, ridername='spy')
self.seaspy.busy = False
self.seaspy.name = "SEA seaspy"
@@ -277,7 +282,7 @@ class SeaInstrument(Instrument):
self.history = deque(maxlen=1000)
self.init()
gevent.Greenlet.spawn(self.checkconnections)
def init(self):
self.values = {}
self.groups = {}
@@ -286,7 +291,7 @@ class SeaInstrument(Instrument):
self.timeStamp = None
self.history.clear()
self.lastcmd = None
def checkconnections(self):
while True:
if len(self.clients) == 0 and self.seaspy.connected:
@@ -302,11 +307,11 @@ class SeaInstrument(Instrument):
if not self.seaspy.connected:
self.init()
return self.register(SeaClient())
def remove(self, client):
Instrument.remove(self, client)
self.last_client_remove = time.time()
def findgroup(self, path):
'get a group from sea and store it'
if not path in self.groups:
@@ -315,7 +320,7 @@ class SeaInstrument(Instrument):
self.groups[path].lastreq = time.time()
self.poll_groups([path])
return self.groups[path]
def poll_groups(self, paths):
'polls values and components of requested groups'
for path in list(paths):
@@ -404,8 +409,8 @@ class SeaInstrument(Instrument):
#print 'TO ', components
if grouptitle != None:
gobj.grouptitle = grouptitle
def make_seacmd(self):
global port
if not self.seacmd:
@@ -414,14 +419,14 @@ class SeaInstrument(Instrument):
True, ridername='cmd')
self.seacmd.name = "SEA user"
self.seacmd.connect()
def console(self):
self.make_seacmd()
def addconsole(self, msg):
self.history.append(msg)
self.consolepos += 1
def pollconsole(self):
if not self.seacmd:
return
@@ -464,22 +469,22 @@ class SeaInstrument(Instrument):
idx = min(len(self.history), self.consolepos - startindex) # distance from end
messages = []
for i in range(-idx,0):
type, line, hid = self.history[i]
messages.append(dict(type=type, line=line, origin=('self' if hid==id else 'other')))
typ, line, hid = self.history[i]
messages.append(dict(type=typ, line=line, origin=('self' if hid==id else 'other')))
return self.consolepos, messages
def command(self, command, id):
self.make_seacmd()
self.seacmd.send_line('fulltransact '+command)
self.lastid = id
self.lastcmd = command
class SeaGraph(object):
class SeaGraph:
HISTORICAL = 0
ACTUAL = 1
LIVE = 2
def __init__(self):
self.livemode = self.HISTORICAL
self.time = [0, 0]
@@ -523,18 +528,18 @@ class SeaGraph(object):
self.time[0] = self.time[1]
# reduction not yet implemented
return dict(type='graph-draw', reduced=False, graph=result)
def w_gettime(self, time):
time = [float(t) for t in time.split(',')]
return dict(type='time', time= seagraph.get_abs_time(time))
def w_getvars(self, time):
time = [float(t) for t in time.split(',')]
scanner = seagraph.VarsScanner(instrument.logger_dir, instrument.test_day)
result = dict(type='var_list')
result['blocks'] = list(scanner.get_message(time[-1]).values())
return result
def w_updategraph(self):
logging.info("UPD GRAPH %d", self.livemode)
if self.livemode == self.HISTORICAL:
@@ -544,7 +549,7 @@ class SeaGraph(object):
return dict(type='accept-graph', live=True)
#self.livemode = self.LIVE
#return dict(type='accept-graph', live=True)
def graphpoll(self):
if self.livemode == self.LIVE:
self.time[1], = seagraph.get_abs_time([0])
@@ -562,9 +567,9 @@ class SeaGraph(object):
if len(result) > 0:
return dict(type='graph-update', reduced=False, time=self.time[1], graph=result)
return None
class SeaClient(SeaGraph):
def __init__(self):
self.group_version = {}
self.group_values = {}
@@ -601,7 +606,7 @@ class SeaClient(SeaGraph):
instrument.pollconsole()
self.consolepos, msg = instrument.getconsole(self.consolepos, self.id)
messages.extend(msg)
# graph messages
msg = self.graphpoll()
if msg:
@@ -610,7 +615,7 @@ class SeaClient(SeaGraph):
def info(self):
return self.group_version.keys()
def w_getblock(self, path):
gobj = instrument.findgroup(path.split(',')[-1])
# self.group_version[path] = gobj.version
@@ -618,7 +623,7 @@ class SeaClient(SeaGraph):
self.group_version = {path: gobj.version}
logging.info('getblock %s %d', path, gobj.version)
return dict(type='draw', title=gobj.grouptitle, path=path, components=gobj.components)
def w_updateblock(self, path):
gobj = instrument.findgroup(path)
logging.info('make active %s', path)
@@ -630,15 +635,15 @@ class SeaClient(SeaGraph):
self.consolepos = 0
instrument.console()
return dict(type='accept-console')
def w_sendcommand(self, command):
instrument.command(command, self.id)
return dict(type='accept-command')
class DummyClient(SeaGraph):
async = set(('id','update','redraw','command','reply','graph-update','graph-redraw'))
asynch = set(('id','update','redraw','command','reply','graph-update','graph-redraw'))
def __init__(self, host_port):
self.linesocket = tcp_lineserver.LineClient(host_port)
self.id = uuid.uuid4().hex[0:15]
@@ -646,8 +651,8 @@ class DummyClient(SeaGraph):
self.queue = []
self.syncreply = []
SeaGraph.__init__(self)
def cmd_reply(self, command, replytype, tmo=5):
def cmd_reply(self, command, replytype=None, tmo=5):
self.linesocket.send_line(json.dumps(command))
t = 0
while True:
@@ -657,7 +662,7 @@ class DummyClient(SeaGraph):
line = self.linesocket.get_line()
if line != None:
msg = json.loads(line)
if msg['type'] in self.async:
if msg['type'] in self.asynch:
t = 0
# print 'PUSH',msg, replytype
self.queue.append(msg)
@@ -668,10 +673,10 @@ class DummyClient(SeaGraph):
raise Exception("timeout")
gevent.sleep(0.1)
t += 0.1
if msg['type'] != replytype:
if replytype and msg['type'] != replytype:
logging.error('REPLY MISMATCH %s %s <> %s' , command, replytype, msg['type'])
return msg
def w_getblock(self, path):
return self.cmd_reply(dict(type='getblock', path=path, id=self.id), 'draw')
@@ -694,17 +699,17 @@ class DummyClient(SeaGraph):
messages = []
if line:
msg = json.loads(line)
if msg['type'] in self.async:
if msg['type'] in self.asynch:
messages.append(msg)
else:
self.syncreply.append(msg)
# graph messages
msg = self.graphpoll()
if msg:
messages.append(msg)
return messages
def info(self):
return ["na"]
@@ -715,13 +720,14 @@ class DummyInstrument(Instrument):
self.host_port = hostport_split(instrument_config['hostport'])
self.logger_dir = instrument_config.get('logger_dir', '')
test_day = instrument_config.get('test_day', None)
self.test_day = [int(x) for x in test_day.split('-')] if test_day else None
self.test_day = [int(x) for x in test_day.split('-')] if test_day else None
self.title = inst_name
self.clients = {}
def newClient(self):
return self.register(DummyClient(self.host_port))
class SecopMsg:
def __init__(self, line):
self.par = None
@@ -736,7 +742,14 @@ class SecopMsg:
self.par = sl[1]
if len(sl) > 2:
self.value = json.loads(' '.join(sl[2:]))
self.async = self.type == 'event'
self.asynch = self.type in ('update', 'error_update')
def __repr__(self):
value = repr(self.value)
if len(value) > 50:
value = value[:50] + '...'
return "SecopMsg('%s %s %s')" % (self.type, self.par, value)
def SecopEncode(cmd, par=None, value=None):
line = cmd
@@ -745,24 +758,34 @@ def SecopEncode(cmd, par=None, value=None):
if value:
line += " " + json.dumps(value)
return line
def convert_par(module, name, par):
result = dict(type='input', name=module+":"+name, title=name)
if par['readonly']:
result['type']='rdonly'
#print result
if par.get('readonly', True):
result['type'] = 'rdonly'
else:
result['command'] = 'change %s:%s' % (module, name)
if par['datainfo']['type'] == 'enum':
result['enum_names'] = [dict(title=k, value=v) for k, v in par['datainfo']['members'].items()]
result['type'] = 'enum'
elif par['datainfo']['type'] == 'bool':
result['type'] = 'checkbox'
return result
def convert_event(messages):
if isinstance(messages, SecopMsg):
messages = [messages]
updates = []
for msg in messages:
if msg['type'] == 'event':
updates.append(dict(name=msg.par, value=str(msg.value[0])))
if msg['type'] == 'update':
updates.append(dict(name=msg.par, value=msg.value[0]))
# updates.append(dict(name=msg.par, value=str(msg.value[0])))
return [dict(type='update', updates=updates)]
class SecopClient(object):
class SecopClient:
prio_par = ["value", "status", "target"]
hide_par = ["baseclass", "class", "pollinterval"]
skip_par = ["status2"]
@@ -796,7 +819,7 @@ class SecopClient(object):
if self.out: self.out.write("<"+line+"\n")
msg = SecopMsg(line)
#print '<', msg['type'], msg.par
if msg.async and replytype != msg['type'] + "=" + msg.par:
if msg.asynch and replytype != msg['type'] + "=" + msg.par:
t = 0
self.queue.append(msg)
else:
@@ -811,7 +834,7 @@ class SecopClient(object):
logging.error('REPLY MISMATCH %s <> %s', replytype, '<>', repr(msg))
self.replytype = ""
return msg
def w_getblock(self, path):
path = path.split(',')[-1]
if path == "main":
@@ -866,14 +889,14 @@ class SecopClient(object):
self.consolequeue.append(dict(type='reply',line=line,origin='other'))
if self.out: self.out.write("<"+line+"\n")
msg = SecopMsg(line)
if msg.async and self.replytype != msg['type'] + "=" + msg.par:
if msg.asynch and self.replytype != msg['type'] + "=" + msg.par:
return convert_event(SecopMsg(line))
self.syncreply.append(msg)
return []
def info(self):
return ["na"]
class SecopInstrument(Instrument):
def __init__(self, inst_name, instrument_config):
@@ -881,10 +904,10 @@ class SecopInstrument(Instrument):
self.host_port = hostport_split(instrument_config['hostport'])
self.logger_dir = instrument_config.get('logger_dir', '')
test_day = instrument_config.get('test_day', None)
self.test_day = [int(x) for x in test_day.split('-')] if test_day else None
self.test_day = [int(x) for x in test_day.split('-')] if test_day else None
self.title = inst_name
self.clients = {}
def newClient(self):
return self.register(SecopClient(self.host_port))
@@ -895,21 +918,22 @@ class Logger(object):
def write(self, message):
self.terminal.write(message)
self.log.write(message)
self.log.write(message)
def flush(self):
pass
pass
def handle_pdb(sig, frame):
import pdb
prin ('PDB')
pdb.Pdb().set_trace(frame)
print('PDB')
pdb.Pdb().set_trace(frame)
if __name__ == '__main__':
signal.signal(signal.SIGUSR1, handle_pdb)
print('PID', os.getpid())
if len(sys.argv) > 3:
instrument_config = {}
for arg in sys.argv[1:]:
@@ -927,13 +951,13 @@ if __name__ == '__main__':
inst_name = sys.argv[2]
except IndexError:
inst_name = 'seadummy'
with open('instruments.json') as f:
instrument_list = json.load(f)
instrument_config = instrument_list[inst_name]
logging.basicConfig(filename='log/%s.log' % inst_name, filemode='w', level=logging.INFO, format='%(asctime)s %(levelname)s %(message)s')
# sys.stdout = Logger(instrument_config.get('logger_dir', '.') + '/seaweb_stdout.txt')
# print '-' * 80
type = instrument_config.get('type', 'sea')
@@ -945,7 +969,7 @@ if __name__ == '__main__':
instrument = SecopInstrument(inst_name, instrument_config)
else:
raise TypeError('bad instrument type')
app.debug = True
#server = gevent.wsgi.WSGIServer(('', port), app, keyfile='key.key', certfile='key.crt')
server = gevent.pywsgi.WSGIServer(('', port), app, log=logging.getLogger('server'))