import { Injectable, Logger } from '@nestjs/common'; import { randomUUID } from 'crypto'; import { RabbitmqPublisherService, StatsAdClickEventPayload, StatsAdImpressionEventPayload, StatsVideoClickEventPayload, } from '../../rabbitmq/rabbitmq-publisher.service'; export interface AdClickEvent { uid: string; adId: string; channelId: string; scene: string; slot: string; adType: string; clickedAt: bigint; ip: string; userAgent: string; appVersion?: string; os?: string; createAt: bigint; updateAt: bigint; } export interface VideoClickEvent { uid: string; videoId: string; // channelId: string; categoryId?: string; scene: string; clickedAt: bigint; ip: string; userAgent: string; appVersion?: string; os?: string; createAt: bigint; updateAt: bigint; } export interface AdImpressionEvent { uid: string; adId: string; // channelId: string; scene: string; slot: string; adType: string; impressionAt: bigint; visibleDurationMs?: number; ip: string; userAgent: string; appVersion?: string; os?: string; createAt: bigint; updateAt: bigint; } @Injectable() export class StatsEventsService { private readonly logger = new Logger(StatsEventsService.name); constructor(private readonly rabbitmqPublisher: RabbitmqPublisherService) {} async publishAdClick(event: AdClickEvent): Promise { const payload: StatsAdClickEventPayload = { messageId: randomUUID(), ...event, }; await this.safePublish('stats.ad.click', () => this.rabbitmqPublisher.publishStatsAdClick(payload), ); } async publishVideoClick(event: VideoClickEvent): Promise { const payload: StatsVideoClickEventPayload = { messageId: randomUUID(), ...event, }; await this.safePublish('stats.video.click', () => this.rabbitmqPublisher.publishStatsVideoClick(payload), ); } async publishAdImpression(event: AdImpressionEvent): Promise { const payload: StatsAdImpressionEventPayload = { messageId: randomUUID(), ...event, }; await this.safePublish('stats.ad.impression', () => this.rabbitmqPublisher.publishStatsAdImpression(payload), ); } private async safePublish( label: string, publishFn: () => Promise, ): Promise { try { await publishFn(); } catch (error) { const message = error instanceof Error ? error.message : String(error); const stack = error instanceof Error ? error.stack : undefined; this.logger.error(`Failed to publish ${label}: ${message}`, stack); } } }