message.go 16 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375
  1. package message
  2. import (
  3. "encoding/json"
  4. "encoding/xml"
  5. "errors"
  6. "io"
  7. "net/http"
  8. "sort"
  9. "strings"
  10. "github.com/silenceper/wechat/v2/miniprogram/context"
  11. "github.com/silenceper/wechat/v2/miniprogram/security"
  12. "github.com/silenceper/wechat/v2/util"
  13. )
  14. // ConfirmReceiveMethod 确认收货方式
  15. type ConfirmReceiveMethod int8
  16. const (
  17. // EventTypeTradeManageRemindAccessAPI 提醒接入发货信息管理服务API
  18. // 小程序完成账期授权时/小程序产生第一笔交易时/已产生交易但从未发货的小程序,每天一次
  19. EventTypeTradeManageRemindAccessAPI EventType = "trade_manage_remind_access_api"
  20. // EventTypeTradeManageRemindShipping 提醒需要上传发货信息
  21. // 曾经发过货的小程序,订单超过48小时未发货时
  22. EventTypeTradeManageRemindShipping EventType = "trade_manage_remind_shipping"
  23. // EventTypeTradeManageOrderSettlement 订单将要结算或已经结算
  24. // 订单完成发货时/订单结算时
  25. EventTypeTradeManageOrderSettlement EventType = "trade_manage_order_settlement"
  26. // EventTypeAddExpressPath 运单轨迹更新事件
  27. EventTypeAddExpressPath EventType = "add_express_path"
  28. // EventTypeSecvodUpload 短剧媒资上传完成事件
  29. EventTypeSecvodUpload EventType = "secvod_upload_event"
  30. // EventTypeSecvodAudit 短剧媒资审核状态事件
  31. EventTypeSecvodAudit EventType = "secvod_audit_event"
  32. // EventTypeWxaMediaCheck 媒体内容安全异步审查结果通知
  33. EventTypeWxaMediaCheck EventType = "wxa_media_check"
  34. // EventTypeXpayGoodsDeliverNotify 道具发货推送事件
  35. EventTypeXpayGoodsDeliverNotify EventType = "xpay_goods_deliver_notify"
  36. // EventTypeXpayCoinPayNotify 代币支付推送事件
  37. EventTypeXpayCoinPayNotify EventType = "xpay_coin_pay_notify"
  38. // ConfirmReceiveMethodAuto 自动确认收货
  39. ConfirmReceiveMethodAuto ConfirmReceiveMethod = 1
  40. // ConfirmReceiveMethodManual 手动确认收货
  41. ConfirmReceiveMethodManual ConfirmReceiveMethod = 2
  42. )
  43. // PushReceiver 接收消息推送
  44. // 暂仅支付Aes加密方式
  45. type PushReceiver struct {
  46. *context.Context
  47. }
  48. // NewPushReceiver 实例化
  49. func NewPushReceiver(ctx *context.Context) *PushReceiver {
  50. return &PushReceiver{
  51. Context: ctx,
  52. }
  53. }
  54. // GetMsg 获取接收到的消息(如果是加密的返回解密数据)
  55. func (receiver *PushReceiver) GetMsg(r *http.Request) (string, []byte, error) {
  56. // 判断请求格式
  57. var dataType string
  58. contentType := r.Header.Get("Content-Type")
  59. if strings.HasPrefix(contentType, "text/xml") {
  60. // xml格式
  61. dataType = DataTypeXML
  62. } else {
  63. // json格式
  64. dataType = DataTypeJSON
  65. }
  66. // 读取参数,验证签名
  67. signature := r.FormValue("signature")
  68. timestamp := r.FormValue("timestamp")
  69. nonce := r.FormValue("nonce")
  70. encryptType := r.FormValue("encrypt_type")
  71. // 验证签名
  72. tmpArr := []string{
  73. receiver.Token,
  74. timestamp,
  75. nonce,
  76. }
  77. sort.Strings(tmpArr)
  78. tmpSignature := util.Signature(tmpArr...)
  79. if tmpSignature != signature {
  80. return dataType, nil, errors.New("signature error")
  81. }
  82. if encryptType == "aes" {
  83. // 解密
  84. var reqData DataReceived
  85. if dataType == DataTypeXML {
  86. if err := xml.NewDecoder(r.Body).Decode(&reqData); err != nil {
  87. return dataType, nil, err
  88. }
  89. } else {
  90. if err := json.NewDecoder(r.Body).Decode(&reqData); err != nil {
  91. return dataType, nil, err
  92. }
  93. }
  94. _, rawMsgBytes, err := util.DecryptMsg(receiver.AppID, reqData.Encrypt, receiver.EncodingAESKey)
  95. return dataType, rawMsgBytes, err
  96. }
  97. // 不加密
  98. byteData, err := io.ReadAll(r.Body)
  99. return dataType, byteData, err
  100. }
  101. // GetMsgData 获取接收到的消息(解密数据)
  102. func (receiver *PushReceiver) GetMsgData(r *http.Request) (MsgType, EventType, PushData, error) {
  103. dataType, decryptMsg, err := receiver.GetMsg(r)
  104. if err != nil {
  105. return "", "", nil, err
  106. }
  107. var (
  108. msgType MsgType
  109. eventType EventType
  110. )
  111. if dataType == DataTypeXML {
  112. var commonToken CommonPushData
  113. if err := xml.Unmarshal(decryptMsg, &commonToken); err != nil {
  114. return "", "", nil, err
  115. }
  116. msgType, eventType = commonToken.MsgType, commonToken.Event
  117. } else {
  118. var commonToken CommonPushData
  119. if err := json.Unmarshal(decryptMsg, &commonToken); err != nil {
  120. return "", "", nil, err
  121. }
  122. msgType, eventType = commonToken.MsgType, commonToken.Event
  123. }
  124. if msgType == MsgTypeEvent {
  125. pushData, err := receiver.getEvent(dataType, eventType, decryptMsg)
  126. // 暂不支持其他事件类型
  127. return msgType, eventType, pushData, err
  128. }
  129. // 暂不支持其他消息类型
  130. return msgType, eventType, decryptMsg, nil
  131. }
  132. // getEvent 获取事件推送的数据
  133. func (receiver *PushReceiver) getEvent(dataType string, eventType EventType, decryptMsg []byte) (PushData, error) {
  134. switch eventType {
  135. case EventTypeTradeManageRemindAccessAPI:
  136. // 提醒接入发货信息管理服务API
  137. var pushData PushDataRemindAccessAPI
  138. err := receiver.unmarshal(dataType, decryptMsg, &pushData)
  139. return &pushData, err
  140. case EventTypeTradeManageRemindShipping:
  141. // 提醒需要上传发货信息
  142. var pushData PushDataRemindShipping
  143. err := receiver.unmarshal(dataType, decryptMsg, &pushData)
  144. return &pushData, err
  145. case EventTypeTradeManageOrderSettlement:
  146. // 订单将要结算或已经结算
  147. var pushData PushDataOrderSettlement
  148. err := receiver.unmarshal(dataType, decryptMsg, &pushData)
  149. return &pushData, err
  150. case EventTypeWxaMediaCheck:
  151. // 媒体内容安全异步审查结果通知
  152. var pushData MediaCheckAsyncData
  153. err := receiver.unmarshal(dataType, decryptMsg, &pushData)
  154. return &pushData, err
  155. case EventTypeAddExpressPath:
  156. // 运单轨迹更新
  157. var pushData PushDataAddExpressPath
  158. err := receiver.unmarshal(dataType, decryptMsg, &pushData)
  159. return &pushData, err
  160. case EventTypeSecvodUpload:
  161. // 短剧媒资上传完成
  162. var pushData PushDataSecVodUpload
  163. err := receiver.unmarshal(dataType, decryptMsg, &pushData)
  164. return &pushData, err
  165. case EventTypeSecvodAudit:
  166. // 短剧媒资审核状态
  167. var pushData PushDataSecVodAudit
  168. err := receiver.unmarshal(dataType, decryptMsg, &pushData)
  169. return &pushData, err
  170. case EventTypeXpayGoodsDeliverNotify:
  171. // 道具发货推送事件
  172. var pushData PushDataXpayGoodsDeliverNotify
  173. err := receiver.unmarshal(dataType, decryptMsg, &pushData)
  174. return &pushData, err
  175. case EventTypeXpayCoinPayNotify:
  176. // 代币支付推送事件
  177. var pushData PushDataXpayCoinPayNotify
  178. err := receiver.unmarshal(dataType, decryptMsg, &pushData)
  179. return &pushData, err
  180. }
  181. // 暂不支持其他事件类型,直接返回解密后的数据,由调用方处理
  182. return decryptMsg, nil
  183. }
  184. // unmarshal 解析推送的数据
  185. func (receiver *PushReceiver) unmarshal(dateType string, decryptMsg []byte, pushData interface{}) error {
  186. if dateType == DataTypeXML {
  187. return xml.Unmarshal(decryptMsg, pushData)
  188. }
  189. return json.Unmarshal(decryptMsg, pushData)
  190. }
  191. // DataReceived 接收到的数据
  192. type DataReceived struct {
  193. Encrypt string `json:"Encrypt" xml:"Encrypt"` // 加密的消息体
  194. }
  195. // PushData 推送的数据(已转对应的结构体)
  196. type PushData interface{}
  197. // CommonPushData 推送数据通用部分
  198. type CommonPushData struct {
  199. XMLName xml.Name `json:"-" xml:"xml"`
  200. MsgType MsgType `json:"MsgType" xml:"MsgType"` // 消息类型,为固定值 "event"
  201. Event EventType `json:"Event" xml:"Event"` // 事件类型
  202. ToUserName string `json:"ToUserName" xml:"ToUserName"` // 小程序的原始 ID
  203. FromUserName string `json:"FromUserName" xml:"FromUserName"` // 发送方账号(一个 OpenID,此时发送方是系统账号)
  204. CreateTime int64 `json:"CreateTime" xml:"CreateTime"` // 消息创建时间 (整型),时间戳
  205. }
  206. // MediaCheckAsyncData 媒体内容安全异步审查结果通知
  207. type MediaCheckAsyncData struct {
  208. CommonPushData
  209. Appid string `json:"appid" xml:"appid"`
  210. TraceID string `json:"trace_id" xml:"trace_id"`
  211. Version int `json:"version" xml:"version"`
  212. Detail []*MediaCheckDetail `json:"detail" xml:"detail"`
  213. Errcode int `json:"errcode" xml:"errcode"`
  214. Errmsg string `json:"errmsg" xml:"errmsg"`
  215. Result MediaCheckAsyncResult `json:"result" xml:"result"`
  216. }
  217. // MediaCheckDetail 检测结果详情
  218. type MediaCheckDetail struct {
  219. Strategy string `json:"strategy" xml:"strategy"`
  220. Errcode int `json:"errcode" xml:"errcode"`
  221. Suggest security.CheckSuggest `json:"suggest" xml:"suggest"`
  222. Label int `json:"label" xml:"label"`
  223. Prob int `json:"prob" xml:"prob"`
  224. }
  225. // MediaCheckAsyncResult 检测结果
  226. type MediaCheckAsyncResult struct {
  227. Suggest security.CheckSuggest `json:"suggest" xml:"suggest"`
  228. Label security.CheckLabel `json:"label" xml:"label"`
  229. }
  230. // PushDataOrderSettlement 订单将要结算或已经结算通知
  231. type PushDataOrderSettlement struct {
  232. CommonPushData
  233. TransactionID string `json:"transaction_id" xml:"transaction_id"` // 支付订单号
  234. MerchantID string `json:"merchant_id" xml:"merchant_id"` // 商户号
  235. SubMerchantID string `json:"sub_merchant_id" xml:"sub_merchant_id"` // 子商户号
  236. MerchantTradeNo string `json:"merchant_trade_no" xml:"merchant_trade_no"` // 商户订单号
  237. PayTime int64 `json:"pay_time" xml:"pay_time"` // 支付成功时间,秒级时间戳
  238. ShippedTime int64 `json:"shipped_time" xml:"shipped_time"` // 发货时间,秒级时间戳
  239. EstimatedSettlementTime int64 `json:"estimated_settlement_time" xml:"estimated_settlement_time"` // 预计结算时间,秒级时间戳。发货时推送才有该字段
  240. ConfirmReceiveMethod ConfirmReceiveMethod `json:"confirm_receive_method" xml:"confirm_receive_method"` // 确认收货方式:1. 自动确认收货;2. 手动确认收货。结算时推送才有该字段
  241. ConfirmReceiveTime int64 `json:"confirm_receive_time" xml:"confirm_receive_time"` // 确认收货时间,秒级时间戳。结算时推送才有该字段
  242. SettlementTime int64 `json:"settlement_time" xml:"settlement_time"` // 订单结算时间,秒级时间戳。结算时推送才有该字段
  243. }
  244. // PushDataRemindShipping 提醒需要上传发货信息
  245. type PushDataRemindShipping struct {
  246. CommonPushData
  247. TransactionID string `json:"transaction_id" xml:"transaction_id"` // 微信支付订单号
  248. MerchantID string `json:"merchant_id" xml:"merchant_id"` // 商户号
  249. SubMerchantID string `json:"sub_merchant_id" xml:"sub_merchant_id"` // 子商户号
  250. MerchantTradeNo string `json:"merchant_trade_no" xml:"merchant_trade_no"` // 商户订单号
  251. PayTime int64 `json:"pay_time" xml:"pay_time"` // 支付成功时间,秒级时间戳
  252. Msg string `json:"msg" xml:"msg"` // 消息文本内容
  253. }
  254. // PushDataRemindAccessAPI 提醒接入发货信息管理服务API信息
  255. type PushDataRemindAccessAPI struct {
  256. CommonPushData
  257. Msg string `json:"msg" xml:"msg"` // 消息文本内容
  258. }
  259. // PushDataAddExpressPath 运单轨迹更新信息
  260. type PushDataAddExpressPath struct {
  261. CommonPushData
  262. DeliveryID string `json:"DeliveryID" xml:"DeliveryID"` // 快递公司ID
  263. WayBillID string `json:"WaybillId" xml:"WaybillId"` // 运单ID
  264. OrderID string `json:"OrderId" xml:"OrderId"` // 订单ID
  265. Version int `json:"Version" xml:"Version"` // 轨迹版本号(整型)
  266. Count int `json:"Count" xml:"Count"` // 轨迹节点数(整型)
  267. Actions []*PushDataAddExpressPathAction `json:"Actions" xml:"Actions"` // 轨迹节点列表
  268. }
  269. // PushDataAddExpressPathAction 轨迹节点
  270. type PushDataAddExpressPathAction struct {
  271. ActionTime int64 `json:"ActionTime" xml:"ActionTime"` // 轨迹节点 Unix 时间戳
  272. ActionType int `json:"ActionType" xml:"ActionType"` // 轨迹节点类型
  273. ActionMsg string `json:"ActionMsg" xml:"ActionMsg"` // 轨迹节点详情
  274. }
  275. // PushDataSecVodUpload 短剧媒资上传完成
  276. type PushDataSecVodUpload struct {
  277. CommonPushData
  278. UploadEvent SecVodUploadEvent `json:"upload_event" xml:"upload_event"` // 上传完成事件
  279. }
  280. // SecVodUploadEvent 短剧媒资上传完成事件
  281. type SecVodUploadEvent struct {
  282. MediaID string `json:"media_id" xml:"media_id"` // 媒资id
  283. SourceContext string `json:"source_context" xml:"source_context"` // 透传上传接口中开发者设置的值。
  284. Errcode int `json:"errcode" xml:"errcode"` // 错误码,上传失败时该值非
  285. Errmsg string `json:"errmsg" xml:"errmsg"` // 错误提示
  286. }
  287. // PushDataSecVodAudit 短剧媒资审核状态
  288. type PushDataSecVodAudit struct {
  289. CommonPushData
  290. AuditEvent SecVodAuditEvent `json:"audit_event" xml:"audit_event"` // 审核状态事件
  291. }
  292. // SecVodAuditEvent 短剧媒资审核状态事件
  293. type SecVodAuditEvent struct {
  294. DramaID string `json:"drama_id" xml:"drama_id"` // 剧目id
  295. SourceContext string `json:"source_context" xml:"source_context"` // 透传上传接口中开发者设置的值
  296. AuditDetail DramaAuditDetail `json:"audit_detail" xml:"audit_detail"` // 剧目审核结果,单独每一集的审核结果可以根据drama_id查询剧集详情得到
  297. }
  298. // DramaAuditDetail 剧目审核结果
  299. type DramaAuditDetail struct {
  300. Status int `json:"status" xml:"status"` // 审核状态,0为无效值;1为审核中;2为最终失败;3为审核通过;4为驳回重填
  301. CreateTime int64 `json:"create_time" xml:"create_time"` // 提审时间戳
  302. AuditTime int64 `json:"audit_time" xml:"audit_time"` // 审核时间戳
  303. }
  304. // PushDataXpayGoodsDeliverNotify 道具发货推送
  305. type PushDataXpayGoodsDeliverNotify struct {
  306. CommonPushData
  307. OpenID string `json:"OpenId" xml:"OpenId"` // 用户openid
  308. OutTradeNo string `json:"OutTradeNo" xml:"OutTradeNo"` // 业务订单号
  309. Env int `json:"Env" xml:"Env"` //,环境配置 0:现网环境(也叫正式环境)1:沙箱环境
  310. WeChatPayInfo WeChatPayInfo `json:"WeChatPayInfo" xml:"WeChatPayInfo"` // 微信支付信息 非微信支付渠道可能没有
  311. GoodsInfo GoodsInfo `json:"GoodsInfo" xml:"GoodsInfo"` // 道具参数信息
  312. }
  313. // WeChatPayInfo 微信支付信息
  314. type WeChatPayInfo struct {
  315. MchOrderNo string `json:"MchOrderNo" xml:"MchOrderNo"` // 微信支付商户单号
  316. TransactionID string `json:"TransactionId" xml:"TransactionId"` // 交易单号(微信支付订单号)
  317. PaidTime int64 `json:"PaidTime" xml:"PaidTime"` // 用户支付时间,Linux秒级时间戳
  318. }
  319. // GoodsInfo 道具参数信息
  320. type GoodsInfo struct {
  321. ProductID string `json:"ProductId" xml:"ProductId"` // 道具ID
  322. Quantity int `json:"Quantity" xml:"Quantity"` // 数量
  323. OrigPrice int64 `json:"OrigPrice" xml:"OrigPrice"` // 物品原始价格 (单位:分)
  324. ActualPrice int64 `json:"ActualPrice" xml:"ActualPrice"` // 物品实际支付价格(单位:分)
  325. Attach string `json:"Attach" xml:"Attach"` // 透传信息
  326. }
  327. // PushDataXpayCoinPayNotify 代币支付推送
  328. type PushDataXpayCoinPayNotify struct {
  329. CommonPushData
  330. OpenID string `json:"OpenId" xml:"OpenId"` // 用户openid
  331. OutTradeNo string `json:"OutTradeNo" xml:"OutTradeNo"` // 业务订单号
  332. Env int `json:"Env" xml:"Env"` //,环境配置 0:现网环境(也叫正式环境)1:沙箱环境
  333. WeChatPayInfo WeChatPayInfo `json:"WeChatPayInfo" xml:"WeChatPayInfo"` // 微信支付信息 非微信支付渠道可能没有
  334. CoinInfo CoinInfo `json:"CoinInfo" xml:"CoinInfo"` // 代币参数信息
  335. }
  336. // CoinInfo 代币参数信息
  337. type CoinInfo struct {
  338. Quantity int `json:"Quantity" xml:"Quantity"` // 数量
  339. OrigPrice int64 `json:"OrigPrice" xml:"OrigPrice"` // 物品原始价格 (单位:分)
  340. ActualPrice int64 `json:"ActualPrice" xml:"ActualPrice"` // 物品实际支付价格(单位:分)
  341. Attach string `json:"Attach" xml:"Attach"` // 透传信息
  342. }