acquisitore: elenco sorgenti in cache, calibrata chiesta solo se serve (Refs #92)
Servizio: la ricerca camere di /camera/sources resta 60 s in cache (lock, riscaldamento all'avvio, ?aggiorna=true la forza); le immagini caricate si leggono sempre fresche. Pagina: l'immagine caricata entra nella select senza rileggere l'elenco, pulsante Aggiorna, nessuna richiesta calibrata se la sorgente non ha calibrazione attiva o dopo un 409. Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
This commit is contained in:
@@ -140,6 +140,7 @@ PAGINA = r"""<!doctype html>
|
||||
<label for="sorgente">Camera o immagine</label>
|
||||
<select id="sorgente"></select>
|
||||
</div>
|
||||
<button id="aggiornaSorgenti" class="secondario" type="button" title="Cerca di nuovo le camere collegate">Aggiorna</button>
|
||||
<button id="caricaImmagine" class="secondario" type="button">Carica immagine da file...</button>
|
||||
<input id="fileImmagine" type="file" accept="image/*" hidden>
|
||||
<button id="rimuoviImmagine" class="secondario" type="button" hidden>Rimuovi immagine</button>
|
||||
@@ -312,12 +313,13 @@ async function dettaglio(risposta) {
|
||||
// ---- Sorgente
|
||||
|
||||
// #92: scegli = nome da selezionare (immagine appena caricata); senza, l'ultima scelta ricordata
|
||||
async function caricaSorgenti(scegli) {
|
||||
// #92: aggiorna = true forza la ricerca camere del servizio (camera appena collegata); di norma e' in cache
|
||||
async function caricaSorgenti(scegli, aggiorna) {
|
||||
var sel = $("sorgente");
|
||||
var prima = sel.value;
|
||||
sel.textContent = "";
|
||||
try {
|
||||
var r = await fetch("/camera/sources");
|
||||
var r = await fetch("/camera/sources" + (aggiorna ? "?aggiorna=true" : ""));
|
||||
var j = await r.json();
|
||||
(j.sources || []).forEach(function (s) {
|
||||
var o = document.createElement("option");
|
||||
@@ -341,6 +343,27 @@ function sorgenteImmagine() {
|
||||
return sel.selectedIndex >= 0 && sel.options[sel.selectedIndex].dataset.kind === "image";
|
||||
}
|
||||
|
||||
// #92: aggiunge (o aggiorna) la voce dell'immagine {source, label, kind} nella select e la seleziona
|
||||
function aggiungiSorgente(j) {
|
||||
var sel = $("sorgente");
|
||||
var o = null;
|
||||
for (var i = 0; i < sel.options.length; i++) if (sel.options[i].value === j.source) o = sel.options[i];
|
||||
if (!o) { o = document.createElement("option"); o.value = j.source; sel.appendChild(o); }
|
||||
o.textContent = j.label || j.source;
|
||||
o.dataset.kind = j.kind || "image";
|
||||
sel.value = j.source;
|
||||
cambioSorgente(true);
|
||||
}
|
||||
|
||||
// #92: «Aggiorna» = ricerca camere nuova (sul servizio puo' durare ~10 s)
|
||||
$("aggiornaSorgenti").onclick = async function () {
|
||||
$("aggiornaSorgenti").disabled = true;
|
||||
dire("msgSorgente", "Ricerca delle camere in corso...", "");
|
||||
await caricaSorgenti(undefined, true);
|
||||
dire("msgSorgente", "Elenco aggiornato.", "ok");
|
||||
$("aggiornaSorgenti").disabled = false;
|
||||
};
|
||||
|
||||
// #92: «Carica immagine da file...» -> POST /camera/immagini, poi la nuova immagine diventa la sorgente
|
||||
$("caricaImmagine").onclick = function () { $("fileImmagine").click(); };
|
||||
$("fileImmagine").onchange = async function () {
|
||||
@@ -355,7 +378,7 @@ $("fileImmagine").onchange = async function () {
|
||||
var r = await fetch("/camera/immagini", { method: "POST", body: f });
|
||||
if (!r.ok) { dire("msgSorgente", await dettaglio(r), "errore"); return; }
|
||||
var j = await r.json();
|
||||
await caricaSorgenti(j.source);
|
||||
aggiungiSorgente(j); // #92: la ricerca camere puo' durare ~10 s: la voce nuova si aggiunge senza rileggere l'elenco
|
||||
dire("msgSorgente", "Immagine «" + j.source + "» caricata: premere «Scatta» per vederla.", "ok");
|
||||
} catch (e) {
|
||||
dire("msgSorgente", "Servizio non raggiungibile.", "errore");
|
||||
@@ -385,7 +408,10 @@ $("rimuoviImmagine").onclick = async function () {
|
||||
try {
|
||||
var r = await fetch("/camera/immagini?nome=" + encodeURIComponent(nome), { method: "DELETE" });
|
||||
if (!r.ok) { dire("msgSorgente", await dettaglio(r), "errore"); return; }
|
||||
await caricaSorgenti("");
|
||||
var sel = $("sorgente"); // #92: voce tolta in locale, senza rileggere l'elenco dal servizio
|
||||
sel.removeChild(sel.options[sel.selectedIndex]);
|
||||
if (sel.options.length) sel.selectedIndex = 0;
|
||||
cambioSorgente(true);
|
||||
dire("msgSorgente", "Immagine «" + nome + "» rimossa.", "ok");
|
||||
} catch (e) {
|
||||
dire("msgSorgente", "Servizio non raggiungibile.", "errore");
|
||||
@@ -399,6 +425,7 @@ function cambioSorgente(salva) {
|
||||
fermaAnteprima();
|
||||
azzeraIndicatori();
|
||||
svuotaRiquadri(); // #92: il frame vecchio non e' della nuova sorgente
|
||||
A.calAttiva = null; A.bloccoCal = false; // #92: stato calibrazione della nuova sorgente ancora da leggere
|
||||
annullaRimuovi();
|
||||
$("rimuoviImmagine").hidden = !sorgenteImmagine();
|
||||
dire("msgAnteprima", "");
|
||||
@@ -410,8 +437,8 @@ function cambioSorgente(salva) {
|
||||
|
||||
// ---- Anteprima (#87)
|
||||
|
||||
// #91: ris = {w, h} dell'ultimo frame; #92: urlCal/seqCal = riquadro calibrata, riprendi = ciclo sospeso dalla tab Calibrazione, lato = ultimo lato_max
|
||||
var A = { attiva: false, gen: 0, inVolo: false, url: null, urlCal: null, seqCal: 0, riprendi: false, lato: 1280, nitMax: 0, ris: null };
|
||||
// #91: ris = {w, h} dell'ultimo frame; #92: calAttiva = la sorgente ha una calibrazione attiva (null = non nota), bloccoCal = un 409 ha fermato le richieste calibrata; urlCal/seqCal = riquadro calibrata, riprendi = ciclo sospeso dalla tab Calibrazione, lato = ultimo lato_max
|
||||
var A = { attiva: false, gen: 0, inVolo: false, url: null, urlCal: null, seqCal: 0, riprendi: false, lato: 1280, calAttiva: null, bloccoCal: false, nitMax: 0, ris: null };
|
||||
|
||||
function azzeraIndicatori() {
|
||||
A.nitMax = 0;
|
||||
@@ -464,6 +491,12 @@ function svuotaRiquadri() {
|
||||
async function aggiornaCalibrata(lato) {
|
||||
var sorgente = $("sorgente").value;
|
||||
if (!$("mostraCal").checked || !sorgente) return;
|
||||
if (A.calAttiva === false) { // #92: lo stato dice che non c'e' calibrazione: niente richiesta al servizio
|
||||
A.seqCal++;
|
||||
messaggioCalibrata("nessuna calibrazione attiva su questa sorgente");
|
||||
return;
|
||||
}
|
||||
if (A.bloccoCal) return; // #92: dopo un 409 (risoluzione diversa, planare) si richiede solo dopo Carica/Scollega o cambio sorgente
|
||||
var n = ++A.seqCal;
|
||||
try {
|
||||
var r = await fetch("/camera/anteprima/calibrata", {
|
||||
@@ -472,7 +505,11 @@ async function aggiornaCalibrata(lato) {
|
||||
body: JSON.stringify({ source: sorgente, lato_max: lato || A.lato })
|
||||
});
|
||||
if (n !== A.seqCal) return; // risposta superata da una piu' recente o da un cambio sorgente
|
||||
if (!r.ok) { messaggioCalibrata(await dettaglio(r)); return; } // l'anteprima grezza continua
|
||||
if (!r.ok) { // l'anteprima grezza continua
|
||||
if (r.status === 409) A.bloccoCal = true; // #92: inutile richiedere a ogni frame
|
||||
messaggioCalibrata(await dettaglio(r));
|
||||
return;
|
||||
}
|
||||
var nome = "";
|
||||
try { nome = decodeURIComponent(r.headers.get("X-Calibrazione") || ""); } catch (e) { /* intestazione non decodificabile: nessun nome */ }
|
||||
var blob = await r.blob();
|
||||
@@ -901,10 +938,12 @@ async function aggiornaStato() {
|
||||
if (r.status === 404) {
|
||||
stato.textContent = "Sorgente non calibrata.";
|
||||
$("statoSorgente").textContent = "non calibrata";
|
||||
A.calAttiva = false; // #92
|
||||
} else if (!r.ok) {
|
||||
stato.textContent = await dettaglio(r);
|
||||
} else {
|
||||
var d = await r.json();
|
||||
A.calAttiva = true; // #92
|
||||
stato.textContent = "";
|
||||
var titolo = document.createElement("div");
|
||||
titolo.textContent = "Calibrazione attiva: " + (d.nome ? "«" + d.nome + "»" : "(senza nome)");
|
||||
@@ -1023,8 +1062,9 @@ async function caricaNome(nome) {
|
||||
if (sorgente !== $("sorgente").value) return;
|
||||
if (!r.ok) { dire("msgElenco", await dettaglio(r), "errore"); return; }
|
||||
dire("msgElenco", "Calibrazione «" + nome + "» caricata sulla sorgente.", "ok");
|
||||
aggiornaStato();
|
||||
aggiornaCalibrata(); // #92: il riquadro calibrata usa subito la nuova calibrazione
|
||||
A.bloccoCal = false; // #92
|
||||
await aggiornaStato(); // prima lo stato nuovo, poi il riquadro calibrata con la nuova calibrazione
|
||||
aggiornaCalibrata();
|
||||
} catch (e) {
|
||||
dire("msgElenco", "Servizio non raggiungibile.", "errore");
|
||||
}
|
||||
@@ -1040,8 +1080,9 @@ async function scollega() {
|
||||
} catch (e) {
|
||||
dire("msgElenco", "Servizio non raggiungibile.", "errore");
|
||||
}
|
||||
aggiornaStato();
|
||||
aggiornaCalibrata(); // #92: senza calibrazione il riquadro mostra il 409 del servizio
|
||||
A.bloccoCal = false; // #92
|
||||
await aggiornaStato();
|
||||
aggiornaCalibrata(); // #92: senza calibrazione il riquadro dice che non c'e'
|
||||
}
|
||||
|
||||
// «Elimina» di una riga: conferma in pagina con un secondo clic entro 4 s (niente finestre del browser)
|
||||
|
||||
Reference in New Issue
Block a user