Skip to content

Commit 93ea5d0

Browse files
committed
Починил обновление Xray на разных дисках. Сделал нормальную диагностику падения Xray на FakeDNS. Добавил раннее предупреждение в валидацию Xray-конфига. Прогнал точечную проверку изменений.
1 parent cd74b38 commit 93ea5d0

4 files changed

Lines changed: 86 additions & 37 deletions

File tree

xray_fluent/app_controller.py

Lines changed: 10 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -868,7 +868,16 @@ def validate_singbox_json_text(self, text: str) -> tuple[bool, str]:
868868
return self.validate_json_text(text)
869869

870870
def validate_xray_json_text(self, text: str) -> tuple[bool, str]:
871-
return self.validate_json_text(text)
871+
ok, message = self.validate_json_text(text)
872+
if not ok:
873+
return False, message
874+
if "fakedns" in text.lower():
875+
return (
876+
True,
877+
"JSON корректен. Внимание: в конфиге есть FakeDNS; некоторые версии Xray-core могут падать на старте. "
878+
"Если запуск завершается с panic, отключите FakeDNS или обновите Xray core.",
879+
)
880+
return True, message
872881

873882
def apply_singbox_config_text(self, text: str) -> tuple[bool, Path | None, str]:
874883
ok, message = self.validate_json_text(text)

xray_fluent/ui/main_window.py

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -650,7 +650,10 @@ def _save_core_config(self, core: str, text: str) -> None:
650650
self._show_status("success", f"Сохранено: {path.name}")
651651

652652
def _validate_core_config(self, core: str, text: str) -> None:
653-
ok, message = self.controller.validate_json_text(text)
653+
if core == "singbox":
654+
ok, message = self.controller.validate_singbox_json_text(text)
655+
else:
656+
ok, message = self.controller.validate_xray_json_text(text)
654657
self.configs_page.set_status(core, "success" if ok else "error", message)
655658
if ok:
656659
self._show_status("success", "JSON корректен")

xray_fluent/xray_core_updater.py

Lines changed: 36 additions & 34 deletions
Original file line numberDiff line numberDiff line change
@@ -265,40 +265,42 @@ def _install_zip_archive(archive_path: Path, target_xray_path: Path) -> None:
265265

266266
backup_dir = temp_dir / "_install_backup"
267267
backup_dir.mkdir(parents=True, exist_ok=True)
268-
staged_targets: list[tuple[Path, Path, Path | None]] = []
269-
270-
temp_target = target_xray_path.with_suffix(".exe.new")
271-
shutil.copy2(new_xray, temp_target)
272-
backup_copy: Path | None = None
273-
if target_xray_path.exists():
274-
backup_copy = backup_dir / target_xray_path.name
275-
shutil.copy2(target_xray_path, backup_copy)
276-
staged_targets.append((target_xray_path, temp_target, backup_copy))
277-
278-
for optional_name in ("geoip.dat", "geosite.dat", "wintun.dll"):
279-
src = _find_file(temp_dir, optional_name)
280-
if src:
281-
dest = target_dir / optional_name
282-
staged = temp_dir / f"{optional_name}.new"
283-
shutil.copy2(src, staged)
284-
backup_copy = None
285-
if dest.exists():
286-
backup_copy = backup_dir / optional_name
287-
shutil.copy2(dest, backup_copy)
288-
staged_targets.append((dest, staged, backup_copy))
289-
290-
replaced_targets: list[tuple[Path, Path | None]] = []
291-
try:
292-
for dest, staged, backup_copy in staged_targets:
293-
staged.replace(dest)
294-
replaced_targets.append((dest, backup_copy))
295-
except Exception:
296-
for dest, backup_copy in reversed(replaced_targets):
297-
if backup_copy is not None:
298-
shutil.copy2(backup_copy, dest)
299-
elif dest.exists():
300-
dest.unlink()
301-
raise
268+
with tempfile.TemporaryDirectory(prefix=".xray_install_", dir=target_dir) as stage_dir_str:
269+
stage_dir = Path(stage_dir_str)
270+
staged_targets: list[tuple[Path, Path, Path | None]] = []
271+
272+
staged_xray = stage_dir / target_xray_path.name
273+
shutil.copy2(new_xray, staged_xray)
274+
backup_copy: Path | None = None
275+
if target_xray_path.exists():
276+
backup_copy = backup_dir / target_xray_path.name
277+
shutil.copy2(target_xray_path, backup_copy)
278+
staged_targets.append((target_xray_path, staged_xray, backup_copy))
279+
280+
for optional_name in ("geoip.dat", "geosite.dat", "wintun.dll"):
281+
src = _find_file(temp_dir, optional_name)
282+
if src:
283+
dest = target_dir / optional_name
284+
staged = stage_dir / optional_name
285+
shutil.copy2(src, staged)
286+
backup_copy = None
287+
if dest.exists():
288+
backup_copy = backup_dir / optional_name
289+
shutil.copy2(dest, backup_copy)
290+
staged_targets.append((dest, staged, backup_copy))
291+
292+
replaced_targets: list[tuple[Path, Path | None]] = []
293+
try:
294+
for dest, staged, backup_copy in staged_targets:
295+
staged.replace(dest)
296+
replaced_targets.append((dest, backup_copy))
297+
except Exception:
298+
for dest, backup_copy in reversed(replaced_targets):
299+
if backup_copy is not None:
300+
shutil.copy2(backup_copy, dest)
301+
elif dest.exists():
302+
dest.unlink()
303+
raise
302304

