This commit is contained in:
root
2026-02-12 17:14:01 +01:00
parent 2e9692777f
commit 8dfe3393a5
142 changed files with 32622 additions and 2 deletions
+338
View File
@@ -0,0 +1,338 @@
/**
* 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 = '<div class="loading">Monitoring task...</div>';
return proxmoxTaskManager.monitorTask(taskId, {
onProgress: (status, progress, data, context) => {
const timestamp = new Date().toLocaleTimeString();
const progressText = progress > 0 ? ` (${progress}%)` : '';
const logEntry = document.createElement('div');
logEntry.className = 'log-entry new';
logEntry.innerHTML = `
<span class="log-timestamp">${timestamp}</span>
<span class="log-level info">INFO</span>
<span class="log-message">Task ${status}${progressText}</span>
`;
// Remove loading message if present
const loading = logContent.querySelector('.loading');
if (loading) loading.remove();
logContent.appendChild(logEntry);
logContent.scrollTop = logContent.scrollHeight;
// Remove 'new' class after animation
setTimeout(() => logEntry.classList.remove('new'), 500);
},
onSuccess: (data, context) => {
const timestamp = new Date().toLocaleTimeString();
const logEntry = document.createElement('div');
logEntry.className = 'log-entry new';
logEntry.innerHTML = `
<span class="log-timestamp">${timestamp}</span>
<span class="log-level success">✓</span>
<span class="log-message">Task completed successfully</span>
`;
logContent.appendChild(logEntry);
logContent.scrollTop = logContent.scrollHeight;
if (onComplete) {
setTimeout(() => onComplete(true, data, context), 1000);
}
},
onError: (data, context) => {
const timestamp = new Date().toLocaleTimeString();
const logEntry = document.createElement('div');
logEntry.className = 'log-entry new';
logEntry.innerHTML = `
<span class="log-timestamp">${timestamp}</span>
<span class="log-level error">✗</span>
<span class="log-message">Task failed: ${data.message}</span>
`;
logContent.appendChild(logEntry);
logContent.scrollTop = logContent.scrollHeight;
if (onComplete) {
setTimeout(() => onComplete(false, data, context), 1000);
}
},
onTimeout: (context) => {
const timestamp = new Date().toLocaleTimeString();
const logEntry = document.createElement('div');
logEntry.className = 'log-entry new';
logEntry.innerHTML = `
<span class="log-timestamp">${timestamp}</span>
<span class="log-level warning">⚠</span>
<span class="log-message">Task monitoring timed out</span>
`;
logContent.appendChild(logEntry);
logContent.scrollTop = logContent.scrollHeight;
if (onComplete) {
setTimeout(() => onComplete(false, { message: 'Timeout' }, context), 1000);
}
}
}, {
taskId: taskId,
logContainerId: logContainerId
});
}
// Cleanup bei Seitenwechsel
$(window).on('beforeunload', function() {
proxmoxTaskManager.stopAllMonitoring();
});