jerry преди 1 седмица
родител
ревизия
f6f0df0637
променени са 4 файла, в които са добавени 154 реда и са изтрити 153 реда
  1. 3 3
      booker_builtin.py
  2. 1 1
      booker_order.py
  3. 149 148
      plugins/tls_plugin.py
  4. 1 1
      tools/clash_api.py

+ 3 - 3
booker_builtin.py

@@ -37,8 +37,8 @@ class BuiltinBookerGCO:
             "retry_on_timeout": True,
             "decode_responses": False,
         }
-        self.redis_com = redis.Redis(**redis_conf)
-        self.redis_sub = redis.Redis(**redis_conf)
+        self.redis_com = redis.Redis(**redis_common_kwargs)
+        self.redis_sub = redis.Redis(**redis_common_kwargs)
         self.m_pending_builtin = 0
         
         self.m_tracker_key = f"vs:worker:tasks_tracker:{self.m_cfg.identifier}"
@@ -118,7 +118,7 @@ class BuiltinBookerGCO:
                         t.instance.keep_alive()
                         if t.instance.health_check():
                             healthy_tasks.append(t)
-                            next_delay = random.randint(180, 300) 
+                            next_delay = random.randint(60, 180) 
                             t.next_remote_ping = now + next_delay
                         else:
                             dead_tasks.append(t)

+ 1 - 1
booker_order.py

@@ -131,7 +131,7 @@ class OrderBookerGCO:
                         t.instance.keep_alive()
                         if t.instance.health_check(): 
                             healthy_tasks.append(t)
-                            next_delay = random.randint(180, 300) 
+                            next_delay = random.randint(60, 180) 
                             t.next_remote_ping = now + next_delay
                             self._log(f"🛡️ Task={t.task_ref} keep-alive success. Next ping in {next_delay}s.")
                         else:

+ 149 - 148
plugins/tls_plugin.py

@@ -263,164 +263,165 @@ class TlsPlugin(IVSPlg):
             has_submitted_login = False
             
             for step in range(max_steps):
-                self.page.wait.load_start()
-                current_url = self.page.url
-                self._log(f"--- [Router Step {step+1}] Current URL: {current_url} ---")
-                
-                cloudflare_blocked_indicators = [
-                    "Sorry, you have been blocked" in self.page.html,
-                    "You are being rate limited" in self.page.html,
-                    "Cloudflare Ray ID" in self.page.html
-                ]
-                if any(cloudflare_blocked_indicators):
-                    raise BizLogicError(message="Blocked by Cloudflare WAF. Need to change IP or browser fingerprint.")
-                
-                # 状态 1:到达终极目标页面 (成功退出条件)
-                if "appointment-booking" in current_url or self.page.ele('tag:button@text():Book your appointment', timeout=1):
-                    btn_selector = 'tag:button@text():Book your appointment'            
-                    if self.page.wait.ele_displayed(btn_selector, timeout=10):
-                        self.session_create_time = time.time()
-                        self._log("✅ Login & Navigation Success! Reached appointment-booking.")
-                        session_created = True
-                        break
-                
-                # 状态 2:遇到没有申请人的拦截页 (致命错误退出条件)
-                no_applicant_indicators = [
-                    "Add a new applicant" in self.page.html,
-                    "You have not yet added an applicant" in self.page.html,
-                    "applicants-information" in current_url
-                ]
-                if any(no_applicant_indicators):
-                    raise BizLogicError(message="No applicant added. Cannot proceed to booking.") 
-                
-                if current_url == tls_url:
-                    # 状态 3:首页/登录入口页 -> 需要点击进入登录
-                    if self.page.ele("tag:a@@href:login", timeout=1) and not self.page.ele('tag:label@@text():Email', timeout=1):
-                        self._log("State: Login Portal. Clicking login link...")
-                        login_link = self.page.ele("tag:a@@href:login")
-                        self.mouse.human_click_ele(login_link)
-                        time.sleep(3)
-                        continue
-                    if self.page.ele("tag:svg@@data-testid=user-button", timeout=1):
-                        self._log("State: Already login, logout now...")
-                        user_btn = self.page.ele("tag:svg@@data-testid=user-button")
-                        self.mouse.human_click_ele(user_btn)
-                        time.sleep(1.5)
-                        logout_btn = self.page.ele("#logout")
-                        self.mouse.human_click_ele(logout_btn)
-                        time.sleep(1.5)
-                        self.page.get(tls_url)
-                        time.sleep(3)
-                        continue
-                
-                # 状态 4:真正的登录表单页
-                if self.page.ele('tag:label@@text():Email', timeout=1) and not has_submitted_login:
-                    self._log("State: Login Form. Processing credentials and Captcha...")
+                try:
+                    self.page.wait.load_start()
+                    current_url = self.page.url
+                    self._log(f"--- [Router Step {step+1}] Current URL: {current_url} ---")
                     
