/** * Proxmox Task Management - Generelle Funktionen für Task-Überwachung */ try { console.log('Proxmox Task Manager will start with ', taskMonitorOptions); }catch(e){ console.log('Proxmox Task Manager will start without options'); const taskMonitorOptions = {}; } class ProxmoxTaskManager { constructor(options = taskMonitorOptions || {}) { this.checkInterval = options.checkInterval || 2000; // 1 second default this.maxTimeout = options.maxTimeout || 50000; // 30 seconds default this.taskStatusUrl = options.taskStatusUrl || '/api/task-status/'; this.activeMonitors = new Map(); // Track active monitoring processes } /** * Startet die Überwachung einer Proxmox Task * @param {string} taskId - Die Proxmox Task ID * @param {Object} callbacks - Callback-Funktionen für verschiedene Events * @param {function} callbacks.onProgress - Wird bei jedem Status-Update aufgerufen * @param {function} callbacks.onSuccess - Wird bei erfolgreichem Abschluss aufgerufen * @param {function} callbacks.onError - Wird bei Fehlern aufgerufen * @param {function} callbacks.onTimeout - Wird bei Timeout aufgerufen * @param {Object} context - Zusätzlicher Kontext, der an Callbacks weitergegeben wird */ monitorTask(taskId, callbacks = {}, context = {}) { // Stoppe eventuell bereits laufende Überwachung für diese Task this.stopMonitoring(taskId); const monitor = { taskId: taskId, callbacks: callbacks, context: context, interval: null, timeout: null, startTime: Date.now() }; // Starte Intervall für Status-Checks monitor.interval = setInterval(() => { this._checkTaskStatus(monitor); }, this.checkInterval); // Safety timeout monitor.timeout = setTimeout(() => { this._handleTimeout(monitor); }, this.maxTimeout); // Speichere Monitor für spätere Referenz this.activeMonitors.set(taskId, monitor); // Ersten Check sofort ausführen this._checkTaskStatus(monitor); return taskId; // Return taskId for reference } /** * Stoppt die Überwachung einer Task * @param {string} taskId - Die Task ID */ stopMonitoring(taskId) { const monitor = this.activeMonitors.get(taskId); if (monitor) { if (monitor.interval) clearInterval(monitor.interval); if (monitor.timeout) clearTimeout(monitor.timeout); this.activeMonitors.delete(taskId); } } /** * Stoppt alle aktiven Überwachungen */ stopAllMonitoring() { for (const [taskId] of this.activeMonitors) { this.stopMonitoring(taskId); } } /** * Prüft den Status einer Task * @private */ _checkTaskStatus(monitor) { $.get(this.taskStatusUrl, { 'task_id': monitor.taskId }) .done((data) => { if (data.status === 'success') { const taskStatus = data.task_status; const progress = data.progress || 0; // Progress callback if (monitor.callbacks.onProgress) { monitor.callbacks.onProgress(taskStatus, progress, data, monitor.context); } // Check if task is completed if (taskStatus === 'OK' || taskStatus === 'completed') { this._handleSuccess(monitor, data); } else if (taskStatus === 'stopped' || taskStatus === 'error') { this._handleError(monitor, data); } // If still running, continue monitoring } else { this._handleError(monitor, data); } }) .fail((xhr) => { let errorMsg = 'Network error'; try { const response = JSON.parse(xhr.responseText); errorMsg = response.message || errorMsg; } catch (e) {} this._handleError(monitor, { message: errorMsg }); }); } /** * Behandelt erfolgreichen Task-Abschluss * @private */ _handleSuccess(monitor, data) { this.stopMonitoring(monitor.taskId); if (monitor.callbacks.onSuccess) { monitor.callbacks.onSuccess(data, monitor.context); } } /** * Behandelt Task-Fehler * @private */ _handleError(monitor, data) { this.stopMonitoring(monitor.taskId); if (monitor.callbacks.onError) { monitor.callbacks.onError(data, monitor.context); } } /** * Behandelt Timeout * @private */ _handleTimeout(monitor) { this.stopMonitoring(monitor.taskId); if (monitor.callbacks.onTimeout) { monitor.callbacks.onTimeout(monitor.context); } } /** * Gibt die Anzahl aktiver Überwachungen zurück */ getActiveMonitorCount() { return this.activeMonitors.size; } /** * Gibt alle aktiven Task IDs zurück */ getActiveTaskIds() { return Array.from(this.activeMonitors.keys()); } } /** * Standard Proxmox Task Manager Instanz * Kann global verwendet werden */ const proxmoxTaskManager = new ProxmoxTaskManager(); /** * Hilfsfunktion für einfache Task-Überwachung mit Standard-Callbacks * @param {string} taskId - Die Task ID * @param {Object} element - DOM Element das visuell aktualisiert werden soll * @param {string} action - Aktion die ausgeführt wird (für Logging) * @param {function} onComplete - Optional: Custom completion callback */ function monitorProxmoxTask(taskId, element, action, onComplete = null) { const $element = $(element); return proxmoxTaskManager.monitorTask(taskId, { onProgress: (status, progress, data, context) => { console.log(`Task ${taskId} progress: ${status} (${progress}%)`); // Update tooltip with progress if (progress > 0) { $element.attr('title', `${action}: ${progress}%`); } }, onSuccess: (data, context) => { console.log(`Task ${taskId} completed successfully`); $element.removeClass('pending error'); if (onComplete) { onComplete(true, data, context); } else { // Standard success handling $element.attr('title', `${action} completed successfully`); } }, onError: (data, context) => { console.error(`Task ${taskId} failed:`, data.message); $element.removeClass('pending').addClass('error'); $element.attr('title', `${action} failed: ${data.message}`); if (onComplete) { onComplete(false, data, context); } }, onTimeout: (context) => { console.warn(`Task ${taskId} monitoring timed out`); $element.removeClass('pending').addClass('error'); $element.attr('title', `${action} timed out`); if (onComplete) { onComplete(false, { message: 'Timeout' }, context); } } }, { element: element, action: action, taskId: taskId }); } /** * Erweiterte Task-Überwachung mit Live-Log-Container (für Container-Erstellung etc.) * @param {string} taskId - Die Task ID * @param {string} logContainerId - ID des Log-Containers * @param {function} onComplete - Callback bei Completion */ function monitorProxmoxTaskWithLiveLog(taskId, logContainerId, onComplete = null) { const logContainer = document.getElementById(logContainerId); const logContent = logContainer?.querySelector('.live-log-content'); if (!logContainer || !logContent) { console.error('Log container not found:', logContainerId); return; } // Clear existing content logContent.innerHTML = '