From 4283a085f233cfbb9205ac525b4f42af51d1985a Mon Sep 17 00:00:00 2001 From: jliddev Date: Fri, 12 Nov 2021 13:17:56 -0600 Subject: [PATCH 01/10] Update the prod website url to the correct domain --- wowup-electron/package.json | 2 +- .../src/app/services/wowup/patch-notes.service.ts | 7 +++---- wowup-electron/src/environments/environment.prod.ts | 2 +- 3 files changed, 5 insertions(+), 6 deletions(-) diff --git a/wowup-electron/package.json b/wowup-electron/package.json index 0f804d56..5ef60156 100644 --- a/wowup-electron/package.json +++ b/wowup-electron/package.json @@ -1,7 +1,7 @@ { "name": "wowup", "productName": "WowUp", - "version": "2.6.0-beta.2", + "version": "2.5.2", "description": "World of Warcraft addon updater", "homepage": "https://wowup.io", "author": { diff --git a/wowup-electron/src/app/services/wowup/patch-notes.service.ts b/wowup-electron/src/app/services/wowup/patch-notes.service.ts index a336174b..79b076d8 100644 --- a/wowup-electron/src/app/services/wowup/patch-notes.service.ts +++ b/wowup-electron/src/app/services/wowup/patch-notes.service.ts @@ -16,17 +16,16 @@ export class PatchNotesService { const CHANGELOGS: ChangeLog[] = [ { - Version: "2.6.0", + Version: "2.5.2", html: ` -

New Features

+

Hotfix

`, }, { Version: "2.5.1", html: ` -

Hotfix

-
+
diff --git a/wowup-electron/src/app/components/addons/install-from-url-dialog/install-from-url-dialog.component.ts b/wowup-electron/src/app/components/addons/install-from-url-dialog/install-from-url-dialog.component.ts index bd39b15c..9331acfa 100644 --- a/wowup-electron/src/app/components/addons/install-from-url-dialog/install-from-url-dialog.component.ts +++ b/wowup-electron/src/app/components/addons/install-from-url-dialog/install-from-url-dialog.component.ts @@ -17,6 +17,7 @@ import { GitHubLimitError, NoReleaseFoundError, } from "../../../errors"; +import { SearchByUrlResult } from "../../../addon-providers/addon-provider"; interface DownloadCounts { count: number; @@ -76,7 +77,7 @@ export class InstallFromUrlDialogComponent implements OnDestroy { this.showInstallSpinner = true; this._installSubscription = from( - this._addonService.installPotentialAddon(this.addon, selectedInstallation) + this._addonService.installPotentialAddon(this.addon, selectedInstallation, undefined, this.addon.files[0]) ).subscribe({ next: () => { this.showInstallSpinner = false; @@ -125,21 +126,23 @@ export class InstallFromUrlDialogComponent implements OnDestroy { throw new Error(`Selected installation not found`); } - const importedAddon = await this._addonService.getAddonByUrl(url, selectedInstallation); - if (!importedAddon) { + const searchByUrlResult = await this._addonService.getAddonByUrl(url, selectedInstallation); + if (!searchByUrlResult) { throw new Error("Addon not found"); } - this.addon = importedAddon; + this.addon = searchByUrlResult.searchResult; this.hasThumbnail = !!this.addon.thumbnailUrl; this.thumbnailLetter = this.addon.name.charAt(0).toUpperCase(); const addonInstalled = this._addonService.isInstalled( - importedAddon.externalId, - importedAddon.providerName, + this.addon.externalId, + this.addon.providerName, selectedInstallation ); + this.handleImportErrors(searchByUrlResult); + if (addonInstalled) { this.showInstallSuccess = true; this.showInstallButton = false; @@ -187,6 +190,23 @@ export class InstallFromUrlDialogComponent implements OnDestroy { } } + private handleImportErrors(result: SearchByUrlResult) { + if (!Array.isArray(result.errors)) { + return; + } + + for (const error of result.errors) { + if (error instanceof AssetMissingError) { + const message = this._translateService.instant("DIALOGS.INSTALL_FROM_URL.IMPORT_ASSET_WARNING", { + zipName: result.searchResult.files[0].version, + }); + const title = this._translateService.instant("DIALOGS.INSTALL_FROM_URL.IMPORT_WARNING_TITLE"); + + this.showErrorMessage(message, title); + } + } + } + private getUrlFromQuery(): URL | undefined { try { return new URL(this.query); @@ -197,12 +217,14 @@ export class InstallFromUrlDialogComponent implements OnDestroy { } } - private showErrorMessage(errorMessage: string) { + private showErrorMessage(errorMessage: string, title?: string) { const dialogRef = this._dialog.open(AlertDialogComponent, { minWidth: 250, data: { - title: this._translateService.instant("DIALOGS.INSTALL_FROM_URL.ERROR.TITLE"), + title: title || this._translateService.instant("DIALOGS.INSTALL_FROM_URL.ERROR.TITLE"), message: errorMessage, + positiveButtonStyle: "raised", + positiveButtonColor: "primary", }, }); dialogRef.afterClosed().subscribe(); diff --git a/wowup-electron/src/app/components/common/alert-dialog/alert-dialog.component.html b/wowup-electron/src/app/components/common/alert-dialog/alert-dialog.component.html index 8694bb40..211cf12e 100644 --- a/wowup-electron/src/app/components/common/alert-dialog/alert-dialog.component.html +++ b/wowup-electron/src/app/components/common/alert-dialog/alert-dialog.component.html @@ -2,12 +2,23 @@

 
-
- - -
\ No newline at end of file +
diff --git a/wowup-electron/src/app/errors/index.ts b/wowup-electron/src/app/errors/index.ts index 31c3d526..154071b5 100644 --- a/wowup-electron/src/app/errors/index.ts +++ b/wowup-electron/src/app/errors/index.ts @@ -1,7 +1,9 @@ export * from "./install-error"; -import { AddonWarningType } from "../../common/wowup/models"; import { CustomError } from "ts-custom-error"; +import { AddonWarningType } from "../../common/wowup/models"; +import { AddonSearchResult } from "../models/wowup/addon-search-result"; + export class ErrorContainer extends CustomError { public readonly innerError?: Error; public readonly warningType?: AddonWarningType; @@ -13,9 +15,25 @@ export class ErrorContainer extends CustomError { } } -export class ClassicAssetMissingError extends CustomError {} +export class ClassicAssetMissingError extends CustomError { + public searchResult?: AddonSearchResult; -export class BurningCrusadeAssetMissingError extends CustomError {} + constructor(message?: string, searchResult?: AddonSearchResult) { + super(message); + + this.searchResult = searchResult; + } +} + +export class BurningCrusadeAssetMissingError extends CustomError { + public searchResult?: AddonSearchResult; + + constructor(message?: string, searchResult?: AddonSearchResult) { + super(message); + + this.searchResult = searchResult; + } +} export class AssetMissingError extends CustomError {} diff --git a/wowup-electron/src/app/services/addons/addon.provider.factory.ts b/wowup-electron/src/app/services/addons/addon.provider.factory.ts index e544a126..1394e71c 100644 --- a/wowup-electron/src/app/services/addons/addon.provider.factory.ts +++ b/wowup-electron/src/app/services/addons/addon.provider.factory.ts @@ -63,7 +63,7 @@ export class AddonProviderFactory { } public createGitHubAddonProvider(): GitHubAddonProvider { - return new GitHubAddonProvider(this._httpClient); + return new GitHubAddonProvider(this._httpClient, this._warcraftService); } public createWowUpAddonProvider(): WowUpAddonProvider { diff --git a/wowup-electron/src/app/services/addons/addon.service.ts b/wowup-electron/src/app/services/addons/addon.service.ts index 01ede106..be4a99e8 100644 --- a/wowup-electron/src/app/services/addons/addon.service.ts +++ b/wowup-electron/src/app/services/addons/addon.service.ts @@ -33,7 +33,7 @@ import { AddonDependencyType, AddonWarningType, } from "../../../common/wowup/models"; -import { AddonProvider } from "../../addon-providers/addon-provider"; +import { AddonProvider, SearchByUrlResult } from "../../addon-providers/addon-provider"; import { CurseAddonProvider } from "../../addon-providers/curse-addon-provider"; import { WowUpAddonProvider } from "../../addon-providers/wowup-addon-provider"; import { AddonScanError, AddonSyncError, GenericProviderError } from "../../errors"; @@ -939,7 +939,7 @@ export class AddonService { return this._addonStorage.get(addonId); } - public async getAddonByUrl(url: URL, installation: WowInstallation): Promise { + public async getAddonByUrl(url: URL, installation: WowInstallation): Promise { const provider = this.getAddonProvider(url); if (!provider) { console.warn(`No provider found for url: ${url.toString()}`); diff --git a/wowup-electron/src/app/services/download/download.service.ts b/wowup-electron/src/app/services/download/download.service.ts index 0cb57c8c..d349e912 100644 --- a/wowup-electron/src/app/services/download/download.service.ts +++ b/wowup-electron/src/app/services/download/download.service.ts @@ -12,6 +12,10 @@ import { ElectronService } from "../electron/electron.service"; export class DownloadService { public constructor(private _electronService: ElectronService) {} + /** + * Downloads a file URL to the specified folder, prepends UUID so there are no collisions + * @returns Saved file path + */ public downloadZipFile( url: string, fileName: string, diff --git a/wowup-electron/src/app/services/files/file.service.ts b/wowup-electron/src/app/services/files/file.service.ts index d41c4cbb..f48b0ed8 100644 --- a/wowup-electron/src/app/services/files/file.service.ts +++ b/wowup-electron/src/app/services/files/file.service.ts @@ -26,6 +26,7 @@ import { UnzipRequest } from "../../../common/models/unzip-request"; import { FsDirent, FsStats, TreeNode } from "../../../common/models/ipc-events"; import { ElectronService } from "../electron/electron.service"; import { GetDirectoryTreeOptions, GetDirectoryTreeRequest } from "../../../common/models/ipc-request"; +import { ZipEntry } from "../../../common/models/ipc-response"; @Injectable({ providedIn: "root", @@ -160,8 +161,12 @@ export class FileService { return this._electronService.invoke(IPC_LIST_FILES_CHANNEL, sourcePath, filter); } + public listZipFiles(sourcePath: string, filter: string): Promise { + return this._electronService.invoke("zip-list-files", sourcePath, filter); + } + public readFileInZip(zipPath: string, filePath: string): Promise { - return this._electronService.invoke("zip-read-file", zipPath, filePath); + return this._electronService.invoke("zip-read-file", zipPath, filePath); } public async unzipFile(zipFilePath: string, outputFolder: string): Promise { diff --git a/wowup-electron/src/app/services/wowup/patch-notes.service.ts b/wowup-electron/src/app/services/wowup/patch-notes.service.ts index 5a377ab3..b2945f2e 100644 --- a/wowup-electron/src/app/services/wowup/patch-notes.service.ts +++ b/wowup-electron/src/app/services/wowup/patch-notes.service.ts @@ -21,6 +21,10 @@ const CHANGELOGS: ChangeLog[] = [

New Features

  • Added the ability to switch to Beta build release channel from the app
  • +
+

Changes

+
    +
  • Modified the GitHub install by URL feature to be more flexible for multi-toc addons
`, }, { diff --git a/wowup-electron/src/assets/i18n/cs.json b/wowup-electron/src/assets/i18n/cs.json index 90fa73d7..78efc765 100644 --- a/wowup-electron/src/assets/i18n/cs.json +++ b/wowup-electron/src/assets/i18n/cs.json @@ -281,7 +281,9 @@ "NO_SEARCH_RESULTS": "Hledání neodpovídá žádný addon.", "TITLE": "Instalace addonu se nepodařila" }, + "IMPORT_ASSET_WARNING": "We were unable to verify if the latest release of this addon is compatible with your selected client.\n\nBut we did find a zip file \"{zipName}\".\n\nInstall at your own risk.", "IMPORT_BUTTON": "Importovat", + "IMPORT_WARNING_TITLE": "Addon Import Warning", "INSTALL_BUTTON": "Instalovat", "INSTALL_SUCCESS_LABEL": "Úspěšně nainstalováno!", "SUPPORTED_SOURCES": "Podporuje WowInterface a GitHub", diff --git a/wowup-electron/src/assets/i18n/de.json b/wowup-electron/src/assets/i18n/de.json index 78998fa0..986005cd 100644 --- a/wowup-electron/src/assets/i18n/de.json +++ b/wowup-electron/src/assets/i18n/de.json @@ -281,7 +281,9 @@ "NO_SEARCH_RESULTS": "Es wurden keine Suchergebnisse gefunden.", "TITLE": "Installation fehlgeschlagen" }, + "IMPORT_ASSET_WARNING": "We were unable to verify if the latest release of this addon is compatible with your selected client.\n\nBut we did find a zip file \"{zipName}\".\n\nInstall at your own risk.", "IMPORT_BUTTON": "Importieren", + "IMPORT_WARNING_TITLE": "Addon Import Warning", "INSTALL_BUTTON": "Installieren", "INSTALL_SUCCESS_LABEL": "Installiert!", "SUPPORTED_SOURCES": "Unterstützt WowInterface und GitHub", diff --git a/wowup-electron/src/assets/i18n/en.json b/wowup-electron/src/assets/i18n/en.json index 9cbb8d1b..b4665b2d 100644 --- a/wowup-electron/src/assets/i18n/en.json +++ b/wowup-electron/src/assets/i18n/en.json @@ -281,7 +281,9 @@ "NO_SEARCH_RESULTS": "No search results were found.", "TITLE": "Addon Installation Failed" }, + "IMPORT_ASSET_WARNING": "We were unable to verify if the latest release of this addon is compatible with your selected client.\n\nBut we did find a zip file \"{zipName}\".\n\nInstall at your own risk.", "IMPORT_BUTTON": "Import", + "IMPORT_WARNING_TITLE": "Addon Import Warning", "INSTALL_BUTTON": "Install", "INSTALL_SUCCESS_LABEL": "Installed!", "SUPPORTED_SOURCES": "Supports WowInterface and GitHub", diff --git a/wowup-electron/src/assets/i18n/es.json b/wowup-electron/src/assets/i18n/es.json index 89d7b807..f7647577 100644 --- a/wowup-electron/src/assets/i18n/es.json +++ b/wowup-electron/src/assets/i18n/es.json @@ -281,7 +281,9 @@ "NO_SEARCH_RESULTS": "No se encontraron resultados.", "TITLE": "Falló la instalación del addon" }, + "IMPORT_ASSET_WARNING": "We were unable to verify if the latest release of this addon is compatible with your selected client.\n\nBut we did find a zip file \"{zipName}\".\n\nInstall at your own risk.", "IMPORT_BUTTON": "Importar", + "IMPORT_WARNING_TITLE": "Addon Import Warning", "INSTALL_BUTTON": "Instalar", "INSTALL_SUCCESS_LABEL": "¡Instalado!", "SUPPORTED_SOURCES": "Soporta WowInterface y GitHub", diff --git a/wowup-electron/src/assets/i18n/fr.json b/wowup-electron/src/assets/i18n/fr.json index e128090d..7111eac7 100644 --- a/wowup-electron/src/assets/i18n/fr.json +++ b/wowup-electron/src/assets/i18n/fr.json @@ -281,7 +281,9 @@ "NO_SEARCH_RESULTS": "La recherche n'a retourné aucun résultat.", "TITLE": "Echec de l'installation de l'addon" }, + "IMPORT_ASSET_WARNING": "We were unable to verify if the latest release of this addon is compatible with your selected client.\n\nBut we did find a zip file \"{zipName}\".\n\nInstall at your own risk.", "IMPORT_BUTTON": "Importer", + "IMPORT_WARNING_TITLE": "Addon Import Warning", "INSTALL_BUTTON": "Installer", "INSTALL_SUCCESS_LABEL": "Installé !", "SUPPORTED_SOURCES": "Supporte WowInterface et GitHub", diff --git a/wowup-electron/src/assets/i18n/it.json b/wowup-electron/src/assets/i18n/it.json index ed0be111..646fed8f 100644 --- a/wowup-electron/src/assets/i18n/it.json +++ b/wowup-electron/src/assets/i18n/it.json @@ -281,7 +281,9 @@ "NO_SEARCH_RESULTS": "Nessun risultato dalla ricerca.", "TITLE": "Installazione dell'Addon Fallita" }, + "IMPORT_ASSET_WARNING": "We were unable to verify if the latest release of this addon is compatible with your selected client.\n\nBut we did find a zip file \"{zipName}\".\n\nInstall at your own risk.", "IMPORT_BUTTON": "Importa", + "IMPORT_WARNING_TITLE": "Addon Import Warning", "INSTALL_BUTTON": "Installa", "INSTALL_SUCCESS_LABEL": "Installato!", "SUPPORTED_SOURCES": "(Supporta WowInterface e GitHub)", diff --git a/wowup-electron/src/assets/i18n/ko.json b/wowup-electron/src/assets/i18n/ko.json index 945b4a9c..c5e109be 100644 --- a/wowup-electron/src/assets/i18n/ko.json +++ b/wowup-electron/src/assets/i18n/ko.json @@ -281,7 +281,9 @@ "NO_SEARCH_RESULTS": "검색 결과가 없습니다.", "TITLE": "애드온 설치 실패" }, + "IMPORT_ASSET_WARNING": "We were unable to verify if the latest release of this addon is compatible with your selected client.\n\nBut we did find a zip file \"{zipName}\".\n\nInstall at your own risk.", "IMPORT_BUTTON": "가져오기", + "IMPORT_WARNING_TITLE": "Addon Import Warning", "INSTALL_BUTTON": "설치", "INSTALL_SUCCESS_LABEL": "설치됨!", "SUPPORTED_SOURCES": "WowInterface 와 GitHub 주소가 지원됩니다", diff --git a/wowup-electron/src/assets/i18n/nb.json b/wowup-electron/src/assets/i18n/nb.json index 8b29f6c2..7264671c 100644 --- a/wowup-electron/src/assets/i18n/nb.json +++ b/wowup-electron/src/assets/i18n/nb.json @@ -281,7 +281,9 @@ "NO_SEARCH_RESULTS": "No search results were found.", "TITLE": "Addon Installation Failed" }, + "IMPORT_ASSET_WARNING": "We were unable to verify if the latest release of this addon is compatible with your selected client.\n\nBut we did find a zip file \"{zipName}\".\n\nInstall at your own risk.", "IMPORT_BUTTON": "Importer", + "IMPORT_WARNING_TITLE": "Addon Import Warning", "INSTALL_BUTTON": "Installer", "INSTALL_SUCCESS_LABEL": "Installert!", "SUPPORTED_SOURCES": "Støtter WowInterface og GitHub*", diff --git a/wowup-electron/src/assets/i18n/pt.json b/wowup-electron/src/assets/i18n/pt.json index 079887d4..175add46 100644 --- a/wowup-electron/src/assets/i18n/pt.json +++ b/wowup-electron/src/assets/i18n/pt.json @@ -281,7 +281,9 @@ "NO_SEARCH_RESULTS": "No search results were found.", "TITLE": "Instalação do Addon Falhou" }, + "IMPORT_ASSET_WARNING": "We were unable to verify if the latest release of this addon is compatible with your selected client.\n\nBut we did find a zip file \"{zipName}\".\n\nInstall at your own risk.", "IMPORT_BUTTON": "Importar", + "IMPORT_WARNING_TITLE": "Addon Import Warning", "INSTALL_BUTTON": "Instalar", "INSTALL_SUCCESS_LABEL": "Instalado!", "SUPPORTED_SOURCES": "Suporta WowInterface e GitHub*", diff --git a/wowup-electron/src/assets/i18n/ru.json b/wowup-electron/src/assets/i18n/ru.json index 9de82f9d..cb99f2fc 100644 --- a/wowup-electron/src/assets/i18n/ru.json +++ b/wowup-electron/src/assets/i18n/ru.json @@ -281,7 +281,9 @@ "NO_SEARCH_RESULTS": "Поиск не дал результатов.", "TITLE": "Установка модификации не удалась" }, + "IMPORT_ASSET_WARNING": "We were unable to verify if the latest release of this addon is compatible with your selected client.\n\nBut we did find a zip file \"{zipName}\".\n\nInstall at your own risk.", "IMPORT_BUTTON": "Импорт", + "IMPORT_WARNING_TITLE": "Addon Import Warning", "INSTALL_BUTTON": "Установить", "INSTALL_SUCCESS_LABEL": "Установлена!", "SUPPORTED_SOURCES": "Поддерживаются WowInterface и GitHub", diff --git a/wowup-electron/src/assets/i18n/zh-TW.json b/wowup-electron/src/assets/i18n/zh-TW.json index 177daf0e..29a7412a 100644 --- a/wowup-electron/src/assets/i18n/zh-TW.json +++ b/wowup-electron/src/assets/i18n/zh-TW.json @@ -281,7 +281,9 @@ "NO_SEARCH_RESULTS": "无搜索结果。", "TITLE": "插件安裝失敗" }, + "IMPORT_ASSET_WARNING": "We were unable to verify if the latest release of this addon is compatible with your selected client.\n\nBut we did find a zip file \"{zipName}\".\n\nInstall at your own risk.", "IMPORT_BUTTON": "匯入", + "IMPORT_WARNING_TITLE": "Addon Import Warning", "INSTALL_BUTTON": "安裝", "INSTALL_SUCCESS_LABEL": "安裝成功!", "SUPPORTED_SOURCES": "支援 WowInterface 和 GitHub", diff --git a/wowup-electron/src/assets/i18n/zh.json b/wowup-electron/src/assets/i18n/zh.json index 750843a7..9235a276 100644 --- a/wowup-electron/src/assets/i18n/zh.json +++ b/wowup-electron/src/assets/i18n/zh.json @@ -281,7 +281,9 @@ "NO_SEARCH_RESULTS": "无搜索结果。", "TITLE": "插件安装失败" }, + "IMPORT_ASSET_WARNING": "We were unable to verify if the latest release of this addon is compatible with your selected client.\n\nBut we did find a zip file \"{zipName}\".\n\nInstall at your own risk.", "IMPORT_BUTTON": "导入", + "IMPORT_WARNING_TITLE": "Addon Import Warning", "INSTALL_BUTTON": "安装", "INSTALL_SUCCESS_LABEL": "安装成功!", "SUPPORTED_SOURCES": "支持 WowInterface 和 GitHub", diff --git a/wowup-electron/src/common/models/ipc-response.ts b/wowup-electron/src/common/models/ipc-response.ts index 484ad1d7..01524b67 100644 --- a/wowup-electron/src/common/models/ipc-response.ts +++ b/wowup-electron/src/common/models/ipc-response.ts @@ -9,3 +9,9 @@ export interface BackupGetExistingResponse { export interface BackupCreateResponse { error?: string; } + +export interface ZipEntry { + name: string; + path: string; + isDirectory: boolean; +} diff --git a/wowup-electron/src/common/wowup.d.ts b/wowup-electron/src/common/wowup.d.ts index 0c683d62..95e8fc5a 100644 --- a/wowup-electron/src/common/wowup.d.ts +++ b/wowup-electron/src/common/wowup.d.ts @@ -87,7 +87,8 @@ declare type RendererChannels = | "show-item-in-folder" | "base64-encode" | "base64-decode" - | "set-release-channel"; + | "set-release-channel" + | "zip-list-files"; declare global { interface Window { From 941ecbdd9c13e32229a125e44444d76f168e185c Mon Sep 17 00:00:00 2001 From: Michael Fulton Date: Sat, 20 Nov 2021 12:42:11 -0500 Subject: [PATCH 10/10] Use IPC channel for main proc calls and move platform specific code to platform implementation file --- wowup-electron/app/ipc-events.ts | 7 +++ .../src/app/services/files/file.service.ts | 5 ++ .../warcraft/warcraft-installation.service.ts | 26 +------- .../warcraft/warcraft.service.impl.ts | 2 + .../warcraft/warcraft.service.linux.ts | 62 +++++++++---------- .../services/warcraft/warcraft.service.mac.ts | 7 ++- .../app/services/warcraft/warcraft.service.ts | 1 + .../services/warcraft/warcraft.service.win.ts | 5 ++ wowup-electron/src/common/constants.ts | 1 + wowup-electron/src/common/wowup.d.ts | 1 + 10 files changed, 61 insertions(+), 56 deletions(-) diff --git a/wowup-electron/app/ipc-events.ts b/wowup-electron/app/ipc-events.ts index b5cf78eb..7223672f 100644 --- a/wowup-electron/app/ipc-events.ts +++ b/wowup-electron/app/ipc-events.ts @@ -21,6 +21,7 @@ import * as path from "path"; import { Transform } from "stream"; import * as yauzl from "yauzl"; import * as fs from "fs"; +import * as os from "os"; import { IPC_ADDONS_SAVE_ALL, @@ -34,6 +35,7 @@ import { IPC_DOWNLOAD_FILE_CHANNEL, IPC_FOCUS_WINDOW, IPC_GET_APP_VERSION, + IPC_GET_HOME_DIR, IPC_GET_ASSET_FILE_PATH, IPC_GET_DIRECTORY_TREE, IPC_GET_LATEST_DIR_UPDATE_TIME, @@ -107,6 +109,7 @@ import { createTray, restoreWindow } from "./system-tray"; import { WowUpFolderScanner } from "./wowup-folder-scanner"; import * as push from "./push"; import { GetDirectoryTreeRequest } from "../src/common/models/ipc-request"; +import { electron } from 'process'; let PENDING_OPEN_URLS: string[] = []; @@ -470,6 +473,10 @@ export function initializeIpcHandlers(window: BrowserWindow, userAgent: string): return getDirTree(args.dirPath, args.opts); }); + handle(IPC_GET_HOME_DIR, (): String => { + return os.homedir(); + }); + handle(IPC_MINIMIZE_WINDOW, () => { if (window?.minimizable) { window.minimize(); diff --git a/wowup-electron/src/app/services/files/file.service.ts b/wowup-electron/src/app/services/files/file.service.ts index f48b0ed8..d8675a9b 100644 --- a/wowup-electron/src/app/services/files/file.service.ts +++ b/wowup-electron/src/app/services/files/file.service.ts @@ -4,6 +4,7 @@ import { IPC_COPY_FILE_CHANNEL, IPC_CREATE_DIRECTORY_CHANNEL, IPC_DELETE_DIRECTORY_CHANNEL, + IPC_GET_HOME_DIR, IPC_GET_ASSET_FILE_PATH, IPC_LIST_DIRECTORIES_CHANNEL, IPC_PATH_EXISTS_CHANNEL, @@ -34,6 +35,10 @@ import { ZipEntry } from "../../../common/models/ipc-response"; export class FileService { public constructor(private _electronService: ElectronService) {} + public getHomeDir(): Promise { + return this._electronService.invoke(IPC_GET_HOME_DIR); + } + public getAssetFilePath(fileName: string): Promise { return this._electronService.invoke(IPC_GET_ASSET_FILE_PATH, fileName); } diff --git a/wowup-electron/src/app/services/warcraft/warcraft-installation.service.ts b/wowup-electron/src/app/services/warcraft/warcraft-installation.service.ts index 22dc8cc9..3047d8c7 100644 --- a/wowup-electron/src/app/services/warcraft/warcraft-installation.service.ts +++ b/wowup-electron/src/app/services/warcraft/warcraft-installation.service.ts @@ -234,13 +234,7 @@ export class WarcraftInstallationService { const label = await this.getNewInstallLabel(typeName, currentInstallations.length); - let fullProductPath: string; - if (this._electronService.isLinux) { - fullProductPath = this.getFullLutrisProductPath(product.location, blizzardAgentPath, product.clientType); - } else { - fullProductPath = this.getFullProductPath(product.location, product.clientType); - } - console.log(fullProductPath) + let fullProductPath = this.getFullProductPath(product.location, product.clientType); const wowInstallation: WowInstallation = { id: uuidv4(), clientType: product.clientType, @@ -324,12 +318,7 @@ export class WarcraftInstallationService { const label = await this._translateService.get(`COMMON.CLIENT_TYPES.${typeName.toUpperCase()}`).toPromise(); - let newLocation: string; - if (this._electronService.isLinux) { - newLocation = this.getFullLutrisProductPath(legacyLocation, this._blizzardAgentPath, clientType); - } else { - newLocation = this.getFullProductPath(legacyLocation, clientType); - } + const newLocation = this.getFullProductPath(legacyLocation, clientType); const newLocationExists = await this._fileService.pathExists(newLocation); if (!newLocationExists) { @@ -357,17 +346,6 @@ export class WarcraftInstallationService { return path.join(location, clientFolderName, executableName); } - private getFullLutrisProductPath(location: string, agentPath: string, clientType: WowClientType): string { - const clientFolderName = this._warcraftService.getClientFolderName(clientType); - const executableName = this._warcraftService.getExecutableName(clientType); - const agentPathPrefixRegex = new RegExp(`(.*drive_c)`); - console.log(`location: ${location} agentPath: ${agentPath} clienttype: ${clientType}`) - const regexResults = agentPathPrefixRegex.exec(agentPath) - console.log(regexResults) - const agentPathPrefix = regexResults[1].trim(); - return path.join(agentPathPrefix, location.substr(3), clientFolderName, executableName); - } - private getLegacyDefaultAddonChannel(typeName: string): AddonChannelType { const legacyDefaultChannelKey = `${typeName}${DEFAULT_CHANNEL_PREFERENCE_KEY_SUFFIX}`.toLowerCase(); return parseInt(this._preferenceStorageService.findByKey(legacyDefaultChannelKey), 10) as AddonChannelType; diff --git a/wowup-electron/src/app/services/warcraft/warcraft.service.impl.ts b/wowup-electron/src/app/services/warcraft/warcraft.service.impl.ts index addb62c2..48fa79bf 100644 --- a/wowup-electron/src/app/services/warcraft/warcraft.service.impl.ts +++ b/wowup-electron/src/app/services/warcraft/warcraft.service.impl.ts @@ -1,4 +1,5 @@ import { WowClientType } from "../../../common/warcraft/wow-client-type"; +import { InstalledProduct } from '../../models/warcraft/installed-product'; export interface WarcraftServiceImpl { getExecutableExtension(): string; @@ -6,4 +7,5 @@ export interface WarcraftServiceImpl { getBlizzardAgentPath(): Promise; getExecutableName(clientType: WowClientType): string; getClientType(binaryPath: string): WowClientType; + resolveProducts(decodedProducts: InstalledProduct[], agentPath: string): InstalledProduct[]; } diff --git a/wowup-electron/src/app/services/warcraft/warcraft.service.linux.ts b/wowup-electron/src/app/services/warcraft/warcraft.service.linux.ts index 7d0e1280..f6d6a6ad 100644 --- a/wowup-electron/src/app/services/warcraft/warcraft.service.linux.ts +++ b/wowup-electron/src/app/services/warcraft/warcraft.service.linux.ts @@ -1,7 +1,7 @@ import * as path from "path"; -import os from 'os'; import { WOW_CLASSIC_ERA_FOLDER, WOW_CLASSIC_ERA_PTR_FOLDER } from "../../../common/constants"; import { WowClientType } from "../../../common/warcraft/wow-client-type"; +import { InstalledProduct } from '../../models/warcraft/installed-product'; import { ElectronService } from "../electron/electron.service"; import { FileService } from "../files/file.service"; import { WarcraftServiceImpl } from "./warcraft.service.impl"; @@ -22,9 +22,7 @@ const WOW_APP_NAMES = [ WOW_CLASSIC_BETA_NAME, ]; -const LUTRIS_DEFAULT_LIBRARY_PATH = "/Games" -const LUTRIS_CONFIG_PATH = "/.config/lutris"; -const LUTRIS_CONFIG_FILE = "system.yml"; +const LUTRIS_CONFIG_PATH = "/.config/lutris/system.yml" // Search in this order until products are found on one. // All WoW products can be found under any or all of them, // since each of them are essentially just Battle.net @@ -32,7 +30,7 @@ const LUTRIS_CONFIG_FILE = "system.yml"; const LUTRIS_WOW_DIRS = [ "battlenet/drive_c", "world-of-warcraft/drive_c", - "world-of-warcraft-classic/drive_c"]; + "world-of-warcraft-classic/drive_c"] // BLIZZARD STRINGS const WINDOWS_BLIZZARD_AGENT_PATH = "ProgramData/Battle.net/Agent"; @@ -50,21 +48,20 @@ export class WarcraftServiceLinux implements WarcraftServiceImpl { } /** - * On Linux players are normally using Lutris to install Battle.net launcher or WoW + * On Linux players could be using Lutris to install the Battle.net launcher or WoW */ public async getBlizzardAgentPath(): Promise { try { - const lutrisLibraryPath = await this.getLutrisWowProductPath(); + const lutrisLibraryPath = await this.getLutrisWowPath(); if (lutrisLibraryPath.length === 0) { throw new Error("Lutris library not found"); } const agentPath = path.join(lutrisLibraryPath, WINDOWS_BLIZZARD_AGENT_PATH, BLIZZARD_PRODUCT_DB_NAME); - console.log(`Agent path: ${agentPath}`) const agentPathExists = await this._fileService.pathExists(agentPath); if (agentPathExists) { - console.log(`Found products at ${agentPath}`); + console.log(`Found WoW products at ${agentPath}`); return agentPath; } @@ -75,32 +72,35 @@ export class WarcraftServiceLinux implements WarcraftServiceImpl { return ""; } - public async getLutrisWowProductPath(): Promise { - const lutrisConfigPath = path.join(os.homedir(), LUTRIS_CONFIG_PATH); + public resolveProducts(decodedProducts: InstalledProduct[], agentPath: string): InstalledProduct[] { + const resolvedProducts: InstalledProduct[] = []; + const agentPathPrefixRegex = new RegExp(`(.*drive_c)`); + for (const product of decodedProducts) { + console.log(`location: ${location} agentPath: ${agentPath}`); + const agentPathPrefix = agentPathPrefixRegex.exec(agentPath)[1].trim(); + resolvedProducts.push( + { + ...product, + location: path.join(agentPathPrefix, product.location.substr(3)) + } as InstalledProduct); + + } + return resolvedProducts; + } + + public async getLutrisWowPath(): Promise { + const homeDir = await this._fileService.getHomeDir(); + const resolvedPath = path.join(homeDir, LUTRIS_CONFIG_PATH); try { - const lutrisConfigPathExists = await this._fileService.pathExists(lutrisConfigPath); - if (lutrisConfigPathExists) { - const lutrisConfigFilePath = path.join(lutrisConfigPath, LUTRIS_CONFIG_FILE); - const lutrisConfigFileExists = await this._fileService.pathExists(lutrisConfigFilePath) - let libraryPath: string; - if (lutrisConfigFileExists) { - const lutrisConfig = await this._fileService.readFile(lutrisConfigFilePath); - const libraryPathRegex = new RegExp(`game_path: (.*)`); - const potentialLibraryPath = libraryPathRegex.exec(lutrisConfig)[1].trim(); - const libraryPathExists = await this._fileService.pathExists(potentialLibraryPath); - if (libraryPathExists) { - libraryPath = potentialLibraryPath; - } - } - // If the system.yml file doesn't exist, or game_path entry does not exist within it, - // then use the default game installation path. - if (libraryPath.length == 0) { - libraryPath = path.join(os.homedir(), LUTRIS_DEFAULT_LIBRARY_PATH); - } + const lutrisConfigExists = await this._fileService.pathExists(resolvedPath); + if (lutrisConfigExists) { + const lutrisConfig = await this._fileService.readFile(resolvedPath); + const libraryPathRegex = new RegExp(`game_path: (.*)`); + const libraryPath = libraryPathRegex.exec(lutrisConfig)[1].trim(); const libraryPathExists = await this._fileService.pathExists(libraryPath); if (libraryPathExists) { for (const wowDir of LUTRIS_WOW_DIRS) { - const productPath = path.join(libraryPath, wowDir); + const productPath = path.join(libraryPath, wowDir) const productPathExists = await this._fileService.pathExists(productPath); if (productPathExists) { console.log(`Found WoW product in Lutris library at ${productPath}`); diff --git a/wowup-electron/src/app/services/warcraft/warcraft.service.mac.ts b/wowup-electron/src/app/services/warcraft/warcraft.service.mac.ts index 3ef70b80..9357f795 100644 --- a/wowup-electron/src/app/services/warcraft/warcraft.service.mac.ts +++ b/wowup-electron/src/app/services/warcraft/warcraft.service.mac.ts @@ -2,6 +2,7 @@ import * as path from "path"; import { WOW_CLASSIC_ERA_FOLDER, WOW_CLASSIC_ERA_PTR_FOLDER } from "../../../common/constants"; import { WowClientType } from "../../../common/warcraft/wow-client-type"; +import { InstalledProduct } from '../../models/warcraft/installed-product'; import { FileService } from "../files/file.service"; import { WarcraftServiceImpl } from "./warcraft.service.impl"; @@ -25,7 +26,7 @@ const BLIZZARD_AGENT_PATH = "/Users/Shared/Battle.net/Agent"; const BLIZZARD_PRODUCT_DB_NAME = "product.db"; export class WarcraftServiceMac implements WarcraftServiceImpl { - public constructor(private _fileService: FileService) {} + public constructor(private _fileService: FileService) { } public getExecutableExtension(): string { return "app"; @@ -92,4 +93,8 @@ export class WarcraftServiceMac implements WarcraftServiceImpl { return WowClientType.None; } } + + public resolveProducts(decodedProducts: InstalledProduct[], agentPath: string): InstalledProduct[] { + return decodedProducts; + } } diff --git a/wowup-electron/src/app/services/warcraft/warcraft.service.ts b/wowup-electron/src/app/services/warcraft/warcraft.service.ts index 2de91243..b96f1aa9 100644 --- a/wowup-electron/src/app/services/warcraft/warcraft.service.ts +++ b/wowup-electron/src/app/services/warcraft/warcraft.service.ts @@ -99,6 +99,7 @@ export class WarcraftService { */ public async getInstalledProducts(blizzardAgentPath: string): Promise> { const decodedProducts = await this.decodeProducts(blizzardAgentPath); + const resolvedProducts = this._impl.resolveProducts(decodedProducts, blizzardAgentPath); const dictionary = new Map(); for (const product of decodedProducts) { diff --git a/wowup-electron/src/app/services/warcraft/warcraft.service.win.ts b/wowup-electron/src/app/services/warcraft/warcraft.service.win.ts index b3f8b010..afe8271c 100644 --- a/wowup-electron/src/app/services/warcraft/warcraft.service.win.ts +++ b/wowup-electron/src/app/services/warcraft/warcraft.service.win.ts @@ -4,6 +4,7 @@ import { ElectronService } from "../electron/electron.service"; import { FileService } from "../files/file.service"; import { WarcraftServiceImpl } from "./warcraft.service.impl"; import { IPC_LIST_DISKS_WIN32, WOW_CLASSIC_ERA_FOLDER, WOW_CLASSIC_ERA_PTR_FOLDER } from "../../../common/constants"; +import { InstalledProduct } from '../../models/warcraft/installed-product'; const WOW_RETAIL_NAME = "Wow.exe"; const WOW_RETAIL_PTR_NAME = "WowT.exe"; @@ -109,4 +110,8 @@ export class WarcraftServiceWin implements WarcraftServiceImpl { return WowClientType.None; } } + + public resolveProducts(decodedProducts: InstalledProduct[], agentPath: string): InstalledProduct[] { + return decodedProducts; + } } diff --git a/wowup-electron/src/common/constants.ts b/wowup-electron/src/common/constants.ts index ff5f104d..c082dd53 100644 --- a/wowup-electron/src/common/constants.ts +++ b/wowup-electron/src/common/constants.ts @@ -41,6 +41,7 @@ export const IPC_CURSE_HASH_FILE_CHANNEL = "curse-hash-file"; export const IPC_SHOW_DIRECTORY = "show-directory"; export const IPC_CURSE_GET_SCAN_RESULTS = "curse-get-scan-results"; export const IPC_WOWUP_GET_SCAN_RESULTS = "wowup-get-scan-results"; +export const IPC_GET_HOME_DIR = "get-home-dir"; export const IPC_GET_ASSET_FILE_PATH = "get-asset-file-path"; export const IPC_CREATE_TRAY_MENU_CHANNEL = "create-tray-menu"; export const IPC_LIST_DISKS_WIN32 = "list-disks-win32"; diff --git a/wowup-electron/src/common/wowup.d.ts b/wowup-electron/src/common/wowup.d.ts index 95e8fc5a..08e86589 100644 --- a/wowup-electron/src/common/wowup.d.ts +++ b/wowup-electron/src/common/wowup.d.ts @@ -30,6 +30,7 @@ declare type RendererChannels = | "minimize-window" | "maximize-window" | "show-directory" + | "get-home-dir" | "get-asset-file-path" | "create-directory" | "list-directories"