StartAutoLepao.js 4.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117
  1. const API = require("../../lib/API");
  2. const db = require('../../plugin/DataBase/db')
  3. const Redis = require('../../plugin/DataBase/Redis')
  4. const mq = require('../../plugin/mq')
  5. const { assertRunforgeTaskIngress, publishRunforgeTask } = require('../../plugin/mq/runforgeTaskMq')
  6. const { scheduleDelayedRunforgeTask } = require('../../plugin/mq/lepaoAutoScheduleRedis')
  7. const jkesRedisKeys = require('../../plugin/jkes/redisKeys')
  8. const { BaseStdResponse } = require("../../BaseStdResponse");
  9. const { planJkesAutoRun } = require('../../plugin/jkes/monthPolicy')
  10. class StartAutoLepao extends API {
  11. constructor() {
  12. super();
  13. this.noEncrypt()
  14. this.setPath('/Corn/StartAutoLepao');
  15. this.setMethod('GET');
  16. }
  17. async onRequest(req, res) {
  18. try {
  19. res.json({
  20. ...BaseStdResponse.OK
  21. })
  22. const day = new Date().getDay()
  23. const hour = new Date().getHours()
  24. this.logger.info('开始执行自动乐跑任务')
  25. let sql = `
  26. SELECT name, student_num, auto_day, token, target_count
  27. FROM lepao_account
  28. WHERE auto_run = 1
  29. AND (auto_time = ? OR (auto_time = -1 AND today_auto_time = ?))
  30. AND JSON_CONTAINS(auto_day, CAST(? AS JSON))
  31. `
  32. let r = await db.query(sql, [hour, hour, day])
  33. if (!r)
  34. return this.logger.error('获取自动乐跑账号失败!')
  35. const nowMs = Date.now()
  36. const hourEnd = new Date()
  37. hourEnd.setHours(hourEnd.getHours() + 1, 0, 0, 0)
  38. const spreadWindowMs = Math.max(0, hourEnd.getTime() - nowMs)
  39. let channel
  40. try {
  41. channel = await mq.getChannel('lepao_corn')
  42. await assertRunforgeTaskIngress(channel, this.logger)
  43. } catch (err) {
  44. this.logger.error(`自动乐跑:连接 MQ 或声明拓扑失败:${err.message || err}`)
  45. return
  46. }
  47. for (const item of r) {
  48. const { name, student_num, auto_day, token, target_count } = item
  49. const isSuccess = await Redis.get(jkesRedisKeys.lepaoSuccess(student_num))
  50. if (isSuccess) {
  51. this.logger.info(`${name}(${student_num})当天已乐跑成功,不执行自动乐跑,如仍需跑步请手动发起`)
  52. continue
  53. }
  54. const plan = await planJkesAutoRun(student_num, auto_day, token, {
  55. monthTargetKm: target_count,
  56. stopAfterMinimum: true
  57. })
  58. if (!plan.run) {
  59. this.logger.info(`${name}(${student_num}) JKES 自动乐跑跳过:${plan.reason}`)
  60. continue
  61. }
  62. const delayMs = spreadWindowMs > 0 ? Math.floor(Math.random() * spreadWindowMs) : 0
  63. const fireAt = nowMs + delayMs
  64. const taskId = `lepao:auto:${fireAt}:${student_num}`
  65. const payload = {
  66. id: taskId,
  67. type: 'lepao.startRun',
  68. data: {
  69. taskId,
  70. account: student_num,
  71. targetKm: plan.targetKm,
  72. autoDoubleSlot: plan.targetKm >= 2
  73. },
  74. retry: 0
  75. }
  76. if (delayMs > 0) {
  77. try {
  78. await scheduleDelayedRunforgeTask(fireAt, payload, {
  79. name,
  80. account: student_num,
  81. delayMs
  82. })
  83. this.logger.info(
  84. `${name}(${student_num})已写入 Redis 调度(约 ${Math.round(delayMs / 1000)}s 后进 MQ)`
  85. )
  86. } catch (err) {
  87. this.logger.error(`${name}(${student_num})Redis 调度失败:${err.message || err}`)
  88. }
  89. continue
  90. }
  91. try {
  92. publishRunforgeTask(channel, payload)
  93. this.logger.info(`${name}(${student_num})已投递自动乐跑任务`)
  94. } catch (err) {
  95. this.logger.error(`${name}(${student_num})乐跑投递失败:${err.message || err}`)
  96. }
  97. }
  98. } catch (error) {
  99. this.logger.error(error)
  100. }
  101. }
  102. }
  103. module.exports.StartAutoLepao = StartAutoLepao;