Merge pull request #272 from zkldi:zkldi/issue-246-Kai-API-dan-retrieving

Kai-API dan retrieving (and MIN support)
This commit is contained in:
zkldi
2021-08-11 03:59:30 +01:00
committed by GitHub
22 changed files with 550 additions and 51 deletions
+1
View File
@@ -8,6 +8,7 @@
SESSION_SECRET: "unused",
FLO_API_URL: "https://flo.example.com",
EAG_API_URL: "https://eag.example.com",
MIN_API_URL: "https://min.example.com",
ARC_API_URL: "https://arc.example.com",
ARC_AUTH_TOKEN: "unused",
CDN_FILE_ROOT: "./local-cdn",
+1 -1
View File
@@ -69,7 +69,7 @@
"redis": "3.1.2",
"rimraf": "3.0.2",
"safe-json-stringify": "1.2.0",
"tachi-common": "^0.1.5",
"tachi-common": "^0.1.6",
"typescript": "4.3.4",
"winston": "3.3.3"
},
+4 -4
View File
@@ -51,7 +51,7 @@ specifiers:
rimraf: 3.0.2
safe-json-stringify: 1.2.0
supertest: 6.1.3
tachi-common: ^0.1.5
tachi-common: ^0.1.6
tap: 15.0.9
ts-node: 10.0.0
tsconfig-paths: 3.10.1
@@ -84,7 +84,7 @@ dependencies:
redis: 3.1.2
rimraf: 3.0.2
safe-json-stringify: 1.2.0
tachi-common: 0.1.5_ts-node@10.0.0+typescript@4.3.4
tachi-common: 0.1.6_ts-node@10.0.0+typescript@4.3.4
typescript: 4.3.4
winston: 3.3.3
@@ -3774,8 +3774,8 @@ packages:
strip-ansi: 6.0.0
dev: true
/tachi-common/0.1.5_ts-node@10.0.0+typescript@4.3.4:
resolution: {integrity: sha512-caqTQ43TqTb861lenL27cIFxU9enZJCulSBU6kk1db2/XJNmNsLNtoo5xDwbgYs4eSwxkENGBZ1THbeBG0B5RQ==}
/tachi-common/0.1.6_ts-node@10.0.0+typescript@4.3.4:
resolution: {integrity: sha512-H2kjAIUXyvNGuPlOgvWc25KmujETee4XqRRSG/BQIall0FSiO7yWApZQMelQZITebdlKwzpd976P2NSejTv0Yg==}
dependencies:
monk: 7.3.4
tap: 15.0.9_ts-node@10.0.0+typescript@4.3.4
+1 -1
View File
@@ -1,4 +1,4 @@
export enum IIDXClasses {
export enum IIDXDans {
KYU_7,
KYU_6,
KYU_5,
@@ -2,7 +2,7 @@ import t from "tap";
import { CloseAllConnections } from "test-utils/close-connections";
import { MockJSONFetch } from "test-utils/mock-fetch";
import ResetDBState from "test-utils/resets";
import { IIDXClasses } from "lib/constants/classes";
import { IIDXDans } from "lib/constants/classes";
import CreateLogCtx from "lib/logger/logger";
import { CreateArcIIDXClassHandler } from "./class-handler";
@@ -34,10 +34,10 @@ t.test("#CreateArcIIDXClassHandler", (t) => {
// its not async but typescript complains
const res = await fn("iidx", "SP", 1, {}, logger);
t.equal(res!.dan, IIDXClasses.CHUUDEN);
t.equal(res!.dan, IIDXDans.CHUUDEN);
const res2 = await fn("iidx", "DP", 1, {}, logger);
t.equal(res2!.dan, IIDXClasses.DAN_2);
t.equal(res2!.dan, IIDXDans.DAN_2);
t.end();
});
@@ -1,6 +1,6 @@
import nodeFetch from "utils/fetch";
import { HasOwnProperty } from "utils/misc";
import { IIDXClasses } from "lib/constants/classes";
import { IIDXDans } from "lib/constants/classes";
import { ClassHandler } from "../../../framework/user-game-stats/types";
import { ServerConfig } from "lib/setup/config";
@@ -72,24 +72,24 @@ export async function CreateArcIIDXClassHandler(
}
const ARCClasses = {
皆伝: IIDXClasses.KAIDEN,
中伝: IIDXClasses.CHUUDEN,
十段: IIDXClasses.DAN_10,
九段: IIDXClasses.DAN_9,
八段: IIDXClasses.DAN_8,
七段: IIDXClasses.DAN_7,
六段: IIDXClasses.DAN_6,
五段: IIDXClasses.DAN_5,
四段: IIDXClasses.DAN_4,
三段: IIDXClasses.DAN_3,
二段: IIDXClasses.DAN_2, // These two look very similar but they aren't
ニ段: IIDXClasses.DAN_2, // and ARC uses both, from what I can tell.
初段: IIDXClasses.DAN_1,
一級: IIDXClasses.KYU_1,
二級: IIDXClasses.KYU_2,
三級: IIDXClasses.KYU_3,
四級: IIDXClasses.KYU_4,
五級: IIDXClasses.KYU_5,
六級: IIDXClasses.KYU_6,
七級: IIDXClasses.KYU_7,
皆伝: IIDXDans.KAIDEN,
中伝: IIDXDans.CHUUDEN,
十段: IIDXDans.DAN_10,
九段: IIDXDans.DAN_9,
八段: IIDXDans.DAN_8,
七段: IIDXDans.DAN_7,
六段: IIDXDans.DAN_6,
五段: IIDXDans.DAN_5,
四段: IIDXDans.DAN_4,
三段: IIDXDans.DAN_3,
二段: IIDXDans.DAN_2, // These two look very similar but they aren't
ニ段: IIDXDans.DAN_2, // and ARC uses both, from what I can tell.
初段: IIDXDans.DAN_1,
一級: IIDXDans.KYU_1,
二級: IIDXDans.KYU_2,
三級: IIDXDans.KYU_3,
四級: IIDXDans.KYU_4,
五級: IIDXDans.KYU_5,
六級: IIDXDans.KYU_6,
七級: IIDXDans.KYU_7,
};
@@ -21,7 +21,11 @@ export async function ParseArcIIDX(
fetch
),
context: {},
classHandler: await CreateArcIIDXClassHandler(arcProfileID, ServerConfig.ARC_AUTH_TOKEN),
classHandler: await CreateArcIIDXClassHandler(
arcProfileID,
ServerConfig.ARC_AUTH_TOKEN,
fetch
),
game: "iidx",
};
}
@@ -0,0 +1,7 @@
import { KtLogger } from "lib/logger/logger";
import { KaiAuthDocument } from "tachi-common";
import { ParseKaiSDVX } from "../../common/api-kai/sdvx/parser";
export function ParseMinSDVX(authDoc: KaiAuthDocument, logger: KtLogger) {
return ParseKaiSDVX("MIN", authDoc, logger);
}
@@ -0,0 +1,178 @@
import { IIDXDans } from "lib/constants/classes";
import CreateLogCtx from "lib/logger/logger";
import t from "tap";
import { CloseAllConnections } from "test-utils/close-connections";
import { MockBasicFetch, MockJSONFetch } from "test-utils/mock-fetch";
import ResetDBState from "test-utils/resets";
import { KaiTypeToBaseURL } from "utils/misc";
import { CreateKaiIIDXClassHandler } from "./class-handler";
const logger = CreateLogCtx(__filename);
t.test("#CreateKaiIIDXClassHandler", async (t) => {
t.beforeEach(ResetDBState);
const fn = await CreateKaiIIDXClassHandler(
"FLO",
"token",
MockJSONFetch({
[`${KaiTypeToBaseURL("FLO")}/api/iidx/v2/player_profile`]: {
_links: {},
iidx_id: 12345678,
dj_name: "SOMEONE",
sp: 18,
dp: 4,
access_time: "2021-08-08T18:50:40Z",
register_time: "2019-01-19T12:53:50Z",
},
})
);
t.test("Should return a function with arity 5.", (t) => {
t.equal(fn.length, 5);
t.end();
});
t.test("Should call the provided URL with the authentication token", (t) => {
const res = fn("iidx", "SP", 1, {}, logger);
t.strictSame(res, { dan: 18 });
t.end();
});
t.test("Should return nothing if dan is not a number", async (t) => {
const fn = await CreateKaiIIDXClassHandler(
"FLO",
"token",
MockJSONFetch({
[`${KaiTypeToBaseURL("FLO")}/api/iidx/v2/player_profile`]: {
_links: {},
iidx_id: 12345678,
dj_name: "SOMEONE",
sp: "NOT A NUMBER",
dp: 4,
access_time: "2021-08-08T18:50:40Z",
register_time: "2019-01-19T12:53:50Z",
},
})
);
const res = fn("iidx", "SP", 1, {}, logger);
t.strictSame(res, {});
t.end();
});
t.test("Should return nothing if dan is too great", async (t) => {
const fn = await CreateKaiIIDXClassHandler(
"FLO",
"token",
MockJSONFetch({
[`${KaiTypeToBaseURL("FLO")}/api/iidx/v2/player_profile`]: {
_links: {},
iidx_id: 12345678,
dj_name: "SOMEONE",
sp: IIDXDans.KAIDEN + 1,
dp: 4,
access_time: "2021-08-08T18:50:40Z",
register_time: "2019-01-19T12:53:50Z",
},
})
);
const res = fn("iidx", "SP", 1, {}, logger);
t.strictSame(res, {});
t.end();
});
t.test("Should return nothing if dan is negative", async (t) => {
const fn = await CreateKaiIIDXClassHandler(
"FLO",
"token",
MockJSONFetch({
[`${KaiTypeToBaseURL("FLO")}/api/iidx/v2/player_profile`]: {
_links: {},
iidx_id: 12345678,
dj_name: "SOMEONE",
sp: IIDXDans.KYU_7 - 1,
dp: 4,
access_time: "2021-08-08T18:50:40Z",
register_time: "2019-01-19T12:53:50Z",
},
})
);
const res = fn("iidx", "SP", 1, {}, logger);
t.strictSame(res, {});
t.end();
});
t.test("Should gracefully handle negative API responses", async (t) => {
const fn = await CreateKaiIIDXClassHandler("FLO", "token", MockBasicFetch({ status: 500 }));
const res = fn("iidx", "SP", 1, {}, logger);
t.strictSame(res, {});
t.end();
});
t.test("Should ignore null dans", async (t) => {
const fn = await CreateKaiIIDXClassHandler(
"FLO",
"token",
MockJSONFetch({
[`${KaiTypeToBaseURL("FLO")}/api/iidx/v2/player_profile`]: {
_links: {},
iidx_id: 12345678,
dj_name: "SOMEONE",
sp: 1,
dp: null,
access_time: "2021-08-08T18:50:40Z",
register_time: "2019-01-19T12:53:50Z",
},
})
);
const res = fn("iidx", "DP", 1, {}, logger);
t.strictSame(res, {});
t.end();
});
t.test("Should handle invalid playtypes", async (t) => {
const fn = await CreateKaiIIDXClassHandler(
"FLO",
"token",
MockJSONFetch({
[`${KaiTypeToBaseURL("FLO")}/api/iidx/v2/player_profile`]: {
_links: {},
iidx_id: 12345678,
dj_name: "SOMEONE",
sp: 1,
dp: 1,
access_time: "2021-08-08T18:50:40Z",
register_time: "2019-01-19T12:53:50Z",
},
})
);
const res = fn("iidx", "14K", 1, {}, logger);
t.strictSame(res, {});
t.end();
});
t.end();
});
t.teardown(CloseAllConnections);
@@ -0,0 +1,74 @@
import { IIDXDans } from "lib/constants/classes";
import { ClassHandler } from "lib/score-import/framework/user-game-stats/types";
import nodeFetch from "utils/fetch";
import { KaiTypeToBaseURL } from "utils/misc";
export async function CreateKaiIIDXClassHandler(
kaiType: "FLO" | "EAG",
token: string,
fetch = nodeFetch
): Promise<ClassHandler> {
// eslint-disable-next-line @typescript-eslint/no-explicit-any
let json: any;
let err: unknown;
const baseUrl = KaiTypeToBaseURL(kaiType);
// 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`, {
headers: {
Authorization: `Bearer ${token}`,
},
});
json = await res.json();
} catch (e) {
err = e;
}
return (game, playtype, userID, ratings, logger) => {
if (err) {
logger.error(`An error occured while updating classes for ${baseUrl}.`, { err });
return {};
}
let iidxDan: number | null;
if (playtype === "SP") {
iidxDan = json.sp;
} else if (playtype === "DP") {
iidxDan = json.dp;
} else {
logger.warn(`KAIIIDXClassUpdater called with invalid playtype of ${playtype}.`);
return {};
}
if (iidxDan === null) {
return {};
}
if (!Number.isInteger(iidxDan)) {
logger.warn(`${baseUrl} returned a dan of ${iidxDan}, which was not a number.`);
return {};
}
if (iidxDan > IIDXDans.KAIDEN) {
logger.warn(
`${baseUrl} returned a dan of ${iidxDan}, which was greater than KAIDEN (${IIDXDans.KAIDEN}.)`
);
return {};
}
if (iidxDan < IIDXDans.KYU_7) {
logger.warn(
`${baseUrl} returned a dan of ${iidxDan}, which was less than KYU_7 (${IIDXDans.KYU_7}.)`
);
return {};
}
return {
dan: iidxDan,
};
};
}
@@ -33,10 +33,9 @@ t.test("#ParseKaiIIDX", (t) => {
},
});
const res = ParseKaiIIDX("FLO", fakeAuth, logger, mockFloAPI);
const res = await ParseKaiIIDX("FLO", fakeAuth, logger, mockFloAPI);
t.equal(res.game, "iidx");
t.equal(res.classHandler, null);
t.strictSame(res.context, { service: "FLO" });
const iter = [];
@@ -66,10 +65,9 @@ t.test("#ParseKaiIIDX", (t) => {
},
});
const res = ParseKaiIIDX("EAG", fakeAuth, logger, mockEagAPI);
const res = await ParseKaiIIDX("EAG", fakeAuth, logger, mockEagAPI);
t.equal(res.game, "iidx");
t.equal(res.classHandler, null);
t.strictSame(res.context, { service: "EAG" });
const iter = [];
@@ -5,14 +5,16 @@ import { KaiContext } from "../types";
import { TraverseKaiAPI } from "../traverse-api";
import { ParserFunctionReturns } from "../../types";
import { ServerConfig } from "lib/setup/config";
import { KaiTypeToBaseURL } from "utils/misc";
import { CreateKaiIIDXClassHandler } from "./class-handler";
export function ParseKaiIIDX(
export async function ParseKaiIIDX(
service: "FLO" | "EAG",
authDoc: KaiAuthDocument,
logger: KtLogger,
fetch = nodeFetch
): ParserFunctionReturns<unknown, KaiContext> {
const baseUrl = service === "FLO" ? ServerConfig.FLO_API_URL : ServerConfig.EAG_API_URL;
): Promise<ParserFunctionReturns<unknown, KaiContext>> {
const baseUrl = KaiTypeToBaseURL(service);
return {
iterable: TraverseKaiAPI(
@@ -25,7 +27,7 @@ export function ParseKaiIIDX(
context: {
service,
},
classHandler: null,
classHandler: await CreateKaiIIDXClassHandler(service, authDoc.token, fetch),
game: "iidx",
};
}
@@ -0,0 +1,149 @@
import { SDVXDans } from "lib/constants/classes";
import CreateLogCtx from "lib/logger/logger";
import t from "tap";
import { CloseAllConnections } from "test-utils/close-connections";
import { MockBasicFetch, MockJSONFetch } from "test-utils/mock-fetch";
import ResetDBState from "test-utils/resets";
import { KaiTypeToBaseURL } from "utils/misc";
import { CreateKaiSDVXClassHandler } from "./class-handler";
const logger = CreateLogCtx(__filename);
t.test("#CreateKaiSDVXClassHandler", async (t) => {
t.beforeEach(ResetDBState);
const fn = await CreateKaiSDVXClassHandler(
"FLO",
"token",
MockJSONFetch({
[`${KaiTypeToBaseURL("FLO")}/api/sdvx/v1/player_profile`]: {
_links: {},
sdvx_id: 12345678,
name: "SOMEONE",
skill_level: 10,
access_time: "2019-08-26T18:22:36Z",
register_time: "2019-08-26T18:22:36Z",
},
})
);
t.test("Should return a function with arity 5.", (t) => {
t.equal(fn.length, 5);
t.end();
});
t.test("Should call the provided URL with the authentication token", (t) => {
const res = fn("sdvx", "Single", 1, {}, logger);
t.strictSame(res, { dan: 10 });
t.end();
});
t.test("Should return nothing if dan is not a number", async (t) => {
const fn = await CreateKaiSDVXClassHandler(
"FLO",
"token",
MockJSONFetch({
[`${KaiTypeToBaseURL("FLO")}/api/sdvx/v1/player_profile`]: {
_links: {},
sdvx_id: 12345678,
name: "SOMEONE",
skill_level: "NOT A NUMBER",
access_time: "2019-08-26T18:22:36Z",
register_time: "2019-08-26T18:22:36Z",
},
})
);
const res = fn("sdvx", "Single", 1, {}, logger);
t.strictSame(res, {});
t.end();
});
t.test("Should return nothing if dan is too great", async (t) => {
const fn = await CreateKaiSDVXClassHandler(
"FLO",
"token",
MockJSONFetch({
[`${KaiTypeToBaseURL("FLO")}/api/sdvx/v1/player_profile`]: {
_links: {},
sdvx_id: 12345678,
name: "SOMEONE",
skill_level: SDVXDans.INF + 1,
access_time: "2019-08-26T18:22:36Z",
register_time: "2019-08-26T18:22:36Z",
},
})
);
const res = fn("sdvx", "Single", 1, {}, logger);
t.strictSame(res, {});
t.end();
});
t.test("Should return nothing if dan is negative", async (t) => {
const fn = await CreateKaiSDVXClassHandler(
"FLO",
"token",
MockJSONFetch({
[`${KaiTypeToBaseURL("FLO")}/api/sdvx/v1/player_profile`]: {
_links: {},
sdvx_id: 12345678,
name: "SOMEONE",
skill_level: -1,
access_time: "2019-08-26T18:22:36Z",
register_time: "2019-08-26T18:22:36Z",
},
})
);
const res = fn("sdvx", "Single", 1, {}, logger);
t.strictSame(res, {});
t.end();
});
t.test("Should gracefully handle negative API responses", async (t) => {
const fn = await CreateKaiSDVXClassHandler("FLO", "token", MockBasicFetch({ status: 500 }));
const res = fn("sdvx", "Single", 1, {}, logger);
t.strictSame(res, {});
t.end();
});
t.test("Should ignore null dans", async (t) => {
const fn = await CreateKaiSDVXClassHandler(
"FLO",
"token",
MockJSONFetch({
[`${KaiTypeToBaseURL("FLO")}/api/sdvx/v1/player_profile`]: {
_links: {},
sdvx_id: 12345678,
name: "SOMEONE",
skill_level: null,
access_time: "2019-08-26T18:22:36Z",
register_time: "2019-08-26T18:22:36Z",
},
})
);
const res = fn("sdvx", "Single", 1, {}, logger);
t.strictSame(res, {});
t.end();
});
t.end();
});
t.teardown(CloseAllConnections);
@@ -0,0 +1,65 @@
import { SDVXDans } from "lib/constants/classes";
import { ClassHandler } from "lib/score-import/framework/user-game-stats/types";
import nodeFetch from "utils/fetch";
import { KaiTypeToBaseURL } from "utils/misc";
export async function CreateKaiSDVXClassHandler(
kaiType: "FLO" | "EAG" | "MIN",
token: string,
fetch = nodeFetch
): Promise<ClassHandler> {
// eslint-disable-next-line @typescript-eslint/no-explicit-any
let json: any;
let err: unknown;
const baseUrl = KaiTypeToBaseURL(kaiType);
// 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/sdvx/v1/player_profile`, {
headers: {
Authorization: `Bearer ${token}`,
},
});
json = await res.json();
} catch (e) {
err = e;
}
return (game, playtype, userID, ratings, logger) => {
if (err) {
logger.error(`An error occured while updating classes for ${baseUrl}.`, { err });
return {};
}
const sdvxDan: number | null = json.skill_level;
if (sdvxDan === null) {
return {};
}
if (!Number.isInteger(sdvxDan)) {
logger.warn(`${baseUrl} returned a dan of ${sdvxDan}, which was not a number.`);
return {};
}
if (sdvxDan > SDVXDans.INF) {
logger.warn(
`${baseUrl} returned a dan of ${sdvxDan}, which was greater than INF (${SDVXDans.INF}.)`
);
return {};
}
if (sdvxDan < SDVXDans.DAN_1) {
logger.warn(
`${baseUrl} returned a dan of ${sdvxDan}, which was less than DAN_1 (${SDVXDans.DAN_1}.)`
);
return {};
}
return {
dan: sdvxDan,
};
};
}
@@ -33,10 +33,9 @@ t.test("#ParseKaiSDVX", (t) => {
},
});
const res = ParseKaiSDVX("FLO", fakeAuth, logger, mockFloAPI);
const res = await ParseKaiSDVX("FLO", fakeAuth, logger, mockFloAPI);
t.equal(res.game, "sdvx");
t.equal(res.classHandler, null);
t.strictSame(res.context, { service: "FLO" });
const iter = [];
@@ -66,10 +65,9 @@ t.test("#ParseKaiSDVX", (t) => {
},
});
const res = ParseKaiSDVX("EAG", fakeAuth, logger, mockEagAPI);
const res = await ParseKaiSDVX("EAG", fakeAuth, logger, mockEagAPI);
t.equal(res.game, "sdvx");
t.equal(res.classHandler, null);
t.strictSame(res.context, { service: "EAG" });
const iter = [];
@@ -5,14 +5,16 @@ import { KaiContext } from "../types";
import { TraverseKaiAPI } from "../traverse-api";
import { ParserFunctionReturns } from "../../types";
import { ServerConfig } from "lib/setup/config";
import { KaiTypeToBaseURL } from "utils/misc";
import { CreateKaiSDVXClassHandler } from "./class-handler";
export function ParseKaiSDVX(
service: "FLO" | "EAG",
export async function ParseKaiSDVX(
service: "FLO" | "EAG" | "MIN",
authDoc: KaiAuthDocument,
logger: KtLogger,
fetch = nodeFetch
): ParserFunctionReturns<unknown, KaiContext> {
const baseUrl = service === "FLO" ? ServerConfig.FLO_API_URL : ServerConfig.EAG_API_URL;
): Promise<ParserFunctionReturns<unknown, KaiContext>> {
const baseUrl = KaiTypeToBaseURL(service);
return {
iterable: TraverseKaiAPI(
@@ -25,7 +27,7 @@ export function ParseKaiSDVX(
context: {
service,
},
classHandler: null,
classHandler: await CreateKaiSDVXClassHandler(service, authDoc.token, fetch),
game: "sdvx",
};
}
@@ -31,5 +31,5 @@ export interface KaiSDVXScore {
}
export interface KaiContext {
service: "FLO" | "EAG";
service: "FLO" | "EAG" | "MIN";
}
@@ -44,6 +44,7 @@ export interface ImportTypeDataMap {
"api/arc-ddr": unknown;
"api/flo-iidx": unknown;
"api/flo-sdvx": unknown;
"api/min-sdvx": unknown;
"api/eag-iidx": unknown;
"api/eag-sdvx": unknown;
}
@@ -68,6 +69,7 @@ export interface ImportTypeContextMap {
"api/arc-ddr": EmptyObject;
"api/flo-iidx": KaiContext;
"api/flo-sdvx": KaiContext;
"api/min-sdvx": KaiContext;
"api/eag-iidx": KaiContext;
"api/eag-sdvx": KaiContext;
}
@@ -30,6 +30,7 @@ export const Converters: ConverterMap = {
"api/eag-sdvx": ConvertAPIKaiSDVX,
"api/flo-iidx": ConvertAPIKaiIIDX,
"api/flo-sdvx": ConvertAPIKaiSDVX,
"api/min-sdvx": ConvertAPIKaiSDVX,
"api/arc-iidx": ConvertAPIArcIIDX,
"api/arc-ddr": ConvertAPIArcDDR,
"api/arc-sdvx": ConvertAPIArcSDVX,
+2
View File
@@ -45,6 +45,7 @@ export interface TachiConfig {
SESSION_SECRET: string;
FLO_API_URL: string;
EAG_API_URL: string;
MIN_API_URL: string;
ARC_API_URL: string;
ARC_AUTH_TOKEN: string;
CDN_FILE_ROOT: string;
@@ -64,6 +65,7 @@ const err = p(config, {
SESSION_SECRET: "string",
FLO_API_URL: isValidURL,
EAG_API_URL: isValidURL,
MIN_API_URL: isValidURL,
ARC_API_URL: isValidURL,
ARC_AUTH_TOKEN: "string",
CDN_FILE_ROOT: "string",
+5 -1
View File
@@ -22,6 +22,10 @@ export function MockJSONFetch(urlDataMap: Record<string, unknown>) {
};
}
throw new Error(`Unexpected url ${url} - No Data Present?`);
throw new Error(
`Unexpected url ${url} - No Data Present? Valid urls are ${Object.keys(urlDataMap).join(
", "
)}`
);
}) as NodeFetch;
}
+13 -1
View File
@@ -1,5 +1,5 @@
import crypto from "crypto";
import { ServerTypeInfo } from "lib/setup/config";
import { ServerConfig, ServerTypeInfo } from "lib/setup/config";
import { Game, Playtypes, GetGameConfig, AnySongDocument, AnyChartDocument } from "tachi-common";
// https://github.com/sindresorhus/escape-string-regexp/blob/main/index.js
@@ -76,3 +76,15 @@ export function IsString(val: unknown): val is string {
export function DedupeArr<T>(arr: T[]): T[] {
return [...new Set(arr)];
}
export function KaiTypeToBaseURL(kaiType: "FLO" | "EAG" | "MIN") {
if (kaiType === "FLO") {
return ServerConfig.FLO_API_URL;
} else if (kaiType === "EAG") {
return ServerConfig.EAG_API_URL;
} else if (kaiType === "MIN") {
return ServerConfig.MIN_API_URL;
}
throw new Error(`Invalid Kai Type ${kaiType} provided.`);
}