import de fichiers
This commit is contained in:
BIN
api_server/__pycache__/__init__.cpython-312.pyc
Normal file
BIN
api_server/__pycache__/__init__.cpython-312.pyc
Normal file
Binary file not shown.
BIN
api_server/__pycache__/app.cpython-312.pyc
Normal file
BIN
api_server/__pycache__/app.cpython-312.pyc
Normal file
Binary file not shown.
BIN
api_server/__pycache__/state.cpython-312.pyc
Normal file
BIN
api_server/__pycache__/state.cpython-312.pyc
Normal file
Binary file not shown.
218
api_server/app.py
Normal file
218
api_server/app.py
Normal 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
41
api_server/state.py
Normal 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
19
api_server/test_client.py
Normal 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())
|
||||
Reference in New Issue
Block a user