optimize requests to scoresaber's api
Some checks failed
Deploy Website / docker (ubuntu-latest) (push) Failing after 1m57s

This commit is contained in:
Lee 2024-10-26 15:16:50 +01:00
parent f8b0f7c6cd
commit e57e725639
2 changed files with 13 additions and 29 deletions

@ -12,8 +12,8 @@ import { ScoreSaberScore } from "@ssr/common/model/score/impl/scoresaber-score";
import ScoreSaberLeaderboard from "@ssr/common/model/leaderboard/impl/scoresaber-leaderboard"; import ScoreSaberLeaderboard from "@ssr/common/model/leaderboard/impl/scoresaber-leaderboard";
import { fetchPlayerScores } from "@ssr/common/utils/score-utils"; import { fetchPlayerScores } from "@ssr/common/utils/score-utils";
import PlayerScoresResponse from "@ssr/common/response/player-scores-response"; import PlayerScoresResponse from "@ssr/common/response/player-scores-response";
import { SSRCache } from "@ssr/common/cache";
import { getScoreSaberPlayerFromToken } from "@ssr/common/token-creators"; import { getScoreSaberPlayerFromToken } from "@ssr/common/token-creators";
import { cache } from "react";
const UNKNOWN_PLAYER = { const UNKNOWN_PLAYER = {
title: "ScoreSaber Reloaded - Unknown Player", title: "ScoreSaber Reloaded - Unknown Player",
@ -37,8 +37,9 @@ type PlayerData = {
search: string; search: string;
}; };
const playerCache = new SSRCache({ const getPlayer = cache(async (id: string): Promise<ScoreSaberPlayer | undefined> => {
ttl: 1000 * 60, // 1 minute const playerToken = await scoresaberService.lookupPlayer(id);
return playerToken && (await getScoreSaberPlayerFromToken(playerToken, await getCookieValue("playerId")));
}); });
/** /**
@ -48,35 +49,27 @@ const playerCache = new SSRCache({
* @param fetchScores whether to fetch the scores * @param fetchScores whether to fetch the scores
* @returns the player data and scores * @returns the player data and scores
*/ */
const getPlayerData = async ({ params }: Props, fetchScores: boolean = true): Promise<PlayerData> => { const getPlayerData = cache(async ({ params }: Props, fetchScores: boolean = true): Promise<PlayerData> => {
const { slug } = await params; const { slug } = await params;
const id = slug[0]; // The players id const id = slug[0]; // The players id
const sort: ScoreSort = (slug[1] as ScoreSort) || (await getCookieValue("lastScoreSort", "recent")); // The sorting method const sort: ScoreSort = (slug[1] as ScoreSort) || (await getCookieValue("lastScoreSort", "recent")); // The sorting method
const page = parseInt(slug[2]) || 1; // The page number const page = parseInt(slug[2]) || 1; // The page number
const search = (slug[3] as string) || ""; // The search query const search = (slug[3] as string) || ""; // The search query
const cacheId = `${id}-${sort}-${page}-${search}-${fetchScores}`; const player = await getPlayer(id);
if (playerCache.has(cacheId)) {
return playerCache.get(cacheId) as PlayerData;
}
const playerToken = await scoresaberService.lookupPlayer(id);
const player = playerToken && (await getScoreSaberPlayerFromToken(playerToken, await getCookieValue("playerId")));
let scores: PlayerScoresResponse<ScoreSaberScore, ScoreSaberLeaderboard> | undefined; let scores: PlayerScoresResponse<ScoreSaberScore, ScoreSaberLeaderboard> | undefined;
if (fetchScores) { if (fetchScores && player !== undefined) {
scores = await fetchPlayerScores<ScoreSaberScore, ScoreSaberLeaderboard>("scoresaber", id, page, sort, search); scores = await fetchPlayerScores<ScoreSaberScore, ScoreSaberLeaderboard>("scoresaber", id, page, sort, search);
} }
const playerData = { return {
sort: sort, sort: sort,
page: page, page: page,
search: search, search: search,
player: player, player: player,
scores: scores, scores: scores,
}; };
playerCache.set(cacheId, playerData); });
return playerData;
};
export async function generateMetadata(props: Props): Promise<Metadata> { export async function generateMetadata(props: Props): Promise<Metadata> {
const { player } = await getPlayerData(props, false); const { player } = await getPlayerData(props, false);

@ -1,11 +1,11 @@
import { Metadata } from "next"; import { Metadata } from "next";
import { scoresaberService } from "@ssr/common/service/impl/scoresaber"; import { scoresaberService } from "@ssr/common/service/impl/scoresaber";
import NodeCache from "node-cache";
import { ScoreSaberPlayersPageToken } from "@ssr/common/types/token/scoresaber/score-saber-players-page-token"; import { ScoreSaberPlayersPageToken } from "@ssr/common/types/token/scoresaber/score-saber-players-page-token";
import Card from "@/components/card"; import Card from "@/components/card";
import RankingData from "@/components/ranking/ranking-data"; import RankingData from "@/components/ranking/ranking-data";
import CountryFlag from "@/components/country-flag"; import CountryFlag from "@/components/country-flag";
import { normalizedRegionName } from "@ssr/common/utils/region-utils"; import { normalizedRegionName } from "@ssr/common/utils/region-utils";
import { cache } from "react";
const UNKNOWN_PAGE = { const UNKNOWN_PAGE = {
title: "ScoreSaber Reloaded - Unknown Page", title: "ScoreSaber Reloaded - Unknown Page",
@ -24,36 +24,27 @@ type RankingPageData = {
country: string | undefined; country: string | undefined;
}; };
const rankingCache = new NodeCache({ stdTTL: 60, checkperiod: 120 });
/** /**
* Gets the ranking data. * Gets the ranking data.
* *
* @param params the params * @param params the params
* @returns the ranking data * @returns the ranking data
*/ */
const getRankingData = async ({ params }: Props): Promise<RankingPageData> => { const getRankingData = cache(async ({ params }: Props): Promise<RankingPageData> => {
const { slug } = await params; const { slug } = await params;
const country = (slug && slug.length > 1 && (slug[0] as string).toUpperCase()) || undefined; // The country query const country = (slug && slug.length > 1 && (slug[0] as string).toUpperCase()) || undefined; // The country query
const page = (slug && parseInt(slug[country != undefined ? 1 : 0])) || 1; // The page number const page = (slug && parseInt(slug[country != undefined ? 1 : 0])) || 1; // The page number
const cacheId = `${country === undefined ? "global" : country}-${page}`;
if (rankingCache.has(cacheId)) {
return rankingCache.get(cacheId) as RankingPageData;
}
const players = const players =
country == undefined country == undefined
? await scoresaberService.lookupPlayers(page) ? await scoresaberService.lookupPlayers(page)
: await scoresaberService.lookupPlayersByCountry(page, country); : await scoresaberService.lookupPlayersByCountry(page, country);
const rankingData = { return {
players: players && players.players.length > 0 ? players : undefined, players: players && players.players.length > 0 ? players : undefined,
page, page,
country, country,
}; };
rankingCache.set(cacheId, rankingData); });
return rankingData;
};
export async function generateMetadata(props: Props): Promise<Metadata> { export async function generateMetadata(props: Props): Promise<Metadata> {
const { players, page, country } = await getRankingData(props); const { players, page, country } = await getRankingData(props);