303305
original_xray = staged_targets[0][2]
304306
if original_xray is not None:

xray_fluent/xray_manager.py

Lines changed: 36 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -363,7 +363,10 @@ def _unexpected_exit_message(
363363
startup: bool,
364364
) -> str:
365365
stage = "во время запуска" if startup else "неожиданно"
366-
detail = self._last_output_lines[-1].strip() if self._last_output_lines else ""
366+
diagnostic = self._diagnose_output_failure(stage)
367+
if diagnostic:
368+
return diagnostic
369+
detail = self._best_output_detail()
367370
if detail:
368371
return f"Xray завершился {stage}: {detail}"
369372
if exit_code is None:
@@ -377,6 +380,38 @@ def _report_startup_failure(self, message: str) -> None:
377380
self._startup_failure_reported = True
378381
self.error.emit(message)
379382

383+
def _best_output_detail(self) -> str:
384+
if not self._last_output_lines:
385+
return ""
386+
preferred_markers = ("panic:", "[xray-error]", "error", "failed", "invalid", "not found")
387+
for line in reversed(self._last_output_lines):
388+
clean = line.strip()
389+
lower = clean.lower()
390+
if any(marker in lower for marker in preferred_markers):
391+
return clean
392+
for line in reversed(self._last_output_lines):
393+
clean = line.strip()
394+
lower = clean.lower()
395+
if not clean:
396+
continue
397+
if clean.startswith("github.com/") or lower.startswith("goroutine ") or lower.startswith("[signal"):
398+
continue
399+
return clean
400+
return self._last_output_lines[-1].strip()
401+
402+
def _diagnose_output_failure(self, stage: str) -> str | None:
403+
if not self._last_output_lines:
404+
return None
405+
joined = "\n".join(self._last_output_lines).lower()
406+
if "fakednspostprocessingstage" not in joined and "fakedns" not in joined:
407+
return None
408+
if "panic:" not in joined and "nil pointer dereference" not in joined:
409+
return None
410+
return (
411+
f"Xray завершился {stage}: текущий Xray core упал на секции FakeDNS в конфиге. "
412+
"Отключите FakeDNS в Xray JSON, сбросьте конфиг на шаблон по умолчанию или обновите Xray core."
413+
)
414+
380415

381416
def get_xray_version(xray_path: str) -> str | None:
382417
exe = resolve_configured_path(

0 commit comments

Comments
 (0)