import { Injectable } from '@angular/core'; import { Observable, forkJoin, of } from 'rxjs'; import { map, catchError, timeout } from 'rxjs/operators'; import { HttpApiService } from './http-api.service'; import { AmazonRawApiService } from './amazon-raw-api.service'; import { SorftimeApiService } from './sorftime-api.service'; import { API_CONFIG } from './api.config'; export interface ConnectivityResult { service: string; status: 'ok' | 'error' | 'timeout'; latency: number; message: string; } /** * API 连通性测试服务 * 用于验证各平台 API 的可用性 */ @Injectable({ providedIn: 'root' }) export class ApiConnectivityService { constructor( private api: HttpApiService, private amazonRaw: AmazonRawApiService, private sorftimeApi: SorftimeApiService ) { } /** 测试所有 API 连通性 */ testAll(): Observable { return forkJoin([ this.testAmazon(), this.testSorftime(), this.testTikHub() ]); } /** 测试所有 Sorftime 端点详细连通性 */ testSorftimeEndpoints(): Observable { return forkJoin([ this.testSorftime(), this.testSorftimeCategoryTree(), this.testSorftimeProductQuery(), this.testSorftimeKeywordQuery() ]); } /** Sorftime — CategoryTree 端点 */ private testSorftimeCategoryTree(): Observable { const start = Date.now(); return this.sorftimeApi.getCategoryTree().pipe( timeout(API_CONFIG.TIMEOUT), map((resp: any) => ({ service: 'Sorftime CategoryTree', status: 'ok' as const, latency: Date.now() - start, message: `返回数据: ${Array.isArray(resp?.data) ? resp.data.length : '有'}条类目` })), catchError(err => of({ service: 'Sorftime CategoryTree', status: (err?.name === 'TimeoutError' ? 'timeout' : 'error') as 'timeout' | 'error', latency: Date.now() - start, message: err?.message || '连接失败' })) ); } /** Sorftime — ProductQuery 端点 */ private testSorftimeProductQuery(): Observable { const start = Date.now(); return this.sorftimeApi.searchProducts('test', { pageSize: 1 }).pipe( timeout(API_CONFIG.TIMEOUT), map((resp: any) => ({ service: 'Sorftime ProductQuery', status: 'ok' as const, latency: Date.now() - start, message: `搜索正常` })), catchError(err => of({ service: 'Sorftime ProductQuery', status: (err?.name === 'TimeoutError' ? 'timeout' : 'error') as 'timeout' | 'error', latency: Date.now() - start, message: err?.message || '连接失败' })) ); } /** Sorftime — KeywordQuery 端点 */ private testSorftimeKeywordQuery(): Observable { const start = Date.now(); return this.sorftimeApi.searchKeywords('test').pipe( timeout(API_CONFIG.TIMEOUT), map((resp: any) => ({ service: 'Sorftime KeywordQuery', status: 'ok' as const, latency: Date.now() - start, message: `关键词查询正常` })), catchError(err => of({ service: 'Sorftime KeywordQuery', status: (err?.name === 'TimeoutError' ? 'timeout' : 'error') as 'timeout' | 'error', latency: Date.now() - start, message: err?.message || '连接失败' })) ); } /** 测试 Amazon SP-API */ testAmazon(): Observable { const start = Date.now(); return this.amazonRaw.getMarketplaceParticipations().pipe( timeout(API_CONFIG.TIMEOUT), map(() => ({ service: 'Amazon SP-API', status: 'ok' as const, latency: Date.now() - start, message: '连接正常' })), catchError(err => of({ service: 'Amazon SP-API', status: (err?.name === 'TimeoutError' ? 'timeout' : 'error') as 'timeout' | 'error', latency: Date.now() - start, message: err?.message || '连接失败' })) ); } /** 测试 Sorftime API */ testSorftime(): Observable { const start = Date.now(); return this.api.sorftimeForward('/api/ProductQuery', { query: { domain: 1 }, body: { Query: 1, QueryType: 7, Pattern: 'dress', Page: 1 } }).pipe( timeout(API_CONFIG.TIMEOUT), map(() => ({ service: 'Sorftime API', status: 'ok' as const, latency: Date.now() - start, message: '连接正常' })), catchError(err => of({ service: 'Sorftime API', status: (err?.name === 'TimeoutError' ? 'timeout' : 'error') as 'timeout' | 'error', latency: Date.now() - start, message: err?.message || '连接失败' })) ); } /** 测试 TikHub API */ testTikHub(): Observable { const start = Date.now(); return this.api.tikhubGet('/api/v1/tiktok/app/v3/fetch_video_search_result', { keyword: 'dress', sort_type: 0, publish_time: 0 }).pipe( timeout(API_CONFIG.TIMEOUT), map(() => ({ service: 'TikHub API', status: 'ok' as const, latency: Date.now() - start, message: '连接正常' })), catchError(err => of({ service: 'TikHub API', status: (err?.name === 'TimeoutError' ? 'timeout' : 'error') as 'timeout' | 'error', latency: Date.now() - start, message: err?.message || '连接失败' })) ); } }