from datetime import datetime from glob import glob from os.path import basename, join, exists, splitext, getsize from functools import wraps from collections import OrderedDict import time import toml from flask import render_template, send_from_directory, request, Response from app import app from km3modules.common import LocalDBService CONFIG_PATH = "pipeline.toml" PLOTS_PATH = "../plots" LOGS_PATH = "../logs" USERNAME = None PASSWORD = None app.config['FREEZER_DESTINATION'] = '../km3web' PLOTS = [['dom_activity', 'dom_rates'], 'pmt_rates_du*', ['trigger_rates'], ['ztplot', 'triggermap']] AHRS_PLOTS = ['yaw_calib_du*', 'pitch_calib_du*', 'roll_calib_du*'] TRIGGER_PLOTS = [['trigger_rates'], ['trigger_rates_lin']] K40_PLOTS = [['intradom'], ['angular_k40rate_distribution']] RTTC_PLOTS = [['rttc']] RECO_PLOTS = [['track_reco', 'ztplot_roy'], ['time_residuals']] COMPACT_PLOTS = [['dom_activity', 'dom_rates', 'pmt_rates'], ['trigger_rates', 'trigger_rates_lin'], ['ztplot', 'ztplot_roy', 'triggermap']] SN_PLOTS = [['sn_bg_histogram', 'sn_pk_history']] RASP_PLOTS = [['dom_rates', 'ztplot', 'triggermap'], [ 'pmt_rates_du2', 'pmt_rates_du3', 'pmt_rates_du4', 'pmt_rates_du5' ], ['trigger_rates', 'trigger_rates_lin']] if exists(CONFIG_PATH): config = toml.load(CONFIG_PATH) if "WebServer" in config: print("Reading authentication information from '%s'" % CONFIG_PATH) USERNAME = config["WebServer"]["username"] PASSWORD = config["WebServer"]["password"] def expand_wildcards(plot_layout): """Replace wildcard entries with list of files""" plots = [] for row in plot_layout: if not isinstance(row, list) and '*' in row: plots.append( sorted([ splitext(basename(p))[0] for p in glob(join(app.root_path, PLOTS_PATH, row)) ])) else: plots.append(row) return plots def check_auth(username, password): """This function is called to check if a username / password combination is valid. """ if USERNAME is not None and PASSWORD is not None: return username == USERNAME and password == PASSWORD else: return True def authenticate(): """Sends a 401 response that enables basic auth""" return Response( 'Could not verify your access level for that URL.\n' 'You have to login with proper credentials', 401, {'WWW-Authenticate': 'Basic realm="Login Required"'}) def requires_auth(f): @wraps(f) def decorated(*args, **kwargs): auth = request.authorization if not auth or not check_auth(auth.username, auth.password): return authenticate() return f(*args, **kwargs) return decorated @app.after_request def add_header(r): """ Disable caches. """ r.headers["Cache-Control"] = "no-cache, no-store, must-revalidate" r.headers["Pragma"] = "no-cache" r.headers["Expires"] = "0" r.headers["Cache-Control"] = "public, max-age=0" return r @app.route('/') @app.route('/index.html') @requires_auth def index(): return render_template('plots.html', plots=expand_wildcards(PLOTS)) @app.route('/plot_<plot>.html') @requires_auth def single_plot(plot): return render_template('plot.html', plot=plot) @app.route('/ahrs.html') @requires_auth def ahrs(): return render_template('plots.html', plots=expand_wildcards(AHRS_PLOTS)) @app.route('/reco.html') @requires_auth def reco(): return render_template('plots.html', plots=expand_wildcards(RECO_PLOTS)) @app.route('/sn.html') @requires_auth def supernova(): return render_template('plots.html', plots=expand_wildcards(SN_PLOTS)) @app.route('/compact.html') @requires_auth def compact(): return render_template('plots.html', plots=expand_wildcards(COMPACT_PLOTS)) @app.route('/rttc.html') @requires_auth def rttc(): return render_template( 'plots.html', plots=expand_wildcards(RTTC_PLOTS), info= "Cable Round Trip Time calculated from realtime data provided by the " "Detector Manager. The red lines shows the median and the STD " "from the past 24 hours. " "RTTC = Cable_RTT - (TX_Slave + RX_Slave + TX_Master + RX_Master)") # @app.route('/k40.html') # @requires_auth # def k40(): # return render_template( # 'plots.html', # plots=expand_wildcards(K40_PLOTS), # info="The first plot shows the intra-DOM calibration. " # "y-axis: delta_t [ns], x-axis: cosine of angles. " # "The second plot the angular distribution of K40 rates. " # "y-axis: rate [Hz], x-axis: cosine of angles. " # "blue=before, red=after") @app.route('/trigger.html') @requires_auth def trigger(): return render_template('plots.html', plots=expand_wildcards(TRIGGER_PLOTS)) @app.route('/top10.html') @requires_auth def top10(): category_names = { 'n_hits': 'Number of hits', 'overlays': 'Number of overlays' } top10 = {} dbs = LocalDBService(filename="data/monitoring.sqlite3") for category in ["overlays", "n_hits"]: raw_data = dbs.query( "SELECT plot_filename, n_hits, n_triggered_hits, overlays, " "det_id, run_id, frame_index, trigger_counter, utc_timestamp " "FROM event_selection ORDER BY {cat} DESC LIMIT 10".format( cat=category)) if len(raw_data) > 0: print(raw_data) top10[category_names[category]] = [{ "plot_filename": r[0], "meta": { "Number of hits (triggered)": "{} ({})".format(r[1], r[2]), "Overlays": r[3], "Detector ID": r[4], "Run": r[5], "Frame index": r[6], "Trigger counter": r[7], "Date": datetime.utcfromtimestamp(r[8]).strftime("%c") }, "is_recent": (time.time() - r[8]) < 60 * 60 * 24 } for r in raw_data] return render_template('top10.html', top10=top10) @app.route('/logs.html') @requires_auth def logs(): files = OrderedDict() filenames = sorted(glob(join(app.root_path, LOGS_PATH, "MSG*.log")), reverse=True) main_log = filenames.pop(-1) for filename in [main_log] + filenames: files[basename(filename)] = getsize(filename) return render_template('logs.html', files=files) @app.route('/logs/<path:filename>') @requires_auth def custom_static_logfile(filename): filepath = join(app.root_path, LOGS_PATH) print("Serving: {}/{}".format(filepath, filename)) return send_from_directory(join(app.root_path, LOGS_PATH), filename) @app.route('/plots/<path:filename>') @requires_auth def custom_static(filename): # filepath = join(app.root_path, PLOTS_PATH) # print("Serving: {}/{}".format(filepath, filename)) return send_from_directory(join(app.root_path, PLOTS_PATH), filename) @app.route('/rasp.html') @requires_auth def rasp(): return render_template('plots.html', plots=expand_wildcards(RASP_PLOTS))