const fetch = (...args) => import('node-fetch').then(({ default: fetch }) => fetch(...args)); const fs = require('fs').promises; const path = require('path'); const AdmZip = require('adm-zip'); const util = require('util'); const ncp = util.promisify(require('ncp').ncp); const { downloadUpdate, unzipUpdate } = require('../models/updateHelper'); const { logger, ErrorLogger } = require('../config/logs'); async function getFilesInVersion() { try { const response = await fetch('https://apollon.dinawo.fr/api/get/version'); const data = await response.json(); return data.update.files || []; } catch (error) { throw new Error(`Error getting files in version: ${error.message}`); } } async function listFilesInZip(zipFilePath) { try { const zip = new AdmZip(zipFilePath); const zipEntries = zip.getEntries(); return zipEntries.map(entry => entry.entryName); } catch (error) { throw new Error(`Error listing files in zip: ${error.message}`); } } async function deleteFileOrDirectory(filePath) { try { const stats = await fs.stat(filePath); if (stats.isDirectory()) { logger.info(`Skipped deletion of directory: ${filePath}`); } else { await fs.unlink(filePath); logger.info(`Updated file deleted: ${filePath}`); } } catch (error) { throw new Error(`Error deleting updated file or directory ${filePath}: ${error.message}`); } } ncp.limit = 16; async function moveFilesFromTemp(basePath, tempExtractFolder, filesInZip) { const entries = await fs.readdir(tempExtractFolder, { withFileTypes: true }); for (const entry of entries) { const sourcePath = path.join(tempExtractFolder, entry.name); const targetPath = path.join(basePath, entry.name); if (entry.isDirectory()) { await fs.mkdir(targetPath, { recursive: true }); await ncp(sourcePath, targetPath); } else { const relativePath = path.relative(tempExtractFolder, sourcePath); logger.info(`Processing file: ${relativePath}`); if (filesInZip.includes(relativePath)) { const destinationPath = path.join(basePath, relativePath); await fs.mkdir(path.dirname(destinationPath), { recursive: true }); try { await fs.rename(sourcePath, destinationPath); logger.info(`File moved: ${relativePath}`); } catch (moveError) { logger.error(`Error moving file: ${relativePath}`, moveError); } } else { logger.info(`Skipped moving file: ${relativePath}`); } } } } async function applyUpdate(updateUrl, updateFolder) { const updateFilePath = path.join(updateFolder, 'update.zip'); try { await downloadUpdate(updateUrl, updateFilePath); const filesInZip = await listFilesInZip(updateFilePath); logger.info('Zip contents:', filesInZip); const filesInVersion = await getFilesInVersion(); logger.info('Content of current version:', filesInVersion); for (const file of filesInVersion) { try { await deleteFileOrDirectory(path.join(updateFolder, file)); } catch (error) { ErrorLogger.error(`Error deleting updated file or directory ${file}: ${error.message}`); } } const tempExtractFolder = path.join(updateFolder, 'temp_extract'); await unzipUpdate(updateFilePath, tempExtractFolder); await moveFilesFromTemp(updateFolder, tempExtractFolder, filesInZip); logger.info('Update successful. The update has been applied successfully.'); } catch (error) { ErrorLogger.error(`Error applying update: ${error.message}`); } finally { await cleanUp(updateFolder, updateFilePath); } } async function cleanUp(basePath, zipFilePath) { const tempExtractFolder = path.join(basePath, 'temp_extract'); await fs.rm(tempExtractFolder, { recursive: true }); await fs.unlink(zipFilePath); logger.info('Temporary files successfully deleted.'); } async function checkForUpdates() { try { logger.info('Checking for updates...'); const response = await fetch('https://apollon.dinawo.fr/api/checkupdate'); const result = await response.json(); if (result.updateAvailable) { const updateUrl = 'https://apollon.dinawo.fr/api/download/all'; const updateFolder = path.join(__dirname, '..'); await fs.mkdir(updateFolder, { recursive: true }); await applyUpdate(updateUrl, updateFolder); } else { logger.info('No updates available.'); } } catch (error) { logger.error('Error checking for updates:', error.message); } } module.exports = { applyUpdate, listFilesInZip, checkForUpdates };