@@ -6,6 +6,43 @@ use reqwest;
66
77use crate :: error:: { CommandError , CommandResult } ;
88
9+ #[ command]
10+ pub fn find_alternate_proxy_exe ( current_exe_path : String , target_version : String ) -> CommandResult < Option < String > > {
11+ let current = PathBuf :: from ( & current_exe_path) ;
12+ let parent = current. parent ( )
13+ . ok_or_else ( || CommandError :: General ( "Cannot determine parent directory" . to_string ( ) ) ) ?;
14+
15+ let is_target_plus = target_version == "plus" ;
16+
17+ if let Ok ( entries) = fs:: read_dir ( parent) {
18+ for entry in entries. flatten ( ) {
19+ let path = entry. path ( ) ;
20+ if !path. is_file ( ) { continue ; }
21+ let name = path. file_name ( ) . and_then ( |n| n. to_str ( ) ) . unwrap_or_default ( ) . to_lowercase ( ) ;
22+ let normalized = name. replace ( "-" , "" ) ;
23+
24+ if !normalized. starts_with ( "cliproxy" ) { continue ; }
25+
26+ #[ cfg( windows) ]
27+ if !name. ends_with ( ".exe" ) { continue ; }
28+ #[ cfg( not( windows) ) ]
29+ if name. ends_with ( ".dll" ) || name. ends_with ( ".dylib" ) { continue ; }
30+
31+ if path == current { continue ; }
32+
33+ let has_plus = name. contains ( "plus" ) ;
34+ if is_target_plus && has_plus {
35+ return Ok ( Some ( path. to_string_lossy ( ) . to_string ( ) ) ) ;
36+ }
37+ if !is_target_plus && !has_plus {
38+ return Ok ( Some ( path. to_string_lossy ( ) . to_string ( ) ) ) ;
39+ }
40+ }
41+ }
42+
43+ Ok ( None )
44+ }
45+
946#[ command]
1047pub async fn download_and_extract_proxy ( _app : AppHandle , url : String , target_dir : Option < String > ) -> CommandResult < String > {
1148 let proxy_dir = if let Some ( ref dir) = target_dir {
@@ -18,35 +55,25 @@ pub async fn download_and_extract_proxy(_app: AppHandle, url: String, target_dir
1855 d
1956 } ;
2057
21- let config_path = proxy_dir. join ( "config.yaml" ) ;
22- let config_backup = std:: env:: temp_dir ( ) . join ( "zerolimit_config_backup.yaml" ) ;
23- let had_config = if config_path. exists ( ) {
24- fs:: copy ( & config_path, & config_backup)
25- . map ( |_| true )
26- . unwrap_or_else ( |e| {
27- println ! ( "Warning: Could not back up config.yaml: {}" , e) ;
28- false
29- } )
30- } else {
31- false
58+ let config_extensions = [ "yaml" , "yml" , "json" , "toml" , "env" ] ;
59+ let is_config_file = |name : & str | -> bool {
60+ let lower = name. to_lowercase ( ) ;
61+ config_extensions. iter ( ) . any ( |ext| lower. ends_with ( ext) )
3262 } ;
3363
34- if target_dir . is_some ( ) {
64+ if proxy_dir . exists ( ) {
3565 if let Ok ( entries) = fs:: read_dir ( & proxy_dir) {
3666 for entry in entries. flatten ( ) {
3767 let path = entry. path ( ) ;
68+ if !path. is_file ( ) { continue ; }
3869 let name = path. file_name ( ) . and_then ( |n| n. to_str ( ) ) . unwrap_or_default ( ) . to_lowercase ( ) ;
39- if name. contains ( "cliproxy" ) || name. contains ( "cli-proxy" ) || name == "config.example.yaml" {
70+ if ( name. contains ( "cliproxy" ) || name. contains ( "cli-proxy" ) )
71+ && !is_config_file ( & name)
72+ {
4073 let _ = fs:: remove_file ( & path) ;
4174 }
4275 }
4376 }
44- } else {
45- if proxy_dir. exists ( ) {
46- if let Err ( e) = fs:: remove_dir_all ( & proxy_dir) {
47- println ! ( "Warning: Could not clear old proxy directory: {}" , e) ;
48- }
49- }
5077 }
5178 fs:: create_dir_all ( & proxy_dir)
5279 . map_err ( |e| CommandError :: General ( format ! ( "Failed to create proxy dir: {}" , e) ) ) ?;
@@ -89,6 +116,12 @@ pub async fn download_and_extract_proxy(_app: AppHandle, url: String, target_dir
89116 fs:: create_dir_all ( & outpath)
90117 . map_err ( |e| CommandError :: General ( format ! ( "Failed to create zip dir: {}" , e) ) ) ?;
91118 } else {
119+ let file_name = outpath. file_name ( ) . and_then ( |n| n. to_str ( ) ) . unwrap_or_default ( ) ;
120+ if is_config_file ( file_name) && outpath. exists ( ) {
121+ println ! ( "Skipping existing config file: {:?}" , outpath) ;
122+ continue ;
123+ }
124+
92125 if let Some ( p) = outpath. parent ( ) {
93126 if !p. exists ( ) {
94127 fs:: create_dir_all ( p)
@@ -117,29 +150,50 @@ pub async fn download_and_extract_proxy(_app: AppHandle, url: String, target_dir
117150 }
118151 }
119152 } else if is_tar_gz {
153+ let temp_extract = std:: env:: temp_dir ( ) . join ( "zerolimit_proxy_extract" ) ;
154+ if temp_extract. exists ( ) {
155+ let _ = fs:: remove_dir_all ( & temp_extract) ;
156+ }
157+ fs:: create_dir_all ( & temp_extract)
158+ . map_err ( |e| CommandError :: General ( format ! ( "Failed to create temp extract dir: {}" , e) ) ) ?;
159+
120160 let cursor = Cursor :: new ( bytes) ;
121161 let tar = flate2:: read:: GzDecoder :: new ( cursor) ;
122162 let mut archive = tar:: Archive :: new ( tar) ;
123-
124- archive. unpack ( & proxy_dir)
163+ archive. unpack ( & temp_extract)
125164 . map_err ( |e| CommandError :: General ( format ! ( "Failed to unpack tarball: {}" , e) ) ) ?;
126- } else {
127- return Err ( CommandError :: General ( format ! ( "Unsupported file extension in URL: {}" , url) ) ) ;
128- }
129165
130- println ! ( "Extraction complete. Looking for executable..." ) ;
166+ fn copy_dir_selective ( src : & std:: path:: Path , dst : & std:: path:: Path , is_config : & dyn Fn ( & str ) -> bool ) -> io:: Result < ( ) > {
167+ if !dst. exists ( ) {
168+ fs:: create_dir_all ( dst) ?;
169+ }
170+ for entry in fs:: read_dir ( src) ? {
171+ let entry = entry?;
172+ let src_path = entry. path ( ) ;
173+ let file_name = src_path. file_name ( ) . and_then ( |n| n. to_str ( ) ) . unwrap_or_default ( ) ;
174+ let dst_path = dst. join ( file_name) ;
131175
132- if had_config {
133- let restore_target = proxy_dir. join ( "config.yaml" ) ;
134- match fs:: copy ( & config_backup, & restore_target) {
135- Ok ( _) => {
136- println ! ( "Restored config.yaml from backup." ) ;
137- let _ = fs:: remove_file ( & config_backup) ;
176+ if src_path. is_dir ( ) {
177+ copy_dir_selective ( & src_path, & dst_path, is_config) ?;
178+ } else {
179+ if is_config ( file_name) && dst_path. exists ( ) {
180+ println ! ( "Skipping existing config file: {:?}" , dst_path) ;
181+ continue ;
182+ }
183+ fs:: copy ( & src_path, & dst_path) ?;
184+ }
138185 }
139- Err ( e ) => println ! ( "Warning: Could not restore config.yaml: {}" , e ) ,
186+ Ok ( ( ) )
140187 }
188+ copy_dir_selective ( & temp_extract, & proxy_dir, & is_config_file)
189+ . map_err ( |e| CommandError :: General ( format ! ( "Failed to copy extracted files: {}" , e) ) ) ?;
190+ let _ = fs:: remove_dir_all ( & temp_extract) ;
191+ } else {
192+ return Err ( CommandError :: General ( format ! ( "Unsupported file extension in URL: {}" , url) ) ) ;
141193 }
142194
195+ println ! ( "Extraction complete. Looking for executable..." ) ;
196+
143197 let mut exe_path: Option < PathBuf > = None ;
144198
145199 if let Ok ( entries) = fs:: read_dir ( & proxy_dir) {
@@ -159,7 +213,9 @@ pub async fn download_and_extract_proxy(_app: AppHandle, url: String, target_dir
159213 } else if file_name == "config.example.yaml" {
160214 let mut new_config_path = path. clone ( ) ;
161215 new_config_path. set_file_name ( "config.yaml" ) ;
162- if let Err ( e) = fs:: rename ( & path, & new_config_path) {
216+ if new_config_path. exists ( ) {
217+ println ! ( "Skipping config.example.yaml rename: config.yaml already exists" ) ;
218+ } else if let Err ( e) = fs:: rename ( & path, & new_config_path) {
163219 println ! ( "Notice: Could not rename config.example.yaml: {}" , e) ;
164220 } else {
165221 println ! ( "Successfully renamed config.example.yaml to config.yaml" ) ;
@@ -191,7 +247,9 @@ pub async fn download_and_extract_proxy(_app: AppHandle, url: String, target_dir
191247 } else if file_name == "config.example.yaml" {
192248 let mut new_config_path = path. clone ( ) ;
193249 new_config_path. set_file_name ( "config.yaml" ) ;
194- if let Err ( e) = fs:: rename ( & path, & new_config_path) {
250+ if new_config_path. exists ( ) {
251+ println ! ( "Skipping config.example.yaml rename: config.yaml already exists" ) ;
252+ } else if let Err ( e) = fs:: rename ( & path, & new_config_path) {
195253 println ! ( "Notice: Could not rename config.example.yaml: {}" , e) ;
196254 } else {
197255 println ! ( "Successfully renamed config.example.yaml to config.yaml" ) ;
0 commit comments