From 9cbcab4c1813fb9ed2d835f711c212cf7b8add54 Mon Sep 17 00:00:00 2001 From: Sander Vispoel Date: Fri, 19 Jul 2024 21:53:14 +0200 Subject: [PATCH] Add API key per game version --- apps/server/src/api/item/auction-house.ts | 12 ++++--- apps/server/src/api/item/index.ts | 7 ++-- .../src/scripts/fetch-auction-houses.ts | 4 +-- apps/server/src/utils/tsm.ts | 32 ++++++++++++------- 4 files changed, 34 insertions(+), 21 deletions(-) diff --git a/apps/server/src/api/item/auction-house.ts b/apps/server/src/api/item/auction-house.ts index 168fdfc..9dc135d 100644 --- a/apps/server/src/api/item/auction-house.ts +++ b/apps/server/src/api/item/auction-house.ts @@ -1,6 +1,7 @@ import * as R from 'remeda'; -import { getAuctionHouse } from '../../utils/tsm'; +import * as i from '../../types'; +import { getAuctionHouse, tsmApiKeys } from '../../utils/tsm'; import { createDbClient } from '../../db'; import { items } from '../../db/schema'; import { Item } from '../../types/tsm'; @@ -8,7 +9,10 @@ import { KEYS, kv } from '../../kv'; const queue = new Map>(); -export async function updateAuctionHouseData(auctionHouseId: string | number) { +export async function updateAuctionHouseData( + auctionHouseId: string | number, + version: i.GameVersion, +) { console.info(auctionHouseId, 'Updating AH'); const KV_KEY = KEYS.tsmAHRecentlyFetched(auctionHouseId); @@ -29,10 +33,10 @@ export async function updateAuctionHouseData(auctionHouseId: string | number) { // Add to queue console.info(auctionHouseId, 'Adding AH to queue...'); - + const tsmApiKey = tsmApiKeys[version]; queue.set( auctionHouseId, - getAuctionHouse(auctionHouseId) + getAuctionHouse(auctionHouseId, tsmApiKey) .then((items) => { console.info(auctionHouseId, 'AH fetched!'); return items; diff --git a/apps/server/src/api/item/index.ts b/apps/server/src/api/item/index.ts index b542022..9cdd0c3 100644 --- a/apps/server/src/api/item/index.ts +++ b/apps/server/src/api/item/index.ts @@ -7,7 +7,7 @@ import { createDbClient } from '../../db'; import { items, itemsMetadata } from '../../db/schema'; import { getItemFromBnet } from '../../utils/blizzard/index.ts'; import { qualityMap } from '../../utils'; -import { getAuctionHouse, getItem } from '../../utils/tsm'; +import { getAuctionHouse, getItem, tsmApiKeys } from '../../utils/tsm'; import { Item } from '../../types/tsm'; export async function itemService(itemId: number, auctionHouseId: number, version: i.GameVersion) { @@ -55,10 +55,11 @@ async function queryItem(id: number, auctionHouseId: number, version: i.GameVers let item: Item | undefined | null; // Fetch entire auction house if needed - getAuctionHouse(auctionHouseId); + const tsmApiKey = tsmApiKeys[version]; + getAuctionHouse(auctionHouseId, tsmApiKey); // Get the item from TSM directly - item = await getItem(id, auctionHouseId); + item = await getItem(id, auctionHouseId, tsmApiKey); if (!item) { // If TSM fetch failed, return item from DB if possible diff --git a/apps/server/src/scripts/fetch-auction-houses.ts b/apps/server/src/scripts/fetch-auction-houses.ts index 9e54a40..ce2b1cb 100644 --- a/apps/server/src/scripts/fetch-auction-houses.ts +++ b/apps/server/src/scripts/fetch-auction-houses.ts @@ -7,7 +7,7 @@ const MAX_ERRORS = 3; for (const region of ['eu', 'us'] as i.Region[]) { // Too many realms to fetch them all, so we'll only fetch seasonal periodically - for (const version of ['seasonal'] as i.GameVersion[]) { + for (const version of ['seasonal', 'era', 'classic', 'hardcore'] as i.GameVersion[]) { console.log(`Fetching realms for "${region}-${version}"...`); const realms = await realmService(region, version); @@ -21,7 +21,7 @@ for (const region of ['eu', 'us'] as i.Region[]) { for await (const auctionHouse of realm.auctionHouses) { try { - await updateAuctionHouseData(auctionHouse.auctionHouseId); + await updateAuctionHouseData(auctionHouse.auctionHouseId, version); } catch (err: any) { console.error( `Failed to update AH for "${realm.name}" (${region}-${version})...`, diff --git a/apps/server/src/utils/tsm.ts b/apps/server/src/utils/tsm.ts index 2a2f28e..bf9b279 100644 --- a/apps/server/src/utils/tsm.ts +++ b/apps/server/src/utils/tsm.ts @@ -4,14 +4,21 @@ import { items } from '../db/schema'; import { KEYS, kv } from '../kv'; import { Region, Item } from '../types/tsm'; -const versionMap = { +const versionMap: Record = { era: 'Classic Era', hardcore: 'Classic Era - Hardcore', classic: 'Wrath', seasonal: 'Season of Discovery', } as const; -async function getAccessToken() { +export const tsmApiKeys: Record = { + era: process.env.TSM_API_KEY_D!, + hardcore: process.env.TSM_API_KEY_C!, + classic: process.env.TSM_API_KEY_B!, + seasonal: process.env.TSM_API_KEY!, +}; + +async function getAccessToken(tsmApiKey: string) { const cached = await kv.get(KEYS.tsmAccessToken); if (cached) { return cached; @@ -23,7 +30,7 @@ async function getAccessToken() { client_id: process.env.TSM_CLIENT_ID, grant_type: 'api_token', scope: 'app:realm-api app:pricing-api', - token: process.env.TSM_API_KEY, + token: tsmApiKey ?? process.env.TSM_API_KEY, }), headers: { 'content-type': 'application/json', @@ -60,8 +67,8 @@ async function getAccessToken() { return access_token; } -async function headers() { - const token = await getAccessToken(); +async function headers(tsmApiKey: string) { + const token = await getAccessToken(tsmApiKey); return { Accept: 'application/json', @@ -76,8 +83,9 @@ export async function getRealms(regionq: i.Region, version: i.GameVersion) { // Fetch from TSM if not in cache if (regions.items.length === 0) { + const tsmApiKey = tsmApiKeys[version]; const response = await fetch(`https://realm-api.tradeskillmaster.com/realms`, { - headers: await headers(), + headers: await headers(tsmApiKey), }); if (response.status !== 200) { throw new Error(`Failed to fetch realms`); @@ -108,11 +116,11 @@ export async function getRealms(regionq: i.Region, version: i.GameVersion) { const queue = new Map>(); -async function fetchAuctionHouse(auctionHouseId: string | number) { +async function fetchAuctionHouse(auctionHouseId: string | number, tsmApiKey: string) { console.info(auctionHouseId, 'fetching auction house...'); const response = await fetch(`https://pricing-api.tradeskillmaster.com/ah/${auctionHouseId}`, { - headers: await headers(), + headers: await headers(tsmApiKey), }); if (response.status !== 200) { @@ -125,7 +133,7 @@ async function fetchAuctionHouse(auctionHouseId: string | number) { return response.json() as Promise; } -export async function getAuctionHouse(auctionHouseId: string | number) { +export async function getAuctionHouse(auctionHouseId: string | number, tsmApiKey: string) { // If already in queue, return its request if (queue.has(auctionHouseId)) { console.info(auctionHouseId, 'Waiting for AH in queue to resolve...'); @@ -145,7 +153,7 @@ export async function getAuctionHouse(auctionHouseId: string | number) { return undefined; } - const auctionHouse = await fetchAuctionHouse(auctionHouseId); + const auctionHouse = await fetchAuctionHouse(auctionHouseId, tsmApiKey); if (Array.isArray(auctionHouse) && auctionHouse.length > 0) { try { @@ -170,14 +178,14 @@ export async function getAuctionHouse(auctionHouseId: string | number) { return queue.get(auctionHouseId); } -export async function getItem(itemId: number, auctionHouseId: number) { +export async function getItem(itemId: number, auctionHouseId: number, tsmApiKey: string) { const logPrefix = `${itemId}:${auctionHouseId}`; console.info(logPrefix, 'Fetching item from TSM'); const response = await fetch( `https://pricing-api.tradeskillmaster.com/ah/${auctionHouseId}/item/${itemId}`, { - headers: await headers(), + headers: await headers(tsmApiKey), }, );