|
@@ -11,33 +11,33 @@ const { mq: mqName } = require('../plugin/mq/mqPrefix')
|
|
|
const { startLepaoSchedulePublisher } = require('../plugin/mq/lepaoSchedulePublisher')
|
|
const { startLepaoSchedulePublisher } = require('../plugin/mq/lepaoSchedulePublisher')
|
|
|
const OneBotV11 = require('../plugin/OneBot/OneBotV11')
|
|
const OneBotV11 = require('../plugin/OneBot/OneBotV11')
|
|
|
const AccessControl = require('./AccessControl')
|
|
const AccessControl = require('./AccessControl')
|
|
|
|
|
+const {
|
|
|
|
|
+ resolveServerRole,
|
|
|
|
|
+ shouldServeApi,
|
|
|
|
|
+ shouldRunLepaoWorker
|
|
|
|
|
+} = require('./serverRole')
|
|
|
|
|
|
|
|
class SERVER {
|
|
class SERVER {
|
|
|
constructor() {
|
|
constructor() {
|
|
|
- this.app = express()
|
|
|
|
|
|
|
+ this.serverRole = resolveServerRole()
|
|
|
this.port = config.port || 3000
|
|
this.port = config.port || 3000
|
|
|
- this.apiDirectory = path.join(__dirname, '../apis') // API 文件存放目录
|
|
|
|
|
|
|
+ this.apiDirectory = path.join(__dirname, '../apis')
|
|
|
|
|
|
|
|
- this.logger = new Logger(path.join(__dirname, '../logs/Server.log'), 'INFO')
|
|
|
|
|
|
|
+ const logName = this.serverRole === 'worker' ? 'WorkerServer.log' : 'Server.log'
|
|
|
|
|
+ this.logger = new Logger(path.join(__dirname, '../logs', logName), 'INFO')
|
|
|
|
|
|
|
|
- // 解析 JSON 请求体
|
|
|
|
|
- this.app.use(express.json())
|
|
|
|
|
-
|
|
|
|
|
- //解决cors跨域
|
|
|
|
|
- this.app.use(cors())
|
|
|
|
|
-
|
|
|
|
|
- //使用静态资源
|
|
|
|
|
- this.app.use('/uploads', express.static('./uploads'))
|
|
|
|
|
- this.app.use('/models', express.static('./models'))
|
|
|
|
|
-
|
|
|
|
|
- // 初始化数据库连接
|
|
|
|
|
this.db = new MySQL()
|
|
this.db = new MySQL()
|
|
|
|
|
|
|
|
- // 加载 API 路由
|
|
|
|
|
- this.loadAPIs(this.apiDirectory)
|
|
|
|
|
|
|
+ if (shouldServeApi(this.serverRole)) {
|
|
|
|
|
+ this.app = express()
|
|
|
|
|
+ this.app.use(express.json())
|
|
|
|
|
+ this.app.use(cors())
|
|
|
|
|
+ this.app.use('/uploads', express.static('./uploads'))
|
|
|
|
|
+ this.app.use('/models', express.static('./models'))
|
|
|
|
|
+ this.loadAPIs(this.apiDirectory)
|
|
|
|
|
+ }
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
- // 测试数据库连接
|
|
|
|
|
async initDB() {
|
|
async initDB() {
|
|
|
try {
|
|
try {
|
|
|
this.logger.info('正在测试数据库连接')
|
|
this.logger.info('正在测试数据库连接')
|
|
@@ -49,7 +49,17 @@ class SERVER {
|
|
|
}
|
|
}
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
- // 测试MQ连接
|
|
|
|
|
|
|
+ async startLepaoWorker() {
|
|
|
|
|
+ const worker = new Worker()
|
|
|
|
|
+ await worker.start()
|
|
|
|
|
+ this.logger.info('RunForge Worker 已启动,正在监听 MQ 任务...')
|
|
|
|
|
+ startLepaoSchedulePublisher({
|
|
|
|
|
+ logger: this.logger,
|
|
|
|
|
+ intervalMs: config.rabbitmq?.lepaoScheduleTickMs ?? 2000,
|
|
|
|
|
+ batch: config.rabbitmq?.lepaoScheduleBatch ?? 100
|
|
|
|
|
+ })
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
async initMQ() {
|
|
async initMQ() {
|
|
|
try {
|
|
try {
|
|
|
await mq.init()
|
|
await mq.init()
|
|
@@ -58,18 +68,15 @@ class SERVER {
|
|
|
await ch.assertQueue(mqName('mq_health_check'), { durable: false })
|
|
await ch.assertQueue(mqName('mq_health_check'), { durable: false })
|
|
|
this.logger.info('✅ RabbitMQ 初始化 & 测试成功')
|
|
this.logger.info('✅ RabbitMQ 初始化 & 测试成功')
|
|
|
|
|
|
|
|
- const worker = new Worker()
|
|
|
|
|
- try {
|
|
|
|
|
- await worker.start()
|
|
|
|
|
- this.logger.info('RunForge Worker 已启动,正在监听 MQ 任务...')
|
|
|
|
|
- startLepaoSchedulePublisher({
|
|
|
|
|
- logger: this.logger,
|
|
|
|
|
- intervalMs: config.rabbitmq?.lepaoScheduleTickMs ?? 2000,
|
|
|
|
|
- batch: config.rabbitmq?.lepaoScheduleBatch ?? 100
|
|
|
|
|
- })
|
|
|
|
|
- } catch (err) {
|
|
|
|
|
- console.error('RunForge Worker 启动失败:', err)
|
|
|
|
|
- process.exit(1)
|
|
|
|
|
|
|
+ if (shouldRunLepaoWorker(this.serverRole)) {
|
|
|
|
|
+ try {
|
|
|
|
|
+ await this.startLepaoWorker()
|
|
|
|
|
+ } catch (err) {
|
|
|
|
|
+ console.error('RunForge Worker 启动失败:', err)
|
|
|
|
|
+ process.exit(1)
|
|
|
|
|
+ }
|
|
|
|
|
+ } else {
|
|
|
|
|
+ this.logger.info('serverRole=api,跳过乐跑 Worker 与 Redis→MQ 调度')
|
|
|
}
|
|
}
|
|
|
} catch (e) {
|
|
} catch (e) {
|
|
|
this.logger.error('❌ RabbitMQ 初始化失败')
|
|
this.logger.error('❌ RabbitMQ 初始化失败')
|
|
@@ -102,16 +109,13 @@ class SERVER {
|
|
|
const stats = fs.statSync(itemPath)
|
|
const stats = fs.statSync(itemPath)
|
|
|
|
|
|
|
|
if (stats.isDirectory()) {
|
|
if (stats.isDirectory()) {
|
|
|
- // 如果是目录,递归调用
|
|
|
|
|
this.loadAPIs(itemPath)
|
|
this.loadAPIs(itemPath)
|
|
|
} else if (stats.isFile() && itemPath.endsWith('.js')) {
|
|
} else if (stats.isFile() && itemPath.endsWith('.js')) {
|
|
|
- // 如果是文件且是 JavaScript 文件
|
|
|
|
|
this.loadAPIFile(itemPath)
|
|
this.loadAPIFile(itemPath)
|
|
|
}
|
|
}
|
|
|
})
|
|
})
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
- // 加载单个 API 文件
|
|
|
|
|
loadAPIFile(filePath) {
|
|
loadAPIFile(filePath) {
|
|
|
try {
|
|
try {
|
|
|
const APIClass = require(filePath)
|
|
const APIClass = require(filePath)
|
|
@@ -129,36 +133,45 @@ class SERVER {
|
|
|
}
|
|
}
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
|
|
+ listenHttp() {
|
|
|
|
|
+ this.app.listen(this.port, () => {
|
|
|
|
|
+ this.logger.info(`==========服务器正在 ${this.port} 端口上运行 (role=${this.serverRole})==========`)
|
|
|
|
|
+ })
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ async startApiServices() {
|
|
|
|
|
+ try {
|
|
|
|
|
+ await this.initAccessControlSchema()
|
|
|
|
|
+ } catch (err) {
|
|
|
|
|
+ this.logger.error(`权限模型初始化异常: ${err.message}`)
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ try {
|
|
|
|
|
+ await this.initOneBot()
|
|
|
|
|
+ } catch (err) {
|
|
|
|
|
+ this.logger.error(`OneBot 初始化异常: ${err.message}`)
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ this.listenHttp()
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
start() {
|
|
start() {
|
|
|
- this.logger.info('============正在启动服务器============')
|
|
|
|
|
-
|
|
|
|
|
- // 初始化数据库连接
|
|
|
|
|
- this.initDB().then(() => {
|
|
|
|
|
- this.initMQ().then(() => {
|
|
|
|
|
- this.initAccessControlSchema().then(() => {
|
|
|
|
|
- this.initOneBot().then(() => {
|
|
|
|
|
- this.app.listen(this.port, () => {
|
|
|
|
|
- this.logger.info(`==========服务器正在 ${this.port} 端口上运行==========`)
|
|
|
|
|
- })
|
|
|
|
|
- }).catch(err => {
|
|
|
|
|
- this.logger.error(`OneBot 初始化异常: ${err.message}`)
|
|
|
|
|
- this.app.listen(this.port, () => {
|
|
|
|
|
- this.logger.info(`==========服务器正在 ${this.port} 端口上运行==========`)
|
|
|
|
|
- })
|
|
|
|
|
- })
|
|
|
|
|
- }).catch(err => {
|
|
|
|
|
- this.logger.error(`权限模型初始化异常: ${err.message}`)
|
|
|
|
|
- this.app.listen(this.port, () => {
|
|
|
|
|
- this.logger.info(`==========服务器正在 ${this.port} 端口上运行==========`)
|
|
|
|
|
- })
|
|
|
|
|
- })
|
|
|
|
|
- }).catch(err => {
|
|
|
|
|
- this.logger.error(`启动服务器失败: ${err.message}`)
|
|
|
|
|
|
|
+ this.logger.info(`============正在启动 (role=${this.serverRole})============`)
|
|
|
|
|
+
|
|
|
|
|
+ this.initDB()
|
|
|
|
|
+ .then(() => this.initMQ())
|
|
|
|
|
+ .then(async () => {
|
|
|
|
|
+ if (!shouldServeApi(this.serverRole)) {
|
|
|
|
|
+ this.logger.info('serverRole=worker,未启动 HTTP API,进程将保持运行以消费乐跑任务')
|
|
|
|
|
+ return
|
|
|
|
|
+ }
|
|
|
|
|
+ await this.startApiServices()
|
|
|
|
|
+ })
|
|
|
|
|
+ .catch((err) => {
|
|
|
|
|
+ this.logger.error(`启动失败: ${err.message || err}`)
|
|
|
|
|
+ if (err.stack) this.logger.error(err.stack)
|
|
|
|
|
+ process.exit(1)
|
|
|
})
|
|
})
|
|
|
- }).catch(err => {
|
|
|
|
|
- this.logger.error(`启动服务器失败: ${err.message}`)
|
|
|
|
|
- process.exit(1) // 启动失败时退出进程
|
|
|
|
|
- })
|
|
|
|
|
}
|
|
}
|
|
|
}
|
|
}
|
|
|
|
|
|