tokiospg commited on
Commit
2bbf764
·
verified ·
1 Parent(s): 79d1346

Upload api.py

Browse files
Files changed (1) hide show
  1. api.py +94 -7
api.py CHANGED
@@ -22,9 +22,11 @@ import imaplib
22
  import email
23
  from email.header import decode_header
24
  import re
25
- import hashlib
26
- import time
27
- import pandas as pd
 
 
28
  import io
29
  from urllib.parse import urljoin
30
  from dotenv import load_dotenv
@@ -120,9 +122,25 @@ logger.addHandler(log_handler)
120
 
121
  # --- 2. SEGURIDAD Y CIFRADO ---
122
  # Se utiliza el módulo centralizado `crypto.py`
123
- INTERNAL_API_TOKEN = os.getenv("INTERNAL_API_TOKEN", "default-dev-token")
124
-
125
- def verify_internal_token(x_internal_token: str = Header(None)):
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
126
  if x_internal_token != INTERNAL_API_TOKEN:
127
  raise HTTPException(status_code=403, detail="Acceso denegado: Token interno inválido.")
128
  return x_internal_token
@@ -139,7 +157,76 @@ app.add_middleware(
139
  allow_headers=["*"],
140
  )
141
 
142
- @app.get("/")
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
143
  def estado():
144
  return {"status": "Online", "engine": "Proyelec Core v6.1 — Token-Optimized"}
145
 
 
22
  import email
23
  from email.header import decode_header
24
  import re
25
+ import hashlib
26
+ import time
27
+ import threading
28
+ from datetime import datetime
29
+ import pandas as pd
30
  import io
31
  from urllib.parse import urljoin
32
  from dotenv import load_dotenv
 
122
 
123
  # --- 2. SEGURIDAD Y CIFRADO ---
124
  # Se utiliza el módulo centralizado `crypto.py`
125
+ INTERNAL_API_TOKEN = os.getenv("INTERNAL_API_TOKEN", "default-dev-token")
126
+ RADAR_AUTO_SCAN_ENABLED = os.getenv("RADAR_AUTO_SCAN_ENABLED", "true").strip().lower() in ["1", "true", "yes", "si", "sí", "on"]
127
+ RADAR_AUTO_SCAN_INTERVAL_MINUTES = max(5, int(os.getenv("RADAR_AUTO_SCAN_INTERVAL_MINUTES", "25") or 25))
128
+ RADAR_AUTO_SCAN_ON_STARTUP = os.getenv("RADAR_AUTO_SCAN_ON_STARTUP", "false").strip().lower() in ["1", "true", "yes", "si", "sí", "on"]
129
+ RADAR_SCHEDULER_STATE = {
130
+ "enabled": RADAR_AUTO_SCAN_ENABLED,
131
+ "interval_minutes": RADAR_AUTO_SCAN_INTERVAL_MINUTES,
132
+ "running": False,
133
+ "last_started": None,
134
+ "last_finished": None,
135
+ "last_result": None,
136
+ "last_error": None,
137
+ "next_run_at": None,
138
+ }
139
+ _radar_scheduler_stop = threading.Event()
140
+ _radar_scan_lock = threading.Lock()
141
+ _radar_scheduler_thread = None
142
+
143
+ def verify_internal_token(x_internal_token: str = Header(None)):
144
  if x_internal_token != INTERNAL_API_TOKEN:
145
  raise HTTPException(status_code=403, detail="Acceso denegado: Token interno inválido.")
146
  return x_internal_token
 
157
  allow_headers=["*"],
158
  )
159
 
