mirror of
https://gitlab.com/vyla-entertainment/home.git
synced 2026-11-14 14:17:25 -05:00
Compare commits
2 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| ba8266bd86 | |||
| bb39db0272 |
4
.gitignore
vendored
4
.gitignore
vendored
@@ -35,4 +35,6 @@ yarn-error.log*
|
|||||||
|
|
||||||
*.tmp
|
*.tmp
|
||||||
*.temp
|
*.temp
|
||||||
download-temp.zip
|
download-temp.zip
|
||||||
|
|
||||||
|
.env
|
||||||
@@ -172,7 +172,6 @@ function validatePayload(zipPath) {
|
|||||||
zip.extractAllTo(TEMP_EXTRACT_DIR, true);
|
zip.extractAllTo(TEMP_EXTRACT_DIR, true);
|
||||||
|
|
||||||
const requiredFiles = [
|
const requiredFiles = [
|
||||||
'player/server.js',
|
|
||||||
'frontend/index.html'
|
'frontend/index.html'
|
||||||
];
|
];
|
||||||
|
|
||||||
|
|||||||
48
main.js
48
main.js
@@ -216,18 +216,20 @@ async function start() {
|
|||||||
debugLog(`Is First Run: ${isFirstRun}, Local Version: ${localVersion}, Local SHA: ${localSha}`);
|
debugLog(`Is First Run: ${isFirstRun}, Local Version: ${localVersion}, Local SHA: ${localSha}`);
|
||||||
|
|
||||||
function findLocalZip() {
|
function findLocalZip() {
|
||||||
const searchRoots = [__dirname, process.cwd()];
|
const searchRoots = [__dirname, process.cwd(), path.join(__dirname, '../../..')];
|
||||||
for (const root of searchRoots) {
|
for (const root of searchRoots) {
|
||||||
let cur = root;
|
let cur = root;
|
||||||
for (let i = 0; i < 6; i++) {
|
for (let i = 0; i < 6; i++) {
|
||||||
const zp = path.join(cur, 'update-payload.zip');
|
try {
|
||||||
if (fs.existsSync(zp)) {
|
const zp = path.join(cur, 'update-payload.zip');
|
||||||
const mp = path.join(cur, 'manifest.json');
|
if (fs.existsSync(zp)) {
|
||||||
return { zipPath: zp, manifestPath: fs.existsSync(mp) ? mp : null };
|
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;
|
const parent = path.dirname(cur);
|
||||||
cur = parent;
|
if (parent === cur) break;
|
||||||
|
cur = parent;
|
||||||
|
} catch (e) { }
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return null;
|
return null;
|
||||||
@@ -309,12 +311,24 @@ async function start() {
|
|||||||
debugLog("Update available. Prompting user...");
|
debugLog("Update available. Prompting user...");
|
||||||
sendToTauri('status', { message: `New update available (${release.version}). Awaiting confirmation...` });
|
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();
|
const tempApp = express();
|
||||||
let userDecision = null;
|
let userDecision = null;
|
||||||
tempApp.use((req, res, next) => {
|
tempApp.use((req, res, next) => {
|
||||||
res.header('Access-Control-Allow-Origin', '*');
|
res.header('Access-Control-Allow-Origin', '*');
|
||||||
res.header('Access-Control-Allow-Methods', 'GET,POST,OPTIONS');
|
res.header('Access-Control-Allow-Methods', 'GET,POST,OPTIONS');
|
||||||
res.header('Access-Control-Allow-Headers', '*');
|
res.header('Access-Control-Allow-Headers', '*');
|
||||||
|
res.header('Connection', 'close');
|
||||||
if (req.method === 'OPTIONS') return res.sendStatus(200);
|
if (req.method === 'OPTIONS') return res.sendStatus(200);
|
||||||
next();
|
next();
|
||||||
});
|
});
|
||||||
@@ -326,15 +340,27 @@ async function start() {
|
|||||||
|
|
||||||
const tempServer = await new Promise((resolve) => {
|
const tempServer = await new Promise((resolve) => {
|
||||||
const s = tempApp.listen(4891, '127.0.0.1', () => resolve(s));
|
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 });
|
sendToTauri('update-available', { current: localVersion, latest: release.version });
|
||||||
|
|
||||||
|
let waitLoops = 0;
|
||||||
while (userDecision === null) {
|
while (userDecision === null) {
|
||||||
|
if (!tempServer && waitLoops > 400) {
|
||||||
|
userDecision = false;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
waitLoops++;
|
||||||
await new Promise(r => setTimeout(r, 25));
|
await new Promise(r => setTimeout(r, 25));
|
||||||
}
|
}
|
||||||
|
|
||||||
await new Promise((resolve) => tempServer.close(resolve));
|
if (tempServer) {
|
||||||
|
tempServer.close();
|
||||||
|
}
|
||||||
|
|
||||||
if (userDecision) {
|
if (userDecision) {
|
||||||
debugLog("User accepted update.");
|
debugLog("User accepted update.");
|
||||||
@@ -374,7 +400,7 @@ async function start() {
|
|||||||
|
|
||||||
sendToTauri('status', { message: 'Validating critical components...' });
|
sendToTauri('status', { message: 'Validating critical components...' });
|
||||||
if (!patcher.verifyExtraction()) {
|
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...' });
|
sendToTauri('status', { message: 'Loading encrypted credentials...' });
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
{
|
{
|
||||||
"name": "vyla-home",
|
"name": "vyla-home",
|
||||||
"version": "1.1.33",
|
"version": "1.1.34",
|
||||||
"description": "Vyla Home Desktop App Launcher",
|
"description": "Vyla Home Desktop App Launcher",
|
||||||
"main": "main.js",
|
"main": "main.js",
|
||||||
"scripts": {
|
"scripts": {
|
||||||
|
|||||||
37
patcher.js
37
patcher.js
@@ -84,8 +84,25 @@ class Patcher {
|
|||||||
}
|
}
|
||||||
|
|
||||||
extractZipPayload(zipPath) {
|
extractZipPayload(zipPath) {
|
||||||
|
const AdmZip = require('adm-zip');
|
||||||
const zip = new AdmZip(zipPath);
|
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);
|
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) {
|
verifyChecksum(zipPath, expectedSha256) {
|
||||||
@@ -99,8 +116,8 @@ class Patcher {
|
|||||||
|
|
||||||
verifyExtraction() {
|
verifyExtraction() {
|
||||||
const requiredFiles = [
|
const requiredFiles = [
|
||||||
'player/server.js',
|
'frontend/index.html',
|
||||||
'frontend/index.html'
|
'player/server.js'
|
||||||
];
|
];
|
||||||
|
|
||||||
for (const file of requiredFiles) {
|
for (const file of requiredFiles) {
|
||||||
@@ -112,12 +129,16 @@ class Patcher {
|
|||||||
if (stat.size === 0) {
|
if (stat.size === 0) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
const sampleSize = Math.min(stat.size, 4096);
|
try {
|
||||||
const fd = fs.openSync(fullPath, 'r');
|
const sampleSize = Math.min(stat.size, 4096);
|
||||||
const buffer = Buffer.alloc(sampleSize);
|
const fd = fs.openSync(fullPath, 'r');
|
||||||
fs.readSync(fd, buffer, 0, sampleSize, 0);
|
const buffer = Buffer.alloc(sampleSize);
|
||||||
fs.closeSync(fd);
|
fs.readSync(fd, buffer, 0, sampleSize, 0);
|
||||||
if (buffer.every(byte => byte === 0)) {
|
fs.closeSync(fd);
|
||||||
|
if (buffer.every(byte => byte === 0)) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
} catch (e) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
2
src-tauri/Cargo.lock
generated
2
src-tauri/Cargo.lock
generated
@@ -4238,7 +4238,7 @@ dependencies = [
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "vyla-home"
|
name = "vyla-home"
|
||||||
version = "1.1.33"
|
version = "1.1.34"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"base64 0.22.1",
|
"base64 0.22.1",
|
||||||
"objc2 0.5.2",
|
"objc2 0.5.2",
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
[package]
|
[package]
|
||||||
name = "vyla-home"
|
name = "vyla-home"
|
||||||
version = "1.1.33"
|
version = "1.1.34"
|
||||||
description = "Vyla Home Desktop App Launcher"
|
description = "Vyla Home Desktop App Launcher"
|
||||||
edition = "2021"
|
edition = "2021"
|
||||||
|
|
||||||
|
|||||||
@@ -831,7 +831,12 @@ fn main() {
|
|||||||
|
|
||||||
let msg = match serde_json::from_str::<BackendMessage>(&line) {
|
let msg = match serde_json::from_str::<BackendMessage>(&line) {
|
||||||
Ok(m) => m,
|
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));
|
debug_log(&format!("[MAIN-DEBUG] Received event: {}", msg.event));
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
{
|
{
|
||||||
"$schema": "https://schema.tauri.app/config/2",
|
"$schema": "https://schema.tauri.app/config/2",
|
||||||
"productName": "Vyla Home",
|
"productName": "Vyla Home",
|
||||||
"version": "1.1.33",
|
"version": "1.1.34",
|
||||||
"identifier": "com.vyla.home",
|
"identifier": "com.vyla.home",
|
||||||
"build": {
|
"build": {
|
||||||
"frontendDist": "../ui"
|
"frontendDist": "../ui"
|
||||||
|
|||||||
@@ -136,7 +136,14 @@ class UpdateClient {
|
|||||||
});
|
});
|
||||||
|
|
||||||
file.on('finish', () => {
|
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) => {
|
file.on('error', (err) => {
|
||||||
@@ -150,10 +157,10 @@ class UpdateClient {
|
|||||||
reject(err);
|
reject(err);
|
||||||
});
|
});
|
||||||
|
|
||||||
req.setTimeout(120000, () => {
|
req.setTimeout(900000, () => {
|
||||||
req.destroy();
|
req.destroy();
|
||||||
fs.unlink(destPath, () => { });
|
fs.unlink(destPath, () => { });
|
||||||
reject(new Error('Download timeout'));
|
reject(new Error('Download timeout (15 minutes reached)'));
|
||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user