feat: Initial commit of PDF Tools project

This commit is contained in:
2025-08-25 02:29:48 +08:00
parent af6827cd9e
commit 30180e50a2
48 changed files with 36364 additions and 1 deletions

203
server/config/database.js Normal file
View File

@@ -0,0 +1,203 @@
const mongoose = require('mongoose');
const redis = require('redis');
class DatabaseConnection {
constructor() {
this.mongooseConnection = null;
this.redisClient = null;
}
// 连接MongoDB
async connectMongoDB() {
try {
const mongoUri = process.env.MONGODB_URI || 'mongodb://localhost:27017/pdf-tools';
this.mongooseConnection = await mongoose.connect(mongoUri, {
useNewUrlParser: true,
useUnifiedTopology: true,
serverSelectionTimeoutMS: 5000,
maxPoolSize: 10,
socketTimeoutMS: 45000,
});
console.log('✅ MongoDB连接成功');
// 监听连接事件
mongoose.connection.on('error', (err) => {
console.error('❌ MongoDB连接错误:', err);
});
mongoose.connection.on('disconnected', () => {
console.log('⚠️ MongoDB连接断开');
});
mongoose.connection.on('reconnected', () => {
console.log('✅ MongoDB重新连接成功');
});
return this.mongooseConnection;
} catch (error) {
console.error('❌ MongoDB连接失败:', error);
throw error;
}
}
// 连接Redis
async connectRedis() {
try {
const redisUrl = process.env.REDIS_URL || 'redis://localhost:6379';
this.redisClient = redis.createClient({
url: redisUrl,
retry_strategy: (options) => {
if (options.error && options.error.code === 'ECONNREFUSED') {
console.error('❌ Redis服务器拒绝连接');
return new Error('Redis服务器拒绝连接');
}
if (options.total_retry_time > 1000 * 60 * 60) {
console.error('❌ Redis重连超时');
return new Error('Redis重连超时');
}
if (options.attempt > 10) {
console.error('❌ Redis重连次数超限');
return undefined;
}
// 重连间隔递增
return Math.min(options.attempt * 100, 3000);
}
});
this.redisClient.on('error', (err) => {
console.error('❌ Redis连接错误:', err);
});
this.redisClient.on('connect', () => {
console.log('✅ Redis连接成功');
});
this.redisClient.on('reconnecting', () => {
console.log('🔄 Redis重新连接中...');
});
this.redisClient.on('ready', () => {
console.log('✅ Redis准备就绪');
});
await this.redisClient.connect();
return this.redisClient;
} catch (error) {
console.error('❌ Redis连接失败:', error);
// Redis连接失败不应该阻止应用启动
return null;
}
}
// 初始化所有数据库连接
async initialize() {
try {
// 并行连接数据库
const [mongoConnection, redisConnection] = await Promise.allSettled([
this.connectMongoDB(),
this.connectRedis()
]);
if (mongoConnection.status === 'rejected') {
throw new Error(`MongoDB连接失败: ${mongoConnection.reason.message}`);
}
if (redisConnection.status === 'rejected') {
console.warn('⚠️ Redis连接失败将使用内存缓存');
}
console.log('🎉 数据库初始化完成');
return {
mongodb: mongoConnection.value,
redis: redisConnection.status === 'fulfilled' ? redisConnection.value : null
};
} catch (error) {
console.error('❌ 数据库初始化失败:', error);
throw error;
}
}
// 关闭所有连接
async close() {
try {
const promises = [];
if (this.mongooseConnection) {
promises.push(mongoose.connection.close());
}
if (this.redisClient) {
promises.push(this.redisClient.quit());
}
await Promise.all(promises);
console.log('✅ 数据库连接已关闭');
} catch (error) {
console.error('❌ 关闭数据库连接失败:', error);
}
}
// 获取MongoDB连接状态
getMongoStatus() {
return {
status: mongoose.connection.readyState,
host: mongoose.connection.host,
port: mongoose.connection.port,
name: mongoose.connection.name
};
}
// 获取Redis连接状态
getRedisStatus() {
if (!this.redisClient) {
return { status: 'disconnected', message: '未连接' };
}
return {
status: this.redisClient.isReady ? 'connected' : 'disconnected',
message: this.redisClient.isReady ? '已连接' : '未连接'
};
}
// 健康检查
async healthCheck() {
const health = {
mongodb: { status: 'unknown', message: '' },
redis: { status: 'unknown', message: '' }
};
try {
// MongoDB健康检查
if (mongoose.connection.readyState === 1) {
await mongoose.connection.db.admin().ping();
health.mongodb = { status: 'healthy', message: '连接正常' };
} else {
health.mongodb = { status: 'unhealthy', message: '连接异常' };
}
} catch (error) {
health.mongodb = { status: 'unhealthy', message: error.message };
}
try {
// Redis健康检查
if (this.redisClient && this.redisClient.isReady) {
await this.redisClient.ping();
health.redis = { status: 'healthy', message: '连接正常' };
} else {
health.redis = { status: 'unhealthy', message: '连接异常' };
}
} catch (error) {
health.redis = { status: 'unhealthy', message: error.message };
}
return health;
}
}
// 创建单例实例
const databaseConnection = new DatabaseConnection();
module.exports = databaseConnection;