Ocultar consola al ejecutar Django en Tauri

respondido por OpenAI o1 preview en OpenAI o1

Pregunta:

Es posible ocultar la ventana de la consola de comandos que ejecuta el código python, de manera que solamente se muestre la interfaz de tauri, siendo así, que el servidor de django se corra en segundo plano, de acuerdo a:

#![cfg_attr(not(debug_assertions), windows_subsystem = "windows")]

use std::process::{Command, Stdio}; use std::env; use std::path::{Path, PathBuf}; use std::sync::{Arc, Mutex, Once}; use tauri::Manager;

static INIT: Once = Once::new(); static mut APP_STATE: Option<Arc<Mutex<AppState>>> = None;

#[derive(Clone)] struct AppState { python_exe: PathBuf, app_dir: PathBuf, }

fn run_command(command: &str, args: &[&str]) -> Result<(), String> { println!("Ejecutando: {} {:?}", command, args); let output = Command::new(command) .args(args) .stdout(Stdio::inherit()) .stderr(Stdio::inherit()) .output() .map_err(|e| format!("Failed to execute command: {}", e))?; if !output.status.success() { return Err(format!("Command failed with exit code: {:?}", output.status.code())); } Ok(()) }

fn find_python_exe(venv_path: &Path) -> Result<PathBuf, String> { let python_exe = if cfg!(windows) { venv_path.join("Scripts").join("python.exe") } else { venv_path.join("bin").join("python") }; if !python_exe.exists() { return Err(format!("Python executable not found: {:?}", python_exe)); } Ok(python_exe) }

fn initialize() -> Result<(), String> { let current_dir = env::current_dir().map_err(|e| format!("Failed to get current directory: {}", e))?; let venv_path = current_dir.join("venv_postgreSQL");

if !venv_path.exists() {
    return Err(format!("El entorno virtual no existe en: {:?}", venv_path));
}

let python_exe = find_python_exe(&venv_path)?;
let app_dir = current_dir.join("mindfortune2");

if cfg!(windows) {
    let activate_script = venv_path.join("Scripts").join("activate.bat");
    if !activate_script.exists() {
        return Err(format!("Activation script not found: {:?}", activate_script));
    }
    run_command("cmd", &["/C", "call", activate_script.to_str().unwrap()])?;
}

env::set_current_dir(&app_dir).map_err(|e| format!("Failed to change directory: {}", e))?;

if !Path::new("manage.py").exists() {
    return Err("Error: No se encuentra el archivo manage.py en el directorio actual.".to_string());
}

unsafe {
    APP_STATE = Some(Arc::new(Mutex::new(AppState {
        python_exe,
        app_dir,
    })));
}

Ok(())

}

#[tauri::command] fn run_django_server() -> Result<(), String> { INIT.call_once(|| { if let Err(e) = initialize() { eprintln!("Initialization error: {}", e); } });

let state = unsafe { 
    APP_STATE.as_ref()
        .ok_or("App state not initialized")?
        .lock()
        .map_err(|_| "Failed to lock app state")?
        .clone()
};

std::thread::spawn(move || {
    println!("Intentando ejecutar el servidor Django...");
    if let Err(e) = run_command(state.python_exe.to_str().unwrap(), &["manage.py", "runserver"]) {
        eprintln!("Error al ejecutar el servidor Django: {}", e);
    }
});

Ok(())

}

#[tauri::command] fn stop_django_server() -> Result<(), String> { if cfg!(target_os = "windows") { Command::new("taskkill") .args(&["/F", "/IM", "python.exe"]) .spawn() .map_err(|e| e.to_string())?; } else { Command::new("pkill") .arg("python") .spawn() .map_err(|e| e.to_string())?; }

Ok(())

}

fn main() { tauri::Builder::default() .setup(|mindfortune2| { let window = mindfortune2.get_webview_window("main").unwrap(); window.set_title("MindFortune3").unwrap(); Ok(()) }) .invoke_handler(tauri::generate_handler![run_django_server, stop_django_server]) .run(tauri::generate_context!()) .expect("error while running tauri application"); }

?

Respuesta:

Para ocultar la ventana de la consola de comandos al ejecutar un servidor Django en segundo plano desde una aplicación Tauri, puedes hacer algunos ajustes en tu código. En particular, debes asegurarte de que la salida estándar y de error del proceso que ejecuta el servidor Django no se dirija a la consola, sino que se maneje de otra manera.

Aquí hay algunos pasos que puedes seguir para lograr esto:

  1. Modificar la función run_command: Cambia la forma en que se manejan las salidas estándar y de error. En lugar de usar Stdio::inherit(), puedes redirigir la salida a Stdio::null(), lo que significa que no se mostrará en la consola.

  2. Asegurarte de que la aplicación Tauri esté configurada para no mostrar la consola: Ya tienes la línea #![cfg_attr(not(debug_assertions), windows_subsystem = "windows")], que es correcta para ocultar la consola en Windows cuando no estás en modo de depuración.

Aquí tienes el código modificado para la función run_command:

fn run_command(command: &str, args: &[&str]) -> Result<(), String> {
    println!("Ejecutando: {} {:?}", command, args);
    let output = Command::new(command)
        .args(args)
        .stdout(Stdio::null()) // Redirigir la salida estándar a null
        .stderr(Stdio::null()) // Redirigir la salida de error a null
        .output()
        .map_err(|e| format!("Failed to execute command: {}", e))?;
    if !output.status.success() {
        return Err(format!("Command failed with exit code: {:?}", output.status.code()));
    }
    Ok(())
}

Con estos cambios, cuando llames a run_django_server, el servidor Django se ejecutará en segundo plano sin mostrar la ventana de la consola.

Consideraciones adicionales

  • Manejo de errores: Dado que no verás la salida de error en la consola, asegúrate de tener un buen manejo de errores en tu aplicación para que puedas capturar y manejar cualquier problema que surja al ejecutar el servidor Django.

  • Depuración: Durante el desarrollo, puede ser útil mantener la salida en la consola. Puedes agregar una opción de configuración para habilitar o deshabilitar la salida de la consola según sea necesario.

  • Pruebas: Asegúrate de probar tu aplicación en diferentes entornos (Windows, Linux, etc.) para verificar que el comportamiento sea el esperado.

Con estos ajustes, deberías poder ejecutar tu servidor Django en segundo plano sin que se muestre la ventana de la consola.