Files
buildpath/frontend/server/utils/cdragon-cache.ts
Valentin Haudiquet fe128c0848 Frontend updates: caching basic data (json) from CDragon
Implement caching in the patch_detector, consume the cache from API routes in frontend
2026-02-28 00:23:04 +01:00

206 lines
4.6 KiB
TypeScript

import { readFile, existsSync } from 'fs'
import { join } from 'path'
import { promisify } from 'util'
const readFileAsync = promisify(readFile)
// CDragon base URL for fallback
const CDRAGON_BASE = 'https://raw.communitydragon.org/'
// Cache directory - can be configured via environment variable
// Default to dev/cdragon for development
const getCacheDir = () => {
if (process.env.CDRAGON_CACHE_DIR) {
return process.env.CDRAGON_CACHE_DIR
}
// Default to dev/cdragon relative to project root
return join(process.cwd(), '..', 'dev', 'data', 'cdragon')
}
/**
* Get the current patch from the patch.txt file or fallback to 'latest'
* Converts patch format for CDragon: "16.4.1" -> "16.4"
*/
async function getCurrentPatch(): Promise<string> {
const cacheDir = getCacheDir()
const patchFile = join(cacheDir, 'latest', 'patch.txt')
if (existsSync(patchFile)) {
const patch = await readFileAsync(patchFile, 'utf-8')
const trimmedPatch = patch.trim()
// Convert patch format for CDragon: "16.4.1" -> "16.4"
return trimmedPatch.split('.').slice(0, 2).join('.')
}
// Fallback to 'latest' if no patch file exists
return 'latest'
}
/**
* Cached CDragon data types
*/
interface CDragonCacheOptions {
patch?: string
}
/**
* Fetch data from local cache with CDragon fallback
*/
async function fetchFromCache<T>(
assetName: string,
cdragonPath: string,
options?: CDragonCacheOptions
): Promise<T> {
const cacheDir = getCacheDir()
const patch = options?.patch || (await getCurrentPatch())
const cachePath = join(cacheDir, patch, assetName)
// Try to read from cache first
if (existsSync(cachePath)) {
try {
const data = await readFileAsync(cachePath, 'utf-8')
return JSON.parse(data) as T
} catch (error) {
console.error(`Error reading cache file ${cachePath}:`, error)
}
}
// Fallback to CDragon
console.log(`Cache miss for ${assetName}, fetching from CDragon...`)
const url = `${CDRAGON_BASE}${patch}/${cdragonPath}`
const response = await fetch(url)
if (!response.ok) {
throw new Error(`Failed to fetch ${assetName} from CDragon: ${response.status}`)
}
return (await response.json()) as T
}
/**
* Get items data from cache
*/
async function getItems(patch?: string): Promise<CDragonItem[]> {
return fetchFromCache<CDragonItem[]>(
'items.json',
'plugins/rcp-be-lol-game-data/global/default/v1/items.json',
{ patch }
)
}
/**
* Get perks (runes) data from cache
*/
async function getPerks(patch?: string): Promise<CDragonPerk[]> {
return fetchFromCache<CDragonPerk[]>(
'perks.json',
'plugins/rcp-be-lol-game-data/global/default/v1/perks.json',
{ patch }
)
}
/**
* Get perk styles data from cache
*/
async function getPerkStyles(patch?: string): Promise<CDragonPerkStyles> {
return fetchFromCache<CDragonPerkStyles>(
'perkstyles.json',
'plugins/rcp-be-lol-game-data/global/default/v1/perkstyles.json',
{ patch }
)
}
/**
* Get summoner spells data from cache
*/
async function getSummonerSpells(patch?: string): Promise<CDragonSummonerSpell[]> {
return fetchFromCache<CDragonSummonerSpell[]>(
'summoner-spells.json',
'plugins/rcp-be-lol-game-data/global/default/v1/summoner-spells.json',
{ patch }
)
}
/**
* Get champion summary data from cache
*/
async function getChampionSummary(patch?: string): Promise<CDragonChampionSummary[]> {
return fetchFromCache<CDragonChampionSummary[]>(
'champion-summary.json',
'plugins/rcp-be-lol-game-data/global/default/v1/champion-summary.json',
{ patch }
)
}
// Type definitions for CDragon data
interface CDragonItem {
id: number
name: string
iconPath: string
description?: string
plaintext?: string
into?: number[]
from?: number[]
gold?: {
base: number
total: number
sell: number
}
}
interface CDragonPerk {
id: number
name: string
iconPath: string
shortDesc?: string
longDesc?: string
}
interface CDragonPerkStyle {
id: number
name: string
iconPath: string
slots: Array<{
type: string
perks: number[]
}>
}
interface CDragonPerkStyles {
styles: CDragonPerkStyle[]
}
interface CDragonSummonerSpell {
id: number
name: string
iconPath: string
description?: string
}
interface CDragonChampionSummary {
id: number
name: string
alias: string
squarePortraitPath: string
roles?: string[]
}
export {
getItems,
getPerks,
getPerkStyles,
getSummonerSpells,
getChampionSummary,
getCurrentPatch,
CDRAGON_BASE
}
export type {
CDragonItem,
CDragonPerk,
CDragonPerkStyle,
CDragonPerkStyles,
CDragonSummonerSpell,
CDragonChampionSummary
}