mirror of
https://github.com/hydralauncher/hydra.git
synced 2025-02-13 03:32:13 +00:00
feat: optimizations
This commit is contained in:
parent
fd5262cd6e
commit
27e8a0820f
6 changed files with 167 additions and 116 deletions
|
@ -40,10 +40,8 @@ const watchAchievementsWindows = async () => {
|
|||
);
|
||||
}
|
||||
|
||||
if (!gameAchievementFiles.length) continue;
|
||||
|
||||
for (const file of gameAchievementFiles) {
|
||||
await compareFile(game, file);
|
||||
compareFile(game, file);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
@ -56,8 +54,6 @@ const watchAchievementsWithWine = async () => {
|
|||
},
|
||||
});
|
||||
|
||||
if (games.length === 0) return;
|
||||
|
||||
for (const game of games) {
|
||||
const gameAchievementFiles = findAchievementFiles(game);
|
||||
const achievementFileInsideDirectory =
|
||||
|
@ -65,10 +61,8 @@ const watchAchievementsWithWine = async () => {
|
|||
|
||||
gameAchievementFiles.push(...achievementFileInsideDirectory);
|
||||
|
||||
if (!gameAchievementFiles.length) continue;
|
||||
|
||||
for (const file of gameAchievementFiles) {
|
||||
await compareFile(game, file);
|
||||
compareFile(game, file);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
@ -104,7 +98,7 @@ const compareFile = (game: Game, file: AchievementFile) => {
|
|||
const previousStat = fileStats.get(file.filePath);
|
||||
fileStats.set(file.filePath, currentStat.mtimeMs);
|
||||
|
||||
if (!previousStat) {
|
||||
if (!previousStat || previousStat === -1) {
|
||||
if (currentStat.mtimeMs) {
|
||||
achievementsLogger.log(
|
||||
"First change in file",
|
||||
|
@ -153,50 +147,21 @@ const processAchievementFileDiff = async (
|
|||
export class AchievementWatcherManager {
|
||||
private static hasFinishedMergingWithRemote = false;
|
||||
|
||||
public static watchAchievements = async () => {
|
||||
public static watchAchievements = () => {
|
||||
if (!this.hasFinishedMergingWithRemote) return;
|
||||
|
||||
if (process.platform === "win32") {
|
||||
return watchAchievementsWindows();
|
||||
}
|
||||
|
||||
watchAchievementsWithWine();
|
||||
return watchAchievementsWithWine();
|
||||
};
|
||||
|
||||
public static preSearchAchievements = async () => {
|
||||
const games = await gameRepository.find({
|
||||
where: {
|
||||
isDeleted: false,
|
||||
},
|
||||
});
|
||||
|
||||
const gameAchievementFilesMap = findAllAchievementFiles();
|
||||
|
||||
await Promise.all(
|
||||
games.map(async (game) => {
|
||||
gameAchievementRepository
|
||||
.findOne({
|
||||
where: { objectId: game.objectID, shop: "steam" },
|
||||
})
|
||||
.then((localAchievements) => {
|
||||
if (!localAchievements || !localAchievements.achievements) {
|
||||
getGameAchievementData(game.objectID, "steam");
|
||||
}
|
||||
});
|
||||
|
||||
const gameAchievementFiles: AchievementFile[] = [];
|
||||
private static preProcessGameAchievementFiles = (
|
||||
game: Game,
|
||||
gameAchievementFiles: AchievementFile[]
|
||||
) => {
|
||||
const unlockedAchievements: UnlockedAchievement[] = [];
|
||||
|
||||
for (const objectId of getAlternativeObjectIds(game.objectID)) {
|
||||
gameAchievementFiles.push(
|
||||
...(gameAchievementFilesMap.get(objectId) || [])
|
||||
);
|
||||
|
||||
gameAchievementFiles.push(
|
||||
...findAchievementFileInExecutableDirectory(game)
|
||||
);
|
||||
}
|
||||
|
||||
for (const achievementFile of gameAchievementFiles) {
|
||||
const parsedAchievements = parseAchievementFile(
|
||||
achievementFile.filePath,
|
||||
|
@ -220,16 +185,91 @@ export class AchievementWatcherManager {
|
|||
parsedAchievements
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
await mergeAchievements(
|
||||
return mergeAchievements(
|
||||
game.objectID,
|
||||
"steam",
|
||||
unlockedAchievements,
|
||||
false
|
||||
);
|
||||
};
|
||||
|
||||
private static preSearchAchievementsWindows = async () => {
|
||||
const games = await gameRepository.find({
|
||||
where: {
|
||||
isDeleted: false,
|
||||
},
|
||||
});
|
||||
|
||||
const gameAchievementFilesMap = findAllAchievementFiles();
|
||||
|
||||
return Promise.all(
|
||||
games.map((game) => {
|
||||
gameAchievementRepository
|
||||
.findOne({
|
||||
where: { objectId: game.objectID, shop: game.shop },
|
||||
})
|
||||
.then((localAchievements) => {
|
||||
if (!localAchievements || !localAchievements.achievements) {
|
||||
getGameAchievementData(game.objectID, game.shop);
|
||||
}
|
||||
});
|
||||
|
||||
const gameAchievementFiles: AchievementFile[] = [];
|
||||
|
||||
for (const objectId of getAlternativeObjectIds(game.objectID)) {
|
||||
gameAchievementFiles.push(
|
||||
...(gameAchievementFilesMap.get(objectId) || [])
|
||||
);
|
||||
|
||||
gameAchievementFiles.push(
|
||||
...findAchievementFileInExecutableDirectory(game)
|
||||
);
|
||||
}
|
||||
|
||||
return this.preProcessGameAchievementFiles(game, gameAchievementFiles);
|
||||
})
|
||||
);
|
||||
};
|
||||
|
||||
private static preSearchAchievementsWithWine = async () => {
|
||||
const games = await gameRepository.find({
|
||||
where: {
|
||||
isDeleted: false,
|
||||
winePrefixPath: Not(IsNull()),
|
||||
},
|
||||
});
|
||||
|
||||
return Promise.all(
|
||||
games.map((game) => {
|
||||
gameAchievementRepository
|
||||
.findOne({
|
||||
where: { objectId: game.objectID, shop: game.shop },
|
||||
})
|
||||
.then((localAchievements) => {
|
||||
if (!localAchievements || !localAchievements.achievements) {
|
||||
getGameAchievementData(game.objectID, game.shop);
|
||||
}
|
||||
});
|
||||
|
||||
const gameAchievementFiles = findAchievementFiles(game);
|
||||
const achievementFileInsideDirectory =
|
||||
findAchievementFileInExecutableDirectory(game);
|
||||
|
||||
gameAchievementFiles.push(...achievementFileInsideDirectory);
|
||||
|
||||
return this.preProcessGameAchievementFiles(game, gameAchievementFiles);
|
||||
})
|
||||
);
|
||||
};
|
||||
|
||||
public static preSearchAchievements = async () => {
|
||||
if (process.platform === "win32") {
|
||||
await this.preSearchAchievementsWindows();
|
||||
} else {
|
||||
await this.preSearchAchievementsWithWine();
|
||||
}
|
||||
|
||||
this.hasFinishedMergingWithRemote = true;
|
||||
};
|
|
@ -11,7 +11,8 @@ import { getUnlockedAchievements } from "@main/events/user/get-unlocked-achievem
|
|||
const saveAchievementsOnLocal = async (
|
||||
objectId: string,
|
||||
shop: GameShop,
|
||||
achievements: any[]
|
||||
achievements: any[],
|
||||
sendUpdateEvent: boolean
|
||||
) => {
|
||||
return gameAchievementRepository
|
||||
.upsert(
|
||||
|
@ -23,6 +24,8 @@ const saveAchievementsOnLocal = async (
|
|||
["objectId", "shop"]
|
||||
)
|
||||
.then(() => {
|
||||
if (!sendUpdateEvent) return;
|
||||
|
||||
return getUnlockedAchievements(objectId, shop)
|
||||
.then((achievements) => {
|
||||
WindowManager.mainWindow?.webContents.send(
|
||||
|
@ -133,13 +136,24 @@ export const mergeAchievements = async (
|
|||
return saveAchievementsOnLocal(
|
||||
response.objectId,
|
||||
response.shop,
|
||||
response.achievements
|
||||
response.achievements,
|
||||
publishNotification
|
||||
);
|
||||
})
|
||||
.catch(() => {
|
||||
return saveAchievementsOnLocal(objectId, shop, mergedLocalAchievements);
|
||||
return saveAchievementsOnLocal(
|
||||
objectId,
|
||||
shop,
|
||||
mergedLocalAchievements,
|
||||
publishNotification
|
||||
);
|
||||
});
|
||||
}
|
||||
|
||||
return saveAchievementsOnLocal(objectId, shop, mergedLocalAchievements);
|
||||
return saveAchievementsOnLocal(
|
||||
objectId,
|
||||
shop,
|
||||
mergedLocalAchievements,
|
||||
publishNotification
|
||||
);
|
||||
};
|
||||
|
|
|
@ -14,6 +14,7 @@ import {
|
|||
} from "@shared";
|
||||
// import { omit } from "lodash-es";
|
||||
import { appVersion } from "@main/constants";
|
||||
import { omit } from "lodash-es";
|
||||
|
||||
interface HydraApiOptions {
|
||||
needsAuth?: boolean;
|
||||
|
@ -24,7 +25,7 @@ export class HydraApi {
|
|||
private static instance: AxiosInstance;
|
||||
|
||||
private static readonly EXPIRATION_OFFSET_IN_MS = 1000 * 60 * 5; // 5 minutes
|
||||
private static readonly ADD_LOG_INTERCEPTOR = true;
|
||||
private static readonly ADD_LOG_INTERCEPTOR = false;
|
||||
|
||||
private static secondsToMilliseconds = (seconds: number) => seconds * 1000;
|
||||
|
||||
|
@ -109,59 +110,59 @@ export class HydraApi {
|
|||
});
|
||||
|
||||
if (this.ADD_LOG_INTERCEPTOR) {
|
||||
// this.instance.interceptors.request.use(
|
||||
// (request) => {
|
||||
// logger.log(" ---- REQUEST -----");
|
||||
// const data = Array.isArray(request.data)
|
||||
// ? request.data
|
||||
// : omit(request.data, ["refreshToken"]);
|
||||
// logger.log(request.method, request.url, request.params, data);
|
||||
// return request;
|
||||
// },
|
||||
// (error) => {
|
||||
// logger.error("request error", error);
|
||||
// return Promise.reject(error);
|
||||
// }
|
||||
// );
|
||||
// this.instance.interceptors.response.use(
|
||||
// (response) => {
|
||||
// logger.log(" ---- RESPONSE -----");
|
||||
// const data = Array.isArray(response.data)
|
||||
// ? response.data
|
||||
// : omit(response.data, ["username", "accessToken", "refreshToken"]);
|
||||
// logger.log(
|
||||
// response.status,
|
||||
// response.config.method,
|
||||
// response.config.url,
|
||||
// data
|
||||
// );
|
||||
// return response;
|
||||
// },
|
||||
// (error) => {
|
||||
// logger.error(" ---- RESPONSE ERROR -----");
|
||||
// const { config } = error;
|
||||
// logger.error(
|
||||
// config.method,
|
||||
// config.baseURL,
|
||||
// config.url,
|
||||
// config.headers,
|
||||
// config.data
|
||||
// );
|
||||
// if (error.response) {
|
||||
// logger.error(
|
||||
// "Response",
|
||||
// error.response.status,
|
||||
// error.response.data
|
||||
// );
|
||||
// } else if (error.request) {
|
||||
// logger.error("Request", error.request);
|
||||
// } else {
|
||||
// logger.error("Error", error.message);
|
||||
// }
|
||||
// logger.error(" ----- END RESPONSE ERROR -------");
|
||||
// return Promise.reject(error);
|
||||
// }
|
||||
// );
|
||||
this.instance.interceptors.request.use(
|
||||
(request) => {
|
||||
logger.log(" ---- REQUEST -----");
|
||||
const data = Array.isArray(request.data)
|
||||
? request.data
|
||||
: omit(request.data, ["refreshToken"]);
|
||||
logger.log(request.method, request.url, request.params, data);
|
||||
return request;
|
||||
},
|
||||
(error) => {
|
||||
logger.error("request error", error);
|
||||
return Promise.reject(error);
|
||||
}
|
||||
);
|
||||
this.instance.interceptors.response.use(
|
||||
(response) => {
|
||||
logger.log(" ---- RESPONSE -----");
|
||||
const data = Array.isArray(response.data)
|
||||
? response.data
|
||||
: omit(response.data, ["username", "accessToken", "refreshToken"]);
|
||||
logger.log(
|
||||
response.status,
|
||||
response.config.method,
|
||||
response.config.url,
|
||||
data
|
||||
);
|
||||
return response;
|
||||
},
|
||||
(error) => {
|
||||
logger.error(" ---- RESPONSE ERROR -----");
|
||||
const { config } = error;
|
||||
logger.error(
|
||||
config.method,
|
||||
config.baseURL,
|
||||
config.url,
|
||||
config.headers,
|
||||
config.data
|
||||
);
|
||||
if (error.response) {
|
||||
logger.error(
|
||||
"Response",
|
||||
error.response.status,
|
||||
error.response.data
|
||||
);
|
||||
} else if (error.request) {
|
||||
logger.error("Request", error.request);
|
||||
} else {
|
||||
logger.error("Error", error.message);
|
||||
}
|
||||
logger.error(" ----- END RESPONSE ERROR -------");
|
||||
return Promise.reject(error);
|
||||
}
|
||||
);
|
||||
}
|
||||
|
||||
const userAuth = await userAuthRepository.findOne({
|
||||
|
|
|
@ -4,7 +4,7 @@ import { IsNull } from "typeorm";
|
|||
import { HydraApi } from "../hydra-api";
|
||||
import { mergeWithRemoteGames } from "./merge-with-remote-games";
|
||||
import { WindowManager } from "../window-manager";
|
||||
import { AchievementWatcherManager } from "../achievements/AchievementWatcherManager";
|
||||
import { AchievementWatcherManager } from "../achievements/achievement-watcher-manager";
|
||||
|
||||
export const uploadGamesBatch = async () => {
|
||||
const games = await gameRepository.find({
|
||||
|
@ -29,7 +29,7 @@ export const uploadGamesBatch = async () => {
|
|||
|
||||
await mergeWithRemoteGames();
|
||||
|
||||
await AchievementWatcherManager.preSearchAchievements();
|
||||
AchievementWatcherManager.preSearchAchievements();
|
||||
|
||||
if (WindowManager.mainWindow)
|
||||
WindowManager.mainWindow.webContents.send("on-library-batch-complete");
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
import { sleep } from "@main/helpers";
|
||||
import { DownloadManager } from "./download";
|
||||
import { watchProcesses } from "./process-watcher";
|
||||
import { AchievementWatcherManager } from "./achievements/AchievementWatcherManager";
|
||||
import { AchievementWatcherManager } from "./achievements/achievement-watcher-manager";
|
||||
|
||||
export const startMainLoop = async () => {
|
||||
// eslint-disable-next-line no-constant-condition
|
||||
|
|
|
@ -2,7 +2,7 @@ import { useNavigate } from "react-router-dom";
|
|||
import { PeopleIcon } from "@primer/octicons-react";
|
||||
import * as styles from "./sidebar-profile.css";
|
||||
import { useAppSelector, useUserDetails } from "@renderer/hooks";
|
||||
import { useEffect, useMemo, useRef } from "react";
|
||||
import { useEffect, useMemo } from "react";
|
||||
import { useTranslation } from "react-i18next";
|
||||
import { UserFriendModalTab } from "@renderer/pages/shared-modals/user-friend-modal";
|
||||
import SteamLogo from "@renderer/assets/steam-logo.svg?react";
|
||||
|
@ -13,8 +13,6 @@ const LONG_POLLING_INTERVAL = 60_000;
|
|||
export function SidebarProfile() {
|
||||
const navigate = useNavigate();
|
||||
|
||||
const pollingInterval = useRef<NodeJS.Timeout | null>(null);
|
||||
|
||||
const { t } = useTranslation("sidebar");
|
||||
|
||||
const {
|
||||
|
@ -36,14 +34,12 @@ export function SidebarProfile() {
|
|||
};
|
||||
|
||||
useEffect(() => {
|
||||
pollingInterval.current = setInterval(() => {
|
||||
const pollingInterval = setInterval(() => {
|
||||
syncFriendRequests();
|
||||
}, LONG_POLLING_INTERVAL);
|
||||
|
||||
return () => {
|
||||
if (pollingInterval.current) {
|
||||
clearInterval(pollingInterval.current);
|
||||
}
|
||||
clearInterval(pollingInterval);
|
||||
};
|
||||
}, [syncFriendRequests]);
|
||||
|
||||
|
|
Loading…
Reference in a new issue