From 6f2e4774f44a3632c73220abe48028fdc569a94b Mon Sep 17 00:00:00 2001 From: t8y2 <1156263951@qq.com> Date: Fri, 3 Jul 2026 11:00:53 +0800 Subject: [PATCH] feat(updates): add AtomGit update download source --- .../editor/EditorSettingsDialog.vue | 3 +- apps/desktop/src/composables/useAppUpdater.ts | 4 ++ apps/desktop/src/i18n/locales/en.ts | 3 +- apps/desktop/src/i18n/locales/es.ts | 3 +- apps/desktop/src/i18n/locales/it.ts | 3 +- apps/desktop/src/i18n/locales/ja.ts | 3 +- apps/desktop/src/i18n/locales/pt-BR.ts | 3 +- apps/desktop/src/i18n/locales/zh-CN.ts | 3 +- apps/desktop/src/i18n/locales/zh-TW.ts | 3 +- apps/desktop/src/lib/tauri.ts | 2 +- .../stores/__tests__/settingsStore.spec.ts | 3 +- apps/desktop/src/stores/settingsStore.ts | 3 +- packages/app-tests/appUpdater.test.ts | 2 + src-tauri/src/commands/update.rs | 55 ++++++++++++++++--- 14 files changed, 75 insertions(+), 18 deletions(-) diff --git a/apps/desktop/src/components/editor/EditorSettingsDialog.vue b/apps/desktop/src/components/editor/EditorSettingsDialog.vue index a49ff4ef57..edc85b31ae 100644 --- a/apps/desktop/src/components/editor/EditorSettingsDialog.vue +++ b/apps/desktop/src/components/editor/EditorSettingsDialog.vue @@ -996,7 +996,7 @@ function onLocaleChange(v: any) { } function onUpdateDownloadSourceChange(v: any) { - if (v === "official" || v === "cnb") editUpdateDownloadSource.value = v; + if (v === "official" || v === "cnb" || v === "atomgit") editUpdateDownloadSource.value = v; } function setSidebarObjectDisplay(value: "grouped" | "simple") { @@ -3659,6 +3659,7 @@ onUnmounted(cleanupPreviewEditor); {{ t("settings.updateDownloadSourceOfficial") }} {{ t("settings.updateDownloadSourceCnb") }} + {{ t("settings.updateDownloadSourceAtomgit") }} diff --git a/apps/desktop/src/composables/useAppUpdater.ts b/apps/desktop/src/composables/useAppUpdater.ts index 86846f4f99..941d39c773 100644 --- a/apps/desktop/src/composables/useAppUpdater.ts +++ b/apps/desktop/src/composables/useAppUpdater.ts @@ -16,6 +16,7 @@ export function canDownloadAndInstallUpdate(info: api.UpdateInfo | null, isDeskt } export function normalizeUpdateDownloadSource(value: unknown): SettingsUpdateDownloadSource { + if (value === "atomgit") return "atomgit"; return value === "cnb" ? "cnb" : "official"; } @@ -29,6 +30,9 @@ export function resolveUpdateReleaseUrl(info: api.UpdateInfo | null, source: unk if (normalizedSource === "cnb" && info?.latest_version) { return `https://cnb.cool/dbxio.com/dbx/-/releases/tag/${tagVersion(info.latest_version)}`; } + if (normalizedSource === "atomgit" && info?.latest_version) { + return `https://atomgit.com/t8y2/dbx/releases/${tagVersion(info.latest_version)}`; + } return info?.release_url || fallbackUrl; } diff --git a/apps/desktop/src/i18n/locales/en.ts b/apps/desktop/src/i18n/locales/en.ts index 967fd31e83..9241541e4a 100644 --- a/apps/desktop/src/i18n/locales/en.ts +++ b/apps/desktop/src/i18n/locales/en.ts @@ -2632,9 +2632,10 @@ export default { updateNotificationsEnabled: "Enable update reminders", updateNotificationsEnabledDescription: "When disabled, DBX will not automatically check app or driver updates or show update badges. Manual checks are still available.", updateDownloadSource: "Update download source", - updateDownloadSourceDescription: "Choose where in-app update installers are downloaded from. The official source is recommended; CNB can be faster on mainland China networks.", + updateDownloadSourceDescription: "Choose where in-app update installers are downloaded from. The official source is recommended; CNB or AtomGit can be faster on mainland China networks.", updateDownloadSourceOfficial: "Official source (recommended)", updateDownloadSourceCnb: "CNB", + updateDownloadSourceAtomgit: "AtomGit", debugLoggingEnabled: "Enable debug logs", debugLoggingEnabledDescription: "Record more detailed local user-side diagnostic logs while troubleshooting reports. Disabled by default.", debugLogsCopy: "Copy logs", diff --git a/apps/desktop/src/i18n/locales/es.ts b/apps/desktop/src/i18n/locales/es.ts index c4e45633b8..c4e3f8bdcc 100644 --- a/apps/desktop/src/i18n/locales/es.ts +++ b/apps/desktop/src/i18n/locales/es.ts @@ -2635,9 +2635,10 @@ export default withEnglishFallback({ updateNotificationsEnabled: "Activar recordatorios de actualización", updateNotificationsEnabledDescription: "Al desactivarlo, DBX no comprobará automáticamente actualizaciones de la app ni de los controladores, ni mostrará indicadores. Las comprobaciones manuales siguen disponibles.", updateDownloadSource: "Origen de descarga de actualizaciones", - updateDownloadSourceDescription: "Elige de dónde se descargan los instaladores de actualización. Se recomienda la fuente oficial; CNB puede ser más rápida en redes de China continental.", + updateDownloadSourceDescription: "Elige de dónde se descargan los instaladores de actualización. Se recomienda la fuente oficial; CNB o AtomGit pueden ser más rápidos en redes de China continental.", updateDownloadSourceOfficial: "Fuente oficial (recomendada)", updateDownloadSourceCnb: "CNB", + updateDownloadSourceAtomgit: "AtomGit", debugLoggingEnabled: "Activar logs de depuración", debugLoggingEnabledDescription: "Registra logs de diagnóstico locales del lado del usuario al investigar reportes. Desactivado por defecto.", debugLogsCopy: "Copiar logs", diff --git a/apps/desktop/src/i18n/locales/it.ts b/apps/desktop/src/i18n/locales/it.ts index 9f1cdc0dea..f7ac0e9588 100644 --- a/apps/desktop/src/i18n/locales/it.ts +++ b/apps/desktop/src/i18n/locales/it.ts @@ -2633,9 +2633,10 @@ export default withEnglishFallback({ updateNotificationsEnabled: "Abilita promemoria aggiornamenti", updateNotificationsEnabledDescription: "Se disattivato, DBX non controllerà automaticamente gli aggiornamenti dell'app o dei driver e non mostrerà badge. I controlli manuali restano disponibili.", updateDownloadSource: "Fonte download aggiornamenti", - updateDownloadSourceDescription: "Scegli da dove scaricare gli installer degli aggiornamenti. La fonte ufficiale è consigliata; CNB può essere più veloce sulle reti della Cina continentale.", + updateDownloadSourceDescription: "Scegli da dove scaricare gli installer degli aggiornamenti. La fonte ufficiale è consigliata; CNB o AtomGit possono essere più veloci sulle reti della Cina continentale.", updateDownloadSourceOfficial: "Fonte ufficiale (consigliata)", updateDownloadSourceCnb: "CNB", + updateDownloadSourceAtomgit: "AtomGit", debugLoggingEnabled: "Abilita log di debug", debugLoggingEnabledDescription: "Registra log diagnostici locali lato utente durante l'analisi delle segnalazioni. Disattivato per impostazione predefinita.", debugLogsCopy: "Copia log", diff --git a/apps/desktop/src/i18n/locales/ja.ts b/apps/desktop/src/i18n/locales/ja.ts index 07a93631a9..6232275724 100644 --- a/apps/desktop/src/i18n/locales/ja.ts +++ b/apps/desktop/src/i18n/locales/ja.ts @@ -2906,9 +2906,10 @@ export default withEnglishFallback({ mcpRefresh: "再確認", mcpGuide: "MCPガイド", updateDownloadSource: "アップデートのダウンロード元", - updateDownloadSourceDescription: "アプリ内アップデートのインストーラーのダウンロード元を選択します。公式ソース推奨。中国本土ではCNBの方が高速な場合があります。", + updateDownloadSourceDescription: "アプリ内アップデートのインストーラーのダウンロード元を選択します。公式ソース推奨。中国本土ではCNBまたはAtomGitの方が高速な場合があります。", updateDownloadSourceOfficial: "公式ソース(推奨)", updateDownloadSourceCnb: "CNB", + updateDownloadSourceAtomgit: "AtomGit", infiniteScroll: "無限スクロール読み込み", infiniteScrollDescription: "テーブルのスクロール時に次のページのデータを自動読み込みします。", infiniteScrollMaxRows: "無限スクロールの最大行数", diff --git a/apps/desktop/src/i18n/locales/pt-BR.ts b/apps/desktop/src/i18n/locales/pt-BR.ts index 1cfe604998..8f789a3131 100644 --- a/apps/desktop/src/i18n/locales/pt-BR.ts +++ b/apps/desktop/src/i18n/locales/pt-BR.ts @@ -2634,9 +2634,10 @@ export default withEnglishFallback({ updateNotificationsEnabled: "Ativar lembretes de atualização", updateNotificationsEnabledDescription: "Quando desativado, o DBX não verificará automaticamente atualizações do app ou dos drivers nem mostrará indicadores. Verificações manuais continuam disponíveis.", updateDownloadSource: "Fonte de download de atualização", - updateDownloadSourceDescription: "Escolha de onde os instaladores de atualização no aplicativo são baixados. A fonte oficial é recomendada; a CNB pode ser mais rápida em redes da China continental.", + updateDownloadSourceDescription: "Escolha de onde os instaladores de atualização no aplicativo são baixados. A fonte oficial é recomendada; CNB ou AtomGit podem ser mais rápidos em redes da China continental.", updateDownloadSourceOfficial: "Fonte oficial (recomendada)", updateDownloadSourceCnb: "CNB", + updateDownloadSourceAtomgit: "AtomGit", debugLoggingEnabled: "Ativar logs de depuração", debugLoggingEnabledDescription: "Registra logs locais de diagnóstico do lado do usuário ao investigar relatos. Desativado por padrão.", debugLogsCopy: "Copiar logs", diff --git a/apps/desktop/src/i18n/locales/zh-CN.ts b/apps/desktop/src/i18n/locales/zh-CN.ts index ace09c3456..b85d855618 100644 --- a/apps/desktop/src/i18n/locales/zh-CN.ts +++ b/apps/desktop/src/i18n/locales/zh-CN.ts @@ -2634,9 +2634,10 @@ export default withEnglishFallback({ updateNotificationsEnabled: "启用更新提醒", updateNotificationsEnabledDescription: "关闭后,DBX 不会自动检查应用和驱动更新,也不会显示更新红点;仍可手动检查更新。", updateDownloadSource: "更新下载源", - updateDownloadSourceDescription: "选择应用内更新安装包的下载来源。官方源为推荐选项,CNB 适合国内网络环境。", + updateDownloadSourceDescription: "选择应用内更新安装包的下载来源。官方源为推荐选项,CNB 或 AtomGit 适合国内网络环境。", updateDownloadSourceOfficial: "官方源(推荐)", updateDownloadSourceCnb: "CNB", + updateDownloadSourceAtomgit: "AtomGit", debugLoggingEnabled: "启用调试日志", debugLoggingEnabledDescription: "开启后在本机记录更详细的用户侧诊断日志,反馈问题时可临时开启;默认关闭。", debugLogsCopy: "复制日志", diff --git a/apps/desktop/src/i18n/locales/zh-TW.ts b/apps/desktop/src/i18n/locales/zh-TW.ts index d6b0522ba5..052d9b235f 100644 --- a/apps/desktop/src/i18n/locales/zh-TW.ts +++ b/apps/desktop/src/i18n/locales/zh-TW.ts @@ -2819,9 +2819,10 @@ export default withEnglishFallback({ mcpRefresh: "重新檢查", mcpGuide: "MCP 指南", updateDownloadSource: "更新下載來源", - updateDownloadSourceDescription: "選擇應用程式內更新安裝程式的下載來源。建議使用官方來源;CNB 在中國大陸網路環境下可能更快。", + updateDownloadSourceDescription: "選擇應用程式內更新安裝程式的下載來源。建議使用官方來源;CNB 或 AtomGit 在中國大陸網路環境下可能更快。", updateDownloadSourceOfficial: "官方來源(建議)", updateDownloadSourceCnb: "CNB", + updateDownloadSourceAtomgit: "AtomGit", exportSection: "匯出", exportBatchSize: "匯出批次大小", exportBatchSizeDescription: "匯出資料時每批次擷取的列數(100-100000)。", diff --git a/apps/desktop/src/lib/tauri.ts b/apps/desktop/src/lib/tauri.ts index c6a7895e25..4a53500228 100644 --- a/apps/desktop/src/lib/tauri.ts +++ b/apps/desktop/src/lib/tauri.ts @@ -1163,7 +1163,7 @@ export interface UpdateInfo { release_notes: string; } -export type UpdateDownloadSource = "official" | "cnb"; +export type UpdateDownloadSource = "official" | "cnb" | "atomgit"; export interface UpdateDownloadProgress { downloaded: number; diff --git a/apps/desktop/src/stores/__tests__/settingsStore.spec.ts b/apps/desktop/src/stores/__tests__/settingsStore.spec.ts index e73a47e185..34d512c13f 100644 --- a/apps/desktop/src/stores/__tests__/settingsStore.spec.ts +++ b/apps/desktop/src/stores/__tests__/settingsStore.spec.ts @@ -45,8 +45,9 @@ describe("normalizeEditorSettings", () => { expect(normalizeEditorSettings({ restoreOpenTabsOnLaunch: true } as any).openTabsRestoreMode).toBe("all"); }); - it("preserves CNB update download source and rejects invalid values", () => { + it("preserves mirror update download sources and rejects invalid values", () => { expect(normalizeEditorSettings({ updateDownloadSource: "cnb" }).updateDownloadSource).toBe("cnb"); + expect(normalizeEditorSettings({ updateDownloadSource: "atomgit" }).updateDownloadSource).toBe("atomgit"); expect(normalizeEditorSettings({ updateDownloadSource: "mirror" as any }).updateDownloadSource).toBe("official"); }); }); diff --git a/apps/desktop/src/stores/settingsStore.ts b/apps/desktop/src/stores/settingsStore.ts index 8664bebe49..34dc43494d 100644 --- a/apps/desktop/src/stores/settingsStore.ts +++ b/apps/desktop/src/stores/settingsStore.ts @@ -59,7 +59,7 @@ export type DesktopIconTheme = "default" | "black"; export type InterfaceLayout = "separated" | "classic"; -export type UpdateDownloadSource = "official" | "cnb"; +export type UpdateDownloadSource = "official" | "cnb" | "atomgit"; export type SqlSemanticDiagnosticsMode = "auto" | "enabled" | "disabled"; export type OpenTabsRestoreMode = "all" | "pinned" | "none"; @@ -533,6 +533,7 @@ function normalizeTableFontSize(value: unknown): number { } function normalizeUpdateDownloadSource(value: unknown): UpdateDownloadSource { + if (value === "atomgit") return "atomgit"; return value === "cnb" ? "cnb" : DEFAULT_EDITOR_SETTINGS.updateDownloadSource; } diff --git a/packages/app-tests/appUpdater.test.ts b/packages/app-tests/appUpdater.test.ts index b02fb4b4eb..903854edb6 100644 --- a/packages/app-tests/appUpdater.test.ts +++ b/packages/app-tests/appUpdater.test.ts @@ -34,6 +34,7 @@ test("blocks in-app update installation outside desktop runtime or without an up test("normalizes update download source", () => { assert.equal(normalizeUpdateDownloadSource("official"), "official"); assert.equal(normalizeUpdateDownloadSource("cnb"), "cnb"); + assert.equal(normalizeUpdateDownloadSource("atomgit"), "atomgit"); assert.equal(normalizeUpdateDownloadSource("unknown"), "official"); }); @@ -45,6 +46,7 @@ test("normalizes release tag versions", () => { test("resolves release page URL from update download source", () => { const fallbackUrl = "https://github.com/t8y2/dbx/releases/latest"; assert.equal(resolveUpdateReleaseUrl(updateInfo({ latest_version: "0.5.39" }), "cnb", fallbackUrl), "https://cnb.cool/dbxio.com/dbx/-/releases/tag/v0.5.39"); + assert.equal(resolveUpdateReleaseUrl(updateInfo({ latest_version: "0.5.44" }), "atomgit", fallbackUrl), "https://atomgit.com/t8y2/dbx/releases/v0.5.44"); assert.equal(resolveUpdateReleaseUrl(updateInfo({ release_url: "https://github.com/t8y2/dbx/releases/tag/v0.5.39" }), "official", fallbackUrl), "https://github.com/t8y2/dbx/releases/tag/v0.5.39"); assert.equal(resolveUpdateReleaseUrl(null, "cnb", fallbackUrl), fallbackUrl); }); diff --git a/src-tauri/src/commands/update.rs b/src-tauri/src/commands/update.rs index 198f36f320..dc4826b153 100644 --- a/src-tauri/src/commands/update.rs +++ b/src-tauri/src/commands/update.rs @@ -14,6 +14,7 @@ const OFFICIAL_UPDATE_ENDPOINTS: [&str; 2] = [ ]; const CNB_RELEASE_DOWNLOAD_PREFIX: &str = "https://cnb.cool/dbxio.com/dbx/-/releases/download/"; const GITHUB_RELEASE_DOWNLOAD_PREFIX: &str = "https://github.com/t8y2/dbx/releases/download/"; +const ATOMGIT_RELEASE_DOWNLOAD_PREFIX: &str = "https://atomgit.com/t8y2/dbx/releases/download/"; const UPDATE_DOWNLOAD_PROGRESS_EVENT: &str = "update-download-progress"; #[derive(Debug, Deserialize)] @@ -21,6 +22,7 @@ const UPDATE_DOWNLOAD_PROGRESS_EVENT: &str = "update-download-progress"; pub enum UpdateDownloadSource { Official, Cnb, + Atomgit, } #[derive(Clone, Debug, Serialize)] @@ -34,6 +36,7 @@ impl UpdateDownloadSource { match self { Self::Official => "official", Self::Cnb => "cnb", + Self::Atomgit => "atomgit", } } @@ -45,24 +48,36 @@ impl UpdateDownloadSource { latest_version.ok_or_else(|| "Latest version is required for CNB updates.".to_string())?; Ok(vec![format!("{CNB_RELEASE_DOWNLOAD_PREFIX}{}/latest.json", tag_version(version))]) } + Self::Atomgit => { + let version = + latest_version.ok_or_else(|| "Latest version is required for AtomGit updates.".to_string())?; + Ok(vec![format!("{ATOMGIT_RELEASE_DOWNLOAD_PREFIX}{}/latest.json", tag_version(version))]) + } } } fn rewrite_download_url(&self, url: &str) -> Result, String> { - if !matches!(self, Self::Cnb) { - return Ok(None); - } + let Some(target_prefix) = self.mirror_download_prefix() else { return Ok(None) }; - if url.starts_with(CNB_RELEASE_DOWNLOAD_PREFIX) { + if url.starts_with(target_prefix) { return Ok(None); } + // Mirror latest.json files still contain GitHub asset URLs, so rewrite only that known release prefix. let rewritten = url .strip_prefix(GITHUB_RELEASE_DOWNLOAD_PREFIX) - .map(|path| format!("{CNB_RELEASE_DOWNLOAD_PREFIX}{path}")) - .ok_or_else(|| format!("Unsupported update download URL for CNB source: {url}"))?; + .map(|path| format!("{target_prefix}{path}")) + .ok_or_else(|| format!("Unsupported update download URL for {} source: {url}", self.label()))?; Ok(Some(rewritten)) } + + fn mirror_download_prefix(&self) -> Option<&'static str> { + match self { + Self::Cnb => Some(CNB_RELEASE_DOWNLOAD_PREFIX), + Self::Atomgit => Some(ATOMGIT_RELEASE_DOWNLOAD_PREFIX), + Self::Official => None, + } + } } fn tag_version(version: &str) -> String { @@ -145,7 +160,10 @@ pub async fn download_and_install_update( #[cfg(test)] mod tests { - use super::{tag_version, UpdateDownloadSource, CNB_RELEASE_DOWNLOAD_PREFIX, OFFICIAL_UPDATE_ENDPOINTS}; + use super::{ + tag_version, UpdateDownloadSource, ATOMGIT_RELEASE_DOWNLOAD_PREFIX, CNB_RELEASE_DOWNLOAD_PREFIX, + OFFICIAL_UPDATE_ENDPOINTS, + }; #[test] fn normalizes_update_tag_versions() { @@ -165,6 +183,12 @@ mod tests { assert_eq!(endpoints, vec![format!("{CNB_RELEASE_DOWNLOAD_PREFIX}v0.5.39/latest.json")]); } + #[test] + fn builds_atomgit_update_endpoint_for_tag() { + let endpoints = UpdateDownloadSource::Atomgit.endpoints(Some("0.5.44")).unwrap(); + assert_eq!(endpoints, vec![format!("{ATOMGIT_RELEASE_DOWNLOAD_PREFIX}v0.5.44/latest.json")]); + } + #[test] fn rewrites_github_asset_url_to_cnb() { let download_url = UpdateDownloadSource::Cnb @@ -181,4 +205,21 @@ mod tests { .unwrap(); assert_eq!(download_url, None); } + + #[test] + fn rewrites_github_asset_url_to_atomgit() { + let download_url = UpdateDownloadSource::Atomgit + .rewrite_download_url("https://github.com/t8y2/dbx/releases/download/v0.5.44/DBX_0.5.44_x64.dmg") + .unwrap() + .unwrap(); + assert_eq!(download_url, "https://atomgit.com/t8y2/dbx/releases/download/v0.5.44/DBX_0.5.44_x64.dmg"); + } + + #[test] + fn accepts_existing_atomgit_asset_url() { + let download_url = UpdateDownloadSource::Atomgit + .rewrite_download_url("https://atomgit.com/t8y2/dbx/releases/download/v0.5.44/DBX_0.5.44_x64.dmg") + .unwrap(); + assert_eq!(download_url, None); + } }