mirror of
https://github.com/kodxana/madiator-docker-runpod.git
synced 2024-11-25 20:30:11 +01:00
Fixes for crash during install process, reduced logs spam for Fileapp check
This commit is contained in:
parent
0af6151735
commit
0124ebe43b
5 changed files with 205 additions and 173 deletions
|
@ -223,40 +223,54 @@ def force_kill_app(app_name):
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
return jsonify({'status': 'error', 'message': str(e)})
|
return jsonify({'status': 'error', 'message': str(e)})
|
||||||
|
|
||||||
|
from gevent.lock import RLock
|
||||||
|
websocket_lock = RLock()
|
||||||
|
|
||||||
@sock.route('/ws')
|
@sock.route('/ws')
|
||||||
def websocket(ws):
|
def websocket(ws):
|
||||||
|
with websocket_lock:
|
||||||
active_websockets.add(ws)
|
active_websockets.add(ws)
|
||||||
try:
|
try:
|
||||||
while True:
|
while ws.connected: # Check connection status
|
||||||
message = ws.receive()
|
try:
|
||||||
|
message = ws.receive(timeout=70) # Add timeout slightly higher than heartbeat
|
||||||
|
if message:
|
||||||
data = json.loads(message)
|
data = json.loads(message)
|
||||||
|
|
||||||
if data['type'] == 'heartbeat':
|
if data['type'] == 'heartbeat':
|
||||||
ws.send(json.dumps({'type': 'heartbeat'}))
|
ws.send(json.dumps({'type': 'heartbeat'}))
|
||||||
else:
|
else:
|
||||||
# Handle other message types
|
# Handle other message types
|
||||||
pass
|
pass
|
||||||
|
except Exception as e:
|
||||||
|
if "timed out" in str(e).lower():
|
||||||
|
# Handle timeout gracefully
|
||||||
|
continue
|
||||||
|
print(f"Error handling websocket message: {str(e)}")
|
||||||
|
if not ws.connected:
|
||||||
|
break
|
||||||
|
continue
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
print(f"WebSocket error: {str(e)}")
|
print(f"WebSocket error: {str(e)}")
|
||||||
finally:
|
finally:
|
||||||
|
with websocket_lock:
|
||||||
|
try:
|
||||||
active_websockets.remove(ws)
|
active_websockets.remove(ws)
|
||||||
|
except KeyError:
|
||||||
|
pass
|
||||||
|
|
||||||
def send_heartbeat():
|
def send_heartbeat():
|
||||||
initial_interval = 5 # 5 seconds
|
|
||||||
max_interval = 60 # 60 seconds
|
|
||||||
current_interval = initial_interval
|
|
||||||
start_time = time.time()
|
|
||||||
|
|
||||||
while True:
|
while True:
|
||||||
time.sleep(current_interval)
|
try:
|
||||||
send_websocket_message('heartbeat', {})
|
time.sleep(60) # Fixed 60 second interval
|
||||||
|
with websocket_lock:
|
||||||
# Gradually increase the interval
|
for ws in list(active_websockets): # Create a copy of the set
|
||||||
elapsed_time = time.time() - start_time
|
try:
|
||||||
if elapsed_time < 60: # First minute
|
if ws.connected:
|
||||||
current_interval = min(current_interval * 1.5, max_interval)
|
ws.send(json.dumps({'type': 'heartbeat', 'data': {}}))
|
||||||
else:
|
except Exception as e:
|
||||||
current_interval = max_interval
|
print(f"Error sending heartbeat: {str(e)}")
|
||||||
|
except Exception as e:
|
||||||
|
print(f"Error in heartbeat thread: {str(e)}")
|
||||||
|
|
||||||
# Start heartbeat thread
|
# Start heartbeat thread
|
||||||
threading.Thread(target=send_heartbeat, daemon=True).start()
|
threading.Thread(target=send_heartbeat, daemon=True).start()
|
||||||
|
@ -264,7 +278,15 @@ threading.Thread(target=send_heartbeat, daemon=True).start()
|
||||||
@app.route('/install/<app_name>', methods=['POST'])
|
@app.route('/install/<app_name>', methods=['POST'])
|
||||||
def install_app_route(app_name):
|
def install_app_route(app_name):
|
||||||
try:
|
try:
|
||||||
success, message = install_app(app_name, app_configs, send_websocket_message)
|
def progress_callback(message_type, message_data):
|
||||||
|
try:
|
||||||
|
send_websocket_message(message_type, message_data)
|
||||||
|
except Exception as e:
|
||||||
|
print(f"Error sending progress update: {str(e)}")
|
||||||
|
# Continue even if websocket fails
|
||||||
|
pass
|
||||||
|
|
||||||
|
success, message = install_app(app_name, app_configs, progress_callback)
|
||||||
if success:
|
if success:
|
||||||
return jsonify({'status': 'success', 'message': message})
|
return jsonify({'status': 'success', 'message': message})
|
||||||
else:
|
else:
|
||||||
|
@ -335,7 +357,12 @@ def stop_filebrowser_route():
|
||||||
|
|
||||||
@app.route('/filebrowser_status')
|
@app.route('/filebrowser_status')
|
||||||
def filebrowser_status_route():
|
def filebrowser_status_route():
|
||||||
return jsonify({'status': get_filebrowser_status()})
|
try:
|
||||||
|
status = get_filebrowser_status()
|
||||||
|
return jsonify({'status': status if status else 'unknown'})
|
||||||
|
except Exception as e:
|
||||||
|
app.logger.error(f"Error getting filebrowser status: {str(e)}")
|
||||||
|
return jsonify({'status': 'error', 'message': str(e)}), 500
|
||||||
|
|
||||||
@app.route('/add_app_config', methods=['POST'])
|
@app.route('/add_app_config', methods=['POST'])
|
||||||
def add_new_app_config():
|
def add_new_app_config():
|
||||||
|
|
|
@ -5,7 +5,7 @@ import multiprocessing
|
||||||
workers = multiprocessing.cpu_count() * 2 + 1
|
workers = multiprocessing.cpu_count() * 2 + 1
|
||||||
worker_class = 'geventwebsocket.gunicorn.workers.GeventWebSocketWorker'
|
worker_class = 'geventwebsocket.gunicorn.workers.GeventWebSocketWorker'
|
||||||
worker_connections = 1000
|
worker_connections = 1000
|
||||||
timeout = 300
|
timeout = 0 # Disable timeout completely
|
||||||
|
|
||||||
# Server socket
|
# Server socket
|
||||||
bind = '0.0.0.0:7222'
|
bind = '0.0.0.0:7222'
|
||||||
|
|
|
@ -2640,6 +2640,8 @@
|
||||||
document.getElementById('loadingOverlay').style.display = 'none';
|
document.getElementById('loadingOverlay').style.display = 'none';
|
||||||
reconnectAttempts = 0;
|
reconnectAttempts = 0;
|
||||||
initializeUI();
|
initializeUI();
|
||||||
|
// Start sending heartbeats immediately after connection
|
||||||
|
startHeartbeat();
|
||||||
};
|
};
|
||||||
|
|
||||||
socket.onmessage = function(event) {
|
socket.onmessage = function(event) {
|
||||||
|
@ -2648,7 +2650,8 @@
|
||||||
console.log(`Data received from server:`, data);
|
console.log(`Data received from server:`, data);
|
||||||
|
|
||||||
if (data.type === 'heartbeat') {
|
if (data.type === 'heartbeat') {
|
||||||
sendWebSocketMessage('heartbeat', {});
|
// Reset heartbeat timeout on receiving heartbeat response
|
||||||
|
resetHeartbeatTimeout();
|
||||||
} else if (data.type === 'model_download_progress') {
|
} else if (data.type === 'model_download_progress') {
|
||||||
updateModelDownloadProgress(data.data);
|
updateModelDownloadProgress(data.data);
|
||||||
} else if (data.type === 'status_update') {
|
} else if (data.type === 'status_update') {
|
||||||
|
@ -2675,14 +2678,70 @@
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
let heartbeatInterval;
|
||||||
|
let heartbeatTimeout;
|
||||||
|
|
||||||
|
function startHeartbeat() {
|
||||||
|
// Clear any existing intervals
|
||||||
|
if (heartbeatInterval) {
|
||||||
|
clearInterval(heartbeatInterval);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Send heartbeat every 60 seconds
|
||||||
|
heartbeatInterval = setInterval(() => {
|
||||||
|
if (socket.readyState === WebSocket.OPEN) {
|
||||||
|
socket.send(JSON.stringify({ type: 'heartbeat' }));
|
||||||
|
// Set timeout to reconnect if no response within 10 seconds
|
||||||
|
setHeartbeatTimeout();
|
||||||
|
}
|
||||||
|
}, 60000);
|
||||||
|
}
|
||||||
|
|
||||||
|
function setHeartbeatTimeout() {
|
||||||
|
if (heartbeatTimeout) {
|
||||||
|
clearTimeout(heartbeatTimeout);
|
||||||
|
}
|
||||||
|
heartbeatTimeout = setTimeout(() => {
|
||||||
|
console.log("Heartbeat timeout - attempting reconnect...");
|
||||||
|
if (socket) {
|
||||||
|
socket.close();
|
||||||
|
}
|
||||||
|
handleReconnect();
|
||||||
|
}, 65000); // Increased timeout to 65 seconds
|
||||||
|
}
|
||||||
|
|
||||||
|
function resetHeartbeatTimeout() {
|
||||||
|
if (heartbeatTimeout) {
|
||||||
|
clearTimeout(heartbeatTimeout);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Clean up on page unload
|
||||||
|
window.addEventListener('beforeunload', () => {
|
||||||
|
if (heartbeatInterval) {
|
||||||
|
clearInterval(heartbeatInterval);
|
||||||
|
}
|
||||||
|
if (heartbeatTimeout) {
|
||||||
|
clearTimeout(heartbeatTimeout);
|
||||||
|
}
|
||||||
|
if (socket) {
|
||||||
|
socket.close();
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
function handleReconnect() {
|
function handleReconnect() {
|
||||||
if (reconnectAttempts < maxReconnectAttempts) {
|
if (reconnectAttempts < maxReconnectAttempts) {
|
||||||
reconnectAttempts++;
|
reconnectAttempts++;
|
||||||
document.getElementById('loadingOverlay').style.display = 'flex';
|
document.getElementById('loadingOverlay').style.display = 'flex';
|
||||||
document.getElementById('loadingMessage').textContent = `WebSocket disconnected. Attempting to reconnect (${reconnectAttempts}/${maxReconnectAttempts})...`;
|
document.getElementById('loadingMessage').textContent =
|
||||||
setTimeout(connectWebSocket, reconnectInterval);
|
`WebSocket disconnected. Attempting to reconnect (${reconnectAttempts}/${maxReconnectAttempts})...`;
|
||||||
|
|
||||||
|
// Add exponential backoff
|
||||||
|
const backoffTime = Math.min(1000 * Math.pow(2, reconnectAttempts), 30000);
|
||||||
|
setTimeout(connectWebSocket, backoffTime);
|
||||||
} else {
|
} else {
|
||||||
document.getElementById('loadingMessage').textContent = 'Failed to connect to WebSocket. Please refresh the page or contact support.';
|
document.getElementById('loadingMessage').textContent =
|
||||||
|
'Failed to connect to WebSocket. Installation continues in background. Please refresh page to see status.';
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -2873,9 +2932,14 @@
|
||||||
setInterval(updateStatus, 5000);
|
setInterval(updateStatus, 5000);
|
||||||
setInterval(updateLogs, 1000);
|
setInterval(updateLogs, 1000);
|
||||||
|
|
||||||
|
// Initialize model types
|
||||||
|
refreshModelTypes();
|
||||||
|
}
|
||||||
|
|
||||||
|
async function refreshModelTypes() {
|
||||||
var data = {};
|
var data = {};
|
||||||
data.cmd = 'refreshModelTypes';
|
data.cmd = 'refreshModelTypes';
|
||||||
extendUIHelper(data); // lutzapps - initialize the available SHARED_MODEL_FOLDERS for the "Model Downloader" modelType select list
|
await extendUIHelper(data); // lutzapps - initialize the available SHARED_MODEL_FOLDERS for the "Model Downloader" modelType select list
|
||||||
}
|
}
|
||||||
|
|
||||||
// lutzapps - populate modeltype select options from shared_models
|
// lutzapps - populate modeltype select options from shared_models
|
||||||
|
@ -2933,53 +2997,49 @@
|
||||||
case "refreshModelTypes":
|
case "refreshModelTypes":
|
||||||
// refresh and optionally select the 'modelType' list for "Model Downloader"
|
// refresh and optionally select the 'modelType' list for "Model Downloader"
|
||||||
var modelTypeSelect = document.getElementById('modelType');
|
var modelTypeSelect = document.getElementById('modelType');
|
||||||
|
if (!modelTypeSelect) {
|
||||||
|
console.error('Model type select element not found');
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
try {
|
||||||
// get the data from the Server
|
// get the data from the Server
|
||||||
response = await fetch('/get_model_types');
|
response = await fetch('/get_model_types');
|
||||||
result = await response.json();
|
result = await response.json();
|
||||||
|
|
||||||
//alert(JSON.stringify(result)); // show the JSON-String
|
|
||||||
var model_types = result; // get the JSON-Object
|
var model_types = result; // get the JSON-Object
|
||||||
var count = Object.keys(model_types).length; // count=18, when using the default SHARED_MODEL_FOLDERS dict
|
var count = Object.keys(model_types).length;
|
||||||
|
|
||||||
// the "/get_model_types" app.get_model_types_route() function checks
|
|
||||||
// if the SHARED_MODELS_DIR shared files already exists at the "/workspace" location.
|
|
||||||
// that only happens AFTER the the user clicked the "Create Shared Folders" button
|
|
||||||
// on the "Settings" Tab of the app's WebUI.
|
|
||||||
// it will return an empty model_types_dict, so the "Download Manager" does NOT get
|
|
||||||
// the already in-memory SHARED_MODEL_FOLDERS code-generated default dict
|
|
||||||
// BEFORE the workspace folders in SHARED_MODELS_DIR exists!
|
|
||||||
//
|
|
||||||
// when SHARED_MODELS_DIR exists (or updates), this function will be called via a Socket Message
|
|
||||||
// to "refresh" its content automatically
|
|
||||||
|
|
||||||
var modelTypeSelected = modelTypeSelect.value; // remember the current selected modelType.option value
|
var modelTypeSelected = modelTypeSelect.value; // remember the current selected modelType.option value
|
||||||
modelTypeSelect.options.length = 0; // clear all current modelTypeSelect options
|
modelTypeSelect.options.length = 0; // clear all current modelTypeSelect options
|
||||||
|
|
||||||
for (i = 0 ; i < count; i += 1) {
|
if (count === 0) {
|
||||||
modelTypeOption = document.createElement('option');
|
// Add a default option if no model types are available
|
||||||
|
const defaultOption = document.createElement('option');
|
||||||
|
defaultOption.text = 'Please create shared folders first';
|
||||||
|
defaultOption.value = '';
|
||||||
|
modelTypeSelect.add(defaultOption);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
for (i = 0; i < count; i++) {
|
||||||
|
modelTypeOption = document.createElement('option');
|
||||||
modelType = model_types[String(i)]['modelfolder'];
|
modelType = model_types[String(i)]['modelfolder'];
|
||||||
modelTypeOption.setAttribute('value', modelType);
|
modelTypeOption.setAttribute('value', modelType);
|
||||||
modelTypeOption.appendChild(document.createTextNode(model_types[String(i)]['desc']));
|
modelTypeOption.appendChild(document.createTextNode(model_types[String(i)]['desc']));
|
||||||
//if (modelFolder === modelTypeSelected) {
|
|
||||||
// modelTypeOption.selected = true; // reselect it
|
|
||||||
//}
|
|
||||||
|
|
||||||
modelTypeSelect.appendChild(modelTypeOption);
|
modelTypeSelect.appendChild(modelTypeOption);
|
||||||
}
|
}
|
||||||
|
|
||||||
//modelTypeSelect.selectedIndex = modelfolder_index; // set the selected index
|
if (modelTypeSelected === "") {
|
||||||
//modelTypeSelect.options[mmodelfolder_index].selected = true; // and mark it as "selected" option
|
modelTypeSelect.selectedIndex = 0;
|
||||||
if (modelTypeSelected === "") { // initial refresh, called by initializeUI() function
|
MODELTYPE_SELECTED = modelTypeSelect.options[0].value;
|
||||||
modelTypeSelect.selectedIndex = 0; // use the first modelType option, usually "ckpt"
|
} else {
|
||||||
MODELTYPE_SELECTED = modelTypeSelect.options[0].value; // NOT handled by the onchange() event handler
|
modelTypeSelect.value = modelTypeSelected;
|
||||||
|
MODELTYPE_SELECTED = modelTypeSelected;
|
||||||
}
|
}
|
||||||
else {
|
} catch (error) {
|
||||||
modelTypeSelect.value = modelTypeSelected; // (re-)apply the selected modelType option
|
console.error('Error refreshing model types:', error);
|
||||||
MODELTYPE_SELECTED = modelTypeSelected; // NOT handled by the onchange() event handler
|
|
||||||
}
|
}
|
||||||
|
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case "selectModelType":
|
case "selectModelType":
|
||||||
|
@ -3074,7 +3134,7 @@
|
||||||
progressBar.style.width = '100%';
|
progressBar.style.width = '100%';
|
||||||
progressBar.textContent = '100%';
|
progressBar.textContent = '100%';
|
||||||
await loadModelFolders();
|
await loadModelFolders();
|
||||||
showRecreateSymlinksButton();
|
// Remove showRecreateSymlinksButton call since it's automatic now
|
||||||
} else if (result.status === 'choice_required') {
|
} else if (result.status === 'choice_required') {
|
||||||
if (result.data.type === 'file') {
|
if (result.data.type === 'file') {
|
||||||
showFileChoiceDialog(result.data, url, modelName, modelType, civitaiToken, hfToken);
|
showFileChoiceDialog(result.data, url, modelName, modelType, civitaiToken, hfToken);
|
||||||
|
@ -3175,31 +3235,6 @@
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
function showRecreateSymlinksButton() {
|
|
||||||
const buttonContainer = document.getElementById('recreate-symlinks-container');
|
|
||||||
buttonContainer.innerHTML = `
|
|
||||||
<button onclick="recreateSymlinks()" class="settings-button">Recreate Symlinks</button>
|
|
||||||
<p id="symlink-status"></p>
|
|
||||||
`;
|
|
||||||
buttonContainer.style.display = 'block';
|
|
||||||
}
|
|
||||||
|
|
||||||
async function recreateSymlinks() {
|
|
||||||
const statusElement = document.getElementById('symlink-status');
|
|
||||||
statusElement.textContent = 'Recreating symlinks...';
|
|
||||||
try {
|
|
||||||
const response = await fetch('/recreate_symlinks', { method: 'POST' });
|
|
||||||
const data = await response.json();
|
|
||||||
if (data.status === 'success') {
|
|
||||||
statusElement.textContent = data.message;
|
|
||||||
} else {
|
|
||||||
statusElement.textContent = 'Error: ' + data.message;
|
|
||||||
}
|
|
||||||
} catch (error) {
|
|
||||||
statusElement.textContent = 'Error: ' + error.message;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
async function saveCivitaiToken() {
|
async function saveCivitaiToken() {
|
||||||
const token = document.getElementById('civitaiTokenSave').value;
|
const token = document.getElementById('civitaiTokenSave').value;
|
||||||
try {
|
try {
|
||||||
|
@ -3315,12 +3350,10 @@
|
||||||
|
|
||||||
// Call this function when the Models tab is opened
|
// Call this function when the Models tab is opened
|
||||||
document.querySelector('.navbar-tabs a[onclick="openTab(event, \'models-tab\')"]').addEventListener('click', function() {
|
document.querySelector('.navbar-tabs a[onclick="openTab(event, \'models-tab\')"]').addEventListener('click', function() {
|
||||||
//alert("querySelector");
|
loadModelFolders();
|
||||||
loadModelFolders(); // lutzapps - this ModelFolders is NOT for the 'modelType' "select dropdown" model list
|
refreshModelTypes(); // Refresh model types when switching to Models tab
|
||||||
extendUIHelper(); // lutzapps - select the last know MODELTYPE_SELECTED in the WebUI Dom Id 'modelType' "select dropdown" model list
|
|
||||||
loadCivitaiToken();
|
loadCivitaiToken();
|
||||||
loadHFToken(); // lutzapps - added HF_TOKEN ENV var Support
|
loadHFToken();
|
||||||
|
|
||||||
updateExampleUrls();
|
updateExampleUrls();
|
||||||
});
|
});
|
||||||
|
|
||||||
|
@ -3467,27 +3500,26 @@
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
async function updateFileBrowserStatus() {
|
function updateFileBrowserStatus() {
|
||||||
try {
|
fetch('/filebrowser_status')
|
||||||
const response = await fetch('/filebrowser_status');
|
.then(response => response.json())
|
||||||
const result = await response.json();
|
.then(data => {
|
||||||
const statusElement = document.getElementById('filebrowser-status');
|
const statusElement = document.getElementById('filebrowser-status');
|
||||||
if (statusElement) {
|
if (statusElement) {
|
||||||
statusElement.textContent = result.status;
|
statusElement.textContent = data.status;
|
||||||
}
|
}
|
||||||
const startButton = document.getElementById('start-filebrowser');
|
const startButton = document.getElementById('start-filebrowser');
|
||||||
const stopButton = document.getElementById('stop-filebrowser');
|
const stopButton = document.getElementById('stop-filebrowser');
|
||||||
if (startButton && stopButton) {
|
if (startButton && stopButton) {
|
||||||
startButton.disabled = (result.status === 'running');
|
startButton.disabled = (data.status === 'running');
|
||||||
stopButton.disabled = (result.status === 'stopped');
|
stopButton.disabled = (data.status === 'stopped');
|
||||||
}
|
|
||||||
} catch (error) {
|
|
||||||
console.error('Error updating File Browser status:', error);
|
|
||||||
}
|
}
|
||||||
|
})
|
||||||
|
.catch(error => console.error('Error updating File Browser status:', error));
|
||||||
}
|
}
|
||||||
|
|
||||||
// Call this function periodically to update the status
|
// Reduce the frequency of status updates
|
||||||
setInterval(updateFileBrowserStatus, 5000);
|
setInterval(updateFileBrowserStatus, 30000); // Check every 30 seconds instead of 5 seconds
|
||||||
|
|
||||||
// Update the DOMContentLoaded event listener
|
// Update the DOMContentLoaded event listener
|
||||||
document.addEventListener('DOMContentLoaded', function() {
|
document.addEventListener('DOMContentLoaded', function() {
|
||||||
|
@ -3542,7 +3574,8 @@
|
||||||
console.log("WebSocket message received:", data);
|
console.log("WebSocket message received:", data);
|
||||||
|
|
||||||
if (data.type === 'heartbeat') {
|
if (data.type === 'heartbeat') {
|
||||||
sendWebSocketMessage('heartbeat', {});
|
// Reset heartbeat timeout on receiving heartbeat response
|
||||||
|
resetHeartbeatTimeout();
|
||||||
} else if (data.type === 'install_progress') {
|
} else if (data.type === 'install_progress') {
|
||||||
updateInstallProgress(data.data);
|
updateInstallProgress(data.data);
|
||||||
} else if (data.type === 'install_log') {
|
} else if (data.type === 'install_log') {
|
||||||
|
|
|
@ -699,39 +699,12 @@ def download_and_unpack_venv_v2(app_name:str, app_configs:dict, send_websocket_m
|
||||||
return False, error_message
|
return False, error_message
|
||||||
|
|
||||||
send_websocket_message('install_progress', {'app_name': app_name, 'percentage': 100, 'stage': 'Unpacking Complete'})
|
send_websocket_message('install_progress', {'app_name': app_name, 'percentage': 100, 'stage': 'Unpacking Complete'})
|
||||||
|
send_websocket_message('install_log', {'app_name': app_name, 'log': 'Unpacking complete. Proceeding to clone repository...'})
|
||||||
|
|
||||||
### installing the App from GITHUB
|
# Clone the repository
|
||||||
# Clone the repository if it doesn't exist
|
success, message = clone_application(app_config, send_websocket_message)
|
||||||
success, message = clone_application(app_name)
|
if not success:
|
||||||
|
return False, message
|
||||||
print(f"'DEBUG_SETTINGS' after this run:\n{pretty_dict(DEBUG_SETTINGS)}")
|
|
||||||
|
|
||||||
### original "v1" code (very slow code because of STATISTICS glory
|
|
||||||
|
|
||||||
# unpack_command = f"tar -xzvf {downloaded_file} -C {venv_path}"
|
|
||||||
# process = subprocess.Popen(unpack_command, shell=True, stdout=subprocess.PIPE, stderr=subprocess.STDOUT, universal_newlines=True)
|
|
||||||
|
|
||||||
# total_files = sum(1 for _ in subprocess.Popen(f"tar -tvf {downloaded_file}", shell=True, stdout=subprocess.PIPE).stdout)
|
|
||||||
# files_processed = 0
|
|
||||||
|
|
||||||
# for line in process.stdout:
|
|
||||||
# files_processed += 1
|
|
||||||
# percentage = min(int((files_processed / total_files) * 100), 100)
|
|
||||||
# send_websocket_message('install_progress', {
|
|
||||||
# 'app_name': app_name,
|
|
||||||
# 'percentage': percentage,
|
|
||||||
# 'stage': 'Unpacking',
|
|
||||||
# 'processed': files_processed,
|
|
||||||
# 'total': total_files
|
|
||||||
# })
|
|
||||||
# send_websocket_message('install_log', {'app_name': app_name, 'log': f"Unpacking: {line.strip()}"})
|
|
||||||
|
|
||||||
# process.wait()
|
|
||||||
# rc = process.returncode
|
|
||||||
|
|
||||||
### installing the App from GITHUB
|
|
||||||
# Clone the repository if it doesn't exist
|
|
||||||
success, error_message = clone_application(app_name, send_websocket_message)
|
|
||||||
|
|
||||||
# Clean up the downloaded file
|
# Clean up the downloaded file
|
||||||
send_websocket_message('install_log', {'app_name': app_name, 'log': 'Cleaning up...'})
|
send_websocket_message('install_log', {'app_name': app_name, 'log': 'Cleaning up...'})
|
||||||
|
@ -742,19 +715,10 @@ def download_and_unpack_venv_v2(app_name:str, app_configs:dict, send_websocket_m
|
||||||
os.remove(downloaded_file)
|
os.remove(downloaded_file)
|
||||||
|
|
||||||
send_websocket_message('install_log', {'app_name': app_name, 'log': 'Installation complete. Refresh page to start app'})
|
send_websocket_message('install_log', {'app_name': app_name, 'log': 'Installation complete. Refresh page to start app'})
|
||||||
|
|
||||||
if success:
|
|
||||||
save_install_status(app_name, 'completed', 100, 'Completed')
|
save_install_status(app_name, 'completed', 100, 'Completed')
|
||||||
send_websocket_message('install_complete', {'app_name': app_name, 'status': 'success', 'message': "Virtual environment installed successfully."})
|
send_websocket_message('install_complete', {'app_name': app_name, 'status': 'success', 'message': "Virtual environment installed successfully."})
|
||||||
return True, "Virtual environment installed successfully."
|
return True, "Virtual environment installed successfully."
|
||||||
else:
|
|
||||||
return False, error_message
|
|
||||||
|
|
||||||
except requests.RequestException as e:
|
|
||||||
error_message = f"Download/Decompression failed: {str(e)}"
|
|
||||||
send_websocket_message('install_complete', {'app_name': app_name, 'status': 'error', 'message': error_message})
|
|
||||||
save_install_status(app_name, 'failed', 0, 'Failed')
|
|
||||||
return False, error_message
|
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
error_message = f"Installation failed: {str(e)}\n{traceback.format_exc()}"
|
error_message = f"Installation failed: {str(e)}\n{traceback.format_exc()}"
|
||||||
save_install_status(app_name, 'failed', 0, 'Failed')
|
save_install_status(app_name, 'failed', 0, 'Failed')
|
||||||
|
|
|
@ -1,5 +1,7 @@
|
||||||
import subprocess
|
import subprocess
|
||||||
import time
|
import time
|
||||||
|
import requests
|
||||||
|
from requests.exceptions import Timeout
|
||||||
|
|
||||||
FILEBROWSER_PORT = 8181
|
FILEBROWSER_PORT = 8181
|
||||||
filebrowser_process = None
|
filebrowser_process = None
|
||||||
|
@ -35,4 +37,10 @@ def stop_filebrowser():
|
||||||
return False
|
return False
|
||||||
|
|
||||||
def get_filebrowser_status():
|
def get_filebrowser_status():
|
||||||
return 'running' if filebrowser_process and filebrowser_process.poll() is None else 'stopped'
|
try:
|
||||||
|
response = requests.get('http://localhost:7222/fileapp/', timeout=5)
|
||||||
|
return 'running' if response.status_code == 200 else 'stopped'
|
||||||
|
except Timeout:
|
||||||
|
return 'timeout'
|
||||||
|
except Exception:
|
||||||
|
return 'unknown'
|
||||||
|
|
Loading…
Reference in a new issue