Created
June 27, 2024 17:31
-
-
Save samuelint/6f7c55f0d86f9968c051b4fdd470a060 to your computer and use it in GitHub Desktop.
Tauri Sidecar Lifecycle & Forward stderr
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
// Prevents additional console window on Windows in release, DO NOT REMOVE!! | |
#![cfg_attr(not(debug_assertions), windows_subsystem = "windows")] | |
pub mod sidecar_lifecycle_service; | |
use std::sync::Mutex; | |
use tauri_plugin_log::LogTarget; | |
use tauri::{Manager, State, WindowEvent}; | |
use sidecar_lifecycle_service::SidecarLifeCycleService; | |
struct AppState { | |
code_sidecar_mutex: Mutex<SidecarLifeCycleService>, | |
} | |
#[tauri::command] | |
fn start_server(api_manager_state: State<AppState>) -> Result<String, String> { | |
let am = api_manager_state | |
.code_sidecar_mutex | |
.lock() | |
.unwrap() | |
.start(); | |
am | |
} | |
#[tauri::command] | |
fn stop_server(api_manager_state: State<AppState>) -> Result<String, String> { | |
let app_state = api_manager_state | |
.code_sidecar_mutex | |
.lock() | |
.unwrap() | |
.stop(); | |
app_state | |
} | |
fn main() { | |
let core_sidecar = SidecarLifeCycleService::new("core"); | |
let state = AppState { | |
code_sidecar_mutex: Mutex::new(core_sidecar), | |
}; | |
let log_builder = tauri_plugin_log::Builder::default().targets([ | |
LogTarget::LogDir, | |
LogTarget::Stdout, | |
LogTarget::Stderr, | |
LogTarget::Webview, | |
]); | |
tauri::Builder::default() | |
.manage(state) | |
.plugin(log_builder.build()) | |
.setup(move |app| { | |
let app_state: State<AppState> = app.state(); | |
app_state.code_sidecar_mutex | |
.lock() | |
.unwrap() | |
.start() | |
.expect("Core Sidecar start failed"); | |
Ok(()) | |
}) | |
.on_window_event(move |event| match event.event() { | |
WindowEvent::Destroyed => { | |
let am: State<AppState> = event.window().state(); | |
am.code_sidecar_mutex | |
.lock() | |
.unwrap() | |
.stop() | |
.expect("Core Sidecar stop failed"); | |
} | |
_ => {} | |
}) | |
.invoke_handler(tauri::generate_handler![ | |
start_server, | |
stop_server, | |
]) | |
.run(tauri::generate_context!()) | |
.expect("[Error] while running tauri application"); | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
use std::borrow::BorrowMut; | |
use std::process::{Child, Command, Stdio}; | |
use command_group::{Signal, UnixChildExt}; | |
use tauri::api::process::Command as TCommand; | |
use log::{info, error}; | |
use std::io::{BufReader, BufRead}; | |
use std::thread; | |
fn log_child_stderr(mut child: Child) -> Child { | |
if let Some(stderr) = child.stderr.take() { | |
let stderr_reader = BufReader::new(stderr); | |
thread::spawn(move || { | |
for line in stderr_reader.lines() { | |
match line { | |
Ok(line) => error!("[sidecar | core]: {}", line.trim_end_matches('\n')), | |
Err(err) => error!("Error reading stderr: {}", err), | |
} | |
} | |
}); | |
} | |
child | |
} | |
pub struct SidecarLifeCycleService { | |
program: String, | |
sidecar_command: Command, | |
child: Option<Child>, | |
} | |
impl SidecarLifeCycleService { | |
pub fn new<S: Into<String>>(program: S) -> SidecarLifeCycleService { | |
let program_string = program.into(); | |
let sidecar_command = TCommand::new_sidecar(&program_string).expect("failed to setup sidecar"); | |
SidecarLifeCycleService { | |
program: program_string, | |
sidecar_command: sidecar_command.into(), | |
child: None, | |
} | |
} | |
pub fn start(&mut self) -> Result<String, String> { | |
match self.child.borrow_mut() { | |
Some(_) => { | |
let info = format!("Sidecar {} already running", self.program); | |
info!("{}", &info); | |
Ok(info.into()) | |
} | |
None => { | |
let child = self.sidecar_command.stderr(Stdio::piped()).spawn(); | |
match child { | |
Ok(mut child) => { | |
let id = child.id(); | |
child = log_child_stderr(child); | |
self.child = Some(child); | |
let info = format!("Sidecar {} started - {}", self.program, id); | |
info!("{}", &info); | |
Ok(info.into()) | |
} | |
Err(e) => { | |
let info = format!("Sidecar {} start failed - {}", self.program, e.to_string()); | |
error!("{}", &info); | |
Err(info.into()) | |
} | |
} | |
} | |
} | |
} | |
pub fn stop(&mut self) -> Result<String, String> { | |
match self.child.borrow_mut() { | |
Some(child) => { | |
let id = child.id(); | |
child | |
.signal(Signal::SIGTERM) | |
.expect("Some error happened when killing child process"); | |
self.child = None; | |
let info = format!("Sidecar {} stopped - {}", self.program, id); | |
info!("{}", &info); | |
Ok(info.into()) | |
} | |
_ => { | |
let info = format!("Sidecar {} stop failed", self.program); | |
println!("{}", &info); | |
Ok(info.into()) | |
} | |
} | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment