import { OnModuleInit, Inject, Injectable, HttpException, HttpStatus, InternalServerErrorException, } from '@nestjs/common'; import { firstValueFrom, lastValueFrom, ReplaySubject } from 'rxjs'; import { Link } from '@dadosfera/protospack-v2/dist/lib/Duc/interfaces/entities'; import { DucClient } from '../duc/client.config'; import { ClientGrpc } from '@nestjs/microservices'; import { ProtoServices } from '@dadosfera/protospack-v2/dist/lib/Duc'; import { CustomerUpdateRequest } from '@dadosfera/protospack-v2/dist/lib/Duc/interfaces/messages'; import { ThemeProtoService } from '@dadosfera/protospack-v2/dist/lib/Duc/interfaces/write-service'; import { ThemeRequest } from '@dadosfera/protospack-v2/dist/lib/Duc/interfaces/messages'; import { CustomerThemeRequest, CustomerThemeResponse } from './dtos/customers'; import DadosferaLogger from '@dadosfera/dadosfera-logs'; import { resolve } from 'path'; import { Readable } from 'stream'; type Files = { logo: Express.Multer.File, logoLogin: Express.Multer.File, } @Injectable() export class ThemeService implements OnModuleInit { private themeService: ThemeProtoService; private logger: DadosferaLogger; constructor( @Inject(DucClient.name) private readonly grpcClient: ClientGrpc, @Inject(DadosferaLogger) dadosferaLogger: DadosferaLogger, ) { this.logger = dadosferaLogger.logger; } onModuleInit() { this.themeService = this.grpcClient.getService( ProtoServices.ThemeProtoService, ); } async resetTheme(id: string) { const { theme } = await firstValueFrom( this.themeService.ResetCustomerTheme({ id }), ); return { theme } } async createThemeByCustomer(id: string, theme: CustomerThemeRequest & Files) { if (!id) { this.logger.error('Error - saveCustomertheme - not found id:' + id); throw new HttpException(null, HttpStatus.BAD_REQUEST); } const customerThemeRequest$ = new ReplaySubject(); customerThemeRequest$.next({ customerId: id, displayName: theme.displayName, backgroundColor: theme.backgroundColor, textColor: theme.textColor, isMetadata: true, filename: '', chunk: Buffer.alloc(0) }) if(theme.logo) { await this.sendFile(theme.logo, customerThemeRequest$); } if(theme.logoLogin) { await this.sendFile(theme.logoLogin, customerThemeRequest$); } customerThemeRequest$.complete(); const stream = this.themeService.CustomerCreateTheme(customerThemeRequest$); return lastValueFrom(stream); } async getThemeByCustomer(id: string): Promise { if (!id) { this.logger.error('Error - getCustomerTheme - not found id:' + id); throw new HttpException(null, HttpStatus.BAD_REQUEST); } const { theme } = await firstValueFrom( this.themeService.CustomerGetTheme({ id }), ); return { theme } } private async sendFile(file: Express.Multer.File, stream$: ReplaySubject) { const chunkSize = 4 * 1024 * 1024; const bufferStream = new CustomBufferStream(file.buffer, chunkSize); const parseMimitypeForExtension = { 'image/jpeg': '.jpeg', 'image/jpg': '.jpg', 'image/png': '.png', 'image/svg+xml': '.svg', } const extension = parseMimitypeForExtension[file.mimetype]; return new Promise((resolve, reject) => { bufferStream.on('data', (chunk) => { const filename = file.fieldname.concat(extension); stream$.next({ customerId: '', displayName: '', backgroundColor: '', textColor: '', isMetadata: false, filename: filename, chunk: chunk }); }); bufferStream.on('end', () => { resolve(file.filename) }); bufferStream.on('error', (err) => { reject(err); }); }); } } class CustomBufferStream extends Readable { buffer: Buffer; offset: number; chunkSize: number; constructor(buffer: Buffer, chunkSize: number) { super({ highWaterMark: chunkSize }); // Configura o tamanho do chunk this.buffer = buffer; this.offset = 0; this.chunkSize = chunkSize; } _read() { if (this.offset < this.buffer.length) { const end = Math.min(this.offset + this.chunkSize, this.buffer.length); const copiedBuf = Uint8Array.prototype.slice.call(this.buffer); const chunk = copiedBuf.slice(this.offset, end); this.offset = end; this.push(chunk); } else { this.push(null); } } }