...
This commit is contained in:
@@ -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();
|
||||
});
|
||||
Reference in New Issue
Block a user