1+ use std:: net:: TcpListener ;
12use std:: sync:: { Arc , Mutex } ;
23use tauri:: Manager ;
4+ use tauri_plugin_dialog:: {
5+ DialogExt , MessageDialogBuilder , MessageDialogButtons , MessageDialogKind ,
6+ } ;
37use tauri_plugin_log:: { Target , TargetKind } ;
48use tauri_plugin_shell:: { process:: CommandChild , ShellExt } ;
59
10+ const GPTME_SERVER_PORT : u16 = 5700 ;
11+
612// Learn more about Tauri commands at https://tauri.app/develop/calling-rust/
713#[ tauri:: command]
814fn greet ( name : & str ) -> String {
915 format ! ( "Hello, {}! You've been greeted from Rust!" , name)
1016}
1117
18+ /// Check if a port is available
19+ fn is_port_available ( port : u16 ) -> bool {
20+ TcpListener :: bind ( format ! ( "127.0.0.1:{}" , port) ) . is_ok ( )
21+ }
22+
1223#[ cfg_attr( mobile, tauri:: mobile_entry_point) ]
1324pub fn run ( ) {
1425 tauri:: Builder :: default ( )
@@ -25,6 +36,7 @@ pub fn run() {
2536 )
2637 . plugin ( tauri_plugin_shell:: init ( ) )
2738 . plugin ( tauri_plugin_opener:: init ( ) )
39+ . plugin ( tauri_plugin_dialog:: init ( ) )
2840 . invoke_handler ( tauri:: generate_handler![ greet] )
2941 . setup ( |app| {
3042 log:: info!( "Starting gptme-tauri application" ) ;
@@ -37,14 +49,44 @@ pub fn run() {
3749
3850 // Spawn gptme-server with output capture
3951 tauri:: async_runtime:: spawn ( async move {
52+ // Check if port is available before starting
53+ if !is_port_available ( GPTME_SERVER_PORT ) {
54+ log:: error!(
55+ "Port {} is already in use. Another gptme-server instance may be running." ,
56+ GPTME_SERVER_PORT
57+ ) ;
58+
59+ // Show dialog to inform user about port conflict
60+ let message = format ! (
61+ "Cannot start gptme-server because port {} is already in use.\n \n \
62+ This usually means another gptme-server instance is already running.\n \n \
63+ Please stop the existing gptme-server process and restart this application.",
64+ GPTME_SERVER_PORT
65+ ) ;
66+
67+ MessageDialogBuilder :: new (
68+ app_handle. dialog ( ) . clone ( ) ,
69+ "Port Conflict" ,
70+ message
71+ )
72+ . kind ( MessageDialogKind :: Error )
73+ . buttons ( MessageDialogButtons :: Ok )
74+ . show ( |_result| {
75+ // Dialog closed, nothing to do
76+ } ) ;
77+
78+ return ;
79+ }
80+
4081 // Determine CORS origin based on build mode
4182 let cors_origin = if cfg ! ( debug_assertions) {
4283 "http://localhost:5701" // Dev mode
4384 } else {
4485 "tauri://localhost" // Production mode
4586 } ;
4687
47- log:: info!( "Starting gptme-server with CORS origin: {}" , cors_origin) ;
88+ log:: info!( "Port {} is available, starting gptme-server with CORS origin: {}" ,
89+ GPTME_SERVER_PORT , cors_origin) ;
4890
4991 let sidecar_command = app_handle
5092 . shell ( )
@@ -121,11 +163,22 @@ pub fn run() {
121163 let child_ref = window. state :: < Arc < Mutex < Option < CommandChild > > > > ( ) . clone ( ) ;
122164 if let Ok ( mut child) = child_ref. lock ( ) {
123165 if let Some ( process) = child. take ( ) {
166+ log:: info!( "Attempting to terminate gptme-server process..." ) ;
124167 match process. kill ( ) {
125- Ok ( _) => log:: info!( "gptme-server process terminated successfully" ) ,
126- Err ( e) => log:: error!( "Failed to terminate gptme-server: {}" , e) ,
168+ Ok ( _) => {
169+ log:: info!( "gptme-server process terminated successfully" ) ;
170+ // Give the process a moment to cleanup
171+ std:: thread:: sleep ( std:: time:: Duration :: from_millis ( 100 ) ) ;
172+ } ,
173+ Err ( e) => {
174+ log:: error!( "Failed to terminate gptme-server: {}" , e) ;
175+ }
127176 }
177+ } else {
178+ log:: warn!( "No gptme-server process found to terminate" ) ;
128179 }
180+ } else {
181+ log:: error!( "Failed to acquire lock on child process reference" ) ;
129182 } ;
130183 }
131184 }
0 commit comments