mirror of
https://github.com/hydralauncher/hydra.git
synced 2026-01-11 13:56:16 +00:00
148 lines
3.7 KiB
TypeScript
148 lines
3.7 KiB
TypeScript
import { HydraApi, logger, Ludusavi, WindowManager } from "@main/services";
|
|
import fs from "node:fs";
|
|
import * as tar from "tar";
|
|
import { registerEvent } from "../register-event";
|
|
import axios from "axios";
|
|
import os from "node:os";
|
|
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: {
|
|
[key: string]: {
|
|
hash: string;
|
|
size: number;
|
|
};
|
|
};
|
|
}
|
|
|
|
const replaceLudusaviBackupWithCurrentUser = (
|
|
backupPath: string,
|
|
title: string,
|
|
homeDir: string
|
|
) => {
|
|
const gameBackupPath = path.join(backupPath, title);
|
|
const mappingYamlPath = path.join(gameBackupPath, "mapping.yaml");
|
|
|
|
const data = fs.readFileSync(mappingYamlPath, "utf8");
|
|
const manifest = YAML.parse(data) as {
|
|
backups: LudusaviBackup[];
|
|
drives: Record<string, string>;
|
|
};
|
|
|
|
const currentHomeDir = normalizePath(SystemPath.getPath("home"));
|
|
|
|
/* Renaming logic */
|
|
if (os.platform() === "win32") {
|
|
const mappedHomeDir = path.join(
|
|
gameBackupPath,
|
|
path.join("drive-C", homeDir.replace("C:", ""))
|
|
);
|
|
|
|
if (fs.existsSync(mappedHomeDir)) {
|
|
fs.renameSync(
|
|
mappedHomeDir,
|
|
path.join(gameBackupPath, "drive-C", currentHomeDir.replace("C:", ""))
|
|
);
|
|
}
|
|
}
|
|
|
|
const backups = manifest.backups.map((backup: LudusaviBackup) => {
|
|
const files = Object.entries(backup.files).reduce((prev, [key, value]) => {
|
|
const updatedKey = key.replace(homeDir, currentHomeDir);
|
|
|
|
return {
|
|
...prev,
|
|
[updatedKey]: value,
|
|
};
|
|
}, {});
|
|
|
|
return {
|
|
...backup,
|
|
files,
|
|
};
|
|
});
|
|
|
|
fs.writeFileSync(mappingYamlPath, YAML.stringify({ ...manifest, backups }));
|
|
};
|
|
|
|
const downloadGameArtifact = async (
|
|
_event: Electron.IpcMainInvokeEvent,
|
|
objectId: string,
|
|
shop: GameShop,
|
|
gameArtifactId: string
|
|
) => {
|
|
try {
|
|
const { downloadUrl, objectKey, homeDir } = await HydraApi.post<{
|
|
downloadUrl: string;
|
|
objectKey: string;
|
|
homeDir: string;
|
|
}>(`/profile/games/artifacts/${gameArtifactId}/download`);
|
|
|
|
const zipLocation = path.join(SystemPath.getPath("userData"), objectKey);
|
|
const backupPath = path.join(backupsPath, `${shop}-${objectId}`);
|
|
|
|
if (fs.existsSync(backupPath)) {
|
|
fs.rmSync(backupPath, {
|
|
recursive: true,
|
|
force: true,
|
|
});
|
|
}
|
|
|
|
const response = await axios.get(downloadUrl, {
|
|
responseType: "stream",
|
|
onDownloadProgress: (progressEvent) => {
|
|
WindowManager.mainWindow?.webContents.send(
|
|
`on-backup-download-progress-${objectId}-${shop}`,
|
|
progressEvent
|
|
);
|
|
},
|
|
});
|
|
|
|
const writer = fs.createWriteStream(zipLocation);
|
|
|
|
response.data.pipe(writer);
|
|
|
|
writer.on("error", (err) => {
|
|
logger.error("Failed to write zip", err);
|
|
throw err;
|
|
});
|
|
|
|
fs.mkdirSync(backupPath, { recursive: true });
|
|
|
|
writer.on("close", () => {
|
|
tar
|
|
.x({
|
|
file: zipLocation,
|
|
cwd: backupPath,
|
|
})
|
|
.then(async () => {
|
|
replaceLudusaviBackupWithCurrentUser(
|
|
backupPath,
|
|
objectId,
|
|
normalizePath(homeDir)
|
|
);
|
|
|
|
Ludusavi.restoreBackup(backupPath).then(() => {
|
|
WindowManager.mainWindow?.webContents.send(
|
|
`on-backup-download-complete-${objectId}-${shop}`,
|
|
true
|
|
);
|
|
});
|
|
});
|
|
});
|
|
} catch (err) {
|
|
WindowManager.mainWindow?.webContents.send(
|
|
`on-backup-download-complete-${objectId}-${shop}`,
|
|
false
|
|
);
|
|
}
|
|
};
|
|
|
|
registerEvent("downloadGameArtifact", downloadGameArtifact);
|