util_notify.lua 5.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184
  1. local util_notify_channel = require "util_notify_channel"
  2. local util_notify = {}
  3. -- 消息队列
  4. local msg_queue = {}
  5. -- 发送计数
  6. local msg_count = 0
  7. local error_count = 0
  8. local function urlencodeTab(params)
  9. local msg = {}
  10. for k, v in pairs(params) do
  11. table.insert(msg, string.urlEncode(k) .. "=" .. string.urlEncode(v))
  12. table.insert(msg, "&")
  13. end
  14. table.remove(msg)
  15. return table.concat(msg)
  16. end
  17. --- 发送通知
  18. -- @param msg 消息内容
  19. -- @param channel 通知渠道
  20. -- @return true: 无需重发, false: 需要重发
  21. local function send(msg, channel)
  22. log.info("util_notify.send", "发送通知", channel)
  23. -- 判断消息内容 msg
  24. if type(msg) ~= "string" or msg == "" then
  25. log.error("util_notify.send", "发送通知失败", "msg 参数错误", type(msg))
  26. return true
  27. end
  28. -- 判断通知渠道 channel
  29. if channel and util_notify_channel[channel] == nil then
  30. log.error("util_notify.send", "发送通知失败", "未知通知渠道", channel)
  31. return true
  32. end
  33. -- 发送通知
  34. local code, headers, body = util_notify_channel[channel](msg)
  35. if code == nil then
  36. log.info("util_notify.send", "发送通知失败, 无需重发", "code:", code, "body:", body)
  37. return true
  38. end
  39. if code >= 200 and code < 500 and code ~= 408 and code ~= 409 and code ~= 425 and code ~= 429 then
  40. log.info("util_notify.send", "发送通知成功", "code:", code, "body:", body)
  41. return true
  42. end
  43. log.error("util_notify.send", "发送通知失败, 等待重发", "code:", code, "body:", body)
  44. return false
  45. end
  46. --- 添加到消息队列
  47. -- @param msg 消息内容
  48. -- @param channels 通知渠道
  49. -- @param id 消息唯一标识
  50. function util_notify.add(msg, channels, id)
  51. msg_count = msg_count + 1
  52. if id == nil or id == "" then
  53. id = "msg-t" .. os.time() .. "c" .. msg_count .. "r" .. math.random(9999)
  54. end
  55. if type(msg) == "table" then
  56. msg = table.concat(msg, "\n")
  57. end
  58. channels = channels or config.NOTIFY_TYPE
  59. if type(channels) ~= "table" then
  60. channels = { channels }
  61. end
  62. for _, channel in ipairs(channels) do
  63. table.insert(msg_queue, { id = id, channel = channel, msg = msg, retry = 0 })
  64. end
  65. sys.publish("NEW_MSG")
  66. log.debug("util_notify.add", "添加到消息队列, 当前队列长度:", #msg_queue, "消息内容:", msg:gsub("\r", "\\r"):gsub("\n", "\\n"))
  67. end
  68. --- 轮询消息队列, 发送成功则从队列中删除, 发送失败则等待下次
  69. local function poll()
  70. -- 打印网络状态
  71. if mobile.status() ~= 1 then
  72. log.warn("util_notify.poll", "mobile.status", mobile_status, util_mobile.status())
  73. end
  74. -- 消息队列非空
  75. if next(msg_queue) == nil then
  76. sys.waitUntil("NEW_MSG", 1000 * 10)
  77. return
  78. end
  79. local item = msg_queue[1]
  80. table.remove(msg_queue, 1)
  81. local msg = item.msg
  82. log.info("util_notify.poll", "轮询消息队列中", "总长度: " .. #msg_queue, "当前ID: " .. item.id, "当前重发次数: " .. item.retry, "连续失败次数: " .. error_count)
  83. -- 通知内容添加设备信息
  84. if config.NOTIFY_APPEND_MORE_INFO and not string.find(msg, "开机时长:") then
  85. msg = msg .. util_mobile.appendDeviceInfo()
  86. end
  87. -- 通知内容添加重发次数
  88. if error_count > 0 then
  89. msg = msg .. "\n重发次数: " .. error_count
  90. end
  91. -- 超过最大重发次数
  92. if item.retry > (config.NOTIFY_RETRY_MAX or 20) then
  93. log.warn("util_notify.poll", "超过最大重发次数, 放弃重发", item.msg)
  94. return
  95. end
  96. -- 开始发送
  97. local result = send(msg, item.channel)
  98. -- 发送成功
  99. if result then
  100. error_count = 0
  101. -- 检查 fskv 中如果存在则删除
  102. if fskv.get(item.id) then
  103. fskv.del(item.id)
  104. end
  105. return
  106. end
  107. -- 发送失败
  108. error_count = error_count + 1
  109. item.retry = item.retry + 1
  110. table.insert(msg_queue, item)
  111. log.info("util_notify.poll", "等待下次重发", "当前重发次数", item.retry, "连续失败次数", error_count)
  112. sys.waitUntil("IP_READY", 1000 * 5)
  113. -- 每连续失败 2 次, 开关飞行模式
  114. if error_count % 2 == 0 then
  115. -- 开关飞行模式
  116. log.warn("util_notify.poll", "连续失败次数过多, 开关飞行模式")
  117. mobile.flymode(0, true)
  118. mobile.flymode(0, false)
  119. sys.wait(1000)
  120. end
  121. -- 每条消息第 1 次重发失败后, 保存到 fskv, 断电开机可恢复重发
  122. if item.retry == 1 then
  123. if not (string.find(item.msg, "#SMS") or string.find(item.msg, "#CALL")) then
  124. return
  125. end
  126. log.info("util_notify.poll", "当前第 1 次重发失败, 保存到 fskv", item.id)
  127. if fskv.get(item.id) then
  128. log.info("util_notify.poll", "fskv 已存在, 跳过写入", item.id)
  129. return
  130. end
  131. local kv_set_result = fskv.set(item.id, item.msg)
  132. log.info("util_notify.poll", "fskv.set", kv_set_result, "used,total,count:", fskv.status())
  133. end
  134. end
  135. sys.taskInit(function()
  136. while true do
  137. poll()
  138. sys.wait(100)
  139. end
  140. end)
  141. sys.taskInit(function()
  142. sys.waitUntil("IP_READY")
  143. sys.wait(10000)
  144. local iter = fskv.iter()
  145. while iter do
  146. local k = fskv.next(iter)
  147. if not k then
  148. break
  149. end
  150. local v = fskv.get(k)
  151. if not (v and v ~= "" and string.find(k, "msg-")) then
  152. break
  153. end
  154. log.info("util_notify", "检查到 fskv 中有历史消息", k, v:gsub("\r", "\\r"):gsub("\n", "\\n"))
  155. util_notify.add(v, nil, k)
  156. end
  157. end)
  158. return util_notify