CodeVetter · Repo Unpack · Behavior traces
clash-verge-rev/clash-verge-rev
Startup is a singleton check, then a Tauri setup that always tries to open a window even if pre-init panics, then resolve_setup which starts the core in parallel with tray, hotkeys, timers, and the updater. The primary proxy action is a Mihomo select followed by a profile selection write and a tray refresh. Persistence of a subscription is download, append to profiles.yaml, then a forced enhance-and-apply. Quitting is not window-close: close hides the window, and a real exit runs feat::quit, which can cancel if the core will not stop.
- Before the Tauri builder, Windows runs preinit_app_data_dir and owner_identity::repair_app_data_root_owner. Every platform then calls server::check_singleton. Primary continues; Secondary returns exit code success with no error dialog; a lock or bind error returns failure.
- check_singleton locks singleton-instance.lock, binds 127.0.0.1 on the previous port or port 0, writes singleton-instance.json {port, token}, and starts the warp server before the UI exists. A second process POSTs to the primary and exits.
- setup() sets APP_HANDLE, calls init_work_dir_and_logger (init_config then logger::init), autostart, deep links, and window state inside a panic catch. A second catch always runs resolve_setup_async, resolve_setup_sync, and init_signal so a pre-init panic still attempts the window and core.
- resolve_setup order is migrate_short_update_intervals, macOS dock policy, startup_script, ServiceManager::detect_startup_status, Config::init_config_before_window, WindowManager::create_window (skipped visibly when enable_silent_start), reconcile_startup_tun_availability, init_resources, init_dns_config, Config::init_runtime_config, verify_config_initialization, then a join of core init, tray, timer, hotkey, auto lightweight, auto backup, and silent updater, then Handle::refresh_clash and tray update_part.
- CoreManager::init retries start_core up to 3 times when Config::resolve_startup_mixed_port reports a fallback. start_core takes the config-update flag, then start_core_inner: if ServiceStatus is Ready it calls start_core_by_service; if not installed or sidecar-allowed it calls start_core_by_sidecar. On Windows a service start failure can fall through to the sidecar and spawn_service_handoff_watcher.
- RunEvent::Ready calls set_commands_ready, which opens the embedded visible and scheme routes. macOS reopen while in lightweight mode calls exit_lightweight_mode; otherwise it shows the main window. CloseRequested on the main window prevent_close and hides the window.
- ExitRequested prevent_exit when lightweight mode is on, or when the event has no exit code, in which case it block_on feat::quit. feat::quit sets is_exiting, Config::apply_all_and_save_file, stops the core, shuts down the embedded server, and app_handle.exit. If the core does not stop it clears is_exiting, emits app_quit::core_stop_failed, and returns ShutdownOutcome::Canceled.
- Unpreventable RunEvent::Exit (Windows session end) sets is_exiting if needed and runs feat::clean_session_ending_best_effort, then flushes logs. clash_verge_signal::register(feat::quit) is installed from init_signal.
- Manual subscription import: cmd::import_profile -> PrfItem::from_url -> profiles_append_item_safe -> profiles_save_file_safe -> Timer::global().refresh -> Handle::notify_profile_changed. Failures use codes PROFILE_IMPORT_FAILED. The URL is masked in the tracing span.
- Applying profiles: cmd::enhance_profiles -> feat::enhance_profiles -> CoreManager::update_config_forced -> update_config_with_force(true) -> perform_config_update. Busy and exiting short-circuit as ValidationOutcome::Busy or Skipped. A valid outcome also calls Config::sync_dns_override.
- Verge setting changes: patch_verge_config -> feat::patch_verge -> apply_verge_patch_locked, which begins a DraftTransaction, edit_draft patch_config, process_terminated_flags, commit, refresh_verge, refresh auto-backup, and save_file unless not_save_file. TUN patches then call reconcile_tun_availability. System-proxy patches attach FailedOperation::SystemProxyEnable or SystemProxyDisable.
- If startup_script in verge config is a path ending in .sh, .ps1, or .bat, init::startup_script runs bash or powershell on that path via tauri_plugin_shell during resolve_setup, using the script's parent as the working directory.
- First-boot runtime validation failure does not abort startup. Config::init_runtime_config logs the outcome and CoreManager::use_default_config replaces the runtime with a minimal config, emitting config_validate::boot_error, process_terminated, or error.