2024-06-27 11:12:33 +02:00

234 lines
5.4 KiB
Python

"""
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/<obj>')
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/<obj>')
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/<obj>')
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/<obj>')
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