Files
CRM_Montzar/apps/api/src/integrations/tahesab/tahesab-http.client.ts
T

123 lines
3.5 KiB
TypeScript
Raw Normal View History

import * as http from 'http';
import * as https from 'https';
import { URL } from 'url';
import {
BadGatewayException,
Injectable,
Logger,
RequestTimeoutException,
} from '@nestjs/common';
export type TahesabCallOptions = {
baseUrl: string;
token: string;
dbName: string;
/** مسیر OpenAPI مثل DoNewMoshtari یا CheckHealth-SSL */
path: string;
/** کلید body؛ اگر خالی باشد فقط GET بدون body */
bodyKey?: string;
args?: unknown[];
method?: 'GET' | 'POST';
allowInsecureTls?: boolean;
timeoutMs?: number;
};
@Injectable()
export class TahesabHttpClient {
private readonly logger = new Logger(TahesabHttpClient.name);
async call<T = unknown>(opts: TahesabCallOptions): Promise<T> {
const base = opts.baseUrl.replace(/\/+$/, '');
const path = opts.path.replace(/^\/+/, '');
const url = new URL(`${base}/${path}`);
const method = opts.method ?? (opts.bodyKey ? 'POST' : 'GET');
const timeoutMs = opts.timeoutMs ?? 30_000;
const headers: Record<string, string> = {
Authorization: `Bearer ${opts.token}`,
DBname: opts.dbName,
DBName: opts.dbName,
Accept: 'application/json',
Host: url.host,
};
let body: string | undefined;
if (method === 'POST' && opts.bodyKey) {
headers['Content-Type'] = 'application/json';
body = JSON.stringify({ [opts.bodyKey]: opts.args ?? [] });
headers['Content-Length'] = Buffer.byteLength(body).toString();
}
const isHttps = url.protocol === 'https:';
const lib = isHttps ? https : http;
const agent =
isHttps && opts.allowInsecureTls
? new https.Agent({ rejectUnauthorized: false })
: undefined;
return new Promise<T>((resolve, reject) => {
const req = lib.request(
{
protocol: url.protocol,
hostname: url.hostname,
port: url.port || (isHttps ? 443 : 80),
path: `${url.pathname}${url.search}`,
method,
headers,
timeout: timeoutMs,
agent,
},
(res) => {
const chunks: Buffer[] = [];
res.on('data', (c) => chunks.push(c));
res.on('end', () => {
const text = Buffer.concat(chunks).toString('utf8');
let json: unknown = null;
if (text) {
try {
json = JSON.parse(text);
} catch {
json = { raw: text };
}
}
const status = res.statusCode ?? 0;
if (status < 200 || status >= 300) {
this.logger.warn(
`Tahesab ${method} ${path} → ${status}: ${text.slice(0, 400)}`,
);
reject(
new BadGatewayException(
`پاسخ نامعتبر ته‌حساب (${status}) برای ${path}`,
),
);
return;
}
resolve(json as T);
});
},
);
req.on('timeout', () => {
req.destroy();
reject(
new RequestTimeoutException(
`مهلت اتصال به ته‌حساب برای ${path} به پایان رسید.`,
),
);
});
req.on('error', (err) => {
this.logger.error(`Tahesab call failed: ${path}`, err);
reject(
new BadGatewayException(
`اتصال به ته‌حساب ناموفق بود: ${err.message}`,
),
);
});
if (body) req.write(body);
req.end();
});
}
}