diff --git a/go.sum b/go.sum index 96148ce..6d7bcd3 100644 --- a/go.sum +++ b/go.sum @@ -442,7 +442,11 @@ github.com/tjfoc/gmsm v1.4.1/go.mod h1:j4INPkHWMrhJb38G+J6W4Tw0AbuN8Thu3PbdVYhVc github.com/tmc/grpc-websocket-proxy v0.0.0-20170815181823-89b8d40f7ca8/go.mod h1:ncp9v5uamzpCO7NfCPTXjqaC+bZgJeR0sMTm6dMHP7U= github.com/urfave/cli v1.20.0/go.mod h1:70zkFmudgCuE/ngEzBv17Jvp/497gISqfk5gWijbERA= github.com/urfave/cli v1.22.1/go.mod h1:Gos4lmkARVdJ6EkW0WaNv/tZAAMe9V7XWyB60NtXRu0= +github.com/xialeistudio/go-jpush v0.0.0-20240131095927-52180d0dcd2f h1:tZplxcu/gOk26hCDf4LBTZSB8bbdr1vUEC2Y32YFqE4= +github.com/xialeistudio/go-jpush v0.0.0-20240131095927-52180d0dcd2f/go.mod h1:Yy3A3otA58L9C0kuUOgPFsKQ6/b+HUfX+aPoBA6ibFg= github.com/xiang90/probing v0.0.0-20190116061207-43a291ad63a2/go.mod h1:UETIi67q53MR2AWcXfiuqkDkRtnGDLqkBTpCHuJHxtU= +github.com/ylywyn/jpush-api-go-client v0.0.0-20190906031852-8c4466c6e369 h1:g95WlXTqXFLM36fhvDKcZWHTUnBb2KCEn4tuSizk/d8= +github.com/ylywyn/jpush-api-go-client v0.0.0-20190906031852-8c4466c6e369/go.mod h1:Nv7wKD2/bCdKUFNKcJRa99a+1+aSLlCRJFriFYdjz/I= github.com/yuin/goldmark v1.1.27/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= github.com/yuin/goldmark v1.1.30/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= github.com/yuin/goldmark v1.2.1/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= diff --git a/jPush/push.go b/jPush/push.go new file mode 100644 index 0000000..5d932f3 --- /dev/null +++ b/jPush/push.go @@ -0,0 +1,63 @@ +package jPush + +import ( + jpush "code.fnuoos.com/EggPlanet/egg_system_rules.git/jPush/sdk" + "fmt" +) + +// 极光推送 最大1000个用户 +func PushMoreUser(key, secret, title, content string, alias []string, extras map[string]interface{}) (map[string]interface{}, error) { + var client = jpush.NewClient(key, secret) + audience := &jpush.PushAudience{ + Alias: alias, + } + req := getMsg(title, content, audience, extras) + result, err := client.Push(req) + if err != nil { + return nil, err + } + return result, nil +} + +// 广播推送 一天10次 +func PushAllUser(key, secret, title, content string, extras map[string]interface{}) (map[string]interface{}, error) { + var client = jpush.NewClient(key, secret) + audience := "all" + req := getMsg(title, content, audience, extras) + result, err := client.Push(req) + if err != nil { + fmt.Println(err) + return nil, err + } + fmt.Println(result) + return result, nil +} +func getMsg(title, content string, audience interface{}, extras map[string]interface{}) *jpush.PushRequest { + req := &jpush.PushRequest{ + Platform: "all", + Audience: audience, + Notification: &jpush.PushNotification{ + Alert: content, + Android: &jpush.NotificationAndroid{ + Alert: content, + Title: title, + }, + Hmos: &jpush.NotificationHmos{ + Alert: content, + Title: title, + }, + IOS: &jpush.NotificationIOS{ + Alert: content, + }, + }, + Message: &jpush.PushMessage{ + MsgContent: content, + Extras: extras, + }, + Options: &jpush.PushOptions{ + TimeToLive: 3 * 86400, + ApnsProduction: false, + }, + } + return req +} diff --git a/jPush/sdk/LICENSE b/jPush/sdk/LICENSE new file mode 100644 index 0000000..e69de29 diff --git a/jPush/sdk/README-CN.md b/jPush/sdk/README-CN.md new file mode 100644 index 0000000..28d68f7 --- /dev/null +++ b/jPush/sdk/README-CN.md @@ -0,0 +1,20 @@ +# JPush GO SDK +极光推送golang sdk。 +官方的go sdk就新建了项目,没有文件,故开发本SDK。   +使用教程直接参照单元测试代码即可。 + +## 功能列表 ++ Push API v3 ++ Report API v3 ++ Device API v3 ++ Schedule API v3 + +## 单元测试 +1. 添加**APP_KEY**和**MASTER_SECRET**以及**REGISTRATION_ID**到环境变量 +2. go test + +## 如何使用 +参照单元测试即可 + +## 注意 +**VIP类**接口和**Admin API v1**由于暂时没有权限,没有做实现。有需要的可以提交PR。 diff --git a/jPush/sdk/README.md b/jPush/sdk/README.md new file mode 100644 index 0000000..90be075 --- /dev/null +++ b/jPush/sdk/README.md @@ -0,0 +1,20 @@ +# JPush GO SDK +[中文文档](README-CN.md) + +JPush GO SDK is the official Golang SDK for JPush, a push notification service. Since the official Go SDK only provides a project without any files, this SDK was developed to fill in the gap. Please refer to the unit test code for usage instructions. + +## Feature List ++ Push API v3 ++ Report API v3 ++ Device API v3 ++ Schedule API v3 + +## Unit Testing +1. Add APP_KEY, MASTER_SECRET, and REGISTRATION_ID to the environment variables. +2. Run `go test .` + +## How to Use +Please refer to the unit test code for usage instructions. + +## Note +The VIP class interfaces and Admin API v1 are not implemented due to lack of permission. If needed, you can submit a pull request. diff --git a/jPush/sdk/client.go b/jPush/sdk/client.go new file mode 100644 index 0000000..22a9864 --- /dev/null +++ b/jPush/sdk/client.go @@ -0,0 +1,60 @@ +package jpush + +import ( + "encoding/base64" + "fmt" + "io" + "io/ioutil" + "net/http" + "runtime" +) + +type Client struct { + AppKey string + MasterSecret string + pushUrl string + reportUrl string + deviceUrl string +} + +func NewClient(appKey, masterSecret string) *Client { + client := &Client{AppKey: appKey, MasterSecret: masterSecret} + client.pushUrl = "https://api.jpush.cn" + client.reportUrl = "https://report.jpush.cn" + client.deviceUrl = "https://device.jpush.cn" + return client +} + +func (c *Client) getAuthorization(isGroup bool) string { + str := c.AppKey + ":" + c.MasterSecret + if isGroup { + str = "group-" + str + } + buf := []byte(str) + return fmt.Sprintf("Basic %s", base64.StdEncoding.EncodeToString(buf)) +} + +func (c *Client) getUserAgent() string { + return fmt.Sprintf("(%s) go/%s", runtime.GOOS, runtime.Version()) +} + +func (c *Client) request(method, link string, body io.Reader, isGroup bool) (*Response, error) { + req, err := http.NewRequest(method, link, body) + if err != nil { + return nil, err + } + req.Header.Set("Authorization", c.getAuthorization(isGroup)) + req.Header.Set("User-Agent", c.getUserAgent()) + req.Header.Set("Content-Type", "application/json") + client := &http.Client{} + resp, err := client.Do(req) + if err != nil { + return nil, err + } + defer resp.Body.Close() + buf, err := ioutil.ReadAll(resp.Body) + if err != nil { + return nil, err + } + return &Response{data: buf}, nil +} diff --git a/jPush/sdk/client_device.go b/jPush/sdk/client_device.go new file mode 100644 index 0000000..c0f4971 --- /dev/null +++ b/jPush/sdk/client_device.go @@ -0,0 +1,108 @@ +package jpush + +import ( + "bytes" + "encoding/json" + "strings" +) + +func (c *Client) DeviceView(registrationId string) (map[string]interface{}, error) { + link := c.deviceUrl + "/v3/devices/" + registrationId + resp, err := c.request("GET", link, nil, false) + if err != nil { + return nil, err + } + return resp.Map() +} + +func (c *Client) DeviceRequest(registrationId string, req *DeviceSettingRequest) ([]byte, error) { + link := c.deviceUrl + "/v3/devices/" + registrationId + buf, err := json.Marshal(req) + if err != nil { + return nil, err + } + resp, err := c.request("POST", link, bytes.NewReader(buf), false) + if err != nil { + return nil, err + } + return resp.Bytes(), nil +} + +func (c *Client) DeviceEmptyTagsRequest(registrationId string, req *DeviceSettingEmptyTagsRequest) ([]byte, error) { + link := c.deviceUrl + "/v3/devices/" + registrationId + buf, err := json.Marshal(req) + if err != nil { + return nil, err + } + resp, err := c.request("POST", link, bytes.NewReader(buf), false) + if err != nil { + return nil, err + } + return resp.Bytes(), nil +} + +func (c *Client) DeviceGetWithAlias(alias string, platforms []string) (map[string]interface{}, error) { + link := c.deviceUrl + "/v3/aliases/" + alias + if len(platforms) > 0 { + link += "?platform=" + strings.Join(platforms, ",") + } + resp, err := c.request("GET", link, nil, false) + if err != nil { + return nil, err + } + return resp.Map() +} + +func (c *Client) DeviceDeleteAlias(alias string) ([]byte, error) { + link := c.deviceUrl + "/v3/aliases/" + alias + resp, err := c.request("DELETE", link, nil, false) + if err != nil { + return nil, err + } + return resp.Bytes(), nil +} + +func (c *Client) DeviceGetTags() (map[string]interface{}, error) { + link := c.deviceUrl + "/v3/tags/" + resp, err := c.request("GET", link, nil, false) + if err != nil { + return nil, err + } + return resp.Map() +} + +func (c *Client) DeviceCheckDeviceWithTag(tag, registrationId string) (map[string]interface{}, error) { + link := c.deviceUrl + "/v3/tags/" + tag + "/registration_ids/" + registrationId + resp, err := c.request("GET", link, nil, false) + if err != nil { + return nil, err + } + return resp.Map() +} + +func (c *Client) DeviceBindTags(tag string, req *DeviceBindTagsRequest) ([]byte, error) { + link := c.deviceUrl + "/v3/tags/" + tag + params := make(map[string]interface{}) + params["registration_ids"] = req + buf, err := json.Marshal(params) + if err != nil { + return nil, err + } + resp, err := c.request("POST", link, bytes.NewReader(buf), false) + if err != nil { + return nil, err + } + return resp.Bytes(), nil +} + +func (c *Client) DeviceDeleteTag(tag string, platforms []string) ([]byte, error) { + link := c.deviceUrl + "/v3/tags/" + tag + if len(platforms) > 0 { + link += "?platform=" + strings.Join(platforms, ",") + } + resp, err := c.request("DELETE", link, nil, false) + if err != nil { + return nil, err + } + return resp.Bytes(), nil +} diff --git a/jPush/sdk/client_push.go b/jPush/sdk/client_push.go new file mode 100644 index 0000000..c21cc6f --- /dev/null +++ b/jPush/sdk/client_push.go @@ -0,0 +1,61 @@ +package jpush + +import ( + "bytes" + "encoding/json" + "strconv" +) + +func (c *Client) Push(push *PushRequest) (map[string]interface{}, error) { + link := c.pushUrl + "/v3/push" + buf, err := json.Marshal(push) + if err != nil { + return nil, err + } + resp, err := c.request("POST", link, bytes.NewReader(buf), false) + if err != nil { + return nil, err + } + return resp.Map() +} + +func (c *Client) GetCidPool(count int, cidType string) (map[string]interface{}, error) { + link := c.pushUrl + "/v3/push/cid?" + if count > 0 { + link += "count=" + strconv.Itoa(count) + } + if cidType != "" { + link += "type=" + cidType + } + resp, err := c.request("GET", link, nil, false) + if err != nil { + return nil, err + } + return resp.Map() +} + +func (c *Client) GroupPush(push *PushRequest) (map[string]interface{}, error) { + link := c.pushUrl + "/v3/grouppush" + buf, err := json.Marshal(push) + if err != nil { + return nil, err + } + resp, err := c.request("POST", link, bytes.NewReader(buf), true) + if err != nil { + return nil, err + } + return resp.Map() +} + +func (c *Client) Validate(req *PushRequest) (map[string]interface{}, error) { + link := c.pushUrl + "/v3/push/validate" + buf, err := json.Marshal(req) + if err != nil { + return nil, err + } + resp, err := c.request("POST", link, bytes.NewReader(buf), false) + if err != nil { + return nil, err + } + return resp.Map() +} diff --git a/jPush/sdk/client_report.go b/jPush/sdk/client_report.go new file mode 100644 index 0000000..e091d89 --- /dev/null +++ b/jPush/sdk/client_report.go @@ -0,0 +1,33 @@ +package jpush + +import ( + "bytes" + "encoding/json" + "errors" + "strings" +) + +func (c *Client) ReportReceived(msgIds []string) ([]interface{}, error) { + if len(msgIds) == 0 { + return nil, errors.New("msgIds不能为空") + } + link := c.reportUrl + "/v3/received?msg_ids=" + strings.Join(msgIds, ",") + resp, err := c.request("GET", link, nil, false) + if err != nil { + return nil, err + } + return resp.Array() +} + +func (c *Client) ReportStatusMessage(req *ReportStatusRequest) (map[string]interface{}, error) { + link := c.reportUrl + "/v3/status/message" + buf, err := json.Marshal(req) + if err != nil { + return nil, err + } + resp, err := c.request("POST", link, bytes.NewReader(buf), false) + if err != nil { + return nil, err + } + return resp.Map() +} diff --git a/jPush/sdk/client_schedule.go b/jPush/sdk/client_schedule.go new file mode 100644 index 0000000..eef70dc --- /dev/null +++ b/jPush/sdk/client_schedule.go @@ -0,0 +1,63 @@ +package jpush + +import ( + "bytes" + "encoding/json" + "strconv" +) + +func (c *Client) ScheduleCreateTask(req *ScheduleRequest) (map[string]interface{}, error) { + link := c.pushUrl + "/v3/schedules" + buf, err := json.Marshal(req) + if err != nil { + return nil, err + } + resp, err := c.request("POST", link, bytes.NewReader(buf), false) + if err != nil { + return nil, err + } + return resp.Map() +} + +func (c *Client) ScheduleGetList(page int) (map[string]interface{}, error) { + link := c.pushUrl + "/v3/schedules" + if page > 0 { + link += "?page=" + strconv.Itoa(page) + } + resp, err := c.request("GET", link, nil, false) + if err != nil { + return nil, err + } + return resp.Map() +} + +func (c *Client) ScheduleView(id string) (map[string]interface{}, error) { + link := c.pushUrl + "/v3/schedules/" + id + resp, err := c.request("GET", link, nil, false) + if err != nil { + return nil, err + } + return resp.Map() +} + +func (c *Client) ScheduleUpdate(id string, req *ScheduleRequest) (map[string]interface{}, error) { + link := c.pushUrl + "/v3/schedules/" + id + buf, err := json.Marshal(req) + if err != nil { + return nil, err + } + resp, err := c.request("PUT", link, bytes.NewReader(buf), false) + if err != nil { + return nil, err + } + return resp.Map() +} + +func (c *Client) ScheduleDelete(id string) ([]byte, error) { + link := c.pushUrl + "/v3/schedules/" + id + resp, err := c.request("DELETE", link, nil, false) + if err != nil { + return nil, err + } + return resp.Bytes(), nil +} diff --git a/jPush/sdk/device_request.go b/jPush/sdk/device_request.go new file mode 100644 index 0000000..a02d57e --- /dev/null +++ b/jPush/sdk/device_request.go @@ -0,0 +1,20 @@ +package jpush + +type DeviceSettingRequest struct { + Tags *DeviceSettingRequestTags `json:"tags"` + Alias string `json:"alias"` + Mobile string `json:"mobile"` +} +type DeviceSettingEmptyTagsRequest struct { + Tags string `json:"tags"` + Alias string `json:"alias"` + Mobile string `json:"mobile"` +} +type DeviceSettingRequestTags struct { + Add []string `json:"add,omitempty"` + Remove []string `json:"remove,omitempty"` +} +type DeviceBindTagsRequest struct { + Add []string `json:"add,omitempty"` + Remove []string `json:"remove,omitempty"` +} diff --git a/jPush/sdk/push_request.go b/jPush/sdk/push_request.go new file mode 100644 index 0000000..c6eacd6 --- /dev/null +++ b/jPush/sdk/push_request.go @@ -0,0 +1,114 @@ +package jpush + +import "encoding/json" + +type Platform string + +const ( + PlatformAndroid Platform = "android" + PlatformIOS Platform = "ios" + PlatformWinPhone Platform = "winphone" +) + +type PushAudience struct { + Tag []string `json:"tag,omitempty"` + TagAnd []string `json:"tag_and,omitempty"` + TagNot []string `json:"tag_not,omitempty"` + Alias []string `json:"alias,omitempty"` + RegistrationId []string `json:"registration_id,omitempty"` + Segment []string `json:"segment,omitempty"` + ABTest []string `json:"abtest,omitempty"` +} + +type PushNotification struct { + Alert string `json:"alert,omitempty"` + Android *NotificationAndroid `json:"android,omitempty"` + Hmos *NotificationHmos `json:"hmos,omitempty"` + IOS *NotificationIOS `json:"ios,omitempty"` + WinPhone *NotificationWinPhone `json:"winphone,omitempty"` +} + +type NotificationAndroid struct { + Alert string `json:"alert"` + Title string `json:"title,omitempty"` + BuilderId int `json:"builder_id,int,omitempty"` + Priority int `json:"priority,omitempty"` + Category string `json:"category,omitempty"` + Style int `json:"style,int,omitempty"` + AlertType int `json:"alert_type,int,omitempty"` + BigText string `json:"big_text,omitempty"` + Inbox map[string]interface{} `json:"inbox,omitempty"` + BigPicPath string `json:"big_pic_path,omitempty"` + Extras map[string]interface{} `json:"extras,omitempty"` +} +type NotificationHmos struct { + Alert string `json:"alert"` + Title string `json:"title"` +} +type NotificationIOS struct { + Alert interface{} `json:"alert"` + Sound string `json:"sound,omitempty"` + Badge int `json:"badge,int,omitempty"` + ContentAvailable bool `json:"content-available,omitempty"` + MutableContent bool `json:"mutable-content,omitempty"` + Category string `json:"category,omitempty"` + Extras map[string]interface{} `json:"extras,omitempty"` +} + +type NotificationWinPhone struct { + Alert string `json:"alert"` + Title string `json:"title,omitempty"` + OpenPage string `json:"_open_page,omitempty"` + Extras map[string]interface{} `json:"extras,omitempty"` +} + +type PushMessage struct { + MsgContent string `json:"msg_content"` + Title string `json:"title,omitempty"` + ContentType string `json:"content_type,omitempty"` + Extras map[string]interface{} `json:"extras,omitempty"` +} + +type SmsMessage struct { + Content string `json:"content"` + DelayTime int `json:"delay_time,int,omitempty"` +} + +type PushOptions struct { + SendNo int `json:"sendno,int,omitempty"` + TimeToLive int `json:"time_to_live,int,omitempty"` + OverrideMsgId int64 `json:"override_msg_id,int64,omitempty"` + ApnsProduction bool `json:"apns_production"` + ApnsCollapseId string `json:"apns_collapse_id,omitempty"` + BigPushDuration int `json:"big_push_duration,int,omitempty"` +} + +type PushRequest struct { + Cid string `json:"cid,omitempty"` + Platform Platform `json:"platform"` + Audience interface{} `json:"audience,omitempty"` + Notification *PushNotification `json:"notification,omitempty"` + Message *PushMessage `json:"message,omitempty"` + SmsMessage *SmsMessage `json:"sms_message,omitempty"` + Options *PushOptions `json:"options,omitempty"` +} + +type Response struct { + data []byte +} + +func (res *Response) Array() ([]interface{}, error) { + list := make([]interface{}, 0) + err := json.Unmarshal(res.data, &list) + return list, err +} + +func (res *Response) Map() (map[string]interface{}, error) { + result := make(map[string]interface{}) + err := json.Unmarshal(res.data, &result) + return result, err +} + +func (res *Response) Bytes() []byte { + return res.data +} diff --git a/jPush/sdk/report_request.go b/jPush/sdk/report_request.go new file mode 100644 index 0000000..fd42fa2 --- /dev/null +++ b/jPush/sdk/report_request.go @@ -0,0 +1,7 @@ +package jpush + +type ReportStatusRequest struct { + MsgId int `json:"msg_id,int"` + RegistrationIds []string `json:"registration_ids"` + Date string `json:"date,omitempty"` +} diff --git a/jPush/sdk/schedule_request.go b/jPush/sdk/schedule_request.go new file mode 100644 index 0000000..b51f153 --- /dev/null +++ b/jPush/sdk/schedule_request.go @@ -0,0 +1,33 @@ +package jpush + +const ( + ScheduleTimeUnitDay = "day" + ScheduleTimeUnitWeek = "week" + ScheduleTimeUnitMonth = "month" +) + +type ScheduleRequest struct { + Cid string `json:"cid,omitempty"` + Name string `json:"name"` + Enabled bool `json:"enabled"` + Push *PushRequest `json:"push"` + Trigger *ScheduleTrigger `json:"trigger"` +} + +type ScheduleTrigger struct { + Single *ScheduleTriggerSingle `json:"single,omitempty"` + Periodical *ScheduleTriggerPeriodical `json:"periodical,omitempty"` +} + +type ScheduleTriggerSingle struct { + Timer string `json:"time,omitempty"` +} + +type ScheduleTriggerPeriodical struct { + Start string `json:"start,omitempty"` + End string `json:"end,omitempty"` + Time string `json:"time,omitempty"` + TimeUnit string `json:"time_unit,omitempty"` + Frequency int `json:"frequency,int,omitempty"` + Point interface{} `json:"point,omitempty"` +}