""" Lancer avec python -m flask --debug --app server\\__init__.py run """ import logging import sys import time from flask import Flask, request, session import multiprocessing as mp from api_worker.__init__ import run_instance import uuid from flask_cors import CORS app = Flask("COCOSIM") CORS(app, supports_credentials=True) app.secret_key = bytes.fromhex('192b9bdd22ab9ed4d12e236c78afcb9a393ec15f71bbf5dc987d54727823bcbf') class ProcessBase(object): SESSION_MAX_AGE = 60 * 5 def __init__(self): self._cmd_q = {} self._state_q = {} self._process = {} self._last = {} def known(self): return 'id' in session and session['id'] in self._cmd_q def update(self): self._last[session['id']] = time.time() def cmd_q(self): self.update() return self._cmd_q[session['id']] def state_q(self): self.update() return self._state_q[session['id']] def init_q(self): self.update() self._state_q[session['id']] = mp.Queue() self._cmd_q[session['id']] = mp.Queue() def init_process(self, p): self.update() self.cleanup() self._process[session['id']] = p def process(self): return self._process[session['id']] def purge(self, k=None): if k is None: k = session['id'] del self._cmd_q[k] del self._state_q[k] del self._process[k] del self._last[k] def quit(self): self.purge() self.cleanup() def cleanup(self): ctime = time.time() to_purge = [] for k, v in self._last.items(): if ctime - v > self.SESSION_MAX_AGE: to_purge.append(k) for k in to_purge: logging.info(f"Purging {k}") self.purge(k) def __str__(self): return str(list(self._process.keys())) def __len__(self): return len(self._process.keys()) PROCESS_BASE = ProcessBase() @app.route('/') def hello(): PROCESS_BASE.cleanup() return f"Hello sailor !\nProcess base : {str(PROCESS_BASE)}" @app.route('/init') def init(): session['id'] = uuid.uuid4().int PROCESS_BASE.init_q() PROCESS_BASE.init_process(mp.Process(target=run_instance, args=(session['id'], PROCESS_BASE.cmd_q(), PROCESS_BASE.state_q()))) PROCESS_BASE.process().start() return "OK" @app.route('/start') def start(): if not PROCESS_BASE.known(): return "Unknown", 401 PROCESS_BASE.cmd_q().put({'cmd': "start"}) return "OK" @app.route('/stop') def stop(): if not PROCESS_BASE.known(): return "Unknown", 401 PROCESS_BASE.cmd_q().put({'cmd': "stop"}) return "OK" @app.route('/state') def state(): if not PROCESS_BASE.known(): return "Unknown", 401 PROCESS_BASE.cmd_q().put({'cmd': "state"}) data = PROCESS_BASE.state_q().get() return data @app.route('/quit') def quit(): if not PROCESS_BASE.known(): PROCESS_BASE.cleanup() return "Unknown", 401 PROCESS_BASE.cmd_q().put({'cmd': "quit"}) PROCESS_BASE.process().join() PROCESS_BASE.quit() del session['id'] logging.info("Purge effectuée") return "OK" @app.route('/load', methods=['POST']) def load(): if not PROCESS_BASE.known(): return "Unknown", 401 try: data = request.json PROCESS_BASE.cmd_q().put({'cmd': "load", "args": data}) except Exception: logging.exception("ERROR") return "Error", 418 if PROCESS_BASE.state_q().get() == "OK": return "OK" else: return "Error in graph", 418 @app.route('/push/') def push(obj): """ Push button """ if not PROCESS_BASE.known(): return "Unknown", 401 PROCESS_BASE.cmd_q().put({'cmd': "push", "args": obj}) return "OK" @app.route('/release/') def release(obj): """ Release button """ if not PROCESS_BASE.known(): return "Unknown", 401 PROCESS_BASE.cmd_q().put({'cmd': "release", "args": obj}) return "OK" @app.route('/pause/') def pause_simulation(obj): if not PROCESS_BASE.known(): return "Unknown", 401 PROCESS_BASE.cmd_q.put({'cmd': "pause", "arg": obj}) return "Simulation paused" @app.route('/resume/') def resume_simulation(obj): if not PROCESS_BASE.known(): return "Unknown", 401 PROCESS_BASE.cmd_q.put({'cmd': "resume", "arg": obj}) return "Simulation resumed" def just_run(): """ Pour lancer avec gunicorn """ mp.set_start_method('spawn') app.run() # Ne pas mettre debug en mode multiprocess def main(argv): host = '127.0.0.1' ssl_context = None for arg in argv[1:]: if arg == '-remote': host = '0.0.0.0' elif arg == '-secure-cookie': app.config.update(SESSION_COOKIE_SAMESITE="None", SESSION_COOKIE_SECURE="True") elif arg == '-ssl': ssl_context = 'adhoc' elif arg == '-h': print(""" Options : -remote : bind on 0.0.0.0 instead of 127.0.0.1 -secure-cookie : send secure cookie (for browser UI to be happy) -ssl : enable https with adhoc certificate """) sys.exit(0) else: print(f"Unknown argument : {arg}") sys.exit(-1) mp.set_start_method('spawn') app.run(debug=False, host=host, port=5555, ssl_context=ssl_context) # Ne pas mettre debug en mode multiprocess