-                    recaptchav2_token = ""
-                    if not captcha_future and (self.page.ele('.g-recaptcha') or self.page.ele('xpath://iframe[contains(@src, "recaptcha")]')):
-                        rec_iframe = self.page.ele('xpath://iframe[contains(@src, "recaptcha")]')
-                        rec_iframe_src = rec_iframe.attr('src')
-                        rec_parsed = urlparse(rec_iframe_src)
-                        rec_params = parse_qs(rec_parsed.query)
-                        rec_sitekey = rec_params.get("k", [None])[0]
-                        rec_size = rec_params.get("size", [None])[0]
-                        
-                        if 'normal' == rec_size:
-                            self._log(f"Found dynamic sitekey={rec_sitekey}. Starting async Captcha solver...")
-                            rc_params = {
-                                "type": "ReCaptchaV2TaskProxyLess",
-                                "page": current_url,
-                                "siteKey": rec_sitekey, 
-                                "apiToken": self.free_config.get("capsolver_key", "")
-                            }
-                            captcha_future = captcha_executor.submit(self._solve_recaptcha, rc_params)
-
-                    username = self.config.account.username
-                    password = self.config.account.password
+                    cloudflare_blocked_indicators = [
+                        "Sorry, you have been blocked" in self.page.html,
+                        "You are being rate limited" in self.page.html,
+                        "Cloudflare Ray ID" in self.page.html
+                    ]
+                    if any(cloudflare_blocked_indicators):
+                        raise BizLogicError(message="Blocked by Cloudflare WAF. Need to change IP or browser fingerprint.")
                     
-                    input_ele = self.page.ele('tag:label@@text():Email').next()
-                    self.mouse.human_click_ele(input_ele)
-                    time.sleep(random.uniform(0.2, 0.6))
-                    self.keyboard.type_text(username, humanize=True)
-                    time.sleep(random.uniform(0.5, 1.2)) 
-                
-                    input_ele = self.page.ele('tag:label@@text():Password').next()
-                    self.mouse.human_click_ele(input_ele)
-                    time.sleep(random.uniform(0.2, 0.6))
-                    self.keyboard.type_text(password, humanize=True)
+                    # 状态 1:到达终极目标页面 (成功退出条件)
+                    if "appointment-booking" in current_url or self.page.ele('tag:button@text():Book your appointment', timeout=1):
+                        btn_selector = 'tag:button@text():Book your appointment'            
+                        if self.page.wait.ele_displayed(btn_selector, timeout=10):
+                            self.session_create_time = time.time()
+                            self._log("✅ Login & Navigation Success! Reached appointment-booking.")
+                            session_created = True
+                            break
                     
-                    # 注入 Token
-                    if captcha_future:
-                        self._log("Waiting for background Captcha result...")
-                        try:
-                            # 设一个合理的超时,防止死锁
-                            recaptchav2_token = captcha_future.result(timeout=120) 
-                            self._log("Background Captcha solved successfully!")
-                        except Exception as e:
-                            raise BizLogicError(f"Captcha solving failed or timed out: {e}")
+                    # 状态 2:遇到没有申请人的拦截页 (致命错误退出条件)
+                    no_applicant_indicators = [
+                        "Add a new applicant" in self.page.html,
+                        "You have not yet added an applicant" in self.page.html,
+                        "applicants-information" in current_url
+                    ]
+                    if any(no_applicant_indicators):
+                        raise BizLogicError(message="No applicant added. Cannot proceed to booking.") 
                     
-                        # 注入 Token
-                        if recaptchav2_token:
-                            inject_js = f"var g = document.getElementById('g-recaptcha-response'); if(g) {{ g.value = '{recaptchav2_token}'; }}"
-                            self.page.run_js(inject_js)
-                            time.sleep(random.uniform(0.5, 1.0))
+                    if current_url == tls_url:
+                        # 状态 3:首页/登录入口页 -> 需要点击进入登录
+                        if self.page.ele("tag:a@@href:login", timeout=1) and not self.page.ele('tag:label@@text():Email', timeout=1):
+                            self._log("State: Login Portal. Clicking login link...")
+                            login_link = self.page.ele("tag:a@@href:login")
+                            self.mouse.human_click_ele(login_link)
+                            time.sleep(3)
+                            continue
+                        if self.page.ele("tag:svg@@data-testid=user-button", timeout=1):
+                            self._log("State: Already login, logout now...")
+                            user_btn = self.page.ele("tag:svg@@data-testid=user-button")
+                            self.mouse.human_click_ele(user_btn)
+                            time.sleep(1.5)
+                            logout_btn = self.page.ele("#logout")
+                            self.mouse.human_click_ele(logout_btn)
+                            time.sleep(1.5)
+                            self.page.get(tls_url)
+                            time.sleep(3)
+                            continue
                     
