feat: 百度网盘登录修正为可转存的方法&redis全局处理

This commit is contained in:
mazxd
2025-05-14 22:50:30 +08:00
parent 3ae21ac4c2
commit 38a5c69a37
5 changed files with 160 additions and 67 deletions
+15 -9
View File
@@ -116,11 +116,8 @@ export class BaiduDriveAdapter implements DriveAdapter {
try { try {
// 1. 尝试登录 // 1. 尝试登录
await this.ensureLoggedIn(account); await this.ensureLoggedIn(account);
// 2. 验证登录状态
await this.executeCommand(['pwd']);
// 3. 更新账号状态为活跃 // 2. 更新账号状态为活跃
await this.updateAccountStatus(account, 'active'); await this.updateAccountStatus(account, 'active');
return true; return true;
} catch (error: any) { } catch (error: any) {
@@ -133,14 +130,23 @@ export class BaiduDriveAdapter implements DriveAdapter {
private async ensureLoggedIn(account: Account): Promise<void> { private async ensureLoggedIn(account: Account): Promise<void> {
try { try {
// 先尝试执行一个命令来检查是否已登录 // 检查登录状态
await this.executeCommand(['pwd']); const whoResult = await this.executeCommand(['who']);
// 如果 uid 为 0 或用户名为空,说明未登录
if (whoResult.includes('uid: 0') || whoResult.includes('用户名: ,')) {
// 执行登录
await this.executeCommand([
'login',
`-bduss=${account.accountIdentifier}`,
`-stoken=${account.credentials}`
]);
}
} catch (error) { } catch (error) {
// 如果未登录,则执行登录 // 如果命令执行失败,也尝试登录
await this.executeCommand([ await this.executeCommand([
'login', 'login',
account.accountIdentifier, `-bduss=${account.accountIdentifier}`,
account.credentials `-stoken=${account.credentials}`
]); ]);
} }
} }
+5 -4
View File
@@ -4,14 +4,15 @@ import rateLimit from 'express-rate-limit'
import swaggerUi from 'swagger-ui-express' import swaggerUi from 'swagger-ui-express'
import { swaggerSpec } from './config/swagger' import { swaggerSpec } from './config/swagger'
import { getSearchResults, getLinkForResource } from './controllers/searchController' import { getSearchResults, getLinkForResource } from './controllers/searchController'
import { initRedis } from './lib/redis' import { RedisService } from './services/redisService'
import logger from './lib/logger' import logger from './lib/logger'
const app = express() const app = express()
// 初始化 Redis 连接 // 初始化 Redis 服务
initRedis().catch(err => { const redisService = RedisService.getInstance();
logger.error('Redis 初始化失败,应用启动终止', { error: err }) redisService.initialize().catch(err => {
logger.error('Redis 服务初始化失败,应用启动终止', { error: err })
process.exit(1) process.exit(1)
}) })
-29
View File
@@ -1,29 +0,0 @@
import { createClient } from 'redis';
import { config } from '../config/config';
import logger from './logger';
// 创建 Redis 客户端实例
const redis = createClient({
url: `redis://${config.redis.host}:${config.redis.port}`,
password: config.redis.password
});
// Redis 错误处理和连接监控
redis.on('error', err => logger.error('Redis 客户端错误:', { error: err }));
redis.on('connect', () => logger.info('Redis 客户端已连接'));
redis.on('ready', () => logger.info('Redis 客户端就绪'));
redis.on('reconnecting', () => logger.warn('Redis 客户端正在重连'));
// 初始化 Redis 连接
export async function initRedis(): Promise<void> {
try {
await redis.connect();
logger.info('Redis 连接初始化成功');
} catch (err) {
logger.error('Redis 连接初始化失败:', { error: err });
throw err;
}
}
// 导出 Redis 客户端实例
export { redis };
+108
View File
@@ -0,0 +1,108 @@
import { createClient, RedisClientType } from 'redis';
import { config } from '../config/config';
import logger from '../lib/logger';
export class RedisService {
private static instance: RedisService;
private client: RedisClientType;
private isInitialized: boolean = false;
private constructor() {
this.client = createClient({
url: `redis://${config.redis.host}:${config.redis.port}`,
password: config.redis.password,
socket: {
reconnectStrategy: (retries) => {
if (retries > 10) {
logger.error('Redis 重连次数过多,停止重连');
return new Error('Redis 重连失败');
}
return Math.min(retries * 100, 3000);
}
}
});
this.setupEventListeners();
}
private setupEventListeners() {
this.client.on('error', err => {
logger.error('Redis 客户端错误:', { error: err });
});
this.client.on('connect', () => {
logger.info('Redis 客户端已连接', {
host: config.redis.host,
port: config.redis.port
});
});
this.client.on('ready', () => {
logger.info('Redis 客户端就绪');
});
this.client.on('reconnecting', () => {
logger.warn('Redis 客户端正在重连');
});
this.client.on('end', () => {
logger.warn('Redis 连接已关闭');
});
}
public static getInstance(): RedisService {
if (!RedisService.instance) {
RedisService.instance = new RedisService();
}
return RedisService.instance;
}
public async initialize(): Promise<void> {
if (!this.isInitialized) {
try {
await this.client.connect();
this.isInitialized = true;
logger.info('Redis 服务初始化成功');
} catch (err) {
logger.error('Redis 服务初始化失败:', { error: err });
throw err;
}
}
}
public async get(key: string): Promise<string | null> {
if (!this.isInitialized) {
await this.initialize();
}
return this.client.get(key);
}
public async set(key: string, value: string, options?: { EX?: number }): Promise<void> {
if (!this.isInitialized) {
await this.initialize();
}
await this.client.set(key, value, options);
}
public async del(key: string): Promise<void> {
if (!this.isInitialized) {
await this.initialize();
}
await this.client.del(key);
}
public async exists(key: string): Promise<boolean> {
if (!this.isInitialized) {
await this.initialize();
}
const result = await this.client.exists(key);
return result === 1;
}
public async quit(): Promise<void> {
if (this.isInitialized) {
await this.client.quit();
this.isInitialized = false;
}
}
}
+32 -25
View File
@@ -5,45 +5,52 @@ import { handleError } from '../decorators/errorHandler';
import { AppError } from '../utils/AppError'; import { AppError } from '../utils/AppError';
import { LoginResponse, SearchResponse, SearchParams, SearchResult, LinkResult } from '../entity/search.types'; import { LoginResponse, SearchResponse, SearchParams, SearchResult, LinkResult } from '../entity/search.types';
import { SEARCH_SERVICE } from '../constants/redis.keys'; import { SEARCH_SERVICE } from '../constants/redis.keys';
import { redis } from '../lib/redis'; import { RedisService } from './redisService';
export class SearchService { export class SearchService {
private baseUrl: string; private baseUrl: string;
private redisService: RedisService;
constructor() { constructor() {
this.baseUrl = config.searchService.baseUrl; this.baseUrl = config.searchService.baseUrl;
this.redisService = RedisService.getInstance();
logger.info('搜索服务已初始化', { baseUrl: this.baseUrl }); logger.info('搜索服务已初始化', { baseUrl: this.baseUrl });
} }
@handleError('获取认证 token 失败') @handleError('获取认证 token 失败')
private async getToken(): Promise<string> { private async getToken(): Promise<string> {
// 尝试从 Redis 获取 token try {
const cachedToken = await redis.get(SEARCH_SERVICE.TOKEN); // 尝试从 Redis 获取 token
if (cachedToken) { const cachedToken = await this.redisService.get(SEARCH_SERVICE.TOKEN);
logger.debug('从缓存中获取到 token'); if (cachedToken) {
return cachedToken; logger.debug('从缓存中获取到 token');
} return cachedToken;
logger.info('缓存中未找到 token,尝试登录获取');
// 登录获取新 token
const response = await axios.post<LoginResponse>(
`${this.baseUrl}${config.searchService.endpoints.login}`,
{
username: process.env.SEARCH_SERVICE_USERNAME,
password: process.env.SEARCH_SERVICE_PASSWORD,
} }
);
if (!response.data.success || !response.data.data.token) { logger.info('缓存中未找到 token,尝试登录获取');
throw new AppError('登录失败', 401); // 登录获取新 token
const response = await axios.post<LoginResponse>(
`${this.baseUrl}${config.searchService.endpoints.login}`,
{
username: process.env.SEARCH_SERVICE_USERNAME,
password: process.env.SEARCH_SERVICE_PASSWORD,
}
);
if (!response.data.success || !response.data.data.token) {
throw new AppError('登录失败', 401);
}
logger.info('成功获取新 token');
// 将 token 缓存到 Redis
await this.redisService.set(SEARCH_SERVICE.TOKEN, response.data.data.token, {
EX: 21600, // 6 小时
});
return response.data.data.token;
} catch (error) {
logger.error('获取 token 失败:', { error });
throw error;
} }
logger.info('成功获取新 token');
// 将 token 缓存到 Redis
await redis.set(SEARCH_SERVICE.TOKEN, response.data.data.token, {
EX: 21600, // 6 小时
});
return response.data.data.token;
} }
@handleError('搜索执行失败') @handleError('搜索执行失败')