mirror of
https://github.com/clusterio/clusterio.git
synced 2026-11-13 07:04:53 +09:00
adjusted function input for getting latest mod version and adding chunking to not hit request limits
This commit is contained in:
1 parent
71c1cffcac
commit
a2a3bcd4f8
1 file changed
+64
-89
@@ -2,7 +2,7 @@ import fs from "fs-extra";
|
||||
import path from "path";
|
||||
import { Static, StringContentEncodingOption, Type } from "@sinclair/typebox";
|
||||
import { logger } from "./logging";
|
||||
import { ModInfo } from "./data";
|
||||
import { integerModVersion, ModInfo } from "./data";
|
||||
import * as libSchema from "./schema";
|
||||
import TypedEventEmitter from "./TypedEventEmitter";
|
||||
import { safeOutputFile } from "./file_ops";
|
||||
@@ -12,56 +12,36 @@ export interface ModStoreEvents {
|
||||
change: (mod: ModInfo) => void;
|
||||
}
|
||||
|
||||
interface ModDownloadRequest {
|
||||
name: string;
|
||||
version?: string;
|
||||
sha1?: string;
|
||||
}
|
||||
|
||||
interface ModRelease {
|
||||
download_url: string,
|
||||
// /download/maraxsis/670de301df21001f6147fd1c -- append to mods.factorio.com to download file, auth required
|
||||
file_name: string,
|
||||
// maraxsis_1.8.0.zip -- the file name of the downloaded file ^^
|
||||
info_json: {
|
||||
dependencies?: Array<string>,
|
||||
factorio_version: string;
|
||||
};
|
||||
released_at: string,
|
||||
// 2024-10-15T03:35:29.892000Z -- (ISO 8601)
|
||||
sha1: string,
|
||||
// e227ee560d93485c7f215c9451eaa9cc38d81c98
|
||||
version: string; // 1.8.0 -- just a normal version string
|
||||
info_json: { factorio_version: string; },
|
||||
releasted_at: string, // ISO 8601
|
||||
version: string,
|
||||
sha1: string;
|
||||
}
|
||||
|
||||
interface ModImage {
|
||||
id: string,
|
||||
thumbnail: string,
|
||||
url: string;
|
||||
}
|
||||
|
||||
interface ModLicense {
|
||||
description: string,
|
||||
id: string,
|
||||
name: string,
|
||||
title: string,
|
||||
url: string;
|
||||
}
|
||||
|
||||
interface ModDetails {
|
||||
category: string, // content -- what mod catogory is this apart of, a mod can only be apart of 1 category
|
||||
download_count: number, // 3653 -- how many downloads does the mod have as a number
|
||||
name: string, // maraxsis -- the name of the mod
|
||||
owner: string, // notnotmelon -- the name of the author of the mod
|
||||
releases: Array<ModRelease>, // an array of all releases and version of the mod
|
||||
score: number, // 1054.8333333333333 -- it's prob used for sorting purposes
|
||||
summary: string, // the mod description
|
||||
thumbnail: string, // append path to assets-mods.factorio.com to get full url to thumbnail file
|
||||
title: string, // the full title of the mod, shown on the mod page
|
||||
changelog?: string,
|
||||
created_at?: string,
|
||||
description?: string,
|
||||
homepage?: string,
|
||||
images?: Array<ModImage>,
|
||||
license?: ModLicense,
|
||||
source_url?: string,
|
||||
tags?: Array<string>,
|
||||
updated_at?: string,
|
||||
deprecated?: boolean;
|
||||
name: string,
|
||||
title: string,
|
||||
owner: string,
|
||||
summary: string,
|
||||
downloads_count: number,
|
||||
category: string,
|
||||
score: number,
|
||||
releases: Array<ModRelease>,
|
||||
}
|
||||
|
||||
interface ModsInfoResponse {
|
||||
pagination: any,
|
||||
results: Array<ModDetails>,
|
||||
}
|
||||
|
||||
export default class ModStore extends TypedEventEmitter<keyof ModStoreEvents, ModStoreEvents> {
|
||||
@@ -188,54 +168,49 @@ export default class ModStore extends TypedEventEmitter<keyof ModStoreEvents, Mo
|
||||
return new this(modsDirectory, files);
|
||||
}
|
||||
|
||||
// gets the latest version of the mod provided as a string
|
||||
static async fetchLatestVersionString(modName: string): Promise<string> {
|
||||
const modDetails: ModDetails = await (
|
||||
await fetch(`https://mods.factorio.com/api/mods/${modName}`)
|
||||
).json() as ModDetails;
|
||||
return modDetails.releases[modDetails.releases.length].version;
|
||||
static getLatestVersionFromReleases(releases: Array<ModRelease>): string | undefined {
|
||||
let latestVersion = "0.0.0";
|
||||
releases.forEach((release) => {
|
||||
if (integerModVersion(latestVersion) < integerModVersion(release.version)) {
|
||||
latestVersion = release.version;
|
||||
}
|
||||
});
|
||||
if (latestVersion === "0.0.0") {
|
||||
return undefined;
|
||||
}
|
||||
return latestVersion;
|
||||
}
|
||||
|
||||
// gets the latest version of the mod provided as a string
|
||||
static async fetchLatestVersionModInfo(modName: string): Promise<ModInfo> {
|
||||
const modDetails: ModDetails = await (
|
||||
await fetch(`https://mods.factorio.com/api/mods/${modName}/full`)
|
||||
).json() as ModDetails;
|
||||
const latestRelease: ModRelease = modDetails.releases[modDetails.releases.length];
|
||||
let modInfo = new ModInfo();
|
||||
const info_json = latestRelease.info_json;
|
||||
|
||||
// info.json fields
|
||||
if (modDetails.name) { modInfo.name = modDetails.name; }
|
||||
if (latestRelease.version) { modInfo.version = latestRelease.version; }
|
||||
if (modDetails.title) { modInfo.title = modDetails.title; }
|
||||
if (modDetails.owner) { modInfo.author = modDetails.owner; }
|
||||
if (modDetails.homepage) { modInfo.homepage = modDetails.homepage; }
|
||||
if (modDetails.description) { modInfo.description = modDetails.description; }
|
||||
if (info_json.factorio_version) { modInfo.factorioVersion = info_json.factorio_version; }
|
||||
if (info_json.dependencies) { modInfo.dependencies = info_json.dependencies; }
|
||||
|
||||
const infoJsonSchema = Type.Object({
|
||||
"name": Type.String(),
|
||||
"version": Type.String(),
|
||||
"title": Type.String(),
|
||||
"author": Type.String(),
|
||||
"contact": Type.Optional(Type.String()),
|
||||
"homepage": Type.Optional(Type.String()),
|
||||
"description": Type.Optional(Type.String()),
|
||||
"factorio_version": Type.Optional(Type.String()),
|
||||
"dependencies": Type.Optional(Type.Array(Type.String())),
|
||||
static async getLatestVersionsChunk(modNames: Array<string>): Promise<{ [key: string]: string | undefined; }> {
|
||||
const url = new URL("https://mods.factorio.com/api/mods");
|
||||
url.searchParams.set("page_size", "max");
|
||||
const response = await fetch(url, {
|
||||
method: "POST",
|
||||
body: new URLSearchParams({ namelist: modNames }),
|
||||
});
|
||||
if (response.status !== 200) {
|
||||
throw Error(`Fetch: ${url} returned ${response.status} ${response.statusText}`);
|
||||
}
|
||||
const mods = (await response.json() as ModsInfoResponse).results;
|
||||
const versions: { [key: string]: string | undefined; } = {};
|
||||
mods.forEach((mod) => {
|
||||
const modName = mod.name;
|
||||
let latestVersion = ModStore.getLatestVersionFromReleases(mod.releases);
|
||||
versions[modName] = latestVersion;
|
||||
});
|
||||
|
||||
const validateInfo = libSchema.compile<Static<typeof infoJsonSchema>>(infoJsonSchema as any);
|
||||
|
||||
const valid = validateInfo(modInfo);
|
||||
|
||||
if (valid) {
|
||||
return modInfo;
|
||||
}
|
||||
|
||||
return modInfo;
|
||||
|
||||
return versions;
|
||||
}
|
||||
|
||||
static async getLatestVersions(modNames: Array<string>): Promise<{ [key: string]: string | undefined; }> {
|
||||
const chunkSize = 500;
|
||||
const chunks: Array<{ [key: string]: string | undefined; }> = [];
|
||||
for (let i = 0; i < modNames.length; i += chunkSize) {
|
||||
chunks.push(await ModStore.getLatestVersionsChunk(modNames.slice(i, i + chunkSize)));
|
||||
}
|
||||
const versions = chunks.reduce((acc, curr) => ({ ...acc, ...curr }), {});
|
||||
return versions;
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
Reference in new issue
Block a user