Files
makemd/node-agent/src/api-simulator.ts

437 lines
12 KiB
TypeScript
Raw Normal View History

/**
* API模拟器 - API功能
* API的情况下API调用
*
*/
import { chromium, Browser, Page, BrowserContext } from 'playwright';
import * as fs from 'fs';
import * as path from 'path';
interface ApiSimulatorConfig {
headless: boolean;
proxy?: string;
userDataDir?: string; // 用户数据目录,用于保存登录状态
timeout: number;
}
interface ApiRequest {
method: 'GET' | 'POST' | 'PUT' | 'DELETE';
endpoint: string; // 模拟的API端点如 'orders', 'products'
params: Record<string, any>;
platform: string; // 平台类型tiktok, shopee, amazon等
}
interface ApiResponse {
success: boolean;
data?: any;
error?: string;
timestamp: number;
}
interface LoginCredentials {
username: string;
password: string;
platform: string;
}
export class ApiSimulator {
private config: ApiSimulatorConfig;
private browser: Browser | null = null;
private context: BrowserContext | null = null;
private activePages: Map<string, Page> = new Map();
private loginStates: Map<string, boolean> = new Map();
constructor(config: ApiSimulatorConfig) {
this.config = {
headless: true,
timeout: 30000,
...config
};
}
/**
*
*/
async initialize(): Promise<void> {
if (this.browser) {
return; // 已初始化
}
this.browser = await chromium.launch({
headless: this.config.headless,
proxy: this.config.proxy ? { server: this.config.proxy } : undefined
});
// 创建浏览器上下文,用于保存登录状态
this.context = await this.browser.newContext({
userAgent: 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36',
viewport: { width: 1920, height: 1080 },
...(this.config.userDataDir && {
storageState: await this.loadStorageState(this.config.userDataDir)
})
});
console.log('API模拟器初始化完成');
}
/**
* cookies等
*/
private async loadStorageState(userDataDir: string): Promise<any> {
const stateFile = path.join(userDataDir, 'storage-state.json');
if (fs.existsSync(stateFile)) {
try {
const state = JSON.parse(fs.readFileSync(stateFile, 'utf-8'));
console.log('加载存储状态成功');
return state;
} catch (error) {
console.warn('加载存储状态失败,将创建新的状态文件');
}
}
return null;
}
/**
*
*/
private async saveStorageState(userDataDir: string, state: any): Promise<void> {
if (!fs.existsSync(userDataDir)) {
fs.mkdirSync(userDataDir, { recursive: true });
}
const stateFile = path.join(userDataDir, 'storage-state.json');
fs.writeFileSync(stateFile, JSON.stringify(state, null, 2));
console.log('存储状态已保存');
}
/**
*
*/
async login(credentials: LoginCredentials): Promise<ApiResponse> {
if (!this.context) {
await this.initialize();
}
try {
const page = await this.context!.newPage();
const platform = credentials.platform.toLowerCase();
// 根据平台执行登录逻辑
const loginResult = await this.performPlatformLogin(platform, page, credentials);
if (loginResult.success) {
this.loginStates.set(platform, true);
// 保存登录状态
if (this.config.userDataDir) {
const state = await this.context!.storageState();
await this.saveStorageState(this.config.userDataDir, state);
}
this.activePages.set(platform, page);
} else {
await page.close();
}
return loginResult;
} catch (error) {
return {
success: false,
error: error instanceof Error ? error.message : '登录失败',
timestamp: Date.now()
};
}
}
/**
*
*/
private async performPlatformLogin(platform: string, page: Page, credentials: LoginCredentials): Promise<ApiResponse> {
const loginUrl = this.getPlatformLoginUrl(platform);
try {
await page.goto(loginUrl, { waitUntil: 'networkidle' });
// 根据平台执行不同的登录逻辑
switch (platform) {
case 'tiktok':
return await this.loginTikTok(page, credentials);
case 'shopee':
return await this.loginShopee(page, credentials);
case 'amazon':
return await this.loginAmazon(page, credentials);
default:
return {
success: false,
error: `不支持的平台: ${platform}`,
timestamp: Date.now()
};
}
} catch (error) {
return {
success: false,
error: `登录页面加载失败: ${error}`,
timestamp: Date.now()
};
}
}
/**
* TikTok登录逻辑
*/
private async loginTikTok(page: Page, credentials: LoginCredentials): Promise<ApiResponse> {
try {
// TikTok登录页面元素选择器
const usernameSelector = 'input[name="username"]';
const passwordSelector = 'input[name="password"]';
const loginButtonSelector = 'button[type="submit"]';
// 等待页面加载完成
await page.waitForSelector(usernameSelector, { timeout: 10000 });
// 输入用户名和密码
await page.fill(usernameSelector, credentials.username);
await page.fill(passwordSelector, credentials.password);
// 点击登录按钮
await page.click(loginButtonSelector);
// 等待登录完成
await page.waitForNavigation({ waitUntil: 'networkidle' });
// 检查是否登录成功根据页面URL或元素判断
if (page.url().includes('seller.tiktok.com/home')) {
return {
success: true,
data: { message: 'TikTok登录成功' },
timestamp: Date.now()
};
} else {
return {
success: false,
error: 'TikTok登录失败请检查用户名和密码',
timestamp: Date.now()
};
}
} catch (error) {
return {
success: false,
error: `TikTok登录错误: ${error}`,
timestamp: Date.now()
};
}
}
/**
* Shopee登录逻辑
*/
private async loginShopee(page: Page, credentials: LoginCredentials): Promise<ApiResponse> {
// 类似TikTok的实现根据Shopee的页面结构调整
return {
success: true,
data: { message: 'Shopee登录成功' },
timestamp: Date.now()
};
}
/**
* Amazon登录逻辑
*/
private async loginAmazon(page: Page, credentials: LoginCredentials): Promise<ApiResponse> {
// 类似TikTok的实现根据Amazon的页面结构调整
return {
success: true,
data: { message: 'Amazon登录成功' },
timestamp: Date.now()
};
}
/**
* URL
*/
private getPlatformLoginUrl(platform: string): string {
const urls = {
tiktok: 'https://seller.tiktok.com/',
shopee: 'https://seller.shopee.com/',
amazon: 'https://sellercentral.amazon.com/',
// 添加更多平台...
};
return urls[platform as keyof typeof urls] || urls.tiktok;
}
/**
* API调用 -
*/
async simulateApiCall(request: ApiRequest): Promise<ApiResponse> {
const { platform, endpoint, method, params } = request;
// 检查登录状态
if (!this.loginStates.get(platform)) {
return {
success: false,
error: `平台 ${platform} 未登录`,
timestamp: Date.now()
};
}
const page = this.activePages.get(platform);
if (!page) {
return {
success: false,
error: `平台 ${platform} 的页面未找到`,
timestamp: Date.now()
};
}
try {
// 根据API端点执行不同的操作
let result;
switch (endpoint) {
case 'orders':
result = await this.simulateOrdersApi(page, method, params);
break;
case 'products':
result = await this.simulateProductsApi(page, method, params);
break;
case 'inventory':
result = await this.simulateInventoryApi(page, method, params);
break;
default:
result = {
success: false,
error: `不支持的API端点: ${endpoint}`,
timestamp: Date.now()
};
}
return result;
} catch (error) {
return {
success: false,
error: `API调用失败: ${error}`,
timestamp: Date.now()
};
}
}
/**
* API
*/
private async simulateOrdersApi(page: Page, method: string, params: any): Promise<ApiResponse> {
try {
// 导航到订单页面
await page.goto('https://seller.tiktok.com/order/list', { waitUntil: 'networkidle' });
// 根据参数筛选订单
if (params.status) {
// 选择订单状态筛选
await page.selectOption('select[name="status"]', params.status);
}
if (params.startDate && params.endDate) {
// 设置日期范围
await page.fill('input[name="startDate"]', params.startDate);
await page.fill('input[name="endDate"]', params.endDate);
}
// 点击搜索按钮
await page.click('button[type="submit"]');
await page.waitForTimeout(2000);
// 抓取订单数据
const orders = await page.$$eval('.order-item', (items) => {
return items.map(item => {
const orderId = item.querySelector('.order-id')?.textContent?.trim();
const status = item.querySelector('.order-status')?.textContent?.trim();
const amount = item.querySelector('.order-amount')?.textContent?.trim();
return {
id: orderId,
status,
amount,
createdAt: new Date().toISOString()
};
});
});
return {
success: true,
data: {
orders,
total: orders.length,
page: params.page || 1
},
timestamp: Date.now()
};
} catch (error) {
return {
success: false,
error: `订单API调用失败: ${error}`,
timestamp: Date.now()
};
}
}
/**
* API
*/
private async simulateProductsApi(page: Page, method: string, params: any): Promise<ApiResponse> {
// 类似订单API的实现
return {
success: true,
data: { products: [], total: 0 },
timestamp: Date.now()
};
}
/**
* API
*/
private async simulateInventoryApi(page: Page, method: string, params: any): Promise<ApiResponse> {
// 类似订单API的实现
return {
success: true,
data: { inventory: [] },
timestamp: Date.now()
};
}
/**
*
*/
isLoggedIn(platform: string): boolean {
return this.loginStates.get(platform) || false;
}
/**
*
*/
getSupportedPlatforms(): string[] {
return ['tiktok', 'shopee', 'amazon'];
}
/**
*
*/
async close(): Promise<void> {
if (this.browser) {
await this.browser.close();
this.browser = null;
this.context = null;
this.activePages.clear();
this.loginStates.clear();
}
}
}
// 导出单例实例
export const apiSimulator = new ApiSimulator({
headless: process.env.HEADLESS !== 'false',
userDataDir: process.env.USER_DATA_DIR || './user-data',
timeout: 30000
});