@@ -25,6 +25,28 @@ fn find_child_process_pids() -> Vec<String> {
2525 child_process_pids
2626}
2727
28+ /// Resolve the path to the syft-space-backend executable.
29+ /// In debug builds, SYFT_BACKEND_PATH env var can override the path.
30+ fn resolve_backend_path ( app : & tauri:: App ) -> std:: path:: PathBuf {
31+ if cfg ! ( debug_assertions) {
32+ if let Ok ( override_path) = std:: env:: var ( "SYFT_BACKEND_PATH" ) {
33+ return std:: path:: PathBuf :: from ( override_path) ;
34+ }
35+ }
36+
37+ let exe_name = if cfg ! ( windows) {
38+ "syft-space-backend.exe"
39+ } else {
40+ "syft-space-backend"
41+ } ;
42+
43+ app. path ( )
44+ . resource_dir ( )
45+ . expect ( "failed to resolve resource directory" )
46+ . join ( "syft-space-backend" )
47+ . join ( exe_name)
48+ }
49+
2850#[ cfg_attr( mobile, tauri:: mobile_entry_point) ]
2951pub fn run ( ) {
3052 tauri:: Builder :: default ( )
@@ -80,15 +102,33 @@ pub fn run() {
80102 let ( host, port, token) = utils:: generate_server_args ( ) ;
81103 log:: info!( "Server args - host: {}, port: {}" , host, port) ;
82104
83- // Spawn the Python backend sidecar with connection params
84- let sidecar = app
85- . shell ( )
86- . sidecar ( "syft-space-backend" )
87- . unwrap ( )
105+ // Resolve the backend executable path from resources
106+ let backend_path = resolve_backend_path ( app) ;
107+ log:: info!( "Backend path: {:?}" , backend_path) ;
108+
109+ // Ensure the backend binary is executable on Unix
110+ #[ cfg( unix) ]
111+ {
112+ use std:: os:: unix:: fs:: PermissionsExt ;
113+ if let Ok ( metadata) = std:: fs:: metadata ( & backend_path) {
114+ let mut perms = metadata. permissions ( ) ;
115+ let mode = perms. mode ( ) ;
116+ if mode & 0o111 == 0 {
117+ perms. set_mode ( mode | 0o755 ) ;
118+ let _ = std:: fs:: set_permissions ( & backend_path, perms) ;
119+ }
120+ }
121+ }
122+
123+ // Spawn the Python backend using std::process::Command
124+ let mut child = std:: process:: Command :: new ( & backend_path)
88125 . env ( "SYFT_HOST" , & host)
89126 . env ( "SYFT_PORT" , & port)
90- . env ( "SYFT_ADMIN_API_KEY" , & token) ;
91- let ( mut rx, _child) = sidecar. spawn ( ) . expect ( "failed to spawn sidecar" ) ;
127+ . env ( "SYFT_ADMIN_API_KEY" , & token)
128+ . stdout ( std:: process:: Stdio :: piped ( ) )
129+ . stderr ( std:: process:: Stdio :: piped ( ) )
130+ . spawn ( )
131+ . expect ( "failed to spawn backend process" ) ;
92132
93133 // Create main window with connection params in URL
94134 let url = utils:: generate_main_url ( & host, & port, & token) ;
@@ -147,39 +187,65 @@ pub fn run() {
147187 if let Some ( parent) = log_path. parent ( ) {
148188 std:: fs:: create_dir_all ( parent) . ok ( ) ;
149189 }
150- tauri:: async_runtime:: spawn ( async move {
151- use std:: io:: Write ;
152- use tauri_plugin_shell:: process:: CommandEvent ;
190+
191+ // Spawn stdout reader thread
192+ let stdout = child. stdout . take ( ) . expect ( "failed to take stdout" ) ;
193+ let stdout_log_path = log_path. clone ( ) ;
194+ std:: thread:: spawn ( move || {
195+ use std:: io:: { BufRead , BufReader , Write } ;
153196
154197 let mut log_file = std:: fs:: OpenOptions :: new ( )
155198 . create ( true )
156199 . append ( true )
157- . open ( & log_path )
200+ . open ( & stdout_log_path )
158201 . expect ( "failed to open syft-space-backend log file" ) ;
159202
160- while let Some ( event) = rx. recv ( ) . await {
161- match event {
162- CommandEvent :: Stdout ( line) => {
163- let msg = String :: from_utf8_lossy ( & line) ;
164- log:: info!( "[backend] {}" , msg) ;
165- let _ = writeln ! ( log_file, "{}" , msg) ;
166- }
167- CommandEvent :: Stderr ( line) => {
168- let msg = String :: from_utf8_lossy ( & line) ;
169- log:: error!( "[backend] {}" , msg) ;
170- let _ = writeln ! ( log_file, "{}" , msg) ;
203+ let reader = BufReader :: new ( stdout) ;
204+ for line in reader. lines ( ) {
205+ match line {
206+ Ok ( line) => {
207+ log:: info!( "[backend] {}" , line) ;
208+ let _ = writeln ! ( log_file, "{}" , line) ;
171209 }
172- CommandEvent :: Terminated ( status) => {
173- let msg = format ! ( "terminated with {:?}" , status) ;
174- log:: warn!( "[backend] {}" , msg) ;
175- let _ = writeln ! ( log_file, "{}" , msg) ;
176- break ;
210+ Err ( _) => break ,
211+ }
212+ }
213+ } ) ;
214+
215+ // Spawn stderr reader thread
216+ let stderr = child. stderr . take ( ) . expect ( "failed to take stderr" ) ;
217+ let stderr_log_path = log_path. clone ( ) ;
218+ std:: thread:: spawn ( move || {
219+ use std:: io:: { BufRead , BufReader , Write } ;
220+
221+ let mut log_file = std:: fs:: OpenOptions :: new ( )
222+ . create ( true )
223+ . append ( true )
224+ . open ( & stderr_log_path)
225+ . expect ( "failed to open syft-space-backend log file" ) ;
226+
227+ let reader = BufReader :: new ( stderr) ;
228+ for line in reader. lines ( ) {
229+ match line {
230+ Ok ( line) => {
231+ log:: error!( "[backend] {}" , line) ;
232+ let _ = writeln ! ( log_file, "{}" , line) ;
177233 }
178- _ => { }
234+ Err ( _ ) => break ,
179235 }
180236 }
181237 } ) ;
182238
239+ // Spawn thread to wait for the backend process to exit and log the status
240+ std:: thread:: spawn ( move || match child. wait ( ) {
241+ Ok ( status) => {
242+ log:: warn!( "[backend] terminated with status: {:?}" , status) ;
243+ }
244+ Err ( e) => {
245+ log:: error!( "[backend] error waiting for process: {:?}" , e) ;
246+ }
247+ } ) ;
248+
183249 // Start periodic update checks
184250 updates:: _start_periodic_update_checks ( app. handle ( ) ) ;
185251
0 commit comments