lint errors fixed

main
Inga 🏳‍🌈 2 years ago
parent 581d21d316
commit 7c918115c1
  1. 12
      src/bull/bullConfigService.ts
  2. 70
      src/screenshots/screenshots.controller.ts
  3. 6
      src/screenshots/screenshots.dto.ts
  4. 2
      src/screenshots/screenshots.module.ts
  5. 8
      src/screenshots/screenshots.processor.ts
  6. 4
      src/screenshots/screenshotter.service.spec.ts
  7. 24
      src/screenshots/screenshotter.service.ts
  8. 14
      src/screenshots/shared.ts
  9. 2
      src/setup.jest.ts

@ -1,11 +1,13 @@
import { BullModuleOptions, SharedBullConfigurationFactory } from "@nestjs/bull"; import {
import { Injectable } from "@nestjs/common"; BullModuleOptions,
import { ConfigService } from "@nestjs/config"; SharedBullConfigurationFactory,
} from '@nestjs/bull';
import { Injectable } from '@nestjs/common';
import { ConfigService } from '@nestjs/config';
@Injectable() @Injectable()
export class BullConfigService implements SharedBullConfigurationFactory { export class BullConfigService implements SharedBullConfigurationFactory {
constructor(private readonly configService: ConfigService) { constructor(private readonly configService: ConfigService) {}
}
createSharedConfiguration(): BullModuleOptions { createSharedConfiguration(): BullModuleOptions {
return { return {

@ -1,68 +1,88 @@
import { InjectQueue } from '@nestjs/bull'; import { InjectQueue } from '@nestjs/bull';
import { Body, Controller, Get, NotFoundException, Param, Post, Res, StreamableFile } from '@nestjs/common'; import {
Body,
Controller,
Get,
NotFoundException,
Param,
Post,
Res,
StreamableFile,
} from '@nestjs/common';
import { ApiResponse } from '@nestjs/swagger'; import { ApiResponse } from '@nestjs/swagger';
import { Response } from 'express' import { Response } from 'express';
import { Readable } from 'stream'; import {
import { CreateJobRequestDto, GetJobResponseDto, JobStatusDto } from './screenshots.dto' CreateJobRequestDto,
GetJobResponseDto,
JobStatusDto,
} from './screenshots.dto';
import { QUEUE_NAME, ScreenshotsQueue } from './shared'; import { QUEUE_NAME, ScreenshotsQueue } from './shared';
@Controller('screenshots') @Controller('screenshots')
export class ScreenshotsController { export class ScreenshotsController {
constructor(@InjectQueue(QUEUE_NAME) private readonly screenshotsQueue: ScreenshotsQueue) {} constructor(
@InjectQueue(QUEUE_NAME)
private readonly screenshotsQueue: ScreenshotsQueue,
) {}
@Post() @Post()
async createScreenshotJob(@Body() createScreenshotJobDto: CreateJobRequestDto): Promise<{ jobId: string }> { async createScreenshotJob(
@Body() createScreenshotJobDto: CreateJobRequestDto,
): Promise<{ jobId: string }> {
const result = await this.screenshotsQueue.add({ const result = await this.screenshotsQueue.add({
pageUrl: new URL(createScreenshotJobDto.pageUrl), pageUrl: new URL(createScreenshotJobDto.pageUrl),
imageType: createScreenshotJobDto.imageType, imageType: createScreenshotJobDto.imageType,
}) });
return { return {
jobId: result.id.toString() jobId: result.id.toString(),
} };
} }
@Get(':id') @Get(':id')
@ApiResponse({ status: 404 }) @ApiResponse({ status: 404 })
async getJob(@Param('id') id: string): Promise<GetJobResponseDto> { async getJob(@Param('id') id: string): Promise<GetJobResponseDto> {
const jobInfo = await this.screenshotsQueue.getJob(id) const jobInfo = await this.screenshotsQueue.getJob(id);
if (!jobInfo) { if (!jobInfo) {
throw new NotFoundException() throw new NotFoundException();
} }
switch (await jobInfo.getState()) { switch (await jobInfo.getState()) {
case 'completed': case 'completed':
return { status: JobStatusDto.Completed } return { status: JobStatusDto.Completed };
case 'failed': case 'failed':
return { status: JobStatusDto.Failed } return { status: JobStatusDto.Failed };
default: default:
return { status: JobStatusDto.Queued } return { status: JobStatusDto.Queued };
} }
} }
@Get(':id/result') @Get(':id/result')
@ApiResponse({ status: 404 }) @ApiResponse({ status: 404 })
async getScreenshot(@Param('id') id: string, @Res({ passthrough: true }) res: Response): Promise<StreamableFile> { async getScreenshot(
const jobInfo = await this.screenshotsQueue.getJob(id) @Param('id') id: string,
@Res({ passthrough: true }) res: Response,
): Promise<StreamableFile> {
const jobInfo = await this.screenshotsQueue.getJob(id);
if (!jobInfo) { if (!jobInfo) {
throw new NotFoundException() throw new NotFoundException();
} }
if (!await jobInfo.isCompleted()) { if (!(await jobInfo.isCompleted())) {
throw new NotFoundException() throw new NotFoundException();
} }
switch (jobInfo.data.imageType) { switch (jobInfo.data.imageType) {
case 'jpeg': case 'jpeg':
res.setHeader('Content-Type', 'image/jpeg') res.setHeader('Content-Type', 'image/jpeg');
break break;
case 'png': case 'png':
res.setHeader('Content-Type', 'image/png') res.setHeader('Content-Type', 'image/png');
break break;
} }
const buffer = Buffer.from(await jobInfo.returnvalue as string, 'base64') const buffer = Buffer.from((await jobInfo.returnvalue) as string, 'base64');
return new StreamableFile(buffer) return new StreamableFile(buffer);
} }
} }

@ -1,4 +1,4 @@
import { IsEnum, IsNotEmpty, IsString, IsUrl } from "class-validator"; import { IsEnum, IsUrl } from 'class-validator';
enum ImageTypeDto { enum ImageTypeDto {
Jpeg = 'jpeg', Jpeg = 'jpeg',
@ -16,9 +16,9 @@ export class CreateJobRequestDto {
pageUrl!: string; pageUrl!: string;
@IsEnum(ImageTypeDto) @IsEnum(ImageTypeDto)
imageType!: ImageTypeDto imageType!: ImageTypeDto;
} }
export class GetJobResponseDto { export class GetJobResponseDto {
status!: JobStatusDto status!: JobStatusDto;
} }

@ -12,6 +12,6 @@ import { ScreenshotterService } from './screenshotter.service';
}), }),
], ],
controllers: [ScreenshotsController], controllers: [ScreenshotsController],
providers: [ScreenshotsProcessor, ScreenshotterService] providers: [ScreenshotsProcessor, ScreenshotterService],
}) })
export class ScreenshotsModule {} export class ScreenshotsModule {}

