From 2a6b1eacd583c75068ae70f550a5bb5d6d0e48a7 Mon Sep 17 00:00:00 2001 From: SimplifiedPrivacy Date: Mon, 10 Aug 2026 16:25:45 -0400 Subject: [PATCH] Support for auto-retry on Singbox enable --- .../encrypted_proxy/singbox_runner.py | 76 +++++++++++-------- 1 file changed, 44 insertions(+), 32 deletions(-) diff --git a/core/services/networking/systemwide/encrypted_proxy/singbox_runner.py b/core/services/networking/systemwide/encrypted_proxy/singbox_runner.py index b77d0dd..122a22a 100644 --- a/core/services/networking/systemwide/encrypted_proxy/singbox_runner.py +++ b/core/services/networking/systemwide/encrypted_proxy/singbox_runner.py @@ -46,17 +46,51 @@ def set_dns_for_singbox(current_state: SystemState): raise DNSError(dns_result) -# def _attempt_start_with_retry(profile_id: int, quantity_of_attempts: int = 2) -> Result: -# current_attempt = 0 -# while current_attempt < quantity_of_attempts: -# activation_result = singbox.start(profile_id) +def launch_singbox_binary(profile_id: int) -> Result: + activation_result = singbox.start(profile_id) + if not activation_result.valid: + return activation_result -# if activation_result.valid: -# return activation_result -# else: -# current_attempt = current_attempt + 1 -# logger.error(f"[SINGBOX] Attempt {current_attempt} for Singbox Failed. Because: {activation_result.message}. Trying again..") + process_id = int(activation_result.data) + + logger.info(f"Waiting 2 seconds to see if the process id {process_id} is still alive..") + time.sleep(2) + + # Evaluate if running. + active = pid_tools.is_running(pid=process_id, process_name="sing-box") + logger.info(f"Process {process_id} is {active}") + + if active: + return Result(valid=True, data=process_id) + else: + error_msg = f"While Singbox might have literally allowed the binary to begin, it's killing the process on id {process_id}" + logger.error(f"[{function_name}] {error_msg}") + return Result(valid=False, error_type=ResultError.PROCESS_GOT_KILLED, message=error_msg, data=process_id) + + +def _attempt_start_with_retry(profile_id: int, quantity_of_attempts: int = 2) -> Result: + current_attempt = 0 + + while current_attempt < quantity_of_attempts: + activation_result = launch_singbox_binary(profile_id) + + if activation_result.valid: + return activation_result + else: + current_attempt = current_attempt + 1 + logger.error(f"[SINGBOX] Attempt {current_attempt} for Singbox Failed. Because: {activation_result.message}. Trying again in two seconds..") + time.sleep(2) + + # end of loop / make sure it's not running already.. + error_msg = f"Singbox failed to launch after {quantity_of_attempts} attempts" + logger.error(f"{error_msg}, let's double check it's not running already:") + double_check = pid_tools.get_pid_by_app_name(exact_app_name="sing-box") + if double_check.valid: + return double_check + else: + # I'd like to clarify the error_type here, instead of just returning the pid check or an individual attempt. + return Result(valid=False, error_type=PROCESS_WONT_START, message=error_msg) def end_singbox( @@ -121,28 +155,6 @@ def end_singbox( return Result(valid=False, error_type=ResultError.SINGBOX, message=error_msg) -def launch_singbox_binary(profile_id: int) -> Result: - activation_result = singbox.start(profile_id) - if not activation_result.valid: - return activation_result - - process_id = int(activation_result.data) - - logger.info(f"Waiting 2 seconds to see if the process id {process_id} is still alive..") - time.sleep(2) - - # Evaluate if running. - active = pid_tools.is_running(pid=process_id, process_name="sing-box") - logger.info(f"Process {process_id} is {active}") - - if active: - return Result(valid=True, data=process_id) - else: - error_msg = f"While Singbox might have literally allowed the binary to begin, it's killing the process on id {process_id}" - logger.error(f"[{function_name}] {error_msg}") - return Result(valid=False, error_type=ResultError.PROCESS_GOT_KILLED, message=error_msg, data=process_id) - - def start_singbox( profile_id: int, @@ -177,7 +189,7 @@ def start_singbox( return killed_pre_existing # ============= START BINARY ============= - launched = launch_singbox_binary(profile_id=profile_id) + launched = _attempt_start_with_retry(profile_id=profile_id, quantity_of_attempts=2) if not launched.valid: return launched