init: 整合项目(dashboard + www + docs)
This commit is contained in:
@@ -0,0 +1,23 @@
|
||||
const { Sequelize } = require('sequelize');
|
||||
const { isDevelopment } = require('./env');
|
||||
|
||||
const sequelize = new Sequelize(
|
||||
process.env.DATABASE_NAME || 'audio',
|
||||
process.env.DATABASE_USER || 'root',
|
||||
process.env.DATABASE_PASSWORD || 'root123',
|
||||
{
|
||||
host: process.env.DATABASE_HOST || 'localhost',
|
||||
port: parseInt(process.env.DATABASE_PORT || '3306', 10),
|
||||
dialect: 'mysql',
|
||||
dialectOptions: {
|
||||
charset: 'utf8mb4',
|
||||
},
|
||||
logging: isDevelopment ? (msg) => console.log(msg) : false,
|
||||
define: {
|
||||
timestamps: false,
|
||||
freezeTableName: true,
|
||||
},
|
||||
}
|
||||
);
|
||||
|
||||
module.exports = sequelize;
|
||||
@@ -0,0 +1,12 @@
|
||||
/**
|
||||
* 统一环境判断工具
|
||||
* 通过 APP_ENV 环境变量区分开发/正式环境
|
||||
* - development: 本地开发
|
||||
* - production: 正式环境(Docker 部署)
|
||||
*/
|
||||
const APP_ENV = (process.env.APP_ENV || 'development').trim().toLowerCase();
|
||||
|
||||
const isDevelopment = APP_ENV === 'development';
|
||||
const isProduction = APP_ENV === 'production';
|
||||
|
||||
module.exports = { APP_ENV, isDevelopment, isProduction };
|
||||
@@ -0,0 +1,14 @@
|
||||
/**
|
||||
* 统一从项目根目录加载 .env(dashboard/.env)
|
||||
* - 本地开发:读取根目录 .env
|
||||
* - Docker:由 compose env_file 注入,容器内无 .env 文件,不覆盖已有环境变量
|
||||
*/
|
||||
const path = require('path');
|
||||
const fs = require('fs');
|
||||
const dotenv = require('dotenv');
|
||||
|
||||
const rootEnvPath = path.resolve(__dirname, '../../../.env');
|
||||
|
||||
if (fs.existsSync(rootEnvPath)) {
|
||||
dotenv.config({ path: rootEnvPath });
|
||||
}
|
||||
@@ -0,0 +1,28 @@
|
||||
const winston = require('winston');
|
||||
const path = require('path');
|
||||
const fs = require('fs');
|
||||
|
||||
const logsDir = path.join(__dirname, '..', '..', 'logs');
|
||||
if (!fs.existsSync(logsDir)) {
|
||||
fs.mkdirSync(logsDir, { recursive: true });
|
||||
}
|
||||
|
||||
const logger = winston.createLogger({
|
||||
level: 'info',
|
||||
format: winston.format.combine(
|
||||
winston.format.timestamp({ format: 'YYYY-MM-DD HH:mm:ss' }),
|
||||
winston.format.printf(({ timestamp, level, message, ...meta }) => {
|
||||
const metaStr = Object.keys(meta).length ? ` ${JSON.stringify(meta)}` : '';
|
||||
return `${timestamp} - ${level} - ${message}${metaStr}`;
|
||||
})
|
||||
),
|
||||
transports: [
|
||||
new winston.transports.Console(),
|
||||
new winston.transports.File({
|
||||
filename: path.join(logsDir, 'app.log'),
|
||||
encoding: 'utf-8',
|
||||
}),
|
||||
],
|
||||
});
|
||||
|
||||
module.exports = logger;
|
||||
@@ -0,0 +1,31 @@
|
||||
const Redis = require('ioredis');
|
||||
const logger = require('./logger');
|
||||
|
||||
const REDIS_HOST = process.env.REDIS_HOST || '127.0.0.1';
|
||||
const REDIS_PORT = parseInt(process.env.REDIS_PORT || '6379', 10);
|
||||
const REDIS_PASSWORD = process.env.REDIS_PASSWORD || '';
|
||||
const REDIS_EQ_DB = parseInt(process.env.REDIS_EQ_DB || '1', 10);
|
||||
|
||||
let eqCacheClient = null;
|
||||
|
||||
function getEqCacheRedis() {
|
||||
if (!eqCacheClient) {
|
||||
const options = {
|
||||
host: REDIS_HOST,
|
||||
port: REDIS_PORT,
|
||||
db: REDIS_EQ_DB,
|
||||
maxRetriesPerRequest: 2,
|
||||
connectTimeout: 10000,
|
||||
};
|
||||
if (REDIS_PASSWORD) {
|
||||
options.password = REDIS_PASSWORD;
|
||||
}
|
||||
eqCacheClient = new Redis(options);
|
||||
eqCacheClient.on('error', (err) => {
|
||||
logger.error(`Redis EQ cache error: ${err.message}`);
|
||||
});
|
||||
}
|
||||
return eqCacheClient;
|
||||
}
|
||||
|
||||
module.exports = { getEqCacheRedis };
|
||||
Reference in New Issue
Block a user