Update app.py
Browse files
app.py
CHANGED
@@ -1,5 +1,6 @@
|
|
1 |
import asyncio
|
2 |
-
|
|
|
3 |
from fastapi.responses import HTMLResponse
|
4 |
from fastapi.staticfiles import StaticFiles
|
5 |
from fastapi.middleware.cors import CORSMiddleware
|
@@ -11,13 +12,12 @@ import uvicorn
|
|
11 |
app = FastAPI()
|
12 |
|
13 |
# Configurer CORS pour autoriser toutes les origines
|
14 |
-
# Permet à n'importe quel site web d'appeler votre API
|
15 |
app.add_middleware(
|
16 |
CORSMiddleware,
|
17 |
-
allow_origins=["*"],
|
18 |
allow_credentials=True,
|
19 |
-
allow_methods=["*"],
|
20 |
-
allow_headers=["*"],
|
21 |
)
|
22 |
|
23 |
# Monter un répertoire statique pour servir le fichier index.html
|
@@ -26,6 +26,7 @@ app.mount("/static", StaticFiles(directory="static"), name="static")
|
|
26 |
class MockRequest(BaseModel):
|
27 |
"""Définit la structure attendue pour le corps de la requête POST."""
|
28 |
parameter: str
|
|
|
29 |
|
30 |
class ConnectionManager:
|
31 |
"""Gère les connexions WebSocket actives."""
|
@@ -53,7 +54,7 @@ class ConnectionManager:
|
|
53 |
await websocket.send_text(message)
|
54 |
# Créer un Future pour attendre la réponse
|
55 |
future = asyncio.get_event_loop().create_future()
|
56 |
-
# Utilise l'identifiant du client comme
|
57 |
client_id = str(id(websocket))
|
58 |
self.response_futures[client_id] = future
|
59 |
return future
|
@@ -61,6 +62,15 @@ class ConnectionManager:
|
|
61 |
|
62 |
manager = ConnectionManager()
|
63 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
64 |
|
65 |
@app.get("/", response_class=HTMLResponse)
|
66 |
async def root():
|
@@ -71,32 +81,38 @@ async def root():
|
|
71 |
except FileNotFoundError:
|
72 |
raise HTTPException(status_code=404, detail="index.html not found")
|
73 |
|
74 |
-
|
75 |
@app.post("/v1/mock")
|
76 |
async def mock_endpoint(payload: MockRequest):
|
77 |
"""
|
78 |
-
Endpoint API qui prend un string, le
|
79 |
-
attend une réponse et la retourne.
|
80 |
"""
|
81 |
try:
|
82 |
-
# Récupérer les données JSON du corps de la requête
|
83 |
-
# data = await request.json()
|
84 |
input_string = payload.parameter
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
85 |
|
86 |
if input_string is None:
|
87 |
-
|
88 |
|
89 |
-
print(f"Endpoint /v1/mock appelé avec: '{input_string}'")
|
90 |
-
|
91 |
if not manager.active_connections:
|
92 |
-
|
93 |
|
94 |
# Envoyer le message via WebSocket et obtenir un "future" pour la réponse
|
95 |
print("Envoi du message au client WebSocket...")
|
96 |
response_future = await manager.broadcast(input_string)
|
97 |
|
98 |
if response_future is None:
|
99 |
-
|
100 |
|
101 |
try:
|
102 |
# Attendre la réponse du client WebSocket avec un timeout de 60 secondes
|
@@ -106,12 +122,14 @@ async def mock_endpoint(payload: MockRequest):
|
|
106 |
|
107 |
except asyncio.TimeoutError:
|
108 |
print("Timeout: Aucune réponse du client WebSocket.")
|
109 |
-
|
110 |
|
|
|
|
|
|
|
111 |
except Exception as e:
|
112 |
print(f"Erreur dans /v1/mock: {e}")
|
113 |
-
|
114 |
-
|
115 |
|
116 |
@app.websocket("/ws")
|
117 |
async def websocket_endpoint(websocket: WebSocket):
|
@@ -136,6 +154,5 @@ async def websocket_endpoint(websocket: WebSocket):
|
|
136 |
print(f"Erreur dans le WebSocket: {e}")
|
137 |
manager.disconnect(websocket)
|
138 |
|
139 |
-
|
140 |
if __name__ == "__main__":
|
141 |
uvicorn.run(app, host="0.0.0.0", port=7860)
|
|
|
1 |
import asyncio
|
2 |
+
import os
|
3 |
+
from fastapi import FastAPI, WebSocket, WebSocketDisconnect, HTTPException
|
4 |
from fastapi.responses import HTMLResponse
|
5 |
from fastapi.staticfiles import StaticFiles
|
6 |
from fastapi.middleware.cors import CORSMiddleware
|
|
|
12 |
app = FastAPI()
|
13 |
|
14 |
# Configurer CORS pour autoriser toutes les origines
|
|
|
15 |
app.add_middleware(
|
16 |
CORSMiddleware,
|
17 |
+
allow_origins=["*"],
|
18 |
allow_credentials=True,
|
19 |
+
allow_methods=["*"],
|
20 |
+
allow_headers=["*"],
|
21 |
)
|
22 |
|
23 |
# Monter un répertoire statique pour servir le fichier index.html
|
|
|
26 |
class MockRequest(BaseModel):
|
27 |
"""Définit la structure attendue pour le corps de la requête POST."""
|
28 |
parameter: str
|
29 |
+
secret: str # Nouveau champ pour le secret
|
30 |
|
31 |
class ConnectionManager:
|
32 |
"""Gère les connexions WebSocket actives."""
|
|
|
54 |
await websocket.send_text(message)
|
55 |
# Créer un Future pour attendre la réponse
|
56 |
future = asyncio.get_event_loop().create_future()
|
57 |
+
# Utilise l'identifiant du client comme clé
|
58 |
client_id = str(id(websocket))
|
59 |
self.response_futures[client_id] = future
|
60 |
return future
|
|
|
62 |
|
63 |
manager = ConnectionManager()
|
64 |
|
65 |
+
def verify_secret(provided_secret: str) -> bool:
|
66 |
+
"""Vérifie si le secret fourni correspond à celui de la variable d'environnement."""
|
67 |
+
expected_secret = os.getenv("API_SECRET")
|
68 |
+
|
69 |
+
if not expected_secret:
|
70 |
+
print("ATTENTION: Variable d'environnement API_SECRET non définie!")
|
71 |
+
return False
|
72 |
+
|
73 |
+
return provided_secret == expected_secret
|
74 |
|
75 |
@app.get("/", response_class=HTMLResponse)
|
76 |
async def root():
|
|
|
81 |
except FileNotFoundError:
|
82 |
raise HTTPException(status_code=404, detail="index.html not found")
|
83 |
|
|
|
84 |
@app.post("/v1/mock")
|
85 |
async def mock_endpoint(payload: MockRequest):
|
86 |
"""
|
87 |
+
Endpoint API qui prend un string et un secret, vérifie le secret,
|
88 |
+
puis transmet via WebSocket, attend une réponse et la retourne.
|
89 |
"""
|
90 |
try:
|
|
|
|
|
91 |
input_string = payload.parameter
|
92 |
+
provided_secret = payload.secret
|
93 |
+
|
94 |
+
# Vérification du secret AVANT tout traitement
|
95 |
+
if not verify_secret(provided_secret):
|
96 |
+
print(f"Tentative d'accès avec un secret invalide: '{provided_secret[:10]}...'")
|
97 |
+
raise HTTPException(
|
98 |
+
status_code=401,
|
99 |
+
detail="Secret invalide. Accès non autorisé."
|
100 |
+
)
|
101 |
+
|
102 |
+
print(f"Secret vérifié avec succès. Endpoint /v1/mock appelé avec: '{input_string}'")
|
103 |
|
104 |
if input_string is None:
|
105 |
+
raise HTTPException(status_code=400, detail="Le paramètre 'parameter' est manquant.")
|
106 |
|
|
|
|
|
107 |
if not manager.active_connections:
|
108 |
+
raise HTTPException(status_code=503, detail="Aucun client WebSocket n'est connecté.")
|
109 |
|
110 |
# Envoyer le message via WebSocket et obtenir un "future" pour la réponse
|
111 |
print("Envoi du message au client WebSocket...")
|
112 |
response_future = await manager.broadcast(input_string)
|
113 |
|
114 |
if response_future is None:
|
115 |
+
raise HTTPException(status_code=500, detail="Échec de la diffusion du message.")
|
116 |
|
117 |
try:
|
118 |
# Attendre la réponse du client WebSocket avec un timeout de 60 secondes
|
|
|
122 |
|
123 |
except asyncio.TimeoutError:
|
124 |
print("Timeout: Aucune réponse du client WebSocket.")
|
125 |
+
raise HTTPException(status_code=408, detail="Timeout: Le client n'a pas répondu à temps.")
|
126 |
|
127 |
+
except HTTPException:
|
128 |
+
# Re-lever les HTTPException sans les wrapper
|
129 |
+
raise
|
130 |
except Exception as e:
|
131 |
print(f"Erreur dans /v1/mock: {e}")
|
132 |
+
raise HTTPException(status_code=500, detail=f"Une erreur interne est survenue: {str(e)}")
|
|
|
133 |
|
134 |
@app.websocket("/ws")
|
135 |
async def websocket_endpoint(websocket: WebSocket):
|
|
|
154 |
print(f"Erreur dans le WebSocket: {e}")
|
155 |
manager.disconnect(websocket)
|
156 |
|
|
|
157 |
if __name__ == "__main__":
|
158 |
uvicorn.run(app, host="0.0.0.0", port=7860)
|