11use crate :: apps:: call;
2- use crate :: browser_manager:: { get_running_instance, launch_new_instance, sunset_browser_instance} ;
2+ use crate :: browser_manager:: { get_running_instance, launch_new_instance, sunset_browser_instance, MANAGED_BROWSER } ;
33use crate :: network:: {
44 create_new_page, determine_browser_type, extract_port_from_ws_url, find_free_port,
5- get_browser_info, scan_for_existing_browser_instances,
5+ get_browser_info, get_browser_websocket_url , scan_for_existing_browser_instances,
66} ;
77use crate :: platform:: detect_browsers;
8- use crate :: sketchs:: BrowserConfig ;
8+ use crate :: sketchs:: { BrowserConfig , ManageableBrowserInstance } ;
99use crate :: sketchs_browser:: WebsiteSkills ;
1010use crate :: skills:: download_skill_json;
1111
12- fn is_equivalent_selection ( selected : & str , running : & str ) -> bool {
13- if selected == running {
14- return true ;
12+ const CHROME_PORT : u16 = 9522 ;
13+ const EDGE_PORT : u16 = 9523 ;
14+ const ARC_PORT : u16 = 9524 ;
15+
16+ fn browser_id_for_path ( path : & str ) -> & ' static str {
17+ let lower = path. to_lowercase ( ) ;
18+ if lower. contains ( "edge" ) || lower. contains ( "msedge" ) {
19+ "edge"
20+ } else if lower. contains ( "arc" ) {
21+ "arc"
22+ } else {
23+ "chrome"
1524 }
25+ }
26+ fn static_port_for ( id : & str ) -> u16 {
27+ match id {
28+ "edge" => EDGE_PORT ,
29+ "arc" => ARC_PORT ,
30+ _ => CHROME_PORT ,
31+ }
32+ }
33+
34+ fn is_equivalent_selection ( selected : & str , running : & str ) -> bool {
35+ if selected == running { return true ; }
1636 selected == "arc" && running == "chrome"
1737}
1838
@@ -30,12 +50,8 @@ pub async fn fetch_available_browsers() -> Result<Vec<BrowserConfig>, String> {
3050}
3151
3252#[ tauri:: command]
33- pub async fn validate_connection (
34- ws_endpoint : String ,
35- selected_browser_path : String ,
36- ) -> Result < String , String > {
53+ pub async fn validate_connection ( ws_endpoint : String , selected_browser_path : String ) -> Result < String , String > {
3754 let port = extract_port_from_ws_url ( & ws_endpoint) ?;
38-
3955 let ( browser_string, user_agent) = get_browser_info ( & port) . await ?;
4056 let running_browser_type = determine_browser_type ( & browser_string, & user_agent) ;
4157
@@ -116,48 +132,80 @@ pub async fn launch_browser(browser_path: Option<String>) -> Result<String, Stri
116132 . ok_or_else ( || "No browser found" . to_string ( ) ) ?
117133 } ;
118134
135+ let selected_id = browser_id_for_path ( & target_browser_path) ;
136+ let port = static_port_for ( selected_id) ;
137+
119138 /*
120- ** try to reuse an existing instance
139+ ** close any managed instance to free the static port.
121140 */
122- if let Some ( ws_url) = get_running_instance ( & target_browser_path) . await {
123- if let Ok ( port_str) = extract_port_from_ws_url ( & ws_url) {
124- if let Ok ( port) = port_str. parse :: < u16 > ( ) {
125- let _ = create_new_page ( port, Some ( "https://www.google.com" ) ) . await ;
141+ {
142+ let mut guard = MANAGED_BROWSER . lock ( ) . await ;
143+ if let Some ( mut inst) = guard. take ( ) {
144+ if inst. path != target_browser_path || inst. port != port {
145+ if let Some ( mut child) = inst. child . take ( ) {
146+ let _ = child. kill ( ) ;
147+ let _ = child. wait ( ) ;
148+ }
149+ } else {
150+ * guard = Some ( inst) ;
126151 }
127152 }
128- return Ok ( ws_url) ;
129153 }
130154
131155 /*
132- ** Force Arc => 9222, others => first free from 9222 upward
156+ ** probe the static port (is anything already listening?)
133157 */
134- let is_arc = target_browser_path. to_lowercase ( ) . contains ( "arc" ) ;
135- let port = if is_arc {
136- match get_browser_info ( "9222" ) . await {
137- Ok ( ( browser_string, _ua) ) => {
138- if let Some ( ws) = scan_for_existing_browser_instances ( "arc" ) . await {
139- return Ok ( ws) ;
158+ match get_browser_info ( & port. to_string ( ) ) . await {
159+ Ok ( ( browser_string, user_agent) ) => {
160+ let running = determine_browser_type ( & browser_string, & user_agent) ;
161+ if is_equivalent_selection ( selected_id, & running) {
162+ /*
163+ ** reuse existing instance on the static port
164+ */
165+ let ws_url = get_browser_websocket_url ( port, 20 , 500 )
166+ . await
167+ . map_err ( |e| format ! ( "Failed to obtain DevTools websocket: {e}" ) ) ?;
168+
169+ /*
170+ ** remember (not launched by us)
171+ */
172+ {
173+ let mut managed = MANAGED_BROWSER . lock ( ) . await ;
174+ * managed = Some ( ManageableBrowserInstance {
175+ path : target_browser_path. clone ( ) ,
176+ port,
177+ ws_url : ws_url. clone ( ) ,
178+ child : None ,
179+ launched_by_app : false ,
180+ } ) ;
140181 }
182+ let _ = create_new_page ( port, Some ( "https://www.google.com" ) ) . await ;
183+
184+ return Ok ( ws_url) ;
185+ } else {
141186 return Err ( format ! (
142- "Port 9222 already in use by: {browser_string} . Close it and retry Arc ."
187+ "Static port {port} is already occupied by another browser ({running}) . Close it and retry."
143188 ) ) ;
144189 }
145- Err ( _) => 9222 ,
146190 }
147- } else {
148- find_free_port ( 9222 ) . ok_or_else ( || "Failed to find a free port" . to_string ( ) ) ?
149- } ;
191+ Err ( _) => {
192+ /*
193+ ** nothing on that port — proceed to launch a fresh instance on it
194+ */
195+ }
196+ }
150197
151198 /*
152- ** Launch
199+ ** launch on the static port
153200 */
154201 match launch_new_instance ( & target_browser_path, port) . await {
155202 Ok ( ws_url) => {
156- if !is_arc {
157- if let Ok ( pstr) = extract_port_from_ws_url ( & ws_url) {
158- if let Ok ( p) = pstr. parse :: < u16 > ( ) {
159- let _ = create_new_page ( p, Some ( "https://www.google.com" ) ) . await ;
160- }
203+ /*
204+ ** starter tab (keeps process alive / makes pages() non-empty)
205+ */
206+ if let Ok ( pstr) = extract_port_from_ws_url ( & ws_url) {
207+ if let Ok ( p) = pstr. parse :: < u16 > ( ) {
208+ let _ = create_new_page ( p, Some ( "https://www.google.com" ) ) . await ;
161209 }
162210 }
163211 Ok ( ws_url)
0 commit comments