-                    self._log("Submitting Login...")
-                    login_btn = self.page.ele('tag:button@@text():Login')
-                    self.mouse.human_click_ele(login_btn)
-                    has_submitted_login = True
-                    time.sleep(3)
-                    continue
-                
-                # 状态 5:Travel Groups 页面
-                if "travel-groups" in current_url:
-                    self._log("State: Travel Groups. Selecting targeted group...")
-                    groups = self._parse_travel_groups(self.page.html)
-                    location = self.free_config.get('location')
-                    self.travel_group = next((g for g in groups if location in g['location']), None)
+                    # 状态 4:真正的登录表单页
+                    if self.page.ele('tag:label@@text():Email', timeout=1) and not has_submitted_login:
+                        self._log("State: Login Form. Processing credentials and Captcha...")
+                        
+                        recaptchav2_token = ""
+                        if not captcha_future and (self.page.ele('.g-recaptcha') or self.page.ele('xpath://iframe[contains(@src, "recaptcha")]')):
+                            rec_iframe = self.page.ele('xpath://iframe[contains(@src, "recaptcha")]')
+                            rec_iframe_src = rec_iframe.attr('src')
+                            rec_parsed = urlparse(rec_iframe_src)
+                            rec_params = parse_qs(rec_parsed.query)
+                            rec_sitekey = rec_params.get("k", [None])[0]
+                            rec_size = rec_params.get("size", [None])[0]
+                            
+                            if 'normal' == rec_size:
+                                self._log(f"Found dynamic sitekey={rec_sitekey}. Starting async Captcha solver...")
+                                rc_params = {
+                                    "type": "ReCaptchaV2TaskProxyLess",
+                                    "page": current_url,
+                                    "siteKey": rec_sitekey, 
+                                    "apiToken": self.free_config.get("capsolver_key", "")
+                                }
+                                captcha_future = captcha_executor.submit(self._solve_recaptcha, rc_params)
+
+                        username = self.config.account.username
+                        password = self.config.account.password
+                        
+                        input_ele = self.page.ele('tag:label@@text():Email').next()
+                        self.mouse.human_click_ele(input_ele)
+                        time.sleep(random.uniform(0.2, 0.6))
+                        self.keyboard.type_text(username, humanize=True)
+                        time.sleep(random.uniform(0.5, 1.2)) 
                     
-                    if not self.travel_group or not self.travel_group.get("submitted"):
-                        self._save_screenshot("group_not_found")
-                        raise NotFoundError(f"Group not found for {location}")
-                
-                    formgroup_id = self.travel_group.get('group_number')
-                    btn_selector = f'tag:button@@name=formGroupId@@value={formgroup_id}'
+                        input_ele = self.page.ele('tag:label@@text():Password').next()
+                        self.mouse.human_click_ele(input_ele)
+                        time.sleep(random.uniform(0.2, 0.6))
+                        self.keyboard.type_text(password, humanize=True)
+                        
+                        # 注入 Token
+                        if captcha_future:
+                            self._log("Waiting for background Captcha result...")
+                            try:
+                                # 设一个合理的超时,防止死锁
+                                recaptchav2_token = captcha_future.result(timeout=120) 
+                                self._log("Background Captcha solved successfully!")
+                            except Exception as e:
+                                raise BizLogicError(f"Captcha solving failed or timed out: {e}")
+                        
+                            # 注入 Token
+                            if recaptchav2_token:
+                                inject_js = f"var g = document.getElementById('g-recaptcha-response'); if(g) {{ g.value = '{recaptchav2_token}'; }}"
+                                self.page.run_js(inject_js)
+                                time.sleep(random.uniform(0.5, 1.0))
+                        
+                        self._log("Submitting Login...")
+                        login_btn = self.page.ele('tag:button@@text():Login')
+                        self.mouse.human_click_ele(login_btn)
+                        has_submitted_login = True
+                        time.sleep(3)
+                        continue
                     