@ -14,11 +14,11 @@ export class ScreenshotsProcessor {
const imageData = await this.screenshotterService.takeScreenshot({ const imageData = await this.screenshotterService.takeScreenshot({
url: job.data.pageUrl, url: job.data.pageUrl,
imageType: job.data.imageType, imageType: job.data.imageType,
}) });
job.moveToCompleted(imageData.toString('base64')) job.moveToCompleted(imageData.toString('base64'));
} catch(err) { } catch (err) {
job.moveToFailed({ message: JSON.stringify(err) }) job.moveToFailed({ message: JSON.stringify(err) });
} }
} }
} }

@ -20,7 +20,7 @@ describe('ScreenshotterService', () => {
const image = await service.takeScreenshot({ const image = await service.takeScreenshot({
imageType: 'png', imageType: 'png',
url: new URL('data:text/html,%3Ch1%3EHello%2C%20World%21%3C%2Fh1%3E'), url: new URL('data:text/html,%3Ch1%3EHello%2C%20World%21%3C%2Fh1%3E'),
}) });
expect(image).toMatchImageSnapshot() expect(image).toMatchImageSnapshot();
}); });
}); });

@ -1,26 +1,26 @@
import { Injectable } from '@nestjs/common'; import { Injectable } from '@nestjs/common';
import puppeteer from 'puppeteer' import puppeteer from 'puppeteer';
type TakeScreenshotOptions = { type TakeScreenshotOptions = {
imageType: 'jpeg' | 'png' imageType: 'jpeg' | 'png';
url: URL url: URL;
} };
@Injectable() @Injectable()
export class ScreenshotterService { export class ScreenshotterService {
async takeScreenshot(options: TakeScreenshotOptions): Promise<Buffer> { async takeScreenshot(options: TakeScreenshotOptions): Promise<Buffer> {
const browser = await puppeteer.launch() const browser = await puppeteer.launch();
try { try {
const page = await browser.newPage() const page = await browser.newPage();
await page.goto(options.url.toString()) await page.goto(options.url.toString());
const image = await page.screenshot({ const image = (await page.screenshot({
type: options.imageType, type: options.imageType,
encoding: 'binary' encoding: 'binary',
}) as Buffer })) as Buffer;
return image return image;
} finally { } finally {
browser.close() browser.close();
} }
} }
} }

@ -1,12 +1,12 @@
import { Job, Queue } from "bull" import { Job, Queue } from 'bull';
export const QUEUE_NAME = 'screenshots' export const QUEUE_NAME = 'screenshots';
export type ScreenshotJobData = { export type ScreenshotJobData = {
pageUrl: URL pageUrl: URL;
imageType: 'jpeg' | 'png' imageType: 'jpeg' | 'png';
} };
export type ScreenshotJob = Job<ScreenshotJobData> export type ScreenshotJob = Job<ScreenshotJobData>;
export type ScreenshotsQueue = Queue<ScreenshotJobData> export type ScreenshotsQueue = Queue<ScreenshotJobData>;

@ -1,3 +1,3 @@
const { toMatchImageSnapshot } = require('jest-image-snapshot'); import { toMatchImageSnapshot } from 'jest-image-snapshot';
expect.extend({ toMatchImageSnapshot }); expect.extend({ toMatchImageSnapshot });

Loading…
Cancel
Save