From fec2bd37a438bd2493d40ad50fe5da3823cb3a29 Mon Sep 17 00:00:00 2001 From: yuyx <237899745@qq.com> Date: Wed, 18 Feb 2026 22:14:26 +0800 Subject: [PATCH] feat(update): auto-clean old desktop installer packages --- backend/server.js | 82 ++++++++++++++++++++++++++++++++++++++++++++--- 1 file changed, 78 insertions(+), 4 deletions(-) diff --git a/backend/server.js b/backend/server.js index ed776f6..e9af9c6 100644 --- a/backend/server.js +++ b/backend/server.js @@ -104,6 +104,8 @@ const DOWNLOAD_SIGNED_URL_EXPIRES_SECONDS = Math.max( const DEFAULT_DESKTOP_VERSION = process.env.DESKTOP_LATEST_VERSION || '0.1.2'; const DEFAULT_DESKTOP_INSTALLER_URL = process.env.DESKTOP_INSTALLER_URL || ''; const DEFAULT_DESKTOP_RELEASE_NOTES = process.env.DESKTOP_RELEASE_NOTES || ''; +const DESKTOP_INSTALLERS_DIR = path.resolve(__dirname, '../frontend/downloads'); +const DESKTOP_INSTALLER_FILE_PATTERN = /^wanwan-cloud-desktop_.*_x64-setup\.exe$/i; const RESUMABLE_UPLOAD_SESSION_TTL_MS = Number(process.env.RESUMABLE_UPLOAD_SESSION_TTL_MS || (24 * 60 * 60 * 1000)); // 24小时 const RESUMABLE_UPLOAD_CHUNK_SIZE_BYTES = Number(process.env.RESUMABLE_UPLOAD_CHUNK_SIZE_BYTES || (4 * 1024 * 1024)); // 4MB const RESUMABLE_UPLOAD_MAX_CHUNK_SIZE_BYTES = Number(process.env.RESUMABLE_UPLOAD_MAX_CHUNK_SIZE_BYTES || (32 * 1024 * 1024)); // 32MB @@ -184,6 +186,67 @@ function getDesktopUpdateConfig() { }; } +function resolveDesktopInstallerFileName(installerUrl) { + const raw = String(installerUrl || '').trim(); + if (!raw) return null; + + try { + const parsed = new URL(raw, 'http://local.invalid'); + const pathname = decodeURIComponent(parsed.pathname || ''); + const fileName = path.basename(pathname); + return fileName && fileName !== '.' && fileName !== '/' ? fileName : null; + } catch (error) { + const sanitized = raw.split('?')[0].split('#')[0]; + const fileName = path.basename(sanitized); + return fileName && fileName !== '.' && fileName !== '/' ? fileName : null; + } +} + +function cleanupDesktopInstallerPackages(installerUrl) { + try { + const keepFileName = resolveDesktopInstallerFileName(installerUrl); + if (!keepFileName || !DESKTOP_INSTALLER_FILE_PATTERN.test(keepFileName)) { + return { executed: false, removed: 0, kept: 0, reason: 'installer_url_not_local_package' }; + } + + if (!fs.existsSync(DESKTOP_INSTALLERS_DIR)) { + return { executed: false, removed: 0, kept: 0, reason: 'downloads_dir_missing' }; + } + + const candidates = fs.readdirSync(DESKTOP_INSTALLERS_DIR) + .filter((name) => DESKTOP_INSTALLER_FILE_PATTERN.test(name)); + const keepFilePath = path.join(DESKTOP_INSTALLERS_DIR, keepFileName); + + if (!fs.existsSync(keepFilePath)) { + return { executed: false, removed: 0, kept: candidates.length, reason: 'keep_package_missing' }; + } + + let removed = 0; + for (const fileName of candidates) { + if (fileName === keepFileName) continue; + fs.unlinkSync(path.join(DESKTOP_INSTALLERS_DIR, fileName)); + removed += 1; + console.log(`[桌面端更新] 已清理旧安装包: ${fileName}`); + } + + return { + executed: true, + removed, + kept: candidates.length - removed, + keep_file: keepFileName + }; + } catch (error) { + console.error('[桌面端更新] 清理旧安装包失败:', error); + return { + executed: false, + removed: 0, + kept: 0, + reason: 'cleanup_failed', + error: error.message + }; + } +} + function getResolvedStorageRoot() { const configuredRoot = process.env.STORAGE_ROOT; if (!configuredRoot) { @@ -8693,6 +8756,7 @@ app.post('/api/admin/settings', download_security, desktop_update } = req.body; + let desktopInstallerCleanup = null; if (max_upload_size !== undefined) { const size = parseInt(max_upload_size); @@ -8759,8 +8823,10 @@ app.post('/api/admin/settings', SettingsDB.set('desktop_latest_version', normalizeVersion(desktop_update.latest_version, DEFAULT_DESKTOP_VERSION)); } if (desktop_update.installer_url !== undefined) { - SettingsDB.set('desktop_installer_url', String(desktop_update.installer_url || '').trim()); - SettingsDB.set('desktop_installer_url_win_x64', String(desktop_update.installer_url || '').trim()); + const normalizedInstallerUrl = String(desktop_update.installer_url || '').trim(); + SettingsDB.set('desktop_installer_url', normalizedInstallerUrl); + SettingsDB.set('desktop_installer_url_win_x64', normalizedInstallerUrl); + desktopInstallerCleanup = cleanupDesktopInstallerPackages(normalizedInstallerUrl); } if (desktop_update.release_notes !== undefined) { SettingsDB.set('desktop_release_notes', String(desktop_update.release_notes || '').trim()); @@ -8770,10 +8836,14 @@ app.post('/api/admin/settings', } } - res.json({ + const payload = { success: true, message: '系统设置已更新' - }); + }; + if (desktopInstallerCleanup) { + payload.desktop_installer_cleanup = desktopInstallerCleanup; + } + res.json(payload); } catch (error) { console.error('更新系统设置失败:', error); res.status(500).json({ @@ -10788,6 +10858,10 @@ app.get("/s/:code", (req, res) => { // 启动时清理旧临时文件 cleanupOldTempFiles(); +const desktopCleanupOnStartup = cleanupDesktopInstallerPackages(getDesktopUpdateConfig().installerUrl); +if (desktopCleanupOnStartup.executed && desktopCleanupOnStartup.removed > 0) { + console.log(`[桌面端更新] 启动时已清理 ${desktopCleanupOnStartup.removed} 个旧安装包`); +} // 启动服务器 app.listen(PORT, '0.0.0.0', () => {