1
0
mirror of https://github.com/silenceper/wechat.git synced 2026-02-04 12:52:27 +08:00

Feature: improve code message subscribe (#739)

* fix

* feat(miniapp): 小程序订阅消息 (#429)

1. 用户订阅消息服务端回调处理
2. 用户订阅消息订阅通知事件推送

Co-authored-by: houseme <qzg40737@163.com>

* feat: improve subscribe msg

* feat: add v1.21 and feature branch

* feat: improve code for subscribe

* test

* test

* fix

* fix

* improve comment

* improve code for message

* improve code for unmarshal message

* improve code for message

---------

Co-authored-by: Ralph Maas <stuchilde@outlook.com>
This commit is contained in:
houseme
2023-11-02 09:39:10 +08:00
committed by GitHub
parent d4fd145bb5
commit 56a3734546
8 changed files with 292 additions and 73 deletions

View File

@@ -2,15 +2,15 @@ name: Go
on: on:
push: push:
branches: [ master,release-*,v2 ] branches: [ master,release-*,v2,feature/** ]
pull_request: pull_request:
branches: [ master,release-*,v2 ] branches: [ master,release-*,v2,feature/** ]
jobs: jobs:
golangci: golangci:
strategy: strategy:
matrix: matrix:
go-version: [ '1.16','1.17','1.18','1.19','1.20' ] go-version: [ '1.16','1.17','1.18','1.19','1.20','1.21' ]
name: golangci-lint name: golangci-lint
runs-on: ubuntu-latest runs-on: ubuntu-latest
steps: steps:
@@ -42,7 +42,7 @@ jobs:
# strategy set # strategy set
strategy: strategy:
matrix: matrix:
go: [ '1.16','1.17','1.18','1.19','1.20' ] go: [ '1.16','1.17','1.18','1.19','1.20','1.21' ]
steps: steps:
- uses: actions/checkout@v3 - uses: actions/checkout@v3

View File

@@ -9,6 +9,8 @@ import (
"sort" "sort"
"strings" "strings"
"github.com/tidwall/gjson"
"github.com/silenceper/wechat/v2/miniprogram/context" "github.com/silenceper/wechat/v2/miniprogram/context"
"github.com/silenceper/wechat/v2/miniprogram/security" "github.com/silenceper/wechat/v2/miniprogram/security"
"github.com/silenceper/wechat/v2/util" "github.com/silenceper/wechat/v2/util"
@@ -39,12 +41,25 @@ const (
EventTypeXpayGoodsDeliverNotify EventType = "xpay_goods_deliver_notify" EventTypeXpayGoodsDeliverNotify EventType = "xpay_goods_deliver_notify"
// EventTypeXpayCoinPayNotify 代币支付推送事件 // EventTypeXpayCoinPayNotify 代币支付推送事件
EventTypeXpayCoinPayNotify EventType = "xpay_coin_pay_notify" EventTypeXpayCoinPayNotify EventType = "xpay_coin_pay_notify"
// EventSubscribePopup 用户操作订阅通知弹窗事件推送,用户在图文等场景内订阅通知的操作
EventSubscribePopup EventType = "subscribe_msg_popup_event"
// EventSubscribeMsgChange 用户管理订阅通知,用户在服务通知管理页面做通知管理时的操作
EventSubscribeMsgChange EventType = "subscribe_msg_change_event"
// EventSubscribeMsgSent 发送订阅通知,调用 bizsend 接口发送通知
EventSubscribeMsgSent EventType = "subscribe_msg_sent_event"
// ConfirmReceiveMethodAuto 自动确认收货 // ConfirmReceiveMethodAuto 自动确认收货
ConfirmReceiveMethodAuto ConfirmReceiveMethod = 1 ConfirmReceiveMethodAuto ConfirmReceiveMethod = 1
// ConfirmReceiveMethodManual 手动确认收货 // ConfirmReceiveMethodManual 手动确认收货
ConfirmReceiveMethodManual ConfirmReceiveMethod = 2 ConfirmReceiveMethodManual ConfirmReceiveMethod = 2
) )
const (
// InfoTypeAcceptSubscribeMessage 接受订阅通知
InfoTypeAcceptSubscribeMessage InfoType = "accept"
// InfoTypeRejectSubscribeMessage 拒绝订阅通知
InfoTypeRejectSubscribeMessage InfoType = "reject"
)
// PushReceiver 接收消息推送 // PushReceiver 接收消息推送
// 暂仅支付 Aes 加密方式 // 暂仅支付 Aes 加密方式
type PushReceiver struct { type PushReceiver struct {
@@ -188,19 +203,98 @@ func (receiver *PushReceiver) getEvent(dataType string, eventType EventType, dec
var pushData PushDataXpayCoinPayNotify var pushData PushDataXpayCoinPayNotify
err := receiver.unmarshal(dataType, decryptMsg, &pushData) err := receiver.unmarshal(dataType, decryptMsg, &pushData)
return &pushData, err return &pushData, err
case EventSubscribePopup:
// 用户操作订阅通知弹窗事件推送
return receiver.unmarshalSubscribePopup(dataType, decryptMsg)
case EventSubscribeMsgChange:
// 用户管理订阅通知事件推送
return receiver.unmarshalSubscribeMsgChange(dataType, decryptMsg)
case EventSubscribeMsgSent:
// 用户发送订阅通知事件推送
return receiver.unmarshalSubscribeMsgSent(dataType, decryptMsg)
} }
// 暂不支持其他事件类型,直接返回解密后的数据,由调用方处理 // 暂不支持其他事件类型,直接返回解密后的数据,由调用方处理
return decryptMsg, nil return decryptMsg, nil
} }
// unmarshal 解析推送的数据 // unmarshal 解析推送的数据
func (receiver *PushReceiver) unmarshal(dateType string, decryptMsg []byte, pushData interface{}) error { func (receiver *PushReceiver) unmarshal(dataType string, decryptMsg []byte, pushData interface{}) error {
if dateType == DataTypeXML { if dataType == DataTypeXML {
return xml.Unmarshal(decryptMsg, pushData) return xml.Unmarshal(decryptMsg, pushData)
} }
return json.Unmarshal(decryptMsg, pushData) return json.Unmarshal(decryptMsg, pushData)
} }
// unmarshalSubscribePopup
func (receiver *PushReceiver) unmarshalSubscribePopup(dataType string, decryptMsg []byte) (PushData, error) {
var pushData PushDataSubscribePopup
err := receiver.unmarshal(dataType, decryptMsg, &pushData)
if err == nil {
listData := gjson.Get(string(decryptMsg), "List")
if listData.IsObject() {
listItem := SubscribeMsgPopupEventList{}
if parseErr := json.Unmarshal([]byte(listData.Raw), &listItem); parseErr != nil {
return &pushData, parseErr
}
pushData.SetSubscribeMsgPopupEvents([]SubscribeMsgPopupEventList{listItem})
} else if listData.IsArray() {
listItems := make([]SubscribeMsgPopupEventList, 0)
if parseErr := json.Unmarshal([]byte(listData.Raw), &listItems); parseErr != nil {
return &pushData, parseErr
}
pushData.SetSubscribeMsgPopupEvents(listItems)
}
}
return &pushData, err
}
// unmarshalSubscribeMsgChange 解析用户管理订阅通知事件推送
func (receiver *PushReceiver) unmarshalSubscribeMsgChange(dataType string, decryptMsg []byte) (PushData, error) {
var pushData PushDataSubscribeMsgChange
err := receiver.unmarshal(dataType, decryptMsg, &pushData)
if err == nil {
listData := gjson.Get(string(decryptMsg), "List")
if listData.IsObject() {
listItem := SubscribeMsgChangeList{}
if parseErr := json.Unmarshal([]byte(listData.Raw), &listItem); parseErr != nil {
return &pushData, parseErr
}
pushData.SetSubscribeMsgChangeEvents([]SubscribeMsgChangeList{listItem})
} else if listData.IsArray() {
listItems := make([]SubscribeMsgChangeList, 0)
if parseErr := json.Unmarshal([]byte(listData.Raw), &listItems); parseErr != nil {
return &pushData, parseErr
}
pushData.SetSubscribeMsgChangeEvents(listItems)
}
}
return &pushData, err
}
// unmarshalSubscribeMsgSent 解析用户发送订阅通知事件推送
func (receiver *PushReceiver) unmarshalSubscribeMsgSent(dataType string, decryptMsg []byte) (PushData, error) {
var pushData PushDataSubscribeMsgSent
err := receiver.unmarshal(dataType, decryptMsg, &pushData)
if err == nil {
listData := gjson.Get(string(decryptMsg), "List")
if listData.IsObject() {
listItem := SubscribeMsgSentList{}
if parseErr := json.Unmarshal([]byte(listData.Raw), &listItem); parseErr != nil {
return &pushData, parseErr
}
pushData.SetSubscribeMsgSentEvents([]SubscribeMsgSentList{listItem})
} else if listData.IsArray() {
listItems := make([]SubscribeMsgSentList, 0)
if parseErr := json.Unmarshal([]byte(listData.Raw), &listItems); parseErr != nil {
return &pushData, parseErr
}
pushData.SetSubscribeMsgSentEvents(listItems)
}
}
return &pushData, err
}
// DataReceived 接收到的数据 // DataReceived 接收到的数据
type DataReceived struct { type DataReceived struct {
Encrypt string `json:"Encrypt" xml:"Encrypt"` // 加密的消息体 Encrypt string `json:"Encrypt" xml:"Encrypt"` // 加密的消息体
@@ -306,8 +400,8 @@ type PushDataSecVodUpload struct {
type SecVodUploadEvent struct { type SecVodUploadEvent struct {
MediaID string `json:"media_id" xml:"media_id"` // 媒资 id MediaID string `json:"media_id" xml:"media_id"` // 媒资 id
SourceContext string `json:"source_context" xml:"source_context"` // 透传上传接口中开发者设置的值。 SourceContext string `json:"source_context" xml:"source_context"` // 透传上传接口中开发者设置的值。
Errcode int `json:"errcode" xml:"errcode"` // 错误码,上传失败时该值非 ErrCode int `json:"errcode" xml:"errcode"` // 错误码,上传失败时该值非
Errmsg string `json:"errmsg" xml:"errmsg"` // 错误提示 ErrMsg string `json:"errmsg" xml:"errmsg"` // 错误提示
} }
// PushDataSecVodAudit 短剧媒资审核状态 // PushDataSecVodAudit 短剧媒资审核状态
@@ -373,3 +467,113 @@ type CoinInfo struct {
ActualPrice int64 `json:"ActualPrice" xml:"ActualPrice"` // 物品实际支付价格(单位:分) ActualPrice int64 `json:"ActualPrice" xml:"ActualPrice"` // 物品实际支付价格(单位:分)
Attach string `json:"Attach" xml:"Attach"` // 透传信息 Attach string `json:"Attach" xml:"Attach"` // 透传信息
} }
// PushDataSubscribePopup 用户操作订阅通知弹窗事件推送
type PushDataSubscribePopup struct {
CommonPushData
subscribeMsgPopupEventList []SubscribeMsgPopupEventList `json:"-"`
SubscribeMsgPopupEvent SubscribeMsgPopupEvent `xml:"SubscribeMsgPopupEvent"`
}
// SubscribeMsgPopupEvent 用户操作订阅通知弹窗消息回调
type SubscribeMsgPopupEvent struct {
List []SubscribeMsgPopupEventList `xml:"List"`
}
// SubscribeMsgPopupEventList 订阅消息事件列表
type SubscribeMsgPopupEventList struct {
TemplateID string `xml:"TemplateId" json:"TemplateId"`
SubscribeStatusString string `xml:"SubscribeStatusString" json:"SubscribeStatusString"`
PopupScene string `xml:"PopupScene" json:"PopupScene"`
}
// SetSubscribeMsgPopupEvents 设置订阅消息事件
func (s *PushDataSubscribePopup) SetSubscribeMsgPopupEvents(list []SubscribeMsgPopupEventList) {
s.subscribeMsgPopupEventList = list
}
// GetSubscribeMsgPopupEvents 获取订阅消息事件数据
func (s *PushDataSubscribePopup) GetSubscribeMsgPopupEvents() []SubscribeMsgPopupEventList {
if s.subscribeMsgPopupEventList != nil {
return s.subscribeMsgPopupEventList
}
if s.SubscribeMsgPopupEvent.List == nil || len(s.SubscribeMsgPopupEvent.List) < 1 {
return nil
}
return s.SubscribeMsgPopupEvent.List
}
// PushDataSubscribeMsgChange 用户管理订阅通知事件推送
type PushDataSubscribeMsgChange struct {
CommonPushData
SubscribeMsgChangeEvent SubscribeMsgChangeEvent `xml:"SubscribeMsgChangeEvent"`
subscribeMsgChangeList []SubscribeMsgChangeList `json:"-"`
}
// SubscribeMsgChangeEvent 用户管理订阅通知回调
type SubscribeMsgChangeEvent struct {
List []SubscribeMsgChangeList `xml:"List" json:"List"`
}
// SubscribeMsgChangeList 订阅消息事件列表
type SubscribeMsgChangeList struct {
TemplateID string `xml:"TemplateId" json:"TemplateId"`
SubscribeStatusString string `xml:"SubscribeStatusString" json:"SubscribeStatusString"`
}
// SetSubscribeMsgChangeEvents 设置订阅消息事件
func (s *PushDataSubscribeMsgChange) SetSubscribeMsgChangeEvents(list []SubscribeMsgChangeList) {
s.subscribeMsgChangeList = list
}
// GetSubscribeMsgChangeEvents 获取订阅消息事件数据
func (s *PushDataSubscribeMsgChange) GetSubscribeMsgChangeEvents() []SubscribeMsgChangeList {
if s.subscribeMsgChangeList != nil {
return s.subscribeMsgChangeList
}
if s.SubscribeMsgChangeEvent.List == nil || len(s.SubscribeMsgChangeEvent.List) < 1 {
return nil
}
return s.SubscribeMsgChangeEvent.List
}
// PushDataSubscribeMsgSent 用户发送订阅通知事件推送
type PushDataSubscribeMsgSent struct {
CommonPushData
SubscribeMsgSentEvent SubscribeMsgSentEvent `xml:"SubscribeMsgSentEvent"`
subscribeMsgSentEventList []SubscribeMsgSentList `json:"-"`
}
// SubscribeMsgSentEvent 用户发送订阅通知回调
type SubscribeMsgSentEvent struct {
List []SubscribeMsgSentList `xml:"List" json:"List"`
}
// SubscribeMsgSentList 订阅消息事件列表
type SubscribeMsgSentList struct {
TemplateID string `xml:"TemplateId" json:"TemplateId"`
MsgID string `xml:"MsgID" json:"MsgID"`
ErrorCode int `xml:"ErrorCode" json:"ErrorCode"`
ErrorStatus string `xml:"ErrorStatus" json:"ErrorStatus"`
}
// SetSubscribeMsgSentEvents 设置订阅消息事件
func (s *PushDataSubscribeMsgSent) SetSubscribeMsgSentEvents(list []SubscribeMsgSentList) {
s.subscribeMsgSentEventList = list
}
// GetSubscribeMsgSentEvents 获取订阅消息事件数据
func (s *PushDataSubscribeMsgSent) GetSubscribeMsgSentEvents() []SubscribeMsgSentList {
if s.subscribeMsgSentEventList != nil {
return s.subscribeMsgSentEventList
}
if s.SubscribeMsgSentEvent.List == nil || len(s.SubscribeMsgSentEvent.List) < 1 {
return nil
}
return s.SubscribeMsgSentEvent.List
}

View File

@@ -0,0 +1,15 @@
package message
import "errors"
// ErrInvalidReply 无效的回复
var ErrInvalidReply = errors.New("无效的回复信息")
// ErrUnsupportedReply 不支持的回复类型
var ErrUnsupportedReply = errors.New("不支持的回复消息")
// Reply 消息回复
type Reply struct {
MsgType MsgType
MsgData interface{}
}

View File

@@ -282,7 +282,7 @@ type ResponseEncryptedXMLMsg struct {
Nonce string `xml:"Nonce" json:"Nonce"` Nonce string `xml:"Nonce" json:"Nonce"`
} }
// CDATA 使用该类型,在序列化为 xml 文本时文本会被解析器忽略 // CDATA 使用该类型在序列化为 xml 文本时文本会被解析器忽略
type CDATA string type CDATA string
// MarshalXML 实现自己的序列化方法 // MarshalXML 实现自己的序列化方法