From ebee33ea7c67d2fc16de53da0ef6c3879f372a97 Mon Sep 17 00:00:00 2001 From: landaiqing Date: Thu, 3 Jul 2025 15:21:01 +0800 Subject: [PATCH] :sparkles: Add self-updating service --- .../voidraft/internal/models/models.ts | 156 ++++++ .../voidraft/internal/services/index.ts | 6 +- .../voidraft/internal/services/models.ts | 58 +- .../internal/services/selfupdateservice.ts | 51 ++ .../internal/services/updateservice.ts | 30 - frontend/package-lock.json | 55 ++ frontend/package.json | 2 + .../src/components/monitor/MemoryMonitor.vue | 216 ++++--- .../components/toolbar/DocumentSelector.vue | 4 +- frontend/src/components/toolbar/Toolbar.vue | 138 ++++- frontend/src/i18n/locales/en-US.ts | 19 +- frontend/src/i18n/locales/zh-CN.ts | 20 +- frontend/src/stores/configStore.ts | 22 +- frontend/src/stores/updateStore.ts | 90 ++- .../editor/extensions/hyperlink/index.ts | 5 +- .../src/views/settings/pages/UpdatesPage.vue | 300 ++++++---- go.mod | 42 +- go.sum | 123 ++-- internal/models/config.go | 50 +- internal/services/self_update_service.go | 530 ++++++++++++++++++ internal/services/service_manager.go | 24 +- internal/services/update_service.go | 89 --- 22 files changed, 1565 insertions(+), 465 deletions(-) create mode 100644 frontend/bindings/voidraft/internal/services/selfupdateservice.ts delete mode 100644 frontend/bindings/voidraft/internal/services/updateservice.ts create mode 100644 internal/services/self_update_service.go delete mode 100644 internal/services/update_service.go diff --git a/frontend/bindings/voidraft/internal/models/models.ts b/frontend/bindings/voidraft/internal/models/models.ts index 8c1e4b6..850ca32 100644 --- a/frontend/bindings/voidraft/internal/models/models.ts +++ b/frontend/bindings/voidraft/internal/models/models.ts @@ -471,6 +471,84 @@ export class GeneralConfig { } } +/** + * GiteaConfig Gitea配置 + */ +export class GiteaConfig { + /** + * Gitea服务器URL + */ + "baseURL": string; + + /** + * 仓库所有者 + */ + "owner": string; + + /** + * 仓库名称 + */ + "repo": string; + + /** Creates a new GiteaConfig instance. */ + constructor($$source: Partial = {}) { + if (!("baseURL" in $$source)) { + this["baseURL"] = ""; + } + if (!("owner" in $$source)) { + this["owner"] = ""; + } + if (!("repo" in $$source)) { + this["repo"] = ""; + } + + Object.assign(this, $$source); + } + + /** + * Creates a new GiteaConfig instance from a string or object. + */ + static createFrom($$source: any = {}): GiteaConfig { + let $$parsedSource = typeof $$source === 'string' ? JSON.parse($$source) : $$source; + return new GiteaConfig($$parsedSource as Partial); + } +} + +/** + * GithubConfig GitHub配置 + */ +export class GithubConfig { + /** + * 仓库所有者 + */ + "owner": string; + + /** + * 仓库名称 + */ + "repo": string; + + /** Creates a new GithubConfig instance. */ + constructor($$source: Partial = {}) { + if (!("owner" in $$source)) { + this["owner"] = ""; + } + if (!("repo" in $$source)) { + this["repo"] = ""; + } + + Object.assign(this, $$source); + } + + /** + * Creates a new GithubConfig instance from a string or object. + */ + static createFrom($$source: any = {}): GithubConfig { + let $$parsedSource = typeof $$source === 'string' ? JSON.parse($$source) : $$source; + return new GithubConfig($$parsedSource as Partial); + } +} + /** * HotkeyCombo 热键组合定义 */ @@ -1023,6 +1101,26 @@ export enum TabType { TabTypeTab = "tab", }; +/** + * UpdateSourceType 更新源类型 + */ +export enum UpdateSourceType { + /** + * The Go zero value for the underlying type of the enum. + */ + $zero = "", + + /** + * UpdateSourceGithub GitHub更新源 + */ + UpdateSourceGithub = "github", + + /** + * UpdateSourceGitea Gitea更新源 + */ + UpdateSourceGitea = "gitea", +}; + /** * UpdatesConfig 更新设置配置 */ @@ -1037,6 +1135,36 @@ export class UpdatesConfig { */ "autoUpdate": boolean; + /** + * 主要更新源 + */ + "primarySource": UpdateSourceType; + + /** + * 备用更新源 + */ + "backupSource": UpdateSourceType; + + /** + * 更新前是否备份 + */ + "backupBeforeUpdate": boolean; + + /** + * 更新超时时间(秒) + */ + "updateTimeout": number; + + /** + * GitHub配置 + */ + "github": GithubConfig; + + /** + * Gitea配置 + */ + "gitea": GiteaConfig; + /** Creates a new UpdatesConfig instance. */ constructor($$source: Partial = {}) { if (!("version" in $$source)) { @@ -1045,6 +1173,24 @@ export class UpdatesConfig { if (!("autoUpdate" in $$source)) { this["autoUpdate"] = false; } + if (!("primarySource" in $$source)) { + this["primarySource"] = ("" as UpdateSourceType); + } + if (!("backupSource" in $$source)) { + this["backupSource"] = ("" as UpdateSourceType); + } + if (!("backupBeforeUpdate" in $$source)) { + this["backupBeforeUpdate"] = false; + } + if (!("updateTimeout" in $$source)) { + this["updateTimeout"] = 0; + } + if (!("github" in $$source)) { + this["github"] = (new GithubConfig()); + } + if (!("gitea" in $$source)) { + this["gitea"] = (new GiteaConfig()); + } Object.assign(this, $$source); } @@ -1053,7 +1199,15 @@ export class UpdatesConfig { * Creates a new UpdatesConfig instance from a string or object. */ static createFrom($$source: any = {}): UpdatesConfig { + const $$createField6_0 = $$createType11; + const $$createField7_0 = $$createType12; let $$parsedSource = typeof $$source === 'string' ? JSON.parse($$source) : $$source; + if ("github" in $$parsedSource) { + $$parsedSource["github"] = $$createField6_0($$parsedSource["github"]); + } + if ("gitea" in $$parsedSource) { + $$parsedSource["gitea"] = $$createField7_0($$parsedSource["gitea"]); + } return new UpdatesConfig($$parsedSource as Partial); } } @@ -1075,3 +1229,5 @@ const $$createType7 = HotkeyCombo.createFrom; const $$createType8 = KeyBinding.createFrom; const $$createType9 = $Create.Array($$createType8); const $$createType10 = KeyBindingMetadata.createFrom; +const $$createType11 = GithubConfig.createFrom; +const $$createType12 = GiteaConfig.createFrom; diff --git a/frontend/bindings/voidraft/internal/services/index.ts b/frontend/bindings/voidraft/internal/services/index.ts index 24fafc8..8ed4a2c 100644 --- a/frontend/bindings/voidraft/internal/services/index.ts +++ b/frontend/bindings/voidraft/internal/services/index.ts @@ -8,10 +8,10 @@ import * as ExtensionService from "./extensionservice.js"; import * as HotkeyService from "./hotkeyservice.js"; import * as KeyBindingService from "./keybindingservice.js"; import * as MigrationService from "./migrationservice.js"; +import * as SelfUpdateService from "./selfupdateservice.js"; import * as StartupService from "./startupservice.js"; import * as SystemService from "./systemservice.js"; import * as TrayService from "./trayservice.js"; -import * as UpdateService from "./updateservice.js"; export { ConfigService, DialogService, @@ -20,10 +20,10 @@ export { HotkeyService, KeyBindingService, MigrationService, + SelfUpdateService, StartupService, SystemService, - TrayService, - UpdateService + TrayService }; export * from "./models.js"; diff --git a/frontend/bindings/voidraft/internal/services/models.ts b/frontend/bindings/voidraft/internal/services/models.ts index 09f61c4..9acb2da 100644 --- a/frontend/bindings/voidraft/internal/services/models.ts +++ b/frontend/bindings/voidraft/internal/services/models.ts @@ -116,9 +116,9 @@ export enum MigrationStatus { }; /** - * UpdateCheckResult 更新检查结果 + * SelfUpdateResult 自我更新结果 */ -export class UpdateCheckResult { +export class SelfUpdateResult { /** * 是否有更新 */ @@ -127,57 +127,73 @@ export class UpdateCheckResult { /** * 当前版本 */ - "currentVer": string; + "currentVersion": string; /** * 最新版本 */ - "latestVer": string; + "latestVersion": string; + + /** + * 是否已应用更新 + */ + "updateApplied": boolean; + + /** + * 下载链接 + */ + "assetURL": string; /** * 发布说明 */ "releaseNotes": string; - /** - * 发布页面URL - */ - "releaseURL": string; - /** * 错误信息 */ "error": string; - /** Creates a new UpdateCheckResult instance. */ - constructor($$source: Partial = {}) { + /** + * 更新源(github/gitea) + */ + "source": string; + + /** Creates a new SelfUpdateResult instance. */ + constructor($$source: Partial = {}) { if (!("hasUpdate" in $$source)) { this["hasUpdate"] = false; } - if (!("currentVer" in $$source)) { - this["currentVer"] = ""; + if (!("currentVersion" in $$source)) { + this["currentVersion"] = ""; } - if (!("latestVer" in $$source)) { - this["latestVer"] = ""; + if (!("latestVersion" in $$source)) { + this["latestVersion"] = ""; + } + if (!("updateApplied" in $$source)) { + this["updateApplied"] = false; + } + if (!("assetURL" in $$source)) { + this["assetURL"] = ""; } if (!("releaseNotes" in $$source)) { this["releaseNotes"] = ""; } - if (!("releaseURL" in $$source)) { - this["releaseURL"] = ""; - } if (!("error" in $$source)) { this["error"] = ""; } + if (!("source" in $$source)) { + this["source"] = ""; + } Object.assign(this, $$source); } /** - * Creates a new UpdateCheckResult instance from a string or object. + * Creates a new SelfUpdateResult instance from a string or object. */ - static createFrom($$source: any = {}): UpdateCheckResult { + static createFrom($$source: any = {}): SelfUpdateResult { let $$parsedSource = typeof $$source === 'string' ? JSON.parse($$source) : $$source; - return new UpdateCheckResult($$parsedSource as Partial); + return new SelfUpdateResult($$parsedSource as Partial); } } diff --git a/frontend/bindings/voidraft/internal/services/selfupdateservice.ts b/frontend/bindings/voidraft/internal/services/selfupdateservice.ts new file mode 100644 index 0000000..c963f38 --- /dev/null +++ b/frontend/bindings/voidraft/internal/services/selfupdateservice.ts @@ -0,0 +1,51 @@ +// Cynhyrchwyd y ffeil hon yn awtomatig. PEIDIWCH Â MODIWL +// This file is automatically generated. DO NOT EDIT + +/** + * SelfUpdateService 自我更新服务 + * @module + */ + +// eslint-disable-next-line @typescript-eslint/ban-ts-comment +// @ts-ignore: Unused imports +import {Call as $Call, Create as $Create} from "@wailsio/runtime"; + +// eslint-disable-next-line @typescript-eslint/ban-ts-comment +// @ts-ignore: Unused imports +import * as $models from "./models.js"; + +/** + * ApplyUpdate 应用更新 + */ +export function ApplyUpdate(): Promise<$models.SelfUpdateResult | null> & { cancel(): void } { + let $resultPromise = $Call.ByID(2009328394) as any; + let $typingPromise = $resultPromise.then(($result: any) => { + return $$createType1($result); + }) as any; + $typingPromise.cancel = $resultPromise.cancel.bind($resultPromise); + return $typingPromise; +} + +/** + * CheckForUpdates 检查更新 + */ +export function CheckForUpdates(): Promise<$models.SelfUpdateResult | null> & { cancel(): void } { + let $resultPromise = $Call.ByID(438757208) as any; + let $typingPromise = $resultPromise.then(($result: any) => { + return $$createType1($result); + }) as any; + $typingPromise.cancel = $resultPromise.cancel.bind($resultPromise); + return $typingPromise; +} + +/** + * RestartApplication 重启应用程序 + */ +export function RestartApplication(): Promise & { cancel(): void } { + let $resultPromise = $Call.ByID(3341481538) as any; + return $resultPromise; +} + +// Private type creation functions +const $$createType0 = $models.SelfUpdateResult.createFrom; +const $$createType1 = $Create.Nullable($$createType0); diff --git a/frontend/bindings/voidraft/internal/services/updateservice.ts b/frontend/bindings/voidraft/internal/services/updateservice.ts deleted file mode 100644 index 5244a58..0000000 --- a/frontend/bindings/voidraft/internal/services/updateservice.ts +++ /dev/null @@ -1,30 +0,0 @@ -// Cynhyrchwyd y ffeil hon yn awtomatig. PEIDIWCH Â MODIWL -// This file is automatically generated. DO NOT EDIT - -/** - * UpdateService 更新服务 - * @module - */ - -// eslint-disable-next-line @typescript-eslint/ban-ts-comment -// @ts-ignore: Unused imports -import {Call as $Call, Create as $Create} from "@wailsio/runtime"; - -// eslint-disable-next-line @typescript-eslint/ban-ts-comment -// @ts-ignore: Unused imports -import * as $models from "./models.js"; - -/** - * CheckForUpdates 检查更新 - */ -export function CheckForUpdates(): Promise<$models.UpdateCheckResult> & { cancel(): void } { - let $resultPromise = $Call.ByID(3024322786) as any; - let $typingPromise = $resultPromise.then(($result: any) => { - return $$createType0($result); - }) as any; - $typingPromise.cancel = $resultPromise.cancel.bind($resultPromise); - return $typingPromise; -} - -// Private type creation functions -const $$createType0 = $models.UpdateCheckResult.createFrom; diff --git a/frontend/package-lock.json b/frontend/package-lock.json index ebac803..87156b1 100644 --- a/frontend/package-lock.json +++ b/frontend/package-lock.json @@ -49,6 +49,7 @@ "pinia": "^3.0.3", "pinia-plugin-persistedstate": "^4.4.1", "prettier": "^3.5.3", + "remarkable": "^2.0.1", "sass": "^1.89.2", "vue": "^3.5.17", "vue-i18n": "^11.1.6", @@ -58,6 +59,7 @@ "@eslint/js": "^9.29.0", "@lezer/generator": "^1.7.3", "@types/node": "^24.0.3", + "@types/remarkable": "^2.0.8", "@vitejs/plugin-vue": "^5.2.4", "@wailsio/runtime": "latest", "eslint": "^9.29.0", @@ -2099,6 +2101,13 @@ "undici-types": "~7.8.0" } }, + "node_modules/@types/remarkable": { + "version": "2.0.8", + "resolved": "https://registry.npmmirror.com/@types/remarkable/-/remarkable-2.0.8.tgz", + "integrity": "sha512-eKXqPZfpQl1kOADjdKchHrp2gwn9qMnGXhH/AtZe0UrklzhGJkawJo/Y/D0AlWcdWoWamFNIum8+/nkAISQVGg==", + "dev": true, + "license": "MIT" + }, "node_modules/@typescript-eslint/eslint-plugin": { "version": "8.34.1", "resolved": "https://registry.npmmirror.com/@typescript-eslint/eslint-plugin/-/eslint-plugin-8.34.1.tgz", @@ -2685,6 +2694,15 @@ "dev": true, "license": "Python-2.0" }, + "node_modules/autolinker": { + "version": "3.16.2", + "resolved": "https://registry.npmmirror.com/autolinker/-/autolinker-3.16.2.tgz", + "integrity": "sha512-JiYl7j2Z19F9NdTmirENSUUIIL/9MytEWtmzhfmsKPCp9E+G35Y0UNCMoM9tFigxT59qSc8Ml2dlZXOCVTYwuA==", + "license": "MIT", + "dependencies": { + "tslib": "^2.3.0" + } + }, "node_modules/balanced-match": { "version": "1.0.2", "resolved": "https://registry.npmmirror.com/balanced-match/-/balanced-match-1.0.2.tgz", @@ -4337,6 +4355,31 @@ "url": "https://paulmillr.com/funding/" } }, + "node_modules/remarkable": { + "version": "2.0.1", + "resolved": "https://registry.npmmirror.com/remarkable/-/remarkable-2.0.1.tgz", + "integrity": "sha512-YJyMcOH5lrR+kZdmB0aJJ4+93bEojRZ1HGDn9Eagu6ibg7aVZhc3OWbbShRid+Q5eAfsEqWxpe+g5W5nYNfNiA==", + "license": "MIT", + "dependencies": { + "argparse": "^1.0.10", + "autolinker": "^3.11.0" + }, + "bin": { + "remarkable": "bin/remarkable.js" + }, + "engines": { + "node": ">= 6.0.0" + } + }, + "node_modules/remarkable/node_modules/argparse": { + "version": "1.0.10", + "resolved": "https://registry.npmmirror.com/argparse/-/argparse-1.0.10.tgz", + "integrity": "sha512-o5Roy6tNG4SL/FOkCAN6RzjiakZS25RLYFrcMttJqbdd8BWrnA+fGz57iN5Pb06pvBGvl5gQ0B48dJlslXvoTg==", + "license": "MIT", + "dependencies": { + "sprintf-js": "~1.0.2" + } + }, "node_modules/resolve-from": { "version": "4.0.0", "resolved": "https://registry.npmmirror.com/resolve-from/-/resolve-from-4.0.0.tgz", @@ -4510,6 +4553,12 @@ "node": ">=0.10.0" } }, + "node_modules/sprintf-js": { + "version": "1.0.3", + "resolved": "https://registry.npmmirror.com/sprintf-js/-/sprintf-js-1.0.3.tgz", + "integrity": "sha512-D9cPgkvLlV3t3IzL0D0YLvGA9Ahk4PcvVwUbN0dSGr1aP0Nrt4AEnTUbuGvquEC0mA64Gqt1fzirlRs5ibXx8g==", + "license": "BSD-3-Clause" + }, "node_modules/std-env": { "version": "3.9.0", "resolved": "https://registry.npmmirror.com/std-env/-/std-env-3.9.0.tgz", @@ -4655,6 +4704,12 @@ "typescript": ">=4.8.4" } }, + "node_modules/tslib": { + "version": "2.8.1", + "resolved": "https://registry.npmmirror.com/tslib/-/tslib-2.8.1.tgz", + "integrity": "sha512-oJFu94HQb+KVduSUQL7wnpmqnfmLsOA/nAh6b6EH0wCEoK0/mPeXU6c3wKDV83MkOuHPRHtSXKKU99IBazS/2w==", + "license": "0BSD" + }, "node_modules/type-check": { "version": "0.4.0", "resolved": "https://registry.npmmirror.com/type-check/-/type-check-0.4.0.tgz", diff --git a/frontend/package.json b/frontend/package.json index e6ad64e..4f63287 100644 --- a/frontend/package.json +++ b/frontend/package.json @@ -53,6 +53,7 @@ "pinia": "^3.0.3", "pinia-plugin-persistedstate": "^4.4.1", "prettier": "^3.5.3", + "remarkable": "^2.0.1", "sass": "^1.89.2", "vue": "^3.5.17", "vue-i18n": "^11.1.6", @@ -62,6 +63,7 @@ "@eslint/js": "^9.29.0", "@lezer/generator": "^1.7.3", "@types/node": "^24.0.3", + "@types/remarkable": "^2.0.8", "@vitejs/plugin-vue": "^5.2.4", "@wailsio/runtime": "latest", "eslint": "^9.29.0", diff --git a/frontend/src/components/monitor/MemoryMonitor.vue b/frontend/src/components/monitor/MemoryMonitor.vue index 0bb223f..583e3fa 100644 --- a/frontend/src/components/monitor/MemoryMonitor.vue +++ b/frontend/src/components/monitor/MemoryMonitor.vue @@ -1,18 +1,40 @@