Completely rewrote the code, home builds locally rather on Gitlab, releases are done manually aswell

This commit is contained in:
2026-08-21 14:32:59 -07:00
parent 103e080664
commit cee165ddfa
12 changed files with 993 additions and 588 deletions

View File

@@ -3,22 +3,61 @@
use std::path::PathBuf;
use std::process::{Child, Command, Stdio};
use std::sync::Mutex;
use tauri::{Manager, State, WebviewUrl, WebviewWindowBuilder};
use tauri::{Emitter, Manager, State, WebviewUrl, WebviewWindowBuilder};
fn debug_log(msg: &str) {
if let Ok(user_profile) = std::env::var("USERPROFILE") {
let log_path = std::path::Path::new(&user_profile).join("Downloads").join("vyla-rust-debug.log");
if let Ok(mut file) = std::fs::OpenOptions::new().create(true).append(true).open(&log_path) {
use std::io::Write;
let _ = writeln!(file, "[RUST] {}", msg);
}
}
}
struct NodeServices(Mutex<Option<Child>>);
#[derive(serde::Deserialize)]
#[derive(serde::Deserialize, serde::Serialize, Clone)]
struct BackendMessage {
event: String,
data: serde_json::Value,
}
fn get_project_root() -> PathBuf {
// Helper to remove the \\?\ prefix that Node.js chokes on
fn clean_path(path: &std::path::Path) -> String {
let s = path.to_string_lossy().to_string();
if s.starts_with("\\\\?\\") {
s[4..].to_string()
} else {
s
}
}
fn resolve_script_and_root(app: &tauri::App) -> (String, String) {
if let Ok(resource_dir) = app.path().resource_dir() {
debug_log(&format!("Resource dir found: {:?}", resource_dir));
let candidates = vec![
resource_dir.join("main.js"),
resource_dir.join("_up_").join("main.js"),
];
for candidate in candidates {
if candidate.exists() {
debug_log(&format!("main.js found at: {:?}", candidate));
let root_dir = candidate.parent().unwrap();
return (clean_path(&candidate), clean_path(root_dir));
}
}
}
let mut dir = std::env::current_dir().unwrap_or_else(|_| PathBuf::from("."));
if dir.ends_with("src-tauri") {
dir.pop();
}
dir
let candidate = dir.join("main.js");
debug_log(&format!("Fallback script path: {:?}", candidate));
(clean_path(&candidate), clean_path(&dir))
}
const LINK_HANDLER_SCRIPT: &str = r#"
@@ -54,33 +93,39 @@ const LINK_HANDLER_SCRIPT: &str = r#"
"#;
fn main() {
debug_log("=== Vyla Home Executable Started ===");
tauri::Builder::default()
.plugin(tauri_plugin_shell::init())
.plugin(tauri_plugin_process::init())
.plugin(tauri_plugin_opener::init())
.manage(NodeServices(Mutex::new(None)))
.setup(|app| {
debug_log("Tauri setup started");
let app_data = app.path().app_data_dir().unwrap_or_default();
let app_data_str = app_data.to_string_lossy().to_string();
let app_data_str = clean_path(&app_data);
debug_log(&format!("AppData path: {}", app_data_str));
let window = WebviewWindowBuilder::new(app, "main", WebviewUrl::App("index.html".into()))
.title("Vyla Home")
.inner_size(1280.0, 800.0)
.decorations(true)
.resizable(true)
.fullscreen(false)
.initialization_script(LINK_HANDLER_SCRIPT)
.build()?;
debug_log("Webview created");
let root_dir = get_project_root();
let main_js = root_dir.join("main.js");
let (main_js, root_dir) = resolve_script_and_root(app);
debug_log(&format!("Spawning node with script: {}", main_js));
let mut cmd = Command::new("node");
cmd.arg(&main_js)
.current_dir(&root_dir)
.env("APPDATA_PATH", &app_data_str)
.stdout(Stdio::piped())
.stderr(Stdio::inherit());
.stderr(Stdio::piped());
#[cfg(windows)]
{
@@ -89,29 +134,45 @@ fn main() {
cmd.creation_flags(CREATE_NO_WINDOW);
}
if let Ok(mut child) = cmd.spawn() {
if let Some(stdout) = child.stdout.take() {
let w = window.clone();
std::thread::spawn(move || {
use std::io::{BufRead, BufReader};
let reader = BufReader::new(stdout);
for line in reader.lines().flatten() {
println!("{}", line);
if let Ok(msg) = serde_json::from_str::<BackendMessage>(&line) {
if msg.event == "ready" {
if let Some(url) = msg.data.get("url").and_then(|u| u.as_str()) {
let _ = w.eval(&format!("window.location.href = '{}';", url));
match cmd.spawn() {
Ok(mut child) => {
debug_log("Node spawned successfully");
if let Some(stdout) = child.stdout.take() {
let w = window.clone();
std::thread::spawn(move || {
use std::io::{BufRead, BufReader};
let reader = BufReader::new(stdout);
for line in reader.lines().flatten() {
debug_log(&format!("Node stdout: {}", line));
if let Ok(msg) = serde_json::from_str::<BackendMessage>(&line) {
let _ = w.emit(&msg.event, msg.data.clone());
if msg.event == "ready" {
if let Some(url) = msg.data.get("url").and_then(|u| u.as_str()) {
let _ = w.eval(&format!("window.location.href = '{}';", url));
}
}
}
}
}
});
}
});
}
if let Some(stderr) = child.stderr.take() {
std::thread::spawn(move || {
use std::io::{BufRead, BufReader};
let reader = BufReader::new(stderr);
for line in reader.lines().flatten() {
debug_log(&format!("Node STDERR: {}", line));
}
});
}
let state: State<NodeServices> = app.state();
if let Ok(mut lock) = state.0.lock() {
*lock = Some(child);
};
let state: State<NodeServices> = app.state();
if let Ok(mut lock) = state.0.lock() {
*lock = Some(child);
};
}
Err(e) => {
debug_log(&format!("FAILED to spawn Node: {}", e));
}
}
Ok(())

View File

@@ -21,6 +21,16 @@
"icons/128x128@2x.png",
"icons/icon.icns",
"icons/icon.ico"
],
"resources": [
"../main.js",
"../service-manager.js",
"../patcher.js",
"../crypto-utils.js",
"../credential-manager.js",
"../update-client.js",
"../config/**/*",
"../node_modules/**/*"
]
}
}