dad0136365
Build and Push Multi-Platform Images / build-and-push (push) Successful in 41s
Reformats code style (line breaks, indentation, type annotations) without changing logic. Also includes minor feature additions bundled in the same lint run (stats service, user-settings groups, agrarmonitor polling improvements). Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
133 lines
3.7 KiB
TypeScript
133 lines
3.7 KiB
TypeScript
import {
|
|
Body,
|
|
Controller,
|
|
Get,
|
|
HttpCode,
|
|
HttpStatus,
|
|
MessageEvent,
|
|
NotFoundException,
|
|
Param,
|
|
ParseIntPipe,
|
|
Post,
|
|
Query,
|
|
Res,
|
|
Sse,
|
|
StreamableFile,
|
|
} from '@nestjs/common';
|
|
import type { Response } from 'express';
|
|
import { Observable } from 'rxjs';
|
|
import { map } from 'rxjs/operators';
|
|
import { RequirePermissions } from '../auth/permissions.decorator';
|
|
import { Permission } from '../auth/permissions.enum';
|
|
import { LabelPrintAgentService } from './label-print-agent.service';
|
|
|
|
@Controller('api/label-print-agent')
|
|
export class LabelPrintAgentController {
|
|
constructor(private readonly service: LabelPrintAgentService) {}
|
|
|
|
@Post('preview')
|
|
@HttpCode(HttpStatus.OK)
|
|
@RequirePermissions(Permission.VIEW_SCANNER)
|
|
async preview(
|
|
@Body() body: { templateId: number; fieldValues?: Record<string, string> },
|
|
@Res({ passthrough: true }) res: Response,
|
|
): Promise<StreamableFile> {
|
|
const buf = await this.service.renderPreview(
|
|
body.templateId,
|
|
body.fieldValues ?? {},
|
|
);
|
|
const { Readable } = await import('stream');
|
|
res.setHeader('Content-Type', 'image/png');
|
|
return new StreamableFile(Readable.from(buf));
|
|
}
|
|
|
|
// Manuell einen Job anlegen (Frontend → Backend)
|
|
@Post('jobs')
|
|
@HttpCode(HttpStatus.CREATED)
|
|
@RequirePermissions(Permission.VIEW_SCANNER)
|
|
async createJob(
|
|
@Body() body: { templateId: number; fieldValues?: Record<string, string> },
|
|
) {
|
|
const job = await this.service.createJob(
|
|
body.templateId,
|
|
body.fieldValues ?? {},
|
|
);
|
|
return { jobId: String(job.Id) };
|
|
}
|
|
|
|
// Agent: SSE-Stream für neue Druckaufträge
|
|
@Sse('events')
|
|
sseEvents(
|
|
@Res({ passthrough: true }) res: Response,
|
|
): Observable<MessageEvent> {
|
|
res.setHeader('X-Accel-Buffering', 'no');
|
|
return this.service.newJob$.pipe(
|
|
map(() => ({ data: { type: 'label-job-available' } }) as MessageEvent),
|
|
);
|
|
}
|
|
|
|
// Agent: nächsten Job abholen (Polling)
|
|
@Get('jobs/next')
|
|
async getNextJob(@Query('agentId') agentId: string, @Res() res: Response) {
|
|
const job = await this.service.claimNextJob(agentId ?? 'unknown');
|
|
if (!job) {
|
|
res.status(HttpStatus.NO_CONTENT).send();
|
|
return;
|
|
}
|
|
res.status(HttpStatus.OK).json({
|
|
jobId: String(job.Id),
|
|
labelImageBase64: job.LabelImageData
|
|
? job.LabelImageData.toString('base64')
|
|
: null,
|
|
labelImageContentType: 'image/png',
|
|
labelWidthMm: job.LabelWidthMm,
|
|
labelHeightMm: job.LabelHeightMm,
|
|
});
|
|
}
|
|
|
|
// Agent: Bild separat abrufen
|
|
@Get('jobs/:id/image')
|
|
async getImage(
|
|
@Param('id', ParseIntPipe) id: number,
|
|
@Res({ passthrough: true }) res: Response,
|
|
): Promise<StreamableFile> {
|
|
const buf = await this.service.getJobImage(id);
|
|
if (!buf) throw new NotFoundException('Bild nicht gefunden');
|
|
const { Readable } = await import('stream');
|
|
res.setHeader('Content-Type', 'image/png');
|
|
return new StreamableFile(Readable.from(buf));
|
|
}
|
|
|
|
// Agent: Druck erfolgreich
|
|
@Post('jobs/:id/printed')
|
|
@HttpCode(HttpStatus.OK)
|
|
async markPrinted(
|
|
@Param('id', ParseIntPipe) id: number,
|
|
@Body() body: { agentId?: string; printerName?: string },
|
|
) {
|
|
await this.service.markPrinted(
|
|
id,
|
|
body.agentId ?? 'unknown',
|
|
body.printerName ?? '',
|
|
);
|
|
return { ok: true };
|
|
}
|
|
|
|
// Agent: Druckfehler
|
|
@Post('jobs/:id/error')
|
|
@HttpCode(HttpStatus.OK)
|
|
async markError(
|
|
@Param('id', ParseIntPipe) id: number,
|
|
@Body()
|
|
body: { agentId?: string; printerName?: string; errorMessage?: string },
|
|
) {
|
|
await this.service.markError(
|
|
id,
|
|
body.agentId ?? 'unknown',
|
|
body.printerName ?? '',
|
|
body.errorMessage ?? '',
|
|
);
|
|
return { ok: true };
|
|
}
|
|
}
|