import { Injectable, Logger } from "@nestjs/common"; import { isAxiosError } from "axios"; import { buildParsianTemplateMessage } from "./parsian-template-messages"; import { SmsProviderException, SmsTransportException, } from "./sms-provider.exception"; import { SendMessage, VerifyLookUpMessage } from "./sms-gateway.types"; import { firstValueFrom } from "rxjs"; import { HttpService } from "@nestjs/axios"; @Injectable() export class ParsianSmsGateway { private readonly logger = new Logger(ParsianSmsGateway.name); constructor(private readonly httpService: HttpService) {} async sendMessage(data: SendMessage) { try { const body = await this.requestSend(data.receptor, data.message); this.logger.log(`Parsian Send ok receptor=${data.receptor}`); return body; } catch (e) { if (e instanceof SmsProviderException) throw e; const detail = isAxiosError(e) ? { status: e.response?.status, data: e.response?.data, message: e.message, } : e; this.logger.error( `Parsian Send transport error receptor=${data.receptor} detail=${JSON.stringify(detail)}`, ); throw new SmsTransportException("send", { receptor: data.receptor }, e); } } async verifyLookUp(data: VerifyLookUpMessage) { const message = buildParsianTemplateMessage(data); try { const body = await this.requestSend(data.receptor, message); this.logger.log( `Parsian verifyLookUp ok receptor=${data.receptor} template=${data.template}`, ); return body; } catch (e) { if (e instanceof SmsProviderException) throw e; const detail = isAxiosError(e) ? { status: e.response?.status, data: e.response?.data, message: e.message, } : e; this.logger.error( `Parsian verifyLookUp transport error receptor=${data.receptor} template=${data.template} detail=${JSON.stringify(detail)}`, ); throw new SmsTransportException( "verifyLookup", { receptor: data.receptor, template: data.template }, e, ); } } private parsianHeaders() { return { "Content-Type": "application/json", "X-PACKAGE-API-KEY": process.env.PARSIAN_API_KEY ?? "", Authorization: `Basic ${process.env.PARSIAN_BASIC_TOKEN ?? ""}`, }; } private async requestSend( receptor: string, message: string, ): Promise { const baseUrl = process.env.PARSIAN_SMS_URL; if (!baseUrl?.trim()) { throw new SmsTransportException( "send", { receptor }, new Error("PARSIAN_SMS_URL is not configured"), ); } const url = `${baseUrl}=${receptor}&Message=${encodeURIComponent(message)}`; const response = await firstValueFrom( this.httpService.get(url, { headers: this.parsianHeaders() }), ); if (response.status < 200 || response.status >= 300) { throw new SmsProviderException("send", { receptor, providerBody: response.data, normalized: { httpLikeStatus: response.status, message: String(response.statusText ?? ""), raw: JSON.stringify(response.data), }, }); } return response.data; } }