import de fichiers

This commit is contained in:
2024-02-28 11:40:09 +01:00
parent 25610fd4fa
commit 88aced27bf
112 changed files with 3678 additions and 0 deletions

Binary file not shown.

Binary file not shown.

Binary file not shown.

218
api_server/app.py Normal file
View File

@@ -0,0 +1,218 @@
"""
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"
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

41
api_server/state.py Normal file
View File

@@ -0,0 +1,41 @@
import json
class State(object):
IGNORE = frozenset(['Coude', 'Noeud', 'P24', 'P0', 'Pulse'])
def __init__(self, cocosim_server):
self.cocosim_server = cocosim_server
self.conf = self.cocosim_server.conf["ui"]
self.composants = {}
self._exception = None
def load_conf(self, schema_d):
# Chargement des blocs
for nom, valeur in schema_d['blocs'].items():
if valeur['type'] not in self.IGNORE:
self.composants[nom] = None
def to_json(self):
if self._exception:
return json.dumps({'exn': self._exception})
else:
return json.dumps(self.composants)
def __iter__(self):
return self.conf.__iter__
def items(self):
return self.composants.items()
def keys(self):
return self.composants.keys()
def update(self, nom, valeur):
self.composants[nom] = valeur
def exception(self, e):
self._exception = e
def reset_exception(self):
self._exception = None

19
api_server/test_client.py Normal file
View File

@@ -0,0 +1,19 @@
import asyncio
async def tcp_client():
reader, writer = await asyncio.open_connection(
'127.0.0.1', 8888)
while not writer.is_closing():
message = input("> ")
print(f'Send: {message!r}')
writer.write(message.encode())
await writer.drain()
if message == "state":
data = await reader.read(1000)
else:
data = await reader.read(100)
print(f'Received: {data.decode()!r}')
asyncio.run(tcp_client())