HomeServer/Server/AllServer/MultiServer/Subscription.lua

457 lines
13 KiB
Lua
Raw Permalink Normal View History

2024-11-20 15:41:09 +08:00
local skynet = require "skynet"
local oo = require "Class"
local gameCmd = require "GameCmd"
local json =require "json"
local log = require "Log"
local sqlUrl = require "SqlUrl"
local errorInfo = require "ErrorInfo"
local dataType = require "DataType"
local serverId = tonumber(skynet.getenv "serverId")
local redisKeyUrl = require "RedisKeyUrl"
local httpc = require "http.httpc"
local Subscription = oo.class()
local protocol ="https"
--域名
local domain = "api.weixin.qq.com"
--推送地址 暂时写在这里
local pushUrl = "/cgi-bin/message/subscribe/send?access_token=%s"
--获取token地址
--local getTokenUrl = "/cgi-bin/token?grant_type=client_credential&appid=wxa2951c2cf9636811&secret=bada9eefee3db35b9c9fa21ed40787d8"
local getTokenStableUrl="/cgi-bin/stable_token"--稳定模式
local tokenStablePostData={
grant_type="client_credential",--固定值
appid="wxa2951c2cf9636811",--appid
secret="bada9eefee3db35b9c9fa21ed40787d8"--appsecret
}
--方便管理订阅一个管理列表
local subscriptionMap={}
-- 版本更新提醒
local data1={
character_string1={
value="1.0.0"--版本号
},
thing2={
value="版本描述"
},
date3={
value="2024/01/01"--完成时间
},
time4={
value="10:00:00"--更新时间
},
}
subscriptionMap[8]=data1
-- 邮箱金币
local data2={
date2={
value = os.date("%H:%M",os.time())
},
thing1={
value="待领取"
},
}
subscriptionMap[1]=data2
-- 种花成熟提醒
local data3={
phrase1={
value="任务名称"
},
date2={
value="完成日期"
},
time3={
value="完成时间"
},
thing4={
value="温馨提醒"
},
}
subscriptionMap[2]=data3
-- 食堂进货提醒
local data4={
phrase1={
value="任务名称"
},
date2={
value="完成日期"
},
}
subscriptionMap[3]=data4
-- 萌宠乐园出游提醒
local data5={
phrase1={
value="任务名称"
},
time3={
value="完成时间"
},
thing4={
value="温馨提醒"
},
}
subscriptionMap[4]=data5
-- 渔店钓鱼提醒
local data6={
phrase1={
value="任务名称"
},
date2={
value="完成日期"
},
time3={
value="完成时间"
},
thing4={
value="温馨提醒"
},
}
subscriptionMap[5]=data6
-- 恋家置业收租提醒
local data7={
phrase1={
value="任务名称"
},
time3={
value="完成时间"
},
thing4={
value="温馨提醒"
},
}
subscriptionMap[6]=data7
-- 造型材料提醒
local data8={
phrase1={
value="任务名称"
},
date2={
value="完成日期"
},
thing11={
value="未领取"
},
}
subscriptionMap[7]=data8
--初始化
function Subscription:Init()
end
--每5秒调一次(测试阶段)
function Subscription:On5SecTimer()
-- log.debug("微信订阅 每5秒调一次")
-- --目前只有微信订阅消息
-- self:GetSubscription(1)
end
--获取订阅信息
function Subscription:GetSubscription(subscribeType)
--获取已经订阅的玩家key
local keys= skynet.server.redis:smembers(redisKeyUrl.ThirdSubscribeSetKeys)
if keys == nil or #keys == 0 then
log.debug("GetSubscription keys is nil or #keys == 0")
return
end
--订阅类型配置
local cfgSubscriptions = skynet.server.gameConfig:GetAllCfg("Subscription")
if not cfgSubscriptions then
log.debug("cfgSubscriptions is nil")
return
end
--循环数据
for _, setKey in ipairs(keys) do
local key=string.format(redisKeyUrl.ThirdSubscribe, setKey)
--获取订阅信息
local subscribeInfoListStr = skynet.server.redis:hget(key,tostring(subscribeType))
--不存在数据跳出当前循环
if subscribeInfoListStr == nil or subscribeInfoListStr == "" then
goto coroutine1
end
--反序列化成对象
local subscribeInfoList = json:decode(subscribeInfoListStr)
--判断反序列化是否成功
if subscribeInfoList == nil or next(subscribeInfoList) == nil then
log.debug(string.format("消息发布订阅反序列化失败key:%s,subscribeInfoListStr:%s",key,subscribeInfoListStr))
goto coroutine1
end
--倒序遍历删除不影响table后续索引
for i = #subscribeInfoList, 1, -1 do
local subscribeInfo = subscribeInfoList[i]
--不存在存在数据
if subscribeInfo == nil or next(subscribeInfo) == nil then
goto coroutine
end
--判断是否过期
if subscribeInfo.expireTime < skynet.GetTime() and subscribeInfo.expireTime ~= 0 then
--删除订阅信息
table.remove(subscribeInfoList,i)
goto coroutine
end
--是否需要推送
if subscribeInfo.triggerTimestamp > skynet.GetTime()
or subscribeInfo.triggerTimestamp == 0 --当前在线,没有推送时间
or subscribeInfo.subscribeStatus == 2 --已推送
or subscribeInfo.subscribeStatus == 3 then
goto coroutine
end
local cfgSubscription={}
--根据配置获取提醒标题
for _, value in pairs(cfgSubscriptions) do
if value.id == subscribeInfo.subscribeId then
cfgSubscription=value
end
end
--推送消息到微信
local ret = Subscription:pushMessage(subscribeType,cfgSubscription,subscribeInfo)
if ret and cfgSubscription.subscribeType == 1
and skynet.GetTime() > subscribeInfo.expireTime then--触发订阅,并且未过期 才重置
--更新状态为已推送
subscribeInfo.subscribeStatus = 2
else--手动订阅则删除
table.remove(subscribeInfoList,i)
end
-- 跳出当前循环
::coroutine::
end
if next(subscribeInfoList) ~= nil then
--更新订阅信息
skynet.server.redis:hset(key,tostring(subscribeType),json:encode(subscribeInfoList))
else
--删除
skynet.server.redis:hdel(key,tostring(subscribeType))
--删除索引
skynet.server.redis:srem(redisKeyUrl.ThirdSubscribeSetKeys,setKey)
end
-- 跳出当前循环
::coroutine1::
end
end
--每5分钟调一次
function Subscription:On5MinTimer()
log.debug("微信订阅 五分钟检查一次")
self:GetSubscription(1)
end
--推送消息
function Subscription:pushMessage(subscribeType,cfgSubscription,subscribeInfo)
--失败次数
local failCount=0
--处理微信订阅消息(目前只有微信)
if subscribeType ==1 then
--订阅内容
local postData={
touser = subscribeInfo.uniqueId,
template_id = "",
miniprogram_state = "developer",
lang = "zh_CN",
data={}
}
local template_id=""
local data={}
--获取token地址
local tokenInfo = self:GetWxToken(false)
if tokenInfo == "" then
log.debug("获取token失败")
return false
end
--模版id
postData.template_id=cfgSubscription.subscribeModelId
--设置订阅内容
if subscriptionMap[cfgSubscription.id] then
postData.data=subscriptionMap[cfgSubscription.id]
--版本更新
if postData.data.character_string1 then
--修改推送数值值
postData.data.character_string1.value="1.0.0" --版本号
end
--邮件时间
if cfgSubscription.id == 1 then
postData.data.date2.value= os.date("%H:%M",skynet.GetTime())
postData.data.thing1.value= cfgSubscription.subscribeDesc
end
--基本通用模板
if postData.data.phrase1 then
postData.data.phrase1.value= cfgSubscription.subscribeTitle
end
if postData.data.thing4 then
postData.data.thing4.value= cfgSubscription.subscribeDesc
end
if postData.data.date2 then
postData.data.date2.value= os.date("%m月%d日",subscribeInfo.triggerTimestamp)
end
if postData.data.time3 then
postData.data.time3.value= os.date("%H:%M:%S",subscribeInfo.triggerTimestamp)
end
else--模版id不存在
log.debug(string.format("消息订阅 消息id不存在subscribeId:%s",cfgSubscription.id))
return false
end
-- --版本更新提醒
-- if cfgSubscription.id==8 then
-- postData.data=data1
-- --修改推送数值值
-- postData.data.character_string1.value="1.0.0" --版本号
-- --邮箱金币
-- elseif cfgSubscription.id==1 then
-- postData.data=data2
-- postData.data.date2.value= os.date("%H:%M",skynet.GetTime())
-- postData.data.thing1.value= cfgSubscription.subscribeDesc
-- -- "种花成熟提醒
-- -- 渔店钓鱼提醒
-- -- 食堂进货提醒
-- -- 萌宠乐园出游提醒
-- -- 恋家置业收租提醒
-- -- 食堂收菜提醒
-- -- 造型材料提醒"
-- elseif cfgSubscription.id>=2 and cfgSubscription.id<=7 then
-- postData.data=data3
-- postData.data.phrase1.value= cfgSubscription.subscribeTitle
-- postData.data.thing4.value= cfgSubscription.subscribeDesc
-- postData.data.date2.value= os.date("%m月%d日",subscribeInfo.triggerTimestamp)
-- postData.data.time3.value= os.date("%H:%M:%S",subscribeInfo.triggerTimestamp)
-- else--模版id不存在
-- log.debug(string.format("消息订阅 消息id不存在subscribeId:%s",cfgSubscription.id))
-- return false
-- end
::top::
local url =string.format(pushUrl,tokenInfo)
--推送
local status,body = skynet.server.httpClient:PostJson(domain,url,json:encode(postData),protocol)
if type(status)=="table" then
return false
end
if status ~= 200 then
log.warning(string.format("微信订阅推送 返回状态 ~= 200 url:%s,status:%d,body:%s",url,status,body))
return false
end
--反序列化结果
local bodyObj = json:decode(body)
local errcode = tonumber(bodyObj.errcode)
--推送失败,就意味着后面都会失败,没必要再次推送
if errcode ~= 0 then
if (errcode == 40001 or errcode == 42001)and failCount < 5 then --token过期,重试5次
log.debug("重新获取token:",errcode,failCount)
--获取token地址
tokenInfo = self:GetWxToken(true)
if tokenInfo == "" then
log.debug("获取token失败")
return false
end
failCount=failCount+1
goto top
end
return true
end
return true
end
end
--微信token信息
local token=""
local expires_in=0
--推送消息到微信等
function Subscription:GetWxToken(isForce)
--判断token是否过期,未过期直接返回之前的token
if expires_in > 0 and expires_in > skynet.GetTime() and token ~= "" and not isForce then
return token
end
--获取token-stable模式
local status,body =skynet.server.httpClient:PostJson(domain,getTokenStableUrl,json:encode(tokenStablePostData),protocol) -- skynet.server.httpClient:Get(domain,getTokenUrl,protocol)
if status ~= 200 then
log.warning(string.format("微信订阅推送 获取token失败,domain:%s,url:%s,status:%d,body:%s",domain,getTokenStableUrl,status,body))
return 0
end
--反序列号结果
local bodyObj = json:decode(body)
--反序列化失败
if bodyObj == nil or next(bodyObj) == nil then
log.warning(string.format("微信订阅推送 bodyObj反序列化失败,domain:%s,url:%s,status:%d,body:%s",domain,getTokenStableUrl,status,body))
return 0
end
token = bodyObj.access_token
expires_in =skynet.GetTime() + tonumber(bodyObj.expires_in)
if token == nil or expires_in == nil then
log.warning(string.format("微信订阅推送 token反序列化失败,domain:%s,url:%s,status:%d,body:%s",domain,getTokenStableUrl,status,body))
return 0
end
return token
end
skynet.server.subscription = Subscription
return Subscription