import asyncio import atexit import datetime import socket from functools import lru_cache from time import sleep, time import matplotlib.pyplot as plt import socketio from apscheduler.schedulers.background import BackgroundScheduler from flask import Flask, render_template, request from flask_cors import CORS sio = socketio.Server() app = Flask(__name__) CORS(app) app.wsgi_app = socketio.WSGIApp(sio, app.wsgi_app) # We request users to send the run number to prevent accidentially getting old requests from a previous run # This maybe will give to much errors from people forgetting to change their number # Remove it? # TODO # Save and read from a file to persist over reboots # Save progress through time during 1 run # Save result of different runs db = {"current_run": None, "run_start_timer": None, "run_data": {}} function_times = [] function_data = [] @app.route("/") def index(): return render_template('index.html') @app.route("/start_run/") def start_run(run_index): request_data = live_request(f'/start_run/{run_index}') #make request show up on the live requests if not run_index.isdigit(): return f'{run_index} is not a number' db["current_run"] = run_index starttime = time() if run_index in db["run_data"]: return "This run is already ran, take another number." db["run_data"][run_index] = {"starttime": starttime, "data": {}} # TODO send start request to the first person in the chain. Probably a zeus part already written as example sio.emit('start_run', run_index) return f'Run {run_index} started at {starttime}' @app.route("/link/start//") def link_start(run, link_index): request_data = live_request(f'/link/start/{run}/{link_index}') #make request show up on the live requests if not run.isdigit() or not link_index.isdigit(): return f'{run} and/or {link_index} is not a number' start = time() if db["current_run"] != run: response = "Wrong run number, check that you update your run", 404 else: run_data = db["run_data"][run]["data"] if link_index in run_data: response = "you already started in this run. Ignoring this request." else: run_data[link_index] = {"id": link_index, "start": time()} sio.emit('link_start', run_data[link_index]) response = "Success." stop = time() function_data.append(stop - start) function_times.append(len(function_times)) return response @app.route("/link/handoff//") def link_handoff(run, index): request_data = live_request(f'/link/handoff/{run}/{link_index}') #make request show up on the live requests if not run.isdigit() or not index.isdigit(): return f'{run} and/or {index} is not a number' if db["current_run"] != run: return "Wrong run number, check that you updated you run", 404 else: link_data = db["run_data"][run]["data"][index] if "handoff" in link_data: return "you already handed off control during this run. Ignoring this request" else: link_data["handoff"] = time() sio.emit('link_handoff', link_data) return "Success." @sio.event def connect(sid, data): if db["current_run"]: current_run = db["run_data"][db["current_run"]] sio.emit('sync_current_run', current_run, room=sid) def live_request(route_data): ip = request.remote_addr request_data = {} request_data["hostname"] = lookup_hostname(ip) request_data["time"] = time() request_data["route"] = route_data sio.emit('live_request', request_data) @lru_cache() def lookup_hostname(ip): return socket.gethostbyaddr(ip)[0].split(".")[0] # def plot_graph(): # try: # x = function_times # y = function_data # plt.plot(x, y) # plt.show() # except: # pass if __name__ == '__main__': # scheduler = BackgroundScheduler() # scheduler.add_job(func=plot_graph, trigger="interval", seconds=5) # scheduler.start() app.run(host="0.0.0.0", debug=True) # shut down the scheduler when exiting the app # atexit.register(lambda: scheduler.shutdown())