feat: optimizations

This commit is contained in:
Zamitto 2024-10-21 04:28:04 -03:00
parent fd5262cd6e
commit 27e8a0820f
6 changed files with 167 additions and 116 deletions

View file

@ -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;
};

View file

@ -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
);
};

View file

@ -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({

View file

@ -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");

View file

@ -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

View file

@ -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]);