From 33a3efe5b0fa7252f10d5aab3089f18ed5fa9044 Mon Sep 17 00:00:00 2001 From: zkldi <20380519+zkldi@users.noreply.github.com> Date: Mon, 7 Nov 2022 21:01:47 +0000 Subject: [PATCH 1/2] fix: make kai-type-apis not spontaneously fail to sync classes reauthing *did not* happen in the case where class-searching failed. It happened when the iterator is called, which is after the classHandler is curried. --- .../common/api-kai/iidx/class-handler.ts | 22 ++++++++++++++++++- .../common/api-kai/iidx/parser.ts | 6 +++-- .../common/api-kai/sdvx/class-handler.ts | 16 +++++++++++++- .../common/api-kai/sdvx/parser.ts | 6 +++-- 4 files changed, 44 insertions(+), 6 deletions(-) diff --git a/server/src/lib/score-import/import-types/common/api-kai/iidx/class-handler.ts b/server/src/lib/score-import/import-types/common/api-kai/iidx/class-handler.ts index e5ae16ecc..eb0b3a2f7 100644 --- a/server/src/lib/score-import/import-types/common/api-kai/iidx/class-handler.ts +++ b/server/src/lib/score-import/import-types/common/api-kai/iidx/class-handler.ts @@ -2,11 +2,13 @@ import { KaiTypeToBaseURL } from "../utils"; import { IIDXDans } from "lib/constants/classes"; import nodeFetch from "utils/fetch"; import { IsRecord } from "utils/misc"; +import type { KaiAPIReauthFunction } from "../traverse-api"; import type { ClassHandler } from "lib/score-import/framework/user-game-stats/types"; export async function CreateKaiIIDXClassHandler( kaiType: "EAG" | "FLO", token: string, + reauthFn: KaiAPIReauthFunction, fetch = nodeFetch ): Promise { let json: unknown; @@ -16,13 +18,31 @@ export async function CreateKaiIIDXClassHandler( // SP and DP dans are located in the same place, // fetch once, then return a function that traverses this data. try { - const res = await fetch(`${baseUrl}/api/iidx/v2/player_profile`, { + let res = await fetch(`${baseUrl}/api/iidx/v2/player_profile`, { headers: { Authorization: `Bearer ${token}`, "Content-Type": "application/json", }, }); + // if we failed auth wise. Try reauthing. + if (res.status === 401 || res.status === 403) { + const newToken = await reauthFn(); + + res = await fetch(`${baseUrl}/api/sdvx/v1/player_profile`, { + headers: { + Authorization: `Bearer ${newToken}`, + "Content-Type": "application/json", + }, + }); + } + + if (res.status !== 200) { + const text = await res.text(); + + throw new Error(`Got unexpected status from ${kaiType}: ${res.status}. Body: ${text}`); + } + json = (await res.json()) as unknown; } catch (e: unknown) { err = e; diff --git a/server/src/lib/score-import/import-types/common/api-kai/iidx/parser.ts b/server/src/lib/score-import/import-types/common/api-kai/iidx/parser.ts index 12fce6a53..b97a19a7d 100644 --- a/server/src/lib/score-import/import-types/common/api-kai/iidx/parser.ts +++ b/server/src/lib/score-import/import-types/common/api-kai/iidx/parser.ts @@ -16,19 +16,21 @@ export async function ParseKaiIIDX( ): Promise> { const baseUrl = KaiTypeToBaseURL(service); + const reauthFn = CreateKaiReauthFunction(service, authDoc, logger, fetch); + return { iterable: TraverseKaiAPI( baseUrl, "/api/iidx/v2/play_history", authDoc.token, logger, - CreateKaiReauthFunction(service, authDoc, logger, fetch), + reauthFn, fetch ), context: { service, }, - classHandler: await CreateKaiIIDXClassHandler(service, authDoc.token, fetch), + classHandler: await CreateKaiIIDXClassHandler(service, authDoc.token, reauthFn, fetch), game: "iidx", }; } diff --git a/server/src/lib/score-import/import-types/common/api-kai/sdvx/class-handler.ts b/server/src/lib/score-import/import-types/common/api-kai/sdvx/class-handler.ts index 926f9c08b..d41daae01 100644 --- a/server/src/lib/score-import/import-types/common/api-kai/sdvx/class-handler.ts +++ b/server/src/lib/score-import/import-types/common/api-kai/sdvx/class-handler.ts @@ -2,11 +2,13 @@ import { KaiTypeToBaseURL } from "../utils"; import { SDVXDans } from "lib/constants/classes"; import nodeFetch from "utils/fetch"; import { IsRecord } from "utils/misc"; +import type { KaiAPIReauthFunction } from "../traverse-api"; import type { ClassHandler } from "lib/score-import/framework/user-game-stats/types"; export async function CreateKaiSDVXClassHandler( kaiType: "EAG" | "FLO" | "MIN", token: string, + reauthFn: KaiAPIReauthFunction, fetch = nodeFetch ): Promise { let json: unknown; @@ -14,13 +16,25 @@ export async function CreateKaiSDVXClassHandler( const baseUrl = KaiTypeToBaseURL(kaiType); try { - const res = await fetch(`${baseUrl}/api/sdvx/v1/player_profile`, { + let res = await fetch(`${baseUrl}/api/sdvx/v1/player_profile`, { headers: { Authorization: `Bearer ${token}`, "Content-Type": "application/json", }, }); + // if we failed auth wise. Try reauthing. + if (res.status === 401 || res.status === 403) { + const newToken = await reauthFn(); + + res = await fetch(`${baseUrl}/api/sdvx/v1/player_profile`, { + headers: { + Authorization: `Bearer ${newToken}`, + "Content-Type": "application/json", + }, + }); + } + json = (await res.json()) as unknown; } catch (e: unknown) { err = e; diff --git a/server/src/lib/score-import/import-types/common/api-kai/sdvx/parser.ts b/server/src/lib/score-import/import-types/common/api-kai/sdvx/parser.ts index e34a28edf..f85c177ac 100644 --- a/server/src/lib/score-import/import-types/common/api-kai/sdvx/parser.ts +++ b/server/src/lib/score-import/import-types/common/api-kai/sdvx/parser.ts @@ -16,19 +16,21 @@ export async function ParseKaiSDVX( ): Promise> { const baseUrl = KaiTypeToBaseURL(service); + const reauthFn = CreateKaiReauthFunction(service, authDoc, logger, fetch); + return { iterable: TraverseKaiAPI( baseUrl, "/api/sdvx/v1/play_history", authDoc.token, logger, - CreateKaiReauthFunction(service, authDoc, logger, fetch), + reauthFn, fetch ), context: { service, }, - classHandler: await CreateKaiSDVXClassHandler(service, authDoc.token, fetch), + classHandler: await CreateKaiSDVXClassHandler(service, authDoc.token, reauthFn, fetch), game: "sdvx", }; } From 4b801cf0cbdec3116d5170a40806535f4cdd6ed6 Mon Sep 17 00:00:00 2001 From: zkldi <20380519+zkldi@users.noreply.github.com> Date: Mon, 7 Nov 2022 21:58:21 +0000 Subject: [PATCH 2/2] fix: make tests compile --- .../common/api-kai/iidx/class-handler.test.ts | 54 ++++++++++++++++++- .../common/api-kai/sdvx/class-handler.test.ts | 50 ++++++++++++++++- 2 files changed, 102 insertions(+), 2 deletions(-) diff --git a/server/src/lib/score-import/import-types/common/api-kai/iidx/class-handler.test.ts b/server/src/lib/score-import/import-types/common/api-kai/iidx/class-handler.test.ts index b9b2daed8..bcf18a83b 100644 --- a/server/src/lib/score-import/import-types/common/api-kai/iidx/class-handler.test.ts +++ b/server/src/lib/score-import/import-types/common/api-kai/iidx/class-handler.test.ts @@ -14,6 +14,10 @@ t.test("#CreateKaiIIDXClassHandler", async (t) => { const fn = await CreateKaiIIDXClassHandler( "FLO", "token", + // eslint-disable-next-line @typescript-eslint/require-await + async () => { + throw new Error(`Unexpectedly called reauthFn?`); + }, MockJSONFetch({ [`${KaiTypeToBaseURL("FLO")}/api/iidx/v2/player_profile`]: { _links: {}, @@ -45,6 +49,10 @@ t.test("#CreateKaiIIDXClassHandler", async (t) => { const fn = await CreateKaiIIDXClassHandler( "FLO", "token", + // eslint-disable-next-line @typescript-eslint/require-await + async () => { + throw new Error(`Unexpectedly called reauthFn?`); + }, MockJSONFetch({ [`${KaiTypeToBaseURL("FLO")}/api/iidx/v2/player_profile`]: { _links: {}, @@ -69,6 +77,10 @@ t.test("#CreateKaiIIDXClassHandler", async (t) => { const fn = await CreateKaiIIDXClassHandler( "FLO", "token", + // eslint-disable-next-line @typescript-eslint/require-await + async () => { + throw new Error(`Unexpectedly called reauthFn?`); + }, MockJSONFetch({ [`${KaiTypeToBaseURL("FLO")}/api/iidx/v2/player_profile`]: { _links: {}, @@ -93,6 +105,10 @@ t.test("#CreateKaiIIDXClassHandler", async (t) => { const fn = await CreateKaiIIDXClassHandler( "FLO", "token", + // eslint-disable-next-line @typescript-eslint/require-await + async () => { + throw new Error(`Unexpectedly called reauthFn?`); + }, MockJSONFetch({ [`${KaiTypeToBaseURL("FLO")}/api/iidx/v2/player_profile`]: { _links: {}, @@ -114,7 +130,15 @@ t.test("#CreateKaiIIDXClassHandler", async (t) => { }); t.test("Should gracefully handle negative API responses", async (t) => { - const fn = await CreateKaiIIDXClassHandler("FLO", "token", MockBasicFetch({ status: 500 })); + const fn = await CreateKaiIIDXClassHandler( + "FLO", + "token", + // eslint-disable-next-line @typescript-eslint/require-await + async () => { + throw new Error(`Unexpectedly called reauthFn?`); + }, + MockBasicFetch({ status: 500 }) + ); const res = fn("iidx", "SP", 1, {}, logger); @@ -123,10 +147,34 @@ t.test("#CreateKaiIIDXClassHandler", async (t) => { t.end(); }); + t.test("Should call reauthFn if statusCode is 401", async (t) => { + let pass = false; + const fn = await CreateKaiIIDXClassHandler( + "FLO", + "token", + // eslint-disable-next-line @typescript-eslint/require-await + async () => { + pass = true; + return ""; + }, + MockBasicFetch({ status: 401 }) + ); + + fn("iidx", "SP", 1, {}, logger); + + t.equal(pass, true, "Should've called the reauth fn."); + + t.end(); + }); + t.test("Should ignore null dans", async (t) => { const fn = await CreateKaiIIDXClassHandler( "FLO", "token", + // eslint-disable-next-line @typescript-eslint/require-await + async () => { + throw new Error(`Unexpectedly called reauthFn?`); + }, MockJSONFetch({ [`${KaiTypeToBaseURL("FLO")}/api/iidx/v2/player_profile`]: { _links: {}, @@ -151,6 +199,10 @@ t.test("#CreateKaiIIDXClassHandler", async (t) => { const fn = await CreateKaiIIDXClassHandler( "FLO", "token", + // eslint-disable-next-line @typescript-eslint/require-await + async () => { + throw new Error(`Unexpectedly called reauthFn?`); + }, MockJSONFetch({ [`${KaiTypeToBaseURL("FLO")}/api/iidx/v2/player_profile`]: { _links: {}, diff --git a/server/src/lib/score-import/import-types/common/api-kai/sdvx/class-handler.test.ts b/server/src/lib/score-import/import-types/common/api-kai/sdvx/class-handler.test.ts index 7cbf90a67..57027b703 100644 --- a/server/src/lib/score-import/import-types/common/api-kai/sdvx/class-handler.test.ts +++ b/server/src/lib/score-import/import-types/common/api-kai/sdvx/class-handler.test.ts @@ -14,6 +14,10 @@ t.test("#CreateKaiSDVXClassHandler", async (t) => { const fn = await CreateKaiSDVXClassHandler( "FLO", "token", + // eslint-disable-next-line @typescript-eslint/require-await + async () => { + throw new Error(`Unexpectedly called reauthFn?`); + }, MockJSONFetch({ [`${KaiTypeToBaseURL("FLO")}/api/sdvx/v1/player_profile`]: { _links: {}, @@ -44,6 +48,10 @@ t.test("#CreateKaiSDVXClassHandler", async (t) => { const fn = await CreateKaiSDVXClassHandler( "FLO", "token", + // eslint-disable-next-line @typescript-eslint/require-await + async () => { + throw new Error(`Unexpectedly called reauthFn?`); + }, MockJSONFetch({ [`${KaiTypeToBaseURL("FLO")}/api/sdvx/v1/player_profile`]: { _links: {}, @@ -67,6 +75,10 @@ t.test("#CreateKaiSDVXClassHandler", async (t) => { const fn = await CreateKaiSDVXClassHandler( "FLO", "token", + // eslint-disable-next-line @typescript-eslint/require-await + async () => { + throw new Error(`Unexpectedly called reauthFn?`); + }, MockJSONFetch({ [`${KaiTypeToBaseURL("FLO")}/api/sdvx/v1/player_profile`]: { _links: {}, @@ -90,6 +102,10 @@ t.test("#CreateKaiSDVXClassHandler", async (t) => { const fn = await CreateKaiSDVXClassHandler( "FLO", "token", + // eslint-disable-next-line @typescript-eslint/require-await + async () => { + throw new Error(`Unexpectedly called reauthFn?`); + }, MockJSONFetch({ [`${KaiTypeToBaseURL("FLO")}/api/sdvx/v1/player_profile`]: { _links: {}, @@ -110,7 +126,15 @@ t.test("#CreateKaiSDVXClassHandler", async (t) => { }); t.test("Should gracefully handle negative API responses", async (t) => { - const fn = await CreateKaiSDVXClassHandler("FLO", "token", MockBasicFetch({ status: 500 })); + const fn = await CreateKaiSDVXClassHandler( + "FLO", + "token", + // eslint-disable-next-line @typescript-eslint/require-await + async () => { + throw new Error(`Unexpectedly called reauthFn?`); + }, + MockBasicFetch({ status: 500 }) + ); const res = fn("sdvx", "Single", 1, {}, logger); @@ -119,10 +143,34 @@ t.test("#CreateKaiSDVXClassHandler", async (t) => { t.end(); }); + t.test("Should call reauthFn if statusCode is 401", async (t) => { + let pass = false; + const fn = await CreateKaiSDVXClassHandler( + "FLO", + "token", + // eslint-disable-next-line @typescript-eslint/require-await + async () => { + pass = true; + return ""; + }, + MockBasicFetch({ status: 401 }) + ); + + fn("sdvx", "Single", 1, {}, logger); + + t.equal(pass, true, "Should've called the reauth fn."); + + t.end(); + }); + t.test("Should ignore null dans", async (t) => { const fn = await CreateKaiSDVXClassHandler( "FLO", "token", + // eslint-disable-next-line @typescript-eslint/require-await + async () => { + throw new Error(`Unexpectedly called reauthFn?`); + }, MockJSONFetch({ [`${KaiTypeToBaseURL("FLO")}/api/sdvx/v1/player_profile`]: { _links: {},