fix: daw_engine khong chay tren Windows - bundle resources sai layout

Spawn.log cho thay: resource_dir()/daw_engine/daw_engine.exe exists=false
tren ca ban cai lan target/release - engine KHONG duoc bundle dung cho.

Goc re (doc source tauri-utils/src/resources.rs + tauri-cli/src/interface/rust.rs):
- bundle.resources dang ARRAY ['resources/daw_engine']: ResourcePaths::new
  (Slice) -> target = resource_relpath(path) GIU TIEN TO 'resources/'
  -> engine nam o /resources/daw_engine/...
- lib.rs cu tim o /daw_engine/... -> exists=false.

Fix:
- tauri.conf.json: resources dang MAP {'resources/daw_engine': 'daw_engine/'}
  -> resources_map -> Walk mode, dest.join(strip_prefix) -> giu nguyen cay
  _internal, dich chuan /daw_engine/ (xac nhan tauri-cli
  BundleResources::Map -> settings.resources_map, dong 1467-1469).
- lib.rs: do them 3 vi tri fallback (legacy resources/ prefix, portable
  exe_dir, dev exe_dir/../resources) + log diagnostic day du vao spawn.log
  (liet ke noi dung resource_dir/exe_dir khi khong tim thay).
- build_windows.ps1: them huong dan xac minh spawn.log sau khi cai dat.
This commit is contained in:
2026-08-09 10:48:09 +00:00
parent 29ebbfc1c0
commit 0c0aadb8ee
4 changed files with 139 additions and 34 deletions
+120 -31
View File
@@ -1,34 +1,90 @@
// SonicForge DAW — desktop shell: spawn/terminate daw_engine.exe sidecar.
// SonicForge DAW — desktop shell: spawn/terminate daw_engine sidecar.
//
// QUAN TRONG (fix bản 1.1.1 — engine không chạy trên Windows):
// tauri.conf.json bundle.resources giờ dùng dạng MAP:
// { "resources/daw_engine": "daw_engine/" }
// vì dạng ARRAY ("resources/daw_engine") copy file tới
// $RESOURCE_DIR/resources/daw_engine/... (giữ tiền tố "resources/"),
// trong khi code cũ tìm ở $RESOURCE_DIR/daw_engine/... -> exists=false.
// Dạng map (Walk mode) giữ nguyên cây thư mục (_internal) dưới đích
// "daw_engine/" — đúng layout lib.rs chờ.
// Ngoài ra lib.rs còn dò THÊM các vị trí fallback (legacy/portable/dev)
// và ghi đầy đủ diagnostic vào %APPDATA%/SonicForgeDAW/logs/spawn.log.
use tauri::Manager;
use tauri_plugin_shell::process::CommandChild;
use tauri_plugin_shell::ShellExt;
use std::path::{Path, PathBuf};
use std::sync::Mutex;
struct EngineProcess(Mutex<Option<CommandChild>>);
/// Các vị trí có thể chứa daw_engine, theo thứ tự ưu tiên.
fn engine_candidates(res_dir: &Path, exe_dir: &Path) -> Vec<(PathBuf, String)> {
let exe_name = if cfg!(windows) { "daw_engine.exe" } else { "daw_engine" };
vec![
// 1. Layout chuẩn (resources map): $RESOURCE/daw_engine/daw_engine.exe
(
res_dir.join("daw_engine").join(exe_name),
"resource_dir/daw_engine (map layout)".into(),
),
// 2. Legacy (resources array cũ giữ tiền tố resources/)
(
res_dir.join("resources").join("daw_engine").join(exe_name),
"resource_dir/resources/daw_engine (legacy array)".into(),
),
// 3. Portable: engine đặt cạnh exe
(
exe_dir.join("daw_engine").join(exe_name),
"exe_dir/daw_engine (portable)".into(),
),
// 4. Dev mode: target/{debug,release} -> src-tauri/resources
(
exe_dir.join("..").join("resources").join("daw_engine").join(exe_name),
"exe_dir/../resources/daw_engine (dev)".into(),
),
]
}
fn list_dir_snippet(dir: &Path) -> String {
let mut s = String::new();
match std::fs::read_dir(dir) {
Ok(rd) => {
let mut n = 0;
for e in rd.flatten() {
if n > 0 {
s.push_str(", ");
}
s.push_str(&e.file_name().to_string_lossy());
n += 1;
if n >= 15 {
s.push_str(", ...");
break;
}
}
}
Err(_) => s.push_str("<khong doc duoc dir>"),
}
s
}
#[cfg_attr(mobile, tauri::mobile_entry_point)]
pub fn run() {
tauri::Builder::default()
.plugin(tauri_plugin_shell::init())
.plugin(tauri_plugin_dialog::init())
.setup(|app| {
// 1. Spawn daw_engine (PyInstaller ONEDIR bundle — khong giai nen
// moi lan chay nhu onefile, khoi dong nhanh). Bundle qua Tauri
// resources: resource_dir()/daw_engine/daw_engine(.exe)
let res_dir = app
.path()
.resource_dir()
.expect("resource dir not found");
let engine_dir = res_dir.join("daw_engine");
let engine_exe = if cfg!(windows) {
engine_dir.join("daw_engine.exe")
} else {
engine_dir.join("daw_engine")
};
// Ghi log spawn de chan doan (UI khong duoc panic/thoat — chi log).
// Ghi vao %APPDATA%/SonicForgeDAW/logs/spawn.log (thu muc luon ton
// tai) — KHONG ghi vao engine_dir vi thu muc do co the khong duoc
// bundle vao installer (resources loi) -> ghi am tham that bai.
let exe_dir = std::env::current_exe()
.ok()
.and_then(|p| p.parent().map(|d| d.to_path_buf()))
.unwrap_or_default();
let candidates = engine_candidates(&res_dir, &exe_dir);
// Ghi log spawn de chan doan — vao %APPDATA%/SonicForgeDAW/logs/
// spawn.log (thu muc luon ton tai), KHONG ghi vao engine_dir.
let log_dir = std::env::var("APPDATA").unwrap_or_else(|_| ".".into());
let spawn_log_path = std::path::Path::new(&log_dir)
.join("SonicForgeDAW")
@@ -37,12 +93,31 @@ pub fn run() {
if let Some(parent) = spawn_log_path.parent() {
let _ = std::fs::create_dir_all(parent);
}
let log_line = format!(
"spawn daw_engine: {} exists={}\nresource_dir={}\n",
engine_exe.display(),
engine_exe.exists(),
res_dir.display()
let mut log_line = format!(
"resource_dir={}\nexe_dir={}\n",
res_dir.display(),
exe_dir.display()
);
let mut found: Option<(PathBuf, String)> = None;
for (path, label) in &candidates {
let exists = path.exists();
log_line.push_str(&format!(
" [{label}] {} exists={}\n",
path.display(),
exists
));
if found.is_none() && exists {
found = Some((path.clone(), label.clone()));
}
}
if found.is_none() {
log_line.push_str(&format!(
" NOT FOUND — resource_dir contents: {}\n exe_dir contents: {}\n",
list_dir_snippet(&res_dir),
list_dir_snippet(&exe_dir)
));
}
if let Ok(mut f) = std::fs::OpenOptions::new()
.create(true)
.append(true)
@@ -51,26 +126,40 @@ pub fn run() {
use std::io::Write;
let _ = f.write_all(log_line.as_bytes());
}
match app.shell().command(&engine_exe)
.env("SF_PARENT_PID", std::process::id().to_string())
.spawn() {
Ok((_rx, child)) => {
app.manage(EngineProcess(Mutex::new(Some(child))));
println!("Python Background Engine started (localhost:8000, auto-fallback 8000-8010)");
match found {
Some((engine_exe, label)) => {
match app
.shell()
.command(&engine_exe)
.env("SF_PARENT_PID", std::process::id().to_string())
.spawn()
{
Ok((_rx, child)) => {
app.manage(EngineProcess(Mutex::new(Some(child))));
println!(
"Python Background Engine started ({label}): {}",
engine_exe.display()
);
}
Err(e) => {
println!("Failed to spawn daw_engine {engine_exe:?}: {e}");
app.manage(EngineProcess(Mutex::new(None)));
}
}
}
Err(e) => {
// Khong panic: UI van mo, engine loi se hien trong UI loader
// ("Khong tim thay SonicForge Engine"). Log ro de chan doan.
println!("Failed to spawn daw_engine: {e}");
None => {
println!(
"daw_engine binary not found in any candidate path — xem spawn.log de biet chi tiet"
);
app.manage(EngineProcess(Mutex::new(None)));
}
}
Ok(())
})
.on_window_event(|window, event| {
// 2. Terminate sidecar khi DAW window dong — tranh orphan process
// Terminate sidecar khi DAW window dong — tranh orphan process
if let tauri::WindowEvent::Destroyed = event {
// Lay child ra khoi lock, guard drop ngay tai day (trach E0597)
let child = window
.state::<EngineProcess>()
.0
+3 -3
View File
@@ -32,9 +32,9 @@
"icons/128x128@2x.png",
"icons/favicon.ico"
],
"resources": [
"resources/daw_engine"
],
"resources": {
"resources/daw_engine": "daw_engine/"
},
"externalBin": [],
"windows": {
"nsis": {