160
+ def run_radar_auto_scan(source="scheduler"):
161
+ """Ejecuta el escaneo del Radar SLI de forma segura para jobs automáticos."""
162
+ if not _radar_scan_lock.acquire(blocking=False):
163
+ logger.info("[RADAR AUTO] Escaneo omitido: ya hay un escaneo en curso.")
164
+ return {"status": "skipped", "reason": "scan_already_running"}
165
+
166
+ RADAR_SCHEDULER_STATE["running"] = True
167
+ RADAR_SCHEDULER_STATE["last_started"] = datetime.now().strftime("%Y-%m-%d %H:%M:%S")
168
+ RADAR_SCHEDULER_STATE["last_error"] = None
169
+
170
+ try:
171
+ import sli_scraper
172
+ logger.info(f"[RADAR AUTO] Iniciando escaneo SLI ({source}).")
173
+ result = sli_scraper.ejecutar_radar_detallado(db_module=db)
174
+ RADAR_SCHEDULER_STATE["last_result"] = result
175
+ RADAR_SCHEDULER_STATE["last_finished"] = datetime.now().strftime("%Y-%m-%d %H:%M:%S")
176
+ logger.info(f"[RADAR AUTO] Escaneo completado: {result}")
177
+ return {"status": "success", "result": result}
178
+ except Exception as exc:
179
+ error_text = str(exc)
180
+ RADAR_SCHEDULER_STATE["last_error"] = error_text
181
+ RADAR_SCHEDULER_STATE["last_finished"] = datetime.now().strftime("%Y-%m-%d %H:%M:%S")
182
+ try:
183
+ db.registrar_escaneo_radar(0, 0, f"Auto radar error: {error_text}")
184
+ except Exception:
185
+ logger.exception("[RADAR AUTO] No se pudo registrar error de escaneo.")
186
+ logger.exception(f"[RADAR AUTO] Error en escaneo: {error_text}")
187
+ return {"status": "error", "error": error_text}
188
+ finally:
189
+ RADAR_SCHEDULER_STATE["running"] = False
190
+ _radar_scan_lock.release()
191
+
192
+ def radar_scheduler_loop():
193
+ interval_seconds = RADAR_AUTO_SCAN_INTERVAL_MINUTES * 60
194
+ if RADAR_AUTO_SCAN_ON_STARTUP:
195
+ run_radar_auto_scan(source="startup")
196
+ while not _radar_scheduler_stop.is_set():
197
+ next_run_ts = time.time() + interval_seconds
198
+ RADAR_SCHEDULER_STATE["next_run_at"] = datetime.fromtimestamp(next_run_ts).strftime("%Y-%m-%d %H:%M:%S")
199
+ if _radar_scheduler_stop.wait(interval_seconds):
200
+ break
201
+ run_radar_auto_scan()
202
+
203
+ @app.on_event("startup")
204
+ def start_radar_scheduler():
205
+ global _radar_scheduler_thread
206
+ if not RADAR_AUTO_SCAN_ENABLED:
207
+ logger.info("[RADAR AUTO] Scheduler desactivado por variable de entorno.")
208
+ return
209
+ if _radar_scheduler_thread and _radar_scheduler_thread.is_alive():
210
+ return
211
+ _radar_scheduler_stop.clear()
212
+ _radar_scheduler_thread = threading.Thread(target=radar_scheduler_loop, name="radar-sli-scheduler", daemon=True)
213
+ _radar_scheduler_thread.start()
214
+ logger.info(f"[RADAR AUTO] Scheduler iniciado cada {RADAR_AUTO_SCAN_INTERVAL_MINUTES} minutos.")
215
+
216
+ @app.on_event("shutdown")
217
+ def stop_radar_scheduler():
218
+ _radar_scheduler_stop.set()
219
+ logger.info("[RADAR AUTO] Scheduler detenido.")
220
+
221
+ @app.get("/api/v1/radar/scheduler")
222
+ def radar_scheduler_status(_token: str = Depends(verify_internal_token)):
223
+ return RADAR_SCHEDULER_STATE
224
+
225
+ @app.post("/api/v1/radar/scan-now")
226
+ def radar_scan_now(_token: str = Depends(verify_internal_token)):
227
+ return run_radar_auto_scan(source="manual_api")
228
+
229
+ @app.get("/")
230
  def estado():
231
  return {"status": "Online", "engine": "Proyelec Core v6.1 — Token-Optimized"}
232