1
+ use std:: net:: TcpListener ;
1
2
use std:: sync:: { Arc , Mutex } ;
2
3
use tauri:: Manager ;
4
+ use tauri_plugin_dialog:: {
5
+ DialogExt , MessageDialogBuilder , MessageDialogButtons , MessageDialogKind ,
6
+ } ;
3
7
use tauri_plugin_log:: { Target , TargetKind } ;
4
8
use tauri_plugin_shell:: { process:: CommandChild , ShellExt } ;
5
9
10
+ const GPTME_SERVER_PORT : u16 = 5700 ;
11
+
6
12
// Learn more about Tauri commands at https://tauri.app/develop/calling-rust/
7
13
#[ tauri:: command]
8
14
fn greet ( name : & str ) -> String {
9
15
format ! ( "Hello, {}! You've been greeted from Rust!" , name)
10
16
}
11
17
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
+
12
23
#[ cfg_attr( mobile, tauri:: mobile_entry_point) ]
13
24
pub fn run ( ) {
14
25
tauri:: Builder :: default ( )
@@ -25,6 +36,7 @@ pub fn run() {
25
36
)
26
37
. plugin ( tauri_plugin_shell:: init ( ) )
27
38
. plugin ( tauri_plugin_opener:: init ( ) )
39
+ . plugin ( tauri_plugin_dialog:: init ( ) )
28
40
. invoke_handler ( tauri:: generate_handler![ greet] )
29
41
. setup ( |app| {
30
42
log:: info!( "Starting gptme-tauri application" ) ;
@@ -37,14 +49,44 @@ pub fn run() {
37
49
38
50
// Spawn gptme-server with output capture
39
51
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
+
40
81
// Determine CORS origin based on build mode
41
82
let cors_origin = if cfg ! ( debug_assertions) {
42
83
"http://localhost:5701" // Dev mode
43
84
} else {
44
85
"tauri://localhost" // Production mode
45
86
} ;
46
87
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) ;
48
90
49
91
let sidecar_command = app_handle
50
92
. shell ( )
@@ -121,11 +163,22 @@ pub fn run() {
121
163
let child_ref = window. state :: < Arc < Mutex < Option < CommandChild > > > > ( ) . clone ( ) ;
122
164
if let Ok ( mut child) = child_ref. lock ( ) {
123
165
if let Some ( process) = child. take ( ) {
166
+ log:: info!( "Attempting to terminate gptme-server process..." ) ;
124
167
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
+ }
127
176
}
177
+ } else {
178
+ log:: warn!( "No gptme-server process found to terminate" ) ;
128
179
}
180
+ } else {
181
+ log:: error!( "Failed to acquire lock on child process reference" ) ;
129
182
} ;
130
183
}
131
184
}
0 commit comments