From 100ddd79aa4ef9e2a4a82a2cc6fe5731547dbb6c Mon Sep 17 00:00:00 2001 From: Zamitto <167933696+zamitto@users.noreply.github.com> Date: Fri, 6 Jun 2025 16:52:40 -0300 Subject: [PATCH] feat: add If-Modified-Since header to get-game-achievement-data --- .../achievements/get-game-achievement-data.ts | 33 ++++++++++++++----- .../achievements/merge-achievements.ts | 2 +- src/main/services/hydra-api.ts | 10 ++++-- src/types/level.types.ts | 2 +- 4 files changed, 34 insertions(+), 13 deletions(-) diff --git a/src/main/services/achievements/get-game-achievement-data.ts b/src/main/services/achievements/get-game-achievement-data.ts index 977adcec..f5b7f6cb 100644 --- a/src/main/services/achievements/get-game-achievement-data.ts +++ b/src/main/services/achievements/get-game-achievement-data.ts @@ -3,6 +3,9 @@ import type { GameShop, SteamAchievement } from "@types"; import { UserNotLoggedInError } from "@shared"; import { logger } from "../logger"; import { db, gameAchievementsSublevel, levelKeys } from "@main/level"; +import { AxiosError } from "axios"; + +const LOCAL_CACHE_EXPIRATION = 1000 * 60 * 30; // 30 minutes export const getGameAchievementData = async ( objectId: string, @@ -18,7 +21,7 @@ export const getGameAchievementData = async ( if ( cachedAchievements?.achievements && - Date.now() < (cachedAchievements.cacheExpiresTimestamp ?? 0) + Date.now() < (cachedAchievements.updatedAt ?? 0) + LOCAL_CACHE_EXPIRATION ) { return cachedAchievements.achievements; } @@ -29,18 +32,24 @@ export const getGameAchievementData = async ( }) .then((language) => language || "en"); - return HydraApi.get("/games/achievements", { - shop, - objectId, - language, - }) + return HydraApi.get( + "/games/achievements", + { + shop, + objectId, + language, + }, + { + ifModifiedSince: cachedAchievements?.updatedAt + ? new Date(cachedAchievements?.updatedAt) + : undefined, + } + ) .then(async (achievements) => { await gameAchievementsSublevel.put(gameKey, { unlockedAchievements: cachedAchievements?.unlockedAchievements ?? [], achievements, - cacheExpiresTimestamp: achievements.length - ? Date.now() + 1000 * 60 * 30 // 30 minutes - : undefined, + updatedAt: Date.now() + LOCAL_CACHE_EXPIRATION, }); return achievements; @@ -50,6 +59,12 @@ export const getGameAchievementData = async ( throw err; } + const isNotModified = (err as AxiosError)?.response?.status === 304; + + if (isNotModified) { + return cachedAchievements?.achievements ?? []; + } + logger.error("Failed to get game achievements for", objectId, err); return []; diff --git a/src/main/services/achievements/merge-achievements.ts b/src/main/services/achievements/merge-achievements.ts index 031d9619..f2ea03ac 100644 --- a/src/main/services/achievements/merge-achievements.ts +++ b/src/main/services/achievements/merge-achievements.ts @@ -36,7 +36,7 @@ const saveAchievementsOnLocal = async ( await gameAchievementsSublevel.put(levelKey, { achievements: gameAchievement?.achievements ?? [], unlockedAchievements: unlockedAchievements, - cacheExpiresTimestamp: gameAchievement?.cacheExpiresTimestamp, + updatedAt: gameAchievement?.updatedAt, }); if (!sendUpdateEvent) return; diff --git a/src/main/services/hydra-api.ts b/src/main/services/hydra-api.ts index 0f5a4d21..15d866cb 100644 --- a/src/main/services/hydra-api.ts +++ b/src/main/services/hydra-api.ts @@ -1,4 +1,4 @@ -import axios, { AxiosError, AxiosInstance } from "axios"; +import axios, { AxiosError, AxiosHeaders, AxiosInstance } from "axios"; import { WindowManager } from "./window-manager"; import url from "url"; import { uploadGamesBatch } from "./library-sync"; @@ -16,6 +16,7 @@ import { WSClient } from "./ws/ws-client"; interface HydraApiOptions { needsAuth?: boolean; needsSubscription?: boolean; + ifModifiedSince?: Date; } interface HydraApiUserAuth { @@ -337,8 +338,13 @@ export class HydraApi { ) { await this.validateOptions(options); + const headers = { + ...this.getAxiosConfig().headers, + "If-Modified-Since": options?.ifModifiedSince?.toUTCString(), + }; + return this.instance - .get(url, { params, ...this.getAxiosConfig() }) + .get(url, { params, ...this.getAxiosConfig(), headers }) .then((response) => response.data) .catch(this.handleUnauthorizedError); } diff --git a/src/types/level.types.ts b/src/types/level.types.ts index 6a729cc5..13f59c7f 100644 --- a/src/types/level.types.ts +++ b/src/types/level.types.ts @@ -68,7 +68,7 @@ export interface Download { export interface GameAchievement { achievements: SteamAchievement[]; unlockedAchievements: UnlockedAchievement[]; - cacheExpiresTimestamp: number | undefined; + updatedAt: number | undefined; } export type AchievementCustomNotificationPosition =