manage-your-printer/static/js/printer_monitor.js
2025-06-04 10:03:22 +02:00

494 lines
15 KiB
JavaScript

/**
* Live-Drucker-Monitor für MYP Platform
* Verwaltet Live-Status-Updates mit Session-Caching und automatischer Aktualisierung
*/
class PrinterMonitor {
constructor() {
this.refreshInterval = 30000; // 30 Sekunden Standard-Intervall
this.fastRefreshInterval = 5000; // 5 Sekunden für schnelle Updates
this.currentInterval = null;
this.printers = new Map();
this.callbacks = new Set();
this.isActive = false;
this.useCache = true;
this.lastUpdate = null;
this.errorCount = 0;
this.maxErrors = 3;
// Status-Kategorien für bessere Übersicht
this.statusCategories = {
'online': { label: 'Online', color: 'success', icon: '🟢' },
'offline': { label: 'Offline', color: 'danger', icon: '🔴' },
'standby': { label: 'Standby', color: 'warning', icon: '🟡' },
'unreachable': { label: 'Nicht erreichbar', color: 'secondary', icon: '⚫' },
'unconfigured': { label: 'Nicht konfiguriert', color: 'info', icon: '🔵' }
};
console.log('🖨️ PrinterMonitor initialisiert');
}
/**
* Startet das Live-Monitoring
*/
start() {
if (this.isActive) {
console.log('⚠️ PrinterMonitor läuft bereits');
return;
}
this.isActive = true;
this.errorCount = 0;
console.log('🚀 Starte PrinterMonitor');
// Sofortige erste Aktualisierung
this.updatePrinterStatus();
// Reguläres Intervall starten
this.startInterval();
// Event-Listener für Sichtbarkeitsänderungen
document.addEventListener('visibilitychange', this.handleVisibilityChange.bind(this));
}
/**
* Stoppt das Live-Monitoring
*/
stop() {
if (!this.isActive) {
return;
}
this.isActive = false;
if (this.currentInterval) {
clearInterval(this.currentInterval);
this.currentInterval = null;
}
document.removeEventListener('visibilitychange', this.handleVisibilityChange.bind(this));
console.log('⏹️ PrinterMonitor gestoppt');
}
/**
* Startet das Update-Intervall
*/
startInterval() {
if (this.currentInterval) {
clearInterval(this.currentInterval);
}
this.currentInterval = setInterval(() => {
this.updatePrinterStatus();
}, this.refreshInterval);
}
/**
* Behandelt Sichtbarkeitsänderungen der Seite
*/
handleVisibilityChange() {
if (document.hidden) {
// Seite nicht sichtbar - langsamere Updates
this.refreshInterval = 60000; // 1 Minute
} else {
// Seite sichtbar - normale Updates
this.refreshInterval = 30000; // 30 Sekunden
// Sofortige Aktualisierung wenn Seite wieder sichtbar
this.updatePrinterStatus();
}
if (this.isActive) {
this.startInterval();
}
}
/**
* Holt aktuelle Drucker-Status-Daten
*/
async updatePrinterStatus() {
if (!this.isActive) {
return;
}
try {
const response = await fetch(`/api/printers/monitor/live-status?use_cache=${this.useCache}`, {
method: 'GET',
headers: {
'Content-Type': 'application/json',
'X-Requested-With': 'XMLHttpRequest'
}
});
if (!response.ok) {
throw new Error(`HTTP ${response.status}: ${response.statusText}`);
}
const data = await response.json();
if (data.success) {
this.processPrinterData(data);
this.errorCount = 0; // Reset error count on success
} else {
throw new Error(data.error || 'Unbekannter Fehler');
}
} catch (error) {
this.errorCount++;
console.error('❌ Fehler beim Abrufen des Drucker-Status:', error);
// Bei wiederholten Fehlern weniger frequent versuchen
if (this.errorCount >= this.maxErrors) {
this.refreshInterval = Math.min(this.refreshInterval * 2, 300000); // Max 5 Minuten
this.startInterval();
this.notifyCallbacks({
type: 'error',
message: `Drucker-Status nicht verfügbar (${this.errorCount} Fehler)`,
timestamp: new Date().toISOString()
});
}
}
}
/**
* Verarbeitet empfangene Drucker-Daten
*/
processPrinterData(data) {
const previousPrinters = new Map(this.printers);
// Drucker-Daten aktualisieren
this.printers.clear();
// Flexible Datenextraktion für verschiedene API-Response-Strukturen
let printersData = null;
if (data && data.printers && typeof data.printers === 'object') {
// Alte Struktur: data.printers
printersData = data.printers;
} else if (data && data.status && typeof data.status === 'object') {
// Neue Struktur: data.status
printersData = data.status;
} else if (data && typeof data === 'object' && !data.success && !data.error) {
// Direkte Drucker-Daten ohne Wrapper
printersData = data;
}
if (printersData && typeof printersData === 'object') {
// Drucker-Daten verarbeiten
Object.values(printersData).forEach(printer => {
// Sichere Validierung der Drucker-Objekte
if (printer && typeof printer === 'object' && printer.id) {
this.printers.set(printer.id, {
...printer,
statusInfo: this.statusCategories[printer.status] || this.statusCategories['offline']
});
} else {
console.warn('⚠️ Ungültiges Drucker-Objekt übersprungen:', printer);
}
});
console.log(`${this.printers.size} Drucker erfolgreich verarbeitet`);
} else {
console.warn('⚠️ Keine gültigen Drucker-Daten in Response-Struktur gefunden');
console.debug('Response-Struktur:', data);
// Benachrichtige Callbacks über fehlende Daten (aber nicht als Fehler)
this.notifyCallbacks({
type: 'warning',
message: 'Keine Drucker-Daten verfügbar',
data: data
});
return;
}
this.lastUpdate = new Date(data.timestamp || Date.now());
// Änderungen erkennen und benachrichtigen
const changes = this.detectChanges(previousPrinters, this.printers);
// Callbacks benachrichtigen
this.notifyCallbacks({
type: 'update',
printers: this.printers,
summary: data.summary,
changes: changes,
timestamp: this.lastUpdate,
cacheUsed: data.cache_used
});
console.log(`🔄 Drucker-Status aktualisiert: ${this.printers.size} Drucker`);
}
/**
* Erkennt Änderungen zwischen zwei Drucker-Status-Maps
*/
detectChanges(oldPrinters, newPrinters) {
const changes = [];
newPrinters.forEach((newPrinter, id) => {
const oldPrinter = oldPrinters.get(id);
if (!oldPrinter) {
changes.push({
type: 'added',
printer: newPrinter
});
} else if (oldPrinter.status !== newPrinter.status) {
changes.push({
type: 'status_change',
printer: newPrinter,
oldStatus: oldPrinter.status,
newStatus: newPrinter.status
});
}
});
oldPrinters.forEach((oldPrinter, id) => {
if (!newPrinters.has(id)) {
changes.push({
type: 'removed',
printer: oldPrinter
});
}
});
return changes;
}
/**
* Benachrichtigt alle registrierten Callbacks
*/
notifyCallbacks(data) {
this.callbacks.forEach(callback => {
try {
callback(data);
} catch (error) {
console.error('❌ Fehler in PrinterMonitor Callback:', error);
}
});
}
/**
* Registriert einen Callback für Status-Updates
*/
onUpdate(callback) {
if (typeof callback === 'function') {
this.callbacks.add(callback);
}
}
/**
* Entfernt einen Callback
*/
offUpdate(callback) {
this.callbacks.delete(callback);
}
/**
* Erzwingt eine sofortige Aktualisierung ohne Cache
*/
async forceUpdate() {
const oldUseCache = this.useCache;
this.useCache = false;
try {
await this.updatePrinterStatus();
} finally {
this.useCache = oldUseCache;
}
}
/**
* Löscht den Cache und erzwingt eine Aktualisierung
*/
async clearCache() {
try {
const response = await fetch('/api/printers/monitor/clear-cache', {
method: 'POST',
headers: {
'Content-Type': 'application/json',
'X-Requested-With': 'XMLHttpRequest'
}
});
if (response.ok) {
console.log('🧹 Drucker-Cache geleert');
await this.forceUpdate();
} else {
throw new Error(`HTTP ${response.status}`);
}
} catch (error) {
console.error('❌ Fehler beim Leeren des Caches:', error);
}
}
/**
* Holt eine schnelle Status-Zusammenfassung
*/
async getSummary() {
try {
const response = await fetch('/api/printers/monitor/summary', {
method: 'GET',
headers: {
'Content-Type': 'application/json',
'X-Requested-With': 'XMLHttpRequest'
}
});
if (response.ok) {
const data = await response.json();
return data.success ? data.summary : null;
}
} catch (error) {
console.error('❌ Fehler beim Abrufen der Zusammenfassung:', error);
}
return null;
}
/**
* Gibt den aktuellen Status eines Druckers zurück
*/
getPrinter(id) {
return this.printers.get(id);
}
/**
* Gibt alle Drucker zurück
*/
getAllPrinters() {
return Array.from(this.printers.values());
}
/**
* Gibt Drucker nach Status gefiltert zurück
*/
getPrintersByStatus(status) {
return this.getAllPrinters().filter(printer => printer.status === status);
}
/**
* Gibt eine Status-Zusammenfassung zurück
*/
getStatusSummary() {
const summary = {
total: this.printers.size,
online: 0,
offline: 0,
printing: 0, // Neuer Status: Drucker druckt gerade
standby: 0,
unreachable: 0,
unconfigured: 0,
error: 0 // Status für unbekannte Fehler
};
this.printers.forEach(printer => {
const status = printer.status;
if (summary.hasOwnProperty(status)) {
summary[status]++;
} else {
// Fallback für unbekannte Status
summary.offline++;
}
});
return summary;
}
/**
* Aktiviert schnelle Updates (für kritische Operationen)
*/
enableFastUpdates() {
this.refreshInterval = this.fastRefreshInterval;
if (this.isActive) {
this.startInterval();
}
console.log('⚡ Schnelle Updates aktiviert');
}
/**
* Deaktiviert schnelle Updates
*/
disableFastUpdates() {
this.refreshInterval = 30000; // Zurück zu normal
if (this.isActive) {
this.startInterval();
}
console.log('🐌 Normale Updates aktiviert');
}
/**
* Initialisiert alle Steckdosen (nur für Admins)
*/
async initializeAllOutlets() {
try {
const response = await fetch('/api/printers/monitor/initialize-outlets', {
method: 'POST',
headers: {
'Content-Type': 'application/json',
'X-Requested-With': 'XMLHttpRequest'
}
});
if (response.ok) {
const data = await response.json();
if (data.success) {
console.log('🔌 Steckdosen-Initialisierung erfolgreich:', data.statistics);
// Benachrichtige über Initialisierung
this.notifyCallbacks({
type: 'initialization',
results: data.results,
statistics: data.statistics,
message: data.message
});
// Erzwinge Update nach Initialisierung
await this.forceUpdate();
return data;
} else {
throw new Error(data.error || 'Initialisierung fehlgeschlagen');
}
} else {
throw new Error(`HTTP ${response.status}`);
}
} catch (error) {
console.error('❌ Fehler bei Steckdosen-Initialisierung:', error);
throw error;
}
}
}
// Globale Instanz
window.printerMonitor = new PrinterMonitor();
// Auto-Start wenn DOM bereit ist
document.addEventListener('DOMContentLoaded', () => {
// Nur starten wenn wir auf einer relevanten Seite sind
const relevantPages = ['/printers', '/dashboard', '/admin', '/admin-dashboard'];
const currentPath = window.location.pathname;
if (relevantPages.some(page => currentPath.includes(page))) {
console.log('🖨️ Auto-Start PrinterMonitor für Seite:', currentPath);
window.printerMonitor.start();
}
});
// Automatisches Cleanup bei Seitenverlassen
window.addEventListener('beforeunload', () => {
if (window.printerMonitor) {
window.printerMonitor.stop();
}
});
// Export für Module
if (typeof module !== 'undefined' && module.exports) {
module.exports = PrinterMonitor;
}