Skip to content

Commit

Permalink
feat: bucket-file stream route handler & updated test suite
Browse files Browse the repository at this point in the history
  • Loading branch information
tada5hi committed Feb 27, 2024
1 parent 84f7de9 commit 9b4cfa0
Show file tree
Hide file tree
Showing 7 changed files with 139 additions and 1 deletion.
5 changes: 4 additions & 1 deletion package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 2 additions & 0 deletions packages/server-storage/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -26,13 +26,15 @@
"redis-extension": "^1.3.0",
"routup": "^3.2.0",
"singa": "^1.0.0",
"tar-stream": "^3.1.6",
"typeorm": "^0.3.20",
"typeorm-extension": "^3.5.0",
"winston": "^3.11.0"
},
"devDependencies": {
"@types/busboy": "^1.5.3",
"@types/cors": "^2.8.17",
"@types/tar-stream": "^2.2.3",
"testcontainers": "^10.7.1"
},
"scripts": {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -7,3 +7,4 @@

export * from './delete';
export * from './read';
export * from './stream';
Original file line number Diff line number Diff line change
@@ -0,0 +1,72 @@
/*
* Copyright (c) 2022-2024.
* Author Peter Placzek (tada5hi)
* For the full copyright and license information,
* view the LICENSE file that was distributed with this source code.
*/

import { NotFoundError } from '@ebec/http';
import type { Request, Response } from 'routup';
import { useRequestParam } from 'routup';
import type { Pack } from 'tar-stream';
import tar from 'tar-stream';
import { useDataSource } from 'typeorm-extension';
import { streamToBuffer, useMinio } from '../../../../core';
import {
BucketFileEntity,
} from '../../../../domains';

async function packFile(
pack: Pack,
file: BucketFileEntity,
) : Promise<void> {
const minio = useMinio();
return new Promise<void>((resolve, reject) => {
minio.getObject(file.bucket.name, file.hash)
.then((stream) => streamToBuffer(stream))
.then((data) => {
pack.entry({
name: file.path,
size: data.byteLength,
}, data, (err) => {
if (err) {
reject(err);

return;
}

resolve();
});
})
.catch((e) => reject(e));
});
}

export async function executeBucketFileRouteStreamHandler(req: Request, res: Response) : Promise<any> {
const id = useRequestParam(req, 'id');

const dataSource = await useDataSource();
const repository = dataSource.getRepository(BucketFileEntity);
const entity = await repository.findOne({
where: {
id,
},
relations: ['bucket'],
});

if (!entity) {
throw new NotFoundError();
}

res.writeHead(200, {
'Content-Type': 'application/x-tar',
'Transfer-Encoding': 'chunked',
});

const pack = tar.pack();
pack.pipe(res);

await packFile(pack, entity);

pack.finalize();
}
10 changes: 10 additions & 0 deletions packages/server-storage/src/http/controllers/bucket-file/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@ import {
executeBucketFileRouteDeleteHandler,
executeBucketFileRouteGetManyHandler,
executeBucketFileRouteGetOneHandler,
executeBucketFileRouteStreamHandler,
} from './handlers';

type PartialBucketFile = Partial<BucketFileEntity>;
Expand All @@ -29,6 +30,15 @@ export class BucketFileController {
return await executeBucketFileRouteGetManyHandler(req, res) as PartialBucketFile[];
}

@DGet('/:id/stream', [ForceLoggedInMiddleware])
async stream(
@DPath('id') id: string,
@DRequest() req: any,
@DResponse() res: any,
): Promise<ReadableStream> {
return await executeBucketFileRouteStreamHandler(req, res) as ReadableStream;
}

@DGet('/:id', [ForceLoggedInMiddleware])
async getOne(
@DPath('id') id: string,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -72,6 +72,11 @@ export async function executeBucketRouteStreamHandler(req: Request, res: Respons
bucket_id: entity.id,
});

res.writeHead(200, {
'Content-Type': 'application/x-tar',
'Transfer-Encoding': 'chunked',
});

const pack = tar.pack();
pack.pipe(res);

Expand Down
45 changes: 45 additions & 0 deletions packages/server-storage/test/unit/bucket-file.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@
*/

import path from 'node:path';
import tar from 'tar-stream';
import type { BucketFileEntity } from '../../src/domains';
import {
dropTestDatabase,
Expand Down Expand Up @@ -71,6 +72,50 @@ describe('controllers/bucket-file', () => {
expectPropertiesEqualToSrc(details, response.body);
});

it('should stream resource', (done) => {
const extract = tar.extract();

const headers : Record<string, any>[] = [];

extract.on('entry', async (header, stream, callback) => {
headers.push(header);

callback();
});

extract.on('finish', () => {
expect(headers.length).toBeGreaterThanOrEqual(1);
done();
});

superTest
.get(`/bucket-files/${details.id}/stream`)
.auth('admin', 'start123')
.pipe(extract);
});

it('should stream resource collection', (done) => {
const extract = tar.extract();

const headers : Record<string, any>[] = [];

extract.on('entry', async (header, stream, callback) => {
headers.push(header);

callback();
});

extract.on('finish', () => {
expect(headers.length).toBeGreaterThanOrEqual(1);
done();
});

superTest
.get(`/buckets/${details.bucket_id}/stream`)
.auth('admin', 'start123')
.pipe(extract);
});

it('should delete resource', async () => {
const response = await superTest
.delete(`/bucket-files/${details.id}`)
Expand Down

0 comments on commit 9b4cfa0

Please sign in to comment.