mirror of
https://github.com/Drop-OSS/drop.git
synced 2025-11-20 19:51:09 +10:00
partial: user routes
This commit is contained in:
@ -11,63 +11,70 @@ const GetChunk = type({
|
||||
}).array(),
|
||||
}).configure(throwingArktype);
|
||||
|
||||
export default defineEventHandler(async (h3) => {
|
||||
const body = await readDropValidatedBody(h3, GetChunk);
|
||||
/**
|
||||
* Part of v2 download API. Intended to be client-only.
|
||||
*
|
||||
* Returns raw stream of all files requested, in order.
|
||||
*/
|
||||
export default defineEventHandler<{ body: typeof GetChunk.infer }>(
|
||||
async (h3) => {
|
||||
const body = await readDropValidatedBody(h3, GetChunk);
|
||||
|
||||
const context = await contextManager.fetchContext(body.context);
|
||||
if (!context)
|
||||
throw createError({
|
||||
statusCode: 400,
|
||||
statusMessage: "Invalid download context.",
|
||||
});
|
||||
|
||||
const streamFiles = [];
|
||||
|
||||
for (const file of body.files) {
|
||||
const manifestFile = context.manifest[file.filename];
|
||||
if (!manifestFile)
|
||||
const context = await contextManager.fetchContext(body.context);
|
||||
if (!context)
|
||||
throw createError({
|
||||
statusCode: 400,
|
||||
statusMessage: `Unknown file: ${file.filename}`,
|
||||
statusMessage: "Invalid download context.",
|
||||
});
|
||||
|
||||
const start = manifestFile.lengths
|
||||
.slice(0, file.chunkIndex)
|
||||
.reduce((a, b) => a + b, 0);
|
||||
const end = start + manifestFile.lengths[file.chunkIndex];
|
||||
const streamFiles = [];
|
||||
|
||||
streamFiles.push({ filename: file.filename, start, end });
|
||||
}
|
||||
for (const file of body.files) {
|
||||
const manifestFile = context.manifest[file.filename];
|
||||
if (!manifestFile)
|
||||
throw createError({
|
||||
statusCode: 400,
|
||||
statusMessage: `Unknown file: ${file.filename}`,
|
||||
});
|
||||
|
||||
setHeader(
|
||||
h3,
|
||||
"Content-Lengths",
|
||||
streamFiles.map((e) => e.end - e.start).join(","),
|
||||
); // Non-standard header, but we're cool like that 😎
|
||||
const start = manifestFile.lengths
|
||||
.slice(0, file.chunkIndex)
|
||||
.reduce((a, b) => a + b, 0);
|
||||
const end = start + manifestFile.lengths[file.chunkIndex];
|
||||
|
||||
for (const file of streamFiles) {
|
||||
const gameReadStream = await libraryManager.readFile(
|
||||
context.libraryId,
|
||||
context.libraryPath,
|
||||
context.versionName,
|
||||
file.filename,
|
||||
{ start: file.start, end: file.end },
|
||||
);
|
||||
if (!gameReadStream)
|
||||
throw createError({
|
||||
statusCode: 500,
|
||||
statusMessage: "Failed to create read stream",
|
||||
});
|
||||
await gameReadStream.pipeTo(
|
||||
new WritableStream({
|
||||
write(chunk) {
|
||||
h3.node.res.write(chunk);
|
||||
},
|
||||
}),
|
||||
);
|
||||
}
|
||||
streamFiles.push({ filename: file.filename, start, end });
|
||||
}
|
||||
|
||||
await h3.node.res.end();
|
||||
setHeader(
|
||||
h3,
|
||||
"Content-Lengths",
|
||||
streamFiles.map((e) => e.end - e.start).join(","),
|
||||
); // Non-standard header, but we're cool like that 😎
|
||||
|
||||
return;
|
||||
});
|
||||
for (const file of streamFiles) {
|
||||
const gameReadStream = await libraryManager.readFile(
|
||||
context.libraryId,
|
||||
context.libraryPath,
|
||||
context.versionName,
|
||||
file.filename,
|
||||
{ start: file.start, end: file.end },
|
||||
);
|
||||
if (!gameReadStream)
|
||||
throw createError({
|
||||
statusCode: 500,
|
||||
statusMessage: "Failed to create read stream",
|
||||
});
|
||||
await gameReadStream.pipeTo(
|
||||
new WritableStream({
|
||||
write(chunk) {
|
||||
h3.node.res.write(chunk);
|
||||
},
|
||||
}),
|
||||
);
|
||||
}
|
||||
|
||||
await h3.node.res.end();
|
||||
|
||||
return;
|
||||
},
|
||||
);
|
||||
|
||||
@ -8,15 +8,20 @@ const CreateContext = type({
|
||||
version: "string",
|
||||
}).configure(throwingArktype);
|
||||
|
||||
export default defineClientEventHandler(async (h3) => {
|
||||
const body = await readDropValidatedBody(h3, CreateContext);
|
||||
/**
|
||||
* Part of v2 download API. Create a download context for use with `/api/v2/client/chunk`.
|
||||
*/
|
||||
export default defineClientEventHandler<{ body: typeof CreateContext.infer }>(
|
||||
async (h3) => {
|
||||
const body = await readDropValidatedBody(h3, CreateContext);
|
||||
|
||||
const context = await contextManager.createContext(body.game, body.version);
|
||||
if (!context)
|
||||
throw createError({
|
||||
statusCode: 400,
|
||||
statusMessage: "Invalid game or version",
|
||||
});
|
||||
const context = await contextManager.createContext(body.game, body.version);
|
||||
if (!context)
|
||||
throw createError({
|
||||
statusCode: 400,
|
||||
statusMessage: "Invalid game or version",
|
||||
});
|
||||
|
||||
return { context };
|
||||
});
|
||||
return { context };
|
||||
},
|
||||
);
|
||||
|
||||
Reference in New Issue
Block a user