Add TTL cache for game version/loader APIs and enrich upload metadata
This commit is contained in:
parent
7ddbd36c63
commit
e8d4994cec
@ -5,31 +5,36 @@ import {
|
|||||||
type GameVersionType,
|
type GameVersionType,
|
||||||
type GameVersion,
|
type GameVersion,
|
||||||
} from "@/types";
|
} from "@/types";
|
||||||
|
import { createTtlCache } from "@/lib/utils/cache";
|
||||||
|
|
||||||
|
const TTL = 3_600_000; // 1 hour
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 获取 CurseForge 支持的 Game Version Type 列表。
|
* 获取 CurseForge 支持的 Game Version Type 列表(1h 缓存)。
|
||||||
* GET /api/game/version-types
|
* GET /api/game/version-types
|
||||||
*/
|
*/
|
||||||
export async function getVersionTypes(
|
export const getVersionTypes = createTtlCache(
|
||||||
client: CurseForgeClient,
|
async (client: CurseForgeClient): Promise<GameVersionType[]> => {
|
||||||
): Promise<GameVersionType[]> {
|
const data = await client.uploadGet<unknown[]>(
|
||||||
const data = await client.uploadGet<unknown[]>(
|
"/api/game/version-types",
|
||||||
"/api/game/version-types",
|
);
|
||||||
);
|
return GameVersionTypeSchema.array().parse(data);
|
||||||
return GameVersionTypeSchema.array().parse(data);
|
},
|
||||||
}
|
TTL,
|
||||||
|
);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 获取 CurseForge 支持的 Game Version 列表。
|
* 获取 CurseForge 支持的 Game Version 列表(1h 缓存)。
|
||||||
* 包含 Minecraft 版本、Mod Loader、Environment、Java 等。
|
* 包含 Minecraft 版本、Mod Loader、Environment、Java 等。
|
||||||
* 通过 gameVersionTypeID 区分类型。
|
* 通过 gameVersionTypeID 区分类型。
|
||||||
* GET /api/game/versions
|
* GET /api/game/versions
|
||||||
*/
|
*/
|
||||||
export async function getGameVersions(
|
export const getGameVersions = createTtlCache(
|
||||||
client: CurseForgeClient,
|
async (client: CurseForgeClient): Promise<GameVersion[]> => {
|
||||||
): Promise<GameVersion[]> {
|
const data = await client.uploadGet<unknown[]>(
|
||||||
const data = await client.uploadGet<unknown[]>(
|
"/api/game/versions",
|
||||||
"/api/game/versions",
|
);
|
||||||
);
|
return GameVersionSchema.array().parse(data);
|
||||||
return GameVersionSchema.array().parse(data);
|
},
|
||||||
}
|
TTL,
|
||||||
|
);
|
||||||
|
|||||||
@ -5,25 +5,30 @@ import {
|
|||||||
type LoaderTag,
|
type LoaderTag,
|
||||||
type GameVersionTag,
|
type GameVersionTag,
|
||||||
} from "@/types";
|
} from "@/types";
|
||||||
|
import { createTtlCache } from "@/lib/utils/cache";
|
||||||
|
|
||||||
|
const TTL = 3_600_000; // 1 hour
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 获取 Modrinth 支持的全部模组加载器列表。
|
* 获取 Modrinth 支持的全部模组加载器列表(1h 缓存)。
|
||||||
* GET /tag/loader
|
* GET /tag/loader
|
||||||
*/
|
*/
|
||||||
export async function getLoaders(
|
export const getLoaders = createTtlCache(
|
||||||
client: ModrinthClient,
|
async (client: ModrinthClient): Promise<LoaderTag[]> => {
|
||||||
): Promise<LoaderTag[]> {
|
const data = await client.get<unknown[]>("/tag/loader");
|
||||||
const data = await client.get<unknown[]>("/tag/loader");
|
return LoaderTagSchema.array().parse(data);
|
||||||
return LoaderTagSchema.array().parse(data);
|
},
|
||||||
}
|
TTL,
|
||||||
|
);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 获取 Modrinth 支持的全部 Minecraft 版本列表。
|
* 获取 Modrinth 支持的全部 Minecraft 版本列表(1h 缓存)。
|
||||||
* GET /tag/game_version
|
* GET /tag/game_version
|
||||||
*/
|
*/
|
||||||
export async function getGameVersions(
|
export const getGameVersions = createTtlCache(
|
||||||
client: ModrinthClient,
|
async (client: ModrinthClient): Promise<GameVersionTag[]> => {
|
||||||
): Promise<GameVersionTag[]> {
|
const data = await client.get<unknown[]>("/tag/game_version");
|
||||||
const data = await client.get<unknown[]>("/tag/game_version");
|
return GameVersionTagSchema.array().parse(data);
|
||||||
return GameVersionTagSchema.array().parse(data);
|
},
|
||||||
}
|
TTL,
|
||||||
|
);
|
||||||
|
|||||||
16
src/lib/utils/cache.ts
Normal file
16
src/lib/utils/cache.ts
Normal file
@ -0,0 +1,16 @@
|
|||||||
|
export function createTtlCache<T>(
|
||||||
|
factory: (...args: any[]) => Promise<T>,
|
||||||
|
ttlMs: number,
|
||||||
|
keyFn?: (...args: any[]) => string,
|
||||||
|
): (...args: any[]) => Promise<T> {
|
||||||
|
const cache = new Map<string, { data: T; ts: number }>();
|
||||||
|
|
||||||
|
return async (...args) => {
|
||||||
|
const key = keyFn ? keyFn(...args) : "_";
|
||||||
|
const entry = cache.get(key);
|
||||||
|
if (entry && Date.now() - entry.ts < ttlMs) return entry.data;
|
||||||
|
const data = await factory(...args);
|
||||||
|
cache.set(key, { data, ts: Date.now() });
|
||||||
|
return data;
|
||||||
|
};
|
||||||
|
}
|
||||||
@ -1,5 +1,5 @@
|
|||||||
import { curseforgeClient } from "@/services/clients";
|
import { curseforgeClient } from "@/services/clients";
|
||||||
import { uploadFile } from "@/lib/curseforge";
|
import { uploadFile, getGameVersions } from "@/lib/curseforge";
|
||||||
import { resolveVersionName, buildJarPath } from "@/lib/utils/format";
|
import { resolveVersionName, buildJarPath } from "@/lib/utils/format";
|
||||||
import { readJarBlob } from "@/lib/utils/file";
|
import { readJarBlob } from "@/lib/utils/file";
|
||||||
import type { UploadMetadata } from "@/types";
|
import type { UploadMetadata } from "@/types";
|
||||||
@ -26,11 +26,24 @@ export async function publishCurseForgeVersion(
|
|||||||
|
|
||||||
const primaryBlob = readJarBlob(primaryPath);
|
const primaryBlob = readJarBlob(primaryPath);
|
||||||
|
|
||||||
|
const gameVersions = await getGameVersions(curseforgeClient);
|
||||||
|
|
||||||
|
const resolveId = (name: string): number => {
|
||||||
|
const found = gameVersions.find((v) => v.name === name);
|
||||||
|
if (!found) throw new Error(`Game version "${name}" not found in CurseForge`);
|
||||||
|
return found.id;
|
||||||
|
};
|
||||||
|
|
||||||
const metadata: UploadMetadata = {
|
const metadata: UploadMetadata = {
|
||||||
changelog: input.changelog,
|
changelog: input.changelog,
|
||||||
changelogType: "markdown",
|
changelogType: "markdown",
|
||||||
displayName,
|
displayName,
|
||||||
releaseType: input.versionType,
|
releaseType: input.versionType,
|
||||||
|
gameVersions: [
|
||||||
|
resolveId(mcVersion),
|
||||||
|
...config.curseforge.loaders.map(resolveId),
|
||||||
|
...config.curseforge.environment.map(resolveId),
|
||||||
|
],
|
||||||
relations: config.curseforge.relations,
|
relations: config.curseforge.relations,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|||||||
@ -47,6 +47,7 @@ export async function publishModrinthVersion(
|
|||||||
project_id: config.modrinth.project_id,
|
project_id: config.modrinth.project_id,
|
||||||
name: versionName,
|
name: versionName,
|
||||||
version_number: versionNumber,
|
version_number: versionNumber,
|
||||||
|
changelog: input.changelog,
|
||||||
game_versions: [mcVersion],
|
game_versions: [mcVersion],
|
||||||
version_type: input.versionType,
|
version_type: input.versionType,
|
||||||
loaders: config.modrinth.loaders,
|
loaders: config.modrinth.loaders,
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user