Merge branch 'master' into feature/plugin-template

This commit is contained in:
Cooldude2606 committed 2024-03-06 20:12:08 +00:00
commit 8fbdb5dfab
6 files changed
+51 -1

No files matched your search

+1
View File
@@ -3,3 +3,4 @@ coverage:
project:
default:
if_ci_failed: success
informational: true
+36
View File
@@ -1,8 +1,10 @@
import fs from "fs-extra";
import path from "path";
import { Static } from "@sinclair/typebox";
import { logger } from "./logging";
import { ModInfo } from "./data";
import TypedEventEmitter from "./TypedEventEmitter";
import { safeOutputFile } from "./file_ops";
export interface ModStoreEvents {
/** A stored mod was created, updated or deleted */
@@ -74,6 +76,21 @@ export default class ModStore extends TypedEventEmitter<keyof ModStoreEvents, Mo
}
static async fromDirectory(modsDirectory: string) {
type ModInfoCache = Static<typeof ModInfo.jsonSchema>[];
const cacheFilename = path.join(modsDirectory, "mod-info-cache.json");
let cache = new Map<string, ModInfo>();
try {
const content = await fs.readFile(cacheFilename, "utf8");
cache = new Map((JSON.parse(content) as ModInfoCache).map(item => {
const mod = ModInfo.fromJSON(item);
return [mod.filename, mod];
}));
} catch (err: any) {
if (err.code !== "ENOENT") {
logger.warn(`Error loading ${cacheFilename}:\n${err.stack}`);
}
}
const files = new Map<string, ModInfo>();
for (let entry of await fs.readdir(modsDirectory, { withFileTypes: true })) {
if (entry.isDirectory()) {
@@ -81,10 +98,23 @@ export default class ModStore extends TypedEventEmitter<keyof ModStoreEvents, Mo
continue;
}
if (!entry.name.toLowerCase().endsWith(".zip")) {
continue;
}
if (entry.name.toLowerCase().endsWith(".tmp.zip")) {
continue;
}
const cachedModInfo = cache.get(entry.name);
if (cachedModInfo) {
const stat = await fs.stat(path.join(modsDirectory, entry.name));
if (cachedModInfo.mtimeMs === stat.mtimeMs) {
files.set(cachedModInfo.filename, cachedModInfo);
continue;
}
}
logger.info(`Loading info for Mod ${entry.name}`);
let modInfo: ModInfo;
try {
@@ -96,6 +126,12 @@ export default class ModStore extends TypedEventEmitter<keyof ModStoreEvents, Mo
files.set(modInfo.filename, modInfo);
}
if (files.size) {
logger.info(`Loaded info for ${files.size} mods`);
const content: ModInfoCache = [...files.values()].map(mod => mod.toJSON());
await safeOutputFile(cacheFilename, JSON.stringify(content));
}
return new this(modsDirectory, files);
}
}
+9
View File
@@ -116,6 +116,11 @@ export default class ModInfo {
*/
size = 0;
/**
* Last modification time of the file.
*/
mtimeMs = 0;
/**
* SHA1 hash of this mod
*/
@@ -147,6 +152,7 @@ export default class ModInfo {
static jsonSchema = Type.Object({
...this.infoJsonSchema.properties,
"size": Type.Optional(Type.Integer()),
"mtime_ms": Type.Optional(Type.Number()),
"sha1": Type.Optional(Type.String()),
"updated_at_ms": Type.Optional(Type.Number()),
"is_deleted": Type.Optional(Type.Boolean()),
@@ -170,6 +176,7 @@ export default class ModInfo {
// Additional data
if (json.size) { modInfo.size = json.size; }
if (json.mtime_ms) { modInfo.mtimeMs = json.mtime_ms; }
if (json.sha1) { modInfo.sha1 = json.sha1; }
if (json.updated_at_ms) { modInfo.updatedAtMs = json.updated_at_ms; }
if (json.is_deleted) { modInfo.isDeleted = json.is_deleted; }
@@ -192,6 +199,7 @@ export default class ModInfo {
json.dependencies = this.dependencies;
}
if (this.size) { json.size = this.size; }
if (this.mtimeMs) { json.mtime_ms = this.mtimeMs; }
if (this.sha1) { json.sha1 = this.sha1; }
if (this.updatedAtMs) { json.updated_at_ms = this.updatedAtMs; }
if (this.isDeleted) { json.is_deleted = this.isDeleted; }
@@ -229,6 +237,7 @@ export default class ModInfo {
size: stat.size,
sha1: await libHash.hashFile(modPath),
mtime_ms: stat.mtimeMs,
updated_at_ms: stat.mtimeMs,
is_deleted: false,
});
+1 -1
View File
@@ -150,7 +150,7 @@ function TransferModal(props: ModalProps) {
autoFocus
showSearch
filterOption={(input, option) => (
(option?.title.toLowerCase().indexOf(input.toLowerCase())??-1) >= 0
(option?.title!.toLowerCase().indexOf(input.toLowerCase())??-1) >= 0
)}
>
{[...instances.values()].filter(
+1
View File
@@ -1054,6 +1054,7 @@ describe("Integration of Clusterio", function() {
"factorioVersion: 1.1\n" +
"dependencies:\n" +
`size: ${stat.size}\n` +
`mtimeMs: ${stat.mtimeMs}\n` +
`sha1: ${hash}\n` +
`updatedAtMs: ${stat.mtimeMs}\n` +
"isDeleted: false\n",
+3
View File
@@ -33,6 +33,7 @@ describe("lib/data/ModInfo", function() {
check(ModInfo.fromJSON({ dependencies: ["UltraMod", "SuperLib >= 1.00", "! bad-mod"] }));
check(ModInfo.fromJSON({ filename: "MyMod_1.0.0.zip" }));
check(ModInfo.fromJSON({ size: 1024 }));
check(ModInfo.fromJSON({ mtime_ms: new Date(2024, 0, 1).getTime() }));
check(ModInfo.fromJSON({ sha1: "verified-as-MyMod" }));
check(ModInfo.fromJSON({ is_deleted: true }));
@@ -49,6 +50,7 @@ describe("lib/data/ModInfo", function() {
dependencies: ["UltraMod", "SuperLib >= 1.00", "! bad-mod"],
filename: "MyMod_1.0.0.zip",
size: 1024,
mtime_ms: new Date(2024, 0, 1).getTime(),
sha1: "verified-as-MyMod",
is_deleted: true,
}));
@@ -92,6 +94,7 @@ describe("lib/data/ModInfo", function() {
dependencies: [],
filename: "empty_mod_1.0.0.zip",
size: stat.size,
mtime_ms: stat.mtimeMs,
updated_at_ms: stat.mtimeMs,
sha1: hash,
})