import { Injectable, Logger, OnModuleDestroy, OnModuleInit } from '@nestjs/common'; import { ConfigService } from '@nestjs/config'; import amqp from 'amqplib'; export interface RealtimeNotificationPayload { userId: string; type: string; title: string; message: string; payload?: Record; } @Injectable() export class NotificationPublisherService implements OnModuleInit, OnModuleDestroy { private readonly logger = new Logger(NotificationPublisherService.name); private connection: { createChannel: () => Promise; close: () => Promise } | null = null; private channel: amqp.ConfirmChannel | amqp.Channel | null = null; private readonly queueName = 'id.notifications'; constructor(private readonly config: ConfigService) {} async onModuleInit() { await this.connect(); } async onModuleDestroy() { try { await this.channel?.close(); } catch { // ignore shutdown errors } try { await this.connection?.close(); } catch { // ignore shutdown errors } } private async connect() { const url = this.config.get('RABBITMQ_URL', 'amqp://lendry:lendry_password@localhost:5672/'); try { this.connection = (await amqp.connect(url)) as { createChannel: () => Promise; close: () => Promise; }; this.channel = await this.connection.createChannel(); await this.channel.assertQueue(this.queueName, { durable: true }); this.logger.log('Подключение к RabbitMQ для уведомлений установлено'); } catch (error) { this.logger.warn(`RabbitMQ недоступен, push-уведомления будут только в БД: ${error instanceof Error ? error.message : error}`); } } async publish(notification: RealtimeNotificationPayload) { if (!this.channel) { await this.connect(); } if (!this.channel) return; const body = Buffer.from( JSON.stringify({ userId: notification.userId, type: notification.type, title: notification.title, message: notification.message, payload: notification.payload ?? {} }) ); try { this.channel.sendToQueue(this.queueName, body, { persistent: true }); } catch (error) { this.logger.warn(`Не удалось отправить уведомление в RabbitMQ: ${error instanceof Error ? error.message : error}`); } } }