457 lines
13 KiB
Lua
457 lines
13 KiB
Lua
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
|