Skip to content

Commit

Permalink
feat(xiaomi-push): 添加xiaomi-push
Browse files Browse the repository at this point in the history
  • Loading branch information
am6737 committed Mar 6, 2024
1 parent 2ab4d78 commit 8b7c70a
Show file tree
Hide file tree
Showing 26 changed files with 619 additions and 249 deletions.
17 changes: 13 additions & 4 deletions Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -14,15 +14,24 @@ lint: ## Lint Golang files
vet: ## Run go vet
@go vet ${PKG_LIST}

.PHONY: fmt
fmt: ## Run go fmt against code.
go fmt ./...

.PHONY: test
test: ## Run unittests
test: fmt vet ## Run unittests
@go test -short ${PKG_LIST}

install: ## Install dependencies and protoc
go install google.golang.org/protobuf/cmd/protoc-gen-go@latest
go install google.golang.org/grpc/cmd/protoc-gen-go-grpc@latest
go install github.com/favadi/protoc-go-inject-tag@latest

.PHONY: gen
gen: ## generate protobuf file
@protoc -I=. --go_out=. --go_opt=module=${PKG} --go-grpc_out=. --go-grpc_opt=module=${PKG},require_unimplemented_servers=true api/grpc/v1/*.proto
@go fmt ./...
@protoc-go-inject-tag -input=api/grpc/v1/*.pb.go
#protoc -I=. --go_out=. --go_opt=module=${PKG} --go-grpc_out=. --go-grpc_opt=module=${PKG},require_unimplemented_servers=true api/grpc/v1/*.proto
protoc -I api/grpc/v1 api/grpc/v1/push.proto --go_out=api/grpc/v1 --go-grpc_out=require_unimplemented_servers=false:api/grpc/v1
protoc-go-inject-tag -input=api/grpc/v1/*.pb.go

.PHONY: docker-build
# If you wish built the manager image targeting other platforms you can use the --platform flag.
Expand Down
338 changes: 210 additions & 128 deletions api/grpc/v1/push.pb.go

Large diffs are not rendered by default.

14 changes: 13 additions & 1 deletion api/grpc/v1/push.proto
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,9 @@ syntax = "proto3";
import "google/protobuf/struct.proto";

package v1;
option go_package = "github.com/cossim/hipush/api/grpc/v1";
//option go_package = "github.com/cossim/hipush/api/grpc/v1";
option go_package = "./;v1";


message Alert {
string title = 1;
Expand Down Expand Up @@ -43,13 +45,23 @@ message PushRequest {
bool mutableContent = 13;
// default is production
bool development = 20;

PushOption Option = 21;
}

message PushResponse {
bool success = 1;
int32 counts = 2;
}

message PushOption {
// DryRun 只进行数据校验不实际推送,数据校验成功即为成功
bool DryRun = 1;

// Retry 重试次数
int32 Retry = 2;
}

service PushService {
rpc Push (PushRequest) returns (PushResponse) {}
}
10 changes: 4 additions & 6 deletions api/grpc/v1/push_grpc.pb.go

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

50 changes: 44 additions & 6 deletions api/http/v1/dto/dto.go
Original file line number Diff line number Diff line change
Expand Up @@ -5,12 +5,6 @@ import (
"time"
)

// ClickAction 点击行为
type ClickAction struct {
Url string
Action Action // 点击行为类型
}

// Action 枚举表示点击行为类型
type Action int

Expand Down Expand Up @@ -104,3 +98,47 @@ type OppoPushRequestData struct {
// 附加的自定义参数
Data map[string]string
}

type XiaomiPushRequestData struct {
// Foreground 是否前台显示通知
Foreground bool `json:"foreground,omitempty"`
Title string `json:"title,omitempty" binding:"required"`
Subtitle string `json:"subtitle,omitempty"`
Content string `json:"content,omitempty" binding:"required"`

// Icon 消息图标,用于在通知栏上显示的图标
Icon string `json:"icon,omitempty"`

// TTL 如果用户离线,设置消息在服务器保存的时间,单位:ms,服务器默认最长保留两周。
TTL time.Duration `json:"ttl,omitempty"`

// IsScheduled false为立即推送 true为定时推送
// 消息会在ScheduledStart-ScheduledEnd的时间段内随机展示
IsScheduled bool `json:"is_scheduled,omitempty"`
// ScheduledTime 定时推送的开始时间,指定消息推送的开始时间
// 用自1970年1月1日以来00:00:00.0 UTC时间表示(以毫秒为单位的时间),仅支持七天内的定时消息。
ScheduledTime time.Duration `json:"scheduled_time,omitempty"`

NotifyType int `json:"notify_type,omitempty" json:"notify_type,omitempty"`

// ClickAction 点击动作
ClickAction ClickAction `json:"click_action"`

// 附加的自定义参数
Data map[string]string `json:"data,omitempty"`
}

type ClickAction struct {
// Action 点击行为
// 不同的厂商有不同的定义
Action int `json:"action,omitempty"`

// Activity 打开应用内页(activity 的 intent action)
Activity string `json:"activity,omitempty"`

// Url 打开网页的地址
Url string `json:"url,omitempty"`

// Parameters url跳转后传的参数拼接在url后面
Parameters string `json:"parameters,omitempty"`
}
8 changes: 8 additions & 0 deletions cmd/main.go
Original file line number Diff line number Diff line change
Expand Up @@ -81,6 +81,14 @@ func main() {
return adapter.NewPushServiceAdapter(svc)
})

pushServiceFactory.Register(consts.PlatformXiaomi.String(), func() push.PushService {
svc, err := push.NewXiaomiService(cfg)
if err != nil {
panic(err)
}
return adapter.NewPushServiceAdapter(svc)
})

ctx, cancel := context.WithCancel(context.Background())
defer cancel()

Expand Down
9 changes: 9 additions & 0 deletions config/config.go
Original file line number Diff line number Diff line change
Expand Up @@ -51,6 +51,14 @@ type AndroidAppConfig struct {
MaxRetry int `yaml:"max_retry"`
}

type XiaomiAppConfig struct {
Enabled bool `yaml:"enabled"`
AppID string `yaml:"app_id"`
Package []string `json:"package"`
AppSecret string `yaml:"app_secret"`
MaxRetry int `yaml:"max_retry"`
}

type Config struct {
HTTP HTTPConfig `yaml:"http"`
GRPC GRPCConfig `yaml:"grpc"`
Expand All @@ -59,6 +67,7 @@ type Config struct {
Android []AndroidAppConfig `yaml:" android"`
Vivo []VivoAppConfig `yaml:"vivo"`
Oppo []OppoAppConfig `yaml:"oppo"`
Xiaomi []XiaomiAppConfig `yaml:"xiaomi"`
}

type HTTPConfig struct {
Expand Down
8 changes: 8 additions & 0 deletions config/example.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -75,4 +75,12 @@ oppo:
app_key: ""
# 这里的secret是oppo的masterSecret,
app_secret: ""
max_retry: 5

xiaomi:
- enabled: true
app_id: ""
package:
- xxx.xx.xx
app_secret: ""
max_retry: 5
3 changes: 2 additions & 1 deletion go.mod
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ module github.com/cossim/hipush
go 1.20

require (
github.com/316014408/oppo-push v0.0.0-20190427030828-462d62e6b171
github.com/appleboy/go-fcm v0.1.6
github.com/cossim/go-hms-push v0.0.0-20240301034220-38310a1d80e5
github.com/cossim/vivo-push v0.0.0-20240301025332-148acd987861
Expand All @@ -13,14 +14,14 @@ require (
github.com/google/uuid v1.6.0
github.com/mitchellh/mapstructure v1.5.0
github.com/sideshow/apns2 v0.23.0
github.com/yilee/xiaomi-push v0.0.0-20170213073944-562fbb07388e
go.uber.org/zap v1.27.0
google.golang.org/grpc v1.62.0
google.golang.org/protobuf v1.32.0
gopkg.in/yaml.v3 v3.0.1
)

require (
github.com/316014408/oppo-push v0.0.0-20190427030828-462d62e6b171 // indirect
github.com/bitly/go-simplejson v0.5.1 // indirect
github.com/bytedance/sonic v1.10.0-rc // indirect
github.com/chenzhuoyu/base64x v0.0.0-20230717121745-296ad89f973d // indirect
Expand Down
2 changes: 2 additions & 0 deletions go.sum
Original file line number Diff line number Diff line change
Expand Up @@ -100,6 +100,8 @@ github.com/twitchyliquid64/golang-asm v0.15.1 h1:SU5vSMR7hnwNxj24w34ZyCi/FmDZTkS
github.com/twitchyliquid64/golang-asm v0.15.1/go.mod h1:a1lVb/DtPvCB8fslRZhAngC2+aY1QWCk3Cedj/Gdt08=
github.com/ugorji/go/codec v1.2.11 h1:BMaWp1Bb6fHwEtbplGBGJ498wD+LKlNSl25MjdZY4dU=
github.com/ugorji/go/codec v1.2.11/go.mod h1:UNopzCgEMSXjBc6AOMqYvWC1ktqTAfzJZUZgYf6w6lg=
github.com/yilee/xiaomi-push v0.0.0-20170213073944-562fbb07388e h1:9jcm/cOPXIx7MMS2ooZroJK977BHj0i7CxCFX9mPZ9k=
github.com/yilee/xiaomi-push v0.0.0-20170213073944-562fbb07388e/go.mod h1:fAhsEz37mtLkTw+JbnsLKmGdr/+P0f1Ru0qvH7Saz1M=
go.uber.org/goleak v1.3.0 h1:2K3zAYmnTNqV73imy9J1T3WC+gmCePx2hEGkimedGto=
go.uber.org/multierr v1.10.0 h1:S0h4aNzvfcFsC3dRF1jLoaov7oRaKqRGC/pUEJ2yvPQ=
go.uber.org/multierr v1.10.0/go.mod h1:20+QtiLqy0Nd6FdQB9TLXag12DsQkrbs3htMFfDN80Y=
Expand Down
4 changes: 2 additions & 2 deletions internal/adapter/adapter.go
Original file line number Diff line number Diff line change
Expand Up @@ -13,8 +13,8 @@ func NewPushServiceAdapter(pushService push.PushService) *PushServiceAdapter {
return &PushServiceAdapter{pushService: pushService}
}

func (p *PushServiceAdapter) Send(ctx context.Context, req interface{}) error {
return p.pushService.Send(ctx, req)
func (p *PushServiceAdapter) Send(ctx context.Context, req interface{}, opt push.SendOption) error {
return p.pushService.Send(ctx, req, opt)
}

func (p *PushServiceAdapter) MulticastSend(ctx context.Context, req interface{}) error {
Expand Down
32 changes: 32 additions & 0 deletions internal/notify/xiaomi_notify.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
package notify

import "time"

// XiaomiPushNotification
// https://dev.mi.com/console/doc/detail?pId=2776#_0
type XiaomiPushNotification struct {
AppID string `json:"app_id,omitempty"`

// Tokens 对应regId列表
Tokens []string `json:"tokens" binding:"required"`

Title string `json:"title,omitempty"`
Content string `json:"message,omitempty"`

// NotifyType
// DEFAULT_ALL = -1
// DEFAULT_SOUND = 1; 使用默认提示音提示
// DEFAULT_VIBRATE = 2; 使用默认振动提示
// DEFAULT_LIGHTS = 4; 使用默认呼吸灯提示。
NotifyType int `json:"notify_type,omitempty"`

// TTL 如果用户离线,设置消息在服务器保存的时间,单位:ms。服务器默认最长保留两周。
TTL int64 `json:"time_to_live,omitempty"`

IsShowNotify bool `json:"is_show_notify,omitempty"`

IsScheduled bool
// ScheduledTime 定时推送的开始时间,指定消息推送的开始时间
// 用自1970年1月1日以来00:00:00.0 UTC时间表示(以毫秒为单位的时间),仅支持七天内的定时消息。
ScheduledTime time.Duration
}
2 changes: 1 addition & 1 deletion internal/push/apns_push.go
Original file line number Diff line number Diff line change
Expand Up @@ -133,7 +133,7 @@ var DialTLS = func(cfg *tls.Config) func(network, addr string) (net.Conn, error)
}
}

func (a *APNsService) Send(ctx context.Context, request interface{}) error {
func (a *APNsService) Send(ctx context.Context, request interface{}, opt SendOption) error {
req, ok := request.(*notify.ApnsPushNotification)
if !ok {
return errors.New("invalid request")
Expand Down
4 changes: 2 additions & 2 deletions internal/push/fcm_push.go
Original file line number Diff line number Diff line change
Expand Up @@ -34,7 +34,7 @@ func NewFCMService(cfg *config.Config) (*FCMService, error) {
return s, nil
}

func (f *FCMService) Send(ctx context.Context, request interface{}) error {
func (f *FCMService) Send(ctx context.Context, request interface{}, opt SendOption) error {
req, ok := request.(*notify.FCMPushNotification)
if !ok {
return errors.New("invalid request")
Expand Down Expand Up @@ -90,7 +90,7 @@ Retry:
if to == "" {
to = req.Condition
}
log.Printf("Topic Message: %s", to)
log.Printf("Topic Content: %s", to)
}

// Device Group HTTP Response
Expand Down
4 changes: 2 additions & 2 deletions internal/push/huawei_push.go
Original file line number Diff line number Diff line change
Expand Up @@ -59,7 +59,7 @@ func NewHMSService(cfg *config.Config) (*HMSService, error) {
return s, nil
}

func (h *HMSService) Send(ctx context.Context, request interface{}) error {
func (h *HMSService) Send(ctx context.Context, request interface{}, opt SendOption) error {
req, ok := request.(*notify.HMSPushNotification)
if !ok {
return errors.New("invalid request parameter")
Expand Down Expand Up @@ -195,7 +195,7 @@ func (h *HMSService) buildNotification(req *notify.HMSPushNotification) (*model.
msgRequest.Message.Data = req.Data
}

// Notification Message
// Notification Content
if req.MessageRequest.Message.Android.Notification != nil {
msgRequest.Message.Android.Notification = req.MessageRequest.Message.Android.Notification

Expand Down
14 changes: 9 additions & 5 deletions internal/push/oppo_push.go
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,10 @@ import (
"sync"
)

var (
MaxConcurrentOppoPushes = make(chan struct{}, 100)
)

// OppoService 实现vivo推送,必须实现PushService接口
type OppoService struct {
clients map[string]*op.OppoPush
Expand All @@ -33,14 +37,14 @@ func NewOppoService(cfg *config.Config) (*OppoService, error) {
return s, nil
}

func (o *OppoService) Send(ctx context.Context, request interface{}) error {
func (o *OppoService) Send(ctx context.Context, request interface{}, opt SendOption) error {
req, ok := request.(*notify.OppoPushNotification)
if !ok {
return errors.New("invalid request")
}

var (
retry = req.Option.Retry
retry = opt.Retry
maxRetry = retry
retryCount = 0
)
Expand All @@ -64,7 +68,7 @@ func (o *OppoService) Send(ctx context.Context, request interface{}) error {
return err
}

if req.Option.DryRun {
if opt.DryRun {
return nil
}

Expand Down Expand Up @@ -106,12 +110,12 @@ func (o *OppoService) send(appID string, tokens []string, message *op.Message) (

for _, token := range tokens {
// occupy push slot
MaxConcurrentIOSPushes <- struct{}{}
MaxConcurrentOppoPushes <- struct{}{}
wg.Add(1)
go func(notification *op.Message, token string) {
defer func() {
// free push slot
<-MaxConcurrentIOSPushes
<-MaxConcurrentOppoPushes
wg.Done()
}()

Expand Down
Loading

0 comments on commit 8b7c70a

Please sign in to comment.