Compare commits
75 Commits
Author | SHA1 | Date | |
---|---|---|---|
a6ec455563 | |||
be404b625b | |||
191f0aed80 | |||
b24384f387 | |||
e136b66732 | |||
822e3ab6a2 | |||
b1ffe99a5d | |||
7d4607e947 | |||
55dd7a3777 | |||
fd37ee0dfc | |||
90e8aa5df0 | |||
6df42b9541 | |||
2984c051e9 | |||
46fca20f09 | |||
2ed1e3c292 | |||
6390d37ab4 | |||
925bdfc472 | |||
3b438d68b2 | |||
a94cc98c42 | |||
2cd78ae1e9 | |||
a4fda418b2 | |||
179db4c0a3 | |||
5c70017238 | |||
268ebc7e93 | |||
f66b071813 | |||
d6a69ba05e | |||
f883c913ed | |||
a229626bdf | |||
0a75a0aa37 | |||
d2ce97b2ab | |||
06bdbbb02e | |||
d6479a7ece | |||
a8e14eb797 | |||
b704440f36 | |||
10387261c0 | |||
9f2bfd668a | |||
70b40646ef | |||
43624b4222 | |||
e51942c97f | |||
ae7ed7bdd8 | |||
202095d539 | |||
cf0a979cc9 | |||
8d38dc31f2 | |||
9bacb41be8 | |||
8119f221bd | |||
b9a1e7db99 | |||
2fda3164e6 | |||
0a6ff13ee6 | |||
9780ab7097 | |||
9b7261261f | |||
f6aff481e2 | |||
e6e69c8f5c | |||
df582a2f23 | |||
8f7406c31b | |||
09bf402bbb | |||
6e20ed0f8f | |||
960e95c447 | |||
27f60e1187 | |||
5c1c94bffc | |||
5d10b6d48d | |||
d1ea9225dc | |||
639949f24b | |||
555aca9ed0 | |||
38b2dbcf93 | |||
33c9896bb1 | |||
da17309e78 | |||
9b3f89ddaa | |||
3d37b10d61 | |||
8d668f7de6 | |||
85fdaa445f | |||
e132b43263 | |||
56f85d9a39 | |||
bc9c1361e5 | |||
11a475149a | |||
9f5ae58b9b |
@ -78,14 +78,15 @@ new Settings()
|
|||||||
.treat("lazyPermission", "wr", to_bool, true);
|
.treat("lazyPermission", "wr", to_bool, true);
|
||||||
|
|
||||||
|
|
||||||
|
let args = '';
|
||||||
if (window.instrument) {
|
if (window.instrument) {
|
||||||
window.clientTags = "&instrument=" + window.instrument;
|
args += "&instrument=" + window.instrument;
|
||||||
} else {
|
} else {
|
||||||
let args = '';
|
|
||||||
if (window.stream) { args += "&stream=" + window.stream; }
|
if (window.stream) { args += "&stream=" + window.stream; }
|
||||||
if (window.device) { args += "&device=" + window.device; }
|
if (window.device) { args += "&device=" + window.device; }
|
||||||
window.clientTags = args;
|
|
||||||
}
|
}
|
||||||
|
if (window.hideRightPart) { args += "&history_only=1"; }
|
||||||
|
window.clientTags = args;
|
||||||
|
|
||||||
// console.log('TAGS', window.clientTags);
|
// console.log('TAGS', window.clientTags);
|
||||||
|
|
||||||
|
@ -1,8 +1,10 @@
|
|||||||
#!/usr/bin/env python
|
#!/usr/bin/env python
|
||||||
|
|
||||||
import sys
|
import sys
|
||||||
|
from os.path import expanduser
|
||||||
|
# look for sehistory and frappy at usual locations in home directory
|
||||||
|
sys.path.extend([expanduser('~'), expanduser('~/frappy')])
|
||||||
import argparse
|
import argparse
|
||||||
import socket
|
|
||||||
from webserver import server
|
from webserver import server
|
||||||
from base import Client
|
from base import Client
|
||||||
from influxgraph import InfluxGraph
|
from influxgraph import InfluxGraph
|
||||||
@ -38,6 +40,5 @@ def parseArgv(argv):
|
|||||||
|
|
||||||
args = parseArgv(sys.argv[1:])
|
args = parseArgv(sys.argv[1:])
|
||||||
|
|
||||||
instrument = socket.gethostname().split('.')[0] if args.instrument == 'HOST' else args.instrument
|
instrument = None if args.instrument=='main' else args.instrument
|
||||||
|
|
||||||
server.run(int(args.port), SEHistory(), InfluxGraph, Client, single_instrument=instrument, secop=SecopInteractor)
|
server.run(int(args.port), SEHistory(), InfluxGraph, Client, single_instrument=instrument, secop=SecopInteractor)
|
||||||
|
9
secop.py
9
secop.py
@ -54,9 +54,12 @@ class SecopInteractor(SecopClient):
|
|||||||
self.module_updates = set()
|
self.module_updates = set()
|
||||||
self.param_updates = set()
|
self.param_updates = set()
|
||||||
self.updates = {}
|
self.updates = {}
|
||||||
self.connect()
|
try:
|
||||||
node_map.update({k: self for k in self.modules})
|
self.connect()
|
||||||
self.register_callback(None, updateItem=self.updateItem)
|
node_map.update({k: self for k in self.modules})
|
||||||
|
self.register_callback(None, updateItem=self.updateItem)
|
||||||
|
except Exception as e:
|
||||||
|
print(repr(e))
|
||||||
|
|
||||||
def add_main_components(self, components):
|
def add_main_components(self, components):
|
||||||
for name, desc in self.modules.items():
|
for name, desc in self.modules.items():
|
||||||
|
131
webserver.py
131
webserver.py
@ -14,6 +14,11 @@ import flask
|
|||||||
import circularlog
|
import circularlog
|
||||||
|
|
||||||
|
|
||||||
|
instruments = {ins: 8642 for ins in
|
||||||
|
['amor', 'boa', 'camea', 'dmc', 'eiger', 'focus', 'hrpt', 'sans', 'tasp', 'zebra']
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
def guess_mimetype(filename):
|
def guess_mimetype(filename):
|
||||||
if filename.endswith('.js'):
|
if filename.endswith('.js'):
|
||||||
mimetype = 'text/javascript'
|
mimetype = 'text/javascript'
|
||||||
@ -86,9 +91,13 @@ class Server:
|
|||||||
tags['device'] = devices[0] if len(devices) == 1 else devices
|
tags['device'] = devices[0] if len(devices) == 1 else devices
|
||||||
return streams, tags, ','.join(device_names)
|
return streams, tags, ','.join(device_names)
|
||||||
|
|
||||||
def register_client(self, instrument=None, stream=None, device=None):
|
def register_client(self, instrument=None, stream=None, device=None, history_only=None):
|
||||||
streams, tags, device_name = self.lookup_streams(instrument, stream, device)
|
streams, tags, device_name = self.lookup_streams(instrument, stream, device)
|
||||||
client = self.client_cls(self, streams, instrument or '', device_name)
|
if (history_only or '0') != '0':
|
||||||
|
# create dummy client
|
||||||
|
client = self.client_cls(self, [], '', '')
|
||||||
|
else:
|
||||||
|
client = self.client_cls(self, streams, instrument or '', device_name)
|
||||||
history = self.history_cls(self, instrument, device_name, tags)
|
history = self.history_cls(self, instrument, device_name, tags)
|
||||||
# history.db.debug = True
|
# history.db.debug = True
|
||||||
# all relevant methods of the history instance are saved in client.handlers
|
# all relevant methods of the history instance are saved in client.handlers
|
||||||
@ -106,7 +115,7 @@ class Server:
|
|||||||
|
|
||||||
app.debug = True
|
app.debug = True
|
||||||
|
|
||||||
logging.basicConfig(filename='webserver.log', filemode='w', level=logging.INFO,
|
logging.basicConfig(filename=f'logfile{port}.log', filemode='w', level=logging.INFO,
|
||||||
format='%(asctime)s %(levelname)s %(message)s')
|
format='%(asctime)s %(levelname)s %(message)s')
|
||||||
|
|
||||||
# srv = gevent.wsgi.WSGIServer(('', port), app, keyfile='key.key', certfile='key.crt')
|
# srv = gevent.wsgi.WSGIServer(('', port), app, keyfile='key.key', certfile='key.crt')
|
||||||
@ -137,7 +146,7 @@ pollinterval = 0.2
|
|||||||
@app.route('/update')
|
@app.route('/update')
|
||||||
def get_update(_=None):
|
def get_update(_=None):
|
||||||
# Client Adress: socket.getfqdn(flask.request.remote_addr)
|
# Client Adress: socket.getfqdn(flask.request.remote_addr)
|
||||||
kwargs = {k: flask.request.values.get(k) for k in ('instrument', 'stream', 'device')}
|
kwargs = {k: flask.request.values.get(k) for k in ('instrument', 'stream', 'device', 'history_only')}
|
||||||
|
|
||||||
client = server.register_client(**kwargs)
|
client = server.register_client(**kwargs)
|
||||||
client.remote_info = circularlog.strtm() + " " + socket.getfqdn(flask.request.remote_addr.split(':')[-1])
|
client.remote_info = circularlog.strtm() + " " + socket.getfqdn(flask.request.remote_addr.split(':')[-1])
|
||||||
@ -147,7 +156,8 @@ def get_update(_=None):
|
|||||||
logging.info('UPDATE %s %s', client.id, socket.getfqdn(flask.request.remote_addr.split(':')[-1]))
|
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);
|
# msg = dict(type='id', id=client.id, title=instrument.title);
|
||||||
# yield to_json_sse(msg)
|
# yield to_json_sse(msg)
|
||||||
msg = dict(type='id', id=client.id, instrument=kwargs.get('instrument') or 'n_a',
|
msg = dict(type='id', id=client.id,
|
||||||
|
instrument=kwargs.get('instrument') or server.single_instrument or 'n_a',
|
||||||
device=client.device_name)
|
device=client.device_name)
|
||||||
yield to_json_sse(msg)
|
yield to_json_sse(msg)
|
||||||
try:
|
try:
|
||||||
@ -303,28 +313,31 @@ def default():
|
|||||||
return general_file('SEAWebClient.html')
|
return general_file('SEAWebClient.html')
|
||||||
|
|
||||||
|
|
||||||
@app.route('/select_instrument')
|
#@app.route('/select_instrument')
|
||||||
def select_instrument():
|
#def select_instrument():
|
||||||
out = ['''<html><body><table>
|
# out = ['''<html><body><table>
|
||||||
<style>
|
#<style>
|
||||||
th {
|
#th {
|
||||||
text-align: left;
|
# text-align: left;
|
||||||
}
|
#}
|
||||||
</style>
|
#</style>
|
||||||
<tr><th>instrument</th><th colspan=99>devices</th></tr>''']
|
#<tr><th>instrument</th><th colspan=99>devices</th></tr>''']
|
||||||
result = {}
|
# result = {}
|
||||||
for stream, tags in server.db.get_streams().items():
|
# for stream, tags in server.db.get_streams().items():
|
||||||
ins = tags.get('instrument', '0')
|
# ins = tags.get('instrument', '0')
|
||||||
result.setdefault(ins, []).append((stream, tags.get('device')))
|
# result.setdefault(ins, []).append((stream, tags.get('device')))
|
||||||
bare_streams = result.pop('0', [])
|
# bare_streams = result.pop('0', [])
|
||||||
for ins, streams in result.items():
|
# for ins, streams in result.items():
|
||||||
out.append(f'<tr><td><a href="/?ins={ins}">{ins}</a></td>')
|
# out.append(f'<tr><td><a href="/?ins={ins}">{ins}</a></td>')
|
||||||
out.extend(f'<td>{d or s}</td>' for s, d in streams)
|
# out.extend(f'<td>{d or s}</td>' for s, d in streams)
|
||||||
out.append('</tr>')
|
# out.append('</tr>')
|
||||||
for stream, device in bare_streams:
|
# for stream, device in bare_streams:
|
||||||
out.append(f'<tr><td><a href="/?srv={stream}">{stream}</a></td><td>{device}</td><tr>')
|
# out.append(f'<tr><td><a href="/?srv={stream}">{stream}</a></td><td>{device}</td><tr>')
|
||||||
out.extend(['</table></body></html>', ''])
|
# out.append('</table>')
|
||||||
return '\n'.join(out)
|
# out.append('<h3>servers on the instruments:</h3>')
|
||||||
|
# out.extend([f"<a href='http://{i.lower()}.psi.ch:8642/'>{i}</a> \n" for i in instlist])
|
||||||
|
# out.extend(['</body></html>', ''])
|
||||||
|
# return '\n'.join(out)
|
||||||
|
|
||||||
|
|
||||||
@app.route('/select_experiment')
|
@app.route('/select_experiment')
|
||||||
@ -335,7 +348,6 @@ content="width=device-width, initial-scale=1.0, minimum-scale=1.0, maximum-scale
|
|||||||
<style>
|
<style>
|
||||||
th {
|
th {
|
||||||
text-align: left;
|
text-align: left;
|
||||||
background-color: #cccccc;
|
|
||||||
}
|
}
|
||||||
a {
|
a {
|
||||||
text-decoration: none;
|
text-decoration: none;
|
||||||
@ -343,11 +355,27 @@ a {
|
|||||||
</style></head>
|
</style></head>
|
||||||
<body><table>
|
<body><table>
|
||||||
''']
|
''']
|
||||||
showtitle = 0
|
|
||||||
ONEMONTH = 30 * 24 * 3600
|
ONEMONTH = 30 * 24 * 3600
|
||||||
|
|
||||||
def title(text):
|
out.append('<br><i>direct link to instruments:</i><br>')
|
||||||
out.append(f'<tr><td colspan=2><b>{text}</b></td></tr>')
|
out.extend([f'<a href="http://{ins}.psi.ch:{port}/">{ins.upper()}</a> \n'
|
||||||
|
for ins, port in instruments.items()])
|
||||||
|
if server.db.has_local:
|
||||||
|
out.append('<h3><a href="http://linse-c.psi.ch:8888/">linse-c (central)</a></h3>')
|
||||||
|
|
||||||
|
class prev: # just a namesapce
|
||||||
|
title = None
|
||||||
|
legend = None
|
||||||
|
|
||||||
|
def change_title(text):
|
||||||
|
if text == prev.title:
|
||||||
|
return False
|
||||||
|
if prev.legend:
|
||||||
|
out.append(f'<tr>{prev.legend}</tr>')
|
||||||
|
prev.legend = None
|
||||||
|
prev.title = text
|
||||||
|
out.append(f'<tr><td colspan=3><br><i>{text}:</i></td></tr>')
|
||||||
|
return True
|
||||||
|
|
||||||
# TODO: sort this by (instrument / device) and list dates
|
# TODO: sort this by (instrument / device) and list dates
|
||||||
# period format: Ymd..Ymd, Ymd (single date), Ymd..now, HM..now
|
# period format: Ymd..Ymd, Ymd (single date), Ymd..now, HM..now
|
||||||
@ -369,27 +397,50 @@ a {
|
|||||||
chunk_list.sort(reverse=True)
|
chunk_list.sort(reverse=True)
|
||||||
for end, beg, key, devices in chunk_list:
|
for end, beg, key, devices in chunk_list:
|
||||||
today, begdate, enddate = (time.strftime("%Y-%m-%d", time.localtime(t)) for t in (now, beg, end))
|
today, begdate, enddate = (time.strftime("%Y-%m-%d", time.localtime(t)) for t in (now, beg, end))
|
||||||
|
port = None
|
||||||
|
if key[0] == 'instrument':
|
||||||
|
ins = key[1]
|
||||||
|
port = instruments.get(ins)
|
||||||
|
left = ins.upper()
|
||||||
|
else:
|
||||||
|
left = key[1] # shown in left column
|
||||||
args = ['='.join(key)]
|
args = ['='.join(key)]
|
||||||
|
remote = None if port is None else f'http://{ins}.psi.ch:{port}'
|
||||||
|
history_only = bool(remote)
|
||||||
if end > now:
|
if end > now:
|
||||||
if begdate == today:
|
if begdate == today:
|
||||||
daterange = f'since {time.strftime("%H:%M", time.localtime(beg))}'
|
daterange = f'since {time.strftime("%H:%M", time.localtime(beg))}'
|
||||||
else:
|
else:
|
||||||
daterange = f'since {begdate}'
|
daterange = f'since {begdate}'
|
||||||
if showtitle == 0:
|
change_title('currently running')
|
||||||
title('currently running')
|
|
||||||
showtitle = 1
|
|
||||||
else:
|
else:
|
||||||
|
args.append(f'time={beg},{end}')
|
||||||
|
history_only = True
|
||||||
|
remote = None
|
||||||
daterange = begdate if begdate == enddate else f'{begdate}...{enddate}'
|
daterange = begdate if begdate == enddate else f'{begdate}...{enddate}'
|
||||||
if end < now - ONEMONTH:
|
if end > now - ONEMONTH:
|
||||||
if showtitle == 1:
|
change_title('recently running (history graphics only)')
|
||||||
title('older than 30 days')
|
else:
|
||||||
showtitle = 2
|
change_title('older than 30 days')
|
||||||
|
if history_only:
|
||||||
|
args.append('hr=1')
|
||||||
|
|
||||||
out.append(f'<tr><th><a href="/?{"&".join(args)}">{key[1]} / {" ".join(devices)}</a></th>')
|
def link(label):
|
||||||
|
return f'<a href="/?{"&".join(args)}">{label}</a>'
|
||||||
|
|
||||||
|
label = " ".join(devices)
|
||||||
|
if remote:
|
||||||
|
prev.legend = '<td></td><td></td><td colspan=2>linse-c*: <i>history graphics only</i></td>'
|
||||||
|
out.append(f'<tr><td><a href="{remote}">{ins.upper()}</a></td>'
|
||||||
|
f'<td>{label}</td><td>{link("linse-c*")}</td>')
|
||||||
|
else:
|
||||||
|
out.append(f'<tr><td>{link(left)}</td><td colspan=2>{label}</td>')
|
||||||
out.append(f'<td>{daterange}</td></tr>')
|
out.append(f'<td>{daterange}</td></tr>')
|
||||||
if timerange:
|
if timerange:
|
||||||
out.append(f'<h3><a href="/select_experiment?time=all">earlier dates</a></h3><br>')
|
out.append(f'<h3><a href="/select_experiment?time=all">earlier dates</a></h3><br>')
|
||||||
out.extend(['</table></body></html>', ''])
|
out.append('</table>')
|
||||||
|
|
||||||
|
out.extend(['</body></html>', ''])
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
logging.error('%s', traceback.format_exc())
|
logging.error('%s', traceback.format_exc())
|
||||||
circularlog.log()
|
circularlog.log()
|
||||||
|
Reference in New Issue
Block a user