| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315 |
- --邮件管理
- local LuaMongo = _G.lua_mongo
- local Log = require("common.Log")
- local DB = require("common.DB")
- local Util = require("common.Util")
- local Msg = require("core.Msg")
- local ObjHuman = require("core.ObjHuman")
- local RoleSystemLogic = require("roleSystem.RoleSystemLogic")
- local RoleSystemDefine = require("roleSystem.RoleSystemDefine")
- local RoleDBLogic = require("role.RoleDBLogic")
- local MailExcel = require("excel.mail")
- local CommonDB = require("common.CommonDB")
- SYSTEM = 1 -- 系统邮件
- GONGGAO = 2 -- 公告
- MAIL_MAX_CNT = 100 -- 邮件最大值
- local FIELD_ID = {_id = nil}
- local FIELD_RECEIVER = {uuid = nil,type = nil}
- --后面如果fbAccount有值应该把区服id一起
- function add(type,receiverUuid,title,content,items,senderName,sender,time,fbTime,fbContent,fbAccount,expireTime)
- if _G.is_middle == true or type == GONGGAO then
- return
- end
-
- local mail = {}
- mail.type = type
- mail.receiverUuid = receiverUuid
- mail.title = title
- mail.content = content
- mail.read = nil
- mail.senderName = title
- mail.head = 0
- mail.fbTime = fbTime
- mail.fbContent = fbContent
-
- --后面用到
- local fields = {head = 1,lv = 1}
- if fbAccount ~= nil then
- local db = RoleDBLogic.getDbByAccount(fbAccount,fields)
- mail.fbHead = db.head
- mail.fbLv = db.lv
- end
-
- if sender and sender.db and sender.db.identity then
- mail.identity = sender.db.identity
- end
- if sender and sender.db and sender.db.head then
- mail.head = sender.db.head
- end
- if time == nil then
- mail.time = os.time()
- else
- mail.time = time
- end
-
- if expireTime then
- mail.expireTime = expireTime
- end
-
- if items then
- mail.items = {}
- for _,item in ipairs(items) do
- mail.items[#mail.items + 1] = {item[1],item[2]}
- end
- end
- if items == nil then
- mail.get = 1
- mail.flag = nil
- else
- mail.get = nil
- mail.flag = 1
- end
- LuaMongo.insert(DB.db_mail, mail)
- -- 检测红点会调用getMails(), 短时间插入多封邮件加上玩家邮件数量过多,会发生段错误
- -- RoleSystemLogic.onDotByUuid(receiverUuid, RoleSystemDefine.ROLE_SYS_ID_204)
- return mail
- end
- -- condition = {startLv = 1, endLv = 100, lastLoginTime = xxx}
- local MailLvQuery = {lv = {["$gte"] = 0, ["$lte"] = 0}}
- local MailLvField = {lastLoginTime = 1, lastLogoutTime = 1}
- function sendMailByCondition(condition, title, content, gridList,fbTime,fbContent,fbAccount,expireTime)
- local startLv = condition.startLv and tonumber(condition.startLv)
- local endLv = condition.endLv and tonumber(condition.endLv)
- local lastLoginTime = condition.lastLoginTime and tonumber(condition.lastLoginTime) or 0
- if startLv == nil or endLv == nil or lastLoginTime == nil then
- return
- end
-
- local successCount = 0
- local failCount = 0
- --Log.write(Log.LOGID_ERR_PCALL, "mail sendMailByCondition" , "")
- -- 在线的只要等级符合直接发
- for uuid, oHuman in pairs(ObjHuman.onlineUuid) do
- if oHuman.db.lv >= startLv and
- oHuman.db.lv <= endLv then
- p_ret, err = pcall(add, SYSTEM, oHuman.db._id, title, content, gridList, condition.senderName, nil, nil,fbTime,fbContent,fbAccount,expireTime)
- if p_ret then
- successCount = successCount + 1
- --Log.write(Log.LOGID_ERR_PCALL, "mail rolename=" .. oHuman.db.name, err)
- else
- failCount = failCount + 1
- --Log.write(Log.LOGID_ERR_PCALL, "mail rolename=" .. oHuman.db.name, err)
- end
- end
- end
- -- 不在线的,还需要验证x天内登录
- MailLvQuery.lv["$gte"] = startLv
- MailLvQuery.lv["$lte"] = endLv
- LuaMongo.find(DB.db_char, MailLvQuery, MailLvField)
- while true do
- local data = {}
- if not LuaMongo.next(data) then
- break
- end
- if not ObjHuman.onlineUuid[data._id] and
- (lastLoginTime == 0 or
- (data.lastLoginTime and data.lastLoginTime >= lastLoginTime) or
- (data.lastLogoutTime and data.lastLogoutTime >= lastLoginTime)
- ) then
- p_ret, err = pcall(add, SYSTEM, data._id, title, content, gridList, condition.senderName, nil, nil,fbTime,fbContent,fbAccount)
- if p_ret then
- successCount = successCount + 1
- else
- failCount = failCount + 1
- Log.write(Log.LOGID_ERR_PCALL, "mail role uuid=" .. data._id, err)
- end
- end
- end
- return successCount, failCount
- end
- function del(mailUuid)
- FIELD_ID._id = mailUuid
- LuaMongo.remove(DB.db_mail, FIELD_ID)
- end
- function getMail(mailUuid)
- FIELD_ID._id = mailUuid
- LuaMongo.find(DB.db_mail,FIELD_ID)
- local mail = {}
- if not LuaMongo.next(mail) then
- return nil
- end
- return mail
- end
- local function cmpMail(a, b)
- return a.time > b.time
- end
- local mails = {}
- -- function getMails(receiverUuid,mailType)
- -- for key in ipairs(mails) do
- -- mails[key] = nil
- -- end
- -- FIELD_RECEIVER.receiverUuid = receiverUuid
- -- FIELD_RECEIVER.type = mailType
- -- LuaMongo.find(DB.db_mail,{["$query"]=FIELD_RECEIVER})
-
- -- local lastTime = os.time() - 7 * 86400
- -- local mailCnt = 0
- -- while true do
- -- local mail = {}
- -- -- if not LuaMongo.next(mail) then
- -- -- break
- -- -- end
- -- local res, err = pcall(function ()
- -- return LuaMongo.next(mail)
- -- end)
- -- if not res then
- -- Log.write(Log.LOGID_DEBUG, "MailManager.getMails err = ".. err)
- -- break
- -- end
- -- if not err then
- -- break
- -- end
- -- if mail.expireTime then -- 有指定过期时间
- -- if mail.time > os.time() - mail.expireTime then
- -- mailCnt = mailCnt + 1
- -- mails[mailCnt] = mail
- -- end
- -- elseif mail.time > lastTime then -- 没有就用默认过期时间
- -- mailCnt = mailCnt + 1
- -- mails[mailCnt] = mail
- -- end
- -- end
-
- -- if mailCnt > MAIL_MAX_CNT then
- -- table.sort(mails, cmpMail)
- -- for i = MAIL_MAX_CNT + 1, mailCnt do
- -- mails[i] = nil
- -- end
- -- end
- -- return mails
- -- end
- -- 替换原有的 getMails 函数
- function getMails(receiverUuid, mailType)
- -- 1. 清空缓存表
- for i = 1, #mails do mails[i] = nil end
- local now = os.time()
- local mailCnt = 0
- local tempMails = {}
- local SCAN_LIMIT = 2000 -- 单次分段查询安全上限
- local foundEnough = false
- -- 2.将时间划分为多个小窗口,避免单次 find 触发底层 OOM
- -- 窗口设计:最近7天 -> 7~14天 -> 14~30天 -> 30~60天
- local timeWindows = {
- {now - 7*86400, now},
- {now - 14*86400, now - 7*86400},
- {now - 30*86400, now - 14*86400},
- {now - 60*86400, now - 30*86400}
- }
- -- 60天 -> 开服
- local serverOpenTime = CommonDB.getServerOpenTime()
- timeWindows[#timeWindows+1] = { serverOpenTime, now - 60*86400 }
- for _, window in ipairs(timeWindows) do
- if foundEnough then break end
- -- 使用最简平铺查询,彻底避开 C 扩展解析缺陷
- local query = {
- receiverUuid = receiverUuid,
- type = mailType,
- time = { ["$gte"] = window[1], ["$lte"] = window[2] }
- }
- LuaMongo.find(DB.db_mail, query)
- local mail = {}
- local scanCnt = 0
- while true do
- local has_next = LuaMongo.next(mail)
- if not has_next then break end
-
- scanCnt = scanCnt + 1
- if scanCnt > SCAN_LIMIT then
- Log.write(Log.LOGID_DEBUG, string.format("Mail segment limit hit! uuid=%s window=%d~%d",
- receiverUuid, window[1], window[2]))
- break
- end
- -- 浅拷贝隔离 C 驱动内部 Buffer
- local m = {}
- for k, v in pairs(mail) do m[k] = v end
- tempMails[#tempMails + 1] = m
- -- 清空复用表
- for k in pairs(mail) do mail[k] = nil end
- end
- -- 如果已收集足够多数据(留足过滤冗余),提前终止后续窗口查询
- if #tempMails >= 500 then
- foundEnough = true
- break
- end
- end
- -- 3.按时间倒序排序,确保后续取到的是“最新”的
- table.sort(tempMails, cmpMail)
- -- 4. 过滤过期邮件,精准截取最新 100 条
- for _, m in ipairs(tempMails) do
- if type(m.time) ~= "number" then m.time = 0 end
- local isExpired = false
- local expireTime = m.expireTime
- if expireTime and type(expireTime) == "number" then
- if m.time <= now - expireTime then isExpired = true end
- elseif m.time <= now - 7 * 86400 then
- isExpired = true
- end
- if not isExpired then
- mailCnt = mailCnt + 1
- mails[mailCnt] = m
- if mailCnt >= MAIL_MAX_CNT then break end -- 达到 100 条立即退出
- end
- end
- return mails
- end
- function saveMail(mail)
- FIELD_ID._id = mail._id
- LuaMongo.update(DB.db_mail, FIELD_ID, mail)
- end
- function delAll(uuid,mailType)
- local QueryMailByUuid = {get = {["$exists"] = 0}, read = {["$exists"] = 1}}
- QueryMailByUuid.receiverUuid = uuid
- QueryMailByUuid.type = mailType
- QueryMailByUuid.get["$exists"] = 1
- LuaMongo.remove(DB.db_mail, QueryMailByUuid)
- end
|