mirror of
https://github.com/hydralauncher/hydra.git
synced 2026-01-11 05:46:17 +00:00
feat: optimizations
This commit is contained in:
@@ -1,6 +1,6 @@
|
|||||||
{
|
{
|
||||||
"name": "hydralauncher",
|
"name": "hydralauncher",
|
||||||
"version": "3.6.1",
|
"version": "3.6.2",
|
||||||
"description": "Hydra",
|
"description": "Hydra",
|
||||||
"main": "./out/main/index.js",
|
"main": "./out/main/index.js",
|
||||||
"author": "Los Broxas",
|
"author": "Los Broxas",
|
||||||
|
|||||||
@@ -101,8 +101,13 @@ def process_list():
|
|||||||
auth_error = validate_rpc_password()
|
auth_error = validate_rpc_password()
|
||||||
if auth_error:
|
if auth_error:
|
||||||
return auth_error
|
return auth_error
|
||||||
|
|
||||||
|
iter_list = ['exe', 'pid', 'name']
|
||||||
|
if sys.platform != 'win32':
|
||||||
|
iter_list.append('cwd')
|
||||||
|
iter_list.append('environ')
|
||||||
|
|
||||||
process_list = [proc.info for proc in psutil.process_iter(['exe', 'cwd', 'pid', 'name', 'environ'])]
|
process_list = [proc.info for proc in psutil.process_iter(iter_list)]
|
||||||
return jsonify(process_list), 200
|
return jsonify(process_list), 200
|
||||||
|
|
||||||
@app.route("/profile-image", methods=["POST"])
|
@app.route("/profile-image", methods=["POST"])
|
||||||
|
|||||||
@@ -1,17 +1,38 @@
|
|||||||
import type { GameShop, GameStats } from "@types";
|
import type { GameShop, GameStats } from "@types";
|
||||||
import { registerEvent } from "../register-event";
|
import { registerEvent } from "../register-event";
|
||||||
import { HydraApi } from "@main/services";
|
import { HydraApi } from "@main/services";
|
||||||
|
import { gamesStatsCacheSublevel, levelKeys } from "@main/level";
|
||||||
|
|
||||||
|
const LOCAL_CACHE_EXPIRATION = 1000 * 60 * 30; // 30 minutes
|
||||||
|
|
||||||
const getGameStats = async (
|
const getGameStats = async (
|
||||||
_event: Electron.IpcMainInvokeEvent,
|
_event: Electron.IpcMainInvokeEvent,
|
||||||
objectId: string,
|
objectId: string,
|
||||||
shop: GameShop
|
shop: GameShop
|
||||||
) => {
|
) => {
|
||||||
|
const cachedStats = await gamesStatsCacheSublevel.get(
|
||||||
|
levelKeys.game(shop, objectId)
|
||||||
|
);
|
||||||
|
|
||||||
|
if (
|
||||||
|
cachedStats &&
|
||||||
|
cachedStats.updatedAt + LOCAL_CACHE_EXPIRATION > Date.now()
|
||||||
|
) {
|
||||||
|
return cachedStats;
|
||||||
|
}
|
||||||
|
|
||||||
return HydraApi.get<GameStats>(
|
return HydraApi.get<GameStats>(
|
||||||
`/games/stats`,
|
`/games/stats`,
|
||||||
{ objectId, shop },
|
{ objectId, shop },
|
||||||
{ needsAuth: false }
|
{ needsAuth: false }
|
||||||
);
|
).then(async (data) => {
|
||||||
|
await gamesStatsCacheSublevel.put(levelKeys.game(shop, objectId), {
|
||||||
|
...data,
|
||||||
|
updatedAt: Date.now(),
|
||||||
|
});
|
||||||
|
|
||||||
|
return data;
|
||||||
|
});
|
||||||
};
|
};
|
||||||
|
|
||||||
registerEvent("getGameStats", getGameStats);
|
registerEvent("getGameStats", getGameStats);
|
||||||
|
|||||||
@@ -20,7 +20,6 @@ import "./library/create-game-shortcut";
|
|||||||
import "./library/close-game";
|
import "./library/close-game";
|
||||||
import "./library/delete-game-folder";
|
import "./library/delete-game-folder";
|
||||||
import "./library/get-game-by-object-id";
|
import "./library/get-game-by-object-id";
|
||||||
import "./library/sync-game-by-object-id";
|
|
||||||
import "./library/get-library";
|
import "./library/get-library";
|
||||||
import "./library/extract-game-download";
|
import "./library/extract-game-download";
|
||||||
import "./library/open-game";
|
import "./library/open-game";
|
||||||
|
|||||||
@@ -1,32 +0,0 @@
|
|||||||
import { registerEvent } from "../register-event";
|
|
||||||
import { gamesSublevel, levelKeys } from "@main/level";
|
|
||||||
import { HydraApi } from "@main/services";
|
|
||||||
import type { GameShop, UserGameDetails } from "@types";
|
|
||||||
|
|
||||||
const syncGameByObjectId = async (
|
|
||||||
_event: Electron.IpcMainInvokeEvent,
|
|
||||||
shop: GameShop,
|
|
||||||
objectId: string
|
|
||||||
) => {
|
|
||||||
return HydraApi.get<UserGameDetails>(
|
|
||||||
`/profile/games/${shop}/${objectId}`
|
|
||||||
).then(async (res) => {
|
|
||||||
const { id, playTimeInSeconds, isFavorite, ...rest } = res;
|
|
||||||
|
|
||||||
const gameKey = levelKeys.game(shop, objectId);
|
|
||||||
|
|
||||||
const currentData = await gamesSublevel.get(gameKey);
|
|
||||||
|
|
||||||
await gamesSublevel.put(gameKey, {
|
|
||||||
...currentData,
|
|
||||||
...rest,
|
|
||||||
remoteId: id,
|
|
||||||
playTimeInMilliseconds: playTimeInSeconds * 1000,
|
|
||||||
favorite: isFavorite ?? currentData?.favorite,
|
|
||||||
});
|
|
||||||
|
|
||||||
return res;
|
|
||||||
});
|
|
||||||
};
|
|
||||||
|
|
||||||
registerEvent("syncGameByObjectId", syncGameByObjectId);
|
|
||||||
11
src/main/level/sublevels/game-stats-cache.ts
Normal file
11
src/main/level/sublevels/game-stats-cache.ts
Normal file
@@ -0,0 +1,11 @@
|
|||||||
|
import type { GameStats } from "@types";
|
||||||
|
|
||||||
|
import { db } from "../level";
|
||||||
|
import { levelKeys } from "./keys";
|
||||||
|
|
||||||
|
export const gamesStatsCacheSublevel = db.sublevel<
|
||||||
|
string,
|
||||||
|
GameStats & { updatedAt: number }
|
||||||
|
>(levelKeys.gameStatsCache, {
|
||||||
|
valueEncoding: "json",
|
||||||
|
});
|
||||||
@@ -2,6 +2,7 @@ export * from "./downloads";
|
|||||||
export * from "./games";
|
export * from "./games";
|
||||||
export * from "./game-shop-assets";
|
export * from "./game-shop-assets";
|
||||||
export * from "./game-shop-cache";
|
export * from "./game-shop-cache";
|
||||||
|
export * from "./game-stats-cache";
|
||||||
export * from "./game-achievements";
|
export * from "./game-achievements";
|
||||||
export * from "./keys";
|
export * from "./keys";
|
||||||
export * from "./themes";
|
export * from "./themes";
|
||||||
|
|||||||
@@ -7,6 +7,7 @@ export const levelKeys = {
|
|||||||
auth: "auth",
|
auth: "auth",
|
||||||
themes: "themes",
|
themes: "themes",
|
||||||
gameShopAssets: "gameShopAssets",
|
gameShopAssets: "gameShopAssets",
|
||||||
|
gameStatsCache: "gameStatsAssets",
|
||||||
gameShopCache: "gameShopCache",
|
gameShopCache: "gameShopCache",
|
||||||
gameShopCacheItem: (shop: GameShop, objectId: string, language: string) =>
|
gameShopCacheItem: (shop: GameShop, objectId: string, language: string) =>
|
||||||
`${shop}:${objectId}:${language}`,
|
`${shop}:${objectId}:${language}`,
|
||||||
|
|||||||
@@ -5,7 +5,7 @@ import { logger } from "../logger";
|
|||||||
import { db, gameAchievementsSublevel, levelKeys } from "@main/level";
|
import { db, gameAchievementsSublevel, levelKeys } from "@main/level";
|
||||||
import { AxiosError } from "axios";
|
import { AxiosError } from "axios";
|
||||||
|
|
||||||
const LOCAL_CACHE_EXPIRATION = 1000 * 60 * 30; // 30 minutes
|
const LOCAL_CACHE_EXPIRATION = 1000 * 60 * 60; // 1 hour
|
||||||
|
|
||||||
const getModifiedSinceHeader = (
|
const getModifiedSinceHeader = (
|
||||||
cachedAchievements: GameAchievement | undefined
|
cachedAchievements: GameAchievement | undefined
|
||||||
|
|||||||
@@ -31,8 +31,8 @@ export interface ProcessPayload {
|
|||||||
exe: string | null;
|
exe: string | null;
|
||||||
pid: number;
|
pid: number;
|
||||||
name: string;
|
name: string;
|
||||||
environ: Record<string, string> | null;
|
environ?: Record<string, string> | null;
|
||||||
cwd: string | null;
|
cwd?: string | null;
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface PauseSeedingPayload {
|
export interface PauseSeedingPayload {
|
||||||
|
|||||||
@@ -25,7 +25,7 @@ interface GameExecutables {
|
|||||||
[key: string]: ExecutableInfo[];
|
[key: string]: ExecutableInfo[];
|
||||||
}
|
}
|
||||||
|
|
||||||
const TICKS_TO_UPDATE_API = 80;
|
const TICKS_TO_UPDATE_API = 120;
|
||||||
let currentTick = 1;
|
let currentTick = 1;
|
||||||
|
|
||||||
const platform = process.platform;
|
const platform = process.platform;
|
||||||
|
|||||||
@@ -187,8 +187,6 @@ contextBridge.exposeInMainWorld("electron", {
|
|||||||
ipcRenderer.invoke("deleteGameFolder", shop, objectId),
|
ipcRenderer.invoke("deleteGameFolder", shop, objectId),
|
||||||
getGameByObjectId: (shop: GameShop, objectId: string) =>
|
getGameByObjectId: (shop: GameShop, objectId: string) =>
|
||||||
ipcRenderer.invoke("getGameByObjectId", shop, objectId),
|
ipcRenderer.invoke("getGameByObjectId", shop, objectId),
|
||||||
syncGameByObjectId: (shop: GameShop, objectId: string) =>
|
|
||||||
ipcRenderer.invoke("syncGameByObjectId", shop, objectId),
|
|
||||||
resetGameAchievements: (shop: GameShop, objectId: string) =>
|
resetGameAchievements: (shop: GameShop, objectId: string) =>
|
||||||
ipcRenderer.invoke("resetGameAchievements", shop, objectId),
|
ipcRenderer.invoke("resetGameAchievements", shop, objectId),
|
||||||
extractGameDownload: (shop: GameShop, objectId: string) =>
|
extractGameDownload: (shop: GameShop, objectId: string) =>
|
||||||
|
|||||||
@@ -182,14 +182,6 @@ export function GameDetailsContextProvider({
|
|||||||
})
|
})
|
||||||
.catch(() => {});
|
.catch(() => {});
|
||||||
}
|
}
|
||||||
|
|
||||||
window.electron
|
|
||||||
.syncGameByObjectId(shop, objectId)
|
|
||||||
.then(() => {
|
|
||||||
if (abortController.signal.aborted) return;
|
|
||||||
updateGame();
|
|
||||||
})
|
|
||||||
.catch(() => {});
|
|
||||||
}, [
|
}, [
|
||||||
updateGame,
|
updateGame,
|
||||||
dispatch,
|
dispatch,
|
||||||
|
|||||||
1
src/renderer/src/declaration.d.ts
vendored
1
src/renderer/src/declaration.d.ts
vendored
@@ -155,7 +155,6 @@ declare global {
|
|||||||
shop: GameShop,
|
shop: GameShop,
|
||||||
objectId: string
|
objectId: string
|
||||||
) => Promise<LibraryGame | null>;
|
) => Promise<LibraryGame | null>;
|
||||||
syncGameByObjectId: (shop: GameShop, objectId: string) => Promise<void>;
|
|
||||||
onGamesRunning: (
|
onGamesRunning: (
|
||||||
cb: (
|
cb: (
|
||||||
gamesRunning: Pick<GameRunning, "id" | "sessionDurationInMillis">[]
|
gamesRunning: Pick<GameRunning, "id" | "sessionDurationInMillis">[]
|
||||||
|
|||||||
Reference in New Issue
Block a user