Skip to content

Commit 7abf13a

Browse files
authored
Merge pull request #19 from zouyonghe/main
fix(desktop): stabilize packaged WebUI routing and tray restart bridge on macOS
2 parents 692fb6c + 0f16d0d commit 7abf13a

3 files changed

Lines changed: 207 additions & 18 deletions

File tree

src-tauri/src/main.rs

Lines changed: 126 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -304,20 +304,27 @@ impl BackendState {
304304
.clone()
305305
.unwrap_or_else(|| backend_dir.to_path_buf())
306306
});
307-
let webui_dir = env::var("ASTRBOT_WEBUI_DIR")
307+
let embedded_webui_dir = env::var("ASTRBOT_WEBUI_DIR")
308308
.ok()
309309
.map(PathBuf::from)
310310
.or_else(|| {
311311
resolve_resource_path(app, "webui/index.html")
312312
.and_then(|index_path| index_path.parent().map(Path::to_path_buf))
313313
});
314+
let webui_dir = resolve_packaged_webui_dir(embedded_webui_dir, root_dir.as_deref())?;
315+
316+
let args = vec![
317+
launch_script_path.to_string_lossy().to_string(),
318+
"--webui-dir".to_string(),
319+
webui_dir.to_string_lossy().to_string(),
320+
];
314321

