mirror of
https://github.com/hydralauncher/hydra.git
synced 2026-01-11 13:56:16 +00:00
feat: create SystemPath class to prevent Hydra not opening when some user folders are not correctly set on windows
This commit is contained in:
@@ -1,23 +1,24 @@
|
||||
import { app } from "electron";
|
||||
import path from "node:path";
|
||||
import { SystemPath } from "./services/system-path";
|
||||
|
||||
export const LUDUSAVI_MANIFEST_URL = "https://cdn.losbroxas.org/manifest.yaml";
|
||||
|
||||
export const defaultDownloadsPath = app.getPath("downloads");
|
||||
export const defaultDownloadsPath = SystemPath.getPath("downloads");
|
||||
|
||||
export const isStaging = import.meta.env.MAIN_VITE_API_URL.includes("staging");
|
||||
|
||||
export const levelDatabasePath = path.join(
|
||||
app.getPath("userData"),
|
||||
SystemPath.getPath("userData"),
|
||||
`hydra-db${isStaging ? "-staging" : ""}`
|
||||
);
|
||||
|
||||
export const commonRedistPath = path.join(
|
||||
app.getPath("userData"),
|
||||
SystemPath.getPath("userData"),
|
||||
"CommonRedist"
|
||||
);
|
||||
|
||||
export const logsPath = path.join(app.getPath("userData"), "logs");
|
||||
export const logsPath = path.join(SystemPath.getPath("userData"), "logs");
|
||||
|
||||
export const seedsPath = app.isPackaged
|
||||
? path.join(process.resourcesPath, "seeds")
|
||||
@@ -27,7 +28,7 @@ export const achievementSoundPath = app.isPackaged
|
||||
? path.join(process.resourcesPath, "achievement.wav")
|
||||
: path.join(__dirname, "..", "..", "resources", "achievement.wav");
|
||||
|
||||
export const backupsPath = path.join(app.getPath("userData"), "Backups");
|
||||
export const backupsPath = path.join(SystemPath.getPath("userData"), "Backups");
|
||||
|
||||
export const appVersion = app.getVersion() + (isStaging ? "-staging" : "");
|
||||
|
||||
|
||||
@@ -4,13 +4,13 @@ import * as tar from "tar";
|
||||
import { registerEvent } from "../register-event";
|
||||
import axios from "axios";
|
||||
import os from "node:os";
|
||||
import { app } from "electron";
|
||||
import path from "node:path";
|
||||
import { backupsPath } from "@main/constants";
|
||||
import type { GameShop } from "@types";
|
||||
|
||||
import YAML from "yaml";
|
||||
import { normalizePath } from "@main/helpers";
|
||||
import { SystemPath } from "@main/services/system-path";
|
||||
|
||||
export interface LudusaviBackup {
|
||||
files: {
|
||||
@@ -35,7 +35,7 @@ const replaceLudusaviBackupWithCurrentUser = (
|
||||
drives: Record<string, string>;
|
||||
};
|
||||
|
||||
const currentHomeDir = normalizePath(app.getPath("home"));
|
||||
const currentHomeDir = normalizePath(SystemPath.getPath("home"));
|
||||
|
||||
/* Renaming logic */
|
||||
if (os.platform() === "win32") {
|
||||
@@ -84,7 +84,7 @@ const downloadGameArtifact = async (
|
||||
homeDir: string;
|
||||
}>(`/profile/games/artifacts/${gameArtifactId}/download`);
|
||||
|
||||
const zipLocation = path.join(app.getPath("userData"), objectKey);
|
||||
const zipLocation = path.join(SystemPath.getPath("userData"), objectKey);
|
||||
const backupPath = path.join(backupsPath, `${shop}-${objectId}`);
|
||||
|
||||
if (fs.existsSync(backupPath)) {
|
||||
|
||||
@@ -5,6 +5,7 @@ import { app } from "electron";
|
||||
import { removeSymbolsFromName } from "@shared";
|
||||
import { GameShop } from "@types";
|
||||
import { gamesSublevel, levelKeys } from "@main/level";
|
||||
import { SystemPath } from "@main/services/system-path";
|
||||
|
||||
const createGameShortcut = async (
|
||||
_event: Electron.IpcMainInvokeEvent,
|
||||
@@ -24,7 +25,7 @@ const createGameShortcut = async (
|
||||
const options = {
|
||||
filePath,
|
||||
name: removeSymbolsFromName(game.title),
|
||||
outputPath: app.getPath("desktop"),
|
||||
outputPath: SystemPath.getPath("desktop"),
|
||||
};
|
||||
|
||||
return createDesktopShortcut({
|
||||
|
||||
@@ -4,9 +4,10 @@ import { app } from "electron";
|
||||
import path from "path";
|
||||
import fs from "node:fs";
|
||||
import { logger } from "@main/services";
|
||||
import { SystemPath } from "@main/services/system-path";
|
||||
|
||||
const windowsStartupPath = path.join(
|
||||
app.getPath("appData"),
|
||||
SystemPath.getPath("appData"),
|
||||
"Microsoft",
|
||||
"Windows",
|
||||
"Start Menu",
|
||||
|
||||
@@ -9,8 +9,11 @@ import { levelKeys, db } from "./level";
|
||||
import type { UserPreferences } from "@types";
|
||||
import { TorBoxClient } from "./services/download/torbox";
|
||||
import { CommonRedistManager } from "./services/common-redist-manager";
|
||||
import { SystemPath } from "./services/system-path";
|
||||
|
||||
export const loadState = async () => {
|
||||
SystemPath.checkIfPathsAreAvailable();
|
||||
|
||||
const userPreferences = await db.get<string, UserPreferences | null>(
|
||||
levelKeys.userPreferences,
|
||||
{
|
||||
|
||||
@@ -1,26 +1,26 @@
|
||||
import path from "node:path";
|
||||
import fs from "node:fs";
|
||||
import { app } from "electron";
|
||||
import type { Game, AchievementFile } from "@types";
|
||||
import { Cracker } from "@shared";
|
||||
import { achievementsLogger } from "../logger";
|
||||
import { SystemPath } from "../system-path";
|
||||
|
||||
const getAppDataPath = () => {
|
||||
if (process.platform === "win32") {
|
||||
return app.getPath("appData");
|
||||
return SystemPath.getPath("appData");
|
||||
}
|
||||
|
||||
const user = app.getPath("home").split("/").pop();
|
||||
const user = SystemPath.getPath("home").split("/").pop();
|
||||
|
||||
return path.join("drive_c", "users", user || "", "AppData", "Roaming");
|
||||
};
|
||||
|
||||
const getDocumentsPath = () => {
|
||||
if (process.platform === "win32") {
|
||||
return app.getPath("documents");
|
||||
return SystemPath.getPath("documents");
|
||||
}
|
||||
|
||||
const user = app.getPath("home").split("/").pop();
|
||||
const user = SystemPath.getPath("home").split("/").pop();
|
||||
|
||||
return path.join("drive_c", "users", user || "", "Documents");
|
||||
};
|
||||
@@ -38,7 +38,7 @@ const getLocalAppDataPath = () => {
|
||||
return path.join(appData, "..", "Local");
|
||||
}
|
||||
|
||||
const user = app.getPath("home").split("/").pop();
|
||||
const user = SystemPath.getPath("home").split("/").pop();
|
||||
|
||||
return path.join("drive_c", "users", user || "", "AppData", "Local");
|
||||
};
|
||||
|
||||
@@ -1,5 +1,4 @@
|
||||
import { levelKeys, gamesSublevel, db } from "@main/level";
|
||||
import { app } from "electron";
|
||||
import path from "node:path";
|
||||
import * as tar from "tar";
|
||||
import crypto from "node:crypto";
|
||||
@@ -15,6 +14,7 @@ import axios from "axios";
|
||||
import { Ludusavi } from "./ludusavi";
|
||||
import { formatDate, SubscriptionRequiredError } from "@shared";
|
||||
import i18next, { t } from "i18next";
|
||||
import { SystemPath } from "./system-path";
|
||||
|
||||
export class CloudSync {
|
||||
public static getBackupLabel(automatic: boolean) {
|
||||
@@ -102,7 +102,7 @@ export class CloudSync {
|
||||
shop,
|
||||
objectId,
|
||||
hostname: os.hostname(),
|
||||
homeDir: normalizePath(app.getPath("home")),
|
||||
homeDir: normalizePath(SystemPath.getPath("home")),
|
||||
downloadOptionTitle,
|
||||
platform: os.platform(),
|
||||
label,
|
||||
|
||||
@@ -4,8 +4,8 @@ import fs from "node:fs";
|
||||
import cp from "node:child_process";
|
||||
import path from "node:path";
|
||||
import { logger } from "./logger";
|
||||
import { app } from "electron";
|
||||
import { WindowManager } from "./window-manager";
|
||||
import { SystemPath } from "./system-path";
|
||||
|
||||
export class CommonRedistManager {
|
||||
private static readonly redistributables = [
|
||||
@@ -18,7 +18,7 @@ export class CommonRedistManager {
|
||||
];
|
||||
private static readonly installationTimeout = 1000 * 60 * 5; // 5 minutes
|
||||
private static readonly installationLog = path.join(
|
||||
app.getPath("temp"),
|
||||
SystemPath.getPath("temp"),
|
||||
"common_redist_install.log"
|
||||
);
|
||||
|
||||
|
||||
@@ -8,9 +8,13 @@ import YAML from "yaml";
|
||||
|
||||
import ludusaviWorkerPath from "../workers/ludusavi.worker?modulePath";
|
||||
import { LUDUSAVI_MANIFEST_URL } from "@main/constants";
|
||||
import { SystemPath } from "./system-path";
|
||||
|
||||
export class Ludusavi {
|
||||
private static ludusaviPath = path.join(app.getPath("appData"), "ludusavi");
|
||||
private static ludusaviPath = path.join(
|
||||
SystemPath.getPath("appData"),
|
||||
"ludusavi"
|
||||
);
|
||||
private static ludusaviConfigPath = path.join(
|
||||
this.ludusaviPath,
|
||||
"config.yaml"
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
import { Notification, app } from "electron";
|
||||
import { Notification } from "electron";
|
||||
import { t } from "i18next";
|
||||
import trayIcon from "@resources/tray-icon.png?asset";
|
||||
import fs from "node:fs";
|
||||
@@ -13,13 +13,14 @@ import { WindowManager } from "../window-manager";
|
||||
import type { Game, UserPreferences } from "@types";
|
||||
import { db, levelKeys } from "@main/level";
|
||||
import { restartAndInstallUpdate } from "@main/events/autoupdater/restart-and-install-update";
|
||||
import { SystemPath } from "../system-path";
|
||||
|
||||
async function downloadImage(url: string | null) {
|
||||
if (!url) return undefined;
|
||||
if (!url.startsWith("http")) return undefined;
|
||||
|
||||
const fileName = url.split("/").pop()!;
|
||||
const outputPath = path.join(app.getPath("temp"), fileName);
|
||||
const outputPath = path.join(SystemPath.getPath("temp"), fileName);
|
||||
const writer = fs.createWriteStream(outputPath);
|
||||
|
||||
const response = await axios.get(url, {
|
||||
|
||||
45
src/main/services/system-path.ts
Normal file
45
src/main/services/system-path.ts
Normal file
@@ -0,0 +1,45 @@
|
||||
import { app, dialog } from "electron";
|
||||
import { logger } from "./logger";
|
||||
|
||||
export class SystemPath {
|
||||
static readonly paths = {
|
||||
userData: "userData",
|
||||
downloads: "downloads",
|
||||
documents: "documents",
|
||||
desktop: "desktop",
|
||||
home: "home",
|
||||
appData: "appData",
|
||||
temp: "temp",
|
||||
};
|
||||
|
||||
static checkIfPathsAreAvailable() {
|
||||
const paths = Object.keys(SystemPath.paths) as Array<
|
||||
keyof typeof SystemPath.paths
|
||||
>;
|
||||
|
||||
paths.forEach((pathName) => {
|
||||
try {
|
||||
app.getPath(pathName);
|
||||
} catch (error) {
|
||||
logger.error(`Error getting path ${pathName}`);
|
||||
if (error instanceof Error) {
|
||||
logger.error(error.message, error.stack);
|
||||
}
|
||||
|
||||
dialog.showErrorBox(
|
||||
`Hydra was not able to find path for '${pathName}' system folder`,
|
||||
`Some functionalities may not work as expected.\nPlease check your system settings.`
|
||||
);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
static getPath(pathName: keyof typeof SystemPath.paths): string {
|
||||
try {
|
||||
return app.getPath(pathName);
|
||||
} catch (error) {
|
||||
logger.error(`Error getting path: ${error}`);
|
||||
return "";
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user