Compare commits

...

5 Commits

Author SHA1 Message Date
e3283fff45 updated sdk 2026-09-13 18:51:05 -07:00
64ed5981be v1.1.35 2026-09-07 11:26:23 -07:00
ba8266bd86 fixed files not downloading properly 2026-09-07 11:21:39 -07:00
bb39db0272 v1.1.34 2026-09-06 19:37:27 -07:00
d799da3d2a v1.1.33 2026-09-06 11:01:48 -07:00
10 changed files with 92 additions and 32 deletions

4
.gitignore vendored
View File

@@ -35,4 +35,6 @@ yarn-error.log*
*.tmp
*.temp
download-temp.zip
download-temp.zip
.env

View File

@@ -172,7 +172,6 @@ function validatePayload(zipPath) {
zip.extractAllTo(TEMP_EXTRACT_DIR, true);
const requiredFiles = [
'player/server.js',
'frontend/index.html'
];

48
main.js
View File

@@ -216,18 +216,20 @@ async function start() {
debugLog(`Is First Run: ${isFirstRun}, Local Version: ${localVersion}, Local SHA: ${localSha}`);
function findLocalZip() {
const searchRoots = [__dirname, process.cwd()];
const searchRoots = [__dirname, process.cwd(), path.join(__dirname, '../../..')];
for (const root of searchRoots) {
let cur = root;
for (let i = 0; i < 6; i++) {
const zp = path.join(cur, 'update-payload.zip');
if (fs.existsSync(zp)) {
const mp = path.join(cur, 'manifest.json');
return { zipPath: zp, manifestPath: fs.existsSync(mp) ? mp : null };
}
const parent = path.dirname(cur);
if (parent === cur) break;
cur = parent;
try {
const zp = path.join(cur, 'update-payload.zip');
if (fs.existsSync(zp)) {
const mp = path.join(cur, 'manifest.json');
return { zipPath: zp, manifestPath: fs.existsSync(mp) ? mp : null };
}
const parent = path.dirname(cur);
if (parent === cur) break;
cur = parent;
} catch (e) { }
}
}
return null;
@@ -309,12 +311,24 @@ async function start() {
debugLog("Update available. Prompting user...");
sendToTauri('status', { message: `New update available (${release.version}). Awaiting confirmation...` });
try {
if (process.platform === 'win32') {
require('child_process').spawnSync('powershell.exe', [
'-NoProfile', '-NonInteractive', '-Command',
`Get-NetTCPConnection -LocalPort 4891 -ErrorAction SilentlyContinue | ForEach-Object { Stop-Process -Id $_.OwningProcess -Force }`
], { stdio: 'ignore', windowsHide: true });
} else {
require('child_process').spawnSync('fuser', ['-k', '-9', `4891/tcp`], { stdio: 'ignore' });
}
} catch (e) { }
const tempApp = express();
let userDecision = null;
tempApp.use((req, res, next) => {
res.header('Access-Control-Allow-Origin', '*');
res.header('Access-Control-Allow-Methods', 'GET,POST,OPTIONS');
res.header('Access-Control-Allow-Headers', '*');
res.header('Connection', 'close');
if (req.method === 'OPTIONS') return res.sendStatus(200);
next();
});
@@ -326,15 +340,27 @@ async function start() {
const tempServer = await new Promise((resolve) => {
const s = tempApp.listen(4891, '127.0.0.1', () => resolve(s));
s.on('error', (err) => {
debugLog(`Update server bind error: ${err.message}`);
resolve(null);
});
});
sendToTauri('update-available', { current: localVersion, latest: release.version });
let waitLoops = 0;
while (userDecision === null) {
if (!tempServer && waitLoops > 400) {
userDecision = false;
break;
}
waitLoops++;
await new Promise(r => setTimeout(r, 25));
}
await new Promise((resolve) => tempServer.close(resolve));
if (tempServer) {
tempServer.close();
}
if (userDecision) {
debugLog("User accepted update.");
@@ -374,7 +400,7 @@ async function start() {
sendToTauri('status', { message: 'Validating critical components...' });
if (!patcher.verifyExtraction()) {
throw new Error('No application files found. Ensure you run "npm run build:payload" to generate the local development payload.');
throw new Error('No application files found. Ensure you ran "npm run build:payload" and the extraction succeeded.');
}
sendToTauri('status', { message: 'Loading encrypted credentials...' });

View File

@@ -1,6 +1,6 @@
{
"name": "vyla-home",
"version": "1.1.32",
"version": "1.1.35",
"description": "Vyla Home Desktop App Launcher",
"main": "main.js",
"scripts": {
@@ -15,7 +15,7 @@
"@tauri-apps/plugin-opener": "^2.0.0",
"@tauri-apps/plugin-process": "^2.0.0",
"@tauri-apps/plugin-shell": "^2.0.0",
"@vyla-entertainment/sdk": "^1.11.0",
"@vyla-entertainment/sdk": "^1.12.0",
"adm-zip": "^0.6.0",
"express": "^4.19.2"
},
@@ -54,4 +54,4 @@
"installerHeaderIcon": "build/icon.ico"
}
}
}
}

View File

@@ -84,8 +84,25 @@ class Patcher {
}
extractZipPayload(zipPath) {
const AdmZip = require('adm-zip');
const zip = new AdmZip(zipPath);
const entries = zip.getEntries();
if (!entries || entries.length === 0) {
throw new Error('Downloaded archive is empty, invalid, or truncated.');
}
zip.extractAllTo(this.appDataPath, true);
const testPath = path.join(this.appDataPath, 'frontend', 'index.html');
if (!fs.existsSync(testPath)) {
const { execSync } = require('child_process');
if (process.platform === 'win32') {
execSync(`powershell.exe -NoProfile -NonInteractive -Command "Expand-Archive -Path '${zipPath}' -DestinationPath '${this.appDataPath}' -Force"`, { windowsHide: true });
} else {
execSync(`unzip -o "${zipPath}" -d "${this.appDataPath}"`);
}
}
}
verifyChecksum(zipPath, expectedSha256) {
@@ -99,8 +116,8 @@ class Patcher {
verifyExtraction() {
const requiredFiles = [
'player/server.js',
'frontend/index.html'
'frontend/index.html',
'player/server.js'
];
for (const file of requiredFiles) {
@@ -112,12 +129,16 @@ class Patcher {
if (stat.size === 0) {
return false;
}
const sampleSize = Math.min(stat.size, 4096);
const fd = fs.openSync(fullPath, 'r');
const buffer = Buffer.alloc(sampleSize);
fs.readSync(fd, buffer, 0, sampleSize, 0);
fs.closeSync(fd);
if (buffer.every(byte => byte === 0)) {
try {
const sampleSize = Math.min(stat.size, 4096);
const fd = fs.openSync(fullPath, 'r');
const buffer = Buffer.alloc(sampleSize);
fs.readSync(fd, buffer, 0, sampleSize, 0);
fs.closeSync(fd);
if (buffer.every(byte => byte === 0)) {
return false;
}
} catch (e) {
return false;
}
}

2
src-tauri/Cargo.lock generated
View File

@@ -4238,7 +4238,7 @@ dependencies = [
[[package]]
name = "vyla-home"
version = "1.1.32"
version = "1.1.35"
dependencies = [
"base64 0.22.1",
"objc2 0.5.2",

View File

@@ -1,6 +1,6 @@
[package]
name = "vyla-home"
version = "1.1.32"
version = "1.1.35"
description = "Vyla Home Desktop App Launcher"
edition = "2021"

View File

@@ -831,7 +831,12 @@ fn main() {
let msg = match serde_json::from_str::<BackendMessage>(&line) {
Ok(m) => m,
Err(_) => continue,
Err(_) => {
if !line.trim().is_empty() {
debug_log(&format!("[NODE RAW] {}", line));
}
continue;
}
};
debug_log(&format!("[MAIN-DEBUG] Received event: {}", msg.event));

View File

@@ -1,7 +1,7 @@
{
"$schema": "https://schema.tauri.app/config/2",
"productName": "Vyla Home",
"version": "1.1.32",
"version": "1.1.35",
"identifier": "com.vyla.home",
"build": {
"frontendDist": "../ui"
@@ -45,4 +45,4 @@
"../node_modules/**/*"
]
}
}
}

View File

@@ -136,7 +136,14 @@ class UpdateClient {
});
file.on('finish', () => {
file.close(resolve);
file.close(() => {
if (totalSize && downloadedSize < totalSize) {
fs.unlink(destPath, () => { });
reject(new Error(`Download truncated: Received ${downloadedSize} of ${totalSize} bytes. Connection dropped prematurely.`));
} else {
resolve();
}
});
});
file.on('error', (err) => {
@@ -150,10 +157,10 @@ class UpdateClient {
reject(err);
});
req.setTimeout(120000, () => {
req.setTimeout(900000, () => {
req.destroy();
fs.unlink(destPath, () => { });
reject(new Error('Download timeout'));
reject(new Error('Download timeout (15 minutes reached)'));
});
};