feat: 百度网盘登录修正为可转存的方法&redis全局处理
This commit is contained in:
@@ -116,11 +116,8 @@ export class BaiduDriveAdapter implements DriveAdapter {
|
||||
try {
|
||||
// 1. 尝试登录
|
||||
await this.ensureLoggedIn(account);
|
||||
|
||||
// 2. 验证登录状态
|
||||
await this.executeCommand(['pwd']);
|
||||
|
||||
// 3. 更新账号状态为活跃
|
||||
// 2. 更新账号状态为活跃
|
||||
await this.updateAccountStatus(account, 'active');
|
||||
return true;
|
||||
} catch (error: any) {
|
||||
@@ -133,14 +130,23 @@ export class BaiduDriveAdapter implements DriveAdapter {
|
||||
|
||||
private async ensureLoggedIn(account: Account): Promise<void> {
|
||||
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) {
|
||||
// 如果未登录,则执行登录
|
||||
// 如果命令执行失败,也尝试登录
|
||||
await this.executeCommand([
|
||||
'login',
|
||||
account.accountIdentifier,
|
||||
account.credentials
|
||||
`-bduss=${account.accountIdentifier}`,
|
||||
`-stoken=${account.credentials}`
|
||||
]);
|
||||
}
|
||||
}
|
||||
|
||||
+5
-4
@@ -4,14 +4,15 @@ import rateLimit from 'express-rate-limit'
|
||||
import swaggerUi from 'swagger-ui-express'
|
||||
import { swaggerSpec } from './config/swagger'
|
||||
import { getSearchResults, getLinkForResource } from './controllers/searchController'
|
||||
import { initRedis } from './lib/redis'
|
||||
import { RedisService } from './services/redisService'
|
||||
import logger from './lib/logger'
|
||||
|
||||
const app = express()
|
||||
|
||||
// 初始化 Redis 连接
|
||||
initRedis().catch(err => {
|
||||
logger.error('Redis 初始化失败,应用启动终止', { error: err })
|
||||
// 初始化 Redis 服务
|
||||
const redisService = RedisService.getInstance();
|
||||
redisService.initialize().catch(err => {
|
||||
logger.error('Redis 服务初始化失败,应用启动终止', { error: err })
|
||||
process.exit(1)
|
||||
})
|
||||
|
||||
|
||||
@@ -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 };
|
||||
@@ -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;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -5,45 +5,52 @@ import { handleError } from '../decorators/errorHandler';
|
||||
import { AppError } from '../utils/AppError';
|
||||
import { LoginResponse, SearchResponse, SearchParams, SearchResult, LinkResult } from '../entity/search.types';
|
||||
import { SEARCH_SERVICE } from '../constants/redis.keys';
|
||||
import { redis } from '../lib/redis';
|
||||
import { RedisService } from './redisService';
|
||||
|
||||
export class SearchService {
|
||||
private baseUrl: string;
|
||||
private redisService: RedisService;
|
||||
|
||||
constructor() {
|
||||
this.baseUrl = config.searchService.baseUrl;
|
||||
this.redisService = RedisService.getInstance();
|
||||
logger.info('搜索服务已初始化', { baseUrl: this.baseUrl });
|
||||
}
|
||||
|
||||
@handleError('获取认证 token 失败')
|
||||
private async getToken(): Promise<string> {
|
||||
// 尝试从 Redis 获取 token
|
||||
const cachedToken = await redis.get(SEARCH_SERVICE.TOKEN);
|
||||
if (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,
|
||||
try {
|
||||
// 尝试从 Redis 获取 token
|
||||
const cachedToken = await this.redisService.get(SEARCH_SERVICE.TOKEN);
|
||||
if (cachedToken) {
|
||||
logger.debug('从缓存中获取到 token');
|
||||
return cachedToken;
|
||||
}
|
||||
);
|
||||
|
||||
if (!response.data.success || !response.data.data.token) {
|
||||
throw new AppError('登录失败', 401);
|
||||
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) {
|
||||
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('搜索执行失败')
|
||||
|
||||
Reference in New Issue
Block a user