loadPrintLogo function
- String? url,
- SheetLogoSize size,
- KeckPaperSize paper, {
- PixelLoader? pixel,
- Duration timeout = const Duration(seconds: 3),
- Duration negativeCacheTtl = defaultNegativeCacheTtl,
Laedt das Logo unter url und rastert es in die Groesse, die das Blatt
size und paper geben (logoDimensions/logoRaster) -- null ohne Adresse
oder bei jedem Fehler (Netz, Decode, Pixelmass). pixel ersetzt den
Standardweg ueber LogoService/decodePng (Tests, andere Quellen).
Ergebnisse werden je Adresse, Stufe und Papier zwischengespeichert
(clearPrintLogoCache leert den Speicher). Ein Fehlschlag (null)
wird nicht dauerhaft gemerkt, aber kurz: negativeCacheTtl (Vorgabe eine
Minute) sperrt einen erneuten Versuch fuer denselben Schluessel. Ohne
diese Sperre kostete eine kaputte Adresse jeden Bon erneut bis zu
timeout am Tresen, ohne je zum Ziel zu kommen -- der Zustand hielt zwar
nichts fest, aber der Preis war derselbe wie ohne jeden Speicher. Nach
Ablauf der Sperre versucht der naechste Aufruf es wieder, damit eine
inzwischen reparierte Adresse nicht laenger als noetig verborgen bleibt.
timeout deckt den ganzen Aufruf -- Abruf (Standardweg oder pixel),
Decode und Raster -- mit einer einzigen Obergrenze, Vorgabe drei Sekunden
(Hausregel wie im Druck-Kit der Browser-Kasse: das Logo ist Zierde, ein
Druck darf nicht laenger darauf warten). LogoService.timeout bleibt daneben
bestehen und deckt fuer sich nur den HTTP-Teil in _ausLogoService -- das
ist keine zweite Frist fuer denselben Zweck, sondern eine eigene: der
LogoService wird auch direkt genutzt (Bild-Anzeige in der App, ohne
Bondruck) und braucht dort seine eigene Grenze. Treffen beide aufeinander
(Standardweg, timeout hier kleiner oder gleich LogoService.timeout),
gewinnt die kleinere: Future.timeout hier greift, sobald sie ablaeuft,
egal wie weit der HTTP-Abruf innerhalb seiner eigenen Frist noch ist.
Ein Timeout zaehlt wie jeder andere Fehlschlag fuer negativeCacheTtl: der
Speichereintrag ist damit schon weg, ein Ergebnis, das erst danach
eintrifft, findet keinen eigenen Eintrag mehr vor und schreibt keinen
neuen; der naechste Aufruf innerhalb der Negativ-Frist bekommt sofort
null, ohne selbst zu versuchen.
Implementation
Future<PrintLogo?> loadPrintLogo(
String? url,
SheetLogoSize size,
KeckPaperSize paper, {
PixelLoader? pixel,
Duration timeout = const Duration(seconds: 3),
Duration negativeCacheTtl = defaultNegativeCacheTtl,
}) {
if (url == null || url.isEmpty) return Future.value(null);
final schluessel = '$url|${size.code}|${paper.name}';
final vorhanden = _speicher[schluessel];
if (vorhanden != null) return vorhanden;
final letzterFehlschlag = _negativCache[schluessel];
if (letzterFehlschlag != null && DateTime.now().difference(letzterFehlschlag) < negativeCacheTtl) {
return Future.value(null);
}
final abruf = _laden(url, size, paper, pixel).timeout(timeout, onTimeout: () => null);
_speicher[schluessel] = abruf;
abruf.then((logo) {
// Nur den eigenen Eintrag entfernen: wurde der Speicher inzwischen
// geleert oder laeuft schon ein neuerer Abruf, bleibt der stehen. Das
// greift unveraendert auch nach einem Timeout, denn der Speicher haelt
// genau dieses (mit `timeout` umhuellte) Future -- ein spaeter fertig
// werdender roher Ladevorgang schreibt nirgends mehr hinein. Aus
// demselben Grund merkt sich auch das Negativ-Gedaechtnis nur einen
// Fehlschlag, der noch der aktuelle Stand ist -- ein laengst durch einen
// neueren, erfolgreichen Abruf ersetzter Fehlschlag darf keine Sperre
// fuer diesen setzen.
if (logo == null && identical(_speicher[schluessel], abruf)) {
_speicher.remove(schluessel);
_negativCache[schluessel] = DateTime.now();
}
});
return abruf;
}