107 lines
3.8 KiB
TypeScript
107 lines
3.8 KiB
TypeScript
import https from 'https';
|
|
import logger from '../utils/logger.js';
|
|
import { config } from '../config/index.js';
|
|
|
|
export class Notifier {
|
|
private isNotificationEnabled: boolean = true;
|
|
private readonly phoneNumbers: string[] = config.NOTIFICATION_PHONE_NUMBERS.length > 0
|
|
? config.NOTIFICATION_PHONE_NUMBERS
|
|
: []; // No default — must be configured via NOTIFICATION_PHONE_NUMBERS env var
|
|
|
|
/**
|
|
* Sets the notification status.
|
|
* @param status - True to enable, false to disable.
|
|
*/
|
|
public setNotificationStatus(status: boolean): void {
|
|
this.isNotificationEnabled = status;
|
|
logger.info(`[Notifier] WhatsApp notifications are now ${status ? 'ENABLED' : 'DISABLED'}`);
|
|
}
|
|
|
|
/**
|
|
* Gets the current notification status.
|
|
*/
|
|
public getNotificationStatus(): boolean {
|
|
return this.isNotificationEnabled;
|
|
}
|
|
|
|
/**
|
|
* Sends a WhatsApp message to all configured recipients.
|
|
* @param message - The content to send.
|
|
*/
|
|
public async sendAlert(message: string): Promise<void> {
|
|
if (!this.isNotificationEnabled) {
|
|
logger.info(`[Notifier] Notifications disabled. Skipping message: ${message.substring(0, 30)}...`);
|
|
return;
|
|
}
|
|
|
|
if (this.phoneNumbers.length === 0) {
|
|
logger.warn(`[Notifier] No phone numbers configured (set NOTIFICATION_PHONE_NUMBERS env var). Skipping.`);
|
|
return;
|
|
}
|
|
|
|
const sendPromises = this.phoneNumbers.map(number => this.sendSingleWhatsAppMessage(number, message));
|
|
|
|
try {
|
|
await Promise.all(sendPromises);
|
|
logger.info(`[Notifier] Alerts broadcasted to ${this.phoneNumbers.length} recipients.`);
|
|
} catch (error) {
|
|
logger.error('[Notifier] Broadcast failed partially/fully.');
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Sends a WhatsApp message to a specific number using ZenHustles API.
|
|
*/
|
|
private sendSingleWhatsAppMessage(to: string, message: string): Promise<any> {
|
|
return new Promise((resolve, reject) => {
|
|
const data = JSON.stringify({
|
|
message: message,
|
|
toWhatsAppNumber: to
|
|
});
|
|
|
|
const options = {
|
|
hostname: config.NOTIFICATION_API_HOST,
|
|
port: 443,
|
|
path: config.NOTIFICATION_API_PATH,
|
|
method: 'POST',
|
|
headers: {
|
|
'Content-Type': 'application/json',
|
|
'Content-Length': Buffer.byteLength(data)
|
|
}
|
|
};
|
|
|
|
const req = https.request(options, (res) => {
|
|
let responseBody = '';
|
|
|
|
res.on('data', (chunk) => {
|
|
responseBody += chunk;
|
|
});
|
|
|
|
res.on('end', () => {
|
|
if (res.statusCode && res.statusCode >= 200 && res.statusCode < 300) {
|
|
try {
|
|
const parsed = JSON.parse(responseBody);
|
|
logger.info(`[Notifier] Successfully sent to ${to}`);
|
|
resolve(parsed);
|
|
} catch (e) {
|
|
logger.info(`[Notifier] Successfully sent to ${to} (Non-JSON response)`);
|
|
resolve(responseBody);
|
|
}
|
|
} else {
|
|
logger.error(`[Notifier] Failed for ${to}. Status: ${res.statusCode}, Body: ${responseBody}`);
|
|
reject(new Error(`Status ${res.statusCode}`));
|
|
}
|
|
});
|
|
});
|
|
|
|
req.on('error', (error) => {
|
|
logger.error(`[Notifier] Network error for ${to}: ${error.message}`);
|
|
reject(error);
|
|
});
|
|
|
|
req.write(data);
|
|
req.end();
|
|
});
|
|
}
|
|
}
|