diff --git a/src/cdn.ts b/src/cdn.ts index 164dfd2..110558c 100644 --- a/src/cdn.ts +++ b/src/cdn.ts @@ -38,7 +38,7 @@ function buildLocalCDNPath(fullKey: string): string { return path.join(config.cdn.disk_path, fullKey); } -export async function getCDNFileAsStream(namespace: CDNNamespace, key: string): Promise { +export async function getCDNFileAsStream(namespace: CDNNamespace, key: string): Promise<{ size: number | null; stream: Readable } | null> { const fullKey = buildKey(namespace, key); if (!s3) { @@ -49,7 +49,10 @@ export async function getCDNFileAsStream(namespace: CDNNamespace, key: string): return null; } - return fs.createReadStream(filePath); + return { + stream: fs.createReadStream(filePath), + size: fileInfo.size + }; } const response = await s3.send(new GetObjectCommand({ @@ -61,15 +64,18 @@ export async function getCDNFileAsStream(namespace: CDNNamespace, key: string): return null; } - return response.Body; + return { + stream: response.Body, + size: response.ContentLength ?? null + }; } export async function getCDNFileAsBuffer(namespace: CDNNamespace, key: string): Promise { - const stream = await getCDNFileAsStream(namespace, key); - if (!stream) { + const streamOutput = await getCDNFileAsStream(namespace, key); + if (!streamOutput) { return null; } - return bufferConsumer(stream); + return bufferConsumer(streamOutput.stream); } export async function uploadCDNFile(namespace: CDNNamespace, key: string, data: Buffer): Promise { @@ -111,8 +117,13 @@ export async function deleteCDNFile(namespace: CDNNamespace, key: string): Promi })); } -export function streamFileToResponse(response: Response, stream: Readable, headers: Record = {}): void { +export function streamFileToResponse(response: Response, stream: Readable, size: number | null, headers: Record = {}): void { response.setHeaders(new Headers(headers)); + + if (size !== null) { + response.setHeader('Content-Length', size); + } + Stream.pipeline(stream, response, (err) => { if (err) { logger.error('Error with response stream: ' + err.message); diff --git a/src/services/npdi.ts b/src/services/npdi.ts index a9b5ee9..596e9d1 100644 --- a/src/services/npdi.ts +++ b/src/services/npdi.ts @@ -23,7 +23,7 @@ npdi.get('/p01/data/1/:bossAppId/:dataId/:fileHash', async (request, response) = throw new Error('File not found in CDN'); } - return streamFileToResponse(response, fileStream, { + return streamFileToResponse(response, fileStream.stream, fileStream.size, { // * The misspelling here is intentional, it's what the official server sets 'Content-Type': 'applicatoin/octet-stream', 'Content-Disposition': 'attachment', diff --git a/src/services/npdl.ts b/src/services/npdl.ts index a167299..e934949 100644 --- a/src/services/npdl.ts +++ b/src/services/npdl.ts @@ -35,7 +35,7 @@ npdl.get([ return; } - return streamFileToResponse(response, readStream, { + return streamFileToResponse(response, readStream.stream, readStream.size, { 'Last-Modified': new Date(Number(file.updated)).toUTCString() }); });