Merge pull request #260 from zkldi/zkldi/issue-259-Remove-ability-for-server-to-serve-indexhtml

zkldi/issue-259-Remove-ability-for-server-to-serve-indexhtml
This commit is contained in:
zkldi
2021-08-10 22:37:31 +01:00
committed by GitHub
85 changed files with 1455 additions and 1419 deletions
+1 -2
View File
@@ -12,8 +12,7 @@
ARC_AUTH_TOKEN: "unused",
CDN_FILE_ROOT: "./local-cdn",
PORT: 8080,
TYPE: "omni", // It really doesn't matter whether we're in bokutachi or kamaitachi mode. If we had the performance we could run these in parallel?
CLIENT_INDEX_HTML_PATH: "./src/test-utils/mock-index.html",
TYPE: "omni",
ENABLE_SERVER_HTTPS: false,
RUN_OWN_CDN: true
}
+4 -4
View File
@@ -84,7 +84,7 @@ dependencies:
redis: 3.1.2
rimraf: 3.0.2
safe-json-stringify: 1.2.0
tachi-common: github.com/zkldi/tachi-common/42a4da4ced2934d73b862f31a38814a0cc0a16f0_ts-node@10.0.0+typescript@4.3.4
tachi-common: github.com/zkldi/tachi-common/960879126ca93099d412866ca0f3a8327979034f_ts-node@10.0.0+typescript@4.3.4
typescript: 4.3.4
winston: 3.3.3
@@ -4226,9 +4226,9 @@ packages:
engines: {node: '>=6'}
dev: true
github.com/zkldi/tachi-common/42a4da4ced2934d73b862f31a38814a0cc0a16f0_ts-node@10.0.0+typescript@4.3.4:
resolution: {tarball: https://codeload.github.com/zkldi/tachi-common/tar.gz/42a4da4ced2934d73b862f31a38814a0cc0a16f0}
id: github.com/zkldi/tachi-common/42a4da4ced2934d73b862f31a38814a0cc0a16f0
github.com/zkldi/tachi-common/960879126ca93099d412866ca0f3a8327979034f_ts-node@10.0.0+typescript@4.3.4:
resolution: {tarball: https://codeload.github.com/zkldi/tachi-common/tar.gz/960879126ca93099d412866ca0f3a8327979034f}
id: github.com/zkldi/tachi-common/960879126ca93099d412866ca0f3a8327979034f
name: tachi-common
version: 0.1.0
dependencies:
@@ -4,7 +4,7 @@ import path from "path";
import db from "../../../src/external/mongo/db";
(async () => {
const data = JSON.parse(fs.readFileSync(path.join(__dirname, "courses.json"), "utf-8"));
const data = JSON.parse(fs.readFileSync(path.join(__dirname, "courses.json"), "utf-8"));
await db["bms-course-lookup"].insert(data);
await db["bms-course-lookup"].insert(data);
})();
@@ -8,13 +8,13 @@ const charts = JSON.parse(fs.readFileSync(path.join(__dirname, "./charts.json"),
const songs = JSON.parse(fs.readFileSync(path.join(__dirname, "./songs.json"), "utf-8"));
(async () => {
logger.info("starting chart import.");
await db.charts.bms.remove({});
await db.charts.bms.insert(charts);
logger.info("imported charts.");
logger.info("starting chart import.");
await db.charts.bms.remove({});
await db.charts.bms.insert(charts);
logger.info("imported charts.");
await db.songs.bms.remove({});
await db.songs.bms.insert(songs);
await db.songs.bms.remove({});
await db.songs.bms.insert(songs);
logger.info("done.");
logger.info("done.");
})();
+66 -66
View File
@@ -18,83 +18,83 @@ program.parse(process.argv);
const options = program.opts();
const dataset = JSON.parse(
fs.readFileSync(path.join(__dirname, "./out.json"), "utf-8")
fs.readFileSync(path.join(__dirname, "./out.json"), "utf-8")
) as MDBJson[];
const logger = CreateLogCtx(__filename);
(async () => {
for (const data of dataset) {
for (const d in data.difficulties) {
const diff = d as keyof typeof data.difficulties;
for (const data of dataset) {
for (const d in data.difficulties) {
const diff = d as keyof typeof data.difficulties;
if (data.difficulties[diff] === 0) {
logger.verbose(`Skipping chart ${data.title} ${diff}`);
continue;
}
if (data.difficulties[diff] === 0) {
logger.verbose(`Skipping chart ${data.title} ${diff}`);
continue;
}
const spl = diff.split("-");
const chart = (await db.charts.iidx.findOne({
"data.inGameID": data.songID,
playtype: spl[0] as Playtypes["iidx"],
difficulty: spl[1] as Difficulties["iidx:SP" | "iidx:DP"],
isPrimary: true,
})) as ChartDocument<"iidx:SP" | "iidx:DP">;
const spl = diff.split("-");
const chart = (await db.charts.iidx.findOne({
"data.inGameID": data.songID,
playtype: spl[0] as Playtypes["iidx"],
difficulty: spl[1] as Difficulties["iidx:SP" | "iidx:DP"],
isPrimary: true,
})) as ChartDocument<"iidx:SP" | "iidx:DP">;
if (!chart) {
logger.warn(`No chart exists for ${data.title} (${diff}).`);
continue;
}
if (!chart) {
logger.warn(`No chart exists for ${data.title} (${diff}).`);
continue;
}
if (chart.levelNum !== data.difficulties[diff]) {
logger.warn(
`Level Mismatch with ${data.title} (${diff}) [${chart.levelNum} -> ${data.difficulties[diff]}]`
);
if (chart.levelNum !== data.difficulties[diff]) {
logger.warn(
`Level Mismatch with ${data.title} (${diff}) [${chart.levelNum} -> ${data.difficulties[diff]}]`
);
if (options.sync) {
await db.charts.iidx.update(
{
_id: chart._id,
},
{
$set: {
levelNum: data.difficulties[diff],
level: data.difficulties[diff].toString(),
},
}
);
}
}
if (options.sync) {
await db.charts.iidx.update(
{
_id: chart._id,
},
{
$set: {
levelNum: data.difficulties[diff],
level: data.difficulties[diff].toString(),
},
}
);
}
}
if (chart.data.notecount !== data.notecounts[diff]) {
if (
data.notecounts[diff] === undefined ||
Math.abs(chart.data.notecount - data.notecounts[diff]!) > 2
) {
logger.error(
`Significant Notecount Mismatch with ${data.title} (${diff}) [${chart.data.notecount} -> ${data.notecounts[diff]}] - skipping.`
);
// continue;
}
if (chart.data.notecount !== data.notecounts[diff]) {
if (
data.notecounts[diff] === undefined ||
Math.abs(chart.data.notecount - data.notecounts[diff]!) > 2
) {
logger.error(
`Significant Notecount Mismatch with ${data.title} (${diff}) [${chart.data.notecount} -> ${data.notecounts[diff]}] - skipping.`
);
// continue;
}
logger.warn(
`Notecount Mismatch with ${data.title} (${diff}) [${chart.data.notecount} -> ${data.notecounts[diff]}]`
);
logger.warn(
`Notecount Mismatch with ${data.title} (${diff}) [${chart.data.notecount} -> ${data.notecounts[diff]}]`
);
if (options.sync) {
await db.charts.iidx.update(
{
_id: chart._id,
},
{
$set: {
"data.notecount": data.notecounts[diff],
},
}
);
}
}
}
}
logger.info("done");
if (options.sync) {
await db.charts.iidx.update(
{
_id: chart._id,
},
{
$set: {
"data.notecount": data.notecounts[diff],
},
}
);
}
}
}
}
logger.info("done");
})();
+8 -8
View File
@@ -1,12 +1,12 @@
export interface MDBJson {
title: string;
artist: string;
marquee: string;
folder: number;
genre: string;
difficulties: Record<DiffNames, number>;
notecounts: Partial<Record<DiffNames, number>>;
songID: number;
title: string;
artist: string;
marquee: string;
folder: number;
genre: string;
difficulties: Record<DiffNames, number>;
notecounts: Partial<Record<DiffNames, number>>;
songID: number;
}
type DiffNames = `${"SP" | "DP"}-${"BEGINNER" | "NORMAL" | "HYPER" | "ANOTHER" | "LEGGENDARIA"}`;
+15 -15
View File
@@ -7,25 +7,25 @@ const charts = JSON.parse(fs.readFileSync(path.join(__dirname, "charts.json"), "
const map: Map<string, any> = new Map();
for (const chart of charts) {
const id = `${chart.songID}-${chart.difficulty}`;
const doc = map.get(id);
const id = `${chart.songID}-${chart.difficulty}`;
const doc = map.get(id);
if (doc) {
if (Array.isArray(doc.data.hashSHA1)) {
doc.data.hashSHA1.push(chart.data.hashSHA1);
} else {
doc.data.hashSHA1 = [doc.data.hashSHA1, chart.data.hashSHA1];
}
if (doc) {
if (Array.isArray(doc.data.hashSHA1)) {
doc.data.hashSHA1.push(chart.data.hashSHA1);
} else {
doc.data.hashSHA1 = [doc.data.hashSHA1, chart.data.hashSHA1];
}
// insane hack
chart.erasethis = true;
} else {
map.set(id, chart);
}
// insane hack
chart.erasethis = true;
} else {
map.set(id, chart);
}
}
// works because byref
fs.writeFileSync(
path.join(__dirname, "deduped-charts.json"),
JSON.stringify(charts.filter((e: any) => e.erasethis !== true))
path.join(__dirname, "deduped-charts.json"),
JSON.stringify(charts.filter((e: any) => e.erasethis !== true))
);
+4 -4
View File
@@ -6,8 +6,8 @@ const songs = JSON.parse(fs.readFileSync(path.join(__dirname, "songs.json"), "ut
const charts = JSON.parse(fs.readFileSync(path.join(__dirname, "deduped-charts.json"), "utf-8"));
(async () => {
await db.songs.usc.remove({});
await db.charts.usc.remove({});
await db.songs.usc.insert(songs);
await db.charts.usc.insert(charts);
await db.songs.usc.remove({});
await db.charts.usc.remove({});
await db.songs.usc.insert(songs);
await db.charts.usc.insert(charts);
})();
@@ -9,48 +9,48 @@ import { gameOrders } from "tachi-common/js/config";
const logger = CreateLogCtx(__filename);
async function ConvertFn(c: any): Promise<ChartDocument<"chunithm:Single">> {
const song = await db.songs.chunithm.findOne({
id: c.id,
});
const song = await db.songs.chunithm.findOne({
id: c.id,
});
if (!song) {
logger.severe(`Cannot find song with ID ${c.id}?`);
throw new Error(`Cannot find song with ID ${c.id}?`);
}
if (!song) {
logger.severe(`Cannot find song with ID ${c.id}?`);
throw new Error(`Cannot find song with ID ${c.id}?`);
}
const newChartDoc: ChartDocument<"chunithm:Single"> = {
rgcID: null,
chartID: c.chartID,
difficulty: c.difficulty,
songID: c.id,
playtype: c.playtype,
levelNum: c.levelNum,
level: c.level.toString(),
flags: {
"IN BASE GAME": !!c.flags["IN BASE GAME"],
OMNIMIX: !!c.flags.OMNIMIX,
},
data: {
inGameID: c.internals.inGameID,
},
isPrimary: true,
versions: [], // sentinel
};
const newChartDoc: ChartDocument<"chunithm:Single"> = {
rgcID: null,
chartID: c.chartID,
difficulty: c.difficulty,
songID: c.id,
playtype: c.playtype,
levelNum: c.levelNum,
level: c.level.toString(),
flags: {
"IN BASE GAME": !!c.flags["IN BASE GAME"],
OMNIMIX: !!c.flags.OMNIMIX,
},
data: {
inGameID: c.internals.inGameID,
},
isPrimary: true,
versions: [], // sentinel
};
const idx = gameOrders.chunithm.indexOf(song.firstVersion!);
const idx = gameOrders.chunithm.indexOf(song.firstVersion!);
if (idx === -1) {
logger.warn(`Invalid firstAppearance of ${song.firstVersion!}, running anyway.`);
newChartDoc.versions = [song.firstVersion!];
} else {
newChartDoc.versions = gameOrders.chunithm.slice(idx);
}
if (idx === -1) {
logger.warn(`Invalid firstAppearance of ${song.firstVersion!}, running anyway.`);
newChartDoc.versions = [song.firstVersion!];
} else {
newChartDoc.versions = gameOrders.chunithm.slice(idx);
}
return newChartDoc;
return newChartDoc;
}
(async () => {
await MigrateRecords(db.charts.chunithm, "charts-chunithm", ConvertFn);
await MigrateRecords(db.charts.chunithm, "charts-chunithm", ConvertFn);
process.exit(0);
process.exit(0);
})();
@@ -10,53 +10,53 @@ import { oldKTDB } from "./old-db";
const logger = CreateLogCtx(__filename);
async function ConvertFn(c: any): Promise<ChartDocument<"ddr:SP" | "ddr:DP">> {
const song = (await db.songs.ddr.findOne({
id: c.id,
})) as SongDocument<"ddr">;
const song = (await db.songs.ddr.findOne({
id: c.id,
})) as SongDocument<"ddr">;
const oldSong = await oldKTDB.get("songs-ddr").findOne({
id: c.id,
});
const oldSong = await oldKTDB.get("songs-ddr").findOne({
id: c.id,
});
if (!song) {
logger.severe(`Cannot find song with ID ${c.id}?`);
throw new Error(`Cannot find song with ID ${c.id}?`);
}
if (!song) {
logger.severe(`Cannot find song with ID ${c.id}?`);
throw new Error(`Cannot find song with ID ${c.id}?`);
}
const newChartDoc: ChartDocument<"ddr:SP" | "ddr:DP"> = {
rgcID: null,
chartID: c.chartID,
difficulty: c.difficulty,
songID: c.id,
playtype: c.playtype,
levelNum: c.levelNum,
level: c.level.toString(),
flags: {
"IN BASE GAME": true,
"N-1": true,
},
data: {
inGameID: c.internals.inGameID,
songHash: oldSong.internals.songHash,
},
isPrimary: true,
versions: [], // sentinel
};
const newChartDoc: ChartDocument<"ddr:SP" | "ddr:DP"> = {
rgcID: null,
chartID: c.chartID,
difficulty: c.difficulty,
songID: c.id,
playtype: c.playtype,
levelNum: c.levelNum,
level: c.level.toString(),
flags: {
"IN BASE GAME": true,
"N-1": true,
},
data: {
inGameID: c.internals.inGameID,
songHash: oldSong.internals.songHash,
},
isPrimary: true,
versions: [], // sentinel
};
const idx = gameOrders.ddr.indexOf(song.firstVersion!);
const idx = gameOrders.ddr.indexOf(song.firstVersion!);
if (idx === -1) {
logger.warn(`Invalid firstAppearance of ${song.firstVersion!}, running anyway.`);
newChartDoc.versions = [song.firstVersion!];
} else {
newChartDoc.versions = gameOrders.ddr.slice(idx);
}
if (idx === -1) {
logger.warn(`Invalid firstAppearance of ${song.firstVersion!}, running anyway.`);
newChartDoc.versions = [song.firstVersion!];
} else {
newChartDoc.versions = gameOrders.ddr.slice(idx);
}
return newChartDoc;
return newChartDoc;
}
(async () => {
await MigrateRecords(db.charts.ddr, "charts-ddr", ConvertFn);
await MigrateRecords(db.charts.ddr, "charts-ddr", ConvertFn);
process.exit(0);
process.exit(0);
})();
@@ -9,52 +9,52 @@ import { oldKTDB } from "./old-db";
const logger = CreateLogCtx(__filename);
async function ConvertFn(c: any): Promise<ChartDocument<"gitadora:Gita" | "gitadora:Dora">> {
const song = (await db.songs.gitadora.findOne({
id: c.id,
})) as SongDocument<"gitadora">;
const song = (await db.songs.gitadora.findOne({
id: c.id,
})) as SongDocument<"gitadora">;
const oldSong = await oldKTDB.get("songs-gitadora").findOne({
id: c.id,
});
const oldSong = await oldKTDB.get("songs-gitadora").findOne({
id: c.id,
});
if (!song) {
logger.severe(`Cannot find song with ID ${c.id}?`);
throw new Error(`Cannot find song with ID ${c.id}?`);
}
if (!song) {
logger.severe(`Cannot find song with ID ${c.id}?`);
throw new Error(`Cannot find song with ID ${c.id}?`);
}
const newChartDoc: ChartDocument<"gitadora:Gita" | "gitadora:Dora"> = {
rgcID: null,
chartID: c.chartID,
difficulty: c.difficulty,
songID: c.id,
playtype: c.playtype,
levelNum: c.levelNum,
level: c.level.toString(),
flags: {
"IN BASE GAME": true,
OMNIMIX: true,
},
data: {
inGameID: c.internals.inGameINTID,
},
isPrimary: true,
versions: [], // sentinel
};
const newChartDoc: ChartDocument<"gitadora:Gita" | "gitadora:Dora"> = {
rgcID: null,
chartID: c.chartID,
difficulty: c.difficulty,
songID: c.id,
playtype: c.playtype,
levelNum: c.levelNum,
level: c.level.toString(),
flags: {
"IN BASE GAME": true,
OMNIMIX: true,
},
data: {
inGameID: c.internals.inGameINTID,
},
isPrimary: true,
versions: [], // sentinel
};
const idx = gameOrders.gitadora.indexOf(song.firstVersion!);
const idx = gameOrders.gitadora.indexOf(song.firstVersion!);
if (idx === -1) {
logger.warn(`Invalid firstAppearance of ${song.firstVersion!}, running anyway.`);
newChartDoc.versions = [song.firstVersion!];
} else {
newChartDoc.versions = gameOrders.gitadora.slice(idx);
}
if (idx === -1) {
logger.warn(`Invalid firstAppearance of ${song.firstVersion!}, running anyway.`);
newChartDoc.versions = [song.firstVersion!];
} else {
newChartDoc.versions = gameOrders.gitadora.slice(idx);
}
return newChartDoc;
return newChartDoc;
}
(async () => {
await MigrateRecords(db.charts.gitadora, "charts-gitadora", ConvertFn);
await MigrateRecords(db.charts.gitadora, "charts-gitadora", ConvertFn);
process.exit(0);
process.exit(0);
})();
@@ -9,51 +9,51 @@ import { gameOrders } from "tachi-common/js/config";
const logger = CreateLogCtx(__filename);
async function ConvertFn(c: any): Promise<ChartDocument<"iidx:SP" | "iidx:DP">> {
const song = await db.songs.iidx.findOne({
id: c.id,
});
const song = await db.songs.iidx.findOne({
id: c.id,
});
if (!song) {
logger.severe(`Cannot find song with ID ${c.id}?`);
throw new Error(`Cannot find song with ID ${c.id}?`);
}
if (!song) {
logger.severe(`Cannot find song with ID ${c.id}?`);
throw new Error(`Cannot find song with ID ${c.id}?`);
}
const newChartDoc: ChartDocument<"iidx:SP" | "iidx:DP"> = {
rgcID: null,
chartID: c.chartID,
difficulty: c.difficulty,
songID: c.id,
playtype: c.playtype,
levelNum: c.levelNum,
level: c.level.toString(),
flags: {
"IN BASE GAME": !!c.flags["IN BASE GAME"],
OMNIMIX: !!c.flags.OMNIMIX,
"N-1": !!c.flags["N-1"],
},
data: {
inGameID: c.internals.inGameINTID,
notecount: c.notedata.notecount,
arcChartID: null,
},
isPrimary: true,
versions: [], // sentinel
};
const newChartDoc: ChartDocument<"iidx:SP" | "iidx:DP"> = {
rgcID: null,
chartID: c.chartID,
difficulty: c.difficulty,
songID: c.id,
playtype: c.playtype,
levelNum: c.levelNum,
level: c.level.toString(),
flags: {
"IN BASE GAME": !!c.flags["IN BASE GAME"],
OMNIMIX: !!c.flags.OMNIMIX,
"N-1": !!c.flags["N-1"],
},
data: {
inGameID: c.internals.inGameINTID,
notecount: c.notedata.notecount,
arcChartID: null,
},
isPrimary: true,
versions: [], // sentinel
};
const idx = gameOrders.iidx.indexOf(song.firstVersion!);
const idx = gameOrders.iidx.indexOf(song.firstVersion!);
if (idx === -1) {
logger.warn(`Invalid firstAppearance of ${song.firstVersion!}, running anyway.`);
newChartDoc.versions = [song.firstVersion!];
} else {
newChartDoc.versions = gameOrders.iidx.slice(idx);
}
if (idx === -1) {
logger.warn(`Invalid firstAppearance of ${song.firstVersion!}, running anyway.`);
newChartDoc.versions = [song.firstVersion!];
} else {
newChartDoc.versions = gameOrders.iidx.slice(idx);
}
return newChartDoc;
return newChartDoc;
}
(async () => {
await MigrateRecords(db.charts.iidx, "charts-iidx", ConvertFn);
await MigrateRecords(db.charts.iidx, "charts-iidx", ConvertFn);
process.exit(0);
process.exit(0);
})();
@@ -8,46 +8,46 @@ import { gameOrders } from "tachi-common/js/config";
const logger = CreateLogCtx(__filename);
async function ConvertFn(c: any): Promise<ChartDocument<"museca:Single">> {
const song = await db.songs.museca.findOne({
id: c.id,
});
const song = await db.songs.museca.findOne({
id: c.id,
});
if (!song) {
logger.severe(`Cannot find song with ID ${c.id}?`);
throw new Error(`Cannot find song with ID ${c.id}?`);
}
if (!song) {
logger.severe(`Cannot find song with ID ${c.id}?`);
throw new Error(`Cannot find song with ID ${c.id}?`);
}
const newChartDoc: ChartDocument<"museca:Single"> = {
rgcID: null,
chartID: c.chartID,
difficulty: c.difficulty,
songID: c.id,
playtype: c.playtype,
levelNum: c.levelNum,
level: c.level.toString(),
flags: {
"IN BASE GAME": true,
OMNIMIX: true, // false, needs to be overrode for 3 or so charts
},
data: {},
isPrimary: true,
versions: [], // sentinel
};
const newChartDoc: ChartDocument<"museca:Single"> = {
rgcID: null,
chartID: c.chartID,
difficulty: c.difficulty,
songID: c.id,
playtype: c.playtype,
levelNum: c.levelNum,
level: c.level.toString(),
flags: {
"IN BASE GAME": true,
OMNIMIX: true, // false, needs to be overrode for 3 or so charts
},
data: {},
isPrimary: true,
versions: [], // sentinel
};
const idx = gameOrders.museca.indexOf(song.firstVersion!);
const idx = gameOrders.museca.indexOf(song.firstVersion!);
if (idx === -1) {
logger.warn(`Invalid firstAppearance of ${song.firstVersion!}, running anyway.`);
newChartDoc.versions = [song.firstVersion!];
} else {
newChartDoc.versions = gameOrders.museca.slice(idx);
}
if (idx === -1) {
logger.warn(`Invalid firstAppearance of ${song.firstVersion!}, running anyway.`);
newChartDoc.versions = [song.firstVersion!];
} else {
newChartDoc.versions = gameOrders.museca.slice(idx);
}
return newChartDoc;
return newChartDoc;
}
(async () => {
await MigrateRecords(db.charts.museca, "charts-museca", ConvertFn);
await MigrateRecords(db.charts.museca, "charts-museca", ConvertFn);
process.exit(0);
process.exit(0);
})();
@@ -8,49 +8,49 @@ import { gameOrders } from "tachi-common/js/config";
const logger = CreateLogCtx(__filename);
async function ConvertFn(c: any): Promise<ChartDocument<"sdvx:Single">> {
const song = await db.songs.sdvx.findOne({
id: c.id,
});
const song = await db.songs.sdvx.findOne({
id: c.id,
});
if (!song) {
logger.severe(`Cannot find song with ID ${c.id}?`);
throw new Error(`Cannot find song with ID ${c.id}?`);
}
if (!song) {
logger.severe(`Cannot find song with ID ${c.id}?`);
throw new Error(`Cannot find song with ID ${c.id}?`);
}
const newChartDoc: ChartDocument<"sdvx:Single"> = {
rgcID: null,
chartID: c.chartID,
difficulty: c.difficulty,
songID: c.id,
playtype: c.playtype,
levelNum: c.levelNum,
level: c.level.toString(),
flags: {
"IN BASE GAME": !!c.flags["IN BASE GAME"],
OMNIMIX: !!c.flags.OMNIMIX,
"N-1": !!c.flags["N-1"],
},
data: {
inGameID: c.internals.inGameINTID,
},
isPrimary: true,
versions: [], // sentinel
};
const newChartDoc: ChartDocument<"sdvx:Single"> = {
rgcID: null,
chartID: c.chartID,
difficulty: c.difficulty,
songID: c.id,
playtype: c.playtype,
levelNum: c.levelNum,
level: c.level.toString(),
flags: {
"IN BASE GAME": !!c.flags["IN BASE GAME"],
OMNIMIX: !!c.flags.OMNIMIX,
"N-1": !!c.flags["N-1"],
},
data: {
inGameID: c.internals.inGameINTID,
},
isPrimary: true,
versions: [], // sentinel
};
const idx = gameOrders.sdvx.indexOf(song.firstVersion!);
const idx = gameOrders.sdvx.indexOf(song.firstVersion!);
if (idx === -1) {
logger.warn(`Invalid firstAppearance of ${song.firstVersion!}, running anyway.`);
newChartDoc.versions = [song.firstVersion!];
} else {
newChartDoc.versions = gameOrders.sdvx.slice(idx);
}
if (idx === -1) {
logger.warn(`Invalid firstAppearance of ${song.firstVersion!}, running anyway.`);
newChartDoc.versions = [song.firstVersion!];
} else {
newChartDoc.versions = gameOrders.sdvx.slice(idx);
}
return newChartDoc;
return newChartDoc;
}
(async () => {
await MigrateRecords(db.charts.sdvx, "charts-sdvx", ConvertFn);
await MigrateRecords(db.charts.sdvx, "charts-sdvx", ConvertFn);
process.exit(0);
process.exit(0);
})();
@@ -10,39 +10,39 @@ import crypto from "crypto";
const logger = CreateLogCtx(__filename);
function ConvertFn(c: any): FolderDocument[] {
throw new Error("This doesn't work, It was migrated elsewhere.");
throw new Error("This doesn't work, It was migrated elsewhere.");
// let docs = [];
// let docs = [];
// for (const playtype of validPlaytypes[c.game as Game]) {
// const fd: FolderDocument = {
// title: c.title,
// game: c.game,
// playtype,
// type: "query" as const,
// query: {
// collection: c.query.collection,
// body: c.query.query,
// },
// folderID: crypto.randomBytes(20).toString("hex"),
// table: c.table,
// tableIndex: 0, // ???
// };
// for (const playtype of validPlaytypes[c.game as Game]) {
// const fd: FolderDocument = {
// title: c.title,
// game: c.game,
// playtype,
// type: "query" as const,
// query: {
// collection: c.query.collection,
// body: c.query.query,
// },
// folderID: crypto.randomBytes(20).toString("hex"),
// table: c.table,
// tableIndex: 0, // ???
// };
// let gh = gameHuman[c.game as Game];
// let gh = gameHuman[c.game as Game];
// fd.title = fd.title.replace(new RegExp(`${gh} +`, "giu"), "");
// fd.title = fd.title.replace(new RegExp(`${gh} +`, "giu"), "");
// logger.info(`Porting folder ${fd.title} (${playtype})`);
// logger.info(`Porting folder ${fd.title} (${playtype})`);
// docs.push(fd);
// }
// docs.push(fd);
// }
// return docs;
// return docs;
}
(async () => {
await MigrateRecords(db.folders, "folders", ConvertFn);
await MigrateRecords(db.folders, "folders", ConvertFn);
process.exit(0);
process.exit(0);
})();
+54 -54
View File
@@ -9,71 +9,71 @@ import MigrateRecords from "./migrate";
const logger = CreateLogCtx(__filename);
function ConvertFn(c: any): GoalDocument | null {
let charts: GoalDocument["charts"];
let charts: GoalDocument["charts"];
if (c.directChartID) {
charts = {
type: "single",
data: c.directChartID,
};
} else if (c.directChartIDs) {
charts = {
type: "multi",
data: c.directChartIDs,
};
} else if (c.chartQuery) {
logger.warn(`Skipped goal ${c.title}, as it used cQuery.`);
return null;
} else {
logger.warn(`Any Goal ${c.goalID}, ${c.title}. Skipping.`);
return null;
}
if (c.directChartID) {
charts = {
type: "single",
data: c.directChartID,
};
} else if (c.directChartIDs) {
charts = {
type: "multi",
data: c.directChartIDs,
};
} else if (c.chartQuery) {
logger.warn(`Skipped goal ${c.title}, as it used cQuery.`);
return null;
} else {
logger.warn(`Any Goal ${c.goalID}, ${c.title}. Skipping.`);
return null;
}
const partialCriteria: Partial<GoalDocument["criteria"]> = {
mode: "single",
};
const partialCriteria: Partial<GoalDocument["criteria"]> = {
mode: "single",
};
if (c.scoreQuery["scoreData¬lampIndex"]) {
partialCriteria.key = "scoreData.lampIndex";
} else if (c.scoreQuery["scoreData¬gradeIndex"]) {
partialCriteria.key = "scoreData.gradeIndex";
} else if (c.scoreQuery["scoreData¬score"]) {
partialCriteria.key = "scoreData.score";
} else if (c.scoreQuery["scoreData¬percent"]) {
partialCriteria.key = "scoreData.percent";
} else {
throw new Error(`Invalid goal ${c.goalID} ${c.title}.`);
}
if (c.scoreQuery["scoreData¬lampIndex"]) {
partialCriteria.key = "scoreData.lampIndex";
} else if (c.scoreQuery["scoreData¬gradeIndex"]) {
partialCriteria.key = "scoreData.gradeIndex";
} else if (c.scoreQuery["scoreData¬score"]) {
partialCriteria.key = "scoreData.score";
} else if (c.scoreQuery["scoreData¬percent"]) {
partialCriteria.key = "scoreData.percent";
} else {
throw new Error(`Invalid goal ${c.goalID} ${c.title}.`);
}
const v = c.scoreQuery[partialCriteria.key.replace(/\./gu, "¬")];
const v = c.scoreQuery[partialCriteria.key.replace(/\./gu, "¬")];
const value = v ? v["~gte"] : undefined;
const value = v ? v["~gte"] : undefined;
// would break for value == 0, but a goal would never be
// zero.
if (!value) {
throw new Error(`Invalid goal ${c.goalID} ${c.title}.`);
}
// would break for value == 0, but a goal would never be
// zero.
if (!value) {
throw new Error(`Invalid goal ${c.goalID} ${c.title}.`);
}
partialCriteria.value = value;
partialCriteria.value = value;
// @ts-expect-error ts cant resolve this union properly
const newGoalDoc: GoalDocument = {
game: c.game,
playtype: c.playtype,
title: c.title,
timeAdded: c.timeAdded,
goalID: c.goalID, // maybe
createdBy: c.createdBy,
charts,
criteria: partialCriteria as GoalDocument["criteria"],
};
// @ts-expect-error ts cant resolve this union properly
const newGoalDoc: GoalDocument = {
game: c.game,
playtype: c.playtype,
title: c.title,
timeAdded: c.timeAdded,
goalID: c.goalID, // maybe
createdBy: c.createdBy,
charts,
criteria: partialCriteria as GoalDocument["criteria"],
};
return newGoalDoc;
return newGoalDoc;
}
(async () => {
await MigrateRecords(db.goals, "goals", ConvertFn);
await MigrateRecords(db.goals, "goals", ConvertFn);
process.exit(0);
process.exit(0);
})();
@@ -1,5 +1,5 @@
import CreateLogCtx from "lib/logger/logger";
import { ICollection } from "monk";
import CreateLogCtx from "../../src/common/logger";
import { oldKTDB } from "./old-db";
const logger = CreateLogCtx(__filename);
@@ -7,43 +7,43 @@ const logger = CreateLogCtx(__filename);
const newDocuments: unknown[] = [];
export default async function MigrateRecords(
existingCollection: ICollection,
collectionName: string,
HandlerFN: (c: unknown) => unknown
existingCollection: ICollection,
collectionName: string,
HandlerFN: (c: unknown) => unknown
) {
const existingRecords = await existingCollection.count({});
logger.info(`Starting migration for ${collectionName}...`);
const existingRecords = await existingCollection.count({});
logger.info(`Starting migration for ${collectionName}...`);
if (existingRecords > 0) {
logger.error(`${existingRecords} documents already exist in db, terminating.`);
process.exit(1);
}
if (existingRecords > 0) {
logger.error(`${existingRecords} documents already exist in db, terminating.`);
process.exit(1);
}
let i = 0;
let i = 0;
await oldKTDB
.get(collectionName)
.find({})
// @ts-expect-error it exists.
.each(async (c, { pause, resume }) => {
i++;
pause();
await oldKTDB
.get(collectionName)
.find({})
// @ts-expect-error it exists.
.each(async (c, { pause, resume }) => {
i++;
pause();
if (i % 10000 === 0) {
logger.info(`Processed ${i} documents.`);
}
const newDoc = await HandlerFN(c);
if (i % 10000 === 0) {
logger.info(`Processed ${i} documents.`);
}
const newDoc = await HandlerFN(c);
if (newDoc !== null) {
newDocuments.push(newDoc);
}
if (newDoc !== null) {
newDocuments.push(newDoc);
}
resume();
});
resume();
});
logger.info(`Inserting ${newDocuments.length} documents.`);
await existingCollection.insert(newDocuments.flat());
logger.info(`Done!`);
logger.info(`Inserting ${newDocuments.length} documents.`);
await existingCollection.insert(newDocuments.flat());
logger.info(`Done!`);
process.exit(0);
process.exit(0);
}
@@ -8,39 +8,39 @@ const logger = CreateLogCtx(__filename);
const TIERLIST_ID = "ed45403c2cd93922d8a45b3c5bc352a962a8f115";
function ConvertFn(c: any) {
const tdd: TierlistDataDocument<"Individual Difference"> = {
chartID: c.chartID,
type: "score",
key: null,
tierlistDataID: CalculateTierlistDataID(c.chartID, "score", null, TIERLIST_ID),
tierlistID: TIERLIST_ID,
data: {
flags: {
"Individual Difference": c.idvDifference === "FALSE",
},
value: c.tiers["score-tier"],
humanised: `☆${c.tiers["score-tier"]}`,
},
};
const tdd: TierlistDataDocument<"Individual Difference"> = {
chartID: c.chartID,
type: "score",
key: null,
tierlistDataID: CalculateTierlistDataID(c.chartID, "score", null, TIERLIST_ID),
tierlistID: TIERLIST_ID,
data: {
flags: {
"Individual Difference": c.idvDifference === "FALSE",
},
value: c.tiers["score-tier"],
humanised: `☆${c.tiers["score-tier"]}`,
},
};
return tdd;
return tdd;
}
(async () => {
const exists = await db["tierlist-data"].count({
tierlistID: TIERLIST_ID,
});
const exists = await db["tierlist-data"].count({
tierlistID: TIERLIST_ID,
});
if (exists > 0) {
logger.error(`Cancelling migration request as ${exists} documents already exist.`);
return process.exit(1);
}
if (exists > 0) {
logger.error(`Cancelling migration request as ${exists} documents already exist.`);
return process.exit(1);
}
const docs = await oldKTDB.get("tierlistdata").find({
tierlistID: TIERLIST_ID,
});
const docs = await oldKTDB.get("tierlistdata").find({
tierlistID: TIERLIST_ID,
});
const newDocs = await Promise.all(docs.map(ConvertFn));
const newDocs = await Promise.all(docs.map(ConvertFn));
await db["tierlist-data"].insert(newDocs);
await db["tierlist-data"].insert(newDocs);
})();
@@ -5,25 +5,25 @@ import db from "../../src/db/db";
import MigrateRecords from "./migrate";
function ConvertFn(c: any): SongDocument<"chunithm"> {
const newSongDoc: SongDocument<"chunithm"> = {
title: c.title,
artist: c.artist,
id: c.id,
firstVersion: c.firstAppearance,
"alt-titles": c["alt-titles"].filter((e: string) => e !== c.title),
"search-titles": c["search-titles"]
.map((e: string) => e.toString())
.filter((e: string) => e !== c.title),
data: {
genre: c.genre,
},
};
const newSongDoc: SongDocument<"chunithm"> = {
title: c.title,
artist: c.artist,
id: c.id,
firstVersion: c.firstAppearance,
"alt-titles": c["alt-titles"].filter((e: string) => e !== c.title),
"search-titles": c["search-titles"]
.map((e: string) => e.toString())
.filter((e: string) => e !== c.title),
data: {
genre: c.genre,
},
};
return newSongDoc;
return newSongDoc;
}
(async () => {
await MigrateRecords(db.songs.chunithm, "songs-chunithm", ConvertFn);
await MigrateRecords(db.songs.chunithm, "songs-chunithm", ConvertFn);
process.exit(0);
process.exit(0);
})();
@@ -5,24 +5,24 @@ import db from "../../src/db/db";
import MigrateRecords from "./migrate";
function ConvertFn(c: any): SongDocument<"ddr"> {
const newSongDoc: SongDocument<"ddr"> = {
title: c.title,
artist: c.artist,
id: c.id,
firstVersion: c.firstAppearance,
"alt-titles": c["alt-titles"] ? c["alt-titles"].filter((e: string) => e !== c.title) : [],
"search-titles": c["search-title"]
.filter((e: string) => !!e)
.map((e: string) => e.toString())
.filter((e: string) => e !== c.title),
data: {},
};
const newSongDoc: SongDocument<"ddr"> = {
title: c.title,
artist: c.artist,
id: c.id,
firstVersion: c.firstAppearance,
"alt-titles": c["alt-titles"] ? c["alt-titles"].filter((e: string) => e !== c.title) : [],
"search-titles": c["search-title"]
.filter((e: string) => !!e)
.map((e: string) => e.toString())
.filter((e: string) => e !== c.title),
data: {},
};
return newSongDoc;
return newSongDoc;
}
(async () => {
await MigrateRecords(db.songs.ddr, "songs-ddr", ConvertFn);
await MigrateRecords(db.songs.ddr, "songs-ddr", ConvertFn);
process.exit(0);
process.exit(0);
})();
@@ -4,24 +4,24 @@ import db from "../../src/db/db";
import MigrateRecords from "./migrate";
function ConvertFn(c: any): SongDocument<"gitadora"> {
const newSongDoc: SongDocument<"gitadora"> = {
title: c.title,
artist: c.artist,
id: c.id,
firstVersion: c.firstAppearance,
"alt-titles": c["alt-titles"] ? c["alt-titles"].filter((e: string) => e !== c.title) : [],
"search-titles": c["search-titles"]
.filter((e: string) => !!e)
.map((e: string) => e.toString())
.filter((e: string) => e !== c.title),
data: {},
};
const newSongDoc: SongDocument<"gitadora"> = {
title: c.title,
artist: c.artist,
id: c.id,
firstVersion: c.firstAppearance,
"alt-titles": c["alt-titles"] ? c["alt-titles"].filter((e: string) => e !== c.title) : [],
"search-titles": c["search-titles"]
.filter((e: string) => !!e)
.map((e: string) => e.toString())
.filter((e: string) => e !== c.title),
data: {},
};
return newSongDoc;
return newSongDoc;
}
(async () => {
await MigrateRecords(db.songs.gitadora, "songs-gitadora", ConvertFn);
await MigrateRecords(db.songs.gitadora, "songs-gitadora", ConvertFn);
process.exit(0);
process.exit(0);
})();
@@ -5,25 +5,25 @@ import db from "../../src/db/db";
import MigrateRecords from "./migrate";
function ConvertFn(c: any): SongDocument<"iidx"> {
const newSongDoc: SongDocument<"iidx"> = {
title: c.title,
artist: c.artist,
id: c.id,
firstVersion: c.firstAppearance,
"alt-titles": c["alt-titles"].filter((e: string) => e !== c.title),
"search-titles": c["search-titles"]
.map((e: string) => e.toString())
.filter((e: string) => e !== c.title),
data: {
genre: c.genre,
},
};
const newSongDoc: SongDocument<"iidx"> = {
title: c.title,
artist: c.artist,
id: c.id,
firstVersion: c.firstAppearance,
"alt-titles": c["alt-titles"].filter((e: string) => e !== c.title),
"search-titles": c["search-titles"]
.map((e: string) => e.toString())
.filter((e: string) => e !== c.title),
data: {
genre: c.genre,
},
};
return newSongDoc;
return newSongDoc;
}
(async () => {
await MigrateRecords(db.songs.iidx, "songs-iidx", ConvertFn);
await MigrateRecords(db.songs.iidx, "songs-iidx", ConvertFn);
process.exit(0);
process.exit(0);
})();
@@ -4,24 +4,24 @@ import db from "../../src/db/db";
import MigrateRecords from "./migrate";
function ConvertFn(c: any): SongDocument<"museca"> {
const newSongDoc: SongDocument<"museca"> = {
title: c.title,
artist: c.artist,
id: c.id,
firstVersion: c.firstAppearance,
"alt-titles": [],
"search-titles": [],
data: {
titleJP: c.title_jp,
artistJP: c.artist_jp,
},
};
const newSongDoc: SongDocument<"museca"> = {
title: c.title,
artist: c.artist,
id: c.id,
firstVersion: c.firstAppearance,
"alt-titles": [],
"search-titles": [],
data: {
titleJP: c.title_jp,
artistJP: c.artist_jp,
},
};
return newSongDoc;
return newSongDoc;
}
(async () => {
await MigrateRecords(db.songs.museca, "songs-museca", ConvertFn);
await MigrateRecords(db.songs.museca, "songs-museca", ConvertFn);
process.exit(0);
process.exit(0);
})();
@@ -4,25 +4,25 @@ import db from "../../src/db/db";
import MigrateRecords from "./migrate";
function ConvertFn(c: any): SongDocument<"sdvx"> {
const newSongDoc: SongDocument<"sdvx"> = {
title: c.title,
artist: c.artist,
id: c.id,
firstVersion: c.firstAppearance,
"alt-titles": c["alt-titles"].filter((e: string) => e !== c.title),
"search-titles": c["search-titles"]
.map((e: string) => e.toString())
.filter((e: string) => e !== c.title),
data: {
uscEquiv: null,
},
};
const newSongDoc: SongDocument<"sdvx"> = {
title: c.title,
artist: c.artist,
id: c.id,
firstVersion: c.firstAppearance,
"alt-titles": c["alt-titles"].filter((e: string) => e !== c.title),
"search-titles": c["search-titles"]
.map((e: string) => e.toString())
.filter((e: string) => e !== c.title),
data: {
uscEquiv: null,
},
};
return newSongDoc;
return newSongDoc;
}
(async () => {
await MigrateRecords(db.songs.sdvx, "songs-sdvx", ConvertFn);
await MigrateRecords(db.songs.sdvx, "songs-sdvx", ConvertFn);
process.exit(0);
process.exit(0);
})();
@@ -5,37 +5,37 @@ import db from "../../src/external/mongo/db";
import MigrateRecords from "./migrate";
function ConvertFn(c: any): TierlistParent {
const tierlistParent: TierlistParent = {
createdAt: Date.now(),
tierlistID: c.tierlistID,
createdBy: 1,
description: `The official Kamaitachi Tierlist for ${gameHuman[c.game as Game]}${
validPlaytypes[c.game as Game].length > 1 ? ` (${c.playtype})` : ""
}.`,
game: c.game,
playtype: c.playtype,
isDefault: true,
name: c.title,
lastUpdated: Date.now(),
permissions: {
anyPlayer: {
edit: 0,
submit: 1,
vote: 1,
},
},
config: {
autoHumanise: false,
flags: ["Individual Difference"],
requireState: "clear",
},
};
const tierlistParent: TierlistParent = {
createdAt: Date.now(),
tierlistID: c.tierlistID,
createdBy: 1,
description: `The official Kamaitachi Tierlist for ${gameHuman[c.game as Game]}${
validPlaytypes[c.game as Game].length > 1 ? ` (${c.playtype})` : ""
}.`,
game: c.game,
playtype: c.playtype,
isDefault: true,
name: c.title,
lastUpdated: Date.now(),
permissions: {
anyPlayer: {
edit: 0,
submit: 1,
vote: 1,
},
},
config: {
autoHumanise: false,
flags: ["Individual Difference"],
requireState: "clear",
},
};
return tierlistParent;
return tierlistParent;
}
(async () => {
await MigrateRecords(db.tierlists, "tierlist", ConvertFn);
await MigrateRecords(db.tierlists, "tierlist", ConvertFn);
process.exit(0);
process.exit(0);
})();
@@ -8,19 +8,19 @@ import MigrateRecords from "./migrate";
const logger = CreateLogCtx(__filename);
async function ConvertFn(c: any): Promise<UserGoalDocument | null> {
// const newUG: UserGoalDocument = {};
// const newUG: UserGoalDocument = {};
let relatedGoal = await db.goals.findOne({ goalID: c.goalID });
const relatedGoal = await db.goals.findOne({ goalID: c.goalID });
if (!relatedGoal) {
return null;
}
if (!relatedGoal) {
return null;
}
return c;
return c;
}
(async () => {
await MigrateRecords(db["user-goals"], "user-goals", ConvertFn);
await MigrateRecords(db["user-goals"], "user-goals", ConvertFn);
process.exit(0);
process.exit(0);
})();
+29 -29
View File
@@ -3,38 +3,38 @@ import db from "../../src/db/db";
import MigrateRecords from "./migrate";
function ConvertFn(c: any): PrivateUserDocument {
const newUserDoc: PrivateUserDocument = {
username: c.username,
usernameLowercase: c.username.toLowerCase(),
about: c.about,
clan: c.clan,
customBanner: c.custombanner,
customPfp: c.custompfp,
email: c.email,
friends: c.friends,
id: c.id,
lastSeen: c.lastSeen,
password: c.password,
permissions: {},
settings: {
invisible: !!c.settings.invisible,
nsfwSplashes: !!c.settings.nsfwsplashes,
},
socialMedia: {
discord: c.socialmedia.discord || null,
twitter: c.socialmedia.twitter || null,
youtube: c.socialmedia.youtube || null,
twitch: c.socialmedia.twitch || null,
github: c.socialmedia.github || null,
steam: c.socialmedia.steam || null,
},
};
const newUserDoc: PrivateUserDocument = {
username: c.username,
usernameLowercase: c.username.toLowerCase(),
about: c.about,
clan: c.clan,
customBanner: c.custombanner,
customPfp: c.custompfp,
email: c.email,
friends: c.friends,
id: c.id,
lastSeen: c.lastSeen,
password: c.password,
permissions: {},
settings: {
invisible: !!c.settings.invisible,
nsfwSplashes: !!c.settings.nsfwsplashes,
},
socialMedia: {
discord: c.socialmedia.discord || null,
twitter: c.socialmedia.twitter || null,
youtube: c.socialmedia.youtube || null,
twitch: c.socialmedia.twitch || null,
github: c.socialmedia.github || null,
steam: c.socialmedia.steam || null,
},
};
return newUserDoc;
return newUserDoc;
}
(async () => {
await MigrateRecords(db.users, "users", ConvertFn);
await MigrateRecords(db.users, "users", ConvertFn);
process.exit(0);
process.exit(0);
})();
+49 -49
View File
@@ -18,74 +18,74 @@ program.parse(process.argv);
const options = program.opts();
async function GetIIDXSongs() {
const allSongs = [];
const allSongs = [];
let url = `https://${options.url}/api/v1/iidx/27/music/`;
let url = `https://${options.url}/api/v1/iidx/27/music/`;
let moreData = true;
while (moreData) {
// eslint-disable-next-line no-await-in-loop
const songs = await fetch(url, {
headers: {
Authorization: `Bearer ${options.bearer}`,
},
}).then((r) => r.json());
let moreData = true;
while (moreData) {
// eslint-disable-next-line no-await-in-loop
const songs = await fetch(url, {
headers: {
Authorization: `Bearer ${options.bearer}`,
},
}).then((r) => r.json());
if (songs._links._next) {
url = songs._links._next;
} else {
moreData = false;
}
if (songs._links._next) {
url = songs._links._next;
} else {
moreData = false;
}
allSongs.push(...songs._items);
}
allSongs.push(...songs._items);
}
fs.writeFileSync(path.join(__dirname, "./songs.json"), JSON.stringify(allSongs));
fs.writeFileSync(path.join(__dirname, "./songs.json"), JSON.stringify(allSongs));
}
async function GetCharts() {
const songs = JSON.parse(fs.readFileSync(path.join(__dirname, "./songs.json"), "utf-8"));
const songs = JSON.parse(fs.readFileSync(path.join(__dirname, "./songs.json"), "utf-8"));
logger.info("Parsed songs.json");
logger.info("Parsed songs.json");
const allCharts: any[] = [];
const failed: any[] = [];
const allCharts: any[] = [];
const failed: any[] = [];
async function DoStuff(song: any) {
try {
logger.info(
`Starting Request https://${options.url}/api/v1/iidx/27/charts/?music_id=${song._id}&omnimix=true.`
);
async function DoStuff(song: any) {
try {
logger.info(
`Starting Request https://${options.url}/api/v1/iidx/27/charts/?music_id=${song._id}&omnimix=true.`
);
// eslint-disable-next-line no-await-in-loop
const charts = await fetch(
`https://${options.url}/api/v1/iidx/27/charts/?music_id=${song._id}&omnimix=true`,
{
headers: {
Authorization: `Bearer ${options.bearer}`,
},
}
).then((r) => r.json());
// eslint-disable-next-line no-await-in-loop
const charts = await fetch(
`https://${options.url}/api/v1/iidx/27/charts/?music_id=${song._id}&omnimix=true`,
{
headers: {
Authorization: `Bearer ${options.bearer}`,
},
}
).then((r) => r.json());
logger.info(`Parsed: ${charts._related.music[0].title}`);
logger.info(`Parsed: ${charts._related.music[0].title}`);
allCharts.push(charts);
} catch (err) {
logger.error(song);
logger.error(err);
failed.push(err);
}
}
allCharts.push(charts);
} catch (err) {
logger.error(song);
logger.error(err);
failed.push(err);
}
}
const promises = songs.map((s: any) => DoStuff(s));
const promises = songs.map((s: any) => DoStuff(s));
await Promise.all(promises);
await Promise.all(promises);
fs.writeFileSync(path.join(__dirname, "./charts.json"), JSON.stringify(allCharts));
fs.writeFileSync(path.join(__dirname, "./charts.json"), JSON.stringify(allCharts));
logger.info(failed);
logger.info(failed);
logger.info("done?");
logger.info("done?");
}
GetCharts();
+61 -61
View File
@@ -10,77 +10,77 @@ import { FindChartWithPTDFVersion } from "../../src/common/database-lookup/chart
const logger = CreateLogCtx(__filename);
async function MergeIDs() {
const charts = JSON.parse(fs.readFileSync(path.join(__dirname, "./charts.json"), "utf-8"));
const charts = JSON.parse(fs.readFileSync(path.join(__dirname, "./charts.json"), "utf-8"));
for (const chartData of charts) {
const songTitle = chartData._related.music[0].title;
for (const chartData of charts) {
const songTitle = chartData._related.music[0].title;
// eslint-disable-next-line no-await-in-loop
const song = await FindSongOnTitle("iidx", songTitle);
// eslint-disable-next-line no-await-in-loop
const song = await FindSongOnTitle("iidx", songTitle);
if (!song) {
logger.error(`Could not resolve ${songTitle}?`);
continue;
}
if (!song) {
logger.error(`Could not resolve ${songTitle}?`);
continue;
}
for (const chart of chartData._items) {
const playtype: "SP" | "DP" = chart.play_style === "DOUBLE" ? "DP" : "SP";
let difficulty = chart.difficulty === "BLACK" ? "LEGGENDARIA" : chart.difficulty;
const version = "27-omni";
for (const chart of chartData._items) {
const playtype: "SP" | "DP" = chart.play_style === "DOUBLE" ? "DP" : "SP";
let difficulty = chart.difficulty === "BLACK" ? "LEGGENDARIA" : chart.difficulty;
const version = "27-omni";
// yeah this fails for wacky playtype mismatches -- i don't care.
if (
["ミッドナイト堕天使", "Y&Co. is dead or alive", "State Of The Art"].includes(
songTitle
) &&
difficulty === "LEGGENDARIA"
) {
difficulty = "ANOTHER";
}
// yeah this fails for wacky playtype mismatches -- i don't care.
if (
["ミッドナイト堕天使", "Y&Co. is dead or alive", "State Of The Art"].includes(
songTitle
) &&
difficulty === "LEGGENDARIA"
) {
difficulty = "ANOTHER";
}
// eslint-disable-next-line no-await-in-loop
const tachiChart = await FindChartWithPTDFVersion(
"iidx",
song.id,
playtype,
difficulty,
version
);
// eslint-disable-next-line no-await-in-loop
const tachiChart = await FindChartWithPTDFVersion(
"iidx",
song.id,
playtype,
difficulty,
version
);
if (!tachiChart) {
logger.error(
`Could not find chart ${songTitle} ${playtype} ${difficulty} ${version}.`
);
continue;
}
if (!tachiChart) {
logger.error(
`Could not find chart ${songTitle} ${playtype} ${difficulty} ${version}.`
);
continue;
}
// eslint-disable-next-line no-await-in-loop
await (
db.charts.iidx as unknown as ICollection<ChartDocument<"iidx:SP" | "iidx:DP">>
).update(
{
_id: tachiChart._id,
},
{
$set: {
"data.arcChartID": chart._id,
},
}
);
}
}
// eslint-disable-next-line no-await-in-loop
await (
db.charts.iidx as unknown as ICollection<ChartDocument<"iidx:SP" | "iidx:DP">>
).update(
{
_id: tachiChart._id,
},
{
$set: {
"data.arcChartID": chart._id,
},
}
);
}
}
const r = await db.charts.iidx.update(
{
"data.arcChartID": { $exists: false },
},
{ $set: { "data.arcChartID": null } },
{
multi: true,
}
);
const r = await db.charts.iidx.update(
{
"data.arcChartID": { $exists: false },
},
{ $set: { "data.arcChartID": null } },
{
multi: true,
}
);
logger.info("done.", { r });
logger.info("done.", { r });
}
MergeIDs();
+121 -121
View File
@@ -14,161 +14,161 @@ const logger = CreateLogCtx(__filename);
const TIERLIST_ID = "ee9b756e50cff8282091102257b01f423ef855f2";
async function FetchSP12Data() {
const rj = await fetch("https://sp12.iidx.app/api/v1/sheets").then((r) => r.json()); // will throw if somethings wrong, anyway
const rj = await fetch("https://sp12.iidx.app/api/v1/sheets").then((r) => r.json()); // will throw if somethings wrong, anyway
if (!rj.sheets) {
throw new Error(`No sheets in return from sp12?`);
}
if (!rj.sheets) {
throw new Error(`No sheets in return from sp12?`);
}
const tdd: TierlistDataDocument<"Individual Difference">[] = [];
const tdd: TierlistDataDocument<"Individual Difference">[] = [];
for (const sh of rj.sheets) {
let chart;
try {
chart = await HumanisedTitleLookup(sh.title);
} catch (err) {
logger.error((err as Error).message);
continue;
}
for (const sh of rj.sheets) {
let chart;
try {
chart = await HumanisedTitleLookup(sh.title);
} catch (err) {
logger.error((err as Error).message);
continue;
}
for (const key of ["NORMAL CLEAR", "HARD CLEAR", "EX HARD CLEAR"]) {
let fakeKey;
let val;
for (const key of ["NORMAL CLEAR", "HARD CLEAR", "EX HARD CLEAR"]) {
let fakeKey;
let val;
switch (key) {
case "NORMAL CLEAR":
fakeKey = "n_clear";
const v = Math.floor(sh[fakeKey] / 2);
switch (key) {
case "NORMAL CLEAR":
fakeKey = "n_clear";
const v = Math.floor(sh[fakeKey] / 2);
if (v === 9) {
val = 11.8;
} else if (v === 8) {
val = 12.0;
} else if (v === 7) {
val = 12.2;
} else if (v === 6) {
val = 12.4;
} else if (v === 5) {
val = 12.6;
} else if (v < 0) {
continue;
} else {
val = 12.6 + (5 - v) * 0.1;
}
if (v === 9) {
val = 11.8;
} else if (v === 8) {
val = 12.0;
} else if (v === 7) {
val = 12.2;
} else if (v === 6) {
val = 12.4;
} else if (v === 5) {
val = 12.6;
} else if (v < 0) {
continue;
} else {
val = 12.6 + (5 - v) * 0.1;
}
break;
case "HARD CLEAR":
fakeKey = "hard";
const v2 = Math.floor(sh[fakeKey] / 2);
break;
case "HARD CLEAR":
fakeKey = "hard";
const v2 = Math.floor(sh[fakeKey] / 2);
if (v2 === 9) {
val = 11.9;
} else if (v2 === 8) {
val = 12.1;
} else if (v2 === 7) {
val = 12.3;
} else if (v2 === 6) {
val = 12.5;
} else if (v2 === 5) {
val = 12.7;
} else if (v2 < 0) {
continue;
} else {
val = 12.7 + (5 - v2) * 0.1;
}
if (v2 === 9) {
val = 11.9;
} else if (v2 === 8) {
val = 12.1;
} else if (v2 === 7) {
val = 12.3;
} else if (v2 === 6) {
val = 12.5;
} else if (v2 === 5) {
val = 12.7;
} else if (v2 < 0) {
continue;
} else {
val = 12.7 + (5 - v2) * 0.1;
}
break;
case "EX HARD CLEAR":
fakeKey = "exh";
break;
case "EX HARD CLEAR":
fakeKey = "exh";
const v3 = sh[fakeKey];
if (v3 < 0) {
continue;
}
const v3 = sh[fakeKey];
if (v3 < 0) {
continue;
}
val = 12.4 + (12 - v3) * 0.1;
val = 12.4 + (12 - v3) * 0.1;
break;
default:
throw new Error("??");
}
break;
default:
throw new Error("??");
}
const humanised = sh[`${fakeKey}_string`];
const humanised = sh[`${fakeKey}_string`];
if (humanised === "難易度未定") {
continue;
}
if (humanised === "難易度未定") {
continue;
}
if (val < 11.8) {
logger.info(`Skipping ${sh.title} ${key}, ${humanised}.`);
continue;
}
if (val < 11.8) {
logger.info(`Skipping ${sh.title} ${key}, ${humanised}.`);
continue;
}
val = parseFloat(val.toFixed(2));
val = parseFloat(val.toFixed(2));
tdd.push({
chartID: chart.chartID,
type: "lamp",
tierlistID: TIERLIST_ID,
tierlistDataID: CalculateTierlistDataID(chart.chartID, "lamp", key, TIERLIST_ID),
key,
data: {
humanised,
value: val,
flags: {
"Individual Difference": !!humanised.match(/個人差/u),
},
},
});
}
}
tdd.push({
chartID: chart.chartID,
type: "lamp",
tierlistID: TIERLIST_ID,
tierlistDataID: CalculateTierlistDataID(chart.chartID, "lamp", key, TIERLIST_ID),
key,
data: {
humanised,
value: val,
flags: {
"Individual Difference": !!humanised.match(/個人差/u),
},
},
});
}
}
logger.info(`Inserting ${tdd.length} documents...`);
logger.info(`Inserting ${tdd.length} documents...`);
await db["tierlist-data"].insert(tdd);
await db["tierlist-data"].insert(tdd);
logger.info("Done!");
logger.info("Done!");
process.exit(0);
process.exit(0);
}
function isOdd(num: number) {
return num % 2 !== 0;
return num % 2 !== 0;
}
async function HumanisedTitleLookup(originalTitle: string) {
let difficulty: Difficulties["iidx:SP"] = "ANOTHER";
let difficulty: Difficulties["iidx:SP"] = "ANOTHER";
let title = originalTitle;
let title = originalTitle;
if (title.match(/(†|†LEGGENDARIA)$/u)) {
difficulty = "LEGGENDARIA";
title = title.split("†")[0]; // this will break if there is ever a ptp leggendaria
} else if (title.match(/\[H\]$/u)) {
difficulty = "HYPER";
title = title.split("[")[0];
} else if (title.match(/\[A\]$/u)) {
difficulty = "ANOTHER"; // lmao
title = title.split("[")[0];
}
if (title.match(/(†|†LEGGENDARIA)$/u)) {
difficulty = "LEGGENDARIA";
title = title.split("†")[0]; // this will break if there is ever a ptp leggendaria
} else if (title.match(/\[H\]$/u)) {
difficulty = "HYPER";
title = title.split("[")[0];
} else if (title.match(/\[A\]$/u)) {
difficulty = "ANOTHER"; // lmao
title = title.split("[")[0];
}
const song = await FindSongOnTitle("iidx", title);
const song = await FindSongOnTitle("iidx", title);
if (!song) {
throw new Error(
`Could not resolve song ${title} (${difficulty}) (Original ${originalTitle}).`
);
}
if (!song) {
throw new Error(
`Could not resolve song ${title} (${difficulty}) (Original ${originalTitle}).`
);
}
const chart = await FindChartWithPTDF("iidx", song.id, "SP", difficulty);
const chart = await FindChartWithPTDF("iidx", song.id, "SP", difficulty);
if (!chart) {
throw new Error(
`Could not resolve chart ${title} ${difficulty} (Original ${originalTitle}).`
);
}
if (!chart) {
throw new Error(
`Could not resolve chart ${title} ${difficulty} (Original ${originalTitle}).`
);
}
return chart;
return chart;
}
FetchSP12Data();
+118 -118
View File
@@ -12,153 +12,153 @@ const logger = CreateLogCtx(__filename);
const TIERLIST_ID = "ee9b756e50cff8282091102257b01f423ef855f2";
async function parseKr(
dir: string,
key: "NORMAL CLEAR" | "HARD CLEAR",
catVals: { h: string; v: number }[]
dir: string,
key: "NORMAL CLEAR" | "HARD CLEAR",
catVals: { h: string; v: number }[]
) {
const krdata = JSON.parse(fs.readFileSync(path.join(__dirname, "./iidx-pe-kr", dir), "utf-8"));
const krdata = JSON.parse(fs.readFileSync(path.join(__dirname, "./iidx-pe-kr", dir), "utf-8"));
const tdd = [];
const tdd = [];
for (let i = 0; i < krdata.categories.length; i++) {
const data = krdata.categories[i];
if (data.sortindex < 0) {
continue;
}
for (let i = 0; i < krdata.categories.length; i++) {
const data = krdata.categories[i];
if (data.sortindex < 0) {
continue;
}
const cv = catVals[i];
const cv = catVals[i];
if (!cv) {
throw new Error(`cv krdata mismatch ${krdata.categories.length} ${catVals.length}?`);
}
if (!cv) {
throw new Error(`cv krdata mismatch ${krdata.categories.length} ${catVals.length}?`);
}
for (const item of data.items) {
const song = await FindSongOnTitle("iidx", item.data.title.replace(/†$/u, "").trim());
for (const item of data.items) {
const song = await FindSongOnTitle("iidx", item.data.title.replace(/†$/u, "").trim());
if (!song) {
logger.warn(`Could not find song with title ${item.data.title}`);
continue;
}
if (!song) {
logger.warn(`Could not find song with title ${item.data.title}`);
continue;
}
const t = item.data.type;
const t = item.data.type;
let diff: Difficulties["iidx:SP"];
if (t === "A") {
diff = "ANOTHER";
} else if (t === "L") {
diff = "LEGGENDARIA";
} else if (t === "H") {
diff = "HYPER";
} else if (t === "N") {
diff = "NORMAL";
} else {
logger.warn(`${song.title} Unknown difficulty ${t}.`);
continue;
}
let diff: Difficulties["iidx:SP"];
if (t === "A") {
diff = "ANOTHER";
} else if (t === "L") {
diff = "LEGGENDARIA";
} else if (t === "H") {
diff = "HYPER";
} else if (t === "N") {
diff = "NORMAL";
} else {
logger.warn(`${song.title} Unknown difficulty ${t}.`);
continue;
}
const chart = await FindChartWithPTDF("iidx", song.id, "SP", diff);
const chart = await FindChartWithPTDF("iidx", song.id, "SP", diff);
if (!chart) {
logger.warn(`${song.title} ${diff} - Couldn't find chart?`);
continue;
}
if (!chart) {
logger.warn(`${song.title} ${diff} - Couldn't find chart?`);
continue;
}
tdd.push({
chartID: chart.chartID,
type: "lamp" as const,
tierlistID: TIERLIST_ID,
tierlistDataID: CalculateTierlistDataID(chart.chartID, "lamp", key, TIERLIST_ID),
key,
data: {
humanised: cv.h,
value: cv.v,
flags: {
"Individual Difference": !!data.category.match(/個人差/u),
},
},
});
}
}
tdd.push({
chartID: chart.chartID,
type: "lamp" as const,
tierlistID: TIERLIST_ID,
tierlistDataID: CalculateTierlistDataID(chart.chartID, "lamp", key, TIERLIST_ID),
key,
data: {
humanised: cv.h,
value: cv.v,
flags: {
"Individual Difference": !!data.category.match(/個人差/u),
},
},
});
}
}
logger.info(`Inserting ${tdd.length} documents...`);
logger.info(`Inserting ${tdd.length} documents...`);
const x = await db["tierlist-data"].bulkWrite(
tdd.map((e) => ({
updateOne: {
filter: {
tierlistDataID: e.tierlistDataID,
},
update: {
$set: e,
},
upsert: true,
},
}))
);
const x = await db["tierlist-data"].bulkWrite(
tdd.map((e) => ({
updateOne: {
filter: {
tierlistDataID: e.tierlistDataID,
},
update: {
$set: e,
},
upsert: true,
},
}))
);
logger.info(x);
logger.info(x);
logger.info("done...");
logger.info("done...");
}
function h(h: string, v: number) {
return { h, v };
return { h, v };
}
parseKr("sp9H.json", "HARD CLEAR", [
h("S+", 10.2),
h("S", 10),
h("S 個人差", 10),
h("A+", 9.9),
h("A+ 個人差", 9.9),
h("A", 9.8),
h("B+", 9.7),
h("B", 9.6),
h("C+", 9.5),
h("C", 9.4),
h("D", 9.2),
h("E", 9.0),
h("F", 8.8),
h("S+", 10.2),
h("S", 10),
h("S 個人差", 10),
h("A+", 9.9),
h("A+ 個人差", 9.9),
h("A", 9.8),
h("B+", 9.7),
h("B", 9.6),
h("C+", 9.5),
h("C", 9.4),
h("D", 9.2),
h("E", 9.0),
h("F", 8.8),
]);
parseKr("sp10H.json", "HARD CLEAR", [
h("S", 11),
h("A+", 10.9),
h("A", 10.8),
h("B+", 10.7),
h("B", 10.6),
h("C+", 10.5),
h("C", 10.4),
h("D", 10.2),
h("E", 10.0),
h("F", 9.8),
h("S", 11),
h("A+", 10.9),
h("A", 10.8),
h("B+", 10.7),
h("B", 10.6),
h("C+", 10.5),
h("C", 10.4),
h("D", 10.2),
h("E", 10.0),
h("F", 9.8),
]);
parseKr("sp11N.json", "NORMAL CLEAR", [
h("S+", 12.2),
h("S", 12),
h("A+", 11.9),
h("A", 11.8),
h("B", 11.6),
h("C", 11.4),
h("D", 11.2),
h("E", 11.0),
h("F", 10.8),
h("S+", 12.2),
h("S", 12),
h("A+", 11.9),
h("A", 11.8),
h("B", 11.6),
h("C", 11.4),
h("D", 11.2),
h("E", 11.0),
h("F", 10.8),
]);
parseKr("sp11H.json", "HARD CLEAR", [
h("S+", 12.2),
h("S+ 個人差", 12.2),
h("S", 12),
h("S 個人差", 12),
h("A+", 11.9),
h("A+ 個人差", 11.9),
h("A", 11.8),
h("A 個人差", 11.0),
h("B+", 11.7),
h("B", 11.6),
h("C", 11.4),
h("D", 11.2),
h("E", 11.0),
h("F", 10.8),
h("S+", 12.2),
h("S+ 個人差", 12.2),
h("S", 12),
h("S 個人差", 12),
h("A+", 11.9),
h("A+ 個人差", 11.9),
h("A", 11.8),
h("A 個人差", 11.0),
h("B+", 11.7),
h("B", 11.6),
h("C", 11.4),
h("D", 11.2),
h("E", 11.0),
h("F", 10.8),
]);
+12 -12
View File
@@ -4,19 +4,19 @@ import CreateLogCtx from "../common/logger";
const logger = CreateLogCtx(__filename);
(async () => {
let users = await db.counters.findOne({
counterName: "users",
});
const users = await db.counters.findOne({
counterName: "users",
});
if (users) {
throw new Error(`"users" document already exists, exiting.`);
}
if (users) {
throw new Error(`"users" document already exists, exiting.`);
}
await db.counters.insert({
counterName: "users",
value: 1,
});
await db.counters.insert({
counterName: "users",
value: 1,
});
logger.info("Successfully initialised counter documents. Exiting.");
process.exit(0);
logger.info("Successfully initialised counter documents. Exiting.");
process.exit(0);
})();
+14 -14
View File
@@ -3,19 +3,19 @@
import db from "../../src/db/db";
db.charts.iidx
.find({})
.each(async (c, { pause, resume }) => {
pause();
.find({})
.each(async (c, { pause, resume }) => {
pause();
await db.charts.iidx.update(
{ _id: c._id },
{
$set: {
"flags.2dxtra": false,
},
}
);
await db.charts.iidx.update(
{ _id: c._id },
{
$set: {
"flags.2dxtra": false,
},
}
);
resume();
})
.then(() => console.log("done"));
resume();
})
.then(() => console.log("done"));
+9 -9
View File
@@ -7,18 +7,18 @@ import CreateLogCtx from "../../src/common/logger";
const logger = CreateLogCtx(__filename);
let data = JSON.parse(fs.readFileSync(path.join(__dirname, "./hcnverdata.json"), "utf-8"));
const data = JSON.parse(fs.readFileSync(path.join(__dirname, "./hcnverdata.json"), "utf-8"));
for (const d of data) {
let r = p(d, PRUDENCE_CHART_SCHEMAS.iidx);
if (r) {
logger.error(r.userVal);
logger.error(r);
throw r;
}
const r = p(d, PRUDENCE_CHART_SCHEMAS.iidx);
if (r) {
logger.error(r.userVal);
logger.error(r);
throw r;
}
}
db.charts.iidx.insert(data).then(() => {
logger.info("Done.");
process.exit(0);
logger.info("Done.");
process.exit(0);
});
@@ -0,0 +1,44 @@
import db from "external/mongo/db";
(async () => {
const folders = await db.folders.find({}, { sort: { tableIndex: 1 } });
for (const folder of folders) {
const { game, playtype } = folder;
const tableID = ((folder as any).table as string)
.toLowerCase()
.replace(/ /gu, "_")
.replace(/\(/gu, "")
.replace(/\)/gu, "");
console.log(game, playtype, tableID, folder.title);
const existingTable = await db.tables.findOne({ game, playtype, tableID });
if (!existingTable) {
await db.tables.insert({
tableID,
game,
playtype,
description: "todo",
folders: [folder.folderID],
// @ts-expect-error yea
title: folder.table,
});
} else {
await db.tables.update(
{
game,
playtype,
tableID,
},
{
$push: {
folders: folder.folderID,
},
}
);
}
}
})();
+13 -13
View File
@@ -1,18 +1,18 @@
import db from "../../src/db/db";
(async () => {
let charts = await db.charts.chunithm.find({});
const charts = await db.charts.chunithm.find({});
for (const c of charts) {
await db.charts.chunithm.update(
{
_id: c._id,
},
{
$set: {
"data.inGameID": c.songID,
},
}
);
}
for (const c of charts) {
await db.charts.chunithm.update(
{
_id: c._id,
},
{
$set: {
"data.inGameID": c.songID,
},
}
);
}
})();
@@ -2,27 +2,27 @@ import db from "../../../src/db/db";
import { ChartDocument } from "tachi-common";
db.charts.iidx
.find({})
// @ts-expect-error it exists
.each(async (c: ChartDocument<"iidx:SP" | "iidx:DP">, { pause, resume }: any) => {
pause();
.find({})
// @ts-expect-error it exists
.each(async (c: ChartDocument<"iidx:SP" | "iidx:DP">, { pause, resume }: any) => {
pause();
const song = (await db.songs.iidx.findOne({ id: c.songID }))!;
const song = (await db.songs.iidx.findOne({ id: c.songID }))!;
let versions = [];
let versions = [];
if (song.firstVersion === "27") {
versions = ["27", "28", "27-omni", "28-omni"];
} else if (song.firstVersion === "28") {
versions = ["28", "28-omni"];
} else if (song.firstVersion === "inf") {
versions = ["inf"];
} else {
versions = ["26", "27", "28", "26-omni", "27-omni", "28-omni"];
}
if (song.firstVersion === "27") {
versions = ["27", "28", "27-omni", "28-omni"];
} else if (song.firstVersion === "28") {
versions = ["28", "28-omni"];
} else if (song.firstVersion === "inf") {
versions = ["inf"];
} else {
versions = ["26", "27", "28", "26-omni", "27-omni", "28-omni"];
}
await db.charts.iidx.update({ _id: c._id }, { $set: { versions } });
await db.charts.iidx.update({ _id: c._id }, { $set: { versions } });
resume();
})
.then(() => console.log("done"));
resume();
})
.then(() => console.log("done"));
@@ -4,17 +4,17 @@ import db from "../../../src/db/db";
const logger = CreateLogCtx(__filename);
(async () => {
const charts = await db.charts.iidx.find({ versions: { $size: 0 } });
const charts = await db.charts.iidx.find({ versions: { $size: 0 } });
for (const chart of charts) {
// eslint-disable-next-line no-await-in-loop
const song = await db.songs.iidx.findOne({ id: chart.songID });
for (const chart of charts) {
// eslint-disable-next-line no-await-in-loop
const song = await db.songs.iidx.findOne({ id: chart.songID });
if (!song) {
logger.error(`cannot find parent song ${chart.songID}`);
continue;
}
if (!song) {
logger.error(`cannot find parent song ${chart.songID}`);
continue;
}
logger.info(`${song.title} ${chart.playtype} ${chart.difficulty}`);
}
logger.info(`${song.title} ${chart.playtype} ${chart.difficulty}`);
}
})();
@@ -7,90 +7,90 @@ import { FindSongOnTitleInsensitive } from "../../../src/common/database-lookup/
const logger = CreateLogCtx(__filename);
const comicallyLargeJSONData = JSON.parse(
fs.readFileSync(path.join(__dirname, "./versions.json"), "utf-8")
fs.readFileSync(path.join(__dirname, "./versions.json"), "utf-8")
);
const DIFF_MAP = {
A: "ANOTHER",
H: "HYPER",
N: "NORMAL",
B: "BEGINNER",
X: "LEGGENDARIA",
A: "ANOTHER",
H: "HYPER",
N: "NORMAL",
B: "BEGINNER",
X: "LEGGENDARIA",
} as any;
function ConvertVersion(c: string) {
if (c.startsWith("AC")) {
return c.split("AC")[1];
} else if (c.startsWith("OM")) {
return `${c.split("OM")[1]}-omni`;
} else if (c.startsWith("CS")) {
return `${c.split("CS")[1]}-cs`;
} else if (c === "INF") {
return "inf";
} else if (c === "BMUS") {
return "bmus";
} else {
logger.error(`Invalid Chart Version ${c}.`);
throw new Error("Invalid Chart Version");
}
if (c.startsWith("AC")) {
return c.split("AC")[1];
} else if (c.startsWith("OM")) {
return `${c.split("OM")[1]}-omni`;
} else if (c.startsWith("CS")) {
return `${c.split("CS")[1]}-cs`;
} else if (c === "INF") {
return "inf";
} else if (c === "BMUS") {
return "bmus";
} else {
logger.error(`Invalid Chart Version ${c}.`);
throw new Error("Invalid Chart Version");
}
}
(async () => {
for (const data of comicallyLargeJSONData) {
const song = await FindSongOnTitleInsensitive("iidx", data["MUSIC NAME"]);
for (const data of comicallyLargeJSONData) {
const song = await FindSongOnTitleInsensitive("iidx", data["MUSIC NAME"]);
if (!song) {
logger.error(`Can't find song with title ${data["MUSIC NAME"]}.`);
continue;
}
if (!song) {
logger.error(`Can't find song with title ${data["MUSIC NAME"]}.`);
continue;
}
const playtype = data.STYLE === "S" ? "SP" : "DP";
const playtype = data.STYLE === "S" ? "SP" : "DP";
const difficulty = DIFF_MAP[data.DIFF];
const difficulty = DIFF_MAP[data.DIFF];
const relevantVersions = [
"OM27",
"OM26",
"AC27",
"AC26",
"INF",
"CS16",
"CS15",
"CS14",
"CS13",
"CS12",
"CS11",
"CS10",
"CS9",
"CS8",
"CS7",
"BMUS",
"CS6",
"CS5",
"CS4",
"CS3",
]
.filter((e) => data[e] === "1")
.map(ConvertVersion);
const relevantVersions = [
"OM27",
"OM26",
"AC27",
"AC26",
"INF",
"CS16",
"CS15",
"CS14",
"CS13",
"CS12",
"CS11",
"CS10",
"CS9",
"CS8",
"CS7",
"BMUS",
"CS6",
"CS5",
"CS4",
"CS3",
]
.filter((e) => data[e] === "1")
.map(ConvertVersion);
if (!relevantVersions.includes("27-omni") && !relevantVersions.includes("inf")) {
logger.warn(`Song ${song.title} (${playtype} ${difficulty}) has no relevant versions.`);
continue;
}
if (!relevantVersions.includes("27-omni") && !relevantVersions.includes("inf")) {
logger.warn(`Song ${song.title} (${playtype} ${difficulty}) has no relevant versions.`);
continue;
}
// logger.info(relevantVersions);q
// logger.info(relevantVersions);q
const chart = await db.charts.iidx.findOne({ songID: song.id, difficulty, playtype });
const chart = await db.charts.iidx.findOne({ songID: song.id, difficulty, playtype });
if (!chart) {
logger.error(`Can't find chart ${song.title} (${playtype} ${difficulty})`);
continue;
}
if (!chart) {
logger.error(`Can't find chart ${song.title} (${playtype} ${difficulty})`);
continue;
}
await db.charts.iidx.update({ _id: chart._id }, { $set: { versions: relevantVersions } });
}
await db.charts.iidx.update({ _id: chart._id }, { $set: { versions: relevantVersions } });
}
logger.info("done");
logger.info("done");
process.exit(0);
process.exit(0);
})();
@@ -2,27 +2,27 @@ import db from "../../src/db/db";
import { FolderDocument } from "tachi-common";
(async () => {
const folders = (await db.folders.find({})) as any[];
const folders = (await db.folders.find({})) as any[];
for (const fl of folders) {
const f: FolderDocument = {
folderID: fl.folderID,
game: fl.game,
playtype: fl.playtype,
table: fl.table,
tableIndex: fl.tableIndex,
title: fl.title,
type: fl.query.collection === "charts" ? "charts" : "songs",
data: fl.query.body,
};
for (const fl of folders) {
const f: FolderDocument = {
folderID: fl.folderID,
game: fl.game,
playtype: fl.playtype,
table: fl.table,
tableIndex: fl.tableIndex,
title: fl.title,
type: fl.query.collection === "charts" ? "charts" : "songs",
data: fl.query.body,
};
await db.folders.update(
{
_id: fl._id,
},
{ $set: f }
);
}
await db.folders.update(
{
_id: fl._id,
},
{ $set: f }
);
}
console.log("done");
console.log("done");
})();
+18 -18
View File
@@ -1,24 +1,24 @@
import db from "../../src/db/db";
(async () => {
db.folders
.find({})
// @ts-expect-error ??? monk
.each(async (c, { pause, resume }) => {
pause();
db.folders
.find({})
// @ts-expect-error ??? monk
.each(async (c, { pause, resume }) => {
pause();
await db.folders.update(
{
_id: c._id,
},
{
$set: {
tableIndex: Number(c.tableIndex),
},
}
);
await db.folders.update(
{
_id: c._id,
},
{
$set: {
tableIndex: Number(c.tableIndex),
},
}
);
resume();
})
.then(() => console.log("done"));
resume();
})
.then(() => console.log("done"));
})();
+4 -4
View File
@@ -8,14 +8,14 @@ const logger = CreateLogCtx(__filename);
let parsedXML;
const fileData = fs.readFileSync(
path.join(__dirname, "../../src/test-utils/test-data/s3/valid.xml"),
"utf-8"
path.join(__dirname, "../../src/test-utils/test-data/s3/valid.xml"),
"utf-8"
);
try {
parsedXML = parser.parse(fileData);
parsedXML = parser.parse(fileData);
} catch (err) {
logger.error(err);
logger.error(err);
}
fs.writeFileSync(path.join(__dirname, "s3data.json"), JSON.stringify(parsedXML, null, 4));
+3 -3
View File
@@ -3,7 +3,7 @@ import db from "../../db/db";
import path from "path";
(async () => {
let data = await db.scores.find({ game: "iidx", playtype: "SP" }, { limit: 1000 });
fs.writeFileSync(path.join(__dirname, "data.json"), JSON.stringify(data));
process.exit(0);
const data = await db.scores.find({ game: "iidx", playtype: "SP" }, { limit: 1000 });
fs.writeFileSync(path.join(__dirname, "data.json"), JSON.stringify(data));
process.exit(0);
})();
+70 -70
View File
@@ -6,8 +6,8 @@ import path from "path";
import { config, Difficulties, ESDCore, IIDXBPIData, ChartDocument } from "tachi-common";
import { FindSongOnTitle } from "../src/score-import/database-lookup/song-title";
import {
FindChartWithPTDF,
FindChartWithPTDFVersion,
FindChartWithPTDF,
FindChartWithPTDFVersion,
} from "../src/score-import/database-lookup/chart-ptdf";
import db from "../src/db/db";
import CreateLogCtx from "../src/common/logger";
@@ -23,92 +23,92 @@ const options = program.opts();
const dataLoc = path.join(__dirname, "./bpi-poyashi-data/output.json");
const difficultyResolve: Record<string, [string, string]> = {
3: ["SP", "HYPER"],
4: ["SP", "ANOTHER"],
8: ["DP", "HYPER"],
9: ["DP", "ANOTHER"],
10: ["SP", "LEGGENDARIA"],
11: ["DP", "LEGGENDARIA"],
3: ["SP", "HYPER"],
4: ["SP", "ANOTHER"],
8: ["DP", "HYPER"],
9: ["DP", "ANOTHER"],
10: ["SP", "LEGGENDARIA"],
11: ["DP", "LEGGENDARIA"],
};
async function UpdatePoyashiData() {
let data;
if (options.fetch) {
// lol!
logger.info("Fetching data from github...");
const rj = await fetch(
"https://raw.githubusercontent.com/potakusan/bpim-score-repo/master/output/release.json"
).then((r) => r.json());
let data;
if (options.fetch) {
// lol!
logger.info("Fetching data from github...");
const rj = await fetch(
"https://raw.githubusercontent.com/potakusan/bpim-score-repo/master/output/release.json"
).then((r) => r.json());
logger.info("Fetched data.");
fs.writeFileSync(dataLoc, JSON.stringify(rj));
logger.info("Saved data to output.json.");
logger.info("Fetched data.");
fs.writeFileSync(dataLoc, JSON.stringify(rj));
logger.info("Saved data to output.json.");
data = rj;
} else {
logger.info("Reading data from output.json...");
data = JSON.parse(fs.readFileSync(dataLoc, "utf-8"));
}
data = rj;
} else {
logger.info("Reading data from output.json...");
data = JSON.parse(fs.readFileSync(dataLoc, "utf-8"));
}
const realData: IIDXBPIData[] = [];
for (const d of data.body) {
const res = difficultyResolve[d.difficulty];
const realData: IIDXBPIData[] = [];
for (const d of data.body) {
const res = difficultyResolve[d.difficulty];
if (!res) {
throw new Error(`Unknown difficulty ${d.difficulty}`);
}
if (!res) {
throw new Error(`Unknown difficulty ${d.difficulty}`);
}
const [playtype, diff] = res;
const [playtype, diff] = res;
const tachiSong = await FindSongOnTitle("iidx", d.title);
const tachiSong = await FindSongOnTitle("iidx", d.title);
if (!tachiSong) {
logger.warn(`Cannot find song ${d.title}?`);
continue;
}
if (!tachiSong) {
logger.warn(`Cannot find song ${d.title}?`);
continue;
}
const tachiChart = (await FindChartWithPTDFVersion(
"iidx",
tachiSong.id,
playtype as "SP" | "DP",
diff as Difficulties["iidx:DP" | "iidx:SP"],
"28"
)) as ChartDocument<"iidx:SP" | "iidx:DP">;
const tachiChart = (await FindChartWithPTDFVersion(
"iidx",
tachiSong.id,
playtype as "SP" | "DP",
diff as Difficulties["iidx:DP" | "iidx:SP"],
"28"
)) as ChartDocument<"iidx:SP" | "iidx:DP">;
if (!tachiChart) {
logger.warn(
`Cannot find chart ${tachiSong.title} (${tachiSong.id}) ${playtype}, ${diff}?`
);
continue;
}
if (!tachiChart) {
logger.warn(
`Cannot find chart ${tachiSong.title} (${tachiSong.id}) ${playtype}, ${diff}?`
);
continue;
}
const kavg = Number(d.avg);
const kavg = Number(d.avg);
if (kavg < 0) {
logger.warn(
`${tachiSong.title} (${playtype} ${diff}). Invalid kavg ${d.avg}, Skipping.`
);
continue;
}
if (kavg < 0) {
logger.warn(
`${tachiSong.title} (${playtype} ${diff}). Invalid kavg ${d.avg}, Skipping.`
);
continue;
}
const kesd = ESDCore.CalculateESD(
config.judgementWindows.iidx.SP,
kavg / (tachiChart.data.notecount * 2)
);
const kesd = ESDCore.CalculateESD(
config.judgementWindows.iidx.SP,
kavg / (tachiChart.data.notecount * 2)
);
realData.push({
coef: d.coef === -1 ? null : d.coef,
kavg: Number(d.avg),
wr: Number(d.wr),
chartID: tachiChart.chartID,
kesd,
});
}
realData.push({
coef: d.coef === -1 ? null : d.coef,
kavg: Number(d.avg),
wr: Number(d.wr),
chartID: tachiChart.chartID,
kesd,
});
}
await db["iidx-bpi-data"].remove({});
await db["iidx-bpi-data"].insert(realData);
await db["iidx-bpi-data"].remove({});
await db["iidx-bpi-data"].insert(realData);
logger.info(`Removed all, and inserted ${realData.length} documents.`);
logger.info(`Removed all, and inserted ${realData.length} documents.`);
}
UpdatePoyashiData();
+4 -4
View File
@@ -29,14 +29,14 @@ import {
SessionViewDocument,
} from "tachi-common";
import monk, { TMiddleware } from "monk";
import { MONGO_CONNECTION_URL, MONGO_DATABASE_NAME } from "lib/setup/config";
import CreateLogCtx from "lib/logger/logger";
import { OrphanScoreDocument } from "lib/score-import/import-types/common/types";
import { GetMilisecondsSince } from "utils/misc";
import { ServerConfig } from "lib/setup/config";
const logger = CreateLogCtx(__filename);
let dbName = MONGO_DATABASE_NAME;
let dbName = ServerConfig.MONGO_DATABASE_NAME;
/* istanbul ignore next */
if (process.env.NODE_ENV === "test") {
@@ -46,11 +46,11 @@ if (process.env.NODE_ENV === "test") {
let dbtime: bigint;
/* istanbul ignore next */
if (process.env.NODE_ENV !== "test") {
logger.info(`Connecting to database ${MONGO_CONNECTION_URL}/${dbName}...`);
logger.info(`Connecting to database ${ServerConfig.MONGO_CONNECTION_URL}/${dbName}...`);
dbtime = process.hrtime.bigint();
}
export const monkDB = monk(`${MONGO_CONNECTION_URL}/${dbName}`);
export const monkDB = monk(`${ServerConfig.MONGO_CONNECTION_URL}/${dbName}`);
/* istanbul ignore next */
monkDB
+3 -3
View File
@@ -3,7 +3,7 @@ import monk from "monk";
import { IndexOptions } from "mongodb";
import { ValidDatabases } from "tachi-common";
import CreateLogCtx from "lib/logger/logger";
import { CONF_INFO } from "lib/setup/config";
import { ServerTypeInfo } from "lib/setup/config";
import { ONE_DAY } from "lib/constants/time";
const logger = CreateLogCtx(__filename);
@@ -79,7 +79,7 @@ const staticIndexes: Partial<Record<ValidDatabases, Index[]>> = {
],
"bms-course-lookup": [index({ md5sums: 1 }, UNIQUE)],
"api-tokens": [index({ token: 1 }, UNIQUE), index({ userID: 1 })],
tables: [index({ tableID: 1 }, UNIQUE), index({ game: 1, playtype: 1 })],
tables: [index({ tableID: 1, game: 1, playtype: 1 }, UNIQUE)],
"game-stats-snapshots": [index({ timestamp: 1, userID: 1, game: 1, playtype: 1 }, UNIQUE)],
"session-view-cache": [
index({ sessionID: 1, ip: 1 }, UNIQUE),
@@ -89,7 +89,7 @@ const staticIndexes: Partial<Record<ValidDatabases, Index[]>> = {
const indexes: Partial<Record<ValidDatabases, Index[]>> = staticIndexes;
for (const game of CONF_INFO.supportedGames) {
for (const game of ServerTypeInfo.supportedGames) {
if (indexes[`charts-${game}` as ValidDatabases]) {
indexes[`charts-${game}` as ValidDatabases]!.push(
index({ chartID: 1 }, UNIQUE),
+3 -3
View File
@@ -1,7 +1,7 @@
import deepmerge from "deepmerge";
import { Game, Playtypes, GetGameConfig, GetGamePTConfig } from "tachi-common";
import p, { PrudenceSchema, ValidSchemaValue } from "prudence";
import { CONF_INFO } from "lib/setup/config";
import { ServerTypeInfo } from "lib/setup/config";
const LAZY_EMAIL_REGEX = /^[^\s@]+@[^\s@]+\.[^\s@]{2,}$/u;
@@ -87,7 +87,7 @@ export const PR_SCORE_GENERIC = {
comment: p.nullable(p.isBoundedString(1, 240)),
timeAdded: p.isPositive,
scoreID: "string", // temp
importType: p.nullable(p.isIn(CONF_INFO.supportedImportTypes)),
importType: p.nullable(p.isIn(ServerTypeInfo.supportedImportTypes)),
};
type ScoreSchemas = {
@@ -409,7 +409,7 @@ const PRUDENCE_FOLDER_CHART_LOOKUP: PrudenceSchema = {
const PRUDENCE_FOLDER: PrudenceSchema = {
title: "string",
game: p.isIn(CONF_INFO.supportedGames),
game: p.isIn(ServerTypeInfo.supportedGames),
playtype: (self, parent) => p.isIn(GetGameConfig(parent.game as Game).validPlaytypes)(self),
folderID: "string",
table: "string",
+2 -2
View File
@@ -1,7 +1,7 @@
import redis from "redis";
import { RedisIPCChannels, RedisIPCData } from "tachi-common";
import CreateLogCtx from "lib/logger/logger";
import { CONFIG } from "lib/setup/config";
import { ServerConfig } from "lib/setup/config";
const logger = CreateLogCtx(__filename);
@@ -19,7 +19,7 @@ const SubCallbacks: Partial<SubCallbacks> = {};
const SubClient = redis.createClient();
const PubClient = redis.createClient();
const PREFIX = CONFIG.TYPE.toUpperCase(); // KTCHI or BTCHI
const PREFIX = ServerConfig.TYPE.toUpperCase(); // KTCHI or BTCHI
export function RedisPub<T extends RedisIPCChannels>(channel: T, data: RedisIPCData[T]) {
PubClient.publish(`${PREFIX}-${channel}`, JSON.stringify(data));
+3 -1
View File
@@ -1,11 +1,13 @@
import t from "tap";
import { CDNDelete, CDNRedirect, CDNRetrieve, CDNStore, CDNStoreOrOverwrite } from "./cdn";
import fs from "fs";
import { CDN_FILE_ROOT } from "lib/setup/config";
import { ServerConfig } from "lib/setup/config";
import path from "path";
import { CloseAllConnections } from "test-utils/close-connections";
import expressRequestMock from "express-request-mock";
const CDN_FILE_ROOT = ServerConfig.CDN_FILE_ROOT;
function getTestTxt() {
return fs.readFileSync(path.join(CDN_FILE_ROOT, "test.txt"), "utf-8");
}
+2 -2
View File
@@ -1,10 +1,10 @@
import fs from "fs";
import path from "path";
import { CDN_FILE_ROOT } from "lib/setup/config";
import CreateLogCtx from "lib/logger/logger";
import { promisify } from "util";
import mkdirp from "mkdirp";
import { Response } from "express";
import { ServerConfig } from "lib/setup/config";
const readFilePromise = promisify(fs.readFile);
const writeFilePromise = promisify(fs.writeFile);
@@ -19,7 +19,7 @@ const logger = CreateLogCtx(__filename);
* Path directory traversal *is* possible, and *will* ruin your day.
*/
function CDNRoot(fileLoc: string) {
return path.join(CDN_FILE_ROOT, fileLoc);
return path.join(ServerConfig.CDN_FILE_ROOT, fileLoc);
}
/**
+13
View File
@@ -159,3 +159,16 @@ export enum SDVXVFClasses {
IMPERIAL_III,
IMPERIAL_IV,
}
export enum CHUNITHM_COLOURS {
BLUE,
GREEN,
ORANGE,
RED,
PURPLE,
BRONZE,
SILVER,
GOLD,
PLATINUM,
RAINBOW,
}
+3 -1
View File
@@ -1,8 +1,10 @@
import { LOG_LEVEL } from "lib/setup/config";
import { ServerConfig } from "lib/setup/config";
import t from "tap";
import { CloseAllConnections } from "test-utils/close-connections";
import CreateLogCtx, { ChangeRootLogLevel, GetLogLevel, rootLogger, Transports } from "./logger";
const LOG_LEVEL = ServerConfig.LOG_LEVEL;
t.test("Logger Tests", (t) => {
const logger = CreateLogCtx(__filename);
+2 -2
View File
@@ -1,11 +1,11 @@
import winston, { format, transports, Logger, LeveledLogMethod } from "winston";
import { EscapeStringRegexp } from "utils/misc";
import { LOG_LEVEL } from "lib/setup/config";
import SafeJSONStringify from "safe-json-stringify";
import { ServerConfig } from "lib/setup/config";
export type KtLogger = Logger & { severe: LeveledLogMethod };
const level = LOG_LEVEL ?? "info";
const level = ServerConfig.LOG_LEVEL;
const IN_TESTING = process.env.NODE_ENV === "test";
@@ -13,11 +13,7 @@ import {
import CreateLogCtx from "lib/logger/logger";
import { isApproximately } from "test-utils/asserts";
import { DryScore } from "../common/types";
import {
GetKTDataJSON,
Testing511SPA,
TestingIIDXSPDryScore,
} from "test-utils/test-data";
import { GetKTDataJSON, Testing511SPA, TestingIIDXSPDryScore } from "test-utils/test-data";
import { CloseAllConnections } from "test-utils/close-connections";
import deepmerge from "deepmerge";
import ResetDBState from "test-utils/resets";
@@ -1,6 +1,6 @@
import { Game, Playtypes, integer, ScoreCalculatedDataLookup } from "tachi-common";
import { GameClasses } from "tachi-common/js/game-classes";
import { GitadoraColours, SDVXVFClasses } from "lib/constants/classes";
import { CHUNITHM_COLOURS, GitadoraColours, SDVXVFClasses } from "lib/constants/classes";
import { KtLogger } from "lib/logger/logger";
export function CalculateSDVXClass(
@@ -94,6 +94,41 @@ export function GitadoraSkillToColour(sk: number) {
return GitadoraColours.WHITE;
}
export function CalculateChunithmColour(
game: Game,
playtype: Playtypes[Game],
userID: integer,
ratings: Record<string, number>
) {
const colour = ChuniRatingToColour(ratings.naiveRating);
return { colour };
}
function ChuniRatingToColour(rating: number) {
if (rating >= 15) {
return CHUNITHM_COLOURS.RAINBOW;
} else if (rating >= 14.5) {
return CHUNITHM_COLOURS.PLATINUM;
} else if (rating >= 14) {
return CHUNITHM_COLOURS.GOLD;
} else if (rating >= 13) {
return CHUNITHM_COLOURS.SILVER;
} else if (rating >= 12) {
return CHUNITHM_COLOURS.BRONZE;
} else if (rating >= 10) {
return CHUNITHM_COLOURS.PURPLE;
} else if (rating >= 7) {
return CHUNITHM_COLOURS.RED;
} else if (rating >= 4) {
return CHUNITHM_COLOURS.ORANGE;
} else if (rating >= 2) {
return CHUNITHM_COLOURS.GREEN;
}
return CHUNITHM_COLOURS.BLUE;
}
// export function CalculateJubeatColour(
// game: Game,
// playtype: Playtypes[Game],
@@ -2,7 +2,11 @@ import { Game, Playtypes, integer, UserGameStats, ClassDelta, IDStrings } from "
import { GameClasses } from "tachi-common/js/game-classes";
import deepmerge from "deepmerge";
import { KtLogger } from "lib/logger/logger";
import { CalculateGitadoraColour, CalculateSDVXClass } from "./builtin-class-handlers";
import {
CalculateChunithmColour,
CalculateGitadoraColour,
CalculateSDVXClass,
} from "./builtin-class-handlers";
import { ReturnClassIfGreater } from "utils/class";
import { RedisPub } from "external/redis/redis-IPC";
import { ClassHandler, ScoreClasses } from "./types";
@@ -27,7 +31,9 @@ type ClassHandlerMap = {
const STATIC_CLASS_HANDLERS: ClassHandlerMap = {
iidx: null,
bms: null,
chunithm: null,
chunithm: {
Single: CalculateChunithmColour,
},
ddr: null,
gitadora: {
Gita: CalculateGitadoraColour,
@@ -3,7 +3,7 @@ import nodeFetch from "utils/fetch";
import { TraverseKaiAPI } from "../../common/api-kai/traverse-api";
import { ParserFunctionReturns } from "../../common/types";
import { EmptyObject } from "utils/types";
import { ARC_API_URL, ARC_AUTH_TOKEN } from "lib/setup/config";
import { ServerConfig } from "lib/setup/config";
export function ParseArcDDR(
arcProfileID: string,
@@ -12,10 +12,10 @@ export function ParseArcDDR(
): ParserFunctionReturns<unknown, EmptyObject> {
return {
iterable: TraverseKaiAPI(
ARC_API_URL,
ServerConfig.ARC_API_URL,
// DDR Ace.
`/api/v1/ddr/16/player_bests?profile_id=${arcProfileID}`,
ARC_AUTH_TOKEN,
ServerConfig.ARC_AUTH_TOKEN,
logger,
fetch
),
@@ -1,8 +1,8 @@
import nodeFetch from "utils/fetch";
import { HasOwnProperty } from "utils/misc";
import { IIDXClasses } from "lib/constants/classes";
import { ARC_API_URL } from "lib/setup/config";
import { ClassHandler } from "../../../framework/user-game-stats/types";
import { ServerConfig } from "lib/setup/config";
export async function CreateArcIIDXClassHandler(
profileID: string,
@@ -16,11 +16,14 @@ export async function CreateArcIIDXClassHandler(
// 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(`${ARC_API_URL}/api/v1/iidx/27/profiles?_id=${profileID}`, {
headers: {
Authorization: `Bearer ${token}`,
},
});
const res = await fetch(
`${ServerConfig.ARC_API_URL}/api/v1/iidx/27/profiles?_id=${profileID}`,
{
headers: {
Authorization: `Bearer ${token}`,
},
}
);
json = await res.json();
} catch (e) {
@@ -29,7 +32,10 @@ export async function CreateArcIIDXClassHandler(
return (game, playtype, userID, ratings, logger) => {
if (err) {
logger.error(`An error occured while updating classes for ${ARC_API_URL}.`, { err });
logger.error(
`An error occured while updating classes for ${ServerConfig.ARC_API_URL}.`,
{ err }
);
return {};
}
@@ -3,7 +3,7 @@ import nodeFetch from "utils/fetch";
import { TraverseKaiAPI } from "../../common/api-kai/traverse-api";
import { ParserFunctionReturns } from "../../common/types";
import { EmptyObject } from "utils/types";
import { ARC_API_URL, ARC_AUTH_TOKEN } from "lib/setup/config";
import { ServerConfig } from "lib/setup/config";
import { CreateArcIIDXClassHandler } from "./class-handler";
export async function ParseArcIIDX(
@@ -13,15 +13,15 @@ export async function ParseArcIIDX(
): Promise<ParserFunctionReturns<unknown, EmptyObject>> {
return {
iterable: TraverseKaiAPI(
ARC_API_URL,
ServerConfig.ARC_API_URL,
// HEROIC VERSE
`/api/v1/iidx/27/player_bests?profile_id=${arcProfileID}`,
ARC_AUTH_TOKEN,
ServerConfig.ARC_AUTH_TOKEN,
logger,
fetch
),
context: {},
classHandler: await CreateArcIIDXClassHandler(arcProfileID, ARC_AUTH_TOKEN),
classHandler: await CreateArcIIDXClassHandler(arcProfileID, ServerConfig.ARC_AUTH_TOKEN),
game: "iidx",
};
}
@@ -3,7 +3,7 @@ import nodeFetch from "utils/fetch";
import { TraverseKaiAPI } from "../../common/api-kai/traverse-api";
import { ParserFunctionReturns } from "../../common/types";
import { EmptyObject } from "utils/types";
import { ARC_API_URL, ARC_AUTH_TOKEN } from "lib/setup/config";
import { ServerConfig } from "lib/setup/config";
export function ParseArcSDVX(
arcProfileID: string,
@@ -12,10 +12,10 @@ export function ParseArcSDVX(
): ParserFunctionReturns<unknown, EmptyObject> {
return {
iterable: TraverseKaiAPI(
ARC_API_URL,
ServerConfig.ARC_API_URL,
// VIVID WAVE.
`/api/v1/sdvx/5/player_bests?profile_id=${arcProfileID}`,
ARC_AUTH_TOKEN,
ServerConfig.ARC_AUTH_TOKEN,
logger,
fetch
),
@@ -1,11 +1,7 @@
import t from "tap";
import { CloseAllConnections } from "test-utils/close-connections";
import ResetDBState from "test-utils/resets";
import {
GetKTDataJSON,
Testing511Song,
Testing511SPA,
} from "test-utils/test-data";
import { GetKTDataJSON, Testing511Song, Testing511SPA } from "test-utils/test-data";
import CreateLogCtx from "lib/logger/logger";
import { ConvertAPIKaiIIDX } from "./converter";
import deepmerge from "deepmerge";
@@ -4,7 +4,7 @@ import { KaiAuthDocument } from "tachi-common";
import { KaiContext } from "../types";
import { TraverseKaiAPI } from "../traverse-api";
import { ParserFunctionReturns } from "../../types";
import { FLO_API_URL, EAG_API_URL } from "lib/setup/config";
import { ServerConfig } from "lib/setup/config";
export function ParseKaiIIDX(
service: "FLO" | "EAG",
@@ -12,7 +12,7 @@ export function ParseKaiIIDX(
logger: KtLogger,
fetch = nodeFetch
): ParserFunctionReturns<unknown, KaiContext> {
const baseUrl = service === "FLO" ? FLO_API_URL : EAG_API_URL;
const baseUrl = service === "FLO" ? ServerConfig.FLO_API_URL : ServerConfig.EAG_API_URL;
return {
iterable: TraverseKaiAPI(
@@ -1,11 +1,7 @@
import t from "tap";
import { CloseAllConnections } from "test-utils/close-connections";
import ResetDBState from "test-utils/resets";
import {
GetKTDataJSON,
TestingAlbidaADV,
TestingSDVXAlbidaSong,
} from "test-utils/test-data";
import { GetKTDataJSON, TestingAlbidaADV, TestingSDVXAlbidaSong } from "test-utils/test-data";
import CreateLogCtx from "lib/logger/logger";
import { ConvertAPIKaiSDVX, ConvertDifficulty, ConvertVersion, ResolveKaiLamp } from "./converter";
import deepmerge from "deepmerge";
@@ -4,7 +4,7 @@ import { KaiAuthDocument } from "tachi-common";
import { KaiContext } from "../types";
import { TraverseKaiAPI } from "../traverse-api";
import { ParserFunctionReturns } from "../../types";
import { EAG_API_URL, FLO_API_URL } from "lib/setup/config";
import { ServerConfig } from "lib/setup/config";
export function ParseKaiSDVX(
service: "FLO" | "EAG",
@@ -12,7 +12,7 @@ export function ParseKaiSDVX(
logger: KtLogger,
fetch = nodeFetch
): ParserFunctionReturns<unknown, KaiContext> {
const baseUrl = service === "FLO" ? FLO_API_URL : EAG_API_URL;
const baseUrl = service === "FLO" ? ServerConfig.FLO_API_URL : ServerConfig.EAG_API_URL;
return {
iterable: TraverseKaiAPI(
@@ -2,7 +2,7 @@ import { KtLogger } from "lib/logger/logger";
import ScoreImportFatalError from "../../../framework/score-importing/score-import-error";
import nodeFetch from "utils/fetch";
import { VERSION_STR } from "lib/constants/version";
import { CONF_INFO } from "lib/setup/config";
import { ServerTypeInfo } from "lib/setup/config";
/**
* Traverses a Kai-like personal_bests api.
@@ -42,7 +42,7 @@ export async function* TraverseKaiAPI(
const res = await fetch(url, {
headers: {
Authorization: `Bearer ${token}`,
"User-Agent": `${CONF_INFO.name}/${VERSION_STR}`,
"User-Agent": `${ServerTypeInfo.name}/${VERSION_STR}`,
},
});
@@ -61,7 +61,7 @@ export async function* TraverseKaiAPI(
throw new ScoreImportFatalError(
500,
`Recieved no _links prop from ${url}. This is not an error with ${CONF_INFO.name}.`
`Recieved no _links prop from ${url}. This is not an error with ${ServerTypeInfo.name}.`
);
}
@@ -6,7 +6,7 @@ import { Game, ImportTypes, GetGamePTConfig, Playtypes, GetGameConfig } from "ta
import deepmerge from "deepmerge";
import { FormatPrError } from "utils/prudence";
import { ParserFunctionReturns } from "../types";
import { CONF_INFO } from "lib/setup/config";
import { ServerTypeInfo } from "lib/setup/config";
const optNull = (v: ValidSchemaValue) => p.optional(p.nullable(v));
@@ -71,6 +71,7 @@ const PR_BatchManualScore = (game: Game, playtype: Playtypes[Game]): PrudenceSch
}
for (const key in self) {
// @ts-expect-error check
if (!gptConfig.judgements.includes(key)) {
return `Invalid Key ${key}. Expected any of ${gptConfig.judgements.join(", ")}`;
}
@@ -95,7 +96,7 @@ const PR_BatchManualScore = (game: Game, playtype: Playtypes[Game]): PrudenceSch
const PR_BatchManual = (game: Game, playtype: Playtypes[Game]): PrudenceSchema => ({
meta: {
service: p.isBoundedString(3, 15),
game: p.isIn(CONF_INFO.supportedGames),
game: p.isIn(ServerTypeInfo.supportedGames),
playtype: p.is(playtype),
version: "*?string",
},
@@ -144,10 +145,12 @@ export function ParseBatchManualFromObject(
);
}
if (!CONF_INFO.supportedGames.includes(possiblyGame)) {
if (!ServerTypeInfo.supportedGames.includes(possiblyGame)) {
throw new ScoreImportFatalError(
400,
`Invalid game ${possiblyGame} - expected any of ${CONF_INFO.supportedGames.join(", ")}.`
`Invalid game ${possiblyGame} - expected any of ${ServerTypeInfo.supportedGames.join(
", "
)}.`
);
}
@@ -2,10 +2,7 @@ import t from "tap";
import CreateLogCtx from "lib/logger/logger";
import ScoreImportFatalError from "../../../framework/score-importing/score-import-error";
import GenericParseEamIIDXCSV, { NaiveCSVParse, ResolveHeaders } from "./parser";
import {
TestingIIDXEamusementCSV26,
TestingIIDXEamusementCSV27,
} from "test-utils/test-data";
import { TestingIIDXEamusementCSV26, TestingIIDXEamusementCSV27 } from "test-utils/test-data";
import { MockMulterFile } from "test-utils/mock-multer";
import { CloseAllConnections } from "test-utils/close-connections";
+2 -2
View File
@@ -14,7 +14,7 @@ import {
} from "tachi-common";
import { EscapeStringRegexp } from "utils/misc";
import { GetOnlineCutoff, OMIT_PRIVATE_USER_RETURNS } from "utils/user";
import { CONF_INFO } from "lib/setup/config";
import { ServerTypeInfo } from "lib/setup/config";
const logger = CreateLogCtx(__filename);
@@ -165,7 +165,7 @@ async function SearchAllGamesSingleGame(game: Game, search: string) {
export async function SearchAllGamesSongs(search: string) {
const promises = [];
for (const game of CONF_INFO.supportedGames) {
for (const game of ServerTypeInfo.supportedGames) {
promises.push(SearchAllGamesSingleGame(game, search));
}
+10 -35
View File
@@ -50,11 +50,10 @@ export interface TachiConfig {
CDN_FILE_ROOT: string;
TYPE: "ktchi" | "btchi" | "omni";
PORT: integer;
CLIENT_INDEX_HTML_PATH: string;
ENABLE_SERVER_HTTPS: boolean;
RUN_OWN_CDN: boolean;
ENABLE_SERVER_HTTPS?: boolean;
RUN_OWN_CDN?: boolean;
CLIENT_DEV_SERVER?: string | null;
TYPE_INFO: StaticConfig.ServerConfig;
SERVER_TYPE_INFO: StaticConfig.ServerConfig;
}
const err = p(config, {
@@ -69,9 +68,8 @@ const err = p(config, {
ARC_AUTH_TOKEN: "string",
CDN_FILE_ROOT: "string",
PORT: p.isPositiveInteger,
CLIENT_INDEX_HTML_PATH: "string",
ENABLE_SERVER_HTTPS: "boolean",
RUN_OWN_CDN: "boolean",
ENABLE_SERVER_HTTPS: "*boolean",
RUN_OWN_CDN: "*boolean",
CLIENT_DEV_SERVER: "*?string",
TYPE: p.isIn("ktchi", "btchi", "omni"),
});
@@ -81,37 +79,14 @@ if (err) {
}
if (config.TYPE === "ktchi") {
config.TYPE_INFO = StaticConfig.KTCHI_CONFIG;
config.SERVER_TYPE_INFO = StaticConfig.KTCHI_CONFIG;
} else if (config.TYPE === "btchi") {
config.TYPE_INFO = StaticConfig.BTCHI_CONFIG;
config.SERVER_TYPE_INFO = StaticConfig.BTCHI_CONFIG;
} else if (config.TYPE === "omni") {
config.TYPE_INFO = StaticConfig.OMNI_CONFIG;
config.SERVER_TYPE_INFO = StaticConfig.OMNI_CONFIG;
}
const tachiConfig = config as TachiConfig;
// note: we dont use fs.exists here because the file may be moved underfoot.
try {
fs.readFileSync(config.CLIENT_INDEX_HTML_PATH);
} catch (err) {
logger.error(`Error while opening file at CLIENT_INDEX_HTML_PATH. Is one here?`);
process.exit(1);
}
export const MONGO_CONNECTION_URL = tachiConfig.MONGO_CONNECTION_URL;
export const MONGO_DATABASE_NAME = tachiConfig.MONGO_DATABASE_NAME;
export const LOG_LEVEL = tachiConfig.LOG_LEVEL;
export const SESSION_SECRET = tachiConfig.SESSION_SECRET;
export const CAPTCHA_SECRET_KEY = tachiConfig.CAPTCHA_SECRET_KEY;
export const FLO_API_URL = tachiConfig.FLO_API_URL;
export const EAG_API_URL = tachiConfig.EAG_API_URL;
export const ARC_API_URL = tachiConfig.ARC_API_URL;
export const ARC_AUTH_TOKEN = tachiConfig.ARC_AUTH_TOKEN;
export const CDN_FILE_ROOT = tachiConfig.CDN_FILE_ROOT;
export const CONF_INFO = tachiConfig.TYPE_INFO;
export const PORT = tachiConfig.PORT;
export const CONFIG = tachiConfig;
export const CLIENT_INDEX_HTML_PATH = tachiConfig.CLIENT_INDEX_HTML_PATH;
export const ENABLE_SERVER_HTTPS = tachiConfig.ENABLE_SERVER_HTTPS;
export const RUN_OWN_CDN = tachiConfig.RUN_OWN_CDN;
export const CLIENT_DEV_SERVER = tachiConfig.CLIENT_DEV_SERVER;
export const ServerTypeInfo = tachiConfig.SERVER_TYPE_INFO;
export const ServerConfig = tachiConfig;
+8 -8
View File
@@ -1,6 +1,6 @@
import CreateLogCtx from "lib/logger/logger";
import server from "server/server";
import { CONF_INFO, LOG_LEVEL, PORT, ENABLE_SERVER_HTTPS } from "lib/setup/config";
import { ServerTypeInfo, ServerConfig } from "lib/setup/config";
import https from "https";
import fs from "fs";
@@ -8,10 +8,10 @@ import { FormatVersion } from "./lib/constants/version";
const logger = CreateLogCtx(__filename);
logger.info(`Booting ${CONF_INFO.name} - ${FormatVersion()} [ENV: ${process.env.NODE_ENV}]`);
logger.info(`Log level is set to ${LOG_LEVEL}.`);
logger.info(`Booting ${ServerTypeInfo.name} - ${FormatVersion()} [ENV: ${process.env.NODE_ENV}]`);
logger.info(`Log level is set to ${ServerConfig.LOG_LEVEL}.`);
if (ENABLE_SERVER_HTTPS) {
if (ServerConfig.ENABLE_SERVER_HTTPS) {
logger.warn(
"HTTPS Mode is enabled. This should not be used in production, and you should instead run behind a reverse proxy."
);
@@ -20,9 +20,9 @@ if (ENABLE_SERVER_HTTPS) {
const httpsServer = https.createServer({ key: privateKey, cert: certificate }, server);
httpsServer.listen(PORT);
logger.info(`HTTPS Listening on port ${PORT}`);
httpsServer.listen(ServerConfig.PORT);
logger.info(`HTTPS Listening on port ${ServerConfig.PORT}`);
} else {
server.listen(PORT);
logger.info(`HTTP Listening on port ${PORT}`);
server.listen(ServerConfig.PORT);
logger.info(`HTTP Listening on port ${ServerConfig.PORT}`);
}
+2 -2
View File
@@ -1,5 +1,5 @@
import RateLimitRedis from "rate-limit-redis";
import { CONFIG } from "lib/setup/config";
import { ServerConfig } from "lib/setup/config";
import rateLimit from "express-rate-limit";
import CreateLogCtx from "lib/logger/logger";
import { RedisClient } from "external/redis/redis";
@@ -8,7 +8,7 @@ const logger = CreateLogCtx(__filename);
const store =
process.env.NODE_ENV === "production"
? new RateLimitRedis({ prefix: `${CONFIG.TYPE}-RL:`, client: RedisClient })
? new RateLimitRedis({ prefix: `${ServerConfig.TYPE}-RL:`, client: RedisClient })
: undefined; // undefined forces a default to an in-memory store
export function ClearTestingRateLimitCache() {
+3 -3
View File
@@ -1,4 +1,4 @@
import { CONFIG } from "lib/setup/config";
import { ServerConfig } from "lib/setup/config";
import { RequestHandler } from "express";
/**
@@ -7,7 +7,7 @@ import { RequestHandler } from "express";
* this restriction is bypassed.
*/
export const RequireBokutachi: RequestHandler = (req, res, next) => {
if (CONFIG.TYPE === "btchi" || CONFIG.TYPE === "omni") {
if (ServerConfig.TYPE === "btchi" || ServerConfig.TYPE === "omni") {
return next();
}
@@ -23,7 +23,7 @@ export const RequireBokutachi: RequestHandler = (req, res, next) => {
* this restriction is bypassed.
*/
export const RequireKamaitachi: RequestHandler = (req, res, next) => {
if (CONFIG.TYPE === "ktchi" || CONFIG.TYPE === "omni") {
if (ServerConfig.TYPE === "ktchi" || ServerConfig.TYPE === "omni") {
return next();
}
@@ -1,11 +1,13 @@
import { ONE_MINUTE } from "lib/constants/time";
import { ChangeRootLogLevel, GetLogLevel } from "lib/logger/logger";
import { LOG_LEVEL } from "lib/setup/config";
import { ServerConfig } from "lib/setup/config";
import t from "tap";
import { CloseAllConnections } from "test-utils/close-connections";
import { CreateFakeAuthCookie } from "test-utils/fake-auth";
import mockApi from "test-utils/mock-api";
const LOG_LEVEL = ServerConfig.LOG_LEVEL;
t.test("POST /api/v1/admin/change-log-level", async (t) => {
t.beforeEach(() => {
ChangeRootLogLevel(LOG_LEVEL);
@@ -5,7 +5,7 @@ import CreateLogCtx, { ChangeRootLogLevel, GetLogLevel } from "lib/logger/logger
import prValidate from "server/middleware/prudence-validate";
import { GetUserWithID } from "utils/user";
import { ONE_MINUTE } from "lib/constants/time";
import { LOG_LEVEL } from "lib/setup/config";
import { ServerConfig } from "lib/setup/config";
const logger = CreateLogCtx(__filename);
@@ -42,6 +42,8 @@ const RequireAdminLevel: RequestHandler = async (req, res, next) => {
return next();
};
const LOG_LEVEL = ServerConfig.LOG_LEVEL;
router.use(RequireAdminLevel);
let currentLogLevelTimer: NodeJS.Timeout | null = null;
+2 -2
View File
@@ -6,8 +6,8 @@ import { GetNextCounterValue } from "utils/db";
import CreateLogCtx from "lib/logger/logger";
import { FormatUserDoc } from "utils/user";
import nodeFetch from "utils/fetch";
import { CAPTCHA_SECRET_KEY } from "lib/setup/config";
import { Random20Hex } from "utils/misc";
import { ServerConfig } from "lib/setup/config";
const logger = CreateLogCtx(__filename);
@@ -104,7 +104,7 @@ export async function ValidateCaptcha(
fetch = nodeFetch
) {
const r = await fetch(
`https://www.google.com/recaptcha/api/siteverify?secret=${CAPTCHA_SECRET_KEY}&response=${recaptcha}&remoteip=${remoteAddr}`
`https://www.google.com/recaptcha/api/siteverify?secret=${ServerConfig.CAPTCHA_SECRET_KEY}&response=${recaptcha}&remoteip=${remoteAddr}`
);
if (r.status !== 200) {
@@ -1,5 +1,5 @@
import { RequestHandler } from "express";
import { CONF_INFO } from "lib/setup/config";
import { ServerTypeInfo } from "lib/setup/config";
import { IsValidGame } from "utils/misc";
import { AssignToReqTachiData } from "utils/req-tachi-data";
@@ -9,7 +9,7 @@ export const ValidateGameFromParam: RequestHandler = (req, res, next) => {
success: false,
description: `Invalid/unsupported game ${
req.params.game
} - Expected any of ${CONF_INFO.supportedGames.join(", ")}`,
} - Expected any of ${ServerTypeInfo.supportedGames.join(", ")}`,
});
}
@@ -1,6 +1,6 @@
import { GetGameConfig } from "tachi-common";
import t from "tap";
import { CONF_INFO } from "lib/setup/config";
import { ServerTypeInfo } from "lib/setup/config";
import { CloseAllConnections } from "test-utils/close-connections";
import mockApi from "test-utils/mock-api";
@@ -9,10 +9,10 @@ t.test("GET /api/v1/games", async (t) => {
// and also returns configs properly.
const res = await mockApi.get("/api/v1/games");
t.strictSame(res.body.body.supportedGames, CONF_INFO.supportedGames);
t.strictSame(res.body.body.supportedGames, ServerTypeInfo.supportedGames);
t.strictSame(res.body.body.configs.iidx, GetGameConfig("iidx"));
t.equal(Object.keys(res.body.body.configs).length, CONF_INFO.supportedGames.length);
t.equal(Object.keys(res.body.body.configs).length, ServerTypeInfo.supportedGames.length);
t.end();
});
@@ -1,5 +1,5 @@
import { Router } from "express";
import { CONF_INFO } from "lib/setup/config";
import { ServerTypeInfo } from "lib/setup/config";
import { GetGameConfig } from "tachi-common";
import gameRouter from "./_game/router";
@@ -13,13 +13,15 @@ const router: Router = Router({ mergeParams: true });
*/
router.get("/", (req, res) => {
// this line is a bit too 'smart' for its own good, but whatever.
const configs = Object.fromEntries(CONF_INFO.supportedGames.map((e) => [e, GetGameConfig(e)]));
const configs = Object.fromEntries(
ServerTypeInfo.supportedGames.map((e) => [e, GetGameConfig(e)])
);
return res.status(200).json({
success: true,
description: `Returned support information for ${CONF_INFO.supportedGames.length} game(s).`,
description: `Returned support information for ${ServerTypeInfo.supportedGames.length} game(s).`,
body: {
supportedGames: CONF_INFO.supportedGames,
supportedGames: ServerTypeInfo.supportedGames,
configs,
},
});
@@ -14,7 +14,7 @@ import ParseBatchManual from "lib/score-import/import-types/file/batch-manual/pa
import { ParseSolidStateXML } from "lib/score-import/import-types/file/solid-state-squad/parser";
import { ParseMerIIDX } from "lib/score-import/import-types/file/mer-iidx/parser";
import ParsePLIIIDXCSV from "lib/score-import/import-types/file/pli-iidx-csv/parser";
import { CONF_INFO } from "lib/setup/config";
import { ServerTypeInfo } from "lib/setup/config";
import { RequirePermissions } from "server/middleware/auth";
const logger = CreateLogCtx(__filename);
@@ -37,7 +37,7 @@ router.post(
ParseMultipartScoredata,
prValidate(
{
importType: Prudence.isIn(CONF_INFO.supportedImportTypes),
importType: Prudence.isIn(ServerTypeInfo.supportedImportTypes),
},
{},
{ allowExcessKeys: true }
@@ -144,7 +144,7 @@ router.get("/:chartID", async (req, res) => {
return res.status(200).json({
success: true,
description: `Successfull retrieved PB for user.`,
description: `Successfully retrieved PB for user.`,
body: {
scores,
chart,
-17
View File
@@ -1,17 +0,0 @@
import t from "tap";
import { CloseAllConnections } from "test-utils/close-connections";
import mockApi from "test-utils/mock-api";
t.test("GET /", (t) => {
t.test("Should return our index.html", async (t) => {
const res = await mockApi.get("/");
t.equal(res.text, "<div>Hello World.</div>");
t.end();
});
t.end();
});
t.teardown(CloseAllConnections);
+9 -35
View File
@@ -3,15 +3,7 @@ import "express-async-errors";
import expressSession from "express-session";
import { integer } from "tachi-common";
import { RedisClient } from "external/redis/redis";
import {
CDN_FILE_ROOT,
CLIENT_DEV_SERVER,
CLIENT_INDEX_HTML_PATH,
CONFIG,
ENABLE_SERVER_HTTPS,
RUN_OWN_CDN,
SESSION_SECRET,
} from "lib/setup/config";
import { ServerConfig } from "lib/setup/config";
import connectRedis from "connect-redis";
import helmet from "helmet";
import fs from "fs";
@@ -35,24 +27,24 @@ const userSessionMiddleware = expressSession({
// append node_env onto the end of the session name
// so we can separate tokens under the same URL.
// say for staging.kamaitachi.xyz
name: `${CONFIG.TYPE}_${process.env.NODE_ENV}_session`,
secret: SESSION_SECRET,
name: `${ServerConfig.TYPE}_${process.env.NODE_ENV}_session`,
secret: ServerConfig.SESSION_SECRET,
store,
resave: true,
saveUninitialized: false,
cookie: {
secure: process.env.NODE_ENV === "production" || ENABLE_SERVER_HTTPS,
secure: process.env.NODE_ENV === "production" || ServerConfig.ENABLE_SERVER_HTTPS,
},
});
const app: Express = express();
if (process.env.NODE_ENV !== "production" && CLIENT_DEV_SERVER) {
logger.warn(`Enabling CORS requests from ${CLIENT_DEV_SERVER}.`);
if (process.env.NODE_ENV !== "production" && ServerConfig.CLIENT_DEV_SERVER) {
logger.warn(`Enabling CORS requests from ${ServerConfig.CLIENT_DEV_SERVER}.`);
// Allow CORS requests from another server (since we have our dev server hosted separately).
app.use((req, res, next) => {
res.header("Access-Control-Allow-Origin", CLIENT_DEV_SERVER!);
res.header("Access-Control-Allow-Origin", ServerConfig.CLIENT_DEV_SERVER!);
res.header(
"Access-Control-Allow-Headers",
"Origin, X-Requested-With, Content-Type, Accept"
@@ -112,7 +104,7 @@ app.use("/", mainRouter);
// The RUN_OWN_CDN option means that our /cdn path has to be hosted by us. In production,
// this is not the case (we have a dedicated nginx box for it running in a separate process).
// In dev, this is a pain to setup, so we can just run it locally.
if (RUN_OWN_CDN) {
if (ServerConfig.RUN_OWN_CDN) {
if (process.env.NODE_ENV === "production") {
logger.warn(
`Running OWN_CDN in production. Consider making a separate process handle your CDN for performance.`
@@ -121,28 +113,10 @@ if (RUN_OWN_CDN) {
logger.info("Running own CDN.");
}
app.use("/cdn", express.static(CDN_FILE_ROOT));
app.use("/cdn", express.static(ServerConfig.CDN_FILE_ROOT));
app.get("/cdn/*", (req, res) => res.status(404).send("No content here."));
}
const indexHTMLContent = fs.readFileSync(CLIENT_INDEX_HTML_PATH);
/**
* If any user gets to this point, we send them index.html and yield routing to
* the ktchi-client react router.
* @name GET *
*/
app.get("*", (req, res) => res.setHeader("Content-Type", "text/html").send(indexHTMLContent));
/**
* If any user gets to this point, and are not making a GET request, they are probably making an API request.
* And want JSON back.
* @name ALL (except GET) *
*/
app.all("*", (req, res) =>
res.status(404).json({ success: false, description: "404: This URL does not exist." })
);
// completely stolen from ktapi error handler
interface ExpressJSONErr extends SyntaxError {
status: integer;
+3 -3
View File
@@ -7,8 +7,8 @@ import path from "path";
import CreateLogCtx from "lib/logger/logger";
// im installing an entire library for rm rf...
import rimraf from "rimraf";
import { CDN_FILE_ROOT, MONGO_CONNECTION_URL } from "lib/setup/config";
import { SetIndexes } from "external/mongo/indexes";
import { ServerConfig } from "lib/setup/config";
const logger = CreateLogCtx(__filename);
@@ -79,7 +79,7 @@ export default async function ResetDBState() {
export function ResetCDN() {
return new Promise<void>((resolve, reject) =>
rimraf(CDN_FILE_ROOT, (err) => {
rimraf(ServerConfig.CDN_FILE_ROOT, (err) => {
if (err) {
reject(err);
}
@@ -89,7 +89,7 @@ export function ResetCDN() {
}
export async function SetIndexesForDB() {
const url = `${MONGO_CONNECTION_URL}/testingdb`;
const url = `${ServerConfig.MONGO_CONNECTION_URL}/testingdb`;
logger.info(`Setting indexes for ${url}`);
+3
View File
@@ -171,6 +171,9 @@ export async function GetFoldersFromTable(table: TableDocument) {
);
}
// we also need to sort folders in their indexed order.
folders.sort((a, b) => table.folders.indexOf(a.folderID) - table.folders.indexOf(b.folderID));
return folders;
}
+2 -2
View File
@@ -1,5 +1,5 @@
import crypto from "crypto";
import { CONF_INFO } from "lib/setup/config";
import { 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
@@ -62,7 +62,7 @@ export function HasOwnProperty<T>(obj: T, key: string | number | symbol): key is
}
export function IsValidGame(str: string): str is Game {
return !!CONF_INFO.supportedGames.includes(str as Game);
return !!ServerTypeInfo.supportedGames.includes(str as Game);
}
export function IsValidPlaytype(game: Game, str: string): str is Playtypes[Game] {