-                    if self.page.wait.eles_loaded(btn_selector, timeout=10):
-                        buttons = self.page.eles(btn_selector)
-                        select_btn = next((btn for btn in reversed(buttons) if btn.rect.size[0] > 0 and btn.rect.size[1] > 0), None)
+                    # 状态 5:Travel Groups 页面
+                    if "travel-groups" in current_url:
+                        self._log("State: Travel Groups. Selecting targeted group...")
+                        groups = self._parse_travel_groups(self.page.html)
+                        location = self.free_config.get('location')
+                        self.travel_group = next((g for g in groups if location in g['location']), None)
                         
-                        if select_btn:
-                            time.sleep(random.uniform(0.5, 1.2))
-                            self.mouse.human_click_ele(select_btn)
-                            time.sleep(3)
-                            continue
+                        if not self.travel_group or not self.travel_group.get("submitted"):
+                            self._save_screenshot("group_not_found")
+                            raise NotFoundError(f"Group not found for {location}")
+                    
+                        formgroup_id = self.travel_group.get('group_number')
+                        btn_selector = f'tag:button@@name=formGroupId@@value={formgroup_id}'
+                        
+                        if self.page.wait.eles_loaded(btn_selector, timeout=10):
+                            buttons = self.page.eles(btn_selector)
+                            select_btn = next((btn for btn in reversed(buttons) if btn.rect.size[0] > 0 and btn.rect.size[1] > 0), None)
+                            
+                            if select_btn:
+                                time.sleep(random.uniform(0.5, 1.2))
+                                self.mouse.human_click_ele(select_btn)
+                                time.sleep(3)
+                                continue
+                            else:
+                                self._log("[WARN] Select button found but not visible.")
                         else:
-                            self._log("[WARN] Select button found but not visible.")
-                    else:
-                        self._log(f"[WARN] Wait timeout for group button {formgroup_id}")
-                
-                # 状态 6:中间过渡页,需点击 "Book Appointment" 继续往下走
-                if self.page.ele('#book-appointment-btn', timeout=1):
-                    self._log("State: Intermediate Dashboard. Clicking Book Appointment button...")
-                    self.mouse.human_click_ele(self.page.ele('#book-appointment-btn'))
-                    time.sleep(3)
-                    continue
-                
-                # 状态 7:登录失败校验 或 未知加载状态
-                if "login-actions" in current_url and has_submitted_login:
-                    self._log("Waiting on login-actions... (Might be authenticating or invalid credentials)")
+                            self._log(f"[WARN] Wait timeout for group button {formgroup_id}")
+                    
+                    # 状态 6:中间过渡页,需点击 "Book Appointment" 继续往下走
+                    if self.page.ele('#book-appointment-btn', timeout=1):
+                        self._log("State: Intermediate Dashboard. Clicking Book Appointment button...")
+                        self.mouse.human_click_ele(self.page.ele('#book-appointment-btn'))
+                        time.sleep(3)
+                        continue
+                    
+                    # 状态 7:登录失败校验 或 未知加载状态
+                    if "login-actions" in current_url and has_submitted_login:
+                        self._log("Waiting on login-actions... (Might be authenticating or invalid credentials)")
+                        time.sleep(2)
+                        if self.page.ele('text:Invalid username or password', timeout=1): # 假设网页上有错误提示
+                            raise BizLogicError(message="Login Failed! Invalid credentials or Captcha rejected.")
+                        continue
+                    
+                    self._log("State: Transitioning or Unknown. Waiting 2 seconds...")
                     time.sleep(2)
-                    if self.page.ele('text:Invalid username or password', timeout=1): # 假设网页上有错误提示
-                        raise BizLogicError(message="Login Failed! Invalid credentials or Captcha rejected.")
-                    continue
-                
-                # 兜底:未匹配到明确状态,等待页面渲染或重定向
-                self._log("State: Transitioning or Unknown. Waiting 2 seconds...")
-                time.sleep(2)
-            
-            # 如果循环耗尽还没到达目标
+                except Exception as e:
+                    self._log(f'Step {step} exception: {e}')
+                    
             if not session_created:
                 raise BizLogicError(f"Failed to reach appointment-booking after {max_steps} navigation steps. Stuck at: {self.page.url}")
 

+ 1 - 1
tools/clash_api.py

@@ -10,7 +10,7 @@ def switch_next_node():
         "Content-Type": "application/json"
     }
     try:
-        resp = requests.get(f"{configure.API_URL}/proxies", headers=headers, timeout=5)
+        resp = requests.get(f"{configure.CLASH_API_URL}/proxies", headers=headers, timeout=5)
     except Exception as e:
         raise BizLogicError(f'Fetch proxies error, e={e}')
     proxies_data = resp.json()