|
@@ -46,6 +46,17 @@ COUNTRY_MAP = {
|
|
|
def get_country_iso3(name: str) -> str:
|
|
def get_country_iso3(name: str) -> str:
|
|
|
return COUNTRY_MAP.get(name.lower(), "CHN")
|
|
return COUNTRY_MAP.get(name.lower(), "CHN")
|
|
|
|
|
|
|
|
|
|
+def get_alias_email(email: str, new_domain: str = "gmail-app.com") -> str:
|
|
|
|
|
+ """
|
|
|
|
|
+ 将邮箱域名替换为指定域名(默认 gmail-app.com)
|
|
|
|
|
+ """
|
|
|
|
|
+ if "@" not in email:
|
|
|
|
|
+ raise ValueError(f"Invalid email: {email}")
|
|
|
|
|
+
|
|
|
|
|
+ local_part, _ = email.rsplit("@", 1)
|
|
|
|
|
+ return f"{local_part}@{new_domain}"
|
|
|
|
|
+
|
|
|
|
|
+
|
|
|
# ----------------- VfsPlugin 类 -----------------
|
|
# ----------------- VfsPlugin 类 -----------------
|
|
|
|
|
|
|
|
class VfsPlugin(IVSPlg):
|
|
class VfsPlugin(IVSPlg):
|
|
@@ -251,26 +262,25 @@ class VfsPlugin(IVSPlg):
|
|
|
curr = curr.replace(month=curr.month + 1)
|
|
curr = curr.replace(month=curr.month + 1)
|
|
|
return months
|
|
return months
|
|
|
|
|
|
|
|
- def book(self, slot_info: VSQueryResult) -> VSBookResult:
|
|
|
|
|
|
|
+ def book(self, slot_info: VSQueryResult, user_inputs) -> VSBookResult:
|
|
|
"""
|
|
"""
|
|
|
执行完整的预约流程 (对应 C++ VFSApi::book)
|
|
执行完整的预约流程 (对应 C++ VFSApi::book)
|
|
|
包含:上传文档 -> 添加申请人 -> OTP -> 选时间 -> 锁定 -> 支付
|
|
包含:上传文档 -> 添加申请人 -> OTP -> 选时间 -> 锁定 -> 支付
|
|
|
"""
|
|
"""
|
|
|
- res = VSBookResult()
|
|
|
|
|
|
|
+ user_email = user_inputs.get('email', 'get_visa_666@example.com')
|
|
|
|
|
+ user_inputs['alias_email'] = get_alias_email(user_email, new_domain="gmail-app.com")
|
|
|
|
|
|
|
|
- # 1. 准备配置和用户信息
|
|
|
|
|
- # 这里的 uinfo 实际上应该从 Coordinator 传入或从 Config 获取,这里沿用之前的 helper
|
|
|
|
|
- uinfo = self._prepare_user_info()
|
|
|
|
|
|
|
+ res = VSBookResult()
|
|
|
|
|
+ # 定位 Appointment Config
|
|
|
|
|
+ slot_routing_key = slot_info.routing_key
|
|
|
|
|
|
|
|
# C++ 中 from_date 是入参,对应 Python 的 slot_info.earliest_date
|
|
# C++ 中 from_date 是入参,对应 Python 的 slot_info.earliest_date
|
|
|
from_date = slot_info.earliest_date if slot_info.earliest_date else datetime.now().strftime("%d/%m/%Y")
|
|
from_date = slot_info.earliest_date if slot_info.earliest_date else datetime.now().strftime("%d/%m/%Y")
|
|
|
|
|
|
|
|
- # 定位 Appointment Config
|
|
|
|
|
- target_routing_key = slot_info.routing_key
|
|
|
|
|
apt_config = None
|
|
apt_config = None
|
|
|
appt_types = self.free_config.get("appointmentType", [])
|
|
appt_types = self.free_config.get("appointmentType", [])
|
|
|
for apt in appt_types:
|
|
for apt in appt_types:
|
|
|
- if apt.get("routing_key") == target_routing_key or len(appt_types) == 1:
|
|
|
|
|
|
|
+ if apt.get("routingKey") == slot_routing_key or len(appt_types) == 1:
|
|
|
apt_config = apt
|
|
apt_config = apt
|
|
|
break
|
|
break
|
|
|
|
|
|
|
@@ -292,12 +302,12 @@ class VfsPlugin(IVSPlg):
|
|
|
if ocr_enabled:
|
|
if ocr_enabled:
|
|
|
VSC_INFO("vfs_plg", "[%s] OCR Enabled, uploading documents...", self.group_id)
|
|
VSC_INFO("vfs_plg", "[%s] OCR Enabled, uploading documents...", self.group_id)
|
|
|
upload_res = {}
|
|
upload_res = {}
|
|
|
- if not self._upload_applicant_documents(apt_config, uinfo, upload_res):
|
|
|
|
|
|
|
+ if not self._upload_applicant_documents(apt_config, user_inputs, upload_res):
|
|
|
return res
|
|
return res
|
|
|
- # 回填上传结果到 uinfo,供 add_primary_applicant 使用
|
|
|
|
|
- uinfo["applicant_image"] = upload_res.get("passportImageFilename")
|
|
|
|
|
- uinfo["applicant_image_data"] = upload_res.get("passportImageFileBytes") # Base64
|
|
|
|
|
- uinfo["guid"] = upload_res.get("uploadDocumentGUID")
|
|
|
|
|
|
|
+ # 回填上传结果到 user_inputs,供 add_primary_applicant 使用
|
|
|
|
|
+ user_inputs["applicant_image"] = upload_res.get("passportImageFilename")
|
|
|
|
|
+ user_inputs["applicant_image_data"] = upload_res.get("passportImageFileBytes") # Base64
|
|
|
|
|
+ user_inputs["guid"] = upload_res.get("uploadDocumentGUID")
|
|
|
|
|
|
|
|
# ---------------- 需要提供申请号 (Cover Letter) ----------------
|
|
# ---------------- 需要提供申请号 (Cover Letter) ----------------
|
|
|
enable_reference_number = sub_conf.get("enableReferenceNumber", False)
|
|
enable_reference_number = sub_conf.get("enableReferenceNumber", False)
|
|
@@ -313,7 +323,7 @@ class VfsPlugin(IVSPlg):
|
|
|
|
|
|
|
|
while add_primary_retry < MAX_RETRY:
|
|
while add_primary_retry < MAX_RETRY:
|
|
|
urn = [] # 清空
|
|
urn = [] # 清空
|
|
|
- if self._add_primary_applicant(apt_config, uinfo, is_waitlist, ocr_enabled, enable_reference_number, urn):
|
|
|
|
|
|
|
+ if self._add_primary_applicant(apt_config, user_inputs, is_waitlist, ocr_enabled, enable_reference_number, urn):
|
|
|
success_add = True
|
|
success_add = True
|
|
|
break
|
|
break
|
|
|
|
|
|
|
@@ -364,11 +374,11 @@ class VfsPlugin(IVSPlg):
|
|
|
|
|
|
|
|
# ---------------- 规则引擎与日期筛选 (核心步骤 3) ----------------
|
|
# ---------------- 规则引擎与日期筛选 (核心步骤 3) ----------------
|
|
|
# C++: RuleEngine rule_engine(rules);
|
|
# C++: RuleEngine rule_engine(rules);
|
|
|
- rules_str = uinfo.get("rules", "")
|
|
|
|
|
|
|
+ rules_str = user_inputs.get("rules", "")
|
|
|
rule_engine = RuleEngine(rules_str)
|
|
rule_engine = RuleEngine(rules_str)
|
|
|
|
|
|
|
|
- expected_start = uinfo.get("expected_submit_start", "")
|
|
|
|
|
- expected_end = uinfo.get("expected_submit_end", "")
|
|
|
|
|
|
|
+ expected_start = user_inputs.get("expected_start_date", "")
|
|
|
|
|
+ expected_end = user_inputs.get("expected_end_date", "")
|
|
|
rule_engine.set_date_range_start(expected_start)
|
|
rule_engine.set_date_range_start(expected_start)
|
|
|
rule_engine.set_date_range_end(expected_end)
|
|
rule_engine.set_date_range_end(expected_end)
|
|
|
|
|
|
|
@@ -504,7 +514,9 @@ class VfsPlugin(IVSPlg):
|
|
|
if payment_url:
|
|
if payment_url:
|
|
|
res.payment_link = payment_url
|
|
res.payment_link = payment_url
|
|
|
# 保存 Session (C++ save_http_session)
|
|
# 保存 Session (C++ save_http_session)
|
|
|
- self._save_http_session(payment_url)
|
|
|
|
|
|
|
+ saved_session = self._save_http_session(payment_url)
|
|
|
|
|
+ if saved_session:
|
|
|
|
|
+ res.session_id = saved_session['session_id']
|
|
|
else:
|
|
else:
|
|
|
res.message = "Booking confirmed (No payment required)"
|
|
res.message = "Booking confirmed (No payment required)"
|
|
|
|
|
|
|
@@ -558,10 +570,10 @@ class VfsPlugin(IVSPlg):
|
|
|
|
|
|
|
|
return False
|
|
return False
|
|
|
|
|
|
|
|
- def _upload_applicant_documents(self, apt_config, uinfo, res_out: Dict) -> bool:
|
|
|
|
|
|
|
+ def _upload_applicant_documents(self, apt_config, user_inputs, res_out: Dict) -> bool:
|
|
|
"""上传护照图片"""
|
|
"""上传护照图片"""
|
|
|
url = "https://lift-api.vfsglobal.com/appointment/UploadApplicantDocument"
|
|
url = "https://lift-api.vfsglobal.com/appointment/UploadApplicantDocument"
|
|
|
- passport_url = uinfo.get("passport_image_url")
|
|
|
|
|
|
|
+ passport_url = user_inputs.get("passport_image_url")
|
|
|
if not passport_url:
|
|
if not passport_url:
|
|
|
self._set_error(9007, "Missing passport_image_url")
|
|
self._set_error(9007, "Missing passport_image_url")
|
|
|
return False
|
|
return False
|
|
@@ -609,7 +621,7 @@ class VfsPlugin(IVSPlg):
|
|
|
except:
|
|
except:
|
|
|
return False
|
|
return False
|
|
|
|
|
|
|
|
- def _add_primary_applicant(self, apt_config: Dict[str, Any], uinfo: Dict[str, Any],
|
|
|
|
|
|
|
+ def _add_primary_applicant(self, apt_config: Dict[str, Any], user_inputs: Dict[str, Any],
|
|
|
is_waitlist: bool, ocr_enabled: bool, enable_ref: bool,
|
|
is_waitlist: bool, ocr_enabled: bool, enable_ref: bool,
|
|
|
urn_out_list: List[str]) -> bool:
|
|
urn_out_list: List[str]) -> bool:
|
|
|
"""
|
|
"""
|
|
@@ -622,12 +634,12 @@ class VfsPlugin(IVSPlg):
|
|
|
|
|
|
|
|
# --- 辅助 Helper: 映射性别 ---
|
|
# --- 辅助 Helper: 映射性别 ---
|
|
|
# C++: male/Male -> 1, 否则 -> 2
|
|
# C++: male/Male -> 1, 否则 -> 2
|
|
|
- gender_str = str(uinfo.get("gender", "")).lower()
|
|
|
|
|
|
|
+ gender_str = str(user_inputs.get("gender", "")).lower()
|
|
|
gender_code = 1 if gender_str == "male" else 2
|
|
gender_code = 1 if gender_str == "male" else 2
|
|
|
|
|
|
|
|
# --- 辅助 Helper: 获取 Dial Code ---
|
|
# --- 辅助 Helper: 获取 Dial Code ---
|
|
|
# C++ 逻辑处理了 int 和 string
|
|
# C++ 逻辑处理了 int 和 string
|
|
|
- raw_dial = uinfo.get("phone_country_code", "86")
|
|
|
|
|
|
|
+ raw_dial = user_inputs.get("phone_country_code", "86")
|
|
|
dial_code = str(raw_dial)
|
|
dial_code = str(raw_dial)
|
|
|
|
|
|
|
|
# --- 辅助 Helper: 格式化日期 ---
|
|
# --- 辅助 Helper: 格式化日期 ---
|
|
@@ -639,8 +651,8 @@ class VfsPlugin(IVSPlg):
|
|
|
except:
|
|
except:
|
|
|
return d_str # 原样返回
|
|
return d_str # 原样返回
|
|
|
|
|
|
|
|
- dob = _to_ddmmyyyy(str(uinfo.get("birthday", "")))
|
|
|
|
|
- ppt_exp = _to_ddmmyyyy(str(uinfo.get("passport_expiry_date", "")))
|
|
|
|
|
|
|
+ dob = _to_ddmmyyyy(str(user_inputs.get("birthday", "")))
|
|
|
|
|
+ ppt_exp = _to_ddmmyyyy(str(user_inputs.get("passport_expiry_date", "")))
|
|
|
|
|
|
|
|
# --- 构造单个 Applicant 对象 ---
|
|
# --- 构造单个 Applicant 对象 ---
|
|
|
# 对应 C++ 中庞大的 applicant JSON 构建
|
|
# 对应 C++ 中庞大的 applicant JSON 构建
|
|
@@ -650,31 +662,31 @@ class VfsPlugin(IVSPlg):
|
|
|
"loginUser": self.config.account.username,
|
|
"loginUser": self.config.account.username,
|
|
|
|
|
|
|
|
# 基本信息 (全部大写)
|
|
# 基本信息 (全部大写)
|
|
|
- "firstName": str(uinfo.get("first_name", "")).upper(),
|
|
|
|
|
|
|
+ "firstName": str(user_inputs.get("first_name", "")).upper(),
|
|
|
"middleName": "",
|
|
"middleName": "",
|
|
|
- "lastName": str(uinfo.get("last_name", "")).upper(),
|
|
|
|
|
|
|
+ "lastName": str(user_inputs.get("last_name", "")).upper(),
|
|
|
"employerFirstName": "",
|
|
"employerFirstName": "",
|
|
|
"employerLastName": "",
|
|
"employerLastName": "",
|
|
|
"salutation": "",
|
|
"salutation": "",
|
|
|
"gender": gender_code,
|
|
"gender": gender_code,
|
|
|
|
|
|
|
|
# 联系信息
|
|
# 联系信息
|
|
|
- "contactNumber": str(uinfo.get("phone_no", "")),
|
|
|
|
|
|
|
+ "contactNumber": str(user_inputs.get("phone", "")),
|
|
|
"dialCode": dial_code,
|
|
"dialCode": dial_code,
|
|
|
"employerContactNumber": "",
|
|
"employerContactNumber": "",
|
|
|
"employerDialCode": "",
|
|
"employerDialCode": "",
|
|
|
- "emailId": str(uinfo.get("alias_email", "")).upper(),
|
|
|
|
|
|
|
+ "emailId": str(user_inputs.get("alias_email", "")).upper(),
|
|
|
"employerEmailId": "",
|
|
"employerEmailId": "",
|
|
|
|
|
|
|
|
# 证件信息
|
|
# 证件信息
|
|
|
- "passportNumber": str(uinfo.get("passport_no", "")).upper(),
|
|
|
|
|
|
|
+ "passportNumber": str(user_inputs.get("passport_no", "")).upper(),
|
|
|
"confirmPassportNumber": "", # 通常留空
|
|
"confirmPassportNumber": "", # 通常留空
|
|
|
"passportExpirtyDate": ppt_exp, # 注意拼写 Expirty 是 VFS API 的特征
|
|
"passportExpirtyDate": ppt_exp, # 注意拼写 Expirty 是 VFS API 的特征
|
|
|
"dateOfBirth": dob,
|
|
"dateOfBirth": dob,
|
|
|
"nationalId": None,
|
|
"nationalId": None,
|
|
|
|
|
|
|
|
# 国籍 (使用全局辅助函数 get_country_iso3)
|
|
# 国籍 (使用全局辅助函数 get_country_iso3)
|
|
|
- "nationalityCode": get_country_iso3(str(uinfo.get("nationality", ""))),
|
|
|
|
|
|
|
+ "nationalityCode": get_country_iso3(str(user_inputs.get("nationality", ""))),
|
|
|
|
|
|
|
|
# 地址与其它 (大部分为空)
|
|
# 地址与其它 (大部分为空)
|
|
|
"state": None,
|
|
"state": None,
|
|
@@ -720,16 +732,16 @@ class VfsPlugin(IVSPlg):
|
|
|
|
|
|
|
|
# --- 处理 Reference Number (Cover Letter) ---
|
|
# --- 处理 Reference Number (Cover Letter) ---
|
|
|
if enable_ref:
|
|
if enable_ref:
|
|
|
- applicant["referenceNumber"] = str(uinfo.get("cover_letter", ""))
|
|
|
|
|
|
|
+ applicant["referenceNumber"] = str(user_inputs.get("cover_letter", ""))
|
|
|
else:
|
|
else:
|
|
|
applicant["referenceNumber"] = None
|
|
applicant["referenceNumber"] = None
|
|
|
|
|
|
|
|
# --- 处理 OCR 数据 ---
|
|
# --- 处理 OCR 数据 ---
|
|
|
if ocr_enabled:
|
|
if ocr_enabled:
|
|
|
- # 必须从 uinfo 获取上传后返回的 metadata
|
|
|
|
|
- applicant["applicantImage"] = str(uinfo.get("applicant_image", ""))
|
|
|
|
|
- applicant["applicantImageData"] = str(uinfo.get("applicant_image_data", ""))
|
|
|
|
|
- applicant["GUID"] = str(uinfo.get("guid", ""))
|
|
|
|
|
|
|
+ # 必须从 user_inputs 获取上传后返回的 metadata
|
|
|
|
|
+ applicant["applicantImage"] = str(user_inputs.get("applicant_image", ""))
|
|
|
|
|
+ applicant["applicantImageData"] = str(user_inputs.get("applicant_image_data", ""))
|
|
|
|
|
+ applicant["GUID"] = str(user_inputs.get("guid", ""))
|
|
|
|
|
|
|
|
# --- 构造最外层 Payload ---
|
|
# --- 构造最外层 Payload ---
|
|
|
payload = {
|
|
payload = {
|
|
@@ -1025,9 +1037,9 @@ class VfsPlugin(IVSPlg):
|
|
|
proxy_str += f"{self.config.proxy.ip}:{self.config.proxy.port}"
|
|
proxy_str += f"{self.config.proxy.ip}:{self.config.proxy.port}"
|
|
|
|
|
|
|
|
# 2. 提交任务
|
|
# 2. 提交任务
|
|
|
- task_out = {}
|
|
|
|
|
VSC_INFO("vfs_plg", "[%s] Submitting Turnstile task for %s...", self.group_id, website_url)
|
|
VSC_INFO("vfs_plg", "[%s] Submitting Turnstile task for %s...", self.group_id, website_url)
|
|
|
- if not VSCloudApi.Instance().submit_anti_turnstile_task(proxy_str, website_url, task_out):
|
|
|
|
|
|
|
+ task_out = VSCloudApi.Instance().submit_anti_turnstile_task(proxy_str, website_url)
|
|
|
|
|
+ if not task_out:
|
|
|
self._set_error(9002, "Failed to submit captcha task to Cloud API")
|
|
self._set_error(9002, "Failed to submit captcha task to Cloud API")
|
|
|
return ""
|
|
return ""
|
|
|
|
|
|
|
@@ -1041,8 +1053,8 @@ class VfsPlugin(IVSPlg):
|
|
|
start_time = time.time()
|
|
start_time = time.time()
|
|
|
|
|
|
|
|
while time.time() - start_time < timeout:
|
|
while time.time() - start_time < timeout:
|
|
|
- result_out = {}
|
|
|
|
|
- if not VSCloudApi.Instance().get_anti_turnstile_result(task_id, result_out):
|
|
|
|
|
|
|
+ result_out = VSCloudApi.Instance().get_anti_turnstile_result(task_id)
|
|
|
|
|
+ if not result_out:
|
|
|
# 获取结果的网络请求失败,稍后重试
|
|
# 获取结果的网络请求失败,稍后重试
|
|
|
time.sleep(3)
|
|
time.sleep(3)
|
|
|
continue
|
|
continue
|
|
@@ -1416,21 +1428,19 @@ class VfsPlugin(IVSPlg):
|
|
|
content_out = [] # 用于接收结果的容器
|
|
content_out = [] # 用于接收结果的容器
|
|
|
|
|
|
|
|
# 对应 C++: expiry = 5 * 60 (300秒)
|
|
# 对应 C++: expiry = 5 * 60 (300秒)
|
|
|
- status = VSCloudApi.Instance().fetch_mail_content(
|
|
|
|
|
|
|
+ content_out = VSCloudApi.Instance().fetch_mail_content(
|
|
|
master_email,
|
|
master_email,
|
|
|
sender,
|
|
sender,
|
|
|
recipient,
|
|
recipient,
|
|
|
subject_keywords,
|
|
subject_keywords,
|
|
|
body_keywords,
|
|
body_keywords,
|
|
|
formatted_utc_time,
|
|
formatted_utc_time,
|
|
|
- 300,
|
|
|
|
|
- content_out
|
|
|
|
|
|
|
+ 300
|
|
|
)
|
|
)
|
|
|
|
|
|
|
|
- if status and content_out:
|
|
|
|
|
- content = content_out[0]
|
|
|
|
|
|
|
+ if content_out:
|
|
|
# 4. 正则匹配 6位数字 (对应 C++ std::regex otp_pattern(R"(\b\d{6}\b)"))
|
|
# 4. 正则匹配 6位数字 (对应 C++ std::regex otp_pattern(R"(\b\d{6}\b)"))
|
|
|
- match = re.search(r'\b\d{6}\b', content)
|
|
|
|
|
|
|
+ match = re.search(r'\b\d{6}\b', content_out)
|
|
|
if match:
|
|
if match:
|
|
|
otp = match.group(0)
|
|
otp = match.group(0)
|
|
|
VSC_INFO("vfs_plg", "[%s] OTP code found: %s", self.group_id, otp)
|
|
VSC_INFO("vfs_plg", "[%s] OTP code found: %s", self.group_id, otp)
|
|
@@ -1528,24 +1538,6 @@ class VfsPlugin(IVSPlg):
|
|
|
except Exception as e:
|
|
except Exception as e:
|
|
|
self._set_error(9001, f"OTP Login parse error: {str(e)}")
|
|
self._set_error(9001, f"OTP Login parse error: {str(e)}")
|
|
|
return False
|
|
return False
|
|
|
-
|
|
|
|
|
- def _prepare_user_info(self) -> Dict:
|
|
|
|
|
- return {
|
|
|
|
|
- "first_name": "Jiarui",
|
|
|
|
|
- "last_name": "Hu",
|
|
|
|
|
- "passport_no": "E91829352",
|
|
|
|
|
- "phone_country_code": 86,
|
|
|
|
|
- "phone_no": "17386033452",
|
|
|
|
|
- "email": "arket_zz@163.com",
|
|
|
|
|
- "alias_email": "arket_zz@gmail-app.com",
|
|
|
|
|
- "birthday": "1990-01-01",
|
|
|
|
|
- "passport_expiry_date": "2030-01-01",
|
|
|
|
|
- "nationality": "China",
|
|
|
|
|
- "gender": "Male",
|
|
|
|
|
- "expected_submit_start": "2026-01-01",
|
|
|
|
|
- "expected_submit_end": "2026-03-15",
|
|
|
|
|
- "rules": "time_filter = AM,PM\nallowed_weekdays = 1,2,3,4,5,6,7"
|
|
|
|
|
- }
|
|
|
|
|
|
|
|
|
|
def _submit_no_addition_service(self, urn) -> bool:
|
|
def _submit_no_addition_service(self, urn) -> bool:
|
|
|
url = "https://lift-api.vfsglobal.com/vas/mapvas"
|
|
url = "https://lift-api.vfsglobal.com/vas/mapvas"
|
|
@@ -1673,15 +1665,23 @@ class VfsPlugin(IVSPlg):
|
|
|
session_id = hashes.Hash(hashes.SHA256(), backend=default_backend())
|
|
session_id = hashes.Hash(hashes.SHA256(), backend=default_backend())
|
|
|
session_id.update(raw.encode())
|
|
session_id.update(raw.encode())
|
|
|
sid = session_id.finalize().hex()
|
|
sid = session_id.finalize().hex()
|
|
|
|
|
+
|
|
|
|
|
+ proxy_str = ""
|
|
|
|
|
+ if self.config.proxy.ip:
|
|
|
|
|
+ proxy_str = f"{self.config.proxy.scheme}://"
|
|
|
|
|
+ if self.config.proxy.username:
|
|
|
|
|
+ proxy_str += f"{self.config.proxy.username}:{self.config.proxy.password}@"
|
|
|
|
|
+ proxy_str += f"{self.config.proxy.ip}:{self.config.proxy.port}"
|
|
|
|
|
|
|
|
- dummy_res = {}
|
|
|
|
|
- # 代理可能是 None,处理一下
|
|
|
|
|
- proxy_ip = self.config.proxy.ip if self.config.proxy else ""
|
|
|
|
|
-
|
|
|
|
|
- VSCloudApi.Instance().create_http_session(
|
|
|
|
|
- sid, cookies_str, "", ua_str, proxy_ip, page_url, dummy_res
|
|
|
|
|
|
|
+ saved_session = VSCloudApi.Instance().create_http_session(
|
|
|
|
|
+ sid, cookies_str, "", ua_str, proxy_str, page_url
|
|
|
)
|
|
)
|
|
|
- VSC_INFO("vfs_plg", "[%s] Session saved. ID: %s", self.group_id, sid)
|
|
|
|
|
|
|
+ if saved_session:
|
|
|
|
|
+ VSC_INFO("vfs_plg", "[%s] Session saved. ID: %s", self.group_id, sid)
|
|
|
|
|
+ else:
|
|
|
|
|
+ VSC_ERROR("vfs_plg", "[%s] Session save failed. ID: %s", self.group_id, sid)
|
|
|
|
|
+ return saved_session
|
|
|
except Exception as e:
|
|
except Exception as e:
|
|
|
# 捕获异常,确保即使保存 Session 失败,也不影响主流程返回预订结果
|
|
# 捕获异常,确保即使保存 Session 失败,也不影响主流程返回预订结果
|
|
|
VSC_WARN("vfs_plg", "[%s] Failed to save session to cloud: %s", self.group_id, str(e))
|
|
VSC_WARN("vfs_plg", "[%s] Failed to save session to cloud: %s", self.group_id, str(e))
|
|
|
|
|
+ return None
|