mirror of
https://github.com/Drop-OSS/drop.git
synced 2026-07-24 17:03:00 +10:00
d234f8df33
* feat: add store nav and fixes * fix: reduce password requirement & new task error ui * fix: client webtoken fix * fix: delta versions and dockerfile * fix: use setup platforms for filter & display * fix: setup not accounted when returning valid options * feat: tighter delta version support * feat: dl/disk size * feat: offload manifest generation to torrential * fix: bump torrential * feat: remove droplet * feat: bump torrential * feat: convert locales
141 lines
3.8 KiB
TypeScript
141 lines
3.8 KiB
TypeScript
import cacheHandler from "../../cache";
|
|
import prisma from "../../db/database";
|
|
import { castManifest, type DropletManifest } from "./utils";
|
|
|
|
export type DownloadManifestDetails = {
|
|
/***
|
|
* Version ID to manifest
|
|
*/
|
|
manifests: { [key: string]: DropletManifest };
|
|
/***
|
|
* File name to version ID
|
|
*/
|
|
fileList: { [key: string]: string };
|
|
/// Size on disk after download
|
|
installSize: number;
|
|
/// Size of download
|
|
downloadSize: number;
|
|
};
|
|
|
|
function convertMap<T>(map: Map<string, T>): { [key: string]: T } {
|
|
return Object.fromEntries(map.entries().toArray());
|
|
}
|
|
const manifestCache =
|
|
cacheHandler.createCache<DownloadManifestDetails>("manifestCache");
|
|
|
|
/**
|
|
*
|
|
* @param gameId Game ID
|
|
* @param versionId Version ID
|
|
*/
|
|
export async function createDownloadManifestDetails(
|
|
versionId: string,
|
|
refresh = false,
|
|
): Promise<DownloadManifestDetails> {
|
|
if ((await manifestCache.has(versionId)) && !refresh)
|
|
return (await manifestCache.get(versionId))!;
|
|
const mainVersion = await prisma.gameVersion.findUnique({
|
|
where: { versionId },
|
|
select: {
|
|
versionId: true,
|
|
delta: true,
|
|
versionIndex: true,
|
|
fileList: true,
|
|
negativeFileList: true,
|
|
gameId: true,
|
|
dropletManifest: true,
|
|
},
|
|
});
|
|
if (!mainVersion)
|
|
throw createError({ statusCode: 404, message: "Version not found" });
|
|
|
|
const collectedVersions = [];
|
|
let versionIndex = mainVersion.versionIndex;
|
|
while (mainVersion.delta) {
|
|
const nextVersion = await prisma.gameVersion.findFirst({
|
|
where: { gameId: mainVersion.gameId, versionIndex: { lt: versionIndex } },
|
|
orderBy: {
|
|
versionIndex: "desc",
|
|
},
|
|
select: {
|
|
versionId: true,
|
|
versionIndex: true,
|
|
delta: true,
|
|
fileList: true,
|
|
negativeFileList: true,
|
|
dropletManifest: true,
|
|
},
|
|
});
|
|
if (!nextVersion)
|
|
throw createError({
|
|
statusCode: 500,
|
|
message: "Delta version without version underneath it.",
|
|
});
|
|
|
|
versionIndex = nextVersion.versionIndex;
|
|
collectedVersions.push(nextVersion);
|
|
if (!nextVersion.delta) break;
|
|
}
|
|
|
|
collectedVersions.reverse();
|
|
// Apply fileList in lowest priority to newest priority
|
|
const versionOrder = [...collectedVersions, mainVersion];
|
|
|
|
const fileList = new Map<string, string>();
|
|
for (const version of versionOrder) {
|
|
for (const file of version.fileList) {
|
|
fileList.set(file, version.versionId);
|
|
}
|
|
for (const negFile of version.negativeFileList) {
|
|
fileList.delete(negFile);
|
|
}
|
|
}
|
|
|
|
let installSize = 0;
|
|
let downloadSize = 0;
|
|
|
|
// Now that we have our file list, filter the manifests
|
|
const manifests = new Map<string, DropletManifest>();
|
|
for (const version of versionOrder) {
|
|
const files = fileList
|
|
.entries()
|
|
.filter(([, versionId]) => version.versionId === versionId)
|
|
.toArray();
|
|
if (files.length == 0) continue;
|
|
const fileNames = Object.fromEntries(files);
|
|
const manifest = castManifest(version.dropletManifest);
|
|
const filteredChunks = Object.fromEntries(
|
|
Object.entries(manifest.chunks).filter(([, chunkData]) => {
|
|
let flag = false;
|
|
chunkData.files.forEach((fileEntry) => {
|
|
if (fileNames[fileEntry.filename]) {
|
|
flag = true;
|
|
installSize += fileEntry.length;
|
|
}
|
|
});
|
|
// If we have to download this chunk, add it's length
|
|
if (flag) {
|
|
downloadSize += chunkData.files
|
|
.map((v) => v.length)
|
|
.reduce((a, b) => a + b, 0);
|
|
}
|
|
return flag;
|
|
}),
|
|
);
|
|
manifests.set(version.versionId, {
|
|
...manifest,
|
|
chunks: filteredChunks,
|
|
});
|
|
}
|
|
|
|
const result = {
|
|
fileList: convertMap(fileList),
|
|
manifests: convertMap(manifests),
|
|
installSize,
|
|
downloadSize,
|
|
};
|
|
await manifestCache.set(versionId, result);
|
|
|
|
return result;
|
|
}
|