stats-events.service.ts 2.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109
  1. import { Injectable, Logger } from '@nestjs/common';
  2. import { randomUUID } from 'crypto';
  3. import {
  4. RabbitmqPublisherService,
  5. StatsAdClickEventPayload,
  6. StatsAdImpressionEventPayload,
  7. StatsVideoClickEventPayload,
  8. } from '../../rabbitmq/rabbitmq-publisher.service';
  9. export interface AdClickEvent {
  10. uid: string;
  11. adId: string;
  12. channelId: string;
  13. scene: string;
  14. slot: string;
  15. adType: string;
  16. clickedAt: bigint;
  17. ip: string;
  18. userAgent: string;
  19. appVersion?: string;
  20. os?: string;
  21. createAt: bigint;
  22. updateAt: bigint;
  23. }
  24. export interface VideoClickEvent {
  25. uid: string;
  26. videoId: string;
  27. // channelId: string;
  28. categoryId?: string;
  29. scene: string;
  30. clickedAt: bigint;
  31. ip: string;
  32. userAgent: string;
  33. appVersion?: string;
  34. os?: string;
  35. createAt: bigint;
  36. updateAt: bigint;
  37. }
  38. export interface AdImpressionEvent {
  39. uid: string;
  40. adId: string;
  41. // channelId: string;
  42. scene: string;
  43. slot: string;
  44. adType: string;
  45. impressionAt: bigint;
  46. visibleDurationMs?: number;
  47. ip: string;
  48. userAgent: string;
  49. appVersion?: string;
  50. os?: string;
  51. createAt: bigint;
  52. updateAt: bigint;
  53. }
  54. @Injectable()
  55. export class StatsEventsService {
  56. private readonly logger = new Logger(StatsEventsService.name);
  57. constructor(private readonly rabbitmqPublisher: RabbitmqPublisherService) {}
  58. async publishAdClick(event: AdClickEvent): Promise<void> {
  59. const payload: StatsAdClickEventPayload = {
  60. messageId: randomUUID(),
  61. ...event,
  62. };
  63. await this.safePublish('stats.ad.click', () =>
  64. this.rabbitmqPublisher.publishStatsAdClick(payload),
  65. );
  66. }
  67. async publishVideoClick(event: VideoClickEvent): Promise<void> {
  68. const payload: StatsVideoClickEventPayload = {
  69. messageId: randomUUID(),
  70. ...event,
  71. };
  72. await this.safePublish('stats.video.click', () =>
  73. this.rabbitmqPublisher.publishStatsVideoClick(payload),
  74. );
  75. }
  76. async publishAdImpression(event: AdImpressionEvent): Promise<void> {
  77. const payload: StatsAdImpressionEventPayload = {
  78. messageId: randomUUID(),
  79. ...event,
  80. };
  81. await this.safePublish('stats.ad.impression', () =>
  82. this.rabbitmqPublisher.publishStatsAdImpression(payload),
  83. );
  84. }
  85. private async safePublish(
  86. label: string,
  87. publishFn: () => Promise<void>,
  88. ): Promise<void> {
  89. try {
  90. await publishFn();
  91. } catch (error) {
  92. const message = error instanceof Error ? error.message : String(error);
  93. const stack = error instanceof Error ? error.stack : undefined;
  94. this.logger.error(`Failed to publish ${label}: ${message}`, stack);
  95. }
  96. }
  97. }