HomeServer/Server/AllServer/MultiServer/Subscription.lua
2024-11-20 15:41:37 +08:00

457 lines
13 KiB
Lua
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

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