315322
let plan = LaunchPlan {
316323
cmd: python_path.to_string_lossy().to_string(),
317-
args: vec![launch_script_path.to_string_lossy().to_string()],
324+
args,
318325
cwd,
319326
root_dir,
320-
webui_dir,
327+
webui_dir: Some(webui_dir),
321328
packaged_mode: true,
322329
};
323330
Ok(Some(plan))
@@ -1176,7 +1183,10 @@ fn main() {
11761183
})
11771184
.on_page_load(|webview, payload| match payload.event() {
11781185
PageLoadEvent::Started => {
1179-
append_desktop_log(&format!("page-load started: {}", payload.url()))
1186+
append_desktop_log(&format!("page-load started: {}", payload.url()));
1187+
if should_inject_desktop_bridge(webview.app_handle(), payload.url()) {
1188+
inject_desktop_bridge(webview);
1189+
}
11801190
}
11811191
PageLoadEvent::Finished => {
11821192
append_desktop_log(&format!("page-load finished: {}", payload.url()));
@@ -1622,6 +1632,14 @@ fn update_tray_menu_labels(app_handle: &AppHandle) {
16221632

16231633
const DESKTOP_BRIDGE_BOOTSTRAP_SCRIPT: &str = r#"
16241634
(() => {
1635+
if (
1636+
window.astrbotDesktop &&
1637+
window.astrbotDesktop.__tauriBridge === true &&
1638+
typeof window.astrbotDesktop.onTrayRestartBackend === 'function'
1639+
) {
1640+
return;
1641+
}
1642+
16251643
const invoke = window.__TAURI_INTERNALS__?.invoke;
16261644
if (typeof invoke !== 'function') return;
16271645
@@ -1998,7 +2016,7 @@ fn should_inject_desktop_bridge(app_handle: &AppHandle, page_url: &Url) -> bool
19982016
let Ok(backend_url) = Url::parse(&state.backend_url) else {
19992017
return false;
20002018
};
2001-
same_origin(&backend_url, page_url)
2019+
tray_origin_decision(&backend_url, page_url).uses_backend_origin
20022020
}
20032021

20042022
fn inject_desktop_bridge(webview: &tauri::Webview<tauri::Wry>) {
@@ -2160,6 +2178,109 @@ fn default_packaged_root_dir() -> Option<PathBuf> {
21602178
dirs::home_dir().map(|home| home.join(".astrbot"))
21612179
}
21622180

2181+
fn packaged_fallback_webui_probe_dir(root_dir: Option<&Path>) -> Option<PathBuf> {
2182+
match root_dir {
2183+
Some(root) => Some(root.join("data").join("dist")),
2184+
None => default_packaged_root_dir().map(|root| root.join("data").join("dist")),
2185+
}
2186+
}
2187+
2188+
fn packaged_fallback_webui_dir(root_dir: Option<&Path>) -> Option<PathBuf> {
2189+
let candidate = packaged_fallback_webui_probe_dir(root_dir)?;
2190+
if candidate.join("index.html").is_file() {
2191+
Some(candidate)
2192+
} else {
2193+
None
2194+
}
2195+
}
2196+
2197+
fn packaged_fallback_webui_index_display(root_dir: Option<&Path>) -> String {
2198+
packaged_fallback_webui_probe_dir(root_dir)
2199+
.map(|path| path.join("index.html").display().to_string())
2200+
.unwrap_or_else(|| "<unresolved>".to_string())
2201+
}
2202+
2203+
fn packaged_webui_unavailable_error(locale: &str, embedded_index: Option<&Path>) -> String {
2204+
if locale == "en-US" {
2205+
if let Some(index) = embedded_index {
2206+
return format!(
2207+
"Packaged WebUI is unavailable. Missing embedded index at {} and fallback data/dist. Please reinstall AstrBot or download the matching dist.zip to data/dist.",
2208+
index.display()
2209+
);
2210+
}
2211+
return "Packaged WebUI directory is missing and fallback data/dist is unavailable. Please reinstall AstrBot or download the matching dist.zip to data/dist."
2212+
.to_string();
2213+
}
2214+
2215+
if let Some(index) = embedded_index {
2216+
return format!(
2217+
"内置 WebUI 不可用。缺少内置入口文件:{},且回退目录 data/dist 也不可用。请重装 AstrBot,或下载匹配版本的 dist.zip 到 data/dist。",
2218+
index.display()
2219+
);
2220+
}
2221+
2222+
"内置 WebUI 目录缺失,且回退目录 data/dist 也不可用。请重装 AstrBot,或下载匹配版本的 dist.zip 到 data/dist。".to_string()
2223+
}
2224+
2225+
fn resolve_packaged_webui_dir(
2226+
embedded_webui_dir: Option<PathBuf>,
2227+
root_dir: Option<&Path>,
2228+
) -> Result<PathBuf, String> {
2229+
let locale = resolve_shell_locale();
2230+
let fallback_webui_dir = packaged_fallback_webui_dir(root_dir);
2231+
2232+
match embedded_webui_dir {
2233+
Some(candidate) => {
2234+
let embedded_index = candidate.join("index.html");
2235+
if embedded_index.is_file() {
2236+
return Ok(candidate);
2237+
}
2238+
2239+
append_desktop_log(&format!(
2240+
"packaged webui index is missing at {}, trying fallback data/dist",
2241+
embedded_index.display()
2242+
));
2243+
2244+
if let Some(fallback) = fallback_webui_dir {
2245+
append_desktop_log(&format!(
2246+
"using fallback webui directory: {}",
2247+
fallback.display()
2248+
));
2249+
return Ok(fallback);
2250+
}
2251+
2252+
let fallback_index = packaged_fallback_webui_index_display(root_dir);
2253+
append_desktop_log(&format!(
2254+
"packaged webui resolution failed: embedded index missing at {}, fallback index missing at {}",
2255+
embedded_index.display(),
2256+
fallback_index
2257+
));
2258+
2259+
Err(packaged_webui_unavailable_error(
2260+
locale,
2261+
Some(&embedded_index),
2262+
))
2263+
}
2264+
None => {
2265+
if let Some(fallback) = fallback_webui_dir {
2266+
append_desktop_log(&format!(
2267+
"embedded webui directory not found, using fallback webui directory: {}",
2268+
fallback.display()
2269+
));
2270+
return Ok(fallback);
2271+
}
2272+
2273+
let fallback_index = packaged_fallback_webui_index_display(root_dir);
2274+
append_desktop_log(&format!(
2275+
"packaged webui resolution failed: embedded webui directory is missing, fallback index missing at {}",
2276+
fallback_index
2277+
));
2278+
2279+
Err(packaged_webui_unavailable_error(locale, None))
2280+
}
2281+
}
2282+
}
2283+
21632284
fn resolve_backend_timeout_ms(packaged_mode: bool) -> Option<Duration> {
21642285
let default_timeout_ms = if packaged_mode { 0_u64 } else { 20_000_u64 };
21652286
let parsed_timeout_ms = env::var("ASTRBOT_BACKEND_TIMEOUT_MS")

src-tauri/windows/kill-backend-processes.ps1

Lines changed: 70 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -10,26 +10,85 @@ if ([string]::IsNullOrWhiteSpace($InstallDir)) {
1010
}
1111

1212
try {
13-
$installRoot = [System.IO.Path]::GetFullPath($InstallDir).TrimEnd([char]92).ToLowerInvariant()
13+
$installRootRaw = [System.IO.Path]::GetFullPath($InstallDir).TrimEnd([char]92)
1414
} catch {
1515
exit 0
1616
}
1717

18-
if ([string]::IsNullOrWhiteSpace($installRoot)) {
18+
if ([string]::IsNullOrWhiteSpace($installRootRaw)) {
1919
exit 0
2020
}
2121

22+
$installRoot = $installRootRaw
2223
$installRootWithSep = $installRoot + [string][char]92
24+
$currentPid = $PID
25+
$targetProcessNames = @(
26+
"python.exe",
27+
"pythonw.exe",
28+
"astrbot-desktop-tauri.exe",
29+
"astrbot.exe"
30+
)
31+
32+
function Test-IsUnderInstallRoot {
33+
param(
34+
[Parameter(Mandatory = $false)]
35+
[string]$PathValue
36+
)
37+
38+
if ([string]::IsNullOrWhiteSpace($PathValue)) {
39+
return $false
40+
}
41+
42+
try {
43+
$normalized = [System.IO.Path]::GetFullPath($PathValue).TrimEnd([char]92)
44+
return $normalized -ieq $installRoot -or $normalized.StartsWith($installRootWithSep, [System.StringComparison]::OrdinalIgnoreCase)
45+
} catch {
46+
return $false
47+
}
48+
}
49+
50+
function Get-CommandExecutablePath {
51+
param(
52+
[Parameter(Mandatory = $false)]
53+
[string]$CommandLine
54+
)
55+
56+
if ([string]::IsNullOrWhiteSpace($CommandLine)) {
57+
return $null
58+
}
59+
60+
$trimmed = $CommandLine.Trim()
61+
if ($trimmed.StartsWith('"')) {
62+
$endQuote = $trimmed.IndexOf('"', 1)
63+
if ($endQuote -gt 1) {
64+
return $trimmed.Substring(1, $endQuote - 1)
65+
}
66+
return $null
67+
}
68+
69+
$firstSpace = $trimmed.IndexOf(' ')
70+
if ($firstSpace -gt 0) {
71+
return $trimmed.Substring(0, $firstSpace)
72+
}
73+
return $trimmed
74+
}
75+
76+
$nameFilter = ($targetProcessNames | ForEach-Object { "Name='$_'" }) -join " OR "
2377

24-
Get-CimInstance Win32_Process -Filter "Name='python.exe' OR Name='pythonw.exe'" |
25-
Where-Object { $_.ExecutablePath } |
78+
Get-CimInstance Win32_Process -Filter $nameFilter |
2679
ForEach-Object {
27-
try {
28-
$exePath = [System.IO.Path]::GetFullPath($_.ExecutablePath).ToLowerInvariant()
29-
if ($exePath -eq $installRoot -or $exePath.StartsWith($installRootWithSep)) {
30-
Stop-Process -Id $_.ProcessId -Force -ErrorAction SilentlyContinue
31-
}
32-
} catch {
33-
# Ignore per-process path errors and continue cleanup.
80+
if ($_.ProcessId -eq $currentPid) {
81+
return
82+
}
83+
84+
$shouldStop = Test-IsUnderInstallRoot -PathValue $_.ExecutablePath
85+
86+
if (-not $shouldStop) {
87+
$commandExePath = Get-CommandExecutablePath -CommandLine $_.CommandLine
88+
$shouldStop = Test-IsUnderInstallRoot -PathValue $commandExePath
89+
}
90+
91+
if ($shouldStop) {
92+
Stop-Process -Id $_.ProcessId -Force -ErrorAction SilentlyContinue
3493
}
3594
}

src-tauri/windows/nsis-installer-hooks.nsh

Lines changed: 11 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
1-
!macro NSIS_HOOK_PREUNINSTALL
2-
; Ensure packaged backend processes do not keep install files locked during uninstall.
1+
!macro NSIS_RUN_BACKEND_CLEANUP
2+
; Ensure packaged backend processes do not keep install files locked.
33
StrCpy $0 "$SYSDIR\WindowsPowerShell\v1.0\powershell.exe"
44
IfFileExists "$0" +2 0
55
StrCpy $0 "powershell.exe"
@@ -12,6 +12,15 @@
1212
DetailPrint "Skip backend process cleanup: script not found: $1"
1313
!macroend
1414

15+
!macro NSIS_HOOK_PREINSTALL
16+
; Stop old app/backend processes before overwriting files during upgrades.
17+
!insertmacro NSIS_RUN_BACKEND_CLEANUP
18+
!macroend
19+
20+
!macro NSIS_HOOK_PREUNINSTALL
21+
!insertmacro NSIS_RUN_BACKEND_CLEANUP
22+
!macroend
23+
1524
!macro NSIS_HOOK_POSTINSTALL
1625
; Recreate shortcuts to avoid stale links when users migrate from older installers.
1726
StrCpy $0 "$INSTDIR\${MAINBINARYNAME}.exe"

0 commit comments

Comments
 (0)