Server.js 5.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165
  1. const express = require('express')
  2. const cors = require('cors')
  3. const path = require('path')
  4. const fs = require('fs')
  5. const config = require('../config.json')
  6. const Logger = require('./Logger')
  7. const MySQL = require('../plugin/DataBase/MySQL')
  8. const Worker = require('./Lepao/Worker')
  9. const mq = require('../plugin/mq')
  10. const { mq: mqName } = require('../plugin/mq/mqPrefix')
  11. const { startLepaoSchedulePublisher } = require('../plugin/mq/lepaoSchedulePublisher')
  12. const OneBotV11 = require('../plugin/OneBot/OneBotV11')
  13. const AccessControl = require('./AccessControl')
  14. class SERVER {
  15. constructor() {
  16. this.app = express()
  17. this.port = config.port || 3000
  18. this.apiDirectory = path.join(__dirname, '../apis') // API 文件存放目录
  19. this.logger = new Logger(path.join(__dirname, '../logs/Server.log'), 'INFO')
  20. // 解析 JSON 请求体
  21. this.app.use(express.json())
  22. //解决cors跨域
  23. this.app.use(cors())
  24. //使用静态资源
  25. this.app.use('/uploads', express.static('./uploads'))
  26. this.app.use('/models', express.static('./models'))
  27. // 初始化数据库连接
  28. this.db = new MySQL()
  29. // 加载 API 路由
  30. this.loadAPIs(this.apiDirectory)
  31. }
  32. // 测试数据库连接
  33. async initDB() {
  34. try {
  35. this.logger.info('正在测试数据库连接')
  36. await this.db.connect()
  37. await this.db.close()
  38. } catch (error) {
  39. this.logger.error(`数据库连接失败: ${error.stack}`)
  40. process.exit(1)
  41. }
  42. }
  43. // 测试MQ连接
  44. async initMQ() {
  45. try {
  46. await mq.init()
  47. const ch = await mq.getChannel('health')
  48. await ch.assertQueue(mqName('mq_health_check'), { durable: false })
  49. this.logger.info('✅ RabbitMQ 初始化 & 测试成功')
  50. const worker = new Worker()
  51. try {
  52. await worker.start()
  53. this.logger.info('RunForge Worker 已启动,正在监听 MQ 任务...')
  54. startLepaoSchedulePublisher({
  55. logger: this.logger,
  56. intervalMs: config.rabbitmq?.lepaoScheduleTickMs ?? 2000,
  57. batch: config.rabbitmq?.lepaoScheduleBatch ?? 100
  58. })
  59. } catch (err) {
  60. console.error('RunForge Worker 启动失败:', err)
  61. process.exit(1)
  62. }
  63. } catch (e) {
  64. this.logger.error('❌ RabbitMQ 初始化失败')
  65. process.exit(1)
  66. }
  67. }
  68. async initOneBot() {
  69. try {
  70. const ok = await OneBotV11.initOneBotWs()
  71. if (ok) {
  72. this.logger.info('OneBot v11 ws 初始化成功,已开始监听消息')
  73. } else {
  74. this.logger.info('OneBot v11 ws 未初始化(可能未启用)')
  75. }
  76. } catch (err) {
  77. this.logger.error(`OneBot v11 ws 初始化失败: ${err.message}`)
  78. }
  79. }
  80. async initAccessControlSchema() {
  81. await AccessControl.ensurePermissionSchema()
  82. }
  83. loadAPIs(directory) {
  84. const items = fs.readdirSync(directory)
  85. items.forEach(item => {
  86. const itemPath = path.join(directory, item)
  87. const stats = fs.statSync(itemPath)
  88. if (stats.isDirectory()) {
  89. // 如果是目录,递归调用
  90. this.loadAPIs(itemPath)
  91. } else if (stats.isFile() && itemPath.endsWith('.js')) {
  92. // 如果是文件且是 JavaScript 文件
  93. this.loadAPIFile(itemPath)
  94. }
  95. })
  96. }
  97. // 加载单个 API 文件
  98. loadAPIFile(filePath) {
  99. try {
  100. const APIClass = require(filePath)
  101. for (const key in APIClass) {
  102. if (APIClass.hasOwnProperty(key)) {
  103. const apiInstance = new APIClass[key]()
  104. apiInstance.setupRoute()
  105. this.app.use('/', apiInstance.getRouter())
  106. this.logger.info(`已加载API:${apiInstance.path} 类型:${apiInstance.method}`)
  107. }
  108. }
  109. } catch (error) {
  110. this.logger.error(`加载API文件失败: ${filePath},错误: ${error.stack}`)
  111. }
  112. }
  113. start() {
  114. this.logger.info('============正在启动服务器============')
  115. // 初始化数据库连接
  116. this.initDB().then(() => {
  117. this.initMQ().then(() => {
  118. this.initAccessControlSchema().then(() => {
  119. this.initOneBot().then(() => {
  120. this.app.listen(this.port, () => {
  121. this.logger.info(`==========服务器正在 ${this.port} 端口上运行==========`)
  122. })
  123. }).catch(err => {
  124. this.logger.error(`OneBot 初始化异常: ${err.message}`)
  125. this.app.listen(this.port, () => {
  126. this.logger.info(`==========服务器正在 ${this.port} 端口上运行==========`)
  127. })
  128. })
  129. }).catch(err => {
  130. this.logger.error(`权限模型初始化异常: ${err.message}`)
  131. this.app.listen(this.port, () => {
  132. this.logger.info(`==========服务器正在 ${this.port} 端口上运行==========`)
  133. })
  134. })
  135. }).catch(err => {
  136. this.logger.error(`启动服务器失败: ${err.message}`)
  137. })
  138. }).catch(err => {
  139. this.logger.error(`启动服务器失败: ${err.message}`)
  140. process.exit(1) // 启动失败时退出进程
  141. })
  142. }
  143. }
  144. module.exports = SERVER