rwadurian/backend/services/referral-service/src/infrastructure/external/authorization-service.clien...

189 lines
6.4 KiB
TypeScript
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

import { Injectable, Logger } from '@nestjs/common';
import { ConfigService } from '@nestjs/config';
import { HttpService } from '@nestjs/axios';
import { firstValueFrom, timeout, catchError } from 'rxjs';
import { of } from 'rxjs';
// authorization-service 返回格式(经过 TransformInterceptor 包装)
export interface AuthorizationServiceResponse<T> {
success: boolean;
data: T;
timestamp: string;
}
export interface NearestAuthorizationResult {
accountSequence: string | null; // 格式: D + YYMMDD + 5位序号
}
/**
* Authorization Service 客户端
* 用于查询用户推荐链中最近的省/市/社区授权用户
*/
@Injectable()
export class AuthorizationServiceClient {
private readonly logger = new Logger(AuthorizationServiceClient.name);
private readonly baseUrl: string;
private readonly timeoutMs: number;
constructor(
private readonly configService: ConfigService,
private readonly httpService: HttpService,
) {
this.baseUrl =
this.configService.get<string>('AUTHORIZATION_SERVICE_URL') ||
'http://localhost:3009';
this.timeoutMs = this.configService.get<number>('AUTHORIZATION_SERVICE_TIMEOUT_MS') || 5000;
}
/**
* 查找用户推荐链中最近的社区授权用户
* @param accountSequence 用户的 accountSequence (格式: D + YYMMDD + 5位序号)
* @returns 最近社区授权用户的 accountSequence如果没有则返回 null
*/
async findNearestCommunity(accountSequence: string): Promise<string | null> {
try {
const response = await firstValueFrom(
this.httpService
.get<AuthorizationServiceResponse<NearestAuthorizationResult>>(
`${this.baseUrl}/api/v1/authorization/nearest-community`,
{
params: { accountSequence },
},
)
.pipe(
timeout(this.timeoutMs),
catchError((error) => {
this.logger.warn(
`Failed to find nearest community for accountSequence=${accountSequence}: ${error.message}`,
);
return of({ data: { success: false, data: { accountSequence: null }, timestamp: '' } });
}),
),
);
// authorization-service 返回格式: { success, data: { accountSequence }, timestamp }
return response.data.data?.accountSequence ?? null;
} catch (error) {
this.logger.error(
`Error finding nearest community for accountSequence=${accountSequence}`,
error,
);
return null;
}
}
/**
* 查找用户推荐链中最近的省公司授权用户(匹配指定省份)
* @param accountSequence 用户的 accountSequence (格式: D + YYMMDD + 5位序号)
* @param provinceCode 省份代码
* @returns 最近省公司授权用户的 accountSequence如果没有则返回 null
*/
async findNearestProvince(
accountSequence: string,
provinceCode: string,
): Promise<string | null> {
try {
const response = await firstValueFrom(
this.httpService
.get<AuthorizationServiceResponse<NearestAuthorizationResult>>(
`${this.baseUrl}/api/v1/authorization/nearest-province`,
{
params: { accountSequence, provinceCode },
},
)
.pipe(
timeout(this.timeoutMs),
catchError((error) => {
this.logger.warn(
`Failed to find nearest province for accountSequence=${accountSequence}, provinceCode=${provinceCode}: ${error.message}`,
);
return of({ data: { success: false, data: { accountSequence: null }, timestamp: '' } });
}),
),
);
// authorization-service 返回格式: { success, data: { accountSequence }, timestamp }
return response.data.data?.accountSequence ?? null;
} catch (error) {
this.logger.error(
`Error finding nearest province for accountSequence=${accountSequence}, provinceCode=${provinceCode}`,
error,
);
return null;
}
}
/**
* 查找用户推荐链中最近的市公司授权用户(匹配指定城市)
* @param accountSequence 用户的 accountSequence (格式: D + YYMMDD + 5位序号)
* @param cityCode 城市代码
* @returns 最近市公司授权用户的 accountSequence如果没有则返回 null
*/
async findNearestCity(
accountSequence: string,
cityCode: string,
): Promise<string | null> {
try {
const response = await firstValueFrom(
this.httpService
.get<AuthorizationServiceResponse<NearestAuthorizationResult>>(
`${this.baseUrl}/api/v1/authorization/nearest-city`,
{
params: { accountSequence, cityCode },
},
)
.pipe(
timeout(this.timeoutMs),
catchError((error) => {
this.logger.warn(
`Failed to find nearest city for accountSequence=${accountSequence}, cityCode=${cityCode}: ${error.message}`,
);
return of({ data: { success: false, data: { accountSequence: null }, timestamp: '' } });
}),
),
);
// authorization-service 返回格式: { success, data: { accountSequence }, timestamp }
return response.data.data?.accountSequence ?? null;
} catch (error) {
this.logger.error(
`Error finding nearest city for accountSequence=${accountSequence}, cityCode=${cityCode}`,
error,
);
return null;
}
}
/**
* 并行查询所有授权信息
* 优化性能:同时发起三个请求
*/
async findAllNearestAuthorizations(
accountSequence: string, // 格式: D + YYMMDD + 5位序号
provinceCode: string,
cityCode: string,
): Promise<{
nearestCommunity: string | null;
nearestProvinceAuth: string | null;
nearestCityAuth: string | null;
}> {
const [nearestCommunity, nearestProvinceAuth, nearestCityAuth] =
await Promise.all([
this.findNearestCommunity(accountSequence),
this.findNearestProvince(accountSequence, provinceCode),
this.findNearestCity(accountSequence, cityCode),
]);
this.logger.debug(
`Authorization lookup for accountSequence=${accountSequence}: ` +
`community=${nearestCommunity}, province=${nearestProvinceAuth}, city=${nearestCityAuth}`,
);
return {
nearestCommunity,
nearestProvinceAuth,
nearestCityAuth,
};
}
}