1

I am trying to run a streamlit server behind the scenes of a Tauri application.

The streamlit server is packaged with PyInstaller into a single binary file and works as expected when standalone.

I have a rust main.rs file that needs to run a streamlit binary using a Command (in this case its a tauri::api::process::Command using a new_sidecar).

It spawns the server, but when the app closes, my streamlit server is not disposed off.

On window exit, I want to send a kill command to kill the server instance in the child.

Here is an example of my code:

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

use async_std::task;
use std::sync::mpsc::sync_channel;
use std::thread;
use std::time::Duration;
use tauri::api::process::{Command, CommandEvent};
use tauri::{Manager, WindowEvent};


fn main() {
    let (tx_kill, rx_kill) = sync_channel(1);
    tauri::Builder::default()
        .setup(|app| {
            println!("App Setup Start");

            let t = Command::new_sidecar("streamlit").expect("failed to create sidecar");
            let (mut rx, child) = t.spawn().expect("Failed to spawn server");

            let splashscreen_window = app.get_window("splashscreen").unwrap();
            let main_window = app.get_window("main").unwrap();

            // Listen for server port then refresh main window
            tauri::async_runtime::spawn(async move {
                while let Some(event) = rx.recv().await {
                    if let CommandEvent::Stdout(output) = event {
                        if output.contains("Network URL:") {
                            let tokens: Vec<&str> = output.split(":").collect();
                            let port = tokens.last().unwrap();
                            println!("Connect to port {}", port);
                            main_window.eval(&format!(
                                "window.location.replace('http://localhost:{}')",
                                port
                            ));
                            task::sleep(Duration::from_secs(2)).await;
                            splashscreen_window.close().unwrap();
                            main_window.show().unwrap();
                        }
                    }
                }
            });

            // Listen for kill command
            thread::spawn(move || loop {
                let event = rx_kill.recv();
                if event.unwrap() == -1 {
                    child.kill().expect("Failed to close API");
                }
            });

            Ok(())
        })
        .on_window_event(move |event| match event.event() {
            WindowEvent::Destroyed => {
                println!("Window destroyed");
                tx_kill.send(-1).expect("Failed to send close signal");
            }
            _ => {}
        })
        .run(tauri::generate_context!())
        .expect("error while running application");
}

But I am getting an error, when I try to kill the child instance:

 thread::spawn(move || loop {
                let event = rx_kill.recv();
                if event.unwrap() == -1 {
                    child.kill().expect("Failed to close API");
                }
            });
use of moved value: `child`
move occurs because `child` has type `CommandChild`, which does not implement the `Copy` trait

Any ideas?

Giiyms
  • 73
  • 1
  • 8
  • Share the ownership, pick one of these [reference counted types](https://stackoverflow.com/questions/45674479/need-holistic-explanation-about-rusts-cell-and-reference-counted-types/45674912). – cafce25 Dec 21 '22 at 18:06

0 Answers0