mirror of
https://gitlab.com/vyla-entertainment/home.git
synced 2026-11-13 13:47:21 -05:00
Completely rewrote the code, home builds locally rather on Gitlab, releases are done manually aswell
This commit is contained in:
127
main.js
127
main.js
@@ -6,6 +6,13 @@ const ServiceManager = require('./service-manager');
|
||||
const Patcher = require('./patcher');
|
||||
const UpdateClient = require('./update-client');
|
||||
|
||||
const debugLogPath = path.join(os.homedir(), 'Downloads', 'vyla-node-debug.log');
|
||||
function debugLog(msg) {
|
||||
try { fs.appendFileSync(debugLogPath, `[NODE] ${msg}\n`, 'utf8'); } catch (e) { }
|
||||
}
|
||||
|
||||
debugLog("--- Node.js Process Started ---");
|
||||
|
||||
let serviceManager;
|
||||
let expressApp;
|
||||
let expressServer;
|
||||
@@ -14,30 +21,32 @@ let playerExpressServer;
|
||||
|
||||
const APPDATA_DIR = process.env.APPDATA_PATH || path.join(os.homedir(), 'AppData', 'Roaming', 'vyla-home', 'vyla-home-files');
|
||||
fs.mkdirSync(APPDATA_DIR, { recursive: true });
|
||||
console.log(`[DEBUG] AppData directory: ${APPDATA_DIR}`);
|
||||
debugLog(`AppData Dir: ${APPDATA_DIR}`);
|
||||
|
||||
const envConfig = JSON.parse(fs.readFileSync(path.join(__dirname, 'config/env.json'), 'utf8'));
|
||||
const replacementsConfig = JSON.parse(fs.readFileSync(path.join(__dirname, 'config/replacements.json'), 'utf8'));
|
||||
|
||||
const updateClient = new UpdateClient(APPDATA_DIR);
|
||||
|
||||
process.on('unhandledRejection', (reason) => {
|
||||
const message = reason && reason.message ? reason.message : String(reason);
|
||||
console.error(`[ERROR] Unhandled Rejection: ${message}`);
|
||||
fs.appendFileSync(path.join(APPDATA_DIR, 'crash.log'), `[${new Date().toISOString()}] UNHANDLED REJECTION: ${message}\n`, 'utf8');
|
||||
});
|
||||
|
||||
process.on('uncaughtException', (err) => {
|
||||
console.error(`[ERROR] Uncaught Exception: ${err.message}`);
|
||||
fs.appendFileSync(path.join(APPDATA_DIR, 'crash.log'), `[${new Date().toISOString()}] UNCAUGHT EXCEPTION: ${err.message}\n`, 'utf8');
|
||||
});
|
||||
|
||||
function sendToTauri(event, data) {
|
||||
debugLog(`Emitting to Tauri: [${event}] -> ${JSON.stringify(data)}`);
|
||||
process.stdout.write(JSON.stringify({ event, data }) + '\n');
|
||||
}
|
||||
|
||||
process.on('unhandledRejection', (reason) => {
|
||||
const message = reason && reason.message ? reason.message : String(reason);
|
||||
debugLog(`UNHANDLED REJECTION: ${message}`);
|
||||
sendToTauri('error', { message });
|
||||
});
|
||||
|
||||
process.on('uncaughtException', (err) => {
|
||||
debugLog(`UNCAUGHT EXCEPTION: ${err.message}`);
|
||||
sendToTauri('error', { message: err.message });
|
||||
});
|
||||
|
||||
async function start() {
|
||||
console.log('[DEBUG] Initializing patcher and service manager...');
|
||||
debugLog("Inside start() function");
|
||||
sendToTauri('status', { message: 'Initializing patcher...' });
|
||||
const patcher = new Patcher(APPDATA_DIR);
|
||||
serviceManager = new ServiceManager(APPDATA_DIR, envConfig);
|
||||
|
||||
@@ -49,17 +58,22 @@ async function start() {
|
||||
while (attempts < 3 && !downloadSuccess) {
|
||||
attempts++;
|
||||
try {
|
||||
console.log(`[DEBUG] Downloading update, attempt ${attempts}...`);
|
||||
debugLog(`Attempting to download update (Attempt ${attempts})...`);
|
||||
sendToTauri('status', { message: `Downloading update (Attempt ${attempts}/3)...` });
|
||||
|
||||
await updateClient.downloadUpdate(release, tempZipPath, (downloaded, total) => {
|
||||
const percent = Math.round((downloaded / total) * 100);
|
||||
const percent = total > 0 ? Math.round((downloaded / total) * 100) : 0;
|
||||
sendToTauri('download-progress', { downloaded, total, percent });
|
||||
});
|
||||
|
||||
debugLog('Download complete. Verifying checksum...');
|
||||
sendToTauri('status', { message: 'Verifying payload checksum...' });
|
||||
if (!patcher.verifyChecksum(tempZipPath, release.sha256)) {
|
||||
throw new Error('SHA-256 checksum verification failed.');
|
||||
}
|
||||
|
||||
console.log('[DEBUG] Extracting payload and applying patches...');
|
||||
debugLog('Checksum verified. Extracting...');
|
||||
sendToTauri('status', { message: 'Extracting update files...' });
|
||||
patcher.purgeOldCode();
|
||||
patcher.extractZipPayload(tempZipPath);
|
||||
|
||||
@@ -67,14 +81,22 @@ async function start() {
|
||||
throw new Error('Extraction verification failed: critical startup files missing.');
|
||||
}
|
||||
|
||||
debugLog('Extraction complete. Applying patches...');
|
||||
sendToTauri('status', { message: 'Applying patches & configuring...' });
|
||||
patcher.applyPatches(replacementsConfig);
|
||||
patcher.bridgeCredentials(serviceManager.credentialManager);
|
||||
patcher.saveCurrentVersion(release.version, release.sha256);
|
||||
|
||||
fs.unlinkSync(tempZipPath);
|
||||
if (fs.existsSync(tempZipPath)) {
|
||||
fs.unlinkSync(tempZipPath);
|
||||
}
|
||||
downloadSuccess = true;
|
||||
debugLog('Update installed successfully!');
|
||||
} catch (err) {
|
||||
if (fs.existsSync(tempZipPath)) fs.unlinkSync(tempZipPath);
|
||||
debugLog(`Download/Install error on attempt ${attempts}: ${err.message}`);
|
||||
if (fs.existsSync(tempZipPath)) {
|
||||
try { fs.unlinkSync(tempZipPath); } catch (e) { }
|
||||
}
|
||||
if (attempts >= 3) {
|
||||
throw new Error(`Failed to download and verify build after 3 attempts: ${err.message}`);
|
||||
}
|
||||
@@ -87,88 +109,95 @@ async function start() {
|
||||
const isFirstRun = !patcher.verifyExtraction();
|
||||
const localVersion = patcher.getCurrentVersion();
|
||||
const localSha = patcher.getCurrentSha();
|
||||
console.log(`[DEBUG] Local version: ${localVersion}, isFirstRun: ${isFirstRun}`);
|
||||
debugLog(`Is First Run: ${isFirstRun}, Local Version: ${localVersion}`);
|
||||
|
||||
sendToTauri('status', { message: 'Checking for updates...' });
|
||||
let release = null;
|
||||
try {
|
||||
debugLog("Fetching updates from updateClient...");
|
||||
release = await updateClient.checkForUpdates();
|
||||
debugLog(`Update check finished. Found: ${release ? release.version : 'None'}`);
|
||||
} catch (e) {
|
||||
console.warn('[DEBUG] Could not check for remote updates:', e.message);
|
||||
debugLog(`Update check failed (offline?): ${e.message}`);
|
||||
}
|
||||
|
||||
if (release) {
|
||||
const hasUpdate = release.version !== localVersion || (release.sha256 && release.sha256 !== localSha);
|
||||
if (isFirstRun || hasUpdate) {
|
||||
console.log('[DEBUG] Performing update install from release...');
|
||||
debugLog("Update required or first run. Installing remote build...");
|
||||
await installBuild(release);
|
||||
} else {
|
||||
debugLog("Already on the latest version.");
|
||||
}
|
||||
} else if (isFirstRun) {
|
||||
debugLog("No remote release found, but it's the first run. Looking for local update-payload.zip...");
|
||||
const localZip = path.join(__dirname, 'update-payload.zip');
|
||||
console.log(`[DEBUG] Checking local zip at: ${localZip} (exists: ${fs.existsSync(localZip)})`);
|
||||
if (fs.existsSync(path.join(__dirname, 'update-payload.zip'))) {
|
||||
const localZip = path.join(__dirname, 'update-payload.zip');
|
||||
console.log('[DEBUG] Syncing local update-payload.zip to AppData...');
|
||||
if (fs.existsSync(localZip)) {
|
||||
sendToTauri('status', { message: 'Extracting initial local payload...' });
|
||||
patcher.purgeOldCode();
|
||||
patcher.extractZipPayload(localZip);
|
||||
patcher.applyPatches(replacementsConfig);
|
||||
patcher.bridgeCredentials(serviceManager.credentialManager);
|
||||
patcher.saveCurrentVersion("1.0.0");
|
||||
debugLog("Local payload extracted successfully.");
|
||||
} else {
|
||||
debugLog("No local payload found!");
|
||||
}
|
||||
}
|
||||
|
||||
const verified = patcher.verifyExtraction();
|
||||
console.log(`[DEBUG] Payload verification status: ${verified}`);
|
||||
if (!verified) {
|
||||
throw new Error('No application files found. Build the payload first using "npm run build:payload" or check your internet connection.');
|
||||
if (!patcher.verifyExtraction()) {
|
||||
throw new Error('No application files found. Check your internet connection and try again.');
|
||||
}
|
||||
|
||||
console.log('[DEBUG] Loading credentials...');
|
||||
sendToTauri('status', { message: 'Loading credentials...' });
|
||||
serviceManager.credentialManager.loadCredentials();
|
||||
|
||||
console.log('[DEBUG] Starting auth-proxy and stream-api...');
|
||||
sendToTauri('status', { message: 'Starting backend services...' });
|
||||
await serviceManager.startServices([
|
||||
{ name: 'auth-proxy', relativeDir: 'auth-proxy' },
|
||||
{ name: 'stream-api', relativeDir: 'stream-api' },
|
||||
]);
|
||||
debugLog("Backend services spawn requested.");
|
||||
|
||||
const playerDir = path.join(APPDATA_DIR, 'player');
|
||||
console.log(`[DEBUG] Starting Player Express server on port 3001 from: ${playerDir}`);
|
||||
playerExpressApp = express();
|
||||
playerExpressApp.use(express.static(playerDir, { maxAge: '1d', etag: true }));
|
||||
playerExpressApp.get('*', (req, res) => {
|
||||
res.sendFile(path.join(playerDir, 'index.html'));
|
||||
});
|
||||
playerExpressServer = playerExpressApp.listen(3001, '0.0.0.0', () => {
|
||||
console.log('[DEBUG] Player Express server listening on 3001');
|
||||
});
|
||||
playerExpressApp.get('*', (req, res) => { res.sendFile(path.join(playerDir, 'index.html')); });
|
||||
playerExpressServer = playerExpressApp.listen(3001, '0.0.0.0');
|
||||
debugLog("Player Express running on 3001");
|
||||
|
||||
console.log('[DEBUG] Waiting for ports [3000, 3001, 7860]...');
|
||||
sendToTauri('status', { message: 'Waiting for ports 3000, 3001, 7860...' });
|
||||
await serviceManager.waitForPorts([3000, 3001, 7860]);
|
||||
console.log('[DEBUG] All ports ready!');
|
||||
debugLog("Ports 3000, 3001, 7860 are ready.");
|
||||
|
||||
const frontendDir = path.join(APPDATA_DIR, 'frontend');
|
||||
console.log(`[DEBUG] Starting Frontend Express server on port 4890 from: ${frontendDir}`);
|
||||
expressApp = express();
|
||||
expressApp.use(express.static(frontendDir, { maxAge: '1d', etag: true }));
|
||||
expressApp.get('*', (req, res) => {
|
||||
res.sendFile(path.join(frontendDir, 'index.html'));
|
||||
});
|
||||
expressApp.get('*', (req, res) => { res.sendFile(path.join(frontendDir, 'index.html')); });
|
||||
|
||||
const FRONTEND_PORT = 4890;
|
||||
expressServer = expressApp.listen(FRONTEND_PORT, '0.0.0.0', () => {
|
||||
console.log(`[DEBUG] Frontend Express server active at http://localhost:${FRONTEND_PORT}`);
|
||||
debugLog("Frontend Express running on 4890. Sending READY to Tauri.");
|
||||
sendToTauri('ready', { url: `http://localhost:${FRONTEND_PORT}` });
|
||||
});
|
||||
|
||||
} catch (error) {
|
||||
if (serviceManager) {
|
||||
await serviceManager.stopAll().catch(() => { });
|
||||
}
|
||||
console.error('[DEBUG] Fatal error caught:', error.message);
|
||||
debugLog(`Fatal Start Error: ${error.message}`);
|
||||
sendToTauri('error', { message: error.message });
|
||||
}
|
||||
}
|
||||
|
||||
process.on('exit', () => {
|
||||
if (serviceManager) {
|
||||
for (const name of Object.keys(serviceManager.processes)) {
|
||||
const proc = serviceManager.processes[name];
|
||||
if (proc && proc.child) {
|
||||
try { proc.child.kill('SIGKILL'); } catch (e) { }
|
||||
}
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
process.on('SIGINT', async () => {
|
||||
if (expressServer) expressServer.close();
|
||||
if (playerExpressServer) playerExpressServer.close();
|
||||
|
||||
Reference in New Issue
Block a user