正在显示
26 个修改的文件
包含
964 行增加
和
32 行删除
README.md
0 → 100644
1 | +## 推送调用说明 | ||
2 | + | ||
3 | +### 服务端调用 | ||
4 | + | ||
5 | +服务端 project_key 是 slave_key | ||
6 | + | ||
7 | +存在子项目: | ||
8 | + | ||
9 | +主项目键值 ability | ||
10 | + | ||
11 | +子项目键值 worth | ||
12 | + | ||
13 | +那么价值服务端调用推送接口,传入的project_key是worth | ||
14 | + | ||
15 | + | ||
16 | + | ||
17 | +不存在子项目: | ||
18 | + | ||
19 | +主项目键值 mmm.suplus.orders | ||
20 | + | ||
21 | +子项目键值 - | ||
22 | + | ||
23 | +那么订单服务端(消息中心)调用推送接口,传入的project_key是mmm.suplus.orders | ||
24 | + | ||
25 | +### 客户端调用 | ||
26 | + | ||
27 | +app更新设备信息 project_key 是 master_key | ||
28 | + | ||
29 | +例如: | ||
30 | + | ||
31 | +同上,因为客户端主项目里面包含子项目,所以更新设备信息的时候传入主项目的编码,即为 ability,如果一个app只有一个项目 如:mmm.suplus.orders |
@@ -4,14 +4,18 @@ log_level = "${LOG_LEVEL||debug}" | @@ -4,14 +4,18 @@ log_level = "${LOG_LEVEL||debug}" | ||
4 | aliyun_logs_access ="${aliyun_logs_access||F:/log/app.log}" | 4 | aliyun_logs_access ="${aliyun_logs_access||F:/log/app.log}" |
5 | 5 | ||
6 | 6 | ||
7 | -#阿里云基础配置 | ||
8 | -AccessKeyID ="LTAI4FhiZ3UktC6N1u3H5GFC" | ||
9 | -AccessKeySecret ="UyspWwdni55CYQ02hUCint4qY2jNYO" | 7 | +#个人阿里云基础配置 |
8 | +#AccessKeyID ="LTAI4FhiZ3UktC6N1u3H5GFC" | ||
9 | +#AccessKeySecret ="UyspWwdni55CYQ02hUCint4qY2jNYO" | ||
10 | +#OssEndPoint ="oss-cn-shanghai.aliyuncs.com" | ||
11 | +#BuckName ="mmm-vod-dev-public" | ||
10 | cname ="https://media.goexample.live/" | 12 | cname ="https://media.goexample.live/" |
11 | 13 | ||
12 | -OssEndPoint ="oss-cn-shanghai.aliyuncs.com" | ||
13 | -BuckName ="mmm-vod-dev-public" | ||
14 | - | 14 | +#公司 |
15 | +AccessKeyID ="LTAI4Fz1LUBW2fXp6QWaJHRS" | ||
16 | +AccessKeySecret ="aLZXwK8pgrs10Ws03qcN7NsrSXFVsg" | ||
17 | +OssEndPoint ="oss-cn-shenzhen.aliyuncs.com" | ||
18 | +BuckName ="timeless-world" | ||
15 | 19 | ||
16 | #友盟推送 | 20 | #友盟推送 |
17 | UMENG_API_HOST = "http://msg.umeng.com" | 21 | UMENG_API_HOST = "http://msg.umeng.com" |
1 | [dev_online] | 1 | [dev_online] |
2 | -#Ali could | ||
3 | -AccessKeyID ="LTAI4Fz1LUBW2fXp6QWaJHRS" | ||
4 | -AccessKeySecret ="aLZXwK8pgrs10Ws03qcN7NsrSXFVsg" | ||
5 | 2 | ||
6 | #日志 | 3 | #日志 |
7 | log_level = "${LOG_LEVEL||debug}" | 4 | log_level = "${LOG_LEVEL||debug}" |
8 | aliyun_logs_access ="${aliyun_logs_access||F:/log/app.log}" | 5 | aliyun_logs_access ="${aliyun_logs_access||F:/log/app.log}" |
9 | 6 | ||
7 | +#AccessKeyID ="LTAI4FhiZ3UktC6N1u3H5GFC" | ||
8 | +#AccessKeySecret ="UyspWwdni55CYQ02hUCint4qY2jNYO" | ||
9 | +#OssEndPoint ="oss-cn-shanghai.aliyuncs.com" | ||
10 | +#BuckName ="mmm-vod-dev-public" | ||
11 | + | ||
10 | #阿里云 | 12 | #阿里云 |
13 | +AccessKeyID ="LTAI4Fz1LUBW2fXp6QWaJHRS" | ||
14 | +AccessKeySecret ="aLZXwK8pgrs10Ws03qcN7NsrSXFVsg" | ||
11 | cname ="https://media.fjmaimaimai.com/" | 15 | cname ="https://media.fjmaimaimai.com/" |
16 | +OssEndPoint ="oss-cn-shenzhen.aliyuncs.com" | ||
17 | +BuckName ="timeless-world" | ||
12 | 18 | ||
13 | #数据库相关 | 19 | #数据库相关 |
14 | MYSQL_USER = "${MYSQL_USER||root}" | 20 | MYSQL_USER = "${MYSQL_USER||root}" |
@@ -9,6 +9,8 @@ AccessKeySecret ="aLZXwK8pgrs10Ws03qcN7NsrSXFVsg" | @@ -9,6 +9,8 @@ AccessKeySecret ="aLZXwK8pgrs10Ws03qcN7NsrSXFVsg" | ||
9 | 9 | ||
10 | #阿里云 | 10 | #阿里云 |
11 | cname ="https://media.fjmaimaimai.com/" | 11 | cname ="https://media.fjmaimaimai.com/" |
12 | +OssEndPoint ="oss-cn-shenzhen.aliyuncs.com" | ||
13 | +BuckName ="timeless-world" | ||
12 | 14 | ||
13 | #数据库相关 | 15 | #数据库相关 |
14 | MYSQL_USER = "${MYSQL_USER||root}" | 16 | MYSQL_USER = "${MYSQL_USER||root}" |
@@ -9,6 +9,8 @@ AccessKeySecret ="aLZXwK8pgrs10Ws03qcN7NsrSXFVsg" | @@ -9,6 +9,8 @@ AccessKeySecret ="aLZXwK8pgrs10Ws03qcN7NsrSXFVsg" | ||
9 | 9 | ||
10 | #阿里云 | 10 | #阿里云 |
11 | cname ="https://media.fjmaimaimai.com/" | 11 | cname ="https://media.fjmaimaimai.com/" |
12 | +OssEndPoint ="oss-cn-shenzhen.aliyuncs.com" | ||
13 | +BuckName ="timeless-world" | ||
12 | 14 | ||
13 | #数据库相关 | 15 | #数据库相关 |
14 | MYSQL_USER = "${MYSQL_USER||root1}" | 16 | MYSQL_USER = "${MYSQL_USER||root1}" |
@@ -85,5 +85,5 @@ func CreateStsAuth(header *protocol.RequestHeader, files []string) (rsp interfac | @@ -85,5 +85,5 @@ func CreateStsAuth(header *protocol.RequestHeader, files []string) (rsp interfac | ||
85 | FileName: fileBase, | 85 | FileName: fileBase, |
86 | }) | 86 | }) |
87 | } | 87 | } |
88 | - return map[string]interface{}{"access": access, "files": listPath}, nil | 88 | + return map[string]interface{}{"certificate": access, "files": listPath}, nil |
89 | } | 89 | } |
@@ -5,7 +5,7 @@ import ( | @@ -5,7 +5,7 @@ import ( | ||
5 | "gitlab.fjmaimaimai.com/mmm-go/gocomm/pkg/log" | 5 | "gitlab.fjmaimaimai.com/mmm-go/gocomm/pkg/log" |
6 | protocol "openapi/pkg/domain" | 6 | protocol "openapi/pkg/domain" |
7 | "openapi/pkg/infrastructure/push" | 7 | "openapi/pkg/infrastructure/push" |
8 | - "openapi/pkg/infrastructure/push/getui" | 8 | + getui "openapi/pkg/infrastructure/push/getuiV2" |
9 | "openapi/pkg/infrastructure/repository" | 9 | "openapi/pkg/infrastructure/repository" |
10 | "openapi/pkg/infrastructure/utils" | 10 | "openapi/pkg/infrastructure/utils" |
11 | ) | 11 | ) |
@@ -47,6 +47,9 @@ func Notification(header *protocol.RequestHeader, request *protocol.PushInfoRequ | @@ -47,6 +47,9 @@ func Notification(header *protocol.RequestHeader, request *protocol.PushInfoRequ | ||
47 | err = nil | 47 | err = nil |
48 | return | 48 | return |
49 | } | 49 | } |
50 | + if extInfo, ok := appInfo.GetExtInfo(); ok { | ||
51 | + requestOriginal.Ext["intent"] = extInfo.Intent | ||
52 | + } | ||
50 | if len(deviceList) == 0 { | 53 | if len(deviceList) == 0 { |
51 | err = protocol.NewSuccessWithMessage(fmt.Sprintf("接收人:%v 未查询到注册的设备信息!", request.Receivers)) | 54 | err = protocol.NewSuccessWithMessage(fmt.Sprintf("接收人:%v 未查询到注册的设备信息!", request.Receivers)) |
52 | return | 55 | return |
@@ -81,13 +84,16 @@ func NotificationOriginal(header *protocol.RequestHeader, request *protocol.Push | @@ -81,13 +84,16 @@ func NotificationOriginal(header *protocol.RequestHeader, request *protocol.Push | ||
81 | 84 | ||
82 | push.Title(request.Title), | 85 | push.Title(request.Title), |
83 | push.Content(request.Content), | 86 | push.Content(request.Content), |
84 | - //push.TransmissionContent(utils.JsonAssertString(request.Ext)), | 87 | + push.Extra(request.Ext), |
85 | } | 88 | } |
86 | ) | 89 | ) |
87 | rsp = &protocol.PushInfoResponse{} | 90 | rsp = &protocol.PushInfoResponse{} |
88 | if v, ok := request.Ext["transData"]; ok { | 91 | if v, ok := request.Ext["transData"]; ok { |
89 | options = append(options, push.TransmissionContent(utils.JsonAssertString(v))) | 92 | options = append(options, push.TransmissionContent(utils.JsonAssertString(v))) |
90 | } | 93 | } |
94 | + if v, ok := request.Ext["intent"]; ok { | ||
95 | + options = append(options, push.Intent(v.(string))) | ||
96 | + } | ||
91 | clientIds = request.ClientIdList | 97 | clientIds = request.ClientIdList |
92 | switch len(clientIds) { | 98 | switch len(clientIds) { |
93 | case 0: | 99 | case 0: |
@@ -142,7 +148,7 @@ func UpdateDevice(header *protocol.RequestHeader, request *protocol.UpdateDevice | @@ -142,7 +148,7 @@ func UpdateDevice(header *protocol.RequestHeader, request *protocol.UpdateDevice | ||
142 | log.Error(err) | 148 | log.Error(err) |
143 | return | 149 | return |
144 | } | 150 | } |
145 | - if err = rep.UpdateDevice(request.Muid, request.ClientId, request.DeviceToken, request.ProjectKey); err != nil { | 151 | + if err = rep.UpdateDevice(request.Muid, request.ClientId, request.DeviceToken, request.ProjectKey, request.Phone); err != nil { |
146 | log.Error(err) | 152 | log.Error(err) |
147 | } | 153 | } |
148 | err = protocol.NewSuccessWithMessage("更新成功") | 154 | err = protocol.NewSuccessWithMessage("更新成功") |
pkg/constant/push.go
0 → 100644
@@ -5,6 +5,7 @@ var ( | @@ -5,6 +5,7 @@ var ( | ||
5 | AccessKeyID string = "LTAI4FhiZ3UktC6N1u3H5GFC" | 5 | AccessKeyID string = "LTAI4FhiZ3UktC6N1u3H5GFC" |
6 | AccessKeySecret string = "UyspWwdni55CYQ02hUCint4qY2jNYO" | 6 | AccessKeySecret string = "UyspWwdni55CYQ02hUCint4qY2jNYO" |
7 | CName string = "https://media.goexample.live/" | 7 | CName string = "https://media.goexample.live/" |
8 | + RoleArn string = "acs:ram::1777936936207896:role/ossclientsts" //"acs:ram::1373671070046453:role/role-oss-sts" | ||
8 | ) | 9 | ) |
9 | 10 | ||
10 | func init() { | 11 | func init() { |
1 | package domain | 1 | package domain |
2 | 2 | ||
3 | +import ( | ||
4 | + "encoding/json" | ||
5 | + "openapi/pkg/infrastructure/log" | ||
6 | +) | ||
7 | + | ||
3 | /*PushInfo 推送信息*/ | 8 | /*PushInfo 推送信息*/ |
4 | type PushInfoOriginalRequest struct { | 9 | type PushInfoOriginalRequest struct { |
5 | Type int `json:"msgType"` | 10 | Type int `json:"msgType"` |
@@ -35,6 +40,7 @@ type UpdateDeviceRequest struct { | @@ -35,6 +40,7 @@ type UpdateDeviceRequest struct { | ||
35 | Muid int64 `json:"muid" valid:"Required;"` //企业平台中的用户 UID | 40 | Muid int64 `json:"muid" valid:"Required;"` //企业平台中的用户 UID |
36 | ClientId string `json:"clientId" valid:"Required"` | 41 | ClientId string `json:"clientId" valid:"Required"` |
37 | DeviceToken string `json:"deviceToken"` | 42 | DeviceToken string `json:"deviceToken"` |
43 | + Phone string `json:"phone"` | ||
38 | } | 44 | } |
39 | type UpdateDeviceResponse struct { | 45 | type UpdateDeviceResponse struct { |
40 | } | 46 | } |
@@ -54,4 +60,21 @@ type AppInfo struct { | @@ -54,4 +60,21 @@ type AppInfo struct { | ||
54 | AppMasterSecret string | 60 | AppMasterSecret string |
55 | AppId string | 61 | AppId string |
56 | ProjectId int //项目编号 | 62 | ProjectId int //项目编号 |
63 | + ExtInfo string | ||
64 | +} | ||
65 | + | ||
66 | +type ExtInfo struct { | ||
67 | + Intent string `json:"intent"` | ||
68 | +} | ||
69 | + | ||
70 | +func (t *AppInfo) GetExtInfo() (*ExtInfo, bool) { | ||
71 | + extInfo := &ExtInfo{} | ||
72 | + if len(t.ExtInfo) == 0 { | ||
73 | + return nil, false | ||
74 | + } | ||
75 | + if err := json.Unmarshal([]byte(t.ExtInfo), extInfo); err != nil { | ||
76 | + log.Error(err.Error()) | ||
77 | + return nil, false | ||
78 | + } | ||
79 | + return extInfo, true | ||
57 | } | 80 | } |
1 | package aliyun | 1 | package aliyun |
2 | 2 | ||
3 | import ( | 3 | import ( |
4 | - "fmt" | ||
5 | "github.com/aliyun/alibaba-cloud-sdk-go/services/sts" | 4 | "github.com/aliyun/alibaba-cloud-sdk-go/services/sts" |
6 | "openapi/pkg/constant" | 5 | "openapi/pkg/constant" |
7 | "openapi/pkg/infrastructure/log" | 6 | "openapi/pkg/infrastructure/log" |
8 | ) | 7 | ) |
9 | 8 | ||
9 | +/* | ||
10 | + 设置参数。 指定角色的ARN。格式:acs:ram::$accountID:role/$roleName/$RoleSessionName 。 mmm-go@1373671070046453.onaliyun.com | ||
11 | + 配置用户 - ram角色权限-oss授权 | ||
12 | + $accountID 用户的阿里云账号 | ||
13 | + $RoleArn 点到ram角色 具体的权限详情 格式 格式:acs:ram::$accountID:role/$roleName/$RoleSessionName | ||
14 | + | ||
15 | + 1.使用授权账号(mmm-go@1373671070046453.onaliyun.com)登录 | ||
16 | + 2.RAM访问控制->RAM角色管理->添加权限->为权限设置 oss访问权限 | ||
17 | + 3.查看角色详情-》ARN( acs:ram::1373671070046453:role/role-oss-sts )需要配置给程序使用 | ||
18 | + 4.RAM访问控制->用户(mmm-go@1373671070046453.onaliyun.com)->给用户设置角色 | ||
19 | +*/ | ||
20 | + | ||
21 | +/* | ||
22 | + 1.前端sts上传需要设置bucket跨域,bucket->权限管理->跨域设置 | ||
23 | +*/ | ||
10 | func DefaultSts() (interface{}, error) { | 24 | func DefaultSts() (interface{}, error) { |
11 | //构建一个阿里云客户端, 用于发起请求。 | 25 | //构建一个阿里云客户端, 用于发起请求。 |
12 | //构建阿里云客户端时,需要设置AccessKey ID和AccessKey Secret。 | 26 | //构建阿里云客户端时,需要设置AccessKey ID和AccessKey Secret。 |
@@ -18,12 +32,7 @@ func DefaultSts() (interface{}, error) { | @@ -18,12 +32,7 @@ func DefaultSts() (interface{}, error) { | ||
18 | //构建请求对象。 | 32 | //构建请求对象。 |
19 | request := sts.CreateAssumeRoleRequest() | 33 | request := sts.CreateAssumeRoleRequest() |
20 | request.Scheme = "https" | 34 | request.Scheme = "https" |
21 | - | ||
22 | - //设置参数。 指定角色的ARN。格式:acs:ram::$accountID:role/$roleName/$RoleSessionName 。 mmm-go@1373671070046453.onaliyun.com | ||
23 | - // 配置用户 - ram角色权限-oss授权 | ||
24 | - // $accountID 用户的阿里云账号 | ||
25 | - // $RoleArn 点到ram角色 具体的权限详情 格式 格式:acs:ram::$accountID:role/$roleName/$RoleSessionName | ||
26 | - request.RoleArn = fmt.Sprintf("acs:ram::1373671070046453:role/role-oss-sts") | 35 | + request.RoleArn = constant.RoleArn |
27 | // 会话名称 | 36 | // 会话名称 |
28 | request.RoleSessionName = "role-oss-sts-session" | 37 | request.RoleSessionName = "role-oss-sts-session" |
29 | 38 | ||
@@ -38,5 +47,7 @@ func DefaultSts() (interface{}, error) { | @@ -38,5 +47,7 @@ func DefaultSts() (interface{}, error) { | ||
38 | "expiration": response.Credentials.Expiration, | 47 | "expiration": response.Credentials.Expiration, |
39 | "accessKeyId": response.Credentials.AccessKeyId, | 48 | "accessKeyId": response.Credentials.AccessKeyId, |
40 | "securityToken": response.Credentials.SecurityToken, | 49 | "securityToken": response.Credentials.SecurityToken, |
50 | + "bucket": constant.BuckName, | ||
51 | + "endpoint": constant.OssEndPoint, | ||
41 | }, nil | 52 | }, nil |
42 | } | 53 | } |
@@ -6,7 +6,7 @@ import ( | @@ -6,7 +6,7 @@ import ( | ||
6 | _ "github.com/go-sql-driver/mysql" | 6 | _ "github.com/go-sql-driver/mysql" |
7 | "gitlab.fjmaimaimai.com/mmm-go/gocomm/pkg/log" | 7 | "gitlab.fjmaimaimai.com/mmm-go/gocomm/pkg/log" |
8 | "openapi/pkg/constant" | 8 | "openapi/pkg/constant" |
9 | - _ "openapi/pkg/infrastructure/bgorm/model" | 9 | + _ "openapi/pkg/infrastructure/bgorm/models" |
10 | ) | 10 | ) |
11 | 11 | ||
12 | func init() { | 12 | func init() { |
@@ -15,6 +15,7 @@ type PushAppInfo struct { | @@ -15,6 +15,7 @@ type PushAppInfo struct { | ||
15 | AppMasterSecret string `orm:"column(app_master_secret);size(255);null" description:"推送服务端密钥"` | 15 | AppMasterSecret string `orm:"column(app_master_secret);size(255);null" description:"推送服务端密钥"` |
16 | AppId string `orm:"column(app_id);size(255);null" description:"推送应用编号"` | 16 | AppId string `orm:"column(app_id);size(255);null" description:"推送应用编号"` |
17 | ProjectId int `orm:"column(project_id);size(255);null" description:"项目编号"` | 17 | ProjectId int `orm:"column(project_id);size(255);null" description:"项目编号"` |
18 | + ExtInfo string `orm:"column(ext_info);size(1024);null" description:"扩展信息"` | ||
18 | } | 19 | } |
19 | 20 | ||
20 | func (t *PushAppInfo) TableName() string { | 21 | func (t *PushAppInfo) TableName() string { |
@@ -9,6 +9,7 @@ import ( | @@ -9,6 +9,7 @@ import ( | ||
9 | type PushDeviceInfo struct { | 9 | type PushDeviceInfo struct { |
10 | Id int `orm:"column(id);auto"` | 10 | Id int `orm:"column(id);auto"` |
11 | Uid int64 `orm:"column(uid);null" description:"企业平台用户id (muid)"` | 11 | Uid int64 `orm:"column(uid);null" description:"企业平台用户id (muid)"` |
12 | + Phone string `orm:"column(phone);size(100);null" description:"设备手机号"` | ||
12 | ClientId string `orm:"column(client_id);size(100);null" description:"设备识别码 推送标识"` | 13 | ClientId string `orm:"column(client_id);size(100);null" description:"设备识别码 推送标识"` |
13 | DeviceToken string `orm:"column(device_token);size(100);null" description:"设备识别码 推送标识"` | 14 | DeviceToken string `orm:"column(device_token);size(100);null" description:"设备识别码 推送标识"` |
14 | CreateAt time.Time `orm:"column(create_at);type(timestamp);null" description:"创建时间"` | 15 | CreateAt time.Time `orm:"column(create_at);type(timestamp);null" description:"创建时间"` |
@@ -51,6 +51,7 @@ type Message struct { | @@ -51,6 +51,7 @@ type Message struct { | ||
51 | AppKey string `json:"appkey"` | 51 | AppKey string `json:"appkey"` |
52 | IsOffline bool `json:"is_offline"` | 52 | IsOffline bool `json:"is_offline"` |
53 | MsgType string `json:"msgtype"` | 53 | MsgType string `json:"msgtype"` |
54 | + OfflineExpireTime int `json:"offline_expire_time"` //offline_expire_time | ||
54 | } | 55 | } |
55 | 56 | ||
56 | //透传 | 57 | //透传 |
@@ -59,6 +60,7 @@ type Transmission struct { | @@ -59,6 +60,7 @@ type Transmission struct { | ||
59 | TransmissionContent string `json:"transmission_content,omitempty"` //透传内容 | 60 | TransmissionContent string `json:"transmission_content,omitempty"` //透传内容 |
60 | DurationBegin string `json:"duration_begin,omitempty"` | 61 | DurationBegin string `json:"duration_begin,omitempty"` |
61 | DurationEnd string `json:"duration_end,omitempty"` | 62 | DurationEnd string `json:"duration_end,omitempty"` |
63 | + Notify interface{} `json:"notify,omitempty"` | ||
62 | } | 64 | } |
63 | 65 | ||
64 | func (o *Transmission) SetTransmissionType(t bool) { | 66 | func (o *Transmission) SetTransmissionType(t bool) { |
@@ -71,6 +73,27 @@ func (o *Transmission) SetDuration(begin, end string) { | @@ -71,6 +73,27 @@ func (o *Transmission) SetDuration(begin, end string) { | ||
71 | o.DurationBegin = begin | 73 | o.DurationBegin = begin |
72 | o.DurationEnd = end | 74 | o.DurationEnd = end |
73 | } | 75 | } |
76 | +func (o *Transmission) SetNotify(options *push.Options) { | ||
77 | + mapNotify := make(map[string]interface{}) | ||
78 | + mapNotify["title"] = options.Title | ||
79 | + mapNotify["content"] = options.Content | ||
80 | + // 安卓设备生成 | ||
81 | + mapNotify["intent"] = options.Intent | ||
82 | + mapNotify["type"] = 1 | ||
83 | + //mapNotify["extKVList"] = []ExtKVList{ | ||
84 | + // //{Constrains: "HW", Key: "/message/android/notification/badge/add_num", Value: 1}, | ||
85 | + // //{Constrains: "HW", Key: "/message/android/notification/badge/class", Value: `"com.getui.demo.GetuiSdkDemoActivity"`}, | ||
86 | + // // 小米厂家支持 | ||
87 | + // {Constrains: "XM", Key: "channel", Value: "\"2882303761518034255\""},//Default 2882303761518034255 | ||
88 | + //} | ||
89 | + o.Notify = mapNotify | ||
90 | +} | ||
91 | + | ||
92 | +type ExtKVList struct { | ||
93 | + Constrains string `json:"constrains"` | ||
94 | + Key string `json:"key"` | ||
95 | + Value interface{} `json:"value"` | ||
96 | +} | ||
74 | 97 | ||
75 | func NewTemplate(options *push.Options) *Template { | 98 | func NewTemplate(options *push.Options) *Template { |
76 | return &Template{ | 99 | return &Template{ |
@@ -87,6 +110,7 @@ func NewTransmission(options *push.Options) *Transmission { | @@ -87,6 +110,7 @@ func NewTransmission(options *push.Options) *Transmission { | ||
87 | } | 110 | } |
88 | t.SetTransmissionType(false) | 111 | t.SetTransmissionType(false) |
89 | t.SetTransmissionContent(options.TransmissionContent) | 112 | t.SetTransmissionContent(options.TransmissionContent) |
113 | + t.SetNotify(options) | ||
90 | return t | 114 | return t |
91 | } | 115 | } |
92 | func NewMessage(options *push.Options) *Message { | 116 | func NewMessage(options *push.Options) *Message { |
@@ -94,6 +118,7 @@ func NewMessage(options *push.Options) *Message { | @@ -94,6 +118,7 @@ func NewMessage(options *push.Options) *Message { | ||
94 | AppKey: options.AppKey, | 118 | AppKey: options.AppKey, |
95 | IsOffline: true, | 119 | IsOffline: true, |
96 | MsgType: resolveMsgType(options.MsgType), | 120 | MsgType: resolveMsgType(options.MsgType), |
121 | + OfflineExpireTime: 100000000, | ||
97 | } | 122 | } |
98 | } | 123 | } |
99 | func resolveMsgType(msgType int) string { | 124 | func resolveMsgType(msgType int) string { |
@@ -168,6 +193,10 @@ func NewAps(options *push.Options) (v *Aps) { | @@ -168,6 +193,10 @@ func NewAps(options *push.Options) (v *Aps) { | ||
168 | ContentAvailable: 0, | 193 | ContentAvailable: 0, |
169 | Sound: "default", | 194 | Sound: "default", |
170 | } | 195 | } |
196 | + // 声音 | ||
197 | + if value, ok := options.GetExt("sound"); ok { | ||
198 | + v.Sound = value.(string) | ||
199 | + } | ||
171 | return | 200 | return |
172 | } | 201 | } |
173 | func NewAlert(options *push.Options) (v *Alert) { | 202 | func NewAlert(options *push.Options) (v *Alert) { |
@@ -186,7 +215,7 @@ type Aps struct { | @@ -186,7 +215,7 @@ type Aps struct { | ||
186 | Alert *Alert `json:"alert"` | 215 | Alert *Alert `json:"alert"` |
187 | AutoBadge string `json:"autoBadge"` //用于计算应用上面未读数字 | 216 | AutoBadge string `json:"autoBadge"` //用于计算应用上面未读数字 |
188 | ContentAvailable int `json:"content-available,omitempty"` //推送直接带有透传数据 0:有通知栏消息 1:无通知栏消息 | 217 | ContentAvailable int `json:"content-available,omitempty"` //推送直接带有透传数据 0:有通知栏消息 1:无通知栏消息 |
189 | - Sound string `json:"sound"` | 218 | + Sound string `json:"sound"` // 推送声音 storein_voice.mp3 |
190 | } | 219 | } |
191 | type Alert struct { | 220 | type Alert struct { |
192 | Title string `json:"title"` | 221 | Title string `json:"title"` |
pkg/infrastructure/push/getuiV2/getui.go
0 → 100644
1 | +package getuiV2 | ||
2 | + | ||
3 | +import ( | ||
4 | + "crypto/sha256" | ||
5 | + "fmt" | ||
6 | + "github.com/astaxie/beego/httplib" | ||
7 | + "gitlab.fjmaimaimai.com/mmm-go/gocomm/pkg/log" | ||
8 | + "openapi/pkg/infrastructure/push" | ||
9 | + "openapi/pkg/infrastructure/utils" | ||
10 | + "strings" | ||
11 | + "sync" | ||
12 | + "time" | ||
13 | +) | ||
14 | + | ||
15 | +const ( | ||
16 | + host = "https://restapi.getui.com" | ||
17 | + pushSingle = "push/single/cid" | ||
18 | + saveListBody = "push/list/message" | ||
19 | + pushList = "push/list/cid" | ||
20 | + authSign = "auth" | ||
21 | +) | ||
22 | + | ||
23 | +var ( | ||
24 | + authtoken = "" | ||
25 | + expire time.Time | ||
26 | + authMux sync.RWMutex | ||
27 | + expireSpan = time.Second * 600 //token 10分钟过期 | ||
28 | +) | ||
29 | + | ||
30 | +const ( | ||
31 | + error_not_auth = "not_auth" | ||
32 | +) | ||
33 | + | ||
34 | +//GetuiNotification 个推消息推送 | ||
35 | +type GetuiNotification struct { | ||
36 | + Options *push.Options | ||
37 | + Request *httplib.BeegoHTTPRequest | ||
38 | + retry int | ||
39 | +} | ||
40 | + | ||
41 | +func (notify *GetuiNotification) Init(options ...push.Option) error { | ||
42 | + notify.Options = &push.Options{} | ||
43 | + for _, o := range options { | ||
44 | + o(notify.Options) | ||
45 | + } | ||
46 | + notify.retry = 3 | ||
47 | + return nil | ||
48 | +} | ||
49 | +func (notify *GetuiNotification) Send(option map[string]interface{}) (rsp map[string]interface{}, err error) { | ||
50 | + retry := 1 | ||
51 | + for { | ||
52 | + switch notify.Options.PushType { | ||
53 | + case push.PushToSingle: | ||
54 | + rsp, err = notify.pushToSingle(option) | ||
55 | + case push.PushToList: | ||
56 | + rsp, err = notify.pushToList(option) | ||
57 | + default: | ||
58 | + rsp, err = notify.pushToSingle(option) | ||
59 | + } | ||
60 | + if err == nil { | ||
61 | + break | ||
62 | + } | ||
63 | + //重试 | ||
64 | + if err != nil && retry > notify.retry { | ||
65 | + return | ||
66 | + } | ||
67 | + log.Error(fmt.Sprintf("【个推】 重试:%v 失败:%v", retry, err)) | ||
68 | + retry++ | ||
69 | + if retry > notify.retry { | ||
70 | + break | ||
71 | + } | ||
72 | + } | ||
73 | + return | ||
74 | +} | ||
75 | + | ||
76 | +//pushToSingle 单推 | ||
77 | +func (notify *GetuiNotification) pushToSingle(option map[string]interface{}) (rsp map[string]interface{}, err error) { | ||
78 | + var token string | ||
79 | + rsp = make(map[string]interface{}) | ||
80 | + if token, err = notify.GetAuthToken(); err != nil { | ||
81 | + return | ||
82 | + } | ||
83 | + | ||
84 | + var ( | ||
85 | + result *MessageBase | ||
86 | + url = notify.Url(notify.Options.AppId, pushSingle) | ||
87 | + m = notify.Message(pushSingle) | ||
88 | + ) | ||
89 | + notify.Request = httplib.Post(url) | ||
90 | + notify.Request.Header("token", token) | ||
91 | + notify.Request.JSONBody(m) | ||
92 | + if err = notify.Request.ToJSON(&result); err != nil { | ||
93 | + return | ||
94 | + } | ||
95 | + rsp = result.Data | ||
96 | + notify.print(url, m, result, result) | ||
97 | + if err = handleResult(url, result); err != nil { | ||
98 | + return | ||
99 | + } | ||
100 | + return | ||
101 | +} | ||
102 | + | ||
103 | +//pushToList 群推 | ||
104 | +//步骤1.获取token | ||
105 | +//步骤2.save_list_body保存消息共同体 | ||
106 | +//步骤3.push_list | ||
107 | +func (notify *GetuiNotification) pushToList(option map[string]interface{}) (rsp map[string]interface{}, err error) { | ||
108 | + var ( | ||
109 | + token string | ||
110 | + taskId string | ||
111 | + ) | ||
112 | + rsp = make(map[string]interface{}) | ||
113 | + if token, err = notify.GetAuthToken(); err != nil { | ||
114 | + return | ||
115 | + } | ||
116 | + if taskId, err = notify.saveListBody(token, option); err != nil { | ||
117 | + return | ||
118 | + } | ||
119 | + var ( | ||
120 | + result *MessageBase | ||
121 | + url = notify.Url(notify.Options.AppId, pushList) | ||
122 | + m = NewMapData() | ||
123 | + ) | ||
124 | + m.AddFiled("audience.cid", notify.Options.ClientIds) | ||
125 | + m.AddFiled("taskid", taskId) | ||
126 | + m.AddFiled("is_async", true) //是否异步发送 | ||
127 | + notify.Request = httplib.Post(url) | ||
128 | + notify.Request.Header("token", token) | ||
129 | + notify.Request.JSONBody(m.Data) | ||
130 | + if err = notify.Request.ToJSON(&result); err != nil { | ||
131 | + return | ||
132 | + } | ||
133 | + rsp = result.Data | ||
134 | + notify.print(url, m, result, result) | ||
135 | + if err = handleResult(url, result); err != nil { | ||
136 | + return | ||
137 | + } | ||
138 | + return | ||
139 | +} | ||
140 | + | ||
141 | +//saveListBody 保存消息共同体 | ||
142 | +func (notify *GetuiNotification) saveListBody(token string, option map[string]interface{}) (taskId string, err error) { | ||
143 | + var ( | ||
144 | + result *MessageBase | ||
145 | + url = notify.Url(notify.Options.AppId, saveListBody) | ||
146 | + m = notify.Message(saveListBody) | ||
147 | + ) | ||
148 | + notify.Request = httplib.Post(url) | ||
149 | + notify.Request.Header("token", token) | ||
150 | + notify.Request.JSONBody(m) | ||
151 | + delete(m, "audience") | ||
152 | + if err = notify.Request.ToJSON(&result); err != nil { | ||
153 | + return | ||
154 | + } | ||
155 | + notify.print(url, m, result, result) | ||
156 | + if err = handleResult(url, result); err != nil { | ||
157 | + return | ||
158 | + } | ||
159 | + if id, ok := result.Data["taskid"]; ok { | ||
160 | + taskId = id.(string) | ||
161 | + return | ||
162 | + } | ||
163 | + return "", fmt.Errorf("error task id") | ||
164 | +} | ||
165 | + | ||
166 | +//Message 组装消息体 | ||
167 | +func (notify *GetuiNotification) Message(method string) map[string]interface{} { | ||
168 | + msg := NewPushMessage(notify.Options) | ||
169 | + return msg | ||
170 | +} | ||
171 | + | ||
172 | +//Url 组装请求地址 | ||
173 | +func (notify *GetuiNotification) Url(param string, method string) string { | ||
174 | + return fmt.Sprintf("%v/v2/%v/%v", host, param, method) | ||
175 | +} | ||
176 | + | ||
177 | +//GetAuthToken 获取token | ||
178 | +func (notify *GetuiNotification) GetAuthToken() (token string, err error) { | ||
179 | + if authtoken != "" && expire.Unix() > time.Now().Unix() { | ||
180 | + token = authtoken | ||
181 | + return | ||
182 | + } | ||
183 | + | ||
184 | + authMux.Lock() | ||
185 | + defer authMux.Unlock() | ||
186 | + url := notify.Url(notify.Options.AppId, authSign) | ||
187 | + notify.Request = httplib.Post(strings.TrimSpace(url)) | ||
188 | + req := &AuthSignRequest{ | ||
189 | + Timestamp: fmt.Sprintf("%v", time.Now().Unix()*1000), //"1589797286000",// | ||
190 | + AppKey: notify.Options.AppKey, | ||
191 | + } | ||
192 | + req.Sign = sign(req.AppKey, req.Timestamp, notify.Options.AppMasterSecret) | ||
193 | + if _, err = notify.Request.JSONBody(req); err != nil { | ||
194 | + return | ||
195 | + } | ||
196 | + | ||
197 | + var rsp *AuthSignResponse | ||
198 | + err = notify.Request.ToJSON(&rsp) | ||
199 | + notify.print(url, req, rsp, rsp.MessageBase) | ||
200 | + if err != nil { | ||
201 | + return | ||
202 | + } | ||
203 | + if err = handleResult(url, rsp.MessageBase); err != nil { | ||
204 | + return | ||
205 | + } | ||
206 | + authtoken = rsp.Data["token"].(string) | ||
207 | + token = rsp.Data["token"].(string) | ||
208 | + expire = time.Now().Add(rsp.GetExpireTime(expireSpan)) | ||
209 | + log.Info(fmt.Sprintf("【个推】token:%v expire:%v", token, expire)) | ||
210 | + return | ||
211 | +} | ||
212 | + | ||
213 | +//打印日志 debug_module=true print debug log | ||
214 | +func (notify *GetuiNotification) print(url string, v interface{}, rsp interface{}, result *MessageBase) { | ||
215 | + if !notify.Options.DebugModule { | ||
216 | + return | ||
217 | + } | ||
218 | + log.Error(fmt.Sprintf("【个推】 url:%v \n request:%v \n response:%v 结果:%v", url, utils.JsonAssertString(v), utils.JsonAssertString(rsp), result.Msg)) | ||
219 | +} | ||
220 | + | ||
221 | +//处理结果 | ||
222 | +func handleResult(url string, result *MessageBase) (err error) { | ||
223 | + if result.Code == 0 { | ||
224 | + return | ||
225 | + } | ||
226 | + | ||
227 | + switch result.Code { | ||
228 | + case 0: | ||
229 | + break | ||
230 | + default: | ||
231 | + setToken("") | ||
232 | + break | ||
233 | + } | ||
234 | + err = fmt.Errorf("error:%v %v", result.Code, result.Msg) | ||
235 | + return err | ||
236 | +} | ||
237 | +func sign(appKey, timestamp, masterSecret string) string { | ||
238 | + sha := sha256.New() | ||
239 | + sha.Write([]byte(appKey + timestamp + masterSecret)) | ||
240 | + return fmt.Sprintf("%x", sha.Sum(nil)) | ||
241 | +} | ||
242 | + | ||
243 | +func setToken(token string) { | ||
244 | + //authMux.Lock() | ||
245 | + //defer authMux.Unlock() | ||
246 | + authtoken = token | ||
247 | +} |
1 | +package getuiV2 | ||
2 | + | ||
3 | +import ( | ||
4 | + "openapi/pkg/infrastructure/push" | ||
5 | + "openapi/pkg/infrastructure/utils" | ||
6 | + "testing" | ||
7 | +) | ||
8 | + | ||
9 | +func TestGetui(t *testing.T) { | ||
10 | + var param = make(map[string]interface{}) | ||
11 | + param["A"] = "A1" | ||
12 | + param["B"] = 2 | ||
13 | + param["transData"] = struct{ Id int }{Id: 10} | ||
14 | + notification := &GetuiNotification{} | ||
15 | + err := notification.Init( | ||
16 | + push.DebugModule(true), | ||
17 | + | ||
18 | + push.AppId("TkpBI4awmg9fBUx3NWKXS6"), | ||
19 | + push.AppKey("5AjJeDOSOZ5ojQpXJFjhg9"), | ||
20 | + push.AppMasterSecret("9VnM8MaA6n84Y5VnOIaSvA"), | ||
21 | + //单推 | ||
22 | + push.PushType(push.PushToSingle), | ||
23 | + push.ClientId("b5fff5f6b0af551da5f381fa47991828"), | ||
24 | + //群推 | ||
25 | + //push.PushType(push.PushToList), | ||
26 | + //push.ClientIds([]string{"b5fff5f6b0af551da5f381fa47991828"}), | ||
27 | + | ||
28 | + push.MsgType(push.SystemTransmission), //push.SystemNotification | ||
29 | + push.Title("测试 hello"), | ||
30 | + push.Content("hello content"), | ||
31 | + | ||
32 | + push.TransmissionContent(utils.JsonAssertString(param["transData"])), | ||
33 | + push.Extra(param), | ||
34 | + ) | ||
35 | + if err != nil { | ||
36 | + t.Fatal(err) | ||
37 | + } | ||
38 | + _, err = notification.Send(param) | ||
39 | + if err != nil { | ||
40 | + t.Fatal(err) | ||
41 | + } | ||
42 | +} | ||
43 | + | ||
44 | +func TestGetuiPrd(t *testing.T) { | ||
45 | + var param = make(map[string]interface{}) | ||
46 | + param["A"] = "A1" | ||
47 | + param["B"] = 2 | ||
48 | + param["transData"] = struct { | ||
49 | + Id int `json:"id"` | ||
50 | + }{Id: 1} | ||
51 | + notification := &GetuiNotification{} | ||
52 | + err := notification.Init( | ||
53 | + push.DebugModule(true), | ||
54 | + | ||
55 | + push.AppId("WgrbaaStTk7JElrXOCgUg6"), | ||
56 | + push.AppKey("FG5lbqVrHa5rS9NVfxNP7"), | ||
57 | + push.AppMasterSecret("FW3jMNLJrRARYKv2iqA5H5"), | ||
58 | + //单推 | ||
59 | + //push.PushType(push.PushToSingle), | ||
60 | + //push.ClientId("502f4fd7ba5df15ac6b3d5c561efd9ca"), | ||
61 | + //群推 | ||
62 | + push.PushType(push.PushToList), | ||
63 | + push.ClientIds([]string{"502f4fd7ba5df15ac6b3d5c561efd9ca"}), | ||
64 | + | ||
65 | + push.MsgType(push.SystemTransmission), | ||
66 | + push.Title("hello"), | ||
67 | + push.Content("hello content"), | ||
68 | + | ||
69 | + push.TransmissionContent(utils.JsonAssertString(param["transData"])), | ||
70 | + push.Extra(param), | ||
71 | + ) | ||
72 | + if err != nil { | ||
73 | + t.Fatal(err) | ||
74 | + } | ||
75 | + _, err = notification.Send(param) | ||
76 | + if err != nil { | ||
77 | + t.Fatal(err) | ||
78 | + } | ||
79 | +} |
pkg/infrastructure/push/getuiV2/model.go
0 → 100644
1 | +package getuiV2 | ||
2 | + | ||
3 | +import ( | ||
4 | + "gitlab.fjmaimaimai.com/mmm-go/gocomm/identity/uid" | ||
5 | + "openapi/pkg/infrastructure/push" | ||
6 | + "time" | ||
7 | +) | ||
8 | + | ||
9 | +//1.消息模板 | ||
10 | +type NotificationTemplate struct { | ||
11 | + *Template | ||
12 | + Notification *Notification `json:"notification"` | ||
13 | +} | ||
14 | + | ||
15 | +//1.新建通知模板 | ||
16 | +func NewNotificationTemplate(options *push.Options) *NotificationTemplate { | ||
17 | + return &NotificationTemplate{ | ||
18 | + Template: NewTemplate(options), | ||
19 | + Notification: &Notification{ | ||
20 | + Style: (&Style{}).SetStyle0(options), | ||
21 | + Transmission: NewTransmission(options), | ||
22 | + }, | ||
23 | + } | ||
24 | +} | ||
25 | + | ||
26 | +//2.透传模板 | ||
27 | +type TransmissionTemplate struct { | ||
28 | + *Template | ||
29 | + Transmission *Transmission `json:"transmission"` | ||
30 | + PushInfo *PushInfo `json:"push_info"` | ||
31 | +} | ||
32 | + | ||
33 | +//2.新建透传模板 | ||
34 | +func NewTransmissionTemplate(options *push.Options) *TransmissionTemplate { | ||
35 | + return &TransmissionTemplate{ | ||
36 | + Template: NewTemplate(options), | ||
37 | + Transmission: NewTransmission(options), | ||
38 | + PushInfo: NewPushInfo(options), | ||
39 | + } | ||
40 | +} | ||
41 | + | ||
42 | +type Template struct { | ||
43 | + ClientId string `json:"cid,omitempty"` | ||
44 | + RequestId string `json:"requestid,omitempty"` | ||
45 | + Message *Message `json:"message"` | ||
46 | +} | ||
47 | +type Notification struct { | ||
48 | + Style *Style `json:"style"` | ||
49 | + *Transmission | ||
50 | +} | ||
51 | +type Message struct { | ||
52 | + AppKey string `json:"appkey"` | ||
53 | + IsOffline bool `json:"is_offline"` | ||
54 | + MsgType string `json:"msgtype"` | ||
55 | + OfflineExpireTime int `json:"offline_expire_time"` //offline_expire_time | ||
56 | +} | ||
57 | + | ||
58 | +//透传 | ||
59 | +type Transmission struct { | ||
60 | + TransmissionType bool `json:"transmission_type"` //收到消息是否立即启动应用,true为立即启动,false则广播等待启动,默认是否 | ||
61 | + TransmissionContent string `json:"transmission_content,omitempty"` //透传内容 | ||
62 | + DurationBegin string `json:"duration_begin,omitempty"` | ||
63 | + DurationEnd string `json:"duration_end,omitempty"` | ||
64 | + Notify interface{} `json:"notify,omitempty"` | ||
65 | +} | ||
66 | + | ||
67 | +func (o *Transmission) SetTransmissionType(t bool) { | ||
68 | + o.TransmissionType = t | ||
69 | +} | ||
70 | +func (o *Transmission) SetTransmissionContent(s string) { | ||
71 | + o.TransmissionContent = s | ||
72 | +} | ||
73 | +func (o *Transmission) SetDuration(begin, end string) { | ||
74 | + o.DurationBegin = begin | ||
75 | + o.DurationEnd = end | ||
76 | +} | ||
77 | +func (o *Transmission) SetNotify(options *push.Options) { | ||
78 | + mapNotify := make(map[string]interface{}) | ||
79 | + mapNotify["title"] = options.Title | ||
80 | + mapNotify["content"] = options.Content | ||
81 | + // 安卓设备生成 | ||
82 | + mapNotify["intent"] = options.Intent | ||
83 | + mapNotify["type"] = 1 | ||
84 | + //mapNotify["extKVList"] = []ExtKVList{ | ||
85 | + // //{Constrains: "HW", Key: "/message/android/notification/badge/add_num", Value: 1}, | ||
86 | + // //{Constrains: "HW", Key: "/message/android/notification/badge/class", Value: `"com.getui.demo.GetuiSdkDemoActivity"`}, | ||
87 | + // // 小米厂家支持 | ||
88 | + // {Constrains: "XM", Key: "channel", Value: "\"2882303761518034255\""},//Default 2882303761518034255 | ||
89 | + //} | ||
90 | + o.Notify = mapNotify | ||
91 | +} | ||
92 | + | ||
93 | +type ExtKVList struct { | ||
94 | + Constrains string `json:"constrains"` | ||
95 | + Key string `json:"key"` | ||
96 | + Value interface{} `json:"value"` | ||
97 | +} | ||
98 | + | ||
99 | +func NewTemplate(options *push.Options) *Template { | ||
100 | + return &Template{ | ||
101 | + Message: NewMessage(options), | ||
102 | + ClientId: options.ClientId, | ||
103 | + RequestId: genRequestId(), | ||
104 | + } | ||
105 | +} | ||
106 | +func NewTransmission(options *push.Options) *Transmission { | ||
107 | + t := &Transmission{} | ||
108 | + if len(options.TransmissionContent) == 0 { | ||
109 | + //t.SetTransmissionType(false) | ||
110 | + return t | ||
111 | + } | ||
112 | + t.SetTransmissionType(false) | ||
113 | + t.SetTransmissionContent(options.TransmissionContent) | ||
114 | + t.SetNotify(options) | ||
115 | + return t | ||
116 | +} | ||
117 | +func NewMessage(options *push.Options) *Message { | ||
118 | + return &Message{ | ||
119 | + AppKey: options.AppKey, | ||
120 | + IsOffline: true, | ||
121 | + MsgType: resolveMsgType(options.MsgType), | ||
122 | + OfflineExpireTime: 100000000, | ||
123 | + } | ||
124 | +} | ||
125 | +func resolveMsgType(msgType int) string { | ||
126 | + /* | ||
127 | + 消息应用类型, | ||
128 | + 可选项:notification、link、notypopload、startactivity, transmission | ||
129 | + */ | ||
130 | + switch msgType { | ||
131 | + case push.SystemNotification: | ||
132 | + return "notification" | ||
133 | + case push.SystemTransmission: | ||
134 | + return "transmission" | ||
135 | + } | ||
136 | + return "notification" | ||
137 | +} | ||
138 | +func genRequestId() string { | ||
139 | + return uid.NewV1().StringNoDash() | ||
140 | +} | ||
141 | + | ||
142 | +//样式 0:系统样式 1:个推样式 4:纯图样式 6:展开通知样式 | ||
143 | +type Style struct { | ||
144 | + Type int `json:"type"` //样式类型 | ||
145 | + Text string `json:"text"` //通知内容 | ||
146 | + Title string `json:"title"` //通知标题 | ||
147 | + Logo string `json:"logo,omitempty"` //通知的图标名称,包含后缀名(需要在客户端开发时嵌入),如“push.png” | ||
148 | + //IsRing bool `json:"is_ring"` //收到通知是否响铃:true响铃,false不响铃。默认响铃 | ||
149 | + //IsVibrate bool `json:"is_vibrate"` //收到通知是否振动:true振动,false不振动。默认振动 | ||
150 | + NotifyId int `json:"notify_id"` //需要被覆盖的消息已经增加了notifyId字段,用于实现下发消息的覆盖。新的消息使用相同的notifyId下发。 | ||
151 | +} | ||
152 | + | ||
153 | +//设置默认样式 0 | ||
154 | +func (s *Style) SetStyle0(options *push.Options) *Style { | ||
155 | + s.Type = 0 | ||
156 | + s.Title = options.Title | ||
157 | + s.Text = options.Content | ||
158 | + s.Logo = "push.png" //TODO:设置Logo地址 | ||
159 | + s.NotifyId = 1 | ||
160 | + return s | ||
161 | +} | ||
162 | + | ||
163 | +//认证请求/应答 | ||
164 | +type AuthSignRequest struct { | ||
165 | + Sign string `json:"sign"` | ||
166 | + Timestamp string `json:"timestamp"` | ||
167 | + AppKey string `json:"appkey"` | ||
168 | +} | ||
169 | +type AuthSignResponse struct { | ||
170 | + *Result | ||
171 | + *MessageBase | ||
172 | + //ExpireTime string `json:"expire_time"` | ||
173 | + //AuthToken string `json:"token"` | ||
174 | +} | ||
175 | + | ||
176 | +func (auth AuthSignResponse) GetExpireTime(defaultEx time.Duration) time.Duration { | ||
177 | + //v,e := strconv.Atoi(auth.ExpireTime) | ||
178 | + //if e!=nil || v==0{ | ||
179 | + return defaultEx | ||
180 | + //} | ||
181 | + //return time.Duration(v)*time.Second | ||
182 | +} | ||
183 | + | ||
184 | +type MessageBase struct { | ||
185 | + Code int `json:"code"` | ||
186 | + Msg string `json:"msg"` | ||
187 | + Data map[string]interface{} `json:"data"` | ||
188 | +} | ||
189 | + | ||
190 | +//应答结果 | ||
191 | +type Result struct { | ||
192 | + Result string `json:"result"` | ||
193 | + TaskId string `json:"taskid"` | ||
194 | + Status string `json:"status"` | ||
195 | + Desc string `json:"desc"` | ||
196 | +} | ||
197 | + | ||
198 | +//透传附加的推送信息 | ||
199 | +func NewPushInfo(options *push.Options) (v *PushInfo) { | ||
200 | + v = &PushInfo{ | ||
201 | + Aps: NewAps(options), | ||
202 | + Payload: options.TransmissionContent, | ||
203 | + } | ||
204 | + return | ||
205 | +} | ||
206 | +func NewAps(options *push.Options) (v *Aps) { | ||
207 | + v = &Aps{ | ||
208 | + Alert: NewAlert(options), | ||
209 | + AutoBadge: "+1", | ||
210 | + ContentAvailable: 0, | ||
211 | + Sound: "default", | ||
212 | + } | ||
213 | + // 声音 | ||
214 | + if value, ok := options.GetExt("sound"); ok { | ||
215 | + v.Sound = value.(string) | ||
216 | + } | ||
217 | + return | ||
218 | +} | ||
219 | +func NewAlert(options *push.Options) (v *Alert) { | ||
220 | + v = &Alert{ | ||
221 | + //Title: options.Title, //TODO:去掉这个ios通知栏只有内容行,没有标题行,如果后期需要显示这个 需要ext里面扩展字段用来控制是否显示标题 | ||
222 | + Body: options.Content, | ||
223 | + } | ||
224 | + return | ||
225 | +} | ||
226 | + | ||
227 | +type PushInfo struct { | ||
228 | + Aps *Aps `json:"aps"` | ||
229 | + Payload string `json:"payload,omitempty"` | ||
230 | +} | ||
231 | +type Aps struct { | ||
232 | + Alert *Alert `json:"alert"` | ||
233 | + AutoBadge string `json:"autoBadge"` //用于计算应用上面未读数字 | ||
234 | + ContentAvailable int `json:"content-available,omitempty"` //推送直接带有透传数据 0:有通知栏消息 1:无通知栏消息 | ||
235 | + Sound string `json:"sound"` // 推送声音 storein_voice.mp3 | ||
236 | +} | ||
237 | +type Alert struct { | ||
238 | + Title string `json:"title"` | ||
239 | + Body string `json:"body"` | ||
240 | +} |
pkg/infrastructure/push/getuiV2/model_v2.go
0 → 100644
1 | +package getuiV2 | ||
2 | + | ||
3 | +import ( | ||
4 | + "openapi/pkg/infrastructure/push" | ||
5 | + "reflect" | ||
6 | + "strings" | ||
7 | +) | ||
8 | + | ||
9 | +const ( | ||
10 | + splitChar = "." | ||
11 | + contentTemplate = "点击查看详情" | ||
12 | +) | ||
13 | + | ||
14 | +type MapData struct { | ||
15 | + Data map[string]interface{} | ||
16 | +} | ||
17 | + | ||
18 | +func NewMapData() *MapData { | ||
19 | + return &MapData{ | ||
20 | + Data: make(map[string]interface{}), | ||
21 | + } | ||
22 | +} | ||
23 | +func (m *MapData) AddFiled(field string, value interface{}) *MapData { | ||
24 | + fields := strings.Split(field, splitChar) | ||
25 | + var cur map[string]interface{} | ||
26 | + cur = m.Data | ||
27 | + for index, f := range fields { | ||
28 | + if index != (len(fields) - 1) { | ||
29 | + if _, ok := cur[f]; !ok { | ||
30 | + cur[f] = make(map[string]interface{}) | ||
31 | + } | ||
32 | + cur = cur[f].(map[string]interface{}) | ||
33 | + continue | ||
34 | + } | ||
35 | + if _, ok := cur[f]; !ok { | ||
36 | + cur[f] = value | ||
37 | + } | ||
38 | + } | ||
39 | + return m | ||
40 | +} | ||
41 | +func (m *MapData) GetFiledMap(field string) map[string]interface{} { | ||
42 | + fields := strings.Split(field, splitChar) | ||
43 | + cur := m.Data | ||
44 | + for _, f := range fields { | ||
45 | + if _, ok := cur[f]; !ok { | ||
46 | + cur[f] = make(map[string]interface{}) | ||
47 | + } | ||
48 | + cur = cur[f].(map[string]interface{}) | ||
49 | + } | ||
50 | + return cur | ||
51 | +} | ||
52 | +func (m *MapData) SetFieldMap(fieldMap map[string]interface{}, field string, value interface{}) *MapData { | ||
53 | + if value == nil { | ||
54 | + return m | ||
55 | + } | ||
56 | + v := reflect.ValueOf(value) | ||
57 | + if !v.IsValid() { | ||
58 | + return m | ||
59 | + } | ||
60 | + if v.IsZero() { | ||
61 | + return m | ||
62 | + } | ||
63 | + fieldMap[field] = value | ||
64 | + return m | ||
65 | +} | ||
66 | + | ||
67 | +// 推送消息 | ||
68 | +func NewPushMessage(option *push.Options) map[string]interface{} { | ||
69 | + m := NewMapData() | ||
70 | + // request_id | ||
71 | + m.AddFiled("request_id", genRequestId()) | ||
72 | + | ||
73 | + // setting | ||
74 | + m.AddFiled("settings.ttl", 3600*24) | ||
75 | + | ||
76 | + // audience | ||
77 | + m.AddFiled("audience.cid", []string{option.ClientId}) | ||
78 | + if len(option.ClientIds) > 0 { | ||
79 | + m.AddFiled("audience.cid", option.ClientIds) | ||
80 | + } | ||
81 | + | ||
82 | + // push_message | ||
83 | + if option.MsgType == push.Notification { | ||
84 | + pushMessageNotification(m, option) | ||
85 | + } else if option.MsgType == push.SystemTransmission { | ||
86 | + pushMessageTransmission(m, option) | ||
87 | + } | ||
88 | + | ||
89 | + // push_channel | ||
90 | + channelAndroid(m, option) | ||
91 | + channelIOS(m, option) | ||
92 | + | ||
93 | + return m.Data | ||
94 | +} | ||
95 | + | ||
96 | +/*push_message*/ | ||
97 | +func pushMessageNotification(m *MapData, option *push.Options) { | ||
98 | + notification := m.GetFiledMap("push_message.notification") | ||
99 | + | ||
100 | + m.SetFieldMap(notification, "title", option.Title) | ||
101 | + m.SetFieldMap(notification, "body", option.Content) | ||
102 | + | ||
103 | + m.SetFieldMap(notification, "click_type", "payload") | ||
104 | + m.SetFieldMap(notification, "payload", option.TransmissionContent) | ||
105 | + if len(option.Intent) > 0 { | ||
106 | + m.SetFieldMap(notification, "click_type", "intent") | ||
107 | + m.SetFieldMap(notification, "intent", option.Intent) | ||
108 | + } | ||
109 | +} | ||
110 | +func pushMessageTransmission(m *MapData, option *push.Options) { | ||
111 | + m.AddFiled("push_message.transmission", option.TransmissionContent) | ||
112 | +} | ||
113 | + | ||
114 | +/*channel*/ | ||
115 | +/* | ||
116 | + "android":{ | ||
117 | + "ups":{ | ||
118 | + "notification":{ | ||
119 | + "title":"请填写android标题", | ||
120 | + "body":"请填写android内容", | ||
121 | + "click_type":"url", | ||
122 | + "url":"https://xxx" | ||
123 | + } | ||
124 | + } | ||
125 | + }, | ||
126 | +*/ | ||
127 | +func channelAndroid(m *MapData, option *push.Options) { | ||
128 | + notification := m.GetFiledMap("push_channel.android.ups.notification") | ||
129 | + m.SetFieldMap(notification, "title", option.Title). | ||
130 | + SetFieldMap(notification, "body", contentTemplate) //TODO:配置控制body是否展示 | ||
131 | + if len(option.Intent) > 0 { | ||
132 | + m.SetFieldMap(notification, "intent", option.FormatTranDataToIntent()). | ||
133 | + SetFieldMap(notification, "click_type", "intent") | ||
134 | + } else { | ||
135 | + m.SetFieldMap(notification, "click_type", "payload") | ||
136 | + m.SetFieldMap(notification, "payload", option.TransmissionContent) | ||
137 | + } | ||
138 | +} | ||
139 | + | ||
140 | +/* | ||
141 | + "ios":{ | ||
142 | + "type":"notify", | ||
143 | + "payload":"自定义消息", | ||
144 | + "aps":{ | ||
145 | + "alert":{ | ||
146 | + "title":"请填写ios标题", | ||
147 | + "body":"请填写ios内容" | ||
148 | + }, | ||
149 | + "content-available":0 | ||
150 | + }, | ||
151 | + "auto_badge":"+1" | ||
152 | + } | ||
153 | +*/ | ||
154 | +func channelIOS(m *MapData, option *push.Options) { | ||
155 | + m.AddFiled("push_channel.ios.type", "notify") | ||
156 | + m.AddFiled("push_channel.ios.payload", option.TransmissionContent) | ||
157 | + | ||
158 | + alert := m.GetFiledMap("push_channel.ios.aps.alert") | ||
159 | + //TODO:去掉这个ios通知栏只有内容行,没有标题行,如果后期需要显示这个 需要ext里面扩展字段用来控制是否显示标题 | ||
160 | + //m.SetFieldMap(alert, "title", option.Title) | ||
161 | + m.SetFieldMap(alert, "body", option.Content) | ||
162 | + m.AddFiled("push_channel.ios.aps.content-available", 0) | ||
163 | + | ||
164 | + if v, ok := option.GetExt("sound"); ok && len(v.(string)) > 0 { | ||
165 | + m.AddFiled("push_channel.ios.aps.sound", v) | ||
166 | + } | ||
167 | + m.AddFiled("push_channel.ios.auto_badge", "+1") | ||
168 | +} |
1 | +package getuiV2 | ||
2 | + | ||
3 | +import ( | ||
4 | + "gitlab.fjmaimaimai.com/mmm-go/gocomm/common" | ||
5 | + "testing" | ||
6 | +) | ||
7 | + | ||
8 | +func TestNewMapData(t *testing.T) { | ||
9 | + m := NewMapData() | ||
10 | + m.AddFiled("user.id", 1) | ||
11 | + m.AddFiled("user.name", "tip") | ||
12 | + m.AddFiled("user.sex", true) | ||
13 | + | ||
14 | + m.AddFiled("address.lon", 59.2156461) | ||
15 | + m.AddFiled("address.lat", 23.1245648) | ||
16 | + m.AddFiled("phone", "18860183050") | ||
17 | + | ||
18 | + notification := m.GetFiledMap("notification") | ||
19 | + notification["title"] = "xxx" | ||
20 | + notification["body"] = "body" | ||
21 | + m.SetFieldMap(notification, "url", "http://") | ||
22 | + m.SetFieldMap(notification, "options", nil) | ||
23 | + | ||
24 | + t.Log(common.AssertJson(m.Data)) | ||
25 | +} |
1 | package push | 1 | package push |
2 | 2 | ||
3 | +import ( | ||
4 | + "bytes" | ||
5 | + "fmt" | ||
6 | + "strings" | ||
7 | +) | ||
8 | + | ||
3 | type Options struct { | 9 | type Options struct { |
4 | AppId string | 10 | AppId string |
5 | AppKey string | 11 | AppKey string |
@@ -13,9 +19,12 @@ type Options struct { | @@ -13,9 +19,12 @@ type Options struct { | ||
13 | 19 | ||
14 | Title string | 20 | Title string |
15 | Content string | 21 | Content string |
16 | - Extra interface{} //扩展数据 | 22 | + Extra interface{} //扩展数据 map[string]interface{} key:"sound" storein_voice.mp3 |
17 | TransmissionContent string //透传内容 | 23 | TransmissionContent string //透传内容 |
18 | 24 | ||
25 | + //多厂家支持 | ||
26 | + Intent string | ||
27 | + | ||
19 | DebugModule bool | 28 | DebugModule bool |
20 | } | 29 | } |
21 | type Option func(o *Options) | 30 | type Option func(o *Options) |
@@ -95,12 +104,48 @@ func TransmissionContent(content string) Option { | @@ -95,12 +104,48 @@ func TransmissionContent(content string) Option { | ||
95 | o.TransmissionContent = content | 104 | o.TransmissionContent = content |
96 | } | 105 | } |
97 | } | 106 | } |
107 | +func Intent(intent string) Option { | ||
108 | + return func(o *Options) { | ||
109 | + o.Intent = intent | ||
110 | + } | ||
111 | +} | ||
98 | func DebugModule(module bool) Option { | 112 | func DebugModule(module bool) Option { |
99 | return func(o *Options) { | 113 | return func(o *Options) { |
100 | o.DebugModule = module | 114 | o.DebugModule = module |
101 | } | 115 | } |
102 | } | 116 | } |
103 | 117 | ||
118 | +func (o *Options) GetExt(key string) (value interface{}, ok bool) { | ||
119 | + var mapExt map[string]interface{} | ||
120 | + if mapExt, ok = o.Extra.(map[string]interface{}); !ok { | ||
121 | + return | ||
122 | + } | ||
123 | + if value, ok = mapExt[key]; ok { | ||
124 | + return | ||
125 | + } | ||
126 | + return | ||
127 | +} | ||
128 | + | ||
129 | +func (o *Options) FormatTranDataToIntent() string { | ||
130 | + tran, ok := o.GetExt("transData") | ||
131 | + if !ok { | ||
132 | + return o.Intent | ||
133 | + } | ||
134 | + var tranMap map[string]interface{} | ||
135 | + tranMap, ok = tran.(map[string]interface{}) | ||
136 | + if !ok { | ||
137 | + return o.Intent | ||
138 | + } | ||
139 | + var params = bytes.NewBuffer(nil) | ||
140 | + for k, v := range tranMap { | ||
141 | + params.WriteString(fmt.Sprintf("S.%s=%v;", k, v)) | ||
142 | + } | ||
143 | + if idx := strings.Index(o.Intent, "end"); idx > 0 { | ||
144 | + return o.Intent[0:idx] + params.String() + "end" | ||
145 | + } | ||
146 | + return o.Intent | ||
147 | +} | ||
148 | + | ||
104 | const ( | 149 | const ( |
105 | Message = iota + 1 | 150 | Message = iota + 1 |
106 | Notification | 151 | Notification |
@@ -4,7 +4,7 @@ import ( | @@ -4,7 +4,7 @@ import ( | ||
4 | "fmt" | 4 | "fmt" |
5 | "github.com/astaxie/beego/orm" | 5 | "github.com/astaxie/beego/orm" |
6 | "openapi/pkg/domain" | 6 | "openapi/pkg/domain" |
7 | - "openapi/pkg/infrastructure/bgorm/model" | 7 | + "openapi/pkg/infrastructure/bgorm/models" |
8 | . "openapi/pkg/infrastructure/utils" | 8 | . "openapi/pkg/infrastructure/utils" |
9 | ) | 9 | ) |
10 | 10 |
@@ -3,7 +3,7 @@ package repository | @@ -3,7 +3,7 @@ package repository | ||
3 | import ( | 3 | import ( |
4 | "github.com/astaxie/beego/orm" | 4 | "github.com/astaxie/beego/orm" |
5 | "openapi/pkg/domain" | 5 | "openapi/pkg/domain" |
6 | - "openapi/pkg/infrastructure/bgorm/model" | 6 | + "openapi/pkg/infrastructure/bgorm/models" |
7 | "sync" | 7 | "sync" |
8 | ) | 8 | ) |
9 | 9 | ||
@@ -44,6 +44,7 @@ func (repository *AppInfoRepository) transformBgormModelToDomainModel(model *mod | @@ -44,6 +44,7 @@ func (repository *AppInfoRepository) transformBgormModelToDomainModel(model *mod | ||
44 | AppMasterSecret: model.AppMasterSecret, | 44 | AppMasterSecret: model.AppMasterSecret, |
45 | AppId: model.AppId, | 45 | AppId: model.AppId, |
46 | ProjectId: model.ProjectId, | 46 | ProjectId: model.ProjectId, |
47 | + ExtInfo: model.ExtInfo, | ||
47 | }, nil | 48 | }, nil |
48 | } | 49 | } |
49 | 50 |
@@ -3,7 +3,7 @@ package repository | @@ -3,7 +3,7 @@ package repository | ||
3 | import ( | 3 | import ( |
4 | "github.com/astaxie/beego/orm" | 4 | "github.com/astaxie/beego/orm" |
5 | "openapi/pkg/domain" | 5 | "openapi/pkg/domain" |
6 | - "openapi/pkg/infrastructure/bgorm/model" | 6 | + "openapi/pkg/infrastructure/bgorm/models" |
7 | "openapi/pkg/infrastructure/utils" | 7 | "openapi/pkg/infrastructure/utils" |
8 | "strings" | 8 | "strings" |
9 | "time" | 9 | "time" |
@@ -18,10 +18,12 @@ func (repository *PushDeviceRepository) Save(device *domain.UpdateDeviceRequest) | @@ -18,10 +18,12 @@ func (repository *PushDeviceRepository) Save(device *domain.UpdateDeviceRequest) | ||
18 | m := &models.PushDeviceInfo{ | 18 | m := &models.PushDeviceInfo{ |
19 | Uid: device.Muid, | 19 | Uid: device.Muid, |
20 | ClientId: strings.TrimSpace(device.ClientId), | 20 | ClientId: strings.TrimSpace(device.ClientId), |
21 | + Phone: device.Phone, | ||
21 | DeviceToken: strings.TrimSpace(device.DeviceToken), | 22 | DeviceToken: strings.TrimSpace(device.DeviceToken), |
22 | CreateAt: time.Now(), | 23 | CreateAt: time.Now(), |
23 | UpdateAt: time.Now(), | 24 | UpdateAt: time.Now(), |
24 | ProjectMasterKey: device.ProjectKey, | 25 | ProjectMasterKey: device.ProjectKey, |
26 | + IsActive: 1, | ||
25 | } | 27 | } |
26 | _, err := o.Insert(m) | 28 | _, err := o.Insert(m) |
27 | return err | 29 | return err |
@@ -59,17 +61,17 @@ func (repository *PushDeviceRepository) Find(queryOptions map[string]interface{} | @@ -59,17 +61,17 @@ func (repository *PushDeviceRepository) Find(queryOptions map[string]interface{} | ||
59 | return | 61 | return |
60 | } | 62 | } |
61 | 63 | ||
62 | -func (repository *PushDeviceRepository) UpdateDevice(uid int64, clientId, deviceToken string, projectKey string) error { | 64 | +func (repository *PushDeviceRepository) UpdateDevice(uid int64, clientId, deviceToken string, projectKey string, phone string) error { |
63 | o := orm.NewOrm() | 65 | o := orm.NewOrm() |
64 | o.Begin() | 66 | o.Begin() |
65 | - //更新其他绑定这个client_id的设备 is_active=0 | 67 | + //更新(这个项目)其他绑定这个client_id的设备 is_active=0 |
66 | _, err := o.Raw("UPDATE push_device_info SET update_at=now(),is_active=0 where client_id=? and is_active=1 and project_master_key=?", clientId, projectKey).Exec() | 68 | _, err := o.Raw("UPDATE push_device_info SET update_at=now(),is_active=0 where client_id=? and is_active=1 and project_master_key=?", clientId, projectKey).Exec() |
67 | if err != nil { | 69 | if err != nil { |
68 | o.Rollback() | 70 | o.Rollback() |
69 | return err | 71 | return err |
70 | } | 72 | } |
71 | 73 | ||
72 | - _, err = o.Raw("UPDATE push_device_info SET client_id=?,device_token = ?,update_at=now(),is_active=1 where uid=? and project_master_key=?", clientId, deviceToken, uid, projectKey).Exec() | 74 | + _, err = o.Raw("UPDATE push_device_info SET client_id=?,device_token = ?,update_at=now(),is_active=1,phone=? where uid=? and project_master_key=?", clientId, deviceToken, phone, uid, projectKey).Exec() |
73 | if err != nil { | 75 | if err != nil { |
74 | o.Rollback() | 76 | o.Rollback() |
75 | return err | 77 | return err |
@@ -32,8 +32,8 @@ func (this *PushController) PushInfo() { | @@ -32,8 +32,8 @@ func (this *PushController) PushInfo() { | ||
32 | msg = m | 32 | msg = m |
33 | return | 33 | return |
34 | } | 34 | } |
35 | - if len(request.ProjectKey) == 0 { | ||
36 | - request.ProjectKey = "worth" //默认是价值项目 | 35 | + if len(request.ProjectKey) == 0 || request.ProjectKey == "worth" { |
36 | + request.ProjectKey = "mmm.ability.worth" //默认是价值项目 | ||
37 | } | 37 | } |
38 | header := controllers.GetRequestHeader(this.Ctx) | 38 | header := controllers.GetRequestHeader(this.Ctx) |
39 | msg = protocol.NewReturnResponse(push.Notification(header, request)) | 39 | msg = protocol.NewReturnResponse(push.Notification(header, request)) |
@@ -78,7 +78,7 @@ func (this *PushController) UpdateDevice() { | @@ -78,7 +78,7 @@ func (this *PushController) UpdateDevice() { | ||
78 | return | 78 | return |
79 | } | 79 | } |
80 | if request.ProjectKey == "" { | 80 | if request.ProjectKey == "" { |
81 | - request.ProjectKey = "ability" //默认能力展示项目 | 81 | + request.ProjectKey = "mmm.ability" //默认能力展示项目 |
82 | } | 82 | } |
83 | header := controllers.GetRequestHeader(this.Ctx) | 83 | header := controllers.GetRequestHeader(this.Ctx) |
84 | msg = protocol.NewReturnResponse(push.UpdateDevice(header, request)) | 84 | msg = protocol.NewReturnResponse(push.UpdateDevice(header, request)) |
-
请 注册 或 登录 后发表评论