Improve Dashboard functionality

This commit is contained in:
2026-08-29 18:39:48 +02:00
parent 3db3168a8a
commit d0c3ea03a5
+14 -17
View File
@@ -98,7 +98,7 @@ def carica_rubrica():
UTENTI_SIP_DMR = carica_rubrica()
# ====================================================================
# DASHBOARD MANAGER (Motore Dati)
# DASHBOARD MANAGER (Motore Dati - Modificato Sincrono)
# ====================================================================
class DashboardManager:
def __init__(self):
@@ -112,7 +112,7 @@ class DashboardManager:
try: await ws.send_str(msg_str)
except Exception: self.ws_clients.discard(ws)
async def inizia_chiamata(self, id_chiamata, direzione, mittente, destinatario):
def inizia_chiamata(self, id_chiamata, direzione, mittente, destinatario):
nom_mittente = get_nominativo(mittente)
nom_dest = get_nominativo(destinatario)
@@ -126,20 +126,20 @@ class DashboardManager:
"stato": "ON"
}
self.chiamate_attive[id_chiamata] = dati
await self.broadcast({"evento": "chiamata_iniziata", "dati": dati})
asyncio.create_task(self.broadcast({"evento": "chiamata_iniziata", "dati": dati}))
async def aggiorna_rx(self, id_chiamata):
def aggiorna_rx(self, id_chiamata):
if id_chiamata in self.chiamate_attive:
self.chiamate_attive[id_chiamata]["ultimo_frame"] = time.time()
async def termina_chiamata(self, id_chiamata):
def termina_chiamata(self, id_chiamata):
if id_chiamata in self.chiamate_attive:
dati = self.chiamate_attive.pop(id_chiamata)
dati["fine"] = time.time()
dati["durata"] = round(dati["fine"] - dati["inizio"], 1)
dati["stato"] = "OFF"
self.storico.appendleft(dati)
await self.broadcast({"evento": "chiamata_terminata", "dati": dati})
asyncio.create_task(self.broadcast({"evento": "chiamata_terminata", "dati": dati}))
async def watchdog_rx(self):
while True:
@@ -147,7 +147,7 @@ class DashboardManager:
ora = time.time()
for id_chiamata, dati in list(self.chiamate_attive.items()):
if dati["direzione"] == "RX" and ora - dati.get("ultimo_frame", ora) > 1.5:
await self.termina_chiamata(id_chiamata)
self.termina_chiamata(id_chiamata)
# ====================================================================
# ENDPOINT WEB (aiohttp)
@@ -353,10 +353,10 @@ class SessionManager:
self.gestisci_ptt(sess, False)
self.vocoder.rilascia_porta(f"SIP_{call_id}")
# PULIZIA FORZATA: Chiudiamo eventuali righe RX rimaste appese per questo interno
# Chiusura sincrona per evitare code
for id_dash in list(dashboard_app.chiamate_attive.keys()):
if id_dash.startswith("RX_") and id_dash.endswith(f"_{call_id}"):
asyncio.create_task(dashboard_app.termina_chiamata(id_dash))
dashboard_app.termina_chiamata(id_dash)
del self.sessioni[call_id]
asyncio.create_task(dashboard_app.broadcast({"evento": "estensioni_update"}))
@@ -372,11 +372,11 @@ class SessionManager:
nome_base = get_nominativo(sess.dmr_id)
mittente_display = f"{nome_base} (Est. {sess.chiamante})"
asyncio.create_task(dashboard_app.inizia_chiamata(id_dash_tx, "TX", mittente_display, sess.tg_destinazione))
dashboard_app.inizia_chiamata(id_dash_tx, "TX", mittente_display, sess.tg_destinazione)
elif stato is False and sess.ptt_attivo:
sess.ptt_attivo = False
if self.openbridge: self.openbridge.chiudi_flusso_chiamata(sess)
asyncio.create_task(dashboard_app.termina_chiamata(id_dash_tx))
dashboard_app.termina_chiamata(id_dash_tx)
def gestisci_dtmf_digit(self, sess, digit):
if sess.ptt_attivo: return
@@ -424,9 +424,9 @@ class SessionManager:
if id_dash_rx not in dashboard_app.chiamate_attive:
dest_display = f"{sess.chiamante} (TG {tg_arrivo})"
asyncio.create_task(dashboard_app.inizia_chiamata(id_dash_rx, "RX", src_id, dest_display))
dashboard_app.inizia_chiamata(id_dash_rx, "RX", src_id, dest_display)
else:
asyncio.create_task(dashboard_app.aggiorna_rx(id_dash_rx))
dashboard_app.aggiorna_rx(id_dash_rx)
if sess.ultimo_src_id != src_id:
sess.ultimo_src_id = src_id
@@ -540,9 +540,7 @@ class SipProtocol(asyncio.DatagramProtocol):
def connection_made(self, transport): self.manager.sip_transport = transport
def datagram_received(self, data, addr):
if addr[0] != FREEPBX_IP and FREEPBX_IP != "0.0.0.0": return
msg = data.decode('utf-8', errors='ignore')
# FIX: splitlines() digerisce correttamente sia \r\n che \n
msg = data.decode('utf-8', errors='ignore').lstrip()
lines = msg.splitlines()
headers = {line.split(":", 1)[0].strip().upper(): line.split(":", 1)[1].strip() for line in lines[1:] if ":" in line}
call_id = headers.get('CALL-ID', '')
@@ -585,7 +583,6 @@ class SipProtocol(asyncio.DatagramProtocol):
f"Max-Forwards: 70\r\nFrom: {headers.get('FROM', '')}\r\nTo: {headers.get('TO', '')}\r\n"
f"Call-ID: {call_id}\r\nCSeq: {headers.get('CSEQ', '').split()[0]} ACK\r\nContent-Length: 0\r\n\r\n")
self.manager.sip_transport.sendto(ack.encode('utf-8'), addr)
# FIX: Aggiunto supporto al CANCEL e chiusura forzata in dashboard
elif msg.startswith("BYE") or msg.startswith("CANCEL"):
self.manager.termina_chiamata(call_id)
resp = (f"SIP/2.0 200 OK\r\nVia: {headers.get('VIA', '')}\r\nFrom: {headers.get('FROM', '')}\r\nTo: {headers.get('TO', '')}\r\n"