diff --git a/Makefile b/Makefile index cf5cd39..2d52cfc 100644 --- a/Makefile +++ b/Makefile @@ -30,9 +30,10 @@ install: ## Install dependencies and protoc .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 - 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 + #protoc -I=. --go_out=. --go_opt=module=${PKG} --go-grpc_out=. --go-grpc_opt=module=${PKG},require_unimplemented_servers=true api/pb/v1/*.proto + #protoc -I api/pb/v1 api/pb/v1/*.proto --gofast_out=api/pb/v1 --go-grpc_out=require_unimplemented_servers=false:api/pb/v1 + protoc -I api/pb/v1 api/pb/v1/*.proto --go_out=api/pb/v1 --go-grpc_out=require_unimplemented_servers=false:api/pb/v1 + protoc-go-inject-tag -input=api/pb/v1/*.pb.go .PHONY: docker-build # If you wish built the manager image targeting other platforms you can use the --platform flag. diff --git a/api/grpc/v1/push.pb.go b/api/grpc/v1/push.pb.go deleted file mode 100644 index 043dbbc..0000000 --- a/api/grpc/v1/push.pb.go +++ /dev/null @@ -1,700 +0,0 @@ -// Code generated by protoc-gen-go. DO NOT EDIT. -// versions: -// protoc-gen-go v1.33.0 -// protoc v4.25.1 -// source: push.proto - -package v1 - -import ( - protoreflect "google.golang.org/protobuf/reflect/protoreflect" - protoimpl "google.golang.org/protobuf/runtime/protoimpl" - structpb "google.golang.org/protobuf/types/known/structpb" - reflect "reflect" - sync "sync" -) - -const ( - // Verify that this generated code is sufficiently up-to-date. - _ = protoimpl.EnforceVersion(20 - protoimpl.MinVersion) - // Verify that runtime/protoimpl is sufficiently up-to-date. - _ = protoimpl.EnforceVersion(protoimpl.MaxVersion - 20) -) - -type PushRequest_Priority int32 - -const ( - PushRequest_NORMAL PushRequest_Priority = 0 - PushRequest_HIGH PushRequest_Priority = 1 -) - -// Enum value maps for PushRequest_Priority. -var ( - PushRequest_Priority_name = map[int32]string{ - 0: "NORMAL", - 1: "HIGH", - } - PushRequest_Priority_value = map[string]int32{ - "NORMAL": 0, - "HIGH": 1, - } -) - -func (x PushRequest_Priority) Enum() *PushRequest_Priority { - p := new(PushRequest_Priority) - *p = x - return p -} - -func (x PushRequest_Priority) String() string { - return protoimpl.X.EnumStringOf(x.Descriptor(), protoreflect.EnumNumber(x)) -} - -func (PushRequest_Priority) Descriptor() protoreflect.EnumDescriptor { - return file_push_proto_enumTypes[0].Descriptor() -} - -func (PushRequest_Priority) Type() protoreflect.EnumType { - return &file_push_proto_enumTypes[0] -} - -func (x PushRequest_Priority) Number() protoreflect.EnumNumber { - return protoreflect.EnumNumber(x) -} - -// Deprecated: Use PushRequest_Priority.Descriptor instead. -func (PushRequest_Priority) EnumDescriptor() ([]byte, []int) { - return file_push_proto_rawDescGZIP(), []int{1, 0} -} - -type Alert struct { - state protoimpl.MessageState - sizeCache protoimpl.SizeCache - unknownFields protoimpl.UnknownFields - - Title string `protobuf:"bytes,1,opt,name=title,proto3" json:"title,omitempty"` - Body string `protobuf:"bytes,2,opt,name=body,proto3" json:"body,omitempty"` - Subtitle string `protobuf:"bytes,3,opt,name=subtitle,proto3" json:"subtitle,omitempty"` - Action string `protobuf:"bytes,4,opt,name=action,proto3" json:"action,omitempty"` - ActionLocKey string `protobuf:"bytes,5,opt,name=actionLocKey,proto3" json:"actionLocKey,omitempty"` - LaunchImage string `protobuf:"bytes,6,opt,name=launchImage,proto3" json:"launchImage,omitempty"` - LocKey string `protobuf:"bytes,7,opt,name=locKey,proto3" json:"locKey,omitempty"` - TitleLocKey string `protobuf:"bytes,8,opt,name=titleLocKey,proto3" json:"titleLocKey,omitempty"` - LocArgs []string `protobuf:"bytes,9,rep,name=locArgs,proto3" json:"locArgs,omitempty"` - TitleLocArgs []string `protobuf:"bytes,10,rep,name=titleLocArgs,proto3" json:"titleLocArgs,omitempty"` -} - -func (x *Alert) Reset() { - *x = Alert{} - if protoimpl.UnsafeEnabled { - mi := &file_push_proto_msgTypes[0] - ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) - ms.StoreMessageInfo(mi) - } -} - -func (x *Alert) String() string { - return protoimpl.X.MessageStringOf(x) -} - -func (*Alert) ProtoMessage() {} - -func (x *Alert) ProtoReflect() protoreflect.Message { - mi := &file_push_proto_msgTypes[0] - if protoimpl.UnsafeEnabled && x != nil { - ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) - if ms.LoadMessageInfo() == nil { - ms.StoreMessageInfo(mi) - } - return ms - } - return mi.MessageOf(x) -} - -// Deprecated: Use Alert.ProtoReflect.Descriptor instead. -func (*Alert) Descriptor() ([]byte, []int) { - return file_push_proto_rawDescGZIP(), []int{0} -} - -func (x *Alert) GetTitle() string { - if x != nil { - return x.Title - } - return "" -} - -func (x *Alert) GetBody() string { - if x != nil { - return x.Body - } - return "" -} - -func (x *Alert) GetSubtitle() string { - if x != nil { - return x.Subtitle - } - return "" -} - -func (x *Alert) GetAction() string { - if x != nil { - return x.Action - } - return "" -} - -func (x *Alert) GetActionLocKey() string { - if x != nil { - return x.ActionLocKey - } - return "" -} - -func (x *Alert) GetLaunchImage() string { - if x != nil { - return x.LaunchImage - } - return "" -} - -func (x *Alert) GetLocKey() string { - if x != nil { - return x.LocKey - } - return "" -} - -func (x *Alert) GetTitleLocKey() string { - if x != nil { - return x.TitleLocKey - } - return "" -} - -func (x *Alert) GetLocArgs() []string { - if x != nil { - return x.LocArgs - } - return nil -} - -func (x *Alert) GetTitleLocArgs() []string { - if x != nil { - return x.TitleLocArgs - } - return nil -} - -type PushRequest struct { - state protoimpl.MessageState - sizeCache protoimpl.SizeCache - unknownFields protoimpl.UnknownFields - - Platform string `protobuf:"bytes,1,opt,name=platform,proto3" json:"platform,omitempty"` - Tokens []string `protobuf:"bytes,2,rep,name=tokens,proto3" json:"tokens,omitempty"` - Title string `protobuf:"bytes,4,opt,name=title,proto3" json:"title,omitempty"` - Message string `protobuf:"bytes,3,opt,name=message,proto3" json:"message,omitempty"` - Topic string `protobuf:"bytes,5,opt,name=topic,proto3" json:"topic,omitempty"` - Key string `protobuf:"bytes,6,opt,name=key,proto3" json:"key,omitempty"` - Category string `protobuf:"bytes,8,opt,name=category,proto3" json:"category,omitempty"` - Sound string `protobuf:"bytes,10,opt,name=sound,proto3" json:"sound,omitempty"` - Alert *Alert `protobuf:"bytes,9,opt,name=alert,proto3" json:"alert,omitempty"` - Badge int32 `protobuf:"varint,7,opt,name=badge,proto3" json:"badge,omitempty"` - ThreadID string `protobuf:"bytes,12,opt,name=threadID,proto3" json:"threadID,omitempty"` - Data *structpb.Struct `protobuf:"bytes,14,opt,name=data,proto3" json:"data,omitempty"` - Image string `protobuf:"bytes,15,opt,name=image,proto3" json:"image,omitempty"` - ID string `protobuf:"bytes,17,opt,name=ID,proto3" json:"ID,omitempty"` - PushType string `protobuf:"bytes,18,opt,name=pushType,proto3" json:"pushType,omitempty"` - AppID string `protobuf:"bytes,19,opt,name=appID,proto3" json:"appID,omitempty"` - Priority PushRequest_Priority `protobuf:"varint,16,opt,name=priority,proto3,enum=v1.PushRequest_Priority" json:"priority,omitempty"` - ContentAvailable bool `protobuf:"varint,11,opt,name=contentAvailable,proto3" json:"contentAvailable,omitempty"` - MutableContent bool `protobuf:"varint,13,opt,name=mutableContent,proto3" json:"mutableContent,omitempty"` - // default is production - Development bool `protobuf:"varint,20,opt,name=development,proto3" json:"development,omitempty"` - Option *PushOption `protobuf:"bytes,21,opt,name=Option,proto3" json:"Option,omitempty"` -} - -func (x *PushRequest) Reset() { - *x = PushRequest{} - if protoimpl.UnsafeEnabled { - mi := &file_push_proto_msgTypes[1] - ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) - ms.StoreMessageInfo(mi) - } -} - -func (x *PushRequest) String() string { - return protoimpl.X.MessageStringOf(x) -} - -func (*PushRequest) ProtoMessage() {} - -func (x *PushRequest) ProtoReflect() protoreflect.Message { - mi := &file_push_proto_msgTypes[1] - if protoimpl.UnsafeEnabled && x != nil { - ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) - if ms.LoadMessageInfo() == nil { - ms.StoreMessageInfo(mi) - } - return ms - } - return mi.MessageOf(x) -} - -// Deprecated: Use PushRequest.ProtoReflect.Descriptor instead. -func (*PushRequest) Descriptor() ([]byte, []int) { - return file_push_proto_rawDescGZIP(), []int{1} -} - -func (x *PushRequest) GetPlatform() string { - if x != nil { - return x.Platform - } - return "" -} - -func (x *PushRequest) GetTokens() []string { - if x != nil { - return x.Tokens - } - return nil -} - -func (x *PushRequest) GetTitle() string { - if x != nil { - return x.Title - } - return "" -} - -func (x *PushRequest) GetMessage() string { - if x != nil { - return x.Message - } - return "" -} - -func (x *PushRequest) GetTopic() string { - if x != nil { - return x.Topic - } - return "" -} - -func (x *PushRequest) GetKey() string { - if x != nil { - return x.Key - } - return "" -} - -func (x *PushRequest) GetCategory() string { - if x != nil { - return x.Category - } - return "" -} - -func (x *PushRequest) GetSound() string { - if x != nil { - return x.Sound - } - return "" -} - -func (x *PushRequest) GetAlert() *Alert { - if x != nil { - return x.Alert - } - return nil -} - -func (x *PushRequest) GetBadge() int32 { - if x != nil { - return x.Badge - } - return 0 -} - -func (x *PushRequest) GetThreadID() string { - if x != nil { - return x.ThreadID - } - return "" -} - -func (x *PushRequest) GetData() *structpb.Struct { - if x != nil { - return x.Data - } - return nil -} - -func (x *PushRequest) GetImage() string { - if x != nil { - return x.Image - } - return "" -} - -func (x *PushRequest) GetID() string { - if x != nil { - return x.ID - } - return "" -} - -func (x *PushRequest) GetPushType() string { - if x != nil { - return x.PushType - } - return "" -} - -func (x *PushRequest) GetAppID() string { - if x != nil { - return x.AppID - } - return "" -} - -func (x *PushRequest) GetPriority() PushRequest_Priority { - if x != nil { - return x.Priority - } - return PushRequest_NORMAL -} - -func (x *PushRequest) GetContentAvailable() bool { - if x != nil { - return x.ContentAvailable - } - return false -} - -func (x *PushRequest) GetMutableContent() bool { - if x != nil { - return x.MutableContent - } - return false -} - -func (x *PushRequest) GetDevelopment() bool { - if x != nil { - return x.Development - } - return false -} - -func (x *PushRequest) GetOption() *PushOption { - if x != nil { - return x.Option - } - return nil -} - -type PushResponse struct { - state protoimpl.MessageState - sizeCache protoimpl.SizeCache - unknownFields protoimpl.UnknownFields - - Success bool `protobuf:"varint,1,opt,name=success,proto3" json:"success,omitempty"` - Counts int32 `protobuf:"varint,2,opt,name=counts,proto3" json:"counts,omitempty"` -} - -func (x *PushResponse) Reset() { - *x = PushResponse{} - if protoimpl.UnsafeEnabled { - mi := &file_push_proto_msgTypes[2] - ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) - ms.StoreMessageInfo(mi) - } -} - -func (x *PushResponse) String() string { - return protoimpl.X.MessageStringOf(x) -} - -func (*PushResponse) ProtoMessage() {} - -func (x *PushResponse) ProtoReflect() protoreflect.Message { - mi := &file_push_proto_msgTypes[2] - if protoimpl.UnsafeEnabled && x != nil { - ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) - if ms.LoadMessageInfo() == nil { - ms.StoreMessageInfo(mi) - } - return ms - } - return mi.MessageOf(x) -} - -// Deprecated: Use PushResponse.ProtoReflect.Descriptor instead. -func (*PushResponse) Descriptor() ([]byte, []int) { - return file_push_proto_rawDescGZIP(), []int{2} -} - -func (x *PushResponse) GetSuccess() bool { - if x != nil { - return x.Success - } - return false -} - -func (x *PushResponse) GetCounts() int32 { - if x != nil { - return x.Counts - } - return 0 -} - -type PushOption struct { - state protoimpl.MessageState - sizeCache protoimpl.SizeCache - unknownFields protoimpl.UnknownFields - - // DryRun 只进行数据校验不实际推送,数据校验成功即为成功 - DryRun bool `protobuf:"varint,1,opt,name=DryRun,proto3" json:"DryRun,omitempty"` - // Retry 重试次数 - Retry int32 `protobuf:"varint,2,opt,name=Retry,proto3" json:"Retry,omitempty"` -} - -func (x *PushOption) Reset() { - *x = PushOption{} - if protoimpl.UnsafeEnabled { - mi := &file_push_proto_msgTypes[3] - ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) - ms.StoreMessageInfo(mi) - } -} - -func (x *PushOption) String() string { - return protoimpl.X.MessageStringOf(x) -} - -func (*PushOption) ProtoMessage() {} - -func (x *PushOption) ProtoReflect() protoreflect.Message { - mi := &file_push_proto_msgTypes[3] - if protoimpl.UnsafeEnabled && x != nil { - ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) - if ms.LoadMessageInfo() == nil { - ms.StoreMessageInfo(mi) - } - return ms - } - return mi.MessageOf(x) -} - -// Deprecated: Use PushOption.ProtoReflect.Descriptor instead. -func (*PushOption) Descriptor() ([]byte, []int) { - return file_push_proto_rawDescGZIP(), []int{3} -} - -func (x *PushOption) GetDryRun() bool { - if x != nil { - return x.DryRun - } - return false -} - -func (x *PushOption) GetRetry() int32 { - if x != nil { - return x.Retry - } - return 0 -} - -var File_push_proto protoreflect.FileDescriptor - -var file_push_proto_rawDesc = []byte{ - 0x0a, 0x0a, 0x70, 0x75, 0x73, 0x68, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x12, 0x02, 0x76, 0x31, - 0x1a, 0x1c, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2f, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, - 0x66, 0x2f, 0x73, 0x74, 0x72, 0x75, 0x63, 0x74, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x22, 0xa3, - 0x02, 0x0a, 0x05, 0x41, 0x6c, 0x65, 0x72, 0x74, 0x12, 0x14, 0x0a, 0x05, 0x74, 0x69, 0x74, 0x6c, - 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x05, 0x74, 0x69, 0x74, 0x6c, 0x65, 0x12, 0x12, - 0x0a, 0x04, 0x62, 0x6f, 0x64, 0x79, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x04, 0x62, 0x6f, - 0x64, 0x79, 0x12, 0x1a, 0x0a, 0x08, 0x73, 0x75, 0x62, 0x74, 0x69, 0x74, 0x6c, 0x65, 0x18, 0x03, - 0x20, 0x01, 0x28, 0x09, 0x52, 0x08, 0x73, 0x75, 0x62, 0x74, 0x69, 0x74, 0x6c, 0x65, 0x12, 0x16, - 0x0a, 0x06, 0x61, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x18, 0x04, 0x20, 0x01, 0x28, 0x09, 0x52, 0x06, - 0x61, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x12, 0x22, 0x0a, 0x0c, 0x61, 0x63, 0x74, 0x69, 0x6f, 0x6e, - 0x4c, 0x6f, 0x63, 0x4b, 0x65, 0x79, 0x18, 0x05, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0c, 0x61, 0x63, - 0x74, 0x69, 0x6f, 0x6e, 0x4c, 0x6f, 0x63, 0x4b, 0x65, 0x79, 0x12, 0x20, 0x0a, 0x0b, 0x6c, 0x61, - 0x75, 0x6e, 0x63, 0x68, 0x49, 0x6d, 0x61, 0x67, 0x65, 0x18, 0x06, 0x20, 0x01, 0x28, 0x09, 0x52, - 0x0b, 0x6c, 0x61, 0x75, 0x6e, 0x63, 0x68, 0x49, 0x6d, 0x61, 0x67, 0x65, 0x12, 0x16, 0x0a, 0x06, - 0x6c, 0x6f, 0x63, 0x4b, 0x65, 0x79, 0x18, 0x07, 0x20, 0x01, 0x28, 0x09, 0x52, 0x06, 0x6c, 0x6f, - 0x63, 0x4b, 0x65, 0x79, 0x12, 0x20, 0x0a, 0x0b, 0x74, 0x69, 0x74, 0x6c, 0x65, 0x4c, 0x6f, 0x63, - 0x4b, 0x65, 0x79, 0x18, 0x08, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0b, 0x74, 0x69, 0x74, 0x6c, 0x65, - 0x4c, 0x6f, 0x63, 0x4b, 0x65, 0x79, 0x12, 0x18, 0x0a, 0x07, 0x6c, 0x6f, 0x63, 0x41, 0x72, 0x67, - 0x73, 0x18, 0x09, 0x20, 0x03, 0x28, 0x09, 0x52, 0x07, 0x6c, 0x6f, 0x63, 0x41, 0x72, 0x67, 0x73, - 0x12, 0x22, 0x0a, 0x0c, 0x74, 0x69, 0x74, 0x6c, 0x65, 0x4c, 0x6f, 0x63, 0x41, 0x72, 0x67, 0x73, - 0x18, 0x0a, 0x20, 0x03, 0x28, 0x09, 0x52, 0x0c, 0x74, 0x69, 0x74, 0x6c, 0x65, 0x4c, 0x6f, 0x63, - 0x41, 0x72, 0x67, 0x73, 0x22, 0x99, 0x05, 0x0a, 0x0b, 0x50, 0x75, 0x73, 0x68, 0x52, 0x65, 0x71, - 0x75, 0x65, 0x73, 0x74, 0x12, 0x1a, 0x0a, 0x08, 0x70, 0x6c, 0x61, 0x74, 0x66, 0x6f, 0x72, 0x6d, - 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x08, 0x70, 0x6c, 0x61, 0x74, 0x66, 0x6f, 0x72, 0x6d, - 0x12, 0x16, 0x0a, 0x06, 0x74, 0x6f, 0x6b, 0x65, 0x6e, 0x73, 0x18, 0x02, 0x20, 0x03, 0x28, 0x09, - 0x52, 0x06, 0x74, 0x6f, 0x6b, 0x65, 0x6e, 0x73, 0x12, 0x14, 0x0a, 0x05, 0x74, 0x69, 0x74, 0x6c, - 0x65, 0x18, 0x04, 0x20, 0x01, 0x28, 0x09, 0x52, 0x05, 0x74, 0x69, 0x74, 0x6c, 0x65, 0x12, 0x18, - 0x0a, 0x07, 0x6d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x18, 0x03, 0x20, 0x01, 0x28, 0x09, 0x52, - 0x07, 0x6d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x12, 0x14, 0x0a, 0x05, 0x74, 0x6f, 0x70, 0x69, - 0x63, 0x18, 0x05, 0x20, 0x01, 0x28, 0x09, 0x52, 0x05, 0x74, 0x6f, 0x70, 0x69, 0x63, 0x12, 0x10, - 0x0a, 0x03, 0x6b, 0x65, 0x79, 0x18, 0x06, 0x20, 0x01, 0x28, 0x09, 0x52, 0x03, 0x6b, 0x65, 0x79, - 0x12, 0x1a, 0x0a, 0x08, 0x63, 0x61, 0x74, 0x65, 0x67, 0x6f, 0x72, 0x79, 0x18, 0x08, 0x20, 0x01, - 0x28, 0x09, 0x52, 0x08, 0x63, 0x61, 0x74, 0x65, 0x67, 0x6f, 0x72, 0x79, 0x12, 0x14, 0x0a, 0x05, - 0x73, 0x6f, 0x75, 0x6e, 0x64, 0x18, 0x0a, 0x20, 0x01, 0x28, 0x09, 0x52, 0x05, 0x73, 0x6f, 0x75, - 0x6e, 0x64, 0x12, 0x1f, 0x0a, 0x05, 0x61, 0x6c, 0x65, 0x72, 0x74, 0x18, 0x09, 0x20, 0x01, 0x28, - 0x0b, 0x32, 0x09, 0x2e, 0x76, 0x31, 0x2e, 0x41, 0x6c, 0x65, 0x72, 0x74, 0x52, 0x05, 0x61, 0x6c, - 0x65, 0x72, 0x74, 0x12, 0x14, 0x0a, 0x05, 0x62, 0x61, 0x64, 0x67, 0x65, 0x18, 0x07, 0x20, 0x01, - 0x28, 0x05, 0x52, 0x05, 0x62, 0x61, 0x64, 0x67, 0x65, 0x12, 0x1a, 0x0a, 0x08, 0x74, 0x68, 0x72, - 0x65, 0x61, 0x64, 0x49, 0x44, 0x18, 0x0c, 0x20, 0x01, 0x28, 0x09, 0x52, 0x08, 0x74, 0x68, 0x72, - 0x65, 0x61, 0x64, 0x49, 0x44, 0x12, 0x2b, 0x0a, 0x04, 0x64, 0x61, 0x74, 0x61, 0x18, 0x0e, 0x20, - 0x01, 0x28, 0x0b, 0x32, 0x17, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x70, 0x72, 0x6f, - 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2e, 0x53, 0x74, 0x72, 0x75, 0x63, 0x74, 0x52, 0x04, 0x64, 0x61, - 0x74, 0x61, 0x12, 0x14, 0x0a, 0x05, 0x69, 0x6d, 0x61, 0x67, 0x65, 0x18, 0x0f, 0x20, 0x01, 0x28, - 0x09, 0x52, 0x05, 0x69, 0x6d, 0x61, 0x67, 0x65, 0x12, 0x0e, 0x0a, 0x02, 0x49, 0x44, 0x18, 0x11, - 0x20, 0x01, 0x28, 0x09, 0x52, 0x02, 0x49, 0x44, 0x12, 0x1a, 0x0a, 0x08, 0x70, 0x75, 0x73, 0x68, - 0x54, 0x79, 0x70, 0x65, 0x18, 0x12, 0x20, 0x01, 0x28, 0x09, 0x52, 0x08, 0x70, 0x75, 0x73, 0x68, - 0x54, 0x79, 0x70, 0x65, 0x12, 0x14, 0x0a, 0x05, 0x61, 0x70, 0x70, 0x49, 0x44, 0x18, 0x13, 0x20, - 0x01, 0x28, 0x09, 0x52, 0x05, 0x61, 0x70, 0x70, 0x49, 0x44, 0x12, 0x34, 0x0a, 0x08, 0x70, 0x72, - 0x69, 0x6f, 0x72, 0x69, 0x74, 0x79, 0x18, 0x10, 0x20, 0x01, 0x28, 0x0e, 0x32, 0x18, 0x2e, 0x76, - 0x31, 0x2e, 0x50, 0x75, 0x73, 0x68, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x2e, 0x50, 0x72, - 0x69, 0x6f, 0x72, 0x69, 0x74, 0x79, 0x52, 0x08, 0x70, 0x72, 0x69, 0x6f, 0x72, 0x69, 0x74, 0x79, - 0x12, 0x2a, 0x0a, 0x10, 0x63, 0x6f, 0x6e, 0x74, 0x65, 0x6e, 0x74, 0x41, 0x76, 0x61, 0x69, 0x6c, - 0x61, 0x62, 0x6c, 0x65, 0x18, 0x0b, 0x20, 0x01, 0x28, 0x08, 0x52, 0x10, 0x63, 0x6f, 0x6e, 0x74, - 0x65, 0x6e, 0x74, 0x41, 0x76, 0x61, 0x69, 0x6c, 0x61, 0x62, 0x6c, 0x65, 0x12, 0x26, 0x0a, 0x0e, - 0x6d, 0x75, 0x74, 0x61, 0x62, 0x6c, 0x65, 0x43, 0x6f, 0x6e, 0x74, 0x65, 0x6e, 0x74, 0x18, 0x0d, - 0x20, 0x01, 0x28, 0x08, 0x52, 0x0e, 0x6d, 0x75, 0x74, 0x61, 0x62, 0x6c, 0x65, 0x43, 0x6f, 0x6e, - 0x74, 0x65, 0x6e, 0x74, 0x12, 0x20, 0x0a, 0x0b, 0x64, 0x65, 0x76, 0x65, 0x6c, 0x6f, 0x70, 0x6d, - 0x65, 0x6e, 0x74, 0x18, 0x14, 0x20, 0x01, 0x28, 0x08, 0x52, 0x0b, 0x64, 0x65, 0x76, 0x65, 0x6c, - 0x6f, 0x70, 0x6d, 0x65, 0x6e, 0x74, 0x12, 0x26, 0x0a, 0x06, 0x4f, 0x70, 0x74, 0x69, 0x6f, 0x6e, - 0x18, 0x15, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x0e, 0x2e, 0x76, 0x31, 0x2e, 0x50, 0x75, 0x73, 0x68, - 0x4f, 0x70, 0x74, 0x69, 0x6f, 0x6e, 0x52, 0x06, 0x4f, 0x70, 0x74, 0x69, 0x6f, 0x6e, 0x22, 0x20, - 0x0a, 0x08, 0x50, 0x72, 0x69, 0x6f, 0x72, 0x69, 0x74, 0x79, 0x12, 0x0a, 0x0a, 0x06, 0x4e, 0x4f, - 0x52, 0x4d, 0x41, 0x4c, 0x10, 0x00, 0x12, 0x08, 0x0a, 0x04, 0x48, 0x49, 0x47, 0x48, 0x10, 0x01, - 0x22, 0x40, 0x0a, 0x0c, 0x50, 0x75, 0x73, 0x68, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, - 0x12, 0x18, 0x0a, 0x07, 0x73, 0x75, 0x63, 0x63, 0x65, 0x73, 0x73, 0x18, 0x01, 0x20, 0x01, 0x28, - 0x08, 0x52, 0x07, 0x73, 0x75, 0x63, 0x63, 0x65, 0x73, 0x73, 0x12, 0x16, 0x0a, 0x06, 0x63, 0x6f, - 0x75, 0x6e, 0x74, 0x73, 0x18, 0x02, 0x20, 0x01, 0x28, 0x05, 0x52, 0x06, 0x63, 0x6f, 0x75, 0x6e, - 0x74, 0x73, 0x22, 0x3a, 0x0a, 0x0a, 0x50, 0x75, 0x73, 0x68, 0x4f, 0x70, 0x74, 0x69, 0x6f, 0x6e, - 0x12, 0x16, 0x0a, 0x06, 0x44, 0x72, 0x79, 0x52, 0x75, 0x6e, 0x18, 0x01, 0x20, 0x01, 0x28, 0x08, - 0x52, 0x06, 0x44, 0x72, 0x79, 0x52, 0x75, 0x6e, 0x12, 0x14, 0x0a, 0x05, 0x52, 0x65, 0x74, 0x72, - 0x79, 0x18, 0x02, 0x20, 0x01, 0x28, 0x05, 0x52, 0x05, 0x52, 0x65, 0x74, 0x72, 0x79, 0x32, 0x3a, - 0x0a, 0x0b, 0x50, 0x75, 0x73, 0x68, 0x53, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x12, 0x2b, 0x0a, - 0x04, 0x50, 0x75, 0x73, 0x68, 0x12, 0x0f, 0x2e, 0x76, 0x31, 0x2e, 0x50, 0x75, 0x73, 0x68, 0x52, - 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x10, 0x2e, 0x76, 0x31, 0x2e, 0x50, 0x75, 0x73, 0x68, - 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x00, 0x42, 0x07, 0x5a, 0x05, 0x2e, 0x2f, - 0x3b, 0x76, 0x31, 0x62, 0x06, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x33, -} - -var ( - file_push_proto_rawDescOnce sync.Once - file_push_proto_rawDescData = file_push_proto_rawDesc -) - -func file_push_proto_rawDescGZIP() []byte { - file_push_proto_rawDescOnce.Do(func() { - file_push_proto_rawDescData = protoimpl.X.CompressGZIP(file_push_proto_rawDescData) - }) - return file_push_proto_rawDescData -} - -var file_push_proto_enumTypes = make([]protoimpl.EnumInfo, 1) -var file_push_proto_msgTypes = make([]protoimpl.MessageInfo, 4) -var file_push_proto_goTypes = []interface{}{ - (PushRequest_Priority)(0), // 0: v1.PushRequest.Priority - (*Alert)(nil), // 1: v1.Alert - (*PushRequest)(nil), // 2: v1.PushRequest - (*PushResponse)(nil), // 3: v1.PushResponse - (*PushOption)(nil), // 4: v1.PushOption - (*structpb.Struct)(nil), // 5: google.protobuf.Struct -} -var file_push_proto_depIdxs = []int32{ - 1, // 0: v1.PushRequest.alert:type_name -> v1.Alert - 5, // 1: v1.PushRequest.data:type_name -> google.protobuf.Struct - 0, // 2: v1.PushRequest.priority:type_name -> v1.PushRequest.Priority - 4, // 3: v1.PushRequest.Option:type_name -> v1.PushOption - 2, // 4: v1.PushService.Push:input_type -> v1.PushRequest - 3, // 5: v1.PushService.Push:output_type -> v1.PushResponse - 5, // [5:6] is the sub-list for method output_type - 4, // [4:5] is the sub-list for method input_type - 4, // [4:4] is the sub-list for extension type_name - 4, // [4:4] is the sub-list for extension extendee - 0, // [0:4] is the sub-list for field type_name -} - -func init() { file_push_proto_init() } -func file_push_proto_init() { - if File_push_proto != nil { - return - } - if !protoimpl.UnsafeEnabled { - file_push_proto_msgTypes[0].Exporter = func(v interface{}, i int) interface{} { - switch v := v.(*Alert); i { - case 0: - return &v.state - case 1: - return &v.sizeCache - case 2: - return &v.unknownFields - default: - return nil - } - } - file_push_proto_msgTypes[1].Exporter = func(v interface{}, i int) interface{} { - switch v := v.(*PushRequest); i { - case 0: - return &v.state - case 1: - return &v.sizeCache - case 2: - return &v.unknownFields - default: - return nil - } - } - file_push_proto_msgTypes[2].Exporter = func(v interface{}, i int) interface{} { - switch v := v.(*PushResponse); i { - case 0: - return &v.state - case 1: - return &v.sizeCache - case 2: - return &v.unknownFields - default: - return nil - } - } - file_push_proto_msgTypes[3].Exporter = func(v interface{}, i int) interface{} { - switch v := v.(*PushOption); i { - case 0: - return &v.state - case 1: - return &v.sizeCache - case 2: - return &v.unknownFields - default: - return nil - } - } - } - type x struct{} - out := protoimpl.TypeBuilder{ - File: protoimpl.DescBuilder{ - GoPackagePath: reflect.TypeOf(x{}).PkgPath(), - RawDescriptor: file_push_proto_rawDesc, - NumEnums: 1, - NumMessages: 4, - NumExtensions: 0, - NumServices: 1, - }, - GoTypes: file_push_proto_goTypes, - DependencyIndexes: file_push_proto_depIdxs, - EnumInfos: file_push_proto_enumTypes, - MessageInfos: file_push_proto_msgTypes, - }.Build() - File_push_proto = out.File - file_push_proto_rawDesc = nil - file_push_proto_goTypes = nil - file_push_proto_depIdxs = nil -} diff --git a/api/grpc/v1/push.proto b/api/grpc/v1/push.proto deleted file mode 100644 index aa2ced1..0000000 --- a/api/grpc/v1/push.proto +++ /dev/null @@ -1,67 +0,0 @@ -syntax = "proto3"; -import "google/protobuf/struct.proto"; - -package v1; -//option go_package = "github.com/cossim/hipush/api/grpc/v1"; -option go_package = "./;v1"; - - -message Alert { - string title = 1; - string body = 2; - string subtitle = 3; - string action = 4; - string actionLocKey = 5; - string launchImage = 6; - string locKey = 7; - string titleLocKey = 8; - repeated string locArgs = 9; - repeated string titleLocArgs = 10; -} - -message PushRequest { - string platform = 1; - repeated string tokens = 2; - string title = 4; - string message = 3; - string topic = 5; - string key = 6; - string category = 8; - string sound = 10; - Alert alert = 9; - int32 badge = 7; - string threadID = 12; - google.protobuf.Struct data = 14; - string image = 15; - string ID = 17; - string pushType = 18; - string appID = 19; - enum Priority { - NORMAL = 0; - HIGH = 1; - } - Priority priority = 16; - bool contentAvailable = 11; - 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) {} -} \ No newline at end of file diff --git a/api/http/v1/dto/dto.go b/api/http/v1/dto/dto.go deleted file mode 100644 index 57d8e4b..0000000 --- a/api/http/v1/dto/dto.go +++ /dev/null @@ -1,327 +0,0 @@ -package dto - -import ( - "github.com/cossim/hipush/pkg/notify" - "time" -) - -type HuaweiPushRequestData struct { - Title string `json:"title"` - Content string `json:"content"` - - // TTL represents the message cache time in seconds. - // When the user device is offline, the message is cached on the Push server. - // If the user device reconnects to the network within the message cache time, the message will be delivered. - // After the cache time expires, the message will be discarded. - // The default value is "86400s" (1 day), and the maximum value is "1296000s" (15 days). - TTL string `json:"ttl,omitempty"` - - // Category The category of the notification - // https://developer.huawei.com/consumer/cn/doc/HMSCore-References/https-send-api-0000001050986197#:~:text=%E8%BF%9B%E8%A1%8C%E7%BB%9F%E8%AE%A1%E5%88%86%E6%9E%90%E3%80%82-,category,-%E5%90%A6 - Category string `json:"category,omitempty"` - - // Priority The priority of the notification - // normal、high default normal - Priority string `json:"priority,omitempty"` - - // Icon Small icon URL - Icon string `json:"icon,omitempty"` - - // Img Large image URL - Img string `json:"img,omitempty"` - - // Sound represents the custom message notification ringtone. - // It is effective when creating a new channel. - // The ringtone file set here must be stored in the /res/raw path of the application. - // For example, setting it to "/raw/shake" corresponds to the local "/res/raw/shake.xxx" file of the application. - // Supported file formats include MP3, WAV, MPEG, etc. - // If not set, the default system ringtone will be used. - Sound string `json:"sound,omitempty"` - - // Foreground When the application is in the foreground, whether the notification bar message shows the switch - Foreground bool `json:"foreground,omitempty"` - - // Development Test environment push - Development bool `json:"development,omitempty"` - - // Type specifies the type of click action. - // Possible values are: - // 1: Open a custom app page. - // 2: Open a specific URL. - // 3: Open the app. - // https://developer.huawei.com/consumer/cn/doc/HMSCore-References/https-send-api-0000001050986197#ZH-CN_TOPIC_0000001700731289__p431142991615:~:text=%E6%9C%80%E5%A4%A7%E9%95%BF%E5%BA%A61024-,ClickAction,-%E5%8F%82%E6%95%B0 - ClickAction ClickAction `json:"click_action,omitempty"` - - // https://developer.huawei.com/consumer/cn/doc/HMSCore-References/https-send-api-0000001050986197#ZH-CN_TOPIC_0000001700731289__p12819153131618:~:text=%E4%BA%8C%E9%80%89%E4%B8%80%E3%80%82-,BadgeNotification,-%E5%8F%82%E6%95%B0 - Badge BadgeNotification `json:"badge,omitempty"` -} - -// BadgeNotification 结构体用于表示Android通知消息角标控制 -type BadgeNotification struct { - AddNum int `json:"addNum,omitempty"` - SetNum int `json:"setNum,omitempty"` - Class string `json:"class"` -} - -type APNsPushRequest struct { - Title string `json:"title" binding:"required"` - Content string `json:"content" binding:"required"` - - // Topic The topic of the remote notification, which is typically the bundle ID - // for your app. The certificate you create in the Apple Developer Member - // Center must include the capability for this topic. If your certificate - // includes multiple topics, you must specify a value for this header. If - // you omit this header and your APNs certificate does not specify multiple - // topics, the APNs server uses the certificate’s Subject as the default - // topic. - Topic string `json:"topic" binding:"required"` - - // CollapseID A string which allows multiple notifications with the same collapse - // identifier to be displayed to the user as a single notification. The - // value should not exceed 64 bytes. - CollapseID string `json:"collapse_id,omitempty"` - - // An optional canonical UUID that identifies the notification. The - // canonical form is 32 lowercase hexadecimal digits, displayed in five - // groups separated by hyphens in the form 8-4-4-4-12. An example UUID is as - // follows: - // - // 123e4567-e89b-12d3-a456-42665544000 - // - // If you don't set this, a new UUID is created by APNs and returned in the - // response. - ApnsID string - - // Priority The priority of the notification - // normal、high default normal - Priority string `json:"priority,omitempty"` - - // PushType apns-push-type标头的值 - // https://developer.apple.com/documentation/usernotifications/sending-notification-requests-to-apns#Know-when-to-use-push-types - PushType string `json:"push_type,omitempty"` - - URLArgs []string `json:"url_args,omitempty"` - - // TTL represents the expiration date of the notification. - // If the value is nonzero, it indicates that the notification is valid until the specified date. - // The value is a UNIX epoch expressed in seconds (UTC). - // If the value is nonzero, APNs stores the notification and attempts to deliver it at least once, repeating the attempt as needed until the specified date. - // If the value is 0, APNs attempts to deliver the notification only once and does not store it. - TTL int64 `json:"TTL,omitempty"` - - // Badge sets the aps badge on the payload. - // This will display a numeric badge on the app icon. - Badge int `json:"badge,omitempty"` - - Development bool `json:"development,omitempty"` - - // MutableContent sets the aps mutable-content on the payload to 1. - // This will indicate to the to the system to call your Notification Service - // extension to mutate or replace the notification's content. - MutableContent bool `json:"mutable_content,omitempty"` - - // ContentAvailable sets the aps content-available on the payload to 1. - // This will indicate to the app that there is new content available to download - // and launch the app in the background. - ContentAvailable bool `json:"content_available,omitempty"` - - // Sound sets the aps sound on the payload. - // This will play a sound from the app bundle, or the default sound otherwise. - // https://developer.apple.com/documentation/usernotifications/generating-a-remote-notification Table 3. Keys to include in the sound dictionary - Sound interface{} `json:"sound,omitempty"` - - // Data sets a custom key and value on the payload. - // This will add custom key/value data to the notification payload at root level. - Data map[string]interface{} `json:"data,omitempty"` -} - -type Sound struct { - Critical int `json:"critical"` - Name string `json:"name"` - Volume float64 `json:"volume"` -} - -type VivoPushRequestData struct { - Foreground bool `json:"foreground,omitempty"` - // Development 测试环境推送 - Development bool `json:"development,omitempty"` - TTL int `json:"ttl,omitempty"` - // NotifyType 通知类型 1:无,2:响铃,3:振动,4:响铃和振动 - NotifyType int `json:"notify_type,omitempty"` - NotifyID int `json:"notify_id,omitempty"` - Title string `json:"title"` - Content string `json:"content"` - Category string `json:"category,omitempty"` - TaskID string `json:"task_id,omitempty"` - Data map[string]string `json:"data,omitempty"` - ClickAction ClickAction `json:"click_action,omitempty"` -} - -type OppoPushRequestData struct { - Foreground bool `json:"foreground,omitempty"` - Title string `json:"title"` - Subtitle string `json:"subtitle,omitempty"` - Content string `json:"content"` - // IsTimed 是否限时展示,指示消息是否在特定时间范围内展示 - IsTimed bool `json:"is_timed,omitempty"` - // TimedDuration 限时展示时长,单位为秒,消息将在此时长内展示 - TimedDuration int `json:"timed_duration,omitempty"` - // ValidityPeriod 消息有效时长,即推送服务缓存消息的时长,从消息创建是开始计算,最短为1小时,最长10天 - TTL int `json:"ttl,omitempty"` - // IsScheduled false为立即推送 true为定时推送 - // 消息会在ScheduledStart-ScheduledEnd的时间段内随机展示 - IsScheduled bool `json:"is_scheduled,omitempty"` - // ScheduledStart 定时推送的开始时间,指定消息推送的开始时间 - ScheduledStart time.Time `json:"scheduled_start"` - // ScheduledEnd 定时推送的结束时间,指定消息推送的结束时间 - ScheduledEnd time.Time `json:"scheduled_end"` - // Icon 消息图标,用于在通知栏上显示的图标 - Icon string `json:"icon,omitempty"` - // ClickAction 点击动作 - ClickAction notify.OppoClickAction `json:"click_action"` - // 附加的自定义参数 - Data map[string]string `json:"data,omitempty"` -} - -type XiaomiPushRequestData struct { - Title string `json:"title,omitempty" binding:"required"` - Subtitle string `json:"subtitle,omitempty"` - Content string `json:"content,omitempty" binding:"required"` - - // Foreground When the application is in the foreground, whether the notification bar message shows the switch - Foreground bool `json:"foreground,omitempty"` - - // 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 represents the type of notification, and its value can be DEFAULT_ALL or a combination of the following: - // DEFAULT_ALL = -1; DEFAULT_SOUND = 1; - // Use the default sound for notification; DEFAULT_VIBRATE = 2; - //Use default vibration for notification; DEFAULT_LIGHTS = 4; - //Use default lights for notification. - NotifyType int `json:"notify_type,omitempty"` - - // ClickAction Click behavior for predefined notification bar messages - // "1": Open the Launcher Activity of the app after clicking on the notification in the notification bar. - // "2": Open any Activity of the app after clicking on the notification in the notification bar (the developer also needs to pass url). - // "3": Open a webpage after clicking on the notification in the notification bar. - ClickAction ClickAction `json:"click_action"` - - // 附加的自定义参数 - Data map[string]string `json:"data,omitempty"` -} - -type MeizuPushRequestData struct { - Title string `json:"title,omitempty" binding:"required"` - Content string `json:"content,omitempty" binding:"required"` - - // TTL 如果用户离线,设置消息在服务器保存的时间,单位:ms,服务器默认最长保留两周。 - TTL int `json:"ttl,omitempty"` - - NotifyType int `json:"notify_type,omitempty" json:"notify_type,omitempty"` - - // Foreground 是否前台显示通知 - Foreground bool `json:"foreground,omitempty"` - - // IsScheduled 是否定时推送 - IsScheduled bool `json:"scheduled,omitempty"` - // ScheduledStartTime 定时展示开始时间(yyyy-MM-dd HH:mm:ss) - ScheduledStartTime string `json:"scheduled_start_time"` - // ScheduledEndTime 定时展示结束时间(yyyy-MM-dd HH:mm:ss) - ScheduledEndTime string `json:"scheduled_end_time"` - - // ClickAction 点击动作 - ClickAction ClickAction `json:"click_action"` - - // 附加的自定义参数 - Data map[string]string `json:"data,omitempty"` -} - -type AndroidPushRequestData struct { - Title string `json:"title,omitempty" binding:"required"` - Content string `json:"content,omitempty" binding:"required"` - - // TTL represents the duration for which the message is stored on the server if the user is offline. - // The value should follow a specific format indicating the time duration, such as "86400s" for 1 day, "10m" for 10 minutes, or "1h" for 1 hour. - TTL string `json:"ttl,omitempty"` - - Topic string `json:"topic,omitempty"` - - // Priority The priority of the notification - // normal、high default normal - Priority string `json:"priority,omitempty"` - - // CollapseID represents the collapse identifier of the notification. - CollapseID string `json:"collapse_id,omitempty"` - - // Condition represents the condition for sending the notification to devices. - Condition string `json:"condition,omitempty"` - - // Sound represents the custom sound for the push notification. - Sound string `json:"sound,omitempty"` - - // Image represents the image associated with the push notification. - Image string `json:"image,omitempty"` - - // 附加的自定义参数 - Data map[string]string `json:"data,omitempty"` -} - -type HonorPushRequestData struct { - Title string `json:"title,omitempty" binding:"required"` - Content string `json:"content,omitempty" binding:"required"` - - // Icon 消息图标,用于在通知栏上显示的图标 - Icon string `json:"icon,omitempty"` - - // Tag 消息标识,用于消息去重、覆盖 - Tag string `json:"tag,omitempty"` - - // Group 消息分组,例如发送10条带有同样group字段的消息,手机上只会展示该组消息中最新的一条和当前该组接收到的消息总数目,不会展示10条消息。 - Group string `json:"group,omitempty"` - - // NotifyId 消息通知ID,用于消息覆盖 - NotifyId int `json:"notify_id,omitempty"` - - // TTL 如果用户离线,设置消息在服务器保存的时间,单位:ms,服务器默认最长保留两周。 - TTL int `json:"ttl,omitempty"` - - NotifyType int `json:"notify_type,omitempty" json:"notify_type,omitempty"` - - // Development 测试模式推送消息 - Development bool `json:"development,omitempty"` - - // ClickAction 点击动作 - ClickAction ClickAction `json:"click_action"` - - // Badge 消息角标 - Badge BadgeNotification `json:"badge,omitempty"` - - // 附加的自定义参数 - Data map[string]interface{} `json:"data,omitempty"` -} - -type ClickAction struct { - // Action represents the click action. - // Different manufacturers have different definitions. - Action int `json:"action,omitempty"` - - // Activity opens an in-app page (activity's intent action). - Activity string `json:"activity,omitempty"` - - // Url opens the URL of a webpage. - Url string `json:"url,omitempty"` - - // Parameters represent the parameters appended to the URL after the URL redirection. - Parameters map[string]interface{} `json:"parameters,omitempty"` -} diff --git a/api/http/v1/dto/http.go b/api/http/v1/dto/http.go index 2ffae3e..14ce08d 100644 --- a/api/http/v1/dto/http.go +++ b/api/http/v1/dto/http.go @@ -1,40 +1,5 @@ package dto -// PushRequest 表示推送请求的结构体 -type PushRequest struct { - // AppID 应用程序标识 - // ios capacitor.config文件中的appId 例如com.hitosea.apptest - AppID string `json:"app_id"` - - // appName 应用名称 - AppName string `json:"app_name"` - - // Platform 推送平台 consts.Platform - Platform string `json:"platform" binding:"required"` - - // Token 接收推送的设备标识 - // 例如ios为deviceToken - // vivo、oppo为RegId - Token []string `json:"token" binding:"required"` - - // 推送的消息请求数据,不同平台可能有不同的格式 - Data interface{} `json:"data" binding:"required"` - - // PushOptions 推送选项 - Option PushOption `json:"option,omitempty"` -} - -type PushOption struct { - // DryRun 只进行数据校验不实际推送,数据校验成功即为成功 - DryRun bool `json:"dry_run,omitempty"` - - // Retry 重试次数 - Retry int `json:"retry,omitempty"` - - // RetryInterval 重试间隔(以秒为单位) - RetryInterval int `json:"retry_interval,omitempty"` -} - type PushMessageStatRequest struct { // Platform 平台名称 consts.Platform Platform string `json:"platform" binding:"required"` @@ -71,5 +36,5 @@ type PushStats struct { Huawei PushStat `json:"huawei"` // 华为平台推送状态 Honor PushStat `json:"honor"` // 荣耀平台推送状态 HTTP PushStat `json:"http"` // HTTP 推送状态 - GRPC PushStat `json:"grpc"` // GRPC 推送状态 + GRPC PushStat `json:"pb"` // GRPC 推送状态 } diff --git a/api/pb/v1/apns.go b/api/pb/v1/apns.go new file mode 100644 index 0000000..3d437d6 --- /dev/null +++ b/api/pb/v1/apns.go @@ -0,0 +1,145 @@ +package v1 + +import ( + "github.com/cossim/hipush/api/push" + "github.com/sideshow/apns2" + "github.com/sideshow/apns2/payload" + "time" +) + +var _ push.SendRequest = &APNsPushRequest{} + +func (m *APNsPushRequest) GetNotifyType() int32 { + return 0 +} + +func (m *APNsPushRequest) GetAppID() string { + return m.Meta.AppID +} + +func (m *APNsPushRequest) GetAppName() string { + return m.Meta.AppName +} + +func (m *APNsPushRequest) GetToken() []string { + return m.Meta.Token +} + +func (m *APNsPushRequest) GetMessageID() string { + return m.ApnsID +} + +func (m *APNsPushRequest) GetCondition() string { + return "" +} + +func (m *APNsPushRequest) GetIcon() string { + return "" +} + +func (m *APNsPushRequest) GetForeground() bool { + return true +} + +func (m *APNsPushRequest) BuildNotification(req push.SendRequest) (*apns2.Notification, error) { + topic := req.GetTopic() + if topic == "" { + topic = req.GetAppID() + } + notification := &apns2.Notification{ + ApnsID: req.GetMessageID(), + Topic: topic, + CollapseID: req.GetCollapseID(), + } + + if req.GetTTL() != 0 { + notification.Expiration = time.Unix(req.GetTTL(), 0) + } + + if req.GetPriority() == "normal" { + notification.Priority = apns2.PriorityLow + } else if req.GetPriority() == "high" { + notification.Priority = apns2.PriorityHigh + } + + //if len(req.PushType) > 0 { + // notification.PushType = apns2.EPushType(req.PushType) + //} + + payload := payload.NewPayload() + + // add alert object if message length > 0 and title is empty + if len(req.GetContent()) > 0 && req.GetTitle() == "" { + payload.Alert(req.GetContent()) + } + + // zero value for clear the badge on the app icon. + //if req.Badge != nil && *req.Badge >= 0 { + // payload.Badge(*req.Badge) + //} + + if req.GetMutableContent() { + payload.MutableContent() + } + + //switch req.GetSound().(type) { + //// from http request binding + //case map[string]interface{}: + // result := &Sound{} + // _ = mapstructure.Decode(req.GetSound(), &result) + // payload.Sound(result) + //// from http request binding for non critical alerts + //case string: + // payload.Sound(req.GetSound()) + //case Sound: + // payload.Sound(req.GetSound()) + //} + + //if len(req.SoundName) > 0 { + // payload.SoundName(req.SoundName) + //} + // + //if req.SoundVolume > 0 { + // payload.SoundVolume(req.SoundVolume) + //} + + if req.GetContentAvailable() { + payload.ContentAvailable() + } + + //if len(req.URLArgs) > 0 { + // payload.URLArgs(req.URLArgs) + //} + + //if len(req.ThreadID) > 0 { + // payload.ThreadID(req.ThreadID) + //} + + //for k, v := range req.GetData() { + // payload.Custom(k, v) + //} + + payload.AlertTitle(req.GetTitle()) + payload.AlertBody(req.GetContent()) + payload.Category(req.GetCategory()) + + //payload = iosAlertDictionary(payload, req) + + notification.Payload = payload + + return notification, nil +} + +// Sound sets the aps sound on the payload. +// https://developer.apple.com/documentation/usernotifications/generating-a-remote-notification#:~:text=%E8%AD%A6%E6%8A%A5%E7%9A%84%E5%A3%B0%E9%9F%B3%E3%80%82-,sound%E8%A1%A8%203.%E5%AD%97%E5%85%B8%E4%B8%AD%E5%8C%85%E5%90%AB%E7%9A%84%E9%94%AE,-%E9%92%A5%E5%8C%99 +type Sound struct { + // Critical 指示声音是否被标记为关键声音。关键声音通常用于需要立即引起用户注意的通知。 + // 值为 1 表示是关键声音,值为 0 表示不是关键声音。默认为 0。 + Critical int `json:"critical,omitempty"` + // Name 声音的名称或标识符。 + // 通常是声音文件的名称,表示要播放的声音文件。默认为空字符串。 + Name string `json:"name,omitempty"` + // Volume 声音的音量级别。 + // 值范围为 0.0 到 1.0,表示音量的相对级别。默认为 1.0。 + Volume float32 `json:"volume,omitempty"` +} diff --git a/api/pb/v1/fcm.go b/api/pb/v1/fcm.go new file mode 100644 index 0000000..e77182b --- /dev/null +++ b/api/pb/v1/fcm.go @@ -0,0 +1,45 @@ +package v1 + +import "github.com/cossim/hipush/api/push" + +var _ push.SendRequest = &AndroidPushRequestData{} + +func (x *AndroidPushRequestData) GetNotifyType() int32 { + return 0 +} + +func (x *AndroidPushRequestData) GetAppID() string { + return x.Meta.AppID +} + +func (x *AndroidPushRequestData) GetAppName() string { + return x.Meta.AppName +} + +func (x *AndroidPushRequestData) GetToken() []string { + return x.Meta.Token +} + +func (x *AndroidPushRequestData) GetMessageID() string { + return "" +} + +func (x *AndroidPushRequestData) GetCategory() string { + return "" +} + +func (x *AndroidPushRequestData) GetMutableContent() bool { + return false +} + +func (x *AndroidPushRequestData) GetContentAvailable() bool { + return false +} + +func (x *AndroidPushRequestData) GetDevelopment() bool { + return false +} + +func (x *AndroidPushRequestData) GetForeground() bool { + return true +} diff --git a/api/pb/v1/honor.go b/api/pb/v1/honor.go new file mode 100644 index 0000000..ada50fe --- /dev/null +++ b/api/pb/v1/honor.go @@ -0,0 +1,57 @@ +package v1 + +import "github.com/cossim/hipush/api/push" + +var _ push.SendRequest = &HonorPushRequestData{} + +func (x *HonorPushRequestData) GetAppID() string { + return x.Meta.AppID +} + +func (x *HonorPushRequestData) GetAppName() string { + return x.Meta.AppName +} + +func (x *HonorPushRequestData) GetToken() []string { + return x.Meta.Token +} + +func (x *HonorPushRequestData) GetTopic() string { + return "" +} + +func (x *HonorPushRequestData) GetCollapseID() string { + return "" +} + +func (x *HonorPushRequestData) GetMessageID() string { + return "" +} + +func (x *HonorPushRequestData) GetPriority() string { + return "" +} + +func (x *HonorPushRequestData) GetCategory() string { + return "" +} + +func (x *HonorPushRequestData) GetCondition() string { + return "" +} + +func (x *HonorPushRequestData) GetMutableContent() bool { + return false +} + +func (x *HonorPushRequestData) GetContentAvailable() bool { + return false +} + +func (x *HonorPushRequestData) GetForeground() bool { + return true +} + +func (x *HonorPushRequestData) GetNotifyType() int32 { + return 0 +} diff --git a/api/pb/v1/huawei.go b/api/pb/v1/huawei.go new file mode 100644 index 0000000..02f0a1d --- /dev/null +++ b/api/pb/v1/huawei.go @@ -0,0 +1,45 @@ +package v1 + +import "github.com/cossim/hipush/api/push" + +var _ push.SendRequest = &HuaweiPushRequestData{} + +func (x *HuaweiPushRequestData) GetNotifyType() int32 { + return 0 +} + +func (x *HuaweiPushRequestData) GetAppID() string { + return x.Meta.AppID +} + +func (x *HuaweiPushRequestData) GetAppName() string { + return x.Meta.AppName +} + +func (x *HuaweiPushRequestData) GetToken() []string { + return x.Meta.Token +} + +func (x *HuaweiPushRequestData) GetTopic() string { + return "" +} + +func (x *HuaweiPushRequestData) GetCollapseID() string { + return "" +} + +func (x *HuaweiPushRequestData) GetMessageID() string { + return "" +} + +func (x *HuaweiPushRequestData) GetCondition() string { + return "" +} + +func (x *HuaweiPushRequestData) GetMutableContent() bool { + return false +} + +func (x *HuaweiPushRequestData) GetContentAvailable() bool { + return false +} diff --git a/api/pb/v1/interface_type.go b/api/pb/v1/interface_type.go new file mode 100644 index 0000000..4d59624 --- /dev/null +++ b/api/pb/v1/interface_type.go @@ -0,0 +1,41 @@ +package v1 + +import ( + "encoding/json" + "errors" + "github.com/gogo/protobuf/proto" +) + +var _ proto.Marshaler = (*InterfaceType)(nil) +var _ proto.Unmarshaler = (*InterfaceType)(nil) + +func NewInterfaceType(data interface{}) *InterfaceType { + return &InterfaceType{ + Value: data, + } +} + +type InterfaceType struct { + Value interface{} +} + +func (t InterfaceType) Marshal() ([]byte, error) { + return json.Marshal(t.Value) +} +func (t *InterfaceType) MarshalTo(data []byte) (n int, err error) { + return 0, errors.New("not implement") +} +func (t *InterfaceType) Unmarshal(data []byte) error { + return json.Unmarshal(data, &t.Value) +} +func (t *InterfaceType) Size() int { + return -1 +} + +// 因为只做JSON的序列化,所以只实现这两个方法就行了 +func (t InterfaceType) MarshalJSON() ([]byte, error) { + return json.Marshal(t.Value) +} +func (t *InterfaceType) UnmarshalJSON(data []byte) error { + return json.Unmarshal(data, &t.Value) +} diff --git a/api/pb/v1/meizu.go b/api/pb/v1/meizu.go new file mode 100644 index 0000000..a36a8fb --- /dev/null +++ b/api/pb/v1/meizu.go @@ -0,0 +1,53 @@ +package v1 + +import "github.com/cossim/hipush/api/push" + +var _ push.SendRequest = &MeizuPushRequestData{} + +func (x *MeizuPushRequestData) GetAppID() string { + return x.Meta.AppID +} + +func (x *MeizuPushRequestData) GetAppName() string { + return x.Meta.AppName +} + +func (x *MeizuPushRequestData) GetToken() []string { + return x.Meta.Token +} + +func (x *MeizuPushRequestData) GetTopic() string { + return "" +} + +func (x *MeizuPushRequestData) GetCollapseID() string { + return "" +} + +func (x *MeizuPushRequestData) GetMessageID() string { + return "" +} + +func (x *MeizuPushRequestData) GetPriority() string { + return "" +} + +func (x *MeizuPushRequestData) GetCategory() string { + return "" +} + +func (x *MeizuPushRequestData) GetCondition() string { + return "" +} + +func (x *MeizuPushRequestData) GetIcon() string { + return "" +} + +func (x *MeizuPushRequestData) GetMutableContent() bool { + return false +} + +func (x *MeizuPushRequestData) GetContentAvailable() bool { + return false +} diff --git a/api/pb/v1/oppo.go b/api/pb/v1/oppo.go new file mode 100644 index 0000000..40c4038 --- /dev/null +++ b/api/pb/v1/oppo.go @@ -0,0 +1,49 @@ +package v1 + +import "github.com/cossim/hipush/api/push" + +var _ push.SendRequest = &OppoPushRequestData{} + +func (x *OppoPushRequestData) GetAppID() string { + return x.Meta.AppID +} + +func (x *OppoPushRequestData) GetAppName() string { + return x.Meta.AppName +} + +func (x *OppoPushRequestData) GetToken() []string { + return x.Meta.Token +} + +func (x *OppoPushRequestData) GetTopic() string { + return "" +} + +func (x *OppoPushRequestData) GetCollapseID() string { + return "" +} + +func (x *OppoPushRequestData) GetMessageID() string { + return "" +} + +func (x *OppoPushRequestData) GetPriority() string { + return "" +} + +func (x *OppoPushRequestData) GetCategory() string { + return "" +} + +func (x *OppoPushRequestData) GetCondition() string { + return "" +} + +func (x *OppoPushRequestData) GetMutableContent() bool { + return false +} + +func (x *OppoPushRequestData) GetContentAvailable() bool { + return false +} diff --git a/api/pb/v1/push.pb.go b/api/pb/v1/push.pb.go new file mode 100644 index 0000000..417617e --- /dev/null +++ b/api/pb/v1/push.pb.go @@ -0,0 +1,2258 @@ +// Code generated by protoc-gen-go. DO NOT EDIT. +// versions: +// protoc-gen-go v1.33.0 +// protoc v4.25.1 +// source: push.proto + +package v1 + +import ( + protoreflect "google.golang.org/protobuf/reflect/protoreflect" + protoimpl "google.golang.org/protobuf/runtime/protoimpl" + _ "google.golang.org/protobuf/types/descriptorpb" + anypb "google.golang.org/protobuf/types/known/anypb" + structpb "google.golang.org/protobuf/types/known/structpb" + reflect "reflect" + sync "sync" +) + +const ( + // Verify that this generated code is sufficiently up-to-date. + _ = protoimpl.EnforceVersion(20 - protoimpl.MinVersion) + // Verify that runtime/protoimpl is sufficiently up-to-date. + _ = protoimpl.EnforceVersion(protoimpl.MaxVersion - 20) +) + +type PushOption struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + // DryRun 只进行数据校验不实际推送,数据校验成功即为成功 + // @inject_tag: json:"dry_run" + DryRun bool `protobuf:"varint,1,opt,name=DryRun,proto3" json:"dry_run"` + // Development 测试模式推送 + // @inject_tag: json:"development" + Development bool `protobuf:"varint,2,opt,name=Development,proto3" json:"development"` + // Retry 重试次数 + // @inject_tag: json:"retry" + Retry int32 `protobuf:"varint,3,opt,name=Retry,proto3" json:"retry"` + // RetryInterval 重试间隔(以秒为单位) + // @inject_tag: json:"retry_interval" + RetryInterval int32 `protobuf:"varint,4,opt,name=RetryInterval,proto3" json:"retry_interval"` +} + +func (x *PushOption) Reset() { + *x = PushOption{} + if protoimpl.UnsafeEnabled { + mi := &file_push_proto_msgTypes[0] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *PushOption) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*PushOption) ProtoMessage() {} + +func (x *PushOption) ProtoReflect() protoreflect.Message { + mi := &file_push_proto_msgTypes[0] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use PushOption.ProtoReflect.Descriptor instead. +func (*PushOption) Descriptor() ([]byte, []int) { + return file_push_proto_rawDescGZIP(), []int{0} +} + +func (x *PushOption) GetDryRun() bool { + if x != nil { + return x.DryRun + } + return false +} + +func (x *PushOption) GetDevelopment() bool { + if x != nil { + return x.Development + } + return false +} + +func (x *PushOption) GetRetry() int32 { + if x != nil { + return x.Retry + } + return 0 +} + +func (x *PushOption) GetRetryInterval() int32 { + if x != nil { + return x.RetryInterval + } + return 0 +} + +type PushRequest struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + // AppID 应用程序标识 + // ios capacitor.config文件中的appId 例如com.hitosea.apptest + // @inject_tag: json:"app_id" + AppID string `protobuf:"bytes,1,opt,name=AppID,proto3" json:"app_id"` + // AppName 应用名称 + // @inject_tag: json:"app_name" + AppName string `protobuf:"bytes,2,opt,name=AppName,proto3" json:"app_name"` + // Platform 推送平台 consts.Platform + // @inject_tag: json:"platform" binding:"required" + Platform string `protobuf:"bytes,3,opt,name=Platform,proto3" json:"platform" binding:"required"` + // Token 接收推送的设备标识 + // 例如ios为deviceToken + // vivo、oppo为RegId + // @inject_tag: json:"token" binding:"required" + Token []string `protobuf:"bytes,4,rep,name=Token,proto3" json:"token" binding:"required"` + // @inject_tag: json:"data" + Data *structpb.Struct `protobuf:"bytes,5,opt,name=Data,proto3" json:"data"` + // PushOptions 推送选项 + // @inject_tag: json:"option" + Option *PushOption `protobuf:"bytes,6,opt,name=Option,proto3" json:"option"` +} + +func (x *PushRequest) Reset() { + *x = PushRequest{} + if protoimpl.UnsafeEnabled { + mi := &file_push_proto_msgTypes[1] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *PushRequest) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*PushRequest) ProtoMessage() {} + +func (x *PushRequest) ProtoReflect() protoreflect.Message { + mi := &file_push_proto_msgTypes[1] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use PushRequest.ProtoReflect.Descriptor instead. +func (*PushRequest) Descriptor() ([]byte, []int) { + return file_push_proto_rawDescGZIP(), []int{1} +} + +func (x *PushRequest) GetAppID() string { + if x != nil { + return x.AppID + } + return "" +} + +func (x *PushRequest) GetAppName() string { + if x != nil { + return x.AppName + } + return "" +} + +func (x *PushRequest) GetPlatform() string { + if x != nil { + return x.Platform + } + return "" +} + +func (x *PushRequest) GetToken() []string { + if x != nil { + return x.Token + } + return nil +} + +func (x *PushRequest) GetData() *structpb.Struct { + if x != nil { + return x.Data + } + return nil +} + +func (x *PushRequest) GetOption() *PushOption { + if x != nil { + return x.Option + } + return nil +} + +type PushResponse struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + // @inject_tag: json:"code" + Code int32 `protobuf:"varint,1,opt,name=Code,proto3" json:"code"` + // @inject_tag: json:"msg" + Msg string `protobuf:"bytes,2,opt,name=Msg,proto3" json:"msg"` + // @inject_tag: json:"data" + Data *structpb.Struct `protobuf:"bytes,3,opt,name=Data,proto3" json:"data"` +} + +func (x *PushResponse) Reset() { + *x = PushResponse{} + if protoimpl.UnsafeEnabled { + mi := &file_push_proto_msgTypes[2] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *PushResponse) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*PushResponse) ProtoMessage() {} + +func (x *PushResponse) ProtoReflect() protoreflect.Message { + mi := &file_push_proto_msgTypes[2] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use PushResponse.ProtoReflect.Descriptor instead. +func (*PushResponse) Descriptor() ([]byte, []int) { + return file_push_proto_rawDescGZIP(), []int{2} +} + +func (x *PushResponse) GetCode() int32 { + if x != nil { + return x.Code + } + return 0 +} + +func (x *PushResponse) GetMsg() string { + if x != nil { + return x.Msg + } + return "" +} + +func (x *PushResponse) GetData() *structpb.Struct { + if x != nil { + return x.Data + } + return nil +} + +type Meta struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + // @inject_tag: json:"app_id" + AppID string `protobuf:"bytes,1,opt,name=AppID,proto3" json:"app_id"` + // @inject_tag: json:"app_name" + AppName string `protobuf:"bytes,2,opt,name=AppName,proto3" json:"app_name"` + // @inject_tag: json:"token" + Token []string `protobuf:"bytes,3,rep,name=Token,proto3" json:"token"` +} + +func (x *Meta) Reset() { + *x = Meta{} + if protoimpl.UnsafeEnabled { + mi := &file_push_proto_msgTypes[3] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *Meta) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*Meta) ProtoMessage() {} + +func (x *Meta) ProtoReflect() protoreflect.Message { + mi := &file_push_proto_msgTypes[3] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use Meta.ProtoReflect.Descriptor instead. +func (*Meta) Descriptor() ([]byte, []int) { + return file_push_proto_rawDescGZIP(), []int{3} +} + +func (x *Meta) GetAppID() string { + if x != nil { + return x.AppID + } + return "" +} + +func (x *Meta) GetAppName() string { + if x != nil { + return x.AppName + } + return "" +} + +func (x *Meta) GetToken() []string { + if x != nil { + return x.Token + } + return nil +} + +type APNsPushRequest struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + // @inject_tag: json:"meta" + Meta *Meta `protobuf:"bytes,1,opt,name=meta,proto3" json:"meta"` + // Title Notification Title + // @inject_tag: json:"title" + Title string `protobuf:"bytes,2,opt,name=Title,proto3" json:"title"` + // Content Notification Content + // @inject_tag: json:"content" + Content string `protobuf:"bytes,3,opt,name=Content,proto3" json:"content"` + // Topic The topic of the remote notification, which is typically the bundle ID + // for your app. The certificate you create in the Apple Developer Member + // Center must include the capability for this topic. If your certificate + // includes multiple topics, you must specify a value for this header. If + // you omit this header and your APNs certificate does not specify multiple + // topics, the APNs server uses the certificate’s Subject as the default + // topic. + // @inject_tag: json:"topic" + Topic string `protobuf:"bytes,4,opt,name=Topic,proto3" json:"topic"` + // CollapseID A string which allows multiple notifications with the same collapse + // identifier to be displayed to the user as a single notification. The + // value should not exceed 64 bytes. + // @inject_tag: json:"collapse_id" + CollapseID string `protobuf:"bytes,5,opt,name=CollapseID,proto3" json:"collapse_id"` + // ApnsID An optional canonical UUID that identifies the notification. The + // canonical form is 32 lowercase hexadecimal digits, displayed in five + // groups separated by hyphens in the form 8-4-4-4-12. An example UUID is as + // follows: + // + // 123e4567-e89b-12d3-a456-42665544000 + // + // If you don't set this, a new UUID is created by APNs and returned in the + // response. + // @inject_tag: json:"apns_id" + ApnsID string `protobuf:"bytes,6,opt,name=ApnsID,proto3" json:"apns_id"` + // Priority The priority of the notification + // normal、high default normal + // @inject_tag: json:"priority" + Priority string `protobuf:"bytes,7,opt,name=Priority,proto3" json:"priority"` + // PushType apns-push-type the value of the header + // https://developer.apple.com/documentation/usernotifications/sending-notification-requests-to-apns#Know-when-to-use-push-types + // @inject_tag: json:"push_type" + PushType string `protobuf:"bytes,8,opt,name=PushType,proto3" json:"push_type"` + // @inject_tag: json:"url_args" + URLArgs []string `protobuf:"bytes,9,rep,name=URLArgs,proto3" json:"url_args"` + // TTL represents the expiration date of the notification. + // If the value is nonzero, it indicates that the notification is valid until the specified date. + // The value is a UNIX epoch expressed in seconds (UTC). + // If the value is nonzero, APNs stores the notification and attempts to deliver it at least once, repeating the attempt as needed until the specified date. + // If the value is 0, APNs attempts to deliver the notification only once and does not store it. + // @inject_tag: json:"ttl" + TTL int64 `protobuf:"varint,10,opt,name=TTL,proto3" json:"ttl"` + // Badge sets the aps badge on the payload. + // This will display a numeric badge on the app icon. + // @inject_tag: json:"badge" + Badge int32 `protobuf:"varint,11,opt,name=Badge,proto3" json:"badge"` + Development bool `protobuf:"varint,12,opt,name=Development,proto3" json:"Development,omitempty"` + // MutableContent sets the aps mutable-content on the payload to 1. + // This will indicate to the to the system to call your Notification Service + // extension to mutate or replace the notification's content. + // @inject_tag: json:"mutable_content" + MutableContent bool `protobuf:"varint,13,opt,name=MutableContent,proto3" json:"mutable_content"` + // ContentAvailable sets the aps content-available on the payload to 1. + // This will indicate to the app that there is new content available to download + // and launch the app in the background. + // @inject_tag: json:"content_available" + ContentAvailable bool `protobuf:"varint,14,opt,name=ContentAvailable,proto3" json:"content_available"` + // Sound sets the aps sound on the payload. + // This will play a sound from the app bundle, or the default sound otherwise. + // https://developer.apple.com/documentation/usernotifications/generating-a-remote-notification Table 3. Keys to include in the sound dictionary + // @inject_tag: json:"sound" + Sound *structpb.Struct `protobuf:"bytes,15,opt,name=Sound,proto3" json:"sound"` // bytes Sound = 15[(gogoproto.customtype) = "InterfaceType", (gogoproto.nullable) = false]; // InterfaceType为自定义类型 + // Data sets a custom key and value on the payload. + // This will add custom key/value data to the notification payload at root level. + // + // map data = 15; + // + // @inject_tag: json:"data" + Data *structpb.Struct `protobuf:"bytes,16,opt,name=Data,proto3" json:"data"` // map Data = 16[(gogoproto.customtype) = "InterfaceType", (gogoproto.nullable) = false]; // InterfaceType为自定义类型 + // @inject_tag: json:"category" + Category string `protobuf:"bytes,17,opt,name=Category,proto3" json:"category"` +} + +func (x *APNsPushRequest) Reset() { + *x = APNsPushRequest{} + if protoimpl.UnsafeEnabled { + mi := &file_push_proto_msgTypes[4] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *APNsPushRequest) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*APNsPushRequest) ProtoMessage() {} + +func (x *APNsPushRequest) ProtoReflect() protoreflect.Message { + mi := &file_push_proto_msgTypes[4] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use APNsPushRequest.ProtoReflect.Descriptor instead. +func (*APNsPushRequest) Descriptor() ([]byte, []int) { + return file_push_proto_rawDescGZIP(), []int{4} +} + +func (x *APNsPushRequest) GetMeta() *Meta { + if x != nil { + return x.Meta + } + return nil +} + +func (x *APNsPushRequest) GetTitle() string { + if x != nil { + return x.Title + } + return "" +} + +func (x *APNsPushRequest) GetContent() string { + if x != nil { + return x.Content + } + return "" +} + +func (x *APNsPushRequest) GetTopic() string { + if x != nil { + return x.Topic + } + return "" +} + +func (x *APNsPushRequest) GetCollapseID() string { + if x != nil { + return x.CollapseID + } + return "" +} + +func (x *APNsPushRequest) GetApnsID() string { + if x != nil { + return x.ApnsID + } + return "" +} + +func (x *APNsPushRequest) GetPriority() string { + if x != nil { + return x.Priority + } + return "" +} + +func (x *APNsPushRequest) GetPushType() string { + if x != nil { + return x.PushType + } + return "" +} + +func (x *APNsPushRequest) GetURLArgs() []string { + if x != nil { + return x.URLArgs + } + return nil +} + +func (x *APNsPushRequest) GetTTL() int64 { + if x != nil { + return x.TTL + } + return 0 +} + +func (x *APNsPushRequest) GetBadge() int32 { + if x != nil { + return x.Badge + } + return 0 +} + +func (x *APNsPushRequest) GetDevelopment() bool { + if x != nil { + return x.Development + } + return false +} + +func (x *APNsPushRequest) GetMutableContent() bool { + if x != nil { + return x.MutableContent + } + return false +} + +func (x *APNsPushRequest) GetContentAvailable() bool { + if x != nil { + return x.ContentAvailable + } + return false +} + +func (x *APNsPushRequest) GetSound() *structpb.Struct { + if x != nil { + return x.Sound + } + return nil +} + +func (x *APNsPushRequest) GetData() *structpb.Struct { + if x != nil { + return x.Data + } + return nil +} + +func (x *APNsPushRequest) GetCategory() string { + if x != nil { + return x.Category + } + return "" +} + +type AndroidPushRequestData struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + // @inject_tag: json:"meta" + Meta *Meta `protobuf:"bytes,1,opt,name=Meta,proto3" json:"meta"` + // Title Notification Title + // @inject_tag: json:"title" + Title string `protobuf:"bytes,2,opt,name=Title,proto3" json:"title"` + // Content Notification Content + // @inject_tag: json:"content" + Content string `protobuf:"bytes,3,opt,name=Content,proto3" json:"content"` + // @inject_tag: json:"topic" + Topic string `protobuf:"bytes,4,opt,name=Topic,proto3" json:"topic"` + // TTL represents the duration for which the message is stored on the server if the user is offline. + // The value should follow a specific format indicating the time duration, such as "86400s" for 1 day, "10m" for 10 minutes, or "1h" for 1 hour. + // @inject_tag: json:"ttl" + TTL int64 `protobuf:"varint,5,opt,name=TTL,proto3" json:"ttl"` + // Priority The priority of the notification + // normal、high default normal + // @inject_tag: json:"priority" + Priority string `protobuf:"bytes,6,opt,name=Priority,proto3" json:"priority"` + // CollapseID represents the collapse identifier of the notification. + // @inject_tag: json:"collapse_id" + CollapseID string `protobuf:"bytes,7,opt,name=CollapseID,proto3" json:"collapse_id"` + // Condition represents the condition for sending the notification to devices. + // @inject_tag: json:"condition" + Condition string `protobuf:"bytes,8,opt,name=Condition,proto3" json:"condition"` + // Sound represents the custom sound for the push notification. + // @inject_tag: json:"sound" + Sound string `protobuf:"bytes,9,opt,name=Sound,proto3" json:"sound"` + // Icon represents the icon associated with the push notification. + // @inject_tag: json:"icon" + Icon string `protobuf:"bytes,10,opt,name=Icon,proto3" json:"icon"` + // Data Additional Custom Parameters + // @inject_tag: json:"data" + Data map[string]string `protobuf:"bytes,11,rep,name=Data,proto3" json:"data" protobuf_key:"bytes,1,opt,name=key,proto3" protobuf_val:"bytes,2,opt,name=value,proto3"` +} + +func (x *AndroidPushRequestData) Reset() { + *x = AndroidPushRequestData{} + if protoimpl.UnsafeEnabled { + mi := &file_push_proto_msgTypes[5] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *AndroidPushRequestData) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*AndroidPushRequestData) ProtoMessage() {} + +func (x *AndroidPushRequestData) ProtoReflect() protoreflect.Message { + mi := &file_push_proto_msgTypes[5] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use AndroidPushRequestData.ProtoReflect.Descriptor instead. +func (*AndroidPushRequestData) Descriptor() ([]byte, []int) { + return file_push_proto_rawDescGZIP(), []int{5} +} + +func (x *AndroidPushRequestData) GetMeta() *Meta { + if x != nil { + return x.Meta + } + return nil +} + +func (x *AndroidPushRequestData) GetTitle() string { + if x != nil { + return x.Title + } + return "" +} + +func (x *AndroidPushRequestData) GetContent() string { + if x != nil { + return x.Content + } + return "" +} + +func (x *AndroidPushRequestData) GetTopic() string { + if x != nil { + return x.Topic + } + return "" +} + +func (x *AndroidPushRequestData) GetTTL() int64 { + if x != nil { + return x.TTL + } + return 0 +} + +func (x *AndroidPushRequestData) GetPriority() string { + if x != nil { + return x.Priority + } + return "" +} + +func (x *AndroidPushRequestData) GetCollapseID() string { + if x != nil { + return x.CollapseID + } + return "" +} + +func (x *AndroidPushRequestData) GetCondition() string { + if x != nil { + return x.Condition + } + return "" +} + +func (x *AndroidPushRequestData) GetSound() string { + if x != nil { + return x.Sound + } + return "" +} + +func (x *AndroidPushRequestData) GetIcon() string { + if x != nil { + return x.Icon + } + return "" +} + +func (x *AndroidPushRequestData) GetData() map[string]string { + if x != nil { + return x.Data + } + return nil +} + +type HuaweiPushRequestData struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + // @inject_tag: json:"meta" + Meta *Meta `protobuf:"bytes,1,opt,name=Meta,proto3" json:"meta"` + // @inject_tag: json:"title" + Title string `protobuf:"bytes,2,opt,name=Title,proto3" json:"title"` + // @inject_tag: json:"content" + Content string `protobuf:"bytes,3,opt,name=Content,proto3" json:"content"` + // Category The category of the notification + // https://developer.huawei.com/consumer/cn/doc/HMSCore-References/https-send-api-0000001050986197#:~:text=%E8%BF%9B%E8%A1%8C%E7%BB%9F%E8%AE%A1%E5%88%86%E6%9E%90%E3%80%82-,category,-%E5%90%A6 + // @inject_tag: json:"category" + Category string `protobuf:"bytes,4,opt,name=Category,proto3" json:"category"` + // Priority The priority of the notification + // normal、high default normal + // @inject_tag: json:"priority" + Priority string `protobuf:"bytes,5,opt,name=Priority,proto3" json:"priority"` + // Icon Small icon URL + // @inject_tag: json:"icon" + Icon string `protobuf:"bytes,6,opt,name=Icon,proto3" json:"icon"` + // Sound represents the custom message notification ringtone. + // It is effective when creating a new channel. + // The ringtone file set here must be stored in the /res/raw path of the application. + // For example, setting it to "/raw/shake" corresponds to the local "/res/raw/shake.xxx" file of the application. + // Supported file formats include MP3, WAV, MPEG, etc. + // If not set, the default system ringtone will be used. + // @inject_tag: json:"sound" + Sound string `protobuf:"bytes,7,opt,name=Sound,proto3" json:"sound"` + // TTL represents the message cache time in seconds. + // When the user device is offline, the message is cached on the Push server. + // If the user device reconnects to the network within the message cache time, the message will be delivered. + // After the cache time expires, the message will be discarded. + // The default value is "86400s" (1 day), and the maximum value is "1296000s" (15 days). + // @inject_tag: json:"ttl" + TTL int64 `protobuf:"varint,8,opt,name=TTL,proto3" json:"ttl"` + // Foreground When the application is in the foreground, whether the notification bar message shows the switch + // @inject_tag: json:"foreground" + Foreground bool `protobuf:"varint,9,opt,name=Foreground,proto3" json:"foreground"` + ClickAction *ClickAction `protobuf:"bytes,10,opt,name=ClickAction,proto3" json:"ClickAction,omitempty"` + // @inject_tag: json:"badge" + Badge *BadgeNotification `protobuf:"bytes,11,opt,name=Badge,proto3" json:"badge"` +} + +func (x *HuaweiPushRequestData) Reset() { + *x = HuaweiPushRequestData{} + if protoimpl.UnsafeEnabled { + mi := &file_push_proto_msgTypes[6] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *HuaweiPushRequestData) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*HuaweiPushRequestData) ProtoMessage() {} + +func (x *HuaweiPushRequestData) ProtoReflect() protoreflect.Message { + mi := &file_push_proto_msgTypes[6] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use HuaweiPushRequestData.ProtoReflect.Descriptor instead. +func (*HuaweiPushRequestData) Descriptor() ([]byte, []int) { + return file_push_proto_rawDescGZIP(), []int{6} +} + +func (x *HuaweiPushRequestData) GetMeta() *Meta { + if x != nil { + return x.Meta + } + return nil +} + +func (x *HuaweiPushRequestData) GetTitle() string { + if x != nil { + return x.Title + } + return "" +} + +func (x *HuaweiPushRequestData) GetContent() string { + if x != nil { + return x.Content + } + return "" +} + +func (x *HuaweiPushRequestData) GetCategory() string { + if x != nil { + return x.Category + } + return "" +} + +func (x *HuaweiPushRequestData) GetPriority() string { + if x != nil { + return x.Priority + } + return "" +} + +func (x *HuaweiPushRequestData) GetIcon() string { + if x != nil { + return x.Icon + } + return "" +} + +func (x *HuaweiPushRequestData) GetSound() string { + if x != nil { + return x.Sound + } + return "" +} + +func (x *HuaweiPushRequestData) GetTTL() int64 { + if x != nil { + return x.TTL + } + return 0 +} + +func (x *HuaweiPushRequestData) GetForeground() bool { + if x != nil { + return x.Foreground + } + return false +} + +func (x *HuaweiPushRequestData) GetClickAction() *ClickAction { + if x != nil { + return x.ClickAction + } + return nil +} + +func (x *HuaweiPushRequestData) GetBadge() *BadgeNotification { + if x != nil { + return x.Badge + } + return nil +} + +type XiaomiPushRequestData struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + // @inject_tag: json:"meta" + Meta *Meta `protobuf:"bytes,1,opt,name=Meta,proto3" json:"meta"` + // @inject_tag: json:"title" + Title string `protobuf:"bytes,2,opt,name=Title,proto3" json:"title"` + // @inject_tag: json:"subtitle" + Subtitle string `protobuf:"bytes,3,opt,name=Subtitle,proto3" json:"subtitle"` + // @inject_tag: json:"content" + Content string `protobuf:"bytes,4,opt,name=Content,proto3" json:"content"` + // Foreground When the application is in the foreground, whether the notification bar message shows the switch + // @inject_tag: json:"foreground" + Foreground bool `protobuf:"varint,5,opt,name=Foreground,proto3" json:"foreground"` + // Icon 消息图标,用于在通知栏上显示的图标 + // @inject_tag: json:"icon" + Icon string `protobuf:"bytes,6,opt,name=Icon,proto3" json:"icon"` + // TTL 如果用户离线,设置消息在服务器保存的时间,单位:s,服务器默认最长保留两周。 + // @inject_tag: json:"ttl" + TTL int64 `protobuf:"varint,7,opt,name=TTL,proto3" json:"ttl"` + // NotifyType represents the type of notification, and its value can be DEFAULT_ALL or a combination of the following: + // DEFAULT_ALL = -1; DEFAULT_SOUND = 1; + // Use the default sound for notification; DEFAULT_VIBRATE = 2; + // Use default vibration for notification; DEFAULT_LIGHTS = 4; + // Use default lights for notification. + // @inject_tag: json:"notify_type" + NotifyType int32 `protobuf:"varint,8,opt,name=NotifyType,proto3" json:"notify_type"` + // ClickAction Click behavior for predefined notification bar messages + // "1": Open the Launcher Activity of the app after clicking on the notification in the notification bar. + // "2": Open any Activity of the app after clicking on the notification in the notification bar (the developer also needs to pass url). + // "3": Open a webpage after clicking on the notification in the notification bar. + // @inject_tag: json:"click_action" + ClickAction *ClickAction `protobuf:"bytes,9,opt,name=ClickAction,proto3" json:"click_action"` +} + +func (x *XiaomiPushRequestData) Reset() { + *x = XiaomiPushRequestData{} + if protoimpl.UnsafeEnabled { + mi := &file_push_proto_msgTypes[7] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *XiaomiPushRequestData) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*XiaomiPushRequestData) ProtoMessage() {} + +func (x *XiaomiPushRequestData) ProtoReflect() protoreflect.Message { + mi := &file_push_proto_msgTypes[7] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use XiaomiPushRequestData.ProtoReflect.Descriptor instead. +func (*XiaomiPushRequestData) Descriptor() ([]byte, []int) { + return file_push_proto_rawDescGZIP(), []int{7} +} + +func (x *XiaomiPushRequestData) GetMeta() *Meta { + if x != nil { + return x.Meta + } + return nil +} + +func (x *XiaomiPushRequestData) GetTitle() string { + if x != nil { + return x.Title + } + return "" +} + +func (x *XiaomiPushRequestData) GetSubtitle() string { + if x != nil { + return x.Subtitle + } + return "" +} + +func (x *XiaomiPushRequestData) GetContent() string { + if x != nil { + return x.Content + } + return "" +} + +func (x *XiaomiPushRequestData) GetForeground() bool { + if x != nil { + return x.Foreground + } + return false +} + +func (x *XiaomiPushRequestData) GetIcon() string { + if x != nil { + return x.Icon + } + return "" +} + +func (x *XiaomiPushRequestData) GetTTL() int64 { + if x != nil { + return x.TTL + } + return 0 +} + +func (x *XiaomiPushRequestData) GetNotifyType() int32 { + if x != nil { + return x.NotifyType + } + return 0 +} + +func (x *XiaomiPushRequestData) GetClickAction() *ClickAction { + if x != nil { + return x.ClickAction + } + return nil +} + +type OppoPushRequestData struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + // @inject_tag: json:"meta" + Meta *Meta `protobuf:"bytes,1,opt,name=Meta,proto3" json:"meta"` + // Foreground When the application is in the foreground, whether the notification bar message shows the switch + // @inject_tag: json:"foreground" + Foreground bool `protobuf:"varint,2,opt,name=Foreground,proto3" json:"foreground"` + // @inject_tag: json:"title" + Title string `protobuf:"bytes,3,opt,name=Title,proto3" json:"title"` + // @inject_tag: json:"subtitle" + Subtitle string `protobuf:"bytes,4,opt,name=Subtitle,proto3" json:"subtitle"` + // @inject_tag: json:"content" + Content string `protobuf:"bytes,5,opt,name=Content,proto3" json:"content"` + // TTL 消息有效时长,即推送服务缓存消息的时长,从消息创建是开始计算,最短为1小时,最长10天 单位:s + // @inject_tag: json:"ttl" + TTL int64 `protobuf:"varint,6,opt,name=TTL,proto3" json:"ttl"` + // 通知类型 1:无,2:响铃,3:振动,4:响铃和振动 + // @inject_tag: json:"notify_type" + NotifyType int32 `protobuf:"varint,7,opt,name=NotifyType,proto3" json:"notify_type"` + // Icon 消息图标,用于在通知栏上显示的图标 + // @inject_tag: json:"icon" + Icon string `protobuf:"bytes,8,opt,name=Icon,proto3" json:"icon"` + // ClickAction 点击动作 + // Action 点击跳转类型 1:打开APP首页 2:打开链接 3:自定义 4:打开app内指定页面 5:跳转Intentscheme URL 默认值为 0 + // 0 启动应用 + // 1 打开应用内页(activity的action标签名) + // 2 打开网页 + // 4 打开应用内页(activity 全路径类名) + // 5 Intentscheme URL + // @inject_tag: json:"click_action" + ClickAction *ClickAction `protobuf:"bytes,9,opt,name=ClickAction,proto3" json:"click_action"` + // Data Additional Custom Parameters + // @inject_tag: json:"data" + Data map[string]string `protobuf:"bytes,10,rep,name=Data,proto3" json:"data" protobuf_key:"bytes,1,opt,name=key,proto3" protobuf_val:"bytes,2,opt,name=value,proto3"` +} + +func (x *OppoPushRequestData) Reset() { + *x = OppoPushRequestData{} + if protoimpl.UnsafeEnabled { + mi := &file_push_proto_msgTypes[8] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *OppoPushRequestData) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*OppoPushRequestData) ProtoMessage() {} + +func (x *OppoPushRequestData) ProtoReflect() protoreflect.Message { + mi := &file_push_proto_msgTypes[8] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use OppoPushRequestData.ProtoReflect.Descriptor instead. +func (*OppoPushRequestData) Descriptor() ([]byte, []int) { + return file_push_proto_rawDescGZIP(), []int{8} +} + +func (x *OppoPushRequestData) GetMeta() *Meta { + if x != nil { + return x.Meta + } + return nil +} + +func (x *OppoPushRequestData) GetForeground() bool { + if x != nil { + return x.Foreground + } + return false +} + +func (x *OppoPushRequestData) GetTitle() string { + if x != nil { + return x.Title + } + return "" +} + +func (x *OppoPushRequestData) GetSubtitle() string { + if x != nil { + return x.Subtitle + } + return "" +} + +func (x *OppoPushRequestData) GetContent() string { + if x != nil { + return x.Content + } + return "" +} + +func (x *OppoPushRequestData) GetTTL() int64 { + if x != nil { + return x.TTL + } + return 0 +} + +func (x *OppoPushRequestData) GetNotifyType() int32 { + if x != nil { + return x.NotifyType + } + return 0 +} + +func (x *OppoPushRequestData) GetIcon() string { + if x != nil { + return x.Icon + } + return "" +} + +func (x *OppoPushRequestData) GetClickAction() *ClickAction { + if x != nil { + return x.ClickAction + } + return nil +} + +func (x *OppoPushRequestData) GetData() map[string]string { + if x != nil { + return x.Data + } + return nil +} + +type VivoPushRequestData struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + // @inject_tag: json:"meta" + Meta *Meta `protobuf:"bytes,1,opt,name=Meta,proto3" json:"meta"` + // Foreground Whether to display notification bar messages when the app is in the foreground + // @inject_tag: json:"foreground" + Foreground bool `protobuf:"varint,2,opt,name=Foreground,proto3" json:"foreground"` + // TTL The valid duration of the message, in seconds, and the duration of the push service cache message. + // @inject_tag: json:"ttl" + TTL int64 `protobuf:"varint,4,opt,name=TTL,proto3" json:"ttl"` + // NotifyType Notification Type, 1: None, 2: Bell, 3: Vibration, 4: Bell and Vibration + // @inject_tag: json:"notify_type" + NotifyType int32 `protobuf:"varint,5,opt,name=NotifyType,proto3" json:"notify_type"` + // @inject_tag: json:"notify_id" + NotifyID int32 `protobuf:"varint,6,opt,name=NotifyID,proto3" json:"notify_id"` + // @inject_tag: json:"title" + Title string `protobuf:"bytes,7,opt,name=Title,proto3" json:"title"` + // @inject_tag: json:"content" + Content string `protobuf:"bytes,8,opt,name=Content,proto3" json:"content"` + // @inject_tag: json:"category" + Category string `protobuf:"bytes,9,opt,name=Category,proto3" json:"category"` + // @inject_tag: json:"task_id" + TaskId string `protobuf:"bytes,10,opt,name=TaskId,proto3" json:"task_id"` + // @inject_tag: json:"click_action" + ClickAction *ClickAction `protobuf:"bytes,11,opt,name=ClickAction,proto3" json:"click_action"` + // Data Additional Custom Parameters + // @inject_tag: json:"data" + Data map[string]string `protobuf:"bytes,12,rep,name=Data,proto3" json:"data" protobuf_key:"bytes,1,opt,name=key,proto3" protobuf_val:"bytes,2,opt,name=value,proto3"` +} + +func (x *VivoPushRequestData) Reset() { + *x = VivoPushRequestData{} + if protoimpl.UnsafeEnabled { + mi := &file_push_proto_msgTypes[9] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *VivoPushRequestData) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*VivoPushRequestData) ProtoMessage() {} + +func (x *VivoPushRequestData) ProtoReflect() protoreflect.Message { + mi := &file_push_proto_msgTypes[9] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use VivoPushRequestData.ProtoReflect.Descriptor instead. +func (*VivoPushRequestData) Descriptor() ([]byte, []int) { + return file_push_proto_rawDescGZIP(), []int{9} +} + +func (x *VivoPushRequestData) GetMeta() *Meta { + if x != nil { + return x.Meta + } + return nil +} + +func (x *VivoPushRequestData) GetForeground() bool { + if x != nil { + return x.Foreground + } + return false +} + +func (x *VivoPushRequestData) GetTTL() int64 { + if x != nil { + return x.TTL + } + return 0 +} + +func (x *VivoPushRequestData) GetNotifyType() int32 { + if x != nil { + return x.NotifyType + } + return 0 +} + +func (x *VivoPushRequestData) GetNotifyID() int32 { + if x != nil { + return x.NotifyID + } + return 0 +} + +func (x *VivoPushRequestData) GetTitle() string { + if x != nil { + return x.Title + } + return "" +} + +func (x *VivoPushRequestData) GetContent() string { + if x != nil { + return x.Content + } + return "" +} + +func (x *VivoPushRequestData) GetCategory() string { + if x != nil { + return x.Category + } + return "" +} + +func (x *VivoPushRequestData) GetTaskId() string { + if x != nil { + return x.TaskId + } + return "" +} + +func (x *VivoPushRequestData) GetClickAction() *ClickAction { + if x != nil { + return x.ClickAction + } + return nil +} + +func (x *VivoPushRequestData) GetData() map[string]string { + if x != nil { + return x.Data + } + return nil +} + +type ClickAction struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + // Action represents the click action. + // Different manufacturers have different definitions. + // @inject_tag: json:"action" + Action int32 `protobuf:"varint,1,opt,name=Action,proto3" json:"action"` + // Activity opens an in-app page (activity's intent action). + // @inject_tag: json:"activity" + Activity string `protobuf:"bytes,2,opt,name=Activity,proto3" json:"activity"` + // Url opens the URL of a webpage. + // @inject_tag: json:"url" + Url string `protobuf:"bytes,3,opt,name=Url,proto3" json:"url"` + // Parameters represent the parameters appended to the URL after the URL redirection. + // @inject_tag: json:"parameters" + Parameters map[string]*anypb.Any `protobuf:"bytes,4,rep,name=Parameters,proto3" json:"parameters" protobuf_key:"bytes,1,opt,name=key,proto3" protobuf_val:"bytes,2,opt,name=value,proto3"` +} + +func (x *ClickAction) Reset() { + *x = ClickAction{} + if protoimpl.UnsafeEnabled { + mi := &file_push_proto_msgTypes[10] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *ClickAction) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*ClickAction) ProtoMessage() {} + +func (x *ClickAction) ProtoReflect() protoreflect.Message { + mi := &file_push_proto_msgTypes[10] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use ClickAction.ProtoReflect.Descriptor instead. +func (*ClickAction) Descriptor() ([]byte, []int) { + return file_push_proto_rawDescGZIP(), []int{10} +} + +func (x *ClickAction) GetAction() int32 { + if x != nil { + return x.Action + } + return 0 +} + +func (x *ClickAction) GetActivity() string { + if x != nil { + return x.Activity + } + return "" +} + +func (x *ClickAction) GetUrl() string { + if x != nil { + return x.Url + } + return "" +} + +func (x *ClickAction) GetParameters() map[string]*anypb.Any { + if x != nil { + return x.Parameters + } + return nil +} + +type MeizuPushRequestData struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + // @inject_tag: json:"meta" + Meta *Meta `protobuf:"bytes,1,opt,name=Meta,proto3" json:"meta"` + // @inject_tag: json:"title" + Title string `protobuf:"bytes,2,opt,name=Title,proto3" json:"title"` + // @inject_tag: json:"content" + Content string `protobuf:"bytes,3,opt,name=Content,proto3" json:"content"` + // TTL The valid duration of the message, in seconds, and the duration of the push service cache message. + // @inject_tag: json:"ttl" + TTL int64 `protobuf:"varint,4,opt,name=TTL,proto3" json:"ttl"` + // NotifyType + // DEFAULT_ALL = -1; + // DEFAULT_SOUND = 0; 使用默认提示音提示 + // DEFAULT_VIBRATE = 1; 使用默认振动提示 + // DEFAULT_LIGHTS = 2; 使用默认呼吸灯提示。 + // @inject_tag: json:"notify_type" + NotifyType int32 `protobuf:"varint,5,opt,name=NotifyType,proto3" json:"notify_type"` + // Foreground Whether to display notification bar messages when the app is in the foreground + // @inject_tag: json:"foreground" + Foreground bool `protobuf:"varint,6,opt,name=Foreground,proto3" json:"foreground"` + // ClickAction 点击跳转类型 + // 0 打开应用 + // 1 打开应用内页(activity的action标签名) + // 2 打开H5地址(应用本地的URI) + // Activity 打开应用内页(activity 的 intent action) + // @inject_tag: json:"click_action" + ClickAction *ClickAction `protobuf:"bytes,10,opt,name=ClickAction,proto3" json:"click_action"` + // Data Additional Custom Parameters + // @inject_tag: json:"data" + Data map[string]string `protobuf:"bytes,11,rep,name=Data,proto3" json:"data" protobuf_key:"bytes,1,opt,name=key,proto3" protobuf_val:"bytes,2,opt,name=value,proto3"` +} + +func (x *MeizuPushRequestData) Reset() { + *x = MeizuPushRequestData{} + if protoimpl.UnsafeEnabled { + mi := &file_push_proto_msgTypes[11] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *MeizuPushRequestData) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*MeizuPushRequestData) ProtoMessage() {} + +func (x *MeizuPushRequestData) ProtoReflect() protoreflect.Message { + mi := &file_push_proto_msgTypes[11] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use MeizuPushRequestData.ProtoReflect.Descriptor instead. +func (*MeizuPushRequestData) Descriptor() ([]byte, []int) { + return file_push_proto_rawDescGZIP(), []int{11} +} + +func (x *MeizuPushRequestData) GetMeta() *Meta { + if x != nil { + return x.Meta + } + return nil +} + +func (x *MeizuPushRequestData) GetTitle() string { + if x != nil { + return x.Title + } + return "" +} + +func (x *MeizuPushRequestData) GetContent() string { + if x != nil { + return x.Content + } + return "" +} + +func (x *MeizuPushRequestData) GetTTL() int64 { + if x != nil { + return x.TTL + } + return 0 +} + +func (x *MeizuPushRequestData) GetNotifyType() int32 { + if x != nil { + return x.NotifyType + } + return 0 +} + +func (x *MeizuPushRequestData) GetForeground() bool { + if x != nil { + return x.Foreground + } + return false +} + +func (x *MeizuPushRequestData) GetClickAction() *ClickAction { + if x != nil { + return x.ClickAction + } + return nil +} + +func (x *MeizuPushRequestData) GetData() map[string]string { + if x != nil { + return x.Data + } + return nil +} + +type HonorPushRequestData struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + // @inject_tag: json:"meta" + Meta *Meta `protobuf:"bytes,1,opt,name=Meta,proto3" json:"meta"` + // @inject_tag: json:"title" + Title string `protobuf:"bytes,2,opt,name=Title,proto3" json:"title"` + // @inject_tag: json:"content" + Content string `protobuf:"bytes,3,opt,name=Content,proto3" json:"content"` + // Icon Message icon, the icon to display on the notification bar + // @inject_tag: json:"icon" + Icon string `protobuf:"bytes,4,opt,name=Icon,proto3" json:"icon"` + // Tag Message identifier, used for message deduplication and overwriting. + // @inject_tag: json:"tag" + Tag string `protobuf:"bytes,5,opt,name=Tag,proto3" json:"tag"` + // Group 消息分组,例如发送10条带有同样group字段的消息,手机上只会展示该组消息中最新的一条和当前该组接收到的消息总数目,不会展示10条消息。 + // @inject_tag: json:"group" + Group string `protobuf:"bytes,6,opt,name=Group,proto3" json:"group"` + // NotifyId 消息通知ID,用于消息覆盖 + // @inject_tag: json:"notify_id" + NotifyId int32 `protobuf:"varint,7,opt,name=NotifyId,proto3" json:"notify_id"` + // TTL The valid duration of the message, in seconds, and the duration of the push service cache message. + // @inject_tag: json:"ttl" + TTL int64 `protobuf:"varint,8,opt,name=TTL,proto3" json:"ttl"` + // 测试模式推送消息 + // @inject_tag: json:"development" + Development bool `protobuf:"varint,9,opt,name=Development,proto3" json:"development"` + // Action 点击跳转类型 + // 1 打开应用内页(activity的action标签名) + // 2 打开特定url + // 3 打开应用 + // @inject_tag: json:"click_action" + ClickAction *ClickAction `protobuf:"bytes,10,opt,name=ClickAction,proto3" json:"click_action"` + // 消息角标 + // @inject_tag: json:"badge" + Badge *BadgeNotification `protobuf:"bytes,11,opt,name=Badge,proto3" json:"badge"` + // 附加的自定义参数 + // @inject_tag: json:"data" + Data map[string]string `protobuf:"bytes,12,rep,name=Data,proto3" json:"data" protobuf_key:"bytes,1,opt,name=key,proto3" protobuf_val:"bytes,2,opt,name=value,proto3"` +} + +func (x *HonorPushRequestData) Reset() { + *x = HonorPushRequestData{} + if protoimpl.UnsafeEnabled { + mi := &file_push_proto_msgTypes[12] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *HonorPushRequestData) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*HonorPushRequestData) ProtoMessage() {} + +func (x *HonorPushRequestData) ProtoReflect() protoreflect.Message { + mi := &file_push_proto_msgTypes[12] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use HonorPushRequestData.ProtoReflect.Descriptor instead. +func (*HonorPushRequestData) Descriptor() ([]byte, []int) { + return file_push_proto_rawDescGZIP(), []int{12} +} + +func (x *HonorPushRequestData) GetMeta() *Meta { + if x != nil { + return x.Meta + } + return nil +} + +func (x *HonorPushRequestData) GetTitle() string { + if x != nil { + return x.Title + } + return "" +} + +func (x *HonorPushRequestData) GetContent() string { + if x != nil { + return x.Content + } + return "" +} + +func (x *HonorPushRequestData) GetIcon() string { + if x != nil { + return x.Icon + } + return "" +} + +func (x *HonorPushRequestData) GetTag() string { + if x != nil { + return x.Tag + } + return "" +} + +func (x *HonorPushRequestData) GetGroup() string { + if x != nil { + return x.Group + } + return "" +} + +func (x *HonorPushRequestData) GetNotifyId() int32 { + if x != nil { + return x.NotifyId + } + return 0 +} + +func (x *HonorPushRequestData) GetTTL() int64 { + if x != nil { + return x.TTL + } + return 0 +} + +func (x *HonorPushRequestData) GetDevelopment() bool { + if x != nil { + return x.Development + } + return false +} + +func (x *HonorPushRequestData) GetClickAction() *ClickAction { + if x != nil { + return x.ClickAction + } + return nil +} + +func (x *HonorPushRequestData) GetBadge() *BadgeNotification { + if x != nil { + return x.Badge + } + return nil +} + +func (x *HonorPushRequestData) GetData() map[string]string { + if x != nil { + return x.Data + } + return nil +} + +type BadgeNotification struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + // @inject_tag: json:"add_num" + AddNum int32 `protobuf:"varint,1,opt,name=AddNum,proto3" json:"add_num"` + // @inject_tag: json:"set_num" + SetNum int32 `protobuf:"varint,2,opt,name=SetNum,proto3" json:"set_num"` + // @inject_tag: json:"class" + Class string `protobuf:"bytes,3,opt,name=Class,proto3" json:"class"` +} + +func (x *BadgeNotification) Reset() { + *x = BadgeNotification{} + if protoimpl.UnsafeEnabled { + mi := &file_push_proto_msgTypes[13] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *BadgeNotification) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*BadgeNotification) ProtoMessage() {} + +func (x *BadgeNotification) ProtoReflect() protoreflect.Message { + mi := &file_push_proto_msgTypes[13] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use BadgeNotification.ProtoReflect.Descriptor instead. +func (*BadgeNotification) Descriptor() ([]byte, []int) { + return file_push_proto_rawDescGZIP(), []int{13} +} + +func (x *BadgeNotification) GetAddNum() int32 { + if x != nil { + return x.AddNum + } + return 0 +} + +func (x *BadgeNotification) GetSetNum() int32 { + if x != nil { + return x.SetNum + } + return 0 +} + +func (x *BadgeNotification) GetClass() string { + if x != nil { + return x.Class + } + return "" +} + +var File_push_proto protoreflect.FileDescriptor + +var file_push_proto_rawDesc = []byte{ + 0x0a, 0x0a, 0x70, 0x75, 0x73, 0x68, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x12, 0x02, 0x76, 0x31, + 0x1a, 0x19, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2f, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, + 0x66, 0x2f, 0x61, 0x6e, 0x79, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x1a, 0x20, 0x67, 0x6f, 0x6f, + 0x67, 0x6c, 0x65, 0x2f, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2f, 0x64, 0x65, 0x73, + 0x63, 0x72, 0x69, 0x70, 0x74, 0x6f, 0x72, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x1a, 0x1c, 0x67, + 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2f, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2f, 0x73, + 0x74, 0x72, 0x75, 0x63, 0x74, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x22, 0x82, 0x01, 0x0a, 0x0a, + 0x50, 0x75, 0x73, 0x68, 0x4f, 0x70, 0x74, 0x69, 0x6f, 0x6e, 0x12, 0x16, 0x0a, 0x06, 0x44, 0x72, + 0x79, 0x52, 0x75, 0x6e, 0x18, 0x01, 0x20, 0x01, 0x28, 0x08, 0x52, 0x06, 0x44, 0x72, 0x79, 0x52, + 0x75, 0x6e, 0x12, 0x20, 0x0a, 0x0b, 0x44, 0x65, 0x76, 0x65, 0x6c, 0x6f, 0x70, 0x6d, 0x65, 0x6e, + 0x74, 0x18, 0x02, 0x20, 0x01, 0x28, 0x08, 0x52, 0x0b, 0x44, 0x65, 0x76, 0x65, 0x6c, 0x6f, 0x70, + 0x6d, 0x65, 0x6e, 0x74, 0x12, 0x14, 0x0a, 0x05, 0x52, 0x65, 0x74, 0x72, 0x79, 0x18, 0x03, 0x20, + 0x01, 0x28, 0x05, 0x52, 0x05, 0x52, 0x65, 0x74, 0x72, 0x79, 0x12, 0x24, 0x0a, 0x0d, 0x52, 0x65, + 0x74, 0x72, 0x79, 0x49, 0x6e, 0x74, 0x65, 0x72, 0x76, 0x61, 0x6c, 0x18, 0x04, 0x20, 0x01, 0x28, + 0x05, 0x52, 0x0d, 0x52, 0x65, 0x74, 0x72, 0x79, 0x49, 0x6e, 0x74, 0x65, 0x72, 0x76, 0x61, 0x6c, + 0x22, 0xc4, 0x01, 0x0a, 0x0b, 0x50, 0x75, 0x73, 0x68, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, + 0x12, 0x14, 0x0a, 0x05, 0x41, 0x70, 0x70, 0x49, 0x44, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, + 0x05, 0x41, 0x70, 0x70, 0x49, 0x44, 0x12, 0x18, 0x0a, 0x07, 0x41, 0x70, 0x70, 0x4e, 0x61, 0x6d, + 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x07, 0x41, 0x70, 0x70, 0x4e, 0x61, 0x6d, 0x65, + 0x12, 0x1a, 0x0a, 0x08, 0x50, 0x6c, 0x61, 0x74, 0x66, 0x6f, 0x72, 0x6d, 0x18, 0x03, 0x20, 0x01, + 0x28, 0x09, 0x52, 0x08, 0x50, 0x6c, 0x61, 0x74, 0x66, 0x6f, 0x72, 0x6d, 0x12, 0x14, 0x0a, 0x05, + 0x54, 0x6f, 0x6b, 0x65, 0x6e, 0x18, 0x04, 0x20, 0x03, 0x28, 0x09, 0x52, 0x05, 0x54, 0x6f, 0x6b, + 0x65, 0x6e, 0x12, 0x2b, 0x0a, 0x04, 0x44, 0x61, 0x74, 0x61, 0x18, 0x05, 0x20, 0x01, 0x28, 0x0b, + 0x32, 0x17, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, + 0x75, 0x66, 0x2e, 0x53, 0x74, 0x72, 0x75, 0x63, 0x74, 0x52, 0x04, 0x44, 0x61, 0x74, 0x61, 0x12, + 0x26, 0x0a, 0x06, 0x4f, 0x70, 0x74, 0x69, 0x6f, 0x6e, 0x18, 0x06, 0x20, 0x01, 0x28, 0x0b, 0x32, + 0x0e, 0x2e, 0x76, 0x31, 0x2e, 0x50, 0x75, 0x73, 0x68, 0x4f, 0x70, 0x74, 0x69, 0x6f, 0x6e, 0x52, + 0x06, 0x4f, 0x70, 0x74, 0x69, 0x6f, 0x6e, 0x22, 0x61, 0x0a, 0x0c, 0x50, 0x75, 0x73, 0x68, 0x52, + 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x12, 0x0a, 0x04, 0x43, 0x6f, 0x64, 0x65, 0x18, + 0x01, 0x20, 0x01, 0x28, 0x05, 0x52, 0x04, 0x43, 0x6f, 0x64, 0x65, 0x12, 0x10, 0x0a, 0x03, 0x4d, + 0x73, 0x67, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x03, 0x4d, 0x73, 0x67, 0x12, 0x2b, 0x0a, + 0x04, 0x44, 0x61, 0x74, 0x61, 0x18, 0x03, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x17, 0x2e, 0x67, 0x6f, + 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2e, 0x53, 0x74, + 0x72, 0x75, 0x63, 0x74, 0x52, 0x04, 0x44, 0x61, 0x74, 0x61, 0x22, 0x4c, 0x0a, 0x04, 0x4d, 0x65, + 0x74, 0x61, 0x12, 0x14, 0x0a, 0x05, 0x41, 0x70, 0x70, 0x49, 0x44, 0x18, 0x01, 0x20, 0x01, 0x28, + 0x09, 0x52, 0x05, 0x41, 0x70, 0x70, 0x49, 0x44, 0x12, 0x18, 0x0a, 0x07, 0x41, 0x70, 0x70, 0x4e, + 0x61, 0x6d, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x07, 0x41, 0x70, 0x70, 0x4e, 0x61, + 0x6d, 0x65, 0x12, 0x14, 0x0a, 0x05, 0x54, 0x6f, 0x6b, 0x65, 0x6e, 0x18, 0x03, 0x20, 0x03, 0x28, + 0x09, 0x52, 0x05, 0x54, 0x6f, 0x6b, 0x65, 0x6e, 0x22, 0x95, 0x04, 0x0a, 0x0f, 0x41, 0x50, 0x4e, + 0x73, 0x50, 0x75, 0x73, 0x68, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x1c, 0x0a, 0x04, + 0x6d, 0x65, 0x74, 0x61, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x08, 0x2e, 0x76, 0x31, 0x2e, + 0x4d, 0x65, 0x74, 0x61, 0x52, 0x04, 0x6d, 0x65, 0x74, 0x61, 0x12, 0x14, 0x0a, 0x05, 0x54, 0x69, + 0x74, 0x6c, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x05, 0x54, 0x69, 0x74, 0x6c, 0x65, + 0x12, 0x18, 0x0a, 0x07, 0x43, 0x6f, 0x6e, 0x74, 0x65, 0x6e, 0x74, 0x18, 0x03, 0x20, 0x01, 0x28, + 0x09, 0x52, 0x07, 0x43, 0x6f, 0x6e, 0x74, 0x65, 0x6e, 0x74, 0x12, 0x14, 0x0a, 0x05, 0x54, 0x6f, + 0x70, 0x69, 0x63, 0x18, 0x04, 0x20, 0x01, 0x28, 0x09, 0x52, 0x05, 0x54, 0x6f, 0x70, 0x69, 0x63, + 0x12, 0x1e, 0x0a, 0x0a, 0x43, 0x6f, 0x6c, 0x6c, 0x61, 0x70, 0x73, 0x65, 0x49, 0x44, 0x18, 0x05, + 0x20, 0x01, 0x28, 0x09, 0x52, 0x0a, 0x43, 0x6f, 0x6c, 0x6c, 0x61, 0x70, 0x73, 0x65, 0x49, 0x44, + 0x12, 0x16, 0x0a, 0x06, 0x41, 0x70, 0x6e, 0x73, 0x49, 0x44, 0x18, 0x06, 0x20, 0x01, 0x28, 0x09, + 0x52, 0x06, 0x41, 0x70, 0x6e, 0x73, 0x49, 0x44, 0x12, 0x1a, 0x0a, 0x08, 0x50, 0x72, 0x69, 0x6f, + 0x72, 0x69, 0x74, 0x79, 0x18, 0x07, 0x20, 0x01, 0x28, 0x09, 0x52, 0x08, 0x50, 0x72, 0x69, 0x6f, + 0x72, 0x69, 0x74, 0x79, 0x12, 0x1a, 0x0a, 0x08, 0x50, 0x75, 0x73, 0x68, 0x54, 0x79, 0x70, 0x65, + 0x18, 0x08, 0x20, 0x01, 0x28, 0x09, 0x52, 0x08, 0x50, 0x75, 0x73, 0x68, 0x54, 0x79, 0x70, 0x65, + 0x12, 0x18, 0x0a, 0x07, 0x55, 0x52, 0x4c, 0x41, 0x72, 0x67, 0x73, 0x18, 0x09, 0x20, 0x03, 0x28, + 0x09, 0x52, 0x07, 0x55, 0x52, 0x4c, 0x41, 0x72, 0x67, 0x73, 0x12, 0x10, 0x0a, 0x03, 0x54, 0x54, + 0x4c, 0x18, 0x0a, 0x20, 0x01, 0x28, 0x03, 0x52, 0x03, 0x54, 0x54, 0x4c, 0x12, 0x14, 0x0a, 0x05, + 0x42, 0x61, 0x64, 0x67, 0x65, 0x18, 0x0b, 0x20, 0x01, 0x28, 0x05, 0x52, 0x05, 0x42, 0x61, 0x64, + 0x67, 0x65, 0x12, 0x20, 0x0a, 0x0b, 0x44, 0x65, 0x76, 0x65, 0x6c, 0x6f, 0x70, 0x6d, 0x65, 0x6e, + 0x74, 0x18, 0x0c, 0x20, 0x01, 0x28, 0x08, 0x52, 0x0b, 0x44, 0x65, 0x76, 0x65, 0x6c, 0x6f, 0x70, + 0x6d, 0x65, 0x6e, 0x74, 0x12, 0x26, 0x0a, 0x0e, 0x4d, 0x75, 0x74, 0x61, 0x62, 0x6c, 0x65, 0x43, + 0x6f, 0x6e, 0x74, 0x65, 0x6e, 0x74, 0x18, 0x0d, 0x20, 0x01, 0x28, 0x08, 0x52, 0x0e, 0x4d, 0x75, + 0x74, 0x61, 0x62, 0x6c, 0x65, 0x43, 0x6f, 0x6e, 0x74, 0x65, 0x6e, 0x74, 0x12, 0x2a, 0x0a, 0x10, + 0x43, 0x6f, 0x6e, 0x74, 0x65, 0x6e, 0x74, 0x41, 0x76, 0x61, 0x69, 0x6c, 0x61, 0x62, 0x6c, 0x65, + 0x18, 0x0e, 0x20, 0x01, 0x28, 0x08, 0x52, 0x10, 0x43, 0x6f, 0x6e, 0x74, 0x65, 0x6e, 0x74, 0x41, + 0x76, 0x61, 0x69, 0x6c, 0x61, 0x62, 0x6c, 0x65, 0x12, 0x2d, 0x0a, 0x05, 0x53, 0x6f, 0x75, 0x6e, + 0x64, 0x18, 0x0f, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x17, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, + 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2e, 0x53, 0x74, 0x72, 0x75, 0x63, 0x74, + 0x52, 0x05, 0x53, 0x6f, 0x75, 0x6e, 0x64, 0x12, 0x2b, 0x0a, 0x04, 0x44, 0x61, 0x74, 0x61, 0x18, + 0x10, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x17, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x70, + 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2e, 0x53, 0x74, 0x72, 0x75, 0x63, 0x74, 0x52, 0x04, + 0x44, 0x61, 0x74, 0x61, 0x12, 0x1a, 0x0a, 0x08, 0x43, 0x61, 0x74, 0x65, 0x67, 0x6f, 0x72, 0x79, + 0x18, 0x11, 0x20, 0x01, 0x28, 0x09, 0x52, 0x08, 0x43, 0x61, 0x74, 0x65, 0x67, 0x6f, 0x72, 0x79, + 0x22, 0x85, 0x03, 0x0a, 0x16, 0x41, 0x6e, 0x64, 0x72, 0x6f, 0x69, 0x64, 0x50, 0x75, 0x73, 0x68, + 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x44, 0x61, 0x74, 0x61, 0x12, 0x1c, 0x0a, 0x04, 0x4d, + 0x65, 0x74, 0x61, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x08, 0x2e, 0x76, 0x31, 0x2e, 0x4d, + 0x65, 0x74, 0x61, 0x52, 0x04, 0x4d, 0x65, 0x74, 0x61, 0x12, 0x14, 0x0a, 0x05, 0x54, 0x69, 0x74, + 0x6c, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x05, 0x54, 0x69, 0x74, 0x6c, 0x65, 0x12, + 0x18, 0x0a, 0x07, 0x43, 0x6f, 0x6e, 0x74, 0x65, 0x6e, 0x74, 0x18, 0x03, 0x20, 0x01, 0x28, 0x09, + 0x52, 0x07, 0x43, 0x6f, 0x6e, 0x74, 0x65, 0x6e, 0x74, 0x12, 0x14, 0x0a, 0x05, 0x54, 0x6f, 0x70, + 0x69, 0x63, 0x18, 0x04, 0x20, 0x01, 0x28, 0x09, 0x52, 0x05, 0x54, 0x6f, 0x70, 0x69, 0x63, 0x12, + 0x10, 0x0a, 0x03, 0x54, 0x54, 0x4c, 0x18, 0x05, 0x20, 0x01, 0x28, 0x03, 0x52, 0x03, 0x54, 0x54, + 0x4c, 0x12, 0x1a, 0x0a, 0x08, 0x50, 0x72, 0x69, 0x6f, 0x72, 0x69, 0x74, 0x79, 0x18, 0x06, 0x20, + 0x01, 0x28, 0x09, 0x52, 0x08, 0x50, 0x72, 0x69, 0x6f, 0x72, 0x69, 0x74, 0x79, 0x12, 0x1e, 0x0a, + 0x0a, 0x43, 0x6f, 0x6c, 0x6c, 0x61, 0x70, 0x73, 0x65, 0x49, 0x44, 0x18, 0x07, 0x20, 0x01, 0x28, + 0x09, 0x52, 0x0a, 0x43, 0x6f, 0x6c, 0x6c, 0x61, 0x70, 0x73, 0x65, 0x49, 0x44, 0x12, 0x1c, 0x0a, + 0x09, 0x43, 0x6f, 0x6e, 0x64, 0x69, 0x74, 0x69, 0x6f, 0x6e, 0x18, 0x08, 0x20, 0x01, 0x28, 0x09, + 0x52, 0x09, 0x43, 0x6f, 0x6e, 0x64, 0x69, 0x74, 0x69, 0x6f, 0x6e, 0x12, 0x14, 0x0a, 0x05, 0x53, + 0x6f, 0x75, 0x6e, 0x64, 0x18, 0x09, 0x20, 0x01, 0x28, 0x09, 0x52, 0x05, 0x53, 0x6f, 0x75, 0x6e, + 0x64, 0x12, 0x12, 0x0a, 0x04, 0x49, 0x63, 0x6f, 0x6e, 0x18, 0x0a, 0x20, 0x01, 0x28, 0x09, 0x52, + 0x04, 0x49, 0x63, 0x6f, 0x6e, 0x12, 0x38, 0x0a, 0x04, 0x44, 0x61, 0x74, 0x61, 0x18, 0x0b, 0x20, + 0x03, 0x28, 0x0b, 0x32, 0x24, 0x2e, 0x76, 0x31, 0x2e, 0x41, 0x6e, 0x64, 0x72, 0x6f, 0x69, 0x64, + 0x50, 0x75, 0x73, 0x68, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x44, 0x61, 0x74, 0x61, 0x2e, + 0x44, 0x61, 0x74, 0x61, 0x45, 0x6e, 0x74, 0x72, 0x79, 0x52, 0x04, 0x44, 0x61, 0x74, 0x61, 0x1a, + 0x37, 0x0a, 0x09, 0x44, 0x61, 0x74, 0x61, 0x45, 0x6e, 0x74, 0x72, 0x79, 0x12, 0x10, 0x0a, 0x03, + 0x6b, 0x65, 0x79, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x03, 0x6b, 0x65, 0x79, 0x12, 0x14, + 0x0a, 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x05, 0x76, + 0x61, 0x6c, 0x75, 0x65, 0x3a, 0x02, 0x38, 0x01, 0x22, 0xd9, 0x02, 0x0a, 0x15, 0x48, 0x75, 0x61, + 0x77, 0x65, 0x69, 0x50, 0x75, 0x73, 0x68, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x44, 0x61, + 0x74, 0x61, 0x12, 0x1c, 0x0a, 0x04, 0x4d, 0x65, 0x74, 0x61, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, + 0x32, 0x08, 0x2e, 0x76, 0x31, 0x2e, 0x4d, 0x65, 0x74, 0x61, 0x52, 0x04, 0x4d, 0x65, 0x74, 0x61, + 0x12, 0x14, 0x0a, 0x05, 0x54, 0x69, 0x74, 0x6c, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, + 0x05, 0x54, 0x69, 0x74, 0x6c, 0x65, 0x12, 0x18, 0x0a, 0x07, 0x43, 0x6f, 0x6e, 0x74, 0x65, 0x6e, + 0x74, 0x18, 0x03, 0x20, 0x01, 0x28, 0x09, 0x52, 0x07, 0x43, 0x6f, 0x6e, 0x74, 0x65, 0x6e, 0x74, + 0x12, 0x1a, 0x0a, 0x08, 0x43, 0x61, 0x74, 0x65, 0x67, 0x6f, 0x72, 0x79, 0x18, 0x04, 0x20, 0x01, + 0x28, 0x09, 0x52, 0x08, 0x43, 0x61, 0x74, 0x65, 0x67, 0x6f, 0x72, 0x79, 0x12, 0x1a, 0x0a, 0x08, + 0x50, 0x72, 0x69, 0x6f, 0x72, 0x69, 0x74, 0x79, 0x18, 0x05, 0x20, 0x01, 0x28, 0x09, 0x52, 0x08, + 0x50, 0x72, 0x69, 0x6f, 0x72, 0x69, 0x74, 0x79, 0x12, 0x12, 0x0a, 0x04, 0x49, 0x63, 0x6f, 0x6e, + 0x18, 0x06, 0x20, 0x01, 0x28, 0x09, 0x52, 0x04, 0x49, 0x63, 0x6f, 0x6e, 0x12, 0x14, 0x0a, 0x05, + 0x53, 0x6f, 0x75, 0x6e, 0x64, 0x18, 0x07, 0x20, 0x01, 0x28, 0x09, 0x52, 0x05, 0x53, 0x6f, 0x75, + 0x6e, 0x64, 0x12, 0x10, 0x0a, 0x03, 0x54, 0x54, 0x4c, 0x18, 0x08, 0x20, 0x01, 0x28, 0x03, 0x52, + 0x03, 0x54, 0x54, 0x4c, 0x12, 0x1e, 0x0a, 0x0a, 0x46, 0x6f, 0x72, 0x65, 0x67, 0x72, 0x6f, 0x75, + 0x6e, 0x64, 0x18, 0x09, 0x20, 0x01, 0x28, 0x08, 0x52, 0x0a, 0x46, 0x6f, 0x72, 0x65, 0x67, 0x72, + 0x6f, 0x75, 0x6e, 0x64, 0x12, 0x31, 0x0a, 0x0b, 0x43, 0x6c, 0x69, 0x63, 0x6b, 0x41, 0x63, 0x74, + 0x69, 0x6f, 0x6e, 0x18, 0x0a, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x0f, 0x2e, 0x76, 0x31, 0x2e, 0x43, + 0x6c, 0x69, 0x63, 0x6b, 0x41, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x52, 0x0b, 0x43, 0x6c, 0x69, 0x63, + 0x6b, 0x41, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x12, 0x2b, 0x0a, 0x05, 0x42, 0x61, 0x64, 0x67, 0x65, + 0x18, 0x0b, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x15, 0x2e, 0x76, 0x31, 0x2e, 0x42, 0x61, 0x64, 0x67, + 0x65, 0x4e, 0x6f, 0x74, 0x69, 0x66, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x52, 0x05, 0x42, + 0x61, 0x64, 0x67, 0x65, 0x22, 0x9a, 0x02, 0x0a, 0x15, 0x58, 0x69, 0x61, 0x6f, 0x6d, 0x69, 0x50, + 0x75, 0x73, 0x68, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x44, 0x61, 0x74, 0x61, 0x12, 0x1c, + 0x0a, 0x04, 0x4d, 0x65, 0x74, 0x61, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x08, 0x2e, 0x76, + 0x31, 0x2e, 0x4d, 0x65, 0x74, 0x61, 0x52, 0x04, 0x4d, 0x65, 0x74, 0x61, 0x12, 0x14, 0x0a, 0x05, + 0x54, 0x69, 0x74, 0x6c, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x05, 0x54, 0x69, 0x74, + 0x6c, 0x65, 0x12, 0x1a, 0x0a, 0x08, 0x53, 0x75, 0x62, 0x74, 0x69, 0x74, 0x6c, 0x65, 0x18, 0x03, + 0x20, 0x01, 0x28, 0x09, 0x52, 0x08, 0x53, 0x75, 0x62, 0x74, 0x69, 0x74, 0x6c, 0x65, 0x12, 0x18, + 0x0a, 0x07, 0x43, 0x6f, 0x6e, 0x74, 0x65, 0x6e, 0x74, 0x18, 0x04, 0x20, 0x01, 0x28, 0x09, 0x52, + 0x07, 0x43, 0x6f, 0x6e, 0x74, 0x65, 0x6e, 0x74, 0x12, 0x1e, 0x0a, 0x0a, 0x46, 0x6f, 0x72, 0x65, + 0x67, 0x72, 0x6f, 0x75, 0x6e, 0x64, 0x18, 0x05, 0x20, 0x01, 0x28, 0x08, 0x52, 0x0a, 0x46, 0x6f, + 0x72, 0x65, 0x67, 0x72, 0x6f, 0x75, 0x6e, 0x64, 0x12, 0x12, 0x0a, 0x04, 0x49, 0x63, 0x6f, 0x6e, + 0x18, 0x06, 0x20, 0x01, 0x28, 0x09, 0x52, 0x04, 0x49, 0x63, 0x6f, 0x6e, 0x12, 0x10, 0x0a, 0x03, + 0x54, 0x54, 0x4c, 0x18, 0x07, 0x20, 0x01, 0x28, 0x03, 0x52, 0x03, 0x54, 0x54, 0x4c, 0x12, 0x1e, + 0x0a, 0x0a, 0x4e, 0x6f, 0x74, 0x69, 0x66, 0x79, 0x54, 0x79, 0x70, 0x65, 0x18, 0x08, 0x20, 0x01, + 0x28, 0x05, 0x52, 0x0a, 0x4e, 0x6f, 0x74, 0x69, 0x66, 0x79, 0x54, 0x79, 0x70, 0x65, 0x12, 0x31, + 0x0a, 0x0b, 0x43, 0x6c, 0x69, 0x63, 0x6b, 0x41, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x18, 0x09, 0x20, + 0x01, 0x28, 0x0b, 0x32, 0x0f, 0x2e, 0x76, 0x31, 0x2e, 0x43, 0x6c, 0x69, 0x63, 0x6b, 0x41, 0x63, + 0x74, 0x69, 0x6f, 0x6e, 0x52, 0x0b, 0x43, 0x6c, 0x69, 0x63, 0x6b, 0x41, 0x63, 0x74, 0x69, 0x6f, + 0x6e, 0x22, 0x88, 0x03, 0x0a, 0x13, 0x4f, 0x70, 0x70, 0x6f, 0x50, 0x75, 0x73, 0x68, 0x52, 0x65, + 0x71, 0x75, 0x65, 0x73, 0x74, 0x44, 0x61, 0x74, 0x61, 0x12, 0x1c, 0x0a, 0x04, 0x4d, 0x65, 0x74, + 0x61, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x08, 0x2e, 0x76, 0x31, 0x2e, 0x4d, 0x65, 0x74, + 0x61, 0x52, 0x04, 0x4d, 0x65, 0x74, 0x61, 0x12, 0x1e, 0x0a, 0x0a, 0x46, 0x6f, 0x72, 0x65, 0x67, + 0x72, 0x6f, 0x75, 0x6e, 0x64, 0x18, 0x02, 0x20, 0x01, 0x28, 0x08, 0x52, 0x0a, 0x46, 0x6f, 0x72, + 0x65, 0x67, 0x72, 0x6f, 0x75, 0x6e, 0x64, 0x12, 0x14, 0x0a, 0x05, 0x54, 0x69, 0x74, 0x6c, 0x65, + 0x18, 0x03, 0x20, 0x01, 0x28, 0x09, 0x52, 0x05, 0x54, 0x69, 0x74, 0x6c, 0x65, 0x12, 0x1a, 0x0a, + 0x08, 0x53, 0x75, 0x62, 0x74, 0x69, 0x74, 0x6c, 0x65, 0x18, 0x04, 0x20, 0x01, 0x28, 0x09, 0x52, + 0x08, 0x53, 0x75, 0x62, 0x74, 0x69, 0x74, 0x6c, 0x65, 0x12, 0x18, 0x0a, 0x07, 0x43, 0x6f, 0x6e, + 0x74, 0x65, 0x6e, 0x74, 0x18, 0x05, 0x20, 0x01, 0x28, 0x09, 0x52, 0x07, 0x43, 0x6f, 0x6e, 0x74, + 0x65, 0x6e, 0x74, 0x12, 0x10, 0x0a, 0x03, 0x54, 0x54, 0x4c, 0x18, 0x06, 0x20, 0x01, 0x28, 0x03, + 0x52, 0x03, 0x54, 0x54, 0x4c, 0x12, 0x1e, 0x0a, 0x0a, 0x4e, 0x6f, 0x74, 0x69, 0x66, 0x79, 0x54, + 0x79, 0x70, 0x65, 0x18, 0x07, 0x20, 0x01, 0x28, 0x05, 0x52, 0x0a, 0x4e, 0x6f, 0x74, 0x69, 0x66, + 0x79, 0x54, 0x79, 0x70, 0x65, 0x12, 0x12, 0x0a, 0x04, 0x49, 0x63, 0x6f, 0x6e, 0x18, 0x08, 0x20, + 0x01, 0x28, 0x09, 0x52, 0x04, 0x49, 0x63, 0x6f, 0x6e, 0x12, 0x31, 0x0a, 0x0b, 0x43, 0x6c, 0x69, + 0x63, 0x6b, 0x41, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x18, 0x09, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x0f, + 0x2e, 0x76, 0x31, 0x2e, 0x43, 0x6c, 0x69, 0x63, 0x6b, 0x41, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x52, + 0x0b, 0x43, 0x6c, 0x69, 0x63, 0x6b, 0x41, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x12, 0x35, 0x0a, 0x04, + 0x44, 0x61, 0x74, 0x61, 0x18, 0x0a, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x21, 0x2e, 0x76, 0x31, 0x2e, + 0x4f, 0x70, 0x70, 0x6f, 0x50, 0x75, 0x73, 0x68, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x44, + 0x61, 0x74, 0x61, 0x2e, 0x44, 0x61, 0x74, 0x61, 0x45, 0x6e, 0x74, 0x72, 0x79, 0x52, 0x04, 0x44, + 0x61, 0x74, 0x61, 0x1a, 0x37, 0x0a, 0x09, 0x44, 0x61, 0x74, 0x61, 0x45, 0x6e, 0x74, 0x72, 0x79, + 0x12, 0x10, 0x0a, 0x03, 0x6b, 0x65, 0x79, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x03, 0x6b, + 0x65, 0x79, 0x12, 0x14, 0x0a, 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, + 0x09, 0x52, 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x3a, 0x02, 0x38, 0x01, 0x22, 0xa8, 0x03, 0x0a, + 0x13, 0x56, 0x69, 0x76, 0x6f, 0x50, 0x75, 0x73, 0x68, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, + 0x44, 0x61, 0x74, 0x61, 0x12, 0x1c, 0x0a, 0x04, 0x4d, 0x65, 0x74, 0x61, 0x18, 0x01, 0x20, 0x01, + 0x28, 0x0b, 0x32, 0x08, 0x2e, 0x76, 0x31, 0x2e, 0x4d, 0x65, 0x74, 0x61, 0x52, 0x04, 0x4d, 0x65, + 0x74, 0x61, 0x12, 0x1e, 0x0a, 0x0a, 0x46, 0x6f, 0x72, 0x65, 0x67, 0x72, 0x6f, 0x75, 0x6e, 0x64, + 0x18, 0x02, 0x20, 0x01, 0x28, 0x08, 0x52, 0x0a, 0x46, 0x6f, 0x72, 0x65, 0x67, 0x72, 0x6f, 0x75, + 0x6e, 0x64, 0x12, 0x10, 0x0a, 0x03, 0x54, 0x54, 0x4c, 0x18, 0x04, 0x20, 0x01, 0x28, 0x03, 0x52, + 0x03, 0x54, 0x54, 0x4c, 0x12, 0x1e, 0x0a, 0x0a, 0x4e, 0x6f, 0x74, 0x69, 0x66, 0x79, 0x54, 0x79, + 0x70, 0x65, 0x18, 0x05, 0x20, 0x01, 0x28, 0x05, 0x52, 0x0a, 0x4e, 0x6f, 0x74, 0x69, 0x66, 0x79, + 0x54, 0x79, 0x70, 0x65, 0x12, 0x1a, 0x0a, 0x08, 0x4e, 0x6f, 0x74, 0x69, 0x66, 0x79, 0x49, 0x44, + 0x18, 0x06, 0x20, 0x01, 0x28, 0x05, 0x52, 0x08, 0x4e, 0x6f, 0x74, 0x69, 0x66, 0x79, 0x49, 0x44, + 0x12, 0x14, 0x0a, 0x05, 0x54, 0x69, 0x74, 0x6c, 0x65, 0x18, 0x07, 0x20, 0x01, 0x28, 0x09, 0x52, + 0x05, 0x54, 0x69, 0x74, 0x6c, 0x65, 0x12, 0x18, 0x0a, 0x07, 0x43, 0x6f, 0x6e, 0x74, 0x65, 0x6e, + 0x74, 0x18, 0x08, 0x20, 0x01, 0x28, 0x09, 0x52, 0x07, 0x43, 0x6f, 0x6e, 0x74, 0x65, 0x6e, 0x74, + 0x12, 0x1a, 0x0a, 0x08, 0x43, 0x61, 0x74, 0x65, 0x67, 0x6f, 0x72, 0x79, 0x18, 0x09, 0x20, 0x01, + 0x28, 0x09, 0x52, 0x08, 0x43, 0x61, 0x74, 0x65, 0x67, 0x6f, 0x72, 0x79, 0x12, 0x16, 0x0a, 0x06, + 0x54, 0x61, 0x73, 0x6b, 0x49, 0x64, 0x18, 0x0a, 0x20, 0x01, 0x28, 0x09, 0x52, 0x06, 0x54, 0x61, + 0x73, 0x6b, 0x49, 0x64, 0x12, 0x31, 0x0a, 0x0b, 0x43, 0x6c, 0x69, 0x63, 0x6b, 0x41, 0x63, 0x74, + 0x69, 0x6f, 0x6e, 0x18, 0x0b, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x0f, 0x2e, 0x76, 0x31, 0x2e, 0x43, + 0x6c, 0x69, 0x63, 0x6b, 0x41, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x52, 0x0b, 0x43, 0x6c, 0x69, 0x63, + 0x6b, 0x41, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x12, 0x35, 0x0a, 0x04, 0x44, 0x61, 0x74, 0x61, 0x18, + 0x0c, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x21, 0x2e, 0x76, 0x31, 0x2e, 0x56, 0x69, 0x76, 0x6f, 0x50, + 0x75, 0x73, 0x68, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x44, 0x61, 0x74, 0x61, 0x2e, 0x44, + 0x61, 0x74, 0x61, 0x45, 0x6e, 0x74, 0x72, 0x79, 0x52, 0x04, 0x44, 0x61, 0x74, 0x61, 0x1a, 0x37, + 0x0a, 0x09, 0x44, 0x61, 0x74, 0x61, 0x45, 0x6e, 0x74, 0x72, 0x79, 0x12, 0x10, 0x0a, 0x03, 0x6b, + 0x65, 0x79, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x03, 0x6b, 0x65, 0x79, 0x12, 0x14, 0x0a, + 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x05, 0x76, 0x61, + 0x6c, 0x75, 0x65, 0x3a, 0x02, 0x38, 0x01, 0x22, 0xe9, 0x01, 0x0a, 0x0b, 0x43, 0x6c, 0x69, 0x63, + 0x6b, 0x41, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x12, 0x16, 0x0a, 0x06, 0x41, 0x63, 0x74, 0x69, 0x6f, + 0x6e, 0x18, 0x01, 0x20, 0x01, 0x28, 0x05, 0x52, 0x06, 0x41, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x12, + 0x1a, 0x0a, 0x08, 0x41, 0x63, 0x74, 0x69, 0x76, 0x69, 0x74, 0x79, 0x18, 0x02, 0x20, 0x01, 0x28, + 0x09, 0x52, 0x08, 0x41, 0x63, 0x74, 0x69, 0x76, 0x69, 0x74, 0x79, 0x12, 0x10, 0x0a, 0x03, 0x55, + 0x72, 0x6c, 0x18, 0x03, 0x20, 0x01, 0x28, 0x09, 0x52, 0x03, 0x55, 0x72, 0x6c, 0x12, 0x3f, 0x0a, + 0x0a, 0x50, 0x61, 0x72, 0x61, 0x6d, 0x65, 0x74, 0x65, 0x72, 0x73, 0x18, 0x04, 0x20, 0x03, 0x28, + 0x0b, 0x32, 0x1f, 0x2e, 0x76, 0x31, 0x2e, 0x43, 0x6c, 0x69, 0x63, 0x6b, 0x41, 0x63, 0x74, 0x69, + 0x6f, 0x6e, 0x2e, 0x50, 0x61, 0x72, 0x61, 0x6d, 0x65, 0x74, 0x65, 0x72, 0x73, 0x45, 0x6e, 0x74, + 0x72, 0x79, 0x52, 0x0a, 0x50, 0x61, 0x72, 0x61, 0x6d, 0x65, 0x74, 0x65, 0x72, 0x73, 0x1a, 0x53, + 0x0a, 0x0f, 0x50, 0x61, 0x72, 0x61, 0x6d, 0x65, 0x74, 0x65, 0x72, 0x73, 0x45, 0x6e, 0x74, 0x72, + 0x79, 0x12, 0x10, 0x0a, 0x03, 0x6b, 0x65, 0x79, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x03, + 0x6b, 0x65, 0x79, 0x12, 0x2a, 0x0a, 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x18, 0x02, 0x20, 0x01, + 0x28, 0x0b, 0x32, 0x14, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x70, 0x72, 0x6f, 0x74, + 0x6f, 0x62, 0x75, 0x66, 0x2e, 0x41, 0x6e, 0x79, 0x52, 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x3a, + 0x02, 0x38, 0x01, 0x22, 0xda, 0x02, 0x0a, 0x14, 0x4d, 0x65, 0x69, 0x7a, 0x75, 0x50, 0x75, 0x73, + 0x68, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x44, 0x61, 0x74, 0x61, 0x12, 0x1c, 0x0a, 0x04, + 0x4d, 0x65, 0x74, 0x61, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x08, 0x2e, 0x76, 0x31, 0x2e, + 0x4d, 0x65, 0x74, 0x61, 0x52, 0x04, 0x4d, 0x65, 0x74, 0x61, 0x12, 0x14, 0x0a, 0x05, 0x54, 0x69, + 0x74, 0x6c, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x05, 0x54, 0x69, 0x74, 0x6c, 0x65, + 0x12, 0x18, 0x0a, 0x07, 0x43, 0x6f, 0x6e, 0x74, 0x65, 0x6e, 0x74, 0x18, 0x03, 0x20, 0x01, 0x28, + 0x09, 0x52, 0x07, 0x43, 0x6f, 0x6e, 0x74, 0x65, 0x6e, 0x74, 0x12, 0x10, 0x0a, 0x03, 0x54, 0x54, + 0x4c, 0x18, 0x04, 0x20, 0x01, 0x28, 0x03, 0x52, 0x03, 0x54, 0x54, 0x4c, 0x12, 0x1e, 0x0a, 0x0a, + 0x4e, 0x6f, 0x74, 0x69, 0x66, 0x79, 0x54, 0x79, 0x70, 0x65, 0x18, 0x05, 0x20, 0x01, 0x28, 0x05, + 0x52, 0x0a, 0x4e, 0x6f, 0x74, 0x69, 0x66, 0x79, 0x54, 0x79, 0x70, 0x65, 0x12, 0x1e, 0x0a, 0x0a, + 0x46, 0x6f, 0x72, 0x65, 0x67, 0x72, 0x6f, 0x75, 0x6e, 0x64, 0x18, 0x06, 0x20, 0x01, 0x28, 0x08, + 0x52, 0x0a, 0x46, 0x6f, 0x72, 0x65, 0x67, 0x72, 0x6f, 0x75, 0x6e, 0x64, 0x12, 0x31, 0x0a, 0x0b, + 0x43, 0x6c, 0x69, 0x63, 0x6b, 0x41, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x18, 0x0a, 0x20, 0x01, 0x28, + 0x0b, 0x32, 0x0f, 0x2e, 0x76, 0x31, 0x2e, 0x43, 0x6c, 0x69, 0x63, 0x6b, 0x41, 0x63, 0x74, 0x69, + 0x6f, 0x6e, 0x52, 0x0b, 0x43, 0x6c, 0x69, 0x63, 0x6b, 0x41, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x12, + 0x36, 0x0a, 0x04, 0x44, 0x61, 0x74, 0x61, 0x18, 0x0b, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x22, 0x2e, + 0x76, 0x31, 0x2e, 0x4d, 0x65, 0x69, 0x7a, 0x75, 0x50, 0x75, 0x73, 0x68, 0x52, 0x65, 0x71, 0x75, + 0x65, 0x73, 0x74, 0x44, 0x61, 0x74, 0x61, 0x2e, 0x44, 0x61, 0x74, 0x61, 0x45, 0x6e, 0x74, 0x72, + 0x79, 0x52, 0x04, 0x44, 0x61, 0x74, 0x61, 0x1a, 0x37, 0x0a, 0x09, 0x44, 0x61, 0x74, 0x61, 0x45, + 0x6e, 0x74, 0x72, 0x79, 0x12, 0x10, 0x0a, 0x03, 0x6b, 0x65, 0x79, 0x18, 0x01, 0x20, 0x01, 0x28, + 0x09, 0x52, 0x03, 0x6b, 0x65, 0x79, 0x12, 0x14, 0x0a, 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x18, + 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x3a, 0x02, 0x38, 0x01, + 0x22, 0xc1, 0x03, 0x0a, 0x14, 0x48, 0x6f, 0x6e, 0x6f, 0x72, 0x50, 0x75, 0x73, 0x68, 0x52, 0x65, + 0x71, 0x75, 0x65, 0x73, 0x74, 0x44, 0x61, 0x74, 0x61, 0x12, 0x1c, 0x0a, 0x04, 0x4d, 0x65, 0x74, + 0x61, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x08, 0x2e, 0x76, 0x31, 0x2e, 0x4d, 0x65, 0x74, + 0x61, 0x52, 0x04, 0x4d, 0x65, 0x74, 0x61, 0x12, 0x14, 0x0a, 0x05, 0x54, 0x69, 0x74, 0x6c, 0x65, + 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x05, 0x54, 0x69, 0x74, 0x6c, 0x65, 0x12, 0x18, 0x0a, + 0x07, 0x43, 0x6f, 0x6e, 0x74, 0x65, 0x6e, 0x74, 0x18, 0x03, 0x20, 0x01, 0x28, 0x09, 0x52, 0x07, + 0x43, 0x6f, 0x6e, 0x74, 0x65, 0x6e, 0x74, 0x12, 0x12, 0x0a, 0x04, 0x49, 0x63, 0x6f, 0x6e, 0x18, + 0x04, 0x20, 0x01, 0x28, 0x09, 0x52, 0x04, 0x49, 0x63, 0x6f, 0x6e, 0x12, 0x10, 0x0a, 0x03, 0x54, + 0x61, 0x67, 0x18, 0x05, 0x20, 0x01, 0x28, 0x09, 0x52, 0x03, 0x54, 0x61, 0x67, 0x12, 0x14, 0x0a, + 0x05, 0x47, 0x72, 0x6f, 0x75, 0x70, 0x18, 0x06, 0x20, 0x01, 0x28, 0x09, 0x52, 0x05, 0x47, 0x72, + 0x6f, 0x75, 0x70, 0x12, 0x1a, 0x0a, 0x08, 0x4e, 0x6f, 0x74, 0x69, 0x66, 0x79, 0x49, 0x64, 0x18, + 0x07, 0x20, 0x01, 0x28, 0x05, 0x52, 0x08, 0x4e, 0x6f, 0x74, 0x69, 0x66, 0x79, 0x49, 0x64, 0x12, + 0x10, 0x0a, 0x03, 0x54, 0x54, 0x4c, 0x18, 0x08, 0x20, 0x01, 0x28, 0x03, 0x52, 0x03, 0x54, 0x54, + 0x4c, 0x12, 0x20, 0x0a, 0x0b, 0x44, 0x65, 0x76, 0x65, 0x6c, 0x6f, 0x70, 0x6d, 0x65, 0x6e, 0x74, + 0x18, 0x09, 0x20, 0x01, 0x28, 0x08, 0x52, 0x0b, 0x44, 0x65, 0x76, 0x65, 0x6c, 0x6f, 0x70, 0x6d, + 0x65, 0x6e, 0x74, 0x12, 0x31, 0x0a, 0x0b, 0x43, 0x6c, 0x69, 0x63, 0x6b, 0x41, 0x63, 0x74, 0x69, + 0x6f, 0x6e, 0x18, 0x0a, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x0f, 0x2e, 0x76, 0x31, 0x2e, 0x43, 0x6c, + 0x69, 0x63, 0x6b, 0x41, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x52, 0x0b, 0x43, 0x6c, 0x69, 0x63, 0x6b, + 0x41, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x12, 0x2b, 0x0a, 0x05, 0x42, 0x61, 0x64, 0x67, 0x65, 0x18, + 0x0b, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x15, 0x2e, 0x76, 0x31, 0x2e, 0x42, 0x61, 0x64, 0x67, 0x65, + 0x4e, 0x6f, 0x74, 0x69, 0x66, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x52, 0x05, 0x42, 0x61, + 0x64, 0x67, 0x65, 0x12, 0x36, 0x0a, 0x04, 0x44, 0x61, 0x74, 0x61, 0x18, 0x0c, 0x20, 0x03, 0x28, + 0x0b, 0x32, 0x22, 0x2e, 0x76, 0x31, 0x2e, 0x48, 0x6f, 0x6e, 0x6f, 0x72, 0x50, 0x75, 0x73, 0x68, + 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x44, 0x61, 0x74, 0x61, 0x2e, 0x44, 0x61, 0x74, 0x61, + 0x45, 0x6e, 0x74, 0x72, 0x79, 0x52, 0x04, 0x44, 0x61, 0x74, 0x61, 0x1a, 0x37, 0x0a, 0x09, 0x44, + 0x61, 0x74, 0x61, 0x45, 0x6e, 0x74, 0x72, 0x79, 0x12, 0x10, 0x0a, 0x03, 0x6b, 0x65, 0x79, 0x18, + 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x03, 0x6b, 0x65, 0x79, 0x12, 0x14, 0x0a, 0x05, 0x76, 0x61, + 0x6c, 0x75, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, + 0x3a, 0x02, 0x38, 0x01, 0x22, 0x59, 0x0a, 0x11, 0x42, 0x61, 0x64, 0x67, 0x65, 0x4e, 0x6f, 0x74, + 0x69, 0x66, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x12, 0x16, 0x0a, 0x06, 0x41, 0x64, 0x64, + 0x4e, 0x75, 0x6d, 0x18, 0x01, 0x20, 0x01, 0x28, 0x05, 0x52, 0x06, 0x41, 0x64, 0x64, 0x4e, 0x75, + 0x6d, 0x12, 0x16, 0x0a, 0x06, 0x53, 0x65, 0x74, 0x4e, 0x75, 0x6d, 0x18, 0x02, 0x20, 0x01, 0x28, + 0x05, 0x52, 0x06, 0x53, 0x65, 0x74, 0x4e, 0x75, 0x6d, 0x12, 0x14, 0x0a, 0x05, 0x43, 0x6c, 0x61, + 0x73, 0x73, 0x18, 0x03, 0x20, 0x01, 0x28, 0x09, 0x52, 0x05, 0x43, 0x6c, 0x61, 0x73, 0x73, 0x32, + 0x3a, 0x0a, 0x0b, 0x50, 0x75, 0x73, 0x68, 0x53, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x12, 0x2b, + 0x0a, 0x04, 0x50, 0x75, 0x73, 0x68, 0x12, 0x0f, 0x2e, 0x76, 0x31, 0x2e, 0x50, 0x75, 0x73, 0x68, + 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x10, 0x2e, 0x76, 0x31, 0x2e, 0x50, 0x75, 0x73, + 0x68, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x00, 0x42, 0x07, 0x5a, 0x05, 0x2e, + 0x2f, 0x3b, 0x76, 0x31, 0x62, 0x06, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x33, +} + +var ( + file_push_proto_rawDescOnce sync.Once + file_push_proto_rawDescData = file_push_proto_rawDesc +) + +func file_push_proto_rawDescGZIP() []byte { + file_push_proto_rawDescOnce.Do(func() { + file_push_proto_rawDescData = protoimpl.X.CompressGZIP(file_push_proto_rawDescData) + }) + return file_push_proto_rawDescData +} + +var file_push_proto_msgTypes = make([]protoimpl.MessageInfo, 20) +var file_push_proto_goTypes = []interface{}{ + (*PushOption)(nil), // 0: v1.PushOption + (*PushRequest)(nil), // 1: v1.PushRequest + (*PushResponse)(nil), // 2: v1.PushResponse + (*Meta)(nil), // 3: v1.Meta + (*APNsPushRequest)(nil), // 4: v1.APNsPushRequest + (*AndroidPushRequestData)(nil), // 5: v1.AndroidPushRequestData + (*HuaweiPushRequestData)(nil), // 6: v1.HuaweiPushRequestData + (*XiaomiPushRequestData)(nil), // 7: v1.XiaomiPushRequestData + (*OppoPushRequestData)(nil), // 8: v1.OppoPushRequestData + (*VivoPushRequestData)(nil), // 9: v1.VivoPushRequestData + (*ClickAction)(nil), // 10: v1.ClickAction + (*MeizuPushRequestData)(nil), // 11: v1.MeizuPushRequestData + (*HonorPushRequestData)(nil), // 12: v1.HonorPushRequestData + (*BadgeNotification)(nil), // 13: v1.BadgeNotification + nil, // 14: v1.AndroidPushRequestData.DataEntry + nil, // 15: v1.OppoPushRequestData.DataEntry + nil, // 16: v1.VivoPushRequestData.DataEntry + nil, // 17: v1.ClickAction.ParametersEntry + nil, // 18: v1.MeizuPushRequestData.DataEntry + nil, // 19: v1.HonorPushRequestData.DataEntry + (*structpb.Struct)(nil), // 20: google.protobuf.Struct + (*anypb.Any)(nil), // 21: google.protobuf.Any +} +var file_push_proto_depIdxs = []int32{ + 20, // 0: v1.PushRequest.Data:type_name -> google.protobuf.Struct + 0, // 1: v1.PushRequest.Option:type_name -> v1.PushOption + 20, // 2: v1.PushResponse.Data:type_name -> google.protobuf.Struct + 3, // 3: v1.APNsPushRequest.meta:type_name -> v1.Meta + 20, // 4: v1.APNsPushRequest.Sound:type_name -> google.protobuf.Struct + 20, // 5: v1.APNsPushRequest.Data:type_name -> google.protobuf.Struct + 3, // 6: v1.AndroidPushRequestData.Meta:type_name -> v1.Meta + 14, // 7: v1.AndroidPushRequestData.Data:type_name -> v1.AndroidPushRequestData.DataEntry + 3, // 8: v1.HuaweiPushRequestData.Meta:type_name -> v1.Meta + 10, // 9: v1.HuaweiPushRequestData.ClickAction:type_name -> v1.ClickAction + 13, // 10: v1.HuaweiPushRequestData.Badge:type_name -> v1.BadgeNotification + 3, // 11: v1.XiaomiPushRequestData.Meta:type_name -> v1.Meta + 10, // 12: v1.XiaomiPushRequestData.ClickAction:type_name -> v1.ClickAction + 3, // 13: v1.OppoPushRequestData.Meta:type_name -> v1.Meta + 10, // 14: v1.OppoPushRequestData.ClickAction:type_name -> v1.ClickAction + 15, // 15: v1.OppoPushRequestData.Data:type_name -> v1.OppoPushRequestData.DataEntry + 3, // 16: v1.VivoPushRequestData.Meta:type_name -> v1.Meta + 10, // 17: v1.VivoPushRequestData.ClickAction:type_name -> v1.ClickAction + 16, // 18: v1.VivoPushRequestData.Data:type_name -> v1.VivoPushRequestData.DataEntry + 17, // 19: v1.ClickAction.Parameters:type_name -> v1.ClickAction.ParametersEntry + 3, // 20: v1.MeizuPushRequestData.Meta:type_name -> v1.Meta + 10, // 21: v1.MeizuPushRequestData.ClickAction:type_name -> v1.ClickAction + 18, // 22: v1.MeizuPushRequestData.Data:type_name -> v1.MeizuPushRequestData.DataEntry + 3, // 23: v1.HonorPushRequestData.Meta:type_name -> v1.Meta + 10, // 24: v1.HonorPushRequestData.ClickAction:type_name -> v1.ClickAction + 13, // 25: v1.HonorPushRequestData.Badge:type_name -> v1.BadgeNotification + 19, // 26: v1.HonorPushRequestData.Data:type_name -> v1.HonorPushRequestData.DataEntry + 21, // 27: v1.ClickAction.ParametersEntry.value:type_name -> google.protobuf.Any + 1, // 28: v1.PushService.Push:input_type -> v1.PushRequest + 2, // 29: v1.PushService.Push:output_type -> v1.PushResponse + 29, // [29:30] is the sub-list for method output_type + 28, // [28:29] is the sub-list for method input_type + 28, // [28:28] is the sub-list for extension type_name + 28, // [28:28] is the sub-list for extension extendee + 0, // [0:28] is the sub-list for field type_name +} + +func init() { file_push_proto_init() } +func file_push_proto_init() { + if File_push_proto != nil { + return + } + if !protoimpl.UnsafeEnabled { + file_push_proto_msgTypes[0].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*PushOption); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + file_push_proto_msgTypes[1].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*PushRequest); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + file_push_proto_msgTypes[2].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*PushResponse); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + file_push_proto_msgTypes[3].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*Meta); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + file_push_proto_msgTypes[4].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*APNsPushRequest); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + file_push_proto_msgTypes[5].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*AndroidPushRequestData); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + file_push_proto_msgTypes[6].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*HuaweiPushRequestData); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + file_push_proto_msgTypes[7].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*XiaomiPushRequestData); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + file_push_proto_msgTypes[8].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*OppoPushRequestData); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + file_push_proto_msgTypes[9].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*VivoPushRequestData); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + file_push_proto_msgTypes[10].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*ClickAction); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + file_push_proto_msgTypes[11].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*MeizuPushRequestData); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + file_push_proto_msgTypes[12].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*HonorPushRequestData); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + file_push_proto_msgTypes[13].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*BadgeNotification); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + } + type x struct{} + out := protoimpl.TypeBuilder{ + File: protoimpl.DescBuilder{ + GoPackagePath: reflect.TypeOf(x{}).PkgPath(), + RawDescriptor: file_push_proto_rawDesc, + NumEnums: 0, + NumMessages: 20, + NumExtensions: 0, + NumServices: 1, + }, + GoTypes: file_push_proto_goTypes, + DependencyIndexes: file_push_proto_depIdxs, + MessageInfos: file_push_proto_msgTypes, + }.Build() + File_push_proto = out.File + file_push_proto_rawDesc = nil + file_push_proto_goTypes = nil + file_push_proto_depIdxs = nil +} diff --git a/api/pb/v1/push.proto b/api/pb/v1/push.proto new file mode 100644 index 0000000..c7010d2 --- /dev/null +++ b/api/pb/v1/push.proto @@ -0,0 +1,544 @@ +syntax = "proto3"; + +import "google/protobuf/any.proto"; +import "google/protobuf/descriptor.proto"; +//import "github.com/gogo/protobuf/gogoproto/gogo.proto"; +import "google/protobuf/struct.proto"; + +package v1; +//option go_package = "github.com/cossim/hipush/api/grpc/v1"; +option go_package = "./;v1"; + +message PushOption { + // DryRun 只进行数据校验不实际推送,数据校验成功即为成功 + // @inject_tag: json:"dry_run" + bool DryRun = 1; + + // Development 测试模式推送 + // @inject_tag: json:"development" + bool Development =2; + + // Retry 重试次数 + // @inject_tag: json:"retry" + int32 Retry = 3; + + // RetryInterval 重试间隔(以秒为单位) + // @inject_tag: json:"retry_interval" + int32 RetryInterval = 4; +} + +message PushRequest { + // AppID 应用程序标识 + // ios capacitor.config文件中的appId 例如com.hitosea.apptest + // @inject_tag: json:"app_id" + string AppID = 1; + + // AppName 应用名称 + // @inject_tag: json:"app_name" + string AppName = 2; + + // Platform 推送平台 consts.Platform + // @inject_tag: json:"platform" binding:"required" + string Platform = 3; + + // Token 接收推送的设备标识 + // 例如ios为deviceToken + // vivo、oppo为RegId + // @inject_tag: json:"token" binding:"required" + repeated string Token = 4; + + // @inject_tag: json:"data" + google.protobuf.Struct Data = 5; + // bytes Data = 5[(gogoproto.customtype) = "InterfaceType", (gogoproto.nullable) = false]; // InterfaceType为自定义类型 +// bytes Data = 5; // InterfaceType为自定义类型 + + // PushOptions 推送选项 + // @inject_tag: json:"option" + PushOption Option = 6; +} + +message PushResponse { + // @inject_tag: json:"code" + int32 Code = 1; + + // @inject_tag: json:"msg" + string Msg = 2; + + // @inject_tag: json:"data" + google.protobuf.Struct Data = 3; +// bytes Data = 3[(gogoproto.customtype) = "InterfaceType", (gogoproto.nullable) = false]; // InterfaceType为自定义类型 +// bytes Data = 3; +} + +message Meta { + // @inject_tag: json:"app_id" + string AppID = 1; + // @inject_tag: json:"app_name" + string AppName = 2; + // @inject_tag: json:"token" + repeated string Token = 3; +} + +message APNsPushRequest { + // @inject_tag: json:"meta" + Meta meta = 1; + + // Title Notification Title + // @inject_tag: json:"title" + string Title = 2; + + // Content Notification Content + // @inject_tag: json:"content" + string Content = 3; + + // Topic The topic of the remote notification, which is typically the bundle ID + // for your app. The certificate you create in the Apple Developer Member + // Center must include the capability for this topic. If your certificate + // includes multiple topics, you must specify a value for this header. If + // you omit this header and your APNs certificate does not specify multiple + // topics, the APNs server uses the certificate’s Subject as the default + // topic. + // @inject_tag: json:"topic" + string Topic = 4; + + // CollapseID A string which allows multiple notifications with the same collapse + // identifier to be displayed to the user as a single notification. The + // value should not exceed 64 bytes. + // @inject_tag: json:"collapse_id" + string CollapseID = 5; + + // ApnsID An optional canonical UUID that identifies the notification. The + // canonical form is 32 lowercase hexadecimal digits, displayed in five + // groups separated by hyphens in the form 8-4-4-4-12. An example UUID is as + // follows: + // + // 123e4567-e89b-12d3-a456-42665544000 + // + // If you don't set this, a new UUID is created by APNs and returned in the + // response. + // @inject_tag: json:"apns_id" + string ApnsID = 6; + + // Priority The priority of the notification + // normal、high default normal + // @inject_tag: json:"priority" + string Priority = 7; + + // PushType apns-push-type the value of the header + // https://developer.apple.com/documentation/usernotifications/sending-notification-requests-to-apns#Know-when-to-use-push-types + // @inject_tag: json:"push_type" + string PushType = 8; + + // @inject_tag: json:"url_args" + repeated string URLArgs = 9; + + // TTL represents the expiration date of the notification. + // If the value is nonzero, it indicates that the notification is valid until the specified date. + // The value is a UNIX epoch expressed in seconds (UTC). + // If the value is nonzero, APNs stores the notification and attempts to deliver it at least once, repeating the attempt as needed until the specified date. + // If the value is 0, APNs attempts to deliver the notification only once and does not store it. + // @inject_tag: json:"ttl" + int64 TTL = 10; + + // Badge sets the aps badge on the payload. + // This will display a numeric badge on the app icon. + // @inject_tag: json:"badge" + int32 Badge = 11; + bool Development = 12; + + // MutableContent sets the aps mutable-content on the payload to 1. + // This will indicate to the to the system to call your Notification Service + // extension to mutate or replace the notification's content. + // @inject_tag: json:"mutable_content" + bool MutableContent = 13; + + // ContentAvailable sets the aps content-available on the payload to 1. + // This will indicate to the app that there is new content available to download + // and launch the app in the background. + // @inject_tag: json:"content_available" + bool ContentAvailable = 14; + + // Sound sets the aps sound on the payload. + // This will play a sound from the app bundle, or the default sound otherwise. + // https://developer.apple.com/documentation/usernotifications/generating-a-remote-notification Table 3. Keys to include in the sound dictionary + // @inject_tag: json:"sound" + google.protobuf.Struct Sound = 15; + // bytes Sound = 15[(gogoproto.customtype) = "InterfaceType", (gogoproto.nullable) = false]; // InterfaceType为自定义类型 + + // Data sets a custom key and value on the payload. + // This will add custom key/value data to the notification payload at root level. +// map data = 15; + // @inject_tag: json:"data" + google.protobuf.Struct Data = 16; +// map Data = 16[(gogoproto.customtype) = "InterfaceType", (gogoproto.nullable) = false]; // InterfaceType为自定义类型 + + // @inject_tag: json:"category" + string Category = 17; +} + + +message AndroidPushRequestData { + // @inject_tag: json:"meta" + Meta Meta = 1; + + // Title Notification Title + // @inject_tag: json:"title" + string Title = 2; + + // Content Notification Content + // @inject_tag: json:"content" + string Content = 3; + + // @inject_tag: json:"topic" + string Topic = 4; + + // TTL represents the duration for which the message is stored on the server if the user is offline. + // The value should follow a specific format indicating the time duration, such as "86400s" for 1 day, "10m" for 10 minutes, or "1h" for 1 hour. + // @inject_tag: json:"ttl" + int64 TTL = 5; + + // Priority The priority of the notification + // normal、high default normal + // @inject_tag: json:"priority" + string Priority = 6; + + // CollapseID represents the collapse identifier of the notification. + // @inject_tag: json:"collapse_id" + string CollapseID = 7; + + // Condition represents the condition for sending the notification to devices. + // @inject_tag: json:"condition" + string Condition = 8; + + // Sound represents the custom sound for the push notification. + // @inject_tag: json:"sound" + string Sound = 9; + + // Icon represents the icon associated with the push notification. + // @inject_tag: json:"icon" + string Icon = 10; + + // Data Additional Custom Parameters + // @inject_tag: json:"data" + map Data = 11; +} + +message HuaweiPushRequestData { + // @inject_tag: json:"meta" + Meta Meta = 1; + // @inject_tag: json:"title" + string Title = 2; + // @inject_tag: json:"content" + string Content = 3; + + // Category The category of the notification + // https://developer.huawei.com/consumer/cn/doc/HMSCore-References/https-send-api-0000001050986197#:~:text=%E8%BF%9B%E8%A1%8C%E7%BB%9F%E8%AE%A1%E5%88%86%E6%9E%90%E3%80%82-,category,-%E5%90%A6 + // @inject_tag: json:"category" + string Category = 4; + + // Priority The priority of the notification + // normal、high default normal + // @inject_tag: json:"priority" + string Priority = 5; + + // Icon Small icon URL + // @inject_tag: json:"icon" + string Icon = 6; + + // Sound represents the custom message notification ringtone. + // It is effective when creating a new channel. + // The ringtone file set here must be stored in the /res/raw path of the application. + // For example, setting it to "/raw/shake" corresponds to the local "/res/raw/shake.xxx" file of the application. + // Supported file formats include MP3, WAV, MPEG, etc. + // If not set, the default system ringtone will be used. + // @inject_tag: json:"sound" + string Sound = 7; + // TTL represents the message cache time in seconds. + // When the user device is offline, the message is cached on the Push server. + // If the user device reconnects to the network within the message cache time, the message will be delivered. + // After the cache time expires, the message will be discarded. + // The default value is "86400s" (1 day), and the maximum value is "1296000s" (15 days). + // @inject_tag: json:"ttl" + int64 TTL = 8; + + // Foreground When the application is in the foreground, whether the notification bar message shows the switch + // @inject_tag: json:"foreground" + bool Foreground = 9; + + ClickAction ClickAction = 10; + // @inject_tag: json:"badge" + BadgeNotification Badge = 11; +} + +// XiaomiPushRequestData +// https://dev.mi.com/console/doc/detail?pId=2776#_0 +message XiaomiPushRequestData { + // @inject_tag: json:"meta" + Meta Meta = 1; + + // @inject_tag: json:"title" + string Title = 2; + + // @inject_tag: json:"subtitle" + string Subtitle = 3; + + // @inject_tag: json:"content" + string Content = 4; + + // Foreground When the application is in the foreground, whether the notification bar message shows the switch + // @inject_tag: json:"foreground" + bool Foreground = 5; + + // Icon 消息图标,用于在通知栏上显示的图标 + // @inject_tag: json:"icon" + string Icon = 6; + + // TTL 如果用户离线,设置消息在服务器保存的时间,单位:s,服务器默认最长保留两周。 + // @inject_tag: json:"ttl" + int64 TTL = 7; + + // IsScheduled false为立即推送 true为定时推送 + // 消息会在ScheduledStart-ScheduledEnd的时间段内随机展示 +// bool IsScheduled + // ScheduledTime 定时推送的开始时间,指定消息推送的开始时间 + // 用自1970年1月1日以来00:00:00.0 UTC时间表示(以毫秒为单位的时间),仅支持七天内的定时消息。 +// int64 ScheduledTime + + // NotifyType represents the type of notification, and its value can be DEFAULT_ALL or a combination of the following: + // DEFAULT_ALL = -1; DEFAULT_SOUND = 1; + // Use the default sound for notification; DEFAULT_VIBRATE = 2; + //Use default vibration for notification; DEFAULT_LIGHTS = 4; + //Use default lights for notification. + // @inject_tag: json:"notify_type" + int32 NotifyType = 8; + + // ClickAction Click behavior for predefined notification bar messages + // "1": Open the Launcher Activity of the app after clicking on the notification in the notification bar. + // "2": Open any Activity of the app after clicking on the notification in the notification bar (the developer also needs to pass url). + // "3": Open a webpage after clicking on the notification in the notification bar. + // @inject_tag: json:"click_action" + ClickAction ClickAction = 9; + + // 附加的自定义参数 + // Data map[string]string `json:"data,omitempty"` +} + +message OppoPushRequestData { + // @inject_tag: json:"meta" + Meta Meta = 1; + // Foreground When the application is in the foreground, whether the notification bar message shows the switch + // @inject_tag: json:"foreground" + bool Foreground = 2; + + // @inject_tag: json:"title" + string Title = 3; + + // @inject_tag: json:"subtitle" + string Subtitle = 4; + + // @inject_tag: json:"content" + string Content = 5; + + // TTL 消息有效时长,即推送服务缓存消息的时长,从消息创建是开始计算,最短为1小时,最长10天 单位:s + // @inject_tag: json:"ttl" + int64 TTL = 6; + + // 通知类型 1:无,2:响铃,3:振动,4:响铃和振动 + // @inject_tag: json:"notify_type" + int32 NotifyType = 7; + + // Icon 消息图标,用于在通知栏上显示的图标 + // @inject_tag: json:"icon" + string Icon = 8; + + // ClickAction 点击动作 + // Action 点击跳转类型 1:打开APP首页 2:打开链接 3:自定义 4:打开app内指定页面 5:跳转Intentscheme URL 默认值为 0 + // 0 启动应用 + // 1 打开应用内页(activity的action标签名) + // 2 打开网页 + // 4 打开应用内页(activity 全路径类名) + // 5 Intentscheme URL + // @inject_tag: json:"click_action" + ClickAction ClickAction = 9; + + // Data Additional Custom Parameters + // @inject_tag: json:"data" + map Data = 10; +} + +// VivoPushNotification +// https://dev.vivo.com.cn/documentCenter/doc/362#:~:text=%E6%8E%A5%E5%8F%A3%E5%AE%9A%E4%B9%89-,%E8%BE%93%E5%85%A5%E5%8F%82%E6%95%B0%EF%BC%9A,-intent%20uri +message VivoPushRequestData { + // @inject_tag: json:"meta" + Meta Meta = 1; + // Foreground Whether to display notification bar messages when the app is in the foreground + // @inject_tag: json:"foreground" + bool Foreground = 2; + + // TTL The valid duration of the message, in seconds, and the duration of the push service cache message. + // @inject_tag: json:"ttl" + int64 TTL = 4; + + // NotifyType Notification Type, 1: None, 2: Bell, 3: Vibration, 4: Bell and Vibration + // @inject_tag: json:"notify_type" + int32 NotifyType = 5; + + // @inject_tag: json:"notify_id" + int32 NotifyID = 6; + + // @inject_tag: json:"title" + string Title = 7; + + // @inject_tag: json:"content" + string Content = 8; + + // @inject_tag: json:"category" + string Category = 9; + + // @inject_tag: json:"task_id" + string TaskId = 10; + + // @inject_tag: json:"click_action" + ClickAction ClickAction = 11; + + // Data Additional Custom Parameters + // @inject_tag: json:"data" + map Data = 12; +} + +message ClickAction { + // Action represents the click action. + // Different manufacturers have different definitions. + // @inject_tag: json:"action" + int32 Action = 1; + + // Activity opens an in-app page (activity's intent action). + // @inject_tag: json:"activity" + string Activity = 2; + + // Url opens the URL of a webpage. + // @inject_tag: json:"url" + string Url = 3; + + // Parameters represent the parameters appended to the URL after the URL redirection. + // @inject_tag: json:"parameters" + map Parameters = 4; +} + +// MeizuPushNotification +// https://github.com/MEIZUPUSH/PushAPI/blob/master/README.md +message MeizuPushRequestData { + // @inject_tag: json:"meta" + Meta Meta = 1; + + // @inject_tag: json:"title" + string Title = 2; + + // @inject_tag: json:"content" + string Content = 3; + + // TTL The valid duration of the message, in seconds, and the duration of the push service cache message. + // @inject_tag: json:"ttl" + int64 TTL = 4; + + // NotifyType + // DEFAULT_ALL = -1; + // DEFAULT_SOUND = 0; 使用默认提示音提示 + // DEFAULT_VIBRATE = 1; 使用默认振动提示 + // DEFAULT_LIGHTS = 2; 使用默认呼吸灯提示。 + // @inject_tag: json:"notify_type" + int32 NotifyType = 5; + + // Foreground Whether to display notification bar messages when the app is in the foreground + // @inject_tag: json:"foreground" + bool Foreground = 6; +// bool IsScheduled = 7; +// string ScheduledStartTime = 8; // 定时展示开始时间(yyyy-MM-dd HH:mm:ss) +// string ScheduledEndTime = 9; // 定时展示结束时间(yyyy-MM-dd HH:mm:ss) + + // ClickAction 点击跳转类型 + // 0 打开应用 + // 1 打开应用内页(activity的action标签名) + // 2 打开H5地址(应用本地的URI) + // Activity 打开应用内页(activity 的 intent action) + // @inject_tag: json:"click_action" + ClickAction ClickAction = 10; + + // Data Additional Custom Parameters + // @inject_tag: json:"data" + map Data = 11; +} + +message HonorPushRequestData { + // @inject_tag: json:"meta" + Meta Meta = 1; + + // @inject_tag: json:"title" + string Title = 2; + + // @inject_tag: json:"content" + string Content = 3; + + // Icon Message icon, the icon to display on the notification bar + // @inject_tag: json:"icon" + string Icon = 4; + + // Tag Message identifier, used for message deduplication and overwriting. + // @inject_tag: json:"tag" + string Tag = 5; + + // Group 消息分组,例 如发送10条带有同样group字段的消息,手机上只会展示该组消息中最新的一条和当前该组接收到的消息总数目,不会展示10条消息。 + // @inject_tag: json:"group" + string Group = 6; + + // NotifyId 消息通知ID,用于消息覆盖 + // @inject_tag: json:"notify_id" + int32 NotifyId = 7; + + // TTL The valid duration of the message, in seconds, and the duration of the push service cache message. + // @inject_tag: json:"ttl" + int64 TTL = 8; + + // 测试模式推送消息 + // @inject_tag: json:"development" + bool Development = 9; + + // Action 点击跳转类型 + // 1 打开应用内页(activity的action标签名) + // 2 打开特定url + // 3 打开应用 + // @inject_tag: json:"click_action" + ClickAction ClickAction = 10; + + // 消息角标 + // @inject_tag: json:"badge" + BadgeNotification Badge = 11; + + // 附加的自定义参数 + // @inject_tag: json:"data" + map Data = 12; +} + +message BadgeNotification { + // @inject_tag: json:"add_num" + int32 AddNum = 1; + // @inject_tag: json:"set_num" + int32 SetNum = 2; + // @inject_tag: json:"class" + string Class = 3; +} + +//message SendOptions { +// // DryRun 只进行数据校验不实际推送,数据校验成功即为成功 +// bool DryRun = 1; +// // Development 测试模式推送 +// bool Development= 2; +// // Retry 重试次数 +// int32 Retry = 3; +// // RetryInterval 重试间隔(以秒为单位) +// int32 RetryInterval = 4; +//} + +service PushService { + rpc Push (PushRequest) returns (PushResponse) {} +} \ No newline at end of file diff --git a/api/grpc/v1/push_grpc.pb.go b/api/pb/v1/push_grpc.pb.go similarity index 93% rename from api/grpc/v1/push_grpc.pb.go rename to api/pb/v1/push_grpc.pb.go index 48fa12c..26b143b 100644 --- a/api/grpc/v1/push_grpc.pb.go +++ b/api/pb/v1/push_grpc.pb.go @@ -1,6 +1,6 @@ -// Code generated by protoc-gen-go-grpc. DO NOT EDIT. +// Code generated by protoc-gen-go-pb. DO NOT EDIT. // versions: -// - protoc-gen-go-grpc v1.3.0 +// - protoc-gen-go-pb v1.3.0 // - protoc v4.25.1 // source: push.proto @@ -14,7 +14,7 @@ import ( ) // This is a compile-time assertion to ensure that this generated file -// is compatible with the grpc package it is being compiled against. +// is compatible with the pb package it is being compiled against. // Requires gRPC-Go v1.32.0 or later. const _ = grpc.SupportPackageIsVersion7 @@ -91,7 +91,7 @@ func _PushService_Push_Handler(srv interface{}, ctx context.Context, dec func(in } // PushService_ServiceDesc is the grpc.ServiceDesc for PushService service. -// It's only intended for direct use with grpc.RegisterService, +// It's only intended for direct use with pb.RegisterService, // and not to be introspected or modified (even as a copy) var PushService_ServiceDesc = grpc.ServiceDesc{ ServiceName: "v1.PushService", diff --git a/api/pb/v1/vivo.go b/api/pb/v1/vivo.go new file mode 100644 index 0000000..39567cb --- /dev/null +++ b/api/pb/v1/vivo.go @@ -0,0 +1,49 @@ +package v1 + +import "github.com/cossim/hipush/api/push" + +var _ push.SendRequest = &VivoPushRequestData{} + +func (x *VivoPushRequestData) GetAppID() string { + return x.Meta.AppID +} + +func (x *VivoPushRequestData) GetAppName() string { + return x.Meta.AppName +} + +func (x *VivoPushRequestData) GetToken() []string { + return x.Meta.Token +} + +func (x *VivoPushRequestData) GetTopic() string { + return "" +} + +func (x *VivoPushRequestData) GetCollapseID() string { + return "" +} + +func (x *VivoPushRequestData) GetMessageID() string { + return "" +} + +func (x *VivoPushRequestData) GetPriority() string { + return "" +} + +func (x *VivoPushRequestData) GetCondition() string { + return "" +} + +func (x *VivoPushRequestData) GetIcon() string { + return "" +} + +func (x *VivoPushRequestData) GetMutableContent() bool { + return false +} + +func (x *VivoPushRequestData) GetContentAvailable() bool { + return false +} diff --git a/api/pb/v1/xiaomi.go b/api/pb/v1/xiaomi.go new file mode 100644 index 0000000..4c0d217 --- /dev/null +++ b/api/pb/v1/xiaomi.go @@ -0,0 +1,49 @@ +package v1 + +import "github.com/cossim/hipush/api/push" + +var _ push.SendRequest = &XiaomiPushRequestData{} + +func (x *XiaomiPushRequestData) GetAppID() string { + return x.Meta.AppID +} + +func (x *XiaomiPushRequestData) GetAppName() string { + return x.Meta.AppName +} + +func (x *XiaomiPushRequestData) GetToken() []string { + return x.Meta.Token +} + +func (x *XiaomiPushRequestData) GetTopic() string { + return "" +} + +func (x *XiaomiPushRequestData) GetCollapseID() string { + return "" +} + +func (x *XiaomiPushRequestData) GetMessageID() string { + return "" +} + +func (x *XiaomiPushRequestData) GetPriority() string { + return "" +} + +func (x *XiaomiPushRequestData) GetCategory() string { + return "" +} + +func (x *XiaomiPushRequestData) GetCondition() string { + return "" +} + +func (x *XiaomiPushRequestData) GetMutableContent() bool { + return false +} + +func (x *XiaomiPushRequestData) GetContentAvailable() bool { + return false +} diff --git a/api/push/interfaces.go b/api/push/interfaces.go index d6ce8c2..0f56506 100644 --- a/api/push/interfaces.go +++ b/api/push/interfaces.go @@ -34,10 +34,41 @@ type SendResponse struct { TaskId string `json:"task_id"` } +type Message interface { + Meta + GetTitle() string + GetContent() string + GetTopic() string + GetCollapseID() string + GetMessageID() string + GetPriority() string + GetCategory() string + GetCondition() string + GetIcon() string + GetTTL() int64 + GetMutableContent() bool + GetContentAvailable() bool + GetForeground() bool + //GetClickAction() *v1.ClickAction + GetNotifyType() int32 + //GetSound() interface{} + //GetData() map[string]interface{} +} + +type Meta interface { + GetAppID() string + GetAppName() string + GetToken() []string +} + +type SendRequest interface { + Message +} + // PushService 提供推送服务的接口 type PushService interface { // Send 发送消息给单个设备 - Send(ctx context.Context, req interface{}, opt ...SendOption) (*SendResponse, error) + Send(ctx context.Context, req SendRequest, opt ...SendOption) (*SendResponse, error) // GetTasksStatus 查询推送消息的统计信息 GetTasksStatus(ctx context.Context, appid string, taskID []string, obj TaskObjectList) error diff --git a/api/push/option.go b/api/push/option.go index 0f4ecc5..f145940 100644 --- a/api/push/option.go +++ b/api/push/option.go @@ -8,19 +8,23 @@ type SendOption interface { type SendOptions struct { // DryRun 只进行数据校验不实际推送,数据校验成功即为成功 DryRun bool `json:"dry_run,omitempty"` + // Development 测试环境推送 + Development bool `json:"development,omitempty"` // Retry 重试次数 - Retry int `json:"retry,omitempty"` + Retry int32 `json:"retry,omitempty"` // RetryInterval 重试间隔(以秒为单位) - RetryInterval int `json:"retry_interval"` + RetryInterval int32 `json:"retry_interval"` } func (s *SendOptions) Apply(option *SendOptions) { if s.DryRun { option.DryRun = true } - if s.Retry > 0 { - option.Retry = s.Retry + if s.Development { + option.Development = true } + option.Retry = s.Retry + option.RetryInterval = s.RetryInterval } func (s *SendOptions) ApplyOptions(opts []SendOption) *SendOptions { diff --git a/cmd/main.go b/cmd/main.go index 2a1d084..0b79959 100644 --- a/cmd/main.go +++ b/cmd/main.go @@ -9,7 +9,6 @@ import ( h "github.com/cossim/hipush/internal/server/http" "github.com/cossim/hipush/pkg/push" "github.com/cossim/hipush/pkg/status" - "github.com/go-co-op/gocron/v2" "github.com/go-logr/zapr" "go.uber.org/zap" "log" @@ -44,10 +43,10 @@ func main() { zapLogger := zap.NewExample() logger := zapr.NewLogger(zapLogger) - scheduler, err := gocron.NewScheduler() - if err != nil { - panic(err) - } + //scheduler, err := gocron.NewScheduler() + //if err != nil { + // panic(err) + //} pushServiceFactory := factory.NewPushServiceFactory() if err := pushServiceFactory.Register( @@ -56,7 +55,7 @@ func main() { pushServiceFactory.WithPushService(push.NewHMSService(cfg, logger)), pushServiceFactory.WithPushService(push.NewXiaomiService(cfg, logger)), pushServiceFactory.WithPushService(push.NewOppoService(cfg, logger)), - pushServiceFactory.WithPushService(push.NewVivoService(cfg, logger, scheduler)), + pushServiceFactory.WithPushService(push.NewVivoService(cfg, logger)), pushServiceFactory.WithPushService(push.NewMeizuService(cfg, logger)), pushServiceFactory.WithPushService(push.NewHonorService(cfg, logger)), ); err != nil { diff --git a/config/config.go b/config/config.go index 1aa195a..080507c 100644 --- a/config/config.go +++ b/config/config.go @@ -85,7 +85,7 @@ type HonorAppConfig struct { type Config struct { HTTP HTTPConfig `yaml:"http"` - GRPC GRPCConfig `yaml:"grpc"` + GRPC GRPCConfig `yaml:"pb"` Storage Storage `yaml:"storage"` IOS []iOSAppConfig `yaml:"ios"` Huawei []HuaweiAppConfig `yaml:"huawei"` diff --git a/example/andorid/grpc/main.go b/example/andorid/grpc/main.go new file mode 100644 index 0000000..c0a2acb --- /dev/null +++ b/example/andorid/grpc/main.go @@ -0,0 +1,67 @@ +package main + +import ( + "context" + "fmt" + "github.com/golang/protobuf/jsonpb" + "google.golang.org/grpc/credentials/insecure" + "google.golang.org/protobuf/types/known/structpb" + "log" + + "github.com/cossim/hipush/api/pb/v1" + "google.golang.org/grpc" +) + +func main() { + // Set up a connection to the server. + conn, err := grpc.Dial("localhost:7071", grpc.WithTransportCredentials(insecure.NewCredentials())) + if err != nil { + log.Fatalf("did not connect: %v", err) + } + defer conn.Close() + c := v1.NewPushServiceClient(conn) + + ctx := context.Background() + + ap := &v1.AndroidPushRequestData{ + Title: "cossim", + Content: "hello", + Topic: "", + TTL: 0, + Priority: "normal", + CollapseID: "", + Condition: "", + Sound: "", + Icon: "", + Data: nil, + } + + marshaler := &jsonpb.Marshaler{} + jsonString, err := marshaler.MarshalToString(ap) + if err != nil { + log.Fatalf("Failed to marshal struct to JSON: %v", err) + } + + structValue := &structpb.Struct{} + err = jsonpb.UnmarshalString(jsonString, structValue) + if err != nil { + log.Fatalf("Failed to unmarshal JSON to structpb.Struct: %v", err) + } + + req := &v1.PushRequest{ + AppID: "com.hitosea.apptest", + AppName: "cossim", + Platform: "android", + Token: []string{"cb7f8a974eec5fbb2e36762fcb78e51327bcef4822d600f17e8f9bd845af1e12"}, + Data: structValue, + Option: nil, + } + + fmt.Println("req => ", req.Data) + + resp, err := c.Push(ctx, req) + if err != nil { + log.Fatalf("could not push: %v", err) + } + fmt.Println("Push response:", resp) +} diff --git a/example/andorid/http/http_android_push.go b/example/andorid/http/http_android_push.go new file mode 100644 index 0000000..2195d41 --- /dev/null +++ b/example/andorid/http/http_android_push.go @@ -0,0 +1,54 @@ +package main + +import ( + "bytes" + "fmt" + "io/ioutil" + "net/http" +) + +var ( + url = "http://127.0.0.1:7070/api/v1/push" + method = "POST" +) + +func main() { + payload := []byte(`{ + "platform": "android", + "token": [ + "xxx" + ], + "app_name": "cossim", + "data": { + "title": "cossim", + "content": "hello" + }, + "option": { + "dry_run": true, + "development": false, + "retry": 1, + "retry_interval": 0 + } +}`) + + client := &http.Client{} + req, err := http.NewRequest(method, url, bytes.NewBuffer(payload)) + if err != nil { + fmt.Println(err) + return + } + req.Header.Add("Content-Type", "application/json") + res, err := client.Do(req) + if err != nil { + fmt.Println(err) + return + } + defer res.Body.Close() + + body, err := ioutil.ReadAll(res.Body) + if err != nil { + fmt.Println(err) + return + } + fmt.Println(string(body)) +} diff --git a/example/andorid/http_android_push.go b/example/andorid/http_android_push.go deleted file mode 100644 index fc0624a..0000000 --- a/example/andorid/http_android_push.go +++ /dev/null @@ -1,70 +0,0 @@ -package main - -import ( - "encoding/json" - "fmt" - "github.com/cossim/hipush/api/http/v1/dto" - "io/ioutil" - "net/http" - "strings" -) - -var ( - url = "http://127.0.0.1:7070/api/v1/push" - method = "POST" -) - -func main() { - payload := dto.PushRequest{ - AppID: "com.dootask.task", - AppName: "cossim", - Platform: "android", - Token: []string{ - "cb7f8a974eec5fbb2e36762fcb78e51327bcef4822d600f17e8f9bd845af1e12", - }, - Data: dto.AndroidPushRequestData{ - Title: "cossim", - Content: "hello", - TTL: "10m", - Topic: "", - Priority: "normal", - CollapseID: "", - Condition: "", - Sound: "", - Image: "", - Data: nil, - }, - Option: dto.PushOption{ - DryRun: false, - Retry: 1, - RetryInterval: 1, - }, - } - - // Marshal the request object to JSON - reqBody, err := json.Marshal(payload) - if err != nil { - panic(err) - } - - client := &http.Client{} - req, err := http.NewRequest(method, url, strings.NewReader(string(reqBody))) - if err != nil { - fmt.Println(err) - return - } - req.Header.Add("Content-Type", "application/json") - res, err := client.Do(req) - if err != nil { - fmt.Println(err) - return - } - defer res.Body.Close() - - body, err := ioutil.ReadAll(res.Body) - if err != nil { - fmt.Println(err) - return - } - fmt.Println(string(body)) -} diff --git a/example/honor/grpc/main.go b/example/honor/grpc/main.go new file mode 100644 index 0000000..207f3c6 --- /dev/null +++ b/example/honor/grpc/main.go @@ -0,0 +1,71 @@ +package main + +import ( + "context" + "fmt" + "github.com/golang/protobuf/jsonpb" + "google.golang.org/grpc/credentials/insecure" + "google.golang.org/protobuf/types/known/structpb" + "log" + + "github.com/cossim/hipush/api/pb/v1" + "google.golang.org/grpc" +) + +func main() { + // Set up a connection to the server. + conn, err := grpc.Dial("localhost:7071", grpc.WithTransportCredentials(insecure.NewCredentials())) + if err != nil { + log.Fatalf("did not connect: %v", err) + } + defer conn.Close() + c := v1.NewPushServiceClient(conn) + + //Contact the server and print out its response. + ctx := context.Background() + + ap := &v1.HuaweiPushRequestData{ + Title: "cossim", + Content: "hello", + Category: "", + Priority: "", + Icon: "", + Sound: "", + TTL: 0, + Foreground: false, + ClickAction: nil, + Badge: nil, + } + + marshaler := &jsonpb.Marshaler{} + jsonString, err := marshaler.MarshalToString(ap) + if err != nil { + log.Fatalf("Failed to marshal struct to JSON: %v", err) + } + + structValue := &structpb.Struct{} + err = jsonpb.UnmarshalString(jsonString, structValue) + if err != nil { + log.Fatalf("Failed to unmarshal JSON to structpb.Struct: %v", err) + } + + req := &v1.PushRequest{ + AppID: "", + AppName: "cossim", + Platform: "huawei", + Token: []string{"xxx"}, + Data: structValue, + Option: &v1.PushOption{ + DryRun: true, + Development: false, + Retry: 0, + RetryInterval: 0, + }, + } + + resp, err := c.Push(ctx, req) + if err != nil { + log.Fatalf("could not push: %v", err) + } + fmt.Println("Push response:", resp) +} diff --git a/example/honor/http/http_huawei_push.go b/example/honor/http/http_huawei_push.go new file mode 100644 index 0000000..a94fe86 --- /dev/null +++ b/example/honor/http/http_huawei_push.go @@ -0,0 +1,56 @@ +package main + +import ( + "bytes" + "fmt" + "io/ioutil" + "net/http" +) + +var ( + url = "http://127.0.0.1:7070/api/v1/push" + method = "POST" +) + +func main() { + payload := []byte(`{ + "platform": "honor", + "token": [ + "xxx" + ], + "app_id": "xxx", + "app_name": "cossim", + "data": { + "foreground": true, + "title": "测试标题", + "content": "测试内容" + }, + "option": { + "dry_run": true, + "development": false, + "retry": 3, + "retry_interval": 1 + } +}`) + + client := &http.Client{} + req, err := http.NewRequest(method, url, bytes.NewBuffer(payload)) + if err != nil { + fmt.Println(err) + return + } + req.Header.Add("Content-Type", "application/json") + res, err := client.Do(req) + if err != nil { + fmt.Println(err) + return + } + defer res.Body.Close() + + body, err := ioutil.ReadAll(res.Body) + if err != nil { + fmt.Println(err) + return + } + fmt.Println(string(body)) +} diff --git a/example/huawei/grpc/main.go b/example/huawei/grpc/main.go new file mode 100644 index 0000000..32ccf85 --- /dev/null +++ b/example/huawei/grpc/main.go @@ -0,0 +1,71 @@ +package main + +import ( + "context" + "fmt" + "github.com/golang/protobuf/jsonpb" + "google.golang.org/grpc/credentials/insecure" + "google.golang.org/protobuf/types/known/structpb" + "log" + + "github.com/cossim/hipush/api/pb/v1" + "google.golang.org/grpc" +) + +func main() { + // Set up a connection to the server. + conn, err := grpc.Dial("localhost:7071", grpc.WithTransportCredentials(insecure.NewCredentials())) + if err != nil { + log.Fatalf("did not connect: %v", err) + } + defer conn.Close() + c := v1.NewPushServiceClient(conn) + + //Contact the server and print out its response. + ctx := context.Background() + + ap := &v1.HuaweiPushRequestData{ + Title: "cossim", + Content: "hello", + Category: "", + Priority: "", + Icon: "", + Sound: "", + TTL: 0, + Foreground: false, + ClickAction: nil, + Badge: nil, + } + + marshaler := &jsonpb.Marshaler{} + jsonString, err := marshaler.MarshalToString(ap) + if err != nil { + log.Fatalf("Failed to marshal struct to JSON: %v", err) + } + + structValue := &structpb.Struct{} + err = jsonpb.UnmarshalString(jsonString, structValue) + if err != nil { + log.Fatalf("Failed to unmarshal JSON to structpb.Struct: %v", err) + } + + req := &v1.PushRequest{ + AppID: "xxx", + AppName: "cossim", + Platform: "huawei", + Token: []string{"xxx"}, + Data: structValue, + Option: &v1.PushOption{ + DryRun: true, + Development: false, + Retry: 0, + RetryInterval: 0, + }, + } + + resp, err := c.Push(ctx, req) + if err != nil { + log.Fatalf("could not push: %v", err) + } + fmt.Println("Push response:", resp) +} diff --git a/example/huawei/http/http_huawei_push.go b/example/huawei/http/http_huawei_push.go new file mode 100644 index 0000000..2e0c378 --- /dev/null +++ b/example/huawei/http/http_huawei_push.go @@ -0,0 +1,59 @@ +package main + +import ( + "bytes" + "fmt" + "io/ioutil" + "net/http" +) + +var ( + url = "http://127.0.0.1:7070/api/v1/push" + method = "POST" +) + +func main() { + payload := []byte(`{ + "platform": "huawei", + "token": [ + "xxx" + ], + "app_id": "110376397", + "app_name": "cossim", + "data": { + "title": "cossim", + "content": "hello", + "badge": { + "addNum": 1, + "class": "" + } + }, + "option": { + "dry_run": true, + "development": false, + "retry": 3, + "retry_interval": 1 + } +}`) + + client := &http.Client{} + req, err := http.NewRequest(method, url, bytes.NewBuffer(payload)) + if err != nil { + fmt.Println(err) + return + } + req.Header.Add("Content-Type", "application/json") + res, err := client.Do(req) + if err != nil { + fmt.Println(err) + return + } + defer res.Body.Close() + + body, err := ioutil.ReadAll(res.Body) + if err != nil { + fmt.Println(err) + return + } + fmt.Println(string(body)) +} diff --git a/example/huawei/http_huawei_push.go b/example/huawei/http_huawei_push.go deleted file mode 100644 index abe506c..0000000 --- a/example/huawei/http_huawei_push.go +++ /dev/null @@ -1,81 +0,0 @@ -package main - -import ( - "encoding/json" - "fmt" - "github.com/cossim/hipush/api/http/v1/dto" - "io/ioutil" - "net/http" - "strings" -) - -var ( - url = "http://127.0.0.1:7070/api/v1/push" - method = "POST" -) - -func main() { - payload := dto.PushRequest{ - AppID: "xxx", - AppName: "cossim", - Platform: "huawei", - Token: []string{ - "xxx", - }, - Data: dto.HuaweiPushRequestData{ - Title: "cossim", - Content: "hello", - Category: "IM", - Priority: "normal", - TTL: "86400s", - Icon: "", - Img: "", - Sound: "", - Foreground: true, - Development: true, - ClickAction: dto.ClickAction{ - Action: 3, - Activity: "", - Url: "", - Parameters: nil, - }, - Badge: dto.BadgeNotification{ - AddNum: 1, - //SetNum: 1, - //Class: "1", - }, - }, - Option: dto.PushOption{ - DryRun: false, - Retry: 1, - RetryInterval: 1, - }, - } - - // Marshal the request object to JSON - reqBody, err := json.Marshal(payload) - if err != nil { - panic(err) - } - - client := &http.Client{} - req, err := http.NewRequest(method, url, strings.NewReader(string(reqBody))) - if err != nil { - fmt.Println(err) - return - } - req.Header.Add("Content-Type", "application/json") - res, err := client.Do(req) - if err != nil { - fmt.Println(err) - return - } - defer res.Body.Close() - - body, err := ioutil.ReadAll(res.Body) - if err != nil { - fmt.Println(err) - return - } - fmt.Println(string(body)) -} diff --git a/example/ios/grpc/main.go b/example/ios/grpc/main.go new file mode 100644 index 0000000..9e5d40c --- /dev/null +++ b/example/ios/grpc/main.go @@ -0,0 +1,73 @@ +package main + +import ( + "context" + "fmt" + "github.com/golang/protobuf/jsonpb" + "google.golang.org/grpc/credentials/insecure" + "google.golang.org/protobuf/types/known/structpb" + "log" + + "github.com/cossim/hipush/api/pb/v1" + "google.golang.org/grpc" +) + +func main() { + // Set up a connection to the server. + conn, err := grpc.Dial("localhost:7071", grpc.WithTransportCredentials(insecure.NewCredentials())) + if err != nil { + log.Fatalf("did not connect: %v", err) + } + defer conn.Close() + c := v1.NewPushServiceClient(conn) + + //Contact the server and print out its response. + ctx := context.Background() + + ap := &v1.HonorPushRequestData{ + Title: "cossim", + Content: "hello", + Icon: "", + Tag: "", + Group: "", + NotifyId: 0, + TTL: 0, + ClickAction: nil, + Badge: nil, + Data: nil, + } + + marshaler := &jsonpb.Marshaler{} + jsonString, err := marshaler.MarshalToString(ap) + if err != nil { + log.Fatalf("Failed to marshal struct to JSON: %v", err) + } + + structValue := &structpb.Struct{} + err = jsonpb.UnmarshalString(jsonString, structValue) + if err != nil { + log.Fatalf("Failed to unmarshal JSON to structpb.Struct: %v", err) + } + + req := &v1.PushRequest{ + AppID: "xxx", + AppName: "cossim", + Platform: "honor", + Token: []string{"xxx"}, + Data: structValue, + Option: &v1.PushOption{ + DryRun: true, + Development: false, + Retry: 0, + RetryInterval: 0, + }, + } + + fmt.Println("req => ", req.Data) + + resp, err := c.Push(ctx, req) + if err != nil { + log.Fatalf("could not push: %v", err) + } + fmt.Println("Push response:", resp) +} diff --git a/example/ios/http/http_ios_push.go b/example/ios/http/http_ios_push.go new file mode 100644 index 0000000..c9b7868 --- /dev/null +++ b/example/ios/http/http_ios_push.go @@ -0,0 +1,61 @@ +package main + +import ( + "bytes" + "fmt" + "io/ioutil" + "net/http" +) + +var ( + url = "http://127.0.0.1:7070/api/v1/push" + method = "POST" +) + +func main() { + payload := []byte(`{ + "platform": "ios", + "token": [ + "xxx" + ], + "app_id": "com.hitosea.apptest", + "app_name": "cossim", + "data": { + "title": "cossim", + "content": "hello", + "badge": 1, + "sound": { + "critical": 1, + "volume": 4.5, + "name": "" + } + }, + "option": { + "dry_run": true, + "development": false, + "retry": 3, + "retry_interval": 1 + } +}`) + + client := &http.Client{} + req, err := http.NewRequest(method, url, bytes.NewBuffer(payload)) + if err != nil { + fmt.Println(err) + return + } + req.Header.Add("Content-Type", "application/json") + res, err := client.Do(req) + if err != nil { + fmt.Println(err) + return + } + defer res.Body.Close() + + body, err := ioutil.ReadAll(res.Body) + if err != nil { + fmt.Println(err) + return + } + fmt.Println(string(body)) +} diff --git a/example/ios/http_ios_push.go b/example/ios/http_ios_push.go deleted file mode 100644 index 58216ce..0000000 --- a/example/ios/http_ios_push.go +++ /dev/null @@ -1,81 +0,0 @@ -package main - -import ( - "encoding/json" - "fmt" - "github.com/cossim/hipush/api/http/v1/dto" - "github.com/google/uuid" - "io/ioutil" - "net/http" - "strings" - "time" -) - -var ( - url = "http://127.0.0.1:7070/api/v1/push" - method = "POST" -) - -func main() { - payload := dto.PushRequest{ - AppID: "xxx", - AppName: "cossim", - Platform: "ios", - Token: []string{ - "xxx", - }, - Data: dto.APNsPushRequest{ - Title: "cossim", - Content: "hello", - Topic: "com.hitosea.cossim", - CollapseID: "", - ApnsID: uuid.New().String(), - Priority: "normal", - PushType: "alert", - URLArgs: nil, - TTL: time.Now().Add(30 * time.Minute).Unix(), - Badge: 1, - Development: false, - MutableContent: false, - ContentAvailable: false, - Sound: map[string]interface{}{ - "critical": 1, - "volume": 4.5, - "name": "", - }, - Data: nil, - }, - Option: dto.PushOption{ - DryRun: false, - Retry: 1, - RetryInterval: 1, - }, - } - - // Marshal the request object to JSON - reqBody, err := json.Marshal(payload) - if err != nil { - panic(err) - } - - client := &http.Client{} - req, err := http.NewRequest(method, url, strings.NewReader(string(reqBody))) - if err != nil { - fmt.Println(err) - return - } - req.Header.Add("Content-Type", "application/json") - res, err := client.Do(req) - if err != nil { - fmt.Println(err) - return - } - defer res.Body.Close() - - body, err := ioutil.ReadAll(res.Body) - if err != nil { - fmt.Println(err) - return - } - fmt.Println(string(body)) -} diff --git a/example/oppo/grpc/main.go b/example/oppo/grpc/main.go new file mode 100644 index 0000000..7dbbcd7 --- /dev/null +++ b/example/oppo/grpc/main.go @@ -0,0 +1,69 @@ +package main + +import ( + "context" + "fmt" + "github.com/golang/protobuf/jsonpb" + "google.golang.org/grpc/credentials/insecure" + "google.golang.org/protobuf/types/known/structpb" + "log" + + "github.com/cossim/hipush/api/pb/v1" + "google.golang.org/grpc" +) + +func main() { + // Set up a connection to the server. + conn, err := grpc.Dial("localhost:7071", grpc.WithTransportCredentials(insecure.NewCredentials())) + if err != nil { + log.Fatalf("did not connect: %v", err) + } + defer conn.Close() + c := v1.NewPushServiceClient(conn) + + //Contact the server and print out its response. + ctx := context.Background() + + ap := &v1.OppoPushRequestData{ + Foreground: true, + Title: "cossim", + Subtitle: "", + Content: "hello", + TTL: 0, + Icon: "", + ClickAction: nil, + Data: nil, + } + + marshaler := &jsonpb.Marshaler{} + jsonString, err := marshaler.MarshalToString(ap) + if err != nil { + log.Fatalf("Failed to marshal struct to JSON: %v", err) + } + + structValue := &structpb.Struct{} + err = jsonpb.UnmarshalString(jsonString, structValue) + if err != nil { + log.Fatalf("Failed to unmarshal JSON to structpb.Struct: %v", err) + } + + req := &v1.PushRequest{ + AppID: "xxx", + AppName: "cossim", + Platform: "oppo", + Token: []string{"xxx"}, + Data: structValue, + Option: &v1.PushOption{ + DryRun: true, + Development: false, + Retry: 0, + RetryInterval: 0, + }, + } + + resp, err := c.Push(ctx, req) + if err != nil { + log.Fatalf("could not push: %v", err) + } + fmt.Println("Push response:", resp) +} diff --git a/example/oppo/http/main.go b/example/oppo/http/main.go new file mode 100644 index 0000000..363ebde --- /dev/null +++ b/example/oppo/http/main.go @@ -0,0 +1,57 @@ +package main + +import ( + "bytes" + "fmt" + "io/ioutil" + "net/http" +) + +var ( + url = "http://127.0.0.1:7070/api/v1/push" + method = "POST" +) + +func main() { + payload := []byte(`{ + "platform": "oppo", + "token": [ + "xxx" + ], + "app_id": "xxx", + "app_name": "cossim", + "data": { + "title": "测试标题", + "subtitle": "测试子标题", + "content": "测试内容", + "foreground": true + }, + "option": { + "dry_run": true, + "development": false, + "retry": 3, + "retry_interval": 1 + } +}`) + + client := &http.Client{} + req, err := http.NewRequest(method, url, bytes.NewBuffer(payload)) + if err != nil { + fmt.Println(err) + return + } + req.Header.Add("Content-Type", "application/json") + res, err := client.Do(req) + if err != nil { + fmt.Println(err) + return + } + defer res.Body.Close() + + body, err := ioutil.ReadAll(res.Body) + if err != nil { + fmt.Println(err) + return + } + fmt.Println(string(body)) +} diff --git a/example/vivo/grpc/main.go b/example/vivo/grpc/main.go new file mode 100644 index 0000000..9a3a984 --- /dev/null +++ b/example/vivo/grpc/main.go @@ -0,0 +1,71 @@ +package main + +import ( + "context" + "fmt" + "github.com/golang/protobuf/jsonpb" + "google.golang.org/grpc/credentials/insecure" + "google.golang.org/protobuf/types/known/structpb" + "log" + + "github.com/cossim/hipush/api/pb/v1" + "google.golang.org/grpc" +) + +func main() { + // Set up a connection to the server. + conn, err := grpc.Dial("localhost:7071", grpc.WithTransportCredentials(insecure.NewCredentials())) + if err != nil { + log.Fatalf("did not connect: %v", err) + } + defer conn.Close() + c := v1.NewPushServiceClient(conn) + + //Contact the server and print out its response. + ctx := context.Background() + + ap := &v1.VivoPushRequestData{ + Foreground: true, + TTL: 0, + NotifyType: -2, + NotifyID: 0, + Title: "cossim", + Content: "hello", + Category: "IM", + TaskId: "", + ClickAction: nil, + Data: nil, + } + + marshaler := &jsonpb.Marshaler{} + jsonString, err := marshaler.MarshalToString(ap) + if err != nil { + log.Fatalf("Failed to marshal struct to JSON: %v", err) + } + + structValue := &structpb.Struct{} + err = jsonpb.UnmarshalString(jsonString, structValue) + if err != nil { + log.Fatalf("Failed to unmarshal JSON to structpb.Struct: %v", err) + } + + req := &v1.PushRequest{ + AppID: "xxx", + AppName: "cossim", + Platform: "vivo", + Token: []string{"xxx"}, + Data: structValue, + Option: &v1.PushOption{ + DryRun: true, + Development: false, + Retry: 0, + RetryInterval: 0, + }, + } + + resp, err := c.Push(ctx, req) + if err != nil { + log.Fatalf("could not push: %v", err) + } + fmt.Println("Push response:", resp) +} diff --git a/example/vivo/http/main.go b/example/vivo/http/main.go new file mode 100644 index 0000000..fc1228f --- /dev/null +++ b/example/vivo/http/main.go @@ -0,0 +1,58 @@ +package main + +import ( + "bytes" + "fmt" + "io/ioutil" + "net/http" +) + +var ( + url = "http://127.0.0.1:7070/api/v1/push" + method = "POST" +) + +func main() { + payload := []byte(`{ + "platform": "vivo", + "token": [ + "xxx" + ], + "app_id": "xxx", + "app_name": "cossim", + "data": { + "title": "hello", + "content": "hello", + "category": "IM", + "notify_id": 2, + "foreground": true + }, + "option": { + "dry_run": true, + "development": false, + "retry": 3, + "retry_interval": 1 + } +}`) + + client := &http.Client{} + req, err := http.NewRequest(method, url, bytes.NewBuffer(payload)) + if err != nil { + fmt.Println(err) + return + } + req.Header.Add("Content-Type", "application/json") + res, err := client.Do(req) + if err != nil { + fmt.Println(err) + return + } + defer res.Body.Close() + + body, err := ioutil.ReadAll(res.Body) + if err != nil { + fmt.Println(err) + return + } + fmt.Println(string(body)) +} diff --git a/example/xiaomi/grpc/main.go b/example/xiaomi/grpc/main.go index e8fa12d..1329ba1 100644 --- a/example/xiaomi/grpc/main.go +++ b/example/xiaomi/grpc/main.go @@ -3,10 +3,12 @@ package main import ( "context" "fmt" + "github.com/golang/protobuf/jsonpb" "google.golang.org/grpc/credentials/insecure" + "google.golang.org/protobuf/types/known/structpb" "log" - "github.com/cossim/hipush/api/grpc/v1" + "github.com/cossim/hipush/api/pb/v1" "google.golang.org/grpc" ) @@ -19,33 +21,46 @@ func main() { defer conn.Close() c := v1.NewPushServiceClient(conn) - // Contact the server and print out its response. + //Contact the server and print out its response. ctx := context.Background() + + ap := &v1.XiaomiPushRequestData{ + Title: "cossim", + Subtitle: "", + Content: "hello", + Foreground: true, + Icon: "", + TTL: 0, + NotifyType: 0, + ClickAction: nil, + } + + marshaler := &jsonpb.Marshaler{} + jsonString, err := marshaler.MarshalToString(ap) + if err != nil { + log.Fatalf("Failed to marshal struct to JSON: %v", err) + } + + structValue := &structpb.Struct{} + err = jsonpb.UnmarshalString(jsonString, structValue) + if err != nil { + log.Fatalf("Failed to unmarshal JSON to structpb.Struct: %v", err) + } + req := &v1.PushRequest{ + AppID: "xxx", + AppName: "cossim", Platform: "xiaomi", - Tokens: []string{ - "xxx", + Token: []string{"xxx"}, + Data: structValue, + Option: &v1.PushOption{ + DryRun: true, + Development: false, + Retry: 0, + RetryInterval: 0, }, - Title: "cossim", - Message: "", - Topic: "", - Key: "", - Category: "", - Sound: "", - Alert: nil, - Badge: 0, - ThreadID: "", - Data: nil, - Image: "", - ID: "", - PushType: "", - AppID: "", - Priority: 0, - ContentAvailable: false, - MutableContent: false, - Development: false, - Option: nil, } + resp, err := c.Push(ctx, req) if err != nil { log.Fatalf("could not push: %v", err) diff --git a/example/xiaomi/http/main.go b/example/xiaomi/http/main.go index 086c876..ed58bc4 100644 --- a/example/xiaomi/http/main.go +++ b/example/xiaomi/http/main.go @@ -1,13 +1,10 @@ package main import ( - "encoding/json" + "bytes" "fmt" - "github.com/cossim/hipush/api/http/v1/dto" "io/ioutil" "net/http" - "strings" - "time" ) var ( @@ -16,43 +13,29 @@ var ( ) func main() { - payload := dto.PushRequest{ - //AppID: "xxx", - AppName: "cossim", - Platform: "xiaomi", - Token: []string{ - "vAmkC65U7IthVLCyK0udEfUiXCiRAP5DXZtV2h0qt/vgo8k0foiQ8YS3VKcbPMa/", - }, - Data: dto.XiaomiPushRequestData{ - Title: "cossim", - Subtitle: "hello", - Content: "hello", - Icon: "", - TTL: time.Minute, - NotifyType: -1, - ScheduledTime: 0, - IsScheduled: false, - Foreground: true, - ClickAction: dto.ClickAction{ - Action: 1, - }, - Data: nil, - }, - Option: dto.PushOption{ - DryRun: false, - Retry: 1, - RetryInterval: 1, - }, - } - - // Marshal the request object to JSON - reqBody, err := json.Marshal(payload) - if err != nil { - panic(err) - } + payload := []byte(`{ + "platform": "xiaomi", + "token": [ + "xxx" + ], + "app_id": "2882303761520159644", + "app_name": "cossim", + "data": { + "title": "测试标题", + "subtitle": "测试子标题", + "content": "测试内容", + "foreground": true + }, + "option": { + "dry_run": true, + "development": false, + "retry": 0, + "retry_interval": 0 + } +}`) client := &http.Client{} - req, err := http.NewRequest(method, url, strings.NewReader(string(reqBody))) + req, err := http.NewRequest(method, url, bytes.NewBuffer(payload)) if err != nil { fmt.Println(err) return diff --git a/go.mod b/go.mod index ea756f6..0e4e011 100644 --- a/go.mod +++ b/go.mod @@ -46,6 +46,7 @@ require ( github.com/go-playground/universal-translator v0.18.1 // indirect github.com/go-playground/validator/v10 v10.14.0 // indirect github.com/goccy/go-json v0.10.2 // indirect + github.com/gogo/protobuf v1.3.2 // indirect github.com/golang-jwt/jwt/v4 v4.4.1 // indirect github.com/golang/groupcache v0.0.0-20210331224755-41bb18bfe9da // indirect github.com/google/s2a-go v0.1.7 // indirect diff --git a/go.sum b/go.sum index 979ee1f..9ac9577 100644 --- a/go.sum +++ b/go.sum @@ -77,6 +77,8 @@ github.com/go-playground/validator/v10 v10.14.0 h1:vgvQWe3XCz3gIeFDm/HnTIbj6UGmg github.com/go-playground/validator/v10 v10.14.0/go.mod h1:9iXMNT7sEkjXb0I+enO7QXmzG6QCsPWY4zveKFVRSyU= github.com/goccy/go-json v0.10.2 h1:CrxCmQqYDkv1z7lO7Wbh2HN93uovUHgrECaO5ZrCXAU= github.com/goccy/go-json v0.10.2/go.mod h1:6MelG93GURQebXPDq3khkgXZkazVtN9CRI+MGFi0w8I= +github.com/gogo/protobuf v1.3.2 h1:Ov1cvc58UF3b5XjBnZv7+opcTcQFZebYjWzi34vdm4Q= +github.com/gogo/protobuf v1.3.2/go.mod h1:P1XiOD3dCwIKUDQYPy72D8LYyHL2YPYrpS2s69NZV8Q= github.com/golang-jwt/jwt/v4 v4.4.1 h1:pC5DB52sCeK48Wlb9oPcdhnjkz1TKt1D/P7WKJ0kUcQ= github.com/golang-jwt/jwt/v4 v4.4.1/go.mod h1:m21LjoU+eqJr34lmDMbreY2eSTRJ1cv77w39/MY0Ch0= github.com/golang/glog v0.0.0-20160126235308-23def4e6c14b/go.mod h1:SBH7ygxi8pfUlaOkMMuAQtPIUF8ecWP5IEl/CR7VP2Q= @@ -120,6 +122,8 @@ github.com/jonboulle/clockwork v0.4.0 h1:p4Cf1aMWXnXAUh8lVfewRBx1zaTSYKrKMF2g3ST github.com/jonboulle/clockwork v0.4.0/go.mod h1:xgRqUGwRcjKCO1vbZUEtSLrqKoPSsUpK7fnezOII0kc= github.com/json-iterator/go v1.1.12 h1:PV8peI4a0ysnczrg+LtxykD8LfKY9ML6u2jnxaEnrnM= github.com/json-iterator/go v1.1.12/go.mod h1:e30LSqwooZae/UwlEbR2852Gd8hjQvJoHmT4TnhNGBo= +github.com/kisielk/errcheck v1.5.0/go.mod h1:pFxgyoBC7bSaBwPgfKdkLd5X25qrDl4LWUI2bnpBCr8= +github.com/kisielk/gotool v1.0.0/go.mod h1:XhKaO+MFFWcvkIS/tQcRk01m1F5IRFswLeQ+oQHNcck= github.com/klauspost/cpuid/v2 v2.0.9/go.mod h1:FInQzS24/EEf25PyTYn52gqo7WaD8xa0213Md/qVLRg= github.com/klauspost/cpuid/v2 v2.2.4 h1:acbojRNwl3o09bUq+yDCtZFc1aiwaAAxtcn8YkZXnvk= github.com/klauspost/cpuid/v2 v2.2.4/go.mod h1:RVVoqg1df56z8g3pUjL/3lE5UfnlrJX8tyFgg4nqhuY= @@ -170,6 +174,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/yuin/goldmark v1.1.27/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= +github.com/yuin/goldmark v1.2.1/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= github.com/yuin/goldmark v1.4.13/go.mod h1:6yULJ656Px+3vBD8DxQVa3kxgyrAnzto9xy5taEt/CY= go.opencensus.io v0.24.0 h1:y73uSU6J157QMP2kn2r30vwW1A2W2WFwSCGnAVxeaD0= go.opencensus.io v0.24.0/go.mod h1:vNK8G9p7aAivkbmorf4v+7Hgx+Zs0yY+0fOtgBfjQKo= @@ -194,6 +200,7 @@ golang.org/x/arch v0.3.0 h1:02VY4/ZcO/gBOH6PUaoiptASxtXU10jazRCP865E97k= golang.org/x/arch v0.3.0/go.mod h1:5om86z9Hs0C8fWVUuoMHwpExlXzs5Tkyp9hOrfG7pp8= golang.org/x/crypto v0.0.0-20170512130425-ab89591268e0/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4= golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w= +golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= golang.org/x/crypto v0.0.0-20210921155107-089bfa567519/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc= golang.org/x/crypto v0.21.0 h1:X31++rzVUdKhX5sWmSOFZxx8UW/ldWx55cbf08iNAMA= @@ -204,6 +211,8 @@ golang.org/x/exp v0.0.0-20231219180239-dc181d75b848/go.mod h1:iRJReGqOEeBhDZGkGb golang.org/x/lint v0.0.0-20181026193005-c67002cb31c3/go.mod h1:UVdnD1Gm6xHRNCYTkRU2/jEulfH38KcIWyp/GAMgvoE= golang.org/x/lint v0.0.0-20190227174305-5b3e6a55c961/go.mod h1:wehouNa3lNwaWXcvxsM5YxQ5yQlVC4a0KAMCusXpPoU= golang.org/x/lint v0.0.0-20190313153728-d0100b6bd8b3/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc= +golang.org/x/mod v0.2.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= +golang.org/x/mod v0.3.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= golang.org/x/mod v0.6.0-dev.0.20220419223038-86c51ed26bb4/go.mod h1:jJ57K6gSWd91VN4djpZkiMVwK6gcyfeH4XE8wZrZaV4= golang.org/x/net v0.0.0-20180724234803-3673e40ba225/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= golang.org/x/net v0.0.0-20180826012351-8a410e7b638d/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= @@ -211,6 +220,8 @@ golang.org/x/net v0.0.0-20190213061140-3a22650c66bd/go.mod h1:mL1N/T3taQHkDXs73r golang.org/x/net v0.0.0-20190311183353-d8887717615a/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= +golang.org/x/net v0.0.0-20200226121028-0de0cce0169b/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= +golang.org/x/net v0.0.0-20201021035429-f5854403a974/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU= golang.org/x/net v0.0.0-20201110031124-69a78807bb2b/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU= golang.org/x/net v0.0.0-20210226172049-e18ecbb05110/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg= golang.org/x/net v0.0.0-20220403103023-749bd193bc2b/go.mod h1:CfG3xpIq0wQ8r1q4Su4UZFWDARRcnwPjda9FqA0JpMk= @@ -223,6 +234,8 @@ golang.org/x/oauth2 v0.17.0/go.mod h1:OzPDGQiuQMguemayvdylqddI7qcD9lnSDb+1FiwQ5H golang.org/x/sync v0.0.0-20180314180146-1d60e4601c6f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20181108010431-42b317875d0f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sync v0.0.0-20190911185100-cd5d95a43a6e/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sync v0.0.0-20201020160332-67f06af15bc9/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20220722155255-886fb9371eb4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.6.0 h1:5BMeUDZ7vkXGfEr1x9B4bRcTH4lpkTkpdh0T/J+qjbQ= golang.org/x/sync v0.6.0/go.mod h1:Czt+wKu1gCyEFDUtn0jG5QVvpJ6rzVqr5aXyt9drQfk= @@ -255,9 +268,13 @@ golang.org/x/tools v0.0.0-20190226205152-f727befe758c/go.mod h1:9Yl7xja0Znq3iFh3 golang.org/x/tools v0.0.0-20190311212946-11955173bddd/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs= golang.org/x/tools v0.0.0-20190524140312-2c0ae7006135/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q= golang.org/x/tools v0.0.0-20191119224855-298f0cb1881e/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= +golang.org/x/tools v0.0.0-20200619180055-7c47624df98f/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE= +golang.org/x/tools v0.0.0-20210106214847-113979e3529a/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA= golang.org/x/tools v0.1.12/go.mod h1:hNGJHUnrk76NpqgfD5Aqm5Crs+Hm0VOH/i9J2+nxYbc= golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= +golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= +golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= golang.org/x/xerrors v0.0.0-20231012003039-104605ab7028 h1:+cNy6SZtPcJQH3LJVLOSmiC7MMxXNOb3PU/VUEz+EhU= google.golang.org/api v0.169.0 h1:QwWPy71FgMWqJN/l6jVlFHUa29a7dcUy02I8o799nPY= google.golang.org/api v0.169.0/go.mod h1:gpNOiMA2tZ4mf5R9Iwf4rK/Dcz0fbdIgWYWVoxmsyLg= diff --git a/internal/server/grpc/grpc.go b/internal/server/grpc/grpc.go index a1a0d42..9d2178e 100644 --- a/internal/server/grpc/grpc.go +++ b/internal/server/grpc/grpc.go @@ -5,16 +5,12 @@ import ( "encoding/json" "errors" "fmt" - "github.com/cossim/hipush/api/grpc/v1" + "github.com/cossim/hipush/api/pb/v1" push2 "github.com/cossim/hipush/api/push" "github.com/cossim/hipush/config" "github.com/cossim/hipush/internal/factory" - "github.com/cossim/hipush/pkg/consts" - "github.com/cossim/hipush/pkg/notify" - "github.com/cossim/hipush/pkg/push" "github.com/cossim/hipush/pkg/status" "github.com/go-logr/logr" - "github.com/golang/protobuf/jsonpb" "google.golang.org/grpc" "net" ) @@ -29,7 +25,7 @@ type Handler struct { func NewHandler(cfg *config.Config, logger logr.Logger, factory *factory.PushServiceFactory) *Handler { return &Handler{ cfg: cfg, - logger: logger.WithValues("server", "grpc"), + logger: logger.WithValues("server", "pb"), factory: factory, } } @@ -69,7 +65,7 @@ func (h *Handler) Start(ctx context.Context) error { func (h *Handler) Push(ctx context.Context, req *v1.PushRequest) (*v1.PushResponse, error) { resp := &v1.PushResponse{} - h.logger.Info("Received push request", "platform", req.Platform, "tokens", req.Tokens, "req", req) + h.logger.Info("Received push request", "platform", req.Platform, "tokens", req.Token, "req", req) status.StatStorage.AddGrpcTotal(1) @@ -80,16 +76,48 @@ func (h *Handler) Push(ctx context.Context, req *v1.PushRequest) (*v1.PushRespon return resp, err } - r, err := h.getPushRequest(req) + dataBytes, err := json.Marshal(req.Data) if err != nil { - status.StatStorage.AddGrpcFailed(1) - h.logger.Error(err, "failed to get push request") + h.logger.Error(err, "Failed to marshal data") + return resp, err + } + + fmt.Println("dataBytes => ", dataBytes) + + var r v1.APNsPushRequest + marshalJSON, err := req.Data.MarshalJSON() + if err != nil { + return nil, err + } + if err := json.Unmarshal(marshalJSON, &r); err != nil { + h.logger.Error(err, "Failed to unmarshal data") + return resp, err + } + + if err := h.validatePushRequest(&r); err != nil { return nil, err } - _, err = service.Send(ctx, r, &push2.SendOptions{ - DryRun: req.Option.DryRun, - Retry: int(req.Option.Retry), + r.Meta = &v1.Meta{ + AppID: req.AppID, + AppName: req.AppName, + Token: req.Token, + } + + option := v1.PushOption{} + if req.Option != nil { + option.Development = req.Option.Development + option.DryRun = req.Option.DryRun + option.Retry = req.Option.Retry + option.RetryInterval = req.Option.RetryInterval + } + + fmt.Println("r => ", r.String()) + + _, err = service.Send(ctx, &r, &push2.SendOptions{ + DryRun: option.DryRun, + Retry: option.Retry, + RetryInterval: option.RetryInterval, }) if err != nil { status.StatStorage.AddGrpcFailed(1) @@ -103,101 +131,33 @@ func (h *Handler) Push(ctx context.Context, req *v1.PushRequest) (*v1.PushRespon return resp, nil } -func (h *Handler) getPushRequest(req *v1.PushRequest) (push.PushRequest, error) { - badge := int(req.Badge) - - data := make(map[string]interface{}) - if req.Data != nil { - jsonStr, err := (&jsonpb.Marshaler{}).MarshalToString(req.Data) - if err != nil { - return nil, err - } - if err = json.Unmarshal([]byte(jsonStr), &data); err != nil { - return nil, err - } - } - - alert := notify.Alert{} - if req.Alert != nil { - alert = notify.Alert{ - Action: req.Alert.Action, - ActionLocKey: req.Alert.ActionLocKey, - Body: req.Alert.Body, - LaunchImage: req.Alert.LaunchImage, - LocArgs: req.Alert.LocArgs, - LocKey: req.Alert.LocKey, - Title: req.Alert.Title, - Subtitle: req.Alert.Subtitle, - TitleLocArgs: req.Alert.TitleLocArgs, - TitleLocKey: req.Alert.TitleLocKey, - } - } - - return ¬ify.ApnsPushNotification{ - AppID: req.AppID, - ApnsID: req.AppID, - Tokens: req.Tokens, - Title: req.Title, - Content: req.Message, - Topic: req.Topic, - Category: req.Category, - Sound: req.Sound, - Alert: alert, - Badge: &badge, - ThreadID: req.ThreadID, - Data: data, - PushType: req.PushType, - Priority: string(req.Priority), - ContentAvailable: req.ContentAvailable, - MutableContent: req.MutableContent, - Development: req.Development, - }, nil -} - -func (h *Handler) validatePushRequest(req *v1.PushRequest) error { +func (h *Handler) validatePushRequest(req *v1.APNsPushRequest) error { if req == nil { return errors.New("request is nil") } - if !consts.Platform(req.Platform).IsValid() { - return errors.New("invalid platform") + //if !consts.Platform(req.Platform).IsValid() { + // return errors.New("invalid platform") + // + //} - } - - if len(req.Tokens) == 0 { - return errors.New("tokens are required") - } + //if len(req.Token) == 0 { + // return errors.New("tokens are required") + //} // 检查其他必填字段 if req.Title == "" { return errors.New("title is required") } - if req.Message == "" { + if req.Content == "" { return errors.New("message is required") } - // 检查 Alert 字段 - if req.Alert != nil { - if err := h.validateAlert(req.Alert); err != nil { - return err - } - } - // 检查 Data 字段 - if req.Data == nil { - //return errors.New("data is required") - } + //if req.Data == nil { + //return errors.New("data is required") + //} return nil } - -func (h *Handler) validateAlert(alert *v1.Alert) error { - // TODO 检查 Alert 字段的必填参数 - return nil -} - -func (h *Handler) mustEmbedUnimplementedPushServiceServer() { - //TODO implement me - panic("implement me") -} diff --git a/internal/server/http/android.go b/internal/server/http/android.go index 9c8d591..d7ee9ac 100644 --- a/internal/server/http/android.go +++ b/internal/server/http/android.go @@ -2,16 +2,13 @@ package http import ( "encoding/json" - "fmt" - "github.com/cossim/hipush/api/http/v1/dto" + v1 "github.com/cossim/hipush/api/pb/v1" "github.com/cossim/hipush/api/push" - "github.com/cossim/hipush/pkg/notify" "github.com/gin-gonic/gin" "net/http" - "time" ) -func (h *Handler) handleAndroidPush(c *gin.Context, req *dto.PushRequest) error { +func (h *Handler) handleAndroidPush(c *gin.Context, req *v1.PushRequest) error { service, err := h.factory.GetPushService(req.Platform) if err != nil { h.logger.Error(err, "Failed to get push service") @@ -25,39 +22,21 @@ func (h *Handler) handleAndroidPush(c *gin.Context, req *dto.PushRequest) error c.JSON(http.StatusBadRequest, Response{Code: http.StatusBadRequest, Msg: "invalid data", Data: nil}) return err } - var r dto.AndroidPushRequestData + var r v1.AndroidPushRequestData if err := json.Unmarshal(dataBytes, &r); err != nil { h.logger.Error(err, "Failed to unmarshal data") c.JSON(http.StatusBadRequest, Response{Code: http.StatusBadRequest, Msg: "invalid data", Data: nil}) return err } - h.logger.Info("Handling push request", "platform", req.Platform, "appID", req.AppID, "tokens", req.Token, "req", r) + h.logger.Info("Handling push request", "platform", req.Platform, "appID", req.AppID, "tokens", req.Token, "req", r.String()) - ttl, err := time.ParseDuration(r.TTL) - if err != nil { - c.JSON(http.StatusBadRequest, Response{Code: http.StatusBadRequest, Msg: "invalid ttl", Data: nil}) - return err - } - - fmt.Println("ttl => ", ttl) - - rr := ¬ify.FCMPushNotification{ - AppID: req.AppID, - AppName: req.AppName, - Tokens: req.Token, - Title: r.Title, - Content: r.Content, - Topic: r.Topic, - Priority: r.Priority, - Image: r.Image, - Sound: r.Sound, - CollapseID: r.CollapseID, - Condition: r.Condition, - TTL: ttl, - Data: r.Data, + r.Meta = &v1.Meta{ + AppID: req.AppID, + AppName: req.AppName, + Token: req.Token, } - resp, err := service.Send(c, rr, &push.SendOptions{ + resp, err := service.Send(c, &r, &push.SendOptions{ DryRun: req.Option.DryRun, Retry: req.Option.Retry, RetryInterval: req.Option.RetryInterval, diff --git a/internal/server/http/honor.go b/internal/server/http/honor.go index 25516a5..9b0cbaa 100644 --- a/internal/server/http/honor.go +++ b/internal/server/http/honor.go @@ -2,16 +2,14 @@ package http import ( "encoding/json" - "github.com/cossim/hipush/api/http/v1/dto" + v1 "github.com/cossim/hipush/api/pb/v1" "github.com/cossim/hipush/api/push" "github.com/cossim/hipush/pkg/consts" - "github.com/cossim/hipush/pkg/notify" "github.com/gin-gonic/gin" "net/http" - "strconv" ) -func (h *Handler) handleHonorPush(c *gin.Context, req *dto.PushRequest) error { +func (h *Handler) handleHonorPush(c *gin.Context, req *v1.PushRequest) error { service, err := h.factory.GetPushService(consts.Platform(req.Platform).String()) if err != nil { c.JSON(http.StatusBadRequest, Response{Code: http.StatusBadRequest, Msg: err.Error(), Data: nil}) @@ -24,41 +22,22 @@ func (h *Handler) handleHonorPush(c *gin.Context, req *dto.PushRequest) error { c.JSON(http.StatusBadRequest, Response{Code: http.StatusBadRequest, Msg: "invalid data", Data: nil}) return err } - var r dto.HonorPushRequestData + var r v1.HonorPushRequestData if err := json.Unmarshal(dataBytes, &r); err != nil { h.logger.Error(err, "Failed to unmarshal data") c.JSON(http.StatusBadRequest, Response{Code: http.StatusBadRequest, Msg: "invalid data", Data: nil}) return err } - h.logger.Info("Handling push request", "platform", req.Platform, "appID", req.AppID, "tokens", req.Token, "req", r) + h.logger.Info("Handling push request", "platform", req.Platform, "appID", req.AppID, "tokens", req.Token, "req", r.String()) - rr := ¬ify.HonorPushNotification{ - AppID: req.AppID, - AppName: req.AppName, - Tokens: req.Token, - Title: r.Title, - Content: r.Content, - Image: r.Icon, - Priority: "", - Category: "", - TTL: strconv.Itoa(r.TTL), - Data: r.Data, - Development: r.Development, - Badge: ¬ify.BadgeNotification{ - AddNum: r.Badge.AddNum, - SetNum: r.Badge.SetNum, - BadgeClass: r.Badge.Class, - }, - ClickAction: ¬ify.HonorClickAction{ - Action: r.ClickAction.Action, - Activity: r.ClickAction.Activity, - Url: r.ClickAction.Url, - Parameters: r.ClickAction.Parameters, - }, - NotifyId: r.NotifyId, + r.Meta = &v1.Meta{ + AppID: req.AppID, + AppName: req.AppName, + Token: req.Token, } - resp, err := service.Send(c, rr, &push.SendOptions{ + + resp, err := service.Send(c, &r, &push.SendOptions{ DryRun: req.Option.DryRun, Retry: req.Option.Retry, RetryInterval: req.Option.RetryInterval, diff --git a/internal/server/http/http.go b/internal/server/http/http.go index aaaf204..e85043a 100644 --- a/internal/server/http/http.go +++ b/internal/server/http/http.go @@ -4,7 +4,7 @@ import ( "context" "errors" "fmt" - "github.com/cossim/hipush/api/http/v1/dto" + v1 "github.com/cossim/hipush/api/pb/v1" "github.com/cossim/hipush/config" "github.com/cossim/hipush/internal/factory" "github.com/cossim/hipush/pkg/consts" @@ -75,7 +75,7 @@ func (h *Handler) Start(ctx context.Context) error { } func (h *Handler) pushHandler(c *gin.Context) { - req := &dto.PushRequest{} + req := &v1.PushRequest{} if err := c.ShouldBindJSON(req); err != nil { h.logger.Error(err, "failed to bind request") c.JSON(http.StatusBadRequest, Response{Code: http.StatusBadRequest, Msg: err.Error(), Data: nil}) diff --git a/internal/server/http/huawei.go b/internal/server/http/huawei.go index c9972e3..10c4278 100644 --- a/internal/server/http/huawei.go +++ b/internal/server/http/huawei.go @@ -2,16 +2,14 @@ package http import ( "encoding/json" - "fmt" - "github.com/cossim/hipush/api/http/v1/dto" + v1 "github.com/cossim/hipush/api/pb/v1" "github.com/cossim/hipush/api/push" "github.com/cossim/hipush/pkg/consts" - "github.com/cossim/hipush/pkg/notify" "github.com/gin-gonic/gin" "net/http" ) -func (h *Handler) handleHuaweiPush(c *gin.Context, req *dto.PushRequest) error { +func (h *Handler) handleHuaweiPush(c *gin.Context, req *v1.PushRequest) error { service, err := h.factory.GetPushService(consts.Platform(req.Platform).String()) if err != nil { c.JSON(http.StatusBadRequest, Response{Code: http.StatusBadRequest, Msg: err.Error(), Data: nil}) @@ -24,32 +22,21 @@ func (h *Handler) handleHuaweiPush(c *gin.Context, req *dto.PushRequest) error { c.JSON(http.StatusBadRequest, Response{Code: http.StatusBadRequest, Msg: "invalid data", Data: nil}) return err } - var r dto.HuaweiPushRequestData + var r v1.HuaweiPushRequestData if err := json.Unmarshal(dataBytes, &r); err != nil { h.logger.Error(err, "Failed to unmarshal data") c.JSON(http.StatusBadRequest, Response{Code: http.StatusBadRequest, Msg: "invalid data", Data: nil}) return err } - h.logger.Info("Handling push request", "platform", req.Platform, "appID", req.AppID, "tokens", req.Token, "req", r) + h.logger.Info("Handling push request", "platform", req.Platform, "appID", req.AppID, "tokens", req.Token, "req", r.String()) - fmt.Println("title => ", r.Title) - - rr := ¬ify.HMSPushNotification{ - AppID: req.AppID, - AppName: req.AppName, - Tokens: req.Token, - Development: r.Development, - Title: r.Title, - Content: r.Content, - Category: r.Category, - Badge: notify.BadgeNotification{ - AddNum: r.Badge.AddNum, - SetNum: r.Badge.SetNum, - BadgeClass: r.Badge.Class, - }, + r.Meta = &v1.Meta{ + AppID: req.AppID, + AppName: req.AppName, + Token: req.Token, } - resp, err := service.Send(c, rr, &push.SendOptions{ + resp, err := service.Send(c, &r, &push.SendOptions{ DryRun: req.Option.DryRun, Retry: req.Option.Retry, RetryInterval: req.Option.RetryInterval, diff --git a/internal/server/http/ios.go b/internal/server/http/ios.go index 845b7da..2ab9e6e 100644 --- a/internal/server/http/ios.go +++ b/internal/server/http/ios.go @@ -4,14 +4,13 @@ import ( "encoding/json" "errors" "fmt" - "github.com/cossim/hipush/api/http/v1/dto" + v1 "github.com/cossim/hipush/api/pb/v1" "github.com/cossim/hipush/api/push" - "github.com/cossim/hipush/pkg/notify" "github.com/gin-gonic/gin" "net/http" ) -func (h *Handler) handleIOSPush(c *gin.Context, req *dto.PushRequest) error { +func (h *Handler) handleIOSPush(c *gin.Context, req *v1.PushRequest) error { service, err := h.factory.GetPushService(req.Platform) if err != nil { h.logger.Error(err, "Failed to get push service") @@ -19,22 +18,22 @@ func (h *Handler) handleIOSPush(c *gin.Context, req *dto.PushRequest) error { return err } + fmt.Println("req data => ", req.Data) + dataBytes, err := json.Marshal(req.Data) if err != nil { h.logger.Error(err, "Failed to marshal data") c.JSON(http.StatusBadRequest, Response{Code: http.StatusBadRequest, Msg: "invalid data", Data: nil}) return err } - var r dto.APNsPushRequest + var r v1.APNsPushRequest if err := json.Unmarshal(dataBytes, &r); err != nil { h.logger.Error(err, "Failed to unmarshal data") c.JSON(http.StatusBadRequest, Response{Code: http.StatusBadRequest, Msg: "invalid data", Data: nil}) return err } - h.logger.Info("Handling push request", "platform", req.Platform, "appID", req.AppID, "tokens", req.Token, "req", r) - - var topic = r.Topic + h.logger.Info("Handling push request", "platform", req.Platform, "appID", req.AppID, "tokens", req.Token, "req", r.String()) if req.AppID == "" && r.Topic == "" { msg := errors.New("one of AppID and Topic cannot be empty") @@ -42,31 +41,12 @@ func (h *Handler) handleIOSPush(c *gin.Context, req *dto.PushRequest) error { return msg } - if r.Topic == "" { - topic = req.AppID - } - - fmt.Println("topic => ", topic) - - rr := ¬ify.ApnsPushNotification{ - AppID: req.AppID, - AppName: req.AppName, - Tokens: req.Token, - Title: r.Title, - Topic: topic, - Content: r.Content, - ApnsID: r.ApnsID, - Sound: r.Sound, - Development: r.Development, - MutableContent: r.MutableContent, - CollapseID: r.CollapseID, - ContentAvailable: r.ContentAvailable, - Priority: r.Priority, - Data: r.Data, - Badge: &r.Badge, - Expiration: &r.TTL, + r.Meta = &v1.Meta{ + AppID: req.AppID, + AppName: req.AppName, + Token: req.Token, } - resp, err := service.Send(c, rr, &push.SendOptions{ + resp, err := service.Send(c, &r, &push.SendOptions{ DryRun: req.Option.DryRun, Retry: req.Option.Retry, RetryInterval: req.Option.RetryInterval, diff --git a/internal/server/http/meizu.go b/internal/server/http/meizu.go index 1b7c63d..8326dcd 100644 --- a/internal/server/http/meizu.go +++ b/internal/server/http/meizu.go @@ -2,15 +2,14 @@ package http import ( "encoding/json" - "github.com/cossim/hipush/api/http/v1/dto" + v1 "github.com/cossim/hipush/api/pb/v1" "github.com/cossim/hipush/api/push" "github.com/cossim/hipush/pkg/consts" - "github.com/cossim/hipush/pkg/notify" "github.com/gin-gonic/gin" "net/http" ) -func (h *Handler) handleMeizuPush(c *gin.Context, req *dto.PushRequest) error { +func (h *Handler) handleMeizuPush(c *gin.Context, req *v1.PushRequest) error { service, err := h.factory.GetPushService(consts.Platform(req.Platform).String()) if err != nil { c.JSON(http.StatusBadRequest, Response{Code: http.StatusBadRequest, Msg: err.Error(), Data: nil}) @@ -23,37 +22,24 @@ func (h *Handler) handleMeizuPush(c *gin.Context, req *dto.PushRequest) error { c.JSON(http.StatusBadRequest, Response{Code: http.StatusBadRequest, Msg: "invalid data", Data: nil}) return err } - var r dto.MeizuPushRequestData + var r v1.MeizuPushRequestData if err := json.Unmarshal(dataBytes, &r); err != nil { h.logger.Error(err, "Failed to unmarshal data") c.JSON(http.StatusBadRequest, Response{Code: http.StatusBadRequest, Msg: "invalid data", Data: nil}) return err } - h.logger.Info("Handling push request", "platform", req.Platform, "appID", req.AppID, "tokens", req.Token, "req", r) + h.logger.Info("Handling push request", "platform", req.Platform, "appID", req.AppID, "tokens", req.Token, "req", r.String()) - rr := ¬ify.MeizuPushNotification{ - AppID: req.AppID, - AppName: req.AppName, - Tokens: req.Token, - Title: r.Title, - Content: r.Content, - NotifyType: r.NotifyType, - ClickAction: ¬ify.MeizuClickAction{ - Action: r.ClickAction.Action, - Activity: r.ClickAction.Activity, - Url: r.ClickAction.Url, - Parameters: r.ClickAction.Parameters, - }, - TTL: r.TTL, - OffLine: false, - IsShowNotify: false, - IsScheduled: r.IsScheduled, - ScheduledStartTime: r.ScheduledStartTime, - ScheduledEndTime: r.ScheduledEndTime, + r.Meta = &v1.Meta{ + AppID: req.AppID, + AppName: req.AppName, + Token: req.Token, } - resp, err := service.Send(c, rr, &push.SendOptions{ + + resp, err := service.Send(c, &r, &push.SendOptions{ DryRun: req.Option.DryRun, + Development: req.Option.Development, Retry: req.Option.Retry, RetryInterval: req.Option.RetryInterval, }) diff --git a/internal/server/http/oppo.go b/internal/server/http/oppo.go index 3c580d0..103545a 100644 --- a/internal/server/http/oppo.go +++ b/internal/server/http/oppo.go @@ -2,15 +2,14 @@ package http import ( "encoding/json" - "github.com/cossim/hipush/api/http/v1/dto" + v1 "github.com/cossim/hipush/api/pb/v1" "github.com/cossim/hipush/api/push" "github.com/cossim/hipush/pkg/consts" - "github.com/cossim/hipush/pkg/notify" "github.com/gin-gonic/gin" "net/http" ) -func (h *Handler) handleOppoPush(c *gin.Context, req *dto.PushRequest) error { +func (h *Handler) handleOppoPush(c *gin.Context, req *v1.PushRequest) error { service, err := h.factory.GetPushService(consts.Platform(req.Platform).String()) if err != nil { c.JSON(http.StatusBadRequest, Response{Code: http.StatusBadRequest, Msg: err.Error(), Data: nil}) @@ -23,35 +22,25 @@ func (h *Handler) handleOppoPush(c *gin.Context, req *dto.PushRequest) error { c.JSON(http.StatusBadRequest, Response{Code: http.StatusBadRequest, Msg: "invalid data", Data: nil}) return err } - var r dto.OppoPushRequestData + var r v1.OppoPushRequestData if err := json.Unmarshal(dataBytes, &r); err != nil { h.logger.Error(err, "Failed to unmarshal data") c.JSON(http.StatusBadRequest, Response{Code: http.StatusBadRequest, Msg: "invalid data", Data: nil}) return err } - rr := ¬ify.OppoPushNotification{ - AppID: req.AppID, - AppName: req.AppName, - Tokens: req.Token, - Title: r.Title, - Subtitle: r.Subtitle, - Message: r.Content, - Data: r.Data, - ClickAction: &r.ClickAction, - TTL: r.TTL, - Option: notify.PushOption{ - DryRun: req.Option.DryRun, - Retry: req.Option.Retry, - }, + r.Meta = &v1.Meta{ + AppID: req.AppID, + AppName: req.AppName, + Token: req.Token, } - resp, err := service.Send(c, rr, &push.SendOptions{ + resp, err := service.Send(c, &r, &push.SendOptions{ DryRun: req.Option.DryRun, Retry: req.Option.Retry, RetryInterval: req.Option.RetryInterval, }) if err != nil { - c.JSON(http.StatusInternalServerError, Response{Code: http.StatusBadRequest, Msg: err.Error(), Data: nil}) + c.JSON(http.StatusBadRequest, Response{Code: http.StatusBadRequest, Msg: err.Error(), Data: nil}) return err } diff --git a/internal/server/http/vivo.go b/internal/server/http/vivo.go index 2d29742..ed6eb9c 100644 --- a/internal/server/http/vivo.go +++ b/internal/server/http/vivo.go @@ -2,15 +2,14 @@ package http import ( "encoding/json" - "github.com/cossim/hipush/api/http/v1/dto" + v1 "github.com/cossim/hipush/api/pb/v1" "github.com/cossim/hipush/api/push" "github.com/cossim/hipush/pkg/consts" - "github.com/cossim/hipush/pkg/notify" "github.com/gin-gonic/gin" "net/http" ) -func (h *Handler) handleVivoPush(c *gin.Context, req *dto.PushRequest) error { +func (h *Handler) handleVivoPush(c *gin.Context, req *v1.PushRequest) error { service, err := h.factory.GetPushService(consts.Platform(req.Platform).String()) if err != nil { c.JSON(http.StatusBadRequest, Response{Code: http.StatusBadRequest, Msg: err.Error(), Data: nil}) @@ -23,39 +22,21 @@ func (h *Handler) handleVivoPush(c *gin.Context, req *dto.PushRequest) error { c.JSON(http.StatusBadRequest, Response{Code: http.StatusBadRequest, Msg: "invalid data", Data: nil}) return err } - var r dto.VivoPushRequestData + var r v1.VivoPushRequestData if err := json.Unmarshal(dataBytes, &r); err != nil { h.logger.Error(err, "Failed to unmarshal data") c.JSON(http.StatusBadRequest, Response{Code: http.StatusBadRequest, Msg: "invalid data", Data: nil}) return err } - h.logger.Info("Handling push request", "platform", req.Platform, "appID", req.AppID, "tokens", req.Token, "req", r) + h.logger.Info("Handling push request", "platform", req.Platform, "appID", req.AppID, "tokens", req.Token, "req", r.String()) - rr := ¬ify.VivoPushNotification{ + r.Meta = &v1.Meta{ AppID: req.AppID, AppName: req.AppName, - //RequestId: r.TaskID, - Tokens: req.Token, - Title: r.Title, - Message: r.Content, - Category: r.Category, - Data: r.Data, - ClickAction: ¬ify.VivoClickAction{ - Action: r.ClickAction.Action, - Url: r.ClickAction.Url, - Activity: r.ClickAction.Activity, - }, - TaskID: r.TaskID, - NotifyID: r.NotifyID, - NotifyType: r.NotifyType, - TTL: r.TTL, - Retry: 0, - SendOnline: false, - Foreground: r.Foreground, - Development: r.Development, + Token: req.Token, } - resp, err := service.Send(c, rr, &push.SendOptions{ + resp, err := service.Send(c, &r, &push.SendOptions{ DryRun: req.Option.DryRun, Retry: req.Option.Retry, RetryInterval: req.Option.RetryInterval, diff --git a/internal/server/http/xiaomi.go b/internal/server/http/xiaomi.go index ad1bd28..d3b21f9 100644 --- a/internal/server/http/xiaomi.go +++ b/internal/server/http/xiaomi.go @@ -2,15 +2,14 @@ package http import ( "encoding/json" - "github.com/cossim/hipush/api/http/v1/dto" + v1 "github.com/cossim/hipush/api/pb/v1" "github.com/cossim/hipush/api/push" "github.com/cossim/hipush/pkg/consts" - "github.com/cossim/hipush/pkg/notify" "github.com/gin-gonic/gin" "net/http" ) -func (h *Handler) handleXiaomiPush(c *gin.Context, req *dto.PushRequest) error { +func (h *Handler) handleXiaomiPush(c *gin.Context, req *v1.PushRequest) error { service, err := h.factory.GetPushService(consts.Platform(req.Platform).String()) if err != nil { c.JSON(http.StatusBadRequest, Response{Code: http.StatusBadRequest, Msg: err.Error(), Data: nil}) @@ -23,34 +22,27 @@ func (h *Handler) handleXiaomiPush(c *gin.Context, req *dto.PushRequest) error { c.JSON(http.StatusBadRequest, Response{Code: http.StatusBadRequest, Msg: "invalid data", Data: nil}) return err } - var r dto.XiaomiPushRequestData + var r v1.XiaomiPushRequestData if err := json.Unmarshal(dataBytes, &r); err != nil { h.logger.Error(err, "Failed to unmarshal data") c.JSON(http.StatusBadRequest, Response{Code: http.StatusBadRequest, Msg: "invalid data", Data: nil}) return err } - h.logger.Info("Handling push request", "platform", req.Platform, "appID", req.AppID, "appName", req.AppName, "tokens", req.Token, "req", r) + h.logger.Info("Handling push request", "platform", req.Platform, "appID", req.AppID, "appName", req.AppName, "tokens", req.Token, "req", r.String()) - rr := ¬ify.XiaomiPushNotification{ - AppID: req.AppID, - AppName: req.AppName, - Tokens: req.Token, - Title: r.Title, - Content: r.Content, - NotifyType: r.NotifyType, - TTL: int64(r.TTL), - IsShowNotify: r.Foreground, - IsScheduled: r.IsScheduled, - ScheduledTime: r.ScheduledTime, + r.Meta = &v1.Meta{ + AppID: req.AppID, + AppName: req.AppName, + Token: req.Token, } - resp, err := service.Send(c, rr, &push.SendOptions{ + resp, err := service.Send(c, &r, &push.SendOptions{ DryRun: req.Option.DryRun, Retry: req.Option.Retry, RetryInterval: req.Option.RetryInterval, }) if err != nil { - c.JSON(http.StatusInternalServerError, Response{Code: http.StatusBadRequest, Msg: err.Error(), Data: nil}) + c.JSON(http.StatusBadRequest, Response{Code: http.StatusBadRequest, Msg: err.Error(), Data: nil}) return err } diff --git a/pkg/consts/store.go b/pkg/consts/store.go index ac7a858..ff13623 100644 --- a/pkg/consts/store.go +++ b/pkg/consts/store.go @@ -21,7 +21,7 @@ const ( // HTTP方式 HTTPPrefix = key + "-http" // GRPC方式 - GRPCPrefix = key + "-grpc" + GRPCPrefix = key + "-pb" // iOS平台 iOSPrefix = key + "-ios" diff --git a/pkg/notify/apns_notify.go b/pkg/notify/apns_notify.go deleted file mode 100644 index 31beca8..0000000 --- a/pkg/notify/apns_notify.go +++ /dev/null @@ -1,333 +0,0 @@ -package notify - -import ( - "github.com/mitchellh/mapstructure" - "github.com/sideshow/apns2" - "github.com/sideshow/apns2/payload" - "time" -) - -type ApnsPushNotification struct { - AppID string `json:"app_id,omitempty"` - AppName string `json:"app_name,omitempty"` - - Tokens []string `json:"tokens" binding:"required"` - Priority string `json:"priority,omitempty"` - Title string `json:"title,omitempty"` - Content string `json:"content,omitempty"` - Expiration *int64 `json:"expiration,omitempty"` - ApnsID string `json:"apns_id,omitempty"` - CollapseID string `json:"collapse_id,omitempty"` - Topic string `json:"topic,omitempty"` - PushType string `json:"push_type,omitempty"` - Badge *int `json:"badge,omitempty"` - Category string `json:"category,omitempty"` - ThreadID string `json:"thread-id,omitempty"` - URLArgs []string `json:"url-args,omitempty"` - Alert Alert `json:"alert,omitempty"` - ContentAvailable bool `json:"content_available,omitempty"` - MutableContent bool `json:"mutable_content"` - Production bool `json:"production,omitempty"` - Development bool `json:"development,omitempty"` - SoundName string `json:"name,omitempty"` - SoundVolume float32 `json:"volume,omitempty"` - Apns D `json:"apns,omitempty"` - InterruptionLevel string `json:"interruption_level,omitempty"` - Sound interface{} `json:"sound,omitempty"` - Data map[string]interface{} `json:"data,omitempty"` -} - -func (a *ApnsPushNotification) Get() interface{} { - //TODO implement me - panic("implement me") -} - -func (a *ApnsPushNotification) GetRetry() int { - return 0 -} - -func (a *ApnsPushNotification) GetTokens() []string { - return a.Tokens -} - -func (a *ApnsPushNotification) GetTitle() string { - return a.Title -} - -func (a *ApnsPushNotification) GetMessage() string { - return a.Content -} - -func (a *ApnsPushNotification) GetTopic() string { - return a.Topic -} - -func (a *ApnsPushNotification) GetKey() string { - //TODO implement me - panic("implement me") -} - -func (a *ApnsPushNotification) GetCategory() string { - return a.Category -} - -func (a *ApnsPushNotification) GetSound() interface{} { - return a.Sound -} - -func (a *ApnsPushNotification) GetAlert() interface{} { - return a.Alert -} - -func (a *ApnsPushNotification) GetBadge() int { - if a.Badge == nil { - return 0 - } - return *a.Badge -} - -func (a *ApnsPushNotification) GetThreadID() string { - return a.ThreadID -} - -func (a *ApnsPushNotification) GetData() map[string]interface{} { - return a.Data -} - -func (a *ApnsPushNotification) GetImage() string { - //TODO implement me - panic("implement me") -} - -func (a *ApnsPushNotification) GetID() string { - //TODO implement me - panic("implement me") -} - -func (a *ApnsPushNotification) GetPushType() string { - return a.PushType -} - -func (a *ApnsPushNotification) GetPriority() string { - return a.Priority -} - -func (a *ApnsPushNotification) IsContentAvailable() bool { - return a.ContentAvailable -} - -func (a *ApnsPushNotification) IsMutableContent() bool { - return a.MutableContent -} - -func (a *ApnsPushNotification) IsDevelopment() bool { - return a.Development -} - -func (a *ApnsPushNotification) GetExpiration() *int64 { - if a.Expiration == nil { - return nil - } - return a.Expiration -} - -func (a *ApnsPushNotification) GetApnsID() string { - return a.ApnsID -} - -func (a *ApnsPushNotification) GetCollapseID() string { - return a.CollapseID -} - -func (a *ApnsPushNotification) GetURLArgs() []string { - return a.URLArgs -} - -func (a *ApnsPushNotification) GetSoundName() string { - return a.SoundName -} - -func (a *ApnsPushNotification) GetSoundVolume() float32 { - return a.SoundVolume -} - -func (a *ApnsPushNotification) GetApns() map[string]interface{} { - return a.Apns -} - -func (a *ApnsPushNotification) GetInterruptionLevel() string { - return a.InterruptionLevel -} - -// Alert is APNs payload -type Alert struct { - Action string `json:"action,omitempty"` - ActionLocKey string `json:"action-loc-key,omitempty"` - Body string `json:"body,omitempty"` - LaunchImage string `json:"launch-image,omitempty"` - LocArgs []string `json:"loc-args,omitempty"` - LocKey string `json:"loc-key,omitempty"` - Title string `json:"title,omitempty"` - Subtitle string `json:"subtitle,omitempty"` - TitleLocArgs []string `json:"title-loc-args,omitempty"` - TitleLocKey string `json:"title-loc-key,omitempty"` - SummaryArg string `json:"summary-arg,omitempty"` - SummaryArgCount int `json:"summary-arg-count,omitempty"` -} - -// GetIOSNotification use for define iOS notification. -// The iOS Notification Payload (Payload Key Reference) -// Ref: https://apple.co/2VtH6Iu -func GetIOSNotification(req *ApnsPushNotification) *apns2.Notification { - notification := &apns2.Notification{ - ApnsID: req.ApnsID, - Topic: req.Topic, - CollapseID: req.CollapseID, - } - - if req.Expiration != nil { - notification.Expiration = time.Unix(*req.Expiration, 0) - } - - if len(req.Priority) > 0 { - if req.Priority == "normal" { - notification.Priority = apns2.PriorityLow - } else if req.Priority == HIGH { - notification.Priority = apns2.PriorityHigh - } - } - - if len(req.PushType) > 0 { - notification.PushType = apns2.EPushType(req.PushType) - } - - payload := payload.NewPayload() - - // add alert object if message length > 0 and title is empty - if len(req.Content) > 0 && req.Title == "" { - payload.Alert(req.Content) - } - - // zero value for clear the badge on the app icon. - if req.Badge != nil && *req.Badge >= 0 { - payload.Badge(*req.Badge) - } - - if req.MutableContent { - payload.MutableContent() - } - - switch req.Sound.(type) { - // from http request binding - case map[string]interface{}: - result := &Sound{} - _ = mapstructure.Decode(req.Sound, &result) - payload.Sound(result) - // from http request binding for non critical alerts - case string: - payload.Sound(&req.Sound) - case Sound: - payload.Sound(&req.Sound) - } - - if len(req.SoundName) > 0 { - payload.SoundName(req.SoundName) - } - - if req.SoundVolume > 0 { - payload.SoundVolume(req.SoundVolume) - } - - if req.ContentAvailable { - payload.ContentAvailable() - } - - if len(req.URLArgs) > 0 { - payload.URLArgs(req.URLArgs) - } - - if len(req.ThreadID) > 0 { - payload.ThreadID(req.ThreadID) - } - - for k, v := range req.Data { - payload.Custom(k, v) - } - - payload = iosAlertDictionary(payload, req) - - notification.Payload = payload - - return notification -} - -func iosAlertDictionary(notificationPayload *payload.Payload, req *ApnsPushNotification) *payload.Payload { - // Alert dictionary - - if len(req.Title) > 0 { - notificationPayload.AlertTitle(req.Title) - } - - if len(req.InterruptionLevel) > 0 { - notificationPayload.InterruptionLevel(payload.EInterruptionLevel(req.InterruptionLevel)) - } - - if len(req.Content) > 0 && len(req.Title) > 0 { - notificationPayload.AlertBody(req.Content) - } - - if len(req.Alert.Title) > 0 { - notificationPayload.AlertTitle(req.Alert.Title) - } - - // Apple Watch & Safari display this string as part of the notification interface. - if len(req.Alert.Subtitle) > 0 { - notificationPayload.AlertSubtitle(req.Alert.Subtitle) - } - - if len(req.Alert.TitleLocKey) > 0 { - notificationPayload.AlertTitleLocKey(req.Alert.TitleLocKey) - } - - if len(req.Alert.LocArgs) > 0 { - notificationPayload.AlertLocArgs(req.Alert.LocArgs) - } - - if len(req.Alert.TitleLocArgs) > 0 { - notificationPayload.AlertTitleLocArgs(req.Alert.TitleLocArgs) - } - - if len(req.Alert.Body) > 0 { - notificationPayload.AlertBody(req.Alert.Body) - } - - if len(req.Alert.LaunchImage) > 0 { - notificationPayload.AlertLaunchImage(req.Alert.LaunchImage) - } - - if len(req.Alert.LocKey) > 0 { - notificationPayload.AlertLocKey(req.Alert.LocKey) - } - - if len(req.Alert.Action) > 0 { - notificationPayload.AlertAction(req.Alert.Action) - } - - if len(req.Alert.ActionLocKey) > 0 { - notificationPayload.AlertActionLocKey(req.Alert.ActionLocKey) - } - - // General - if len(req.Category) > 0 { - notificationPayload.Category(req.Category) - } - - if len(req.Alert.SummaryArg) > 0 { - notificationPayload.AlertSummaryArg(req.Alert.SummaryArg) - } - if req.Alert.SummaryArgCount > 0 { - notificationPayload.AlertSummaryArgCount(req.Alert.SummaryArgCount) - } - - return notificationPayload -} diff --git a/pkg/notify/fcm_notify.go b/pkg/notify/fcm_notify.go deleted file mode 100644 index c4f9547..0000000 --- a/pkg/notify/fcm_notify.go +++ /dev/null @@ -1,22 +0,0 @@ -package notify - -import "time" - -type FCMPushNotification struct { - AppID string `json:"app_id,omitempty"` - AppName string `json:"app_name,omitempty"` - Tokens []string `json:"tokens,omitempty"` - Title string `json:"title,omitempty"` - Content string `json:"content,omitempty"` - Topic string `json:"topic,omitempty"` - Priority string `json:"priority,omitempty"` - Image string `json:"image,omitempty"` - Sound string `json:"sound,omitempty"` - CollapseID string `json:"collapse_id,omitempty"` - Category string `json:"category,omitempty"` - Condition string `json:"condition,omitempty"` - TTL time.Duration `json:"ttl,omitempty"` - Badge *int `json:"badge,omitempty"` - Data map[string]string `json:"data,omitempty"` - Apns D `json:"apns,omitempty"` -} diff --git a/pkg/notify/hms_notify.go b/pkg/notify/hms_notify.go deleted file mode 100644 index de116c9..0000000 --- a/pkg/notify/hms_notify.go +++ /dev/null @@ -1,25 +0,0 @@ -package notify - -type HMSPushNotification struct { - AppID string `json:"app_id,omitempty"` - AppName string `json:"app_name,omitempty"` - Tokens []string `json:"tokens" binding:"required"` - Topic string `json:"topic,omitempty"` - Title string `json:"title,omitempty"` - Category string `json:"category,omitempty"` - Content string `json:"content,omitempty"` - Condition string `json:"condition,omitempty"` - Priority string `json:"priority,omitempty"` - CollapseKey int `json:"collapse_key,omitempty"` - Image string `json:"image,omitempty"` - Data string `json:"huawei_data,omitempty"` - TTL string `json:"huawei_ttl,omitempty"` - BiTag string `json:"bi_tag,omitempty"` - Sound interface{} `json:"sound,omitempty"` - FastAppTarget int `json:"fast_app_target,omitempty"` - - // Badge 消息角标 - Badge BadgeNotification `json:"badge,omitempty"` - - Development bool `json:"development,omitempty"` -} diff --git a/pkg/notify/honor_notify.go b/pkg/notify/honor_notify.go deleted file mode 100644 index 520f72b..0000000 --- a/pkg/notify/honor_notify.go +++ /dev/null @@ -1,48 +0,0 @@ -package notify - -type HonorPushNotification struct { - AppID string `json:"app_id,omitempty"` - AppName string `json:"app_name,omitempty"` - Tokens []string `json:"tokens" binding:"required"` - Title string `json:"title,omitempty"` - Content string `json:"content,omitempty"` - Image string `json:"image,omitempty"` - Priority string `json:"priority,omitempty"` - Category string `json:"category,omitempty"` - TTL string `json:"ttl,omitempty"` - - // NotifyId 消息通知ID,用于消息覆盖 - NotifyId int `json:"notify_id,omitempty"` - - Data map[string]interface{} `json:"data,omitempty"` - - Development bool `json:"development,omitempty"` - - Badge *BadgeNotification `json:"badge,omitempty"` - - ClickAction *HonorClickAction `json:"click_action,omitempty"` -} - -// BadgeNotification 结构体用于表示Android通知消息角标控制 -type BadgeNotification struct { - AddNum int `json:"addNum,omitempty"` - SetNum int `json:"setNum,omitempty"` - BadgeClass string `json:"badgeClass"` -} - -type HonorClickAction struct { - // Action 点击跳转类型 - // 1 打开应用内页(activity的action标签名) - // 2 打开特定url - // 3 打开应用 - Action int `json:"action,omitempty"` - - // Activity 打开应用内页(activity 的 intent action) - Activity string `json:"activity,omitempty"` - - // Url 打开网页的地址 - Url string `json:"url,omitempty"` - - // Parameters url跳转后传的参数拼接在url后面 - Parameters map[string]interface{} `json:"parameters,omitempty"` -} diff --git a/pkg/notify/meizu_notify.go b/pkg/notify/meizu_notify.go deleted file mode 100644 index 51d88ad..0000000 --- a/pkg/notify/meizu_notify.go +++ /dev/null @@ -1,55 +0,0 @@ -package notify - -// MeizuPushNotification -// https://github.com/MEIZUPUSH/PushAPI/blob/master/README.md -type MeizuPushNotification struct { - AppID string `json:"app_id"` - AppName string `json:"app_name"` - - // Tokens 对应pushId列表 - Tokens []string `json:"tokens" binding:"required"` - - Title string `json:"title,omitempty"` - Content string `json:"message,omitempty"` - - // NotifyType - // DEFAULT_ALL = -1; - // DEFAULT_SOUND = 0; 使用默认提示音提示 - // DEFAULT_VIBRATE = 1; 使用默认振动提示 - // DEFAULT_LIGHTS = 2; 使用默认呼吸灯提示。 - NotifyType int `json:"notify_type,omitempty"` - - ClickAction *MeizuClickAction `json:"click_action,omitempty"` - - // TTL 如果用户离线,设置消息在服务器保存的时间,有效时长 (1 -72 小时内的正整数) - TTL int `json:"time_to_live,omitempty"` - - OffLine bool `json:"offline,omitempty"` - - IsShowNotify bool `json:"is_show_notify,omitempty"` - - // IsScheduled 是否定时推送 - IsScheduled bool - // ScheduledStartTime 定时展示开始时间(yyyy-MM-dd HH:mm:ss) - ScheduledStartTime string - // ScheduledEndTime 定时展示结束时间(yyyy-MM-dd HH:mm:ss) - ScheduledEndTime string -} - -type MeizuClickAction struct { - // Action 点击跳转类型 - // 0 打开应用 - // 1 打开应用内页(activity的action标签名) - // 2 打开H5地址(应用本地的URI) - Action int `json:"action,omitempty"` - - // Activity 打开应用内页(activity 的 intent action) - // 格式 pkg.activity eg: com.meizu.upspushdemo.TestActivity - Activity string `json:"activity,omitempty"` - - // Url 打开网页的地址 - Url string `json:"url,omitempty"` - - // Parameters url跳转后传的参数拼接在url后面 - Parameters map[string]interface{} `json:"parameters,omitempty"` -} diff --git a/pkg/notify/notify.go b/pkg/notify/notify.go deleted file mode 100644 index 5394175..0000000 --- a/pkg/notify/notify.go +++ /dev/null @@ -1,100 +0,0 @@ -package notify - -import ( - "github.com/appleboy/go-fcm" - "github.com/cossim/go-hms-push/push/model" -) - -const ( - HIGH = "high" - NORMAL = "normal" -) - -type ClickAction struct { - Action string `json:"action,omitempty"` - Content string `json:"content,omitempty"` -} - -// PushOption 表示推送选项的结构体 -type PushOption struct { - // DryRun 只进行数据校验不实际推送,数据校验成功即为成功 - DryRun bool `json:"dry_run,omitempty"` - - // Retry 重试次数 - Retry int `json:"retry,omitempty"` -} - -// D provide string array -type D map[string]interface{} - -// Sound sets the aps sound on the payload. -// https://developer.apple.com/documentation/usernotifications/generating-a-remote-notification#:~:text=%E8%AD%A6%E6%8A%A5%E7%9A%84%E5%A3%B0%E9%9F%B3%E3%80%82-,sound%E8%A1%A8%203.%E5%AD%97%E5%85%B8%E4%B8%AD%E5%8C%85%E5%90%AB%E7%9A%84%E9%94%AE,-%E9%92%A5%E5%8C%99 -type Sound struct { - // Critical 指示声音是否被标记为关键声音。关键声音通常用于需要立即引起用户注意的通知。 - // 值为 1 表示是关键声音,值为 0 表示不是关键声音。默认为 0。 - Critical int `json:"critical,omitempty"` - // Name 声音的名称或标识符。 - // 通常是声音文件的名称,表示要播放的声音文件。默认为空字符串。 - Name string `json:"name,omitempty"` - // Volume 声音的音量级别。 - // 值范围为 0.0 到 1.0,表示音量的相对级别。默认为 1.0。 - Volume float32 `json:"volume,omitempty"` -} - -// PushNotification is single notification request -type PushNotification struct { - // Common - ID string `json:"notif_id,omitempty"` - Tokens []string `json:"tokens" binding:"required"` - Platform int `json:"platform" binding:"required"` - Message string `json:"message,omitempty"` - Title string `json:"title,omitempty"` - Image string `json:"image,omitempty"` - Priority string `json:"priority,omitempty"` - ContentAvailable bool `json:"content_available,omitempty"` - MutableContent bool `json:"mutable_content,omitempty"` - Sound interface{} `json:"sound,omitempty"` - Data D `json:"data,omitempty"` - Retry int `json:"retry,omitempty"` - - // Android - APIKey string `json:"api_key,omitempty"` - To string `json:"to,omitempty"` - CollapseKey string `json:"collapse_key,omitempty"` - DelayWhileIdle bool `json:"delay_while_idle,omitempty"` - TimeToLive *uint `json:"time_to_live,omitempty"` - RestrictedPackageName string `json:"restricted_package_name,omitempty"` - DryRun bool `json:"dry_run,omitempty"` - Condition string `json:"condition,omitempty"` - Notification *fcm.Notification `json:"notification,omitempty"` - - // Huawei - AppID string `json:"app_id,omitempty"` - AppSecret string `json:"app_secret,omitempty"` - HuaweiNotification *model.AndroidNotification `json:"huawei_notification,omitempty"` - HuaweiData string `json:"huawei_data,omitempty"` - HuaweiCollapseKey int `json:"huawei_collapse_key,omitempty"` - HuaweiTTL string `json:"huawei_ttl,omitempty"` - BiTag string `json:"bi_tag,omitempty"` - FastAppTarget int `json:"fast_app_target,omitempty"` - - // iOS - Expiration *int64 `json:"expiration,omitempty"` - ApnsID string `json:"apns_id,omitempty"` - CollapseID string `json:"collapse_id,omitempty"` - Topic string `json:"topic,omitempty"` - PushType string `json:"push_type,omitempty"` - Badge *int `json:"badge,omitempty"` - Category string `json:"category,omitempty"` - ThreadID string `json:"thread-id,omitempty"` - URLArgs []string `json:"url-args,omitempty"` - Alert Alert `json:"alert,omitempty"` - Production bool `json:"production,omitempty"` - Development bool `json:"development,omitempty"` - SoundName string `json:"name,omitempty"` - SoundVolume float32 `json:"volume,omitempty"` - Apns D `json:"apns,omitempty"` - - // ref: https://github.com/sideshow/apns2/blob/54928d6193dfe300b6b88dad72b7e2ae138d4f0a/payload/builder.go#L7-L24 - InterruptionLevel string `json:"interruption_level,omitempty"` -} diff --git a/pkg/notify/oppo_notify.go b/pkg/notify/oppo_notify.go deleted file mode 100644 index 1a84d4d..0000000 --- a/pkg/notify/oppo_notify.go +++ /dev/null @@ -1,44 +0,0 @@ -package notify - -type OppoPushNotification struct { - AppID string `json:"app_id"` - AppName string `json:"app_name"` - RequestId string `json:"request_id,omitempty"` - // Tokens 对应regId列表 - Tokens []string `json:"tokens" binding:"required"` - - Title string `json:"title,omitempty"` - Subtitle string `json:"subtitle,omitempty"` - Message string `json:"message,omitempty"` - - // Data 透传数据 客户端自定义键值对 key和Value键值对总长度不能超过1024字符 - Data map[string]string `json:"data,omitempty"` - - ClickAction *OppoClickAction `json:"click_action,omitempty"` - - // TTL 消息缓存时间,单位是秒,取值至少60秒,最长一天。当值为空时,默认一天 - TTL int `json:"ttl,omitempty"` - - // PushOptions 推送选项 - Option PushOption `json:"option,omitempty"` -} - -type OppoClickAction struct { - // Action 点击跳转类型 1:打开APP首页 2:打开链接 3:自定义 4:打开app内指定页面 5:跳转Intentscheme URL 默认值为 0 - // 0 启动应用 - // 1 打开应用内页(activity的action标签名) - // 2 打开网页 - // 4 打开应用内页(activity 全路径类名) - // 5 Intentscheme URL - 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"` - Content string `json:"content,omitempty"` -} diff --git a/pkg/notify/vivo_notify.go b/pkg/notify/vivo_notify.go deleted file mode 100644 index ec6e46b..0000000 --- a/pkg/notify/vivo_notify.go +++ /dev/null @@ -1,55 +0,0 @@ -package notify - -// VivoPushNotification -// https://dev.vivo.com.cn/documentCenter/doc/362#:~:text=%E6%8E%A5%E5%8F%A3%E5%AE%9A%E4%B9%89-,%E8%BE%93%E5%85%A5%E5%8F%82%E6%95%B0%EF%BC%9A,-intent%20uri -type VivoPushNotification struct { - AppID string `json:"app_id"` - AppName string `json:"app_name"` - RequestId string `json:"request_id,omitempty"` - - // NotifyID 每条消息在通知栏的唯一标识 可以用于覆盖消息 - NotifyID int `json:"notify_id,omitempty"` - - TaskID string `json:"task_id,omitempty"` - - // Tokens 对应regId列表 - Tokens []string `json:"tokens" binding:"required"` - - Title string `json:"title,omitempty"` - Message string `json:"message,omitempty"` - Category string `json:"category,omitempty"` - - // Data 透传数据 客户端自定义键值对 key和Value键值对总长度不能超过1024字符 - Data map[string]string `json:"data,omitempty"` - - ClickAction *VivoClickAction `json:"click_action,omitempty"` - - // NotifyType 通知类型 1:无,2:响铃,3:振动,4:响铃和振动 - NotifyType int `json:"notify_type,omitempty"` - - // TTL 消息缓存时间,单位是秒,取值至少60秒,最长一天。当值为空时,默认一天 - TTL int `json:"ttl,omitempty"` - - // Retry 重试次数 - Retry int `json:"retry,omitempty"` - - // SendOnline true表示是在线直推,false表示非直推,设备离线直接丢弃 - SendOnline bool `json:"send_online,omitempty"` - - // Foreground 是否前台通知展示 - Foreground bool `json:"foreground,omitempty"` - - // Development 对应PushMode - Development bool `json:"development,omitempty"` -} - -type VivoClickAction struct { - // Action 点击跳转类型 1:打开APP首页 2:打开链接 3:自定义 4:打开app内指定页面 - Action int `json:"action,omitempty"` - - // Activity 打开应用内页(activity 的 intent action) - Activity string `json:"activity,omitempty"` - - // Url 打开网页的地址 - Url string `json:"url,omitempty"` -} diff --git a/pkg/notify/xiaomi_notify.go b/pkg/notify/xiaomi_notify.go deleted file mode 100644 index 2f5ca84..0000000 --- a/pkg/notify/xiaomi_notify.go +++ /dev/null @@ -1,33 +0,0 @@ -package notify - -import "time" - -// XiaomiPushNotification -// https://dev.mi.com/console/doc/detail?pId=2776#_0 -type XiaomiPushNotification struct { - AppID string `json:"app_id"` - AppName string `json:"app_name"` - - // 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 -} diff --git a/pkg/push/apns_push.go b/pkg/push/apns_push.go index 97bbe65..86c194b 100644 --- a/pkg/push/apns_push.go +++ b/pkg/push/apns_push.go @@ -9,10 +9,10 @@ import ( "github.com/cossim/hipush/api/push" "github.com/cossim/hipush/config" "github.com/cossim/hipush/pkg/consts" - "github.com/cossim/hipush/pkg/notify" "github.com/cossim/hipush/pkg/status" "github.com/go-logr/logr" "github.com/sideshow/apns2" + "github.com/sideshow/apns2/payload" "github.com/sideshow/apns2/token" "log" "net" @@ -150,15 +150,23 @@ var DialTLS = func(cfg *tls.Config) func(network, addr string) (net.Conn, error) } } -func (a *APNsService) Send(ctx context.Context, request interface{}, opt ...push.SendOption) (*push.SendResponse, error) { - req, ok := request.(*notify.ApnsPushNotification) - if !ok { - return nil, errors.New("invalid request") - } - +func (a *APNsService) Send(ctx context.Context, req push.SendRequest, opt ...push.SendOption) (*push.SendResponse, error) { so := &push.SendOptions{} so.ApplyOptions(opt) + var appid string + var ok bool + if req.GetAppID() != "" { + appid = req.GetAppID() + } else if req.GetAppName() != "" { + appid, ok = a.appNameToIDMap[req.GetAppName()] + if !ok { + return nil, ErrInvalidAppID + } + } else { + return nil, ErrInvalidAppID + } + if err := a.checkNotification(req); err != nil { return nil, err } @@ -168,18 +176,6 @@ func (a *APNsService) Send(ctx context.Context, request interface{}, opt ...push return nil, err } - var appid string - if req.AppID != "" { - appid = req.AppID - } else if req.AppName != "" { - appid, ok = a.appNameToIDMap[req.AppName] - if !ok { - return nil, ErrInvalidAppID - } - } else { - return nil, ErrInvalidAppID - } - if so.DryRun { return nil, nil } @@ -188,7 +184,7 @@ func (a *APNsService) Send(ctx context.Context, request interface{}, opt ...push return a.send(appid, token, notification) } - resp, err := RetrySend(ctx, send, req.Tokens, so.Retry, so.RetryInterval, 100) + resp, err := RetrySend(ctx, send, req.GetToken(), so.Retry, so.RetryInterval, 100) if err != nil { return nil, err } @@ -222,99 +218,181 @@ func (a *APNsService) GetTasksStatus(ctx context.Context, appid string, taskID [ return nil } -func (a *APNsService) MapPushRequestToApnsPushNotification(req PushRequest) (*notify.ApnsPushNotification, error) { - badge := req.GetBadge() +// Sound sets the aps sound on the payload. +// https://developer.apple.com/documentation/usernotifications/generating-a-remote-notification#:~:text=%E8%AD%A6%E6%8A%A5%E7%9A%84%E5%A3%B0%E9%9F%B3%E3%80%82-,sound%E8%A1%A8%203.%E5%AD%97%E5%85%B8%E4%B8%AD%E5%8C%85%E5%90%AB%E7%9A%84%E9%94%AE,-%E9%92%A5%E5%8C%99 +type Sound struct { + // Critical 指示声音是否被标记为关键声音。关键声音通常用于需要立即引起用户注意的通知。 + // 值为 1 表示是关键声音,值为 0 表示不是关键声音。默认为 0。 + Critical int `json:"critical,omitempty"` + // Name 声音的名称或标识符。 + // 通常是声音文件的名称,表示要播放的声音文件。默认为空字符串。 + Name string `json:"name,omitempty"` + // Volume 声音的音量级别。 + // 值范围为 0.0 到 1.0,表示音量的相对级别。默认为 1.0。 + Volume float32 `json:"volume,omitempty"` +} - alert, err := a.MapToAlert(req.GetAlert()) - if err != nil { - log.Println("MapToAlert error => ", err) - return nil, err +func (a *APNsService) buildNotification(req push.SendRequest) (*apns2.Notification, error) { + topic := req.GetTopic() + if topic == "" { + topic = req.GetAppID() } - - apnsNotification := ¬ify.ApnsPushNotification{ - Tokens: req.GetTokens(), - Priority: req.GetPriority(), - Title: req.GetTitle(), - Content: req.GetMessage(), - Expiration: req.GetExpiration(), - ApnsID: req.GetApnsID(), - CollapseID: req.GetCollapseID(), - Topic: req.GetTopic(), - PushType: req.GetPushType(), - Badge: &badge, - Category: req.GetCategory(), - ThreadID: req.GetThreadID(), - URLArgs: req.GetURLArgs(), - Alert: alert, - ContentAvailable: req.IsContentAvailable(), - MutableContent: req.IsMutableContent(), - Production: !req.IsDevelopment(), - Development: req.IsDevelopment(), - SoundName: req.GetSoundName(), - SoundVolume: req.GetSoundVolume(), - Apns: req.GetApns(), - InterruptionLevel: req.GetInterruptionLevel(), - Sound: req.GetSound(), - Data: req.GetData(), + notification := &apns2.Notification{ + ApnsID: req.GetMessageID(), + Topic: topic, + CollapseID: req.GetCollapseID(), } - return apnsNotification, nil -} -// MapToAlert 将接口类型的数据转换为 notify.Alert 结构体 -func (a *APNsService) MapToAlert(data interface{}) (notify.Alert, error) { - alertMap, ok := data.(map[string]interface{}) - if !ok { - return notify.Alert{}, errors.New("data is not in the expected format") + if req.GetTTL() != 0 { + notification.Expiration = time.Unix(req.GetTTL(), 0) } - var toString = func(value interface{}) string { - if str, ok := value.(string); ok { - return str - } - return "" + if req.GetPriority() == "normal" { + notification.Priority = apns2.PriorityLow + } else if req.GetPriority() == HIGH { + notification.Priority = apns2.PriorityHigh } - var toStringSlice = func(value interface{}) []string { - if slice, ok := value.([]interface{}); ok { - strSlice := make([]string, len(slice)) - for i, v := range slice { - if str, ok := v.(string); ok { - strSlice[i] = str - } - } - return strSlice - } - return nil + //if len(req.PushType) > 0 { + // notification.PushType = apns2.EPushType(req.PushType) + //} + + payload := payload.NewPayload() + + // add alert object if message length > 0 and title is empty + if len(req.GetContent()) > 0 && req.GetTitle() == "" { + payload.Alert(req.GetContent()) } - var toInt = func(value interface{}) int { - if intValue, ok := value.(int); ok { - return intValue - } - return 0 + // zero value for clear the badge on the app icon. + //if req.Badge != nil && *req.Badge >= 0 { + // payload.Badge(*req.Badge) + //} + + if req.GetMutableContent() { + payload.MutableContent() } - alert := notify.Alert{ - Action: toString(alertMap["action"]), - ActionLocKey: toString(alertMap["action-loc-key"]), - Body: toString(alertMap["body"]), - LaunchImage: toString(alertMap["launch-image"]), - LocArgs: toStringSlice(alertMap["loc-args"]), - LocKey: toString(alertMap["loc-key"]), - Title: toString(alertMap["title"]), - Subtitle: toString(alertMap["subtitle"]), - TitleLocArgs: toStringSlice(alertMap["title-loc-args"]), - TitleLocKey: toString(alertMap["title-loc-key"]), - SummaryArg: toString(alertMap["summary-arg"]), - SummaryArgCount: toInt(alertMap["summary-arg-count"]), + //switch req.GetSound().(type) { + //// from http request binding + //case map[string]interface{}: + // result := &Sound{} + // _ = mapstructure.Decode(req.GetSound(), &result) + // payload.Sound(result) + //// from http request binding for non critical alerts + //case string: + // payload.Sound(req.GetSound()) + //case Sound: + // payload.Sound(req.GetSound()) + //} + + //if len(req.SoundName) > 0 { + // payload.SoundName(req.SoundName) + //} + // + //if req.SoundVolume > 0 { + // payload.SoundVolume(req.SoundVolume) + //} + + if req.GetContentAvailable() { + payload.ContentAvailable() } - return alert, nil -} -func (a *APNsService) buildNotification(req *notify.ApnsPushNotification) (*apns2.Notification, error) { - return notify.GetIOSNotification(req), nil + //if len(req.URLArgs) > 0 { + // payload.URLArgs(req.URLArgs) + //} + + //if len(req.ThreadID) > 0 { + // payload.ThreadID(req.ThreadID) + //} + + //for k, v := range req.GetData() { + // payload.Custom(k, v) + //} + + payload.AlertTitle(req.GetTitle()) + payload.AlertBody(req.GetContent()) + payload.Category(req.GetCategory()) + + //payload = iosAlertDictionary(payload, req) + + notification.Payload = payload + + return notification, nil + //return notify.GetIOSNotification(req), nil } +//func iosAlertDictionary(notificationPayload *payload.Payload, req push.SendRequest) *payload.Payload { +// // Alert dictionary +// +// if len(req.GetTitle()) > 0 { +// notificationPayload.AlertTitle(req.GetTitle()) +// } +// +// if len(req.InterruptionLevel) > 0 { +// notificationPayload.InterruptionLevel(payload.EInterruptionLevel(req.InterruptionLevel)) +// } +// +// if len(req.GetContent()) > 0 && len(req.GetTitle()) > 0 { +// notificationPayload.AlertBody(req.GetContent()) +// } +// +// if len(req.Alert.Title) > 0 { +// notificationPayload.AlertTitle(req.Alert.Title) +// } +// +// // Apple Watch & Safari display this string as part of the notification interface. +// if len(req.Alert.Subtitle) > 0 { +// notificationPayload.AlertSubtitle(req.Alert.Subtitle) +// } +// +// if len(req.Alert.TitleLocKey) > 0 { +// notificationPayload.AlertTitleLocKey(req.Alert.TitleLocKey) +// } +// +// if len(req.Alert.LocArgs) > 0 { +// notificationPayload.AlertLocArgs(req.Alert.LocArgs) +// } +// +// if len(req.Alert.TitleLocArgs) > 0 { +// notificationPayload.AlertTitleLocArgs(req.Alert.TitleLocArgs) +// } +// +// if len(req.Alert.Body) > 0 { +// notificationPayload.AlertBody(req.Alert.Body) +// } +// +// if len(req.Alert.LaunchImage) > 0 { +// notificationPayload.AlertLaunchImage(req.Alert.LaunchImage) +// } +// +// if len(req.Alert.LocKey) > 0 { +// notificationPayload.AlertLocKey(req.Alert.LocKey) +// } +// +// if len(req.Alert.Action) > 0 { +// notificationPayload.AlertAction(req.Alert.Action) +// } +// +// if len(req.Alert.ActionLocKey) > 0 { +// notificationPayload.AlertActionLocKey(req.Alert.ActionLocKey) +// } +// +// // General +// if len(req.Category) > 0 { +// notificationPayload.Category(req.Category) +// } +// +// if len(req.Alert.SummaryArg) > 0 { +// notificationPayload.AlertSummaryArg(req.Alert.SummaryArg) +// } +// if req.Alert.SummaryArgCount > 0 { +// notificationPayload.AlertSummaryArgCount(req.Alert.SummaryArgCount) +// } +// +// return notificationPayload +//} + func (a *APNsService) send(appid string, token string, notification *apns2.Notification) (*Response, error) { if _, ok := a.clients[appid]; !ok { return nil, errors.New("invalid appid or appid push is not enabled") @@ -343,16 +421,16 @@ func (a *APNsService) send(appid string, token string, notification *apns2.Notif return resp, err } -func (a *APNsService) checkNotification(req *notify.ApnsPushNotification) error { - if len(req.Tokens) == 0 { +func (a *APNsService) checkNotification(req push.SendRequest) error { + if len(req.GetToken()) == 0 { return errors.New("tokens cannot be empty") } - if req.Title == "" { + if req.GetTitle() == "" { return errors.New("title cannot be empty") } - if req.Content == "" { + if req.GetContent() == "" { return errors.New("content cannot be empty") } diff --git a/pkg/push/fcm_push.go b/pkg/push/fcm_push.go index 032d0dd..4db582a 100644 --- a/pkg/push/fcm_push.go +++ b/pkg/push/fcm_push.go @@ -5,16 +5,15 @@ import ( "errors" firebase "firebase.google.com/go" "firebase.google.com/go/messaging" - "fmt" "github.com/cossim/hipush/api/push" "github.com/cossim/hipush/config" "github.com/cossim/hipush/pkg/consts" - "github.com/cossim/hipush/pkg/notify" "github.com/cossim/hipush/pkg/status" "github.com/go-logr/logr" "google.golang.org/api/option" "log" "strings" + "time" ) var ( @@ -74,22 +73,16 @@ func NewFCMService(cfg *config.Config, logger logr.Logger) *FCMService { return s } -func (f *FCMService) Send(ctx context.Context, request interface{}, opt ...push.SendOption) (*push.SendResponse, error) { - req, ok := request.(*notify.FCMPushNotification) - if !ok { - return nil, errors.New("invalid request") - } - +func (f *FCMService) Send(ctx context.Context, req push.SendRequest, opt ...push.SendOption) (*push.SendResponse, error) { so := &push.SendOptions{} so.ApplyOptions(opt) - fmt.Println("req.AppName => ", req.AppName) - var appid string - if req.AppID != "" { - appid = req.AppID - } else if req.AppName != "" { - appid, ok = f.appNameToIDMap[req.AppName] + var ok bool + if req.GetAppID() != "" { + appid = req.GetAppID() + } else if req.GetAppName() != "" { + appid, ok = f.appNameToIDMap[req.GetAppName()] if !ok { return nil, ErrInvalidAppID } @@ -111,7 +104,7 @@ func (f *FCMService) Send(ctx context.Context, request interface{}, opt ...push. return f.send(ctx, appid, token, notification) } - retrySend, err := RetrySend(ctx, send, req.Tokens, so.Retry, so.RetryInterval, 100) + retrySend, err := RetrySend(ctx, send, req.GetToken(), so.Retry, so.RetryInterval, 100) if err != nil { return nil, err } @@ -155,28 +148,27 @@ func (f *FCMService) send(ctx context.Context, appid string, token string, notif } // checkNotification for check request message -func (f *FCMService) checkNotification(req *notify.FCMPushNotification) error { +func (f *FCMService) checkNotification(req push.SendRequest) error { var msg string // ignore send topic mesaage from FCM - if !f.IsTopic(req) && len(req.Tokens) == 0 && req.Topic == "" { + if !f.IsTopic(req) && len(req.GetToken()) == 0 && req.GetTopic() == "" { msg = "the message must specify at least one registration ID" return errors.New(msg) } - if len(req.Tokens) == 0 { + if len(req.GetToken()) == 0 { msg = "the token must not be empty" return errors.New(msg) } - if len(req.Tokens) > 1000 { + if len(req.GetToken()) > 1000 { msg = "the message may specify at most 1000 registration IDs" return errors.New(msg) } // ref: https://firebase.google.com/docs/cloud-messaging/http-server-ref - ttlSeconds := int(req.TTL.Seconds()) - fmt.Println("ttlSeconds => ", ttlSeconds) + ttlSeconds := int(req.GetTTL()) if ttlSeconds < 0 || ttlSeconds > 2419200 { msg := "the message's TimeToLive field must be an integer " + "between 0 and 2419200 (4 weeks)" @@ -186,74 +178,81 @@ func (f *FCMService) checkNotification(req *notify.FCMPushNotification) error { return nil } -func (f *FCMService) IsTopic(req *notify.FCMPushNotification) bool { - return req.Topic != "" && strings.HasPrefix(req.Topic, "/topics/") && req.Condition != "" +func (f *FCMService) IsTopic(req push.SendRequest) bool { + return req.GetTopic() != "" && strings.HasPrefix(req.GetTopic(), "/topics/") && req.GetCondition() != "" } // buildAndroidNotification use for define Android notification. // HTTP Connection Server Reference for Android // https://firebase.google.com/docs/cloud-messaging/http-server-ref -func (f *FCMService) buildAndroidNotification(req *notify.FCMPushNotification) *messaging.Message { +func (f *FCMService) buildAndroidNotification(req push.SendRequest) *messaging.Message { notification := &messaging.Message{ //Token: req.Topic, - Topic: req.Topic, - Condition: req.Condition, + Topic: req.GetTopic(), + Condition: req.GetCondition(), Android: &messaging.AndroidConfig{}, } - if len(req.Tokens) > 0 { + if len(req.GetToken()) > 0 { //notification.Token = "" //notification.Token = req.Tokens[0] } - if req.Category != "" { - notification.Android.CollapseKey = req.CollapseID + if req.GetCategory() != "" { + notification.Android.CollapseKey = req.GetCollapseID() } - if req.Priority == HIGH || req.Priority == "normal" { - notification.Android.Priority = req.Priority + if req.GetPriority() == HIGH || req.GetPriority() == "normal" { + notification.Android.Priority = req.GetPriority() } // Add another field - if len(req.Data) > 0 { - notification.Data = req.Data - } + //if len(req.GetData()) > 0 { + // var data = make(map[string]string) + // for k, v := range req.GetData() { + // data[k] = fmt.Sprintf("%v", v) + // } + // notification.Data = data + //} - notification.Android.TTL = &req.TTL + duration := time.Duration(req.GetTTL()) * time.Second + notification.Android.TTL = &duration n := &messaging.Notification{} isNotificationSet := false - if len(req.Content) > 0 { + if len(req.GetContent()) > 0 { isNotificationSet = true - n.Body = req.Content + n.Body = req.GetContent() } - if len(req.Title) > 0 { + if len(req.GetTitle()) > 0 { isNotificationSet = true - n.Title = req.Title + n.Title = req.GetTitle() } - if len(req.Image) > 0 { + if len(req.GetIcon()) > 0 { isNotificationSet = true - n.ImageURL = req.Image + n.ImageURL = req.GetIcon() } - if req.Sound != "" { - isNotificationSet = true - //n.Sound = req.Sound - notification.Android.Notification.Sound = req.Sound - } + //if req.GetSound() != "" { + // isNotificationSet = true + // //n.Sound = req.Sound + // sound, ok := req.GetSound().(string) + // if ok { + // notification.Android.Notification.Sound = sound + // } + //} if isNotificationSet { notification.Notification = n } // handle iOS apns in fcm - - if len(req.Apns) > 0 { - // Handle iOS APNS - } + //if len(req.Apns) > 0 { + // Handle iOS APNS + //} return notification } diff --git a/pkg/push/honor_push.go b/pkg/push/honor_push.go index b506cbc..425964e 100644 --- a/pkg/push/honor_push.go +++ b/pkg/push/honor_push.go @@ -8,7 +8,6 @@ import ( "github.com/cossim/hipush/config" hClient "github.com/cossim/hipush/pkg/client/push" "github.com/cossim/hipush/pkg/consts" - "github.com/cossim/hipush/pkg/notify" "github.com/cossim/hipush/pkg/status" "github.com/go-logr/logr" "log" @@ -62,20 +61,16 @@ func NewHonorService(cfg *config.Config, logger logr.Logger) *HonorService { return s } -func (h *HonorService) Send(ctx context.Context, request interface{}, opt ...push.SendOption) (*push.SendResponse, error) { - req, ok := request.(*notify.HonorPushNotification) - if !ok { - return nil, errors.New("invalid request") - } - +func (h *HonorService) Send(ctx context.Context, req push.SendRequest, opt ...push.SendOption) (*push.SendResponse, error) { so := &push.SendOptions{} so.ApplyOptions(opt) var appid string - if req.AppID != "" { - appid = req.AppID - } else if req.AppName != "" { - appid, ok = h.appNameToIDMap[req.AppName] + var ok bool + if req.GetAppID() != "" { + appid = req.GetAppID() + } else if req.GetAppName() != "" { + appid, ok = h.appNameToIDMap[req.GetAppName()] if !ok { return nil, ErrInvalidAppID } @@ -87,7 +82,7 @@ func (h *HonorService) Send(ctx context.Context, request interface{}, opt ...pus return nil, err } - notification := h.buildAndroidNotification(req) + notification := h.buildAndroidNotification(req, so) if so.DryRun { return nil, nil @@ -97,7 +92,7 @@ func (h *HonorService) Send(ctx context.Context, request interface{}, opt ...pus return h.send(ctx, appid, token, notification) } - resp, err := RetrySend(ctx, send, req.Tokens, so.Retry, so.RetryInterval, 100) + resp, err := RetrySend(ctx, send, req.GetToken(), so.Retry, so.RetryInterval, 100) if err != nil { return nil, err } @@ -213,76 +208,70 @@ func (h *HonorService) send(ctx context.Context, appid string, token string, not //return newTokens, nil } -func (h *HonorService) checkNotification(req *notify.HonorPushNotification) error { - if len(req.Tokens) == 0 { +func (h *HonorService) checkNotification(req push.SendRequest) error { + if len(req.GetToken()) == 0 { return errors.New("tokens cannot be empty") } - if req.Title == "" { + if req.GetTitle() == "" { return errors.New("title cannot be empty") } - if req.Content == "" { + if req.GetContent() == "" { return errors.New("content cannot be empty") } return nil } -func (h *HonorService) buildAndroidNotification(req *notify.HonorPushNotification) *hClient.SendMessageRequest { +func (h *HonorService) buildAndroidNotification(req push.SendRequest, so *push.SendOptions) *hClient.SendMessageRequest { // 构建通知栏消息 notification := &hClient.Notification{ - Title: req.Title, - Body: req.Content, - Image: req.Image, + Title: req.GetTitle(), + Body: req.GetContent(), + Image: req.GetIcon(), } // 构建 Android 平台的通知消息 androidNotification := &hClient.AndroidNotification{ - Title: req.Title, - Body: req.Content, - Image: req.Image, - NotifyID: req.NotifyId, - Badge: &hClient.BadgeNotification{ - AddNum: req.Badge.AddNum, - SetNum: req.Badge.SetNum, - BadgeClass: req.Badge.BadgeClass, - }, - ClickAction: &hClient.ClickAction{ - Type: req.ClickAction.Action, - Intent: req.ClickAction.Activity, - URL: req.ClickAction.Url, - Action: req.ClickAction.Activity, - }, + Title: req.GetTitle(), + Body: req.GetContent(), + Image: req.GetIcon(), + //NotifyID: req.NotifyId, + //Badge: &hClient.BadgeNotification{ + // AddNum: req.Badge.AddNum, + // SetNum: req.Badge.SetNum, + // BadgeClass: req.Badge.BadgeClass, + //}, + //ClickAction: &hClient.ClickAction{ + // Type: req.ClickAction.Action, + // Intent: req.ClickAction.Activity, + // URL: req.ClickAction.Url, + // Action: req.ClickAction.Activity, + //}, } var targetUserType int - if req.Development { + if so.Development { targetUserType = 1 } - // 将 map 转换为 JSON 字符串 - data, err := json.Marshal(req.Data) - if err != nil { - log.Printf("Error marshalling data: %v", err) - } - // 构建 Android 平台消息推送配置 androidConfig := &hClient.AndroidConfig{ - TTL: req.TTL, // 设置消息缓存时间 - BiTag: "", // 设置批量任务消息标识 - Data: string(data), // 设置自定义消息负载 + //TTL: req.GetTTL(), // 设置消息缓存时间 + BiTag: "", // 设置批量任务消息标识 + //Data: string(data), // 设置自定义消息负载 Notification: androidNotification, TargetUserType: targetUserType, // 设置目标用户类型 } // 构建发送消息请求 sendMessageReq := &hClient.SendMessageRequest{ - Data: string(data), // 设置自定义消息负载 + //Data: string(data), // 设置自定义消息负载 Notification: notification, Android: androidConfig, - Token: req.Tokens, + Token: req.GetToken(), } return sendMessageReq diff --git a/pkg/push/huawei_push.go b/pkg/push/huawei_push.go index cff676b..84fe22e 100644 --- a/pkg/push/huawei_push.go +++ b/pkg/push/huawei_push.go @@ -10,26 +10,22 @@ import ( "github.com/cossim/hipush/api/push" "github.com/cossim/hipush/config" "github.com/cossim/hipush/pkg/consts" - "github.com/cossim/hipush/pkg/notify" "github.com/cossim/hipush/pkg/status" "github.com/go-logr/logr" "log" + "time" ) const ( HIGH = "high" NORMAL = "nornal" - DefaultMaxRetry = 1 - DefaultAuthUrl = "https://oauth-login.cloud.huawei.com/oauth2/v3/token" DefaultPushUrl = "https://push-api.cloud.huawei.com" ) var ( - // MaxConcurrentHuaweiPushes pool to limit the number of concurrent iOS pushes - MaxConcurrentHuaweiPushes = make(chan struct{}, 100) - _ push.PushService = &HMSService{} + _ push.PushService = &HMSService{} ) // HMSService 实现huawei推送,实现 PushService 接口 @@ -84,20 +80,16 @@ func NewHMSService(cfg *config.Config, logger logr.Logger) *HMSService { return s } -func (h *HMSService) Send(ctx context.Context, request interface{}, opt ...push.SendOption) (*push.SendResponse, error) { - req, ok := request.(*notify.HMSPushNotification) - if !ok { - return nil, errors.New("invalid request parameter") - } - +func (h *HMSService) Send(ctx context.Context, req push.SendRequest, opt ...push.SendOption) (*push.SendResponse, error) { so := &push.SendOptions{} so.ApplyOptions(opt) var appid string - if req.AppID != "" { - appid = req.AppID - } else if req.AppName != "" { - appid, ok = h.appNameToIDMap[req.AppName] + var ok bool + if req.GetAppID() != "" { + appid = req.GetAppID() + } else if req.GetAppName() != "" { + appid, ok = h.appNameToIDMap[req.GetAppName()] if !ok { return nil, ErrInvalidAppID } @@ -109,7 +101,7 @@ func (h *HMSService) Send(ctx context.Context, request interface{}, opt ...push. return nil, err } - notification, err := h.buildNotification(req) + notification, err := h.buildNotification(req, so) if err != nil { return nil, err } @@ -122,7 +114,7 @@ func (h *HMSService) Send(ctx context.Context, request interface{}, opt ...push. return h.send(ctx, appid, token, notification) } - resp, err := RetrySend(ctx, send, req.Tokens, so.Retry, so.RetryInterval, 100) + resp, err := RetrySend(ctx, send, req.GetToken(), so.Retry, so.RetryInterval, 100) if err != nil { return nil, err } @@ -188,16 +180,16 @@ func (h *HMSService) send(ctx context.Context, appid string, token string, notif return resp, err } -func (h *HMSService) checkNotification(req *notify.HMSPushNotification) error { - if len(req.Tokens) == 0 { +func (h *HMSService) checkNotification(req push.SendRequest) error { + if len(req.GetToken()) == 0 { return errors.New("tokens cannot be empty") } - if req.Title == "" { + if req.GetTitle() == "" { return errors.New("title cannot be empty") } - if req.Content == "" { + if req.GetContent() == "" { return errors.New("content cannot be empty") } @@ -206,47 +198,46 @@ func (h *HMSService) checkNotification(req *notify.HMSPushNotification) error { // HTTP Connection Server Reference for HMS // https://developer.huawei.com/consumer/en/doc/development/HMS-References/push-sendapi -func (h *HMSService) buildNotification(req *notify.HMSPushNotification) (*model.MessageRequest, error) { +func (h *HMSService) buildNotification(req push.SendRequest, so *push.SendOptions) (*model.MessageRequest, error) { msgRequest := model.NewNotificationMsgRequest() msgRequest.Message.Android = model.GetDefaultAndroid() - if len(req.Tokens) > 0 { - msgRequest.Message.Token = req.Tokens + if len(req.GetToken()) > 0 { + msgRequest.Message.Token = req.GetToken() } - if len(req.Topic) > 0 { - msgRequest.Message.Topic = req.Topic + if len(req.GetTopic()) > 0 { + msgRequest.Message.Topic = req.GetTopic() } - if len(req.Condition) > 0 { - msgRequest.Message.Condition = req.Condition + if len(req.GetCondition()) > 0 { + msgRequest.Message.Condition = req.GetCondition() } - msgRequest.Message.Android.Urgency = req.Priority - - if len(req.Priority) > 0 { - msgRequest.Message.Android.Urgency = req.Priority + if len(req.GetPriority()) > 0 { + msgRequest.Message.Android.Urgency = req.GetPriority() } - if len(req.Category) > 0 { - msgRequest.Message.Android.Category = req.Category + if len(req.GetCategory()) > 0 { + msgRequest.Message.Android.Category = req.GetCategory() } - if len(req.TTL) > 0 { - msgRequest.Message.Android.TTL = req.TTL + if req.GetTTL() > 0 { + duration := time.Duration(req.GetTTL()) * time.Second + msgRequest.Message.Android.TTL = duration.String() } - if len(req.BiTag) > 0 { - msgRequest.Message.Android.BiTag = req.BiTag - } + //if len(req.BiTag) > 0 { + // msgRequest.Message.Android.BiTag = req.BiTag + //} - msgRequest.Message.Android.FastAppTarget = req.FastAppTarget + //msgRequest.Message.Android.FastAppTarget = req.FastAppTarget // Add data fields - if len(req.Data) > 0 { - msgRequest.Message.Data = req.Data - } + //if len(req.Data) > 0 { + // msgRequest.Message.Data = req.Data + //} // Notification Content //if req.MessageRequest.Message.Android.Notification != nil { @@ -263,39 +254,33 @@ func (h *HMSService) buildNotification(req *notify.HMSPushNotification) (*model. } } - if len(req.Content) > 0 { + if len(req.GetContent()) > 0 { setDefaultAndroidNotification() - msgRequest.Message.Android.Notification.Body = req.Content + msgRequest.Message.Android.Notification.Body = req.GetContent() } - if len(req.Title) > 0 { + if len(req.GetTitle()) > 0 { setDefaultAndroidNotification() - msgRequest.Message.Android.Notification.Title = req.Title + msgRequest.Message.Android.Notification.Title = req.GetTitle() } - if len(req.Image) > 0 { + if len(req.GetIcon()) > 0 { setDefaultAndroidNotification() - msgRequest.Message.Android.Notification.Image = req.Image + msgRequest.Message.Android.Notification.Image = req.GetIcon() } - if v, ok := req.Sound.(string); ok && len(v) > 0 { - setDefaultAndroidNotification() - msgRequest.Message.Android.Notification.Sound = v - } else if msgRequest.Message.Android.Notification != nil { - msgRequest.Message.Android.Notification.DefaultSound = true - } + //if v, ok := req.Sound.(string); ok && len(v) > 0 { + // setDefaultAndroidNotification() + // msgRequest.Message.Android.Notification.Sound = v + //} else if msgRequest.Message.Android.Notification != nil { + // msgRequest.Message.Android.Notification.DefaultSound = true + //} + msgRequest.Message.Android.Notification.DefaultSound = true - if req.Development { + if so.Development { msgRequest.Message.Android.TargetUserType = 1 } - m, err := json.Marshal(msgRequest) - if err != nil { - log.Printf("Failed to marshal the default message! Error is " + err.Error()) - return nil, err - } - - log.Printf("Default message is %s", string(m)) return msgRequest, nil } diff --git a/pkg/push/meizu_push.go b/pkg/push/meizu_push.go index f363c31..0f8e634 100644 --- a/pkg/push/meizu_push.go +++ b/pkg/push/meizu_push.go @@ -8,7 +8,6 @@ import ( "github.com/cossim/hipush/api/push" "github.com/cossim/hipush/config" "github.com/cossim/hipush/pkg/consts" - "github.com/cossim/hipush/pkg/notify" "github.com/cossim/hipush/pkg/status" "github.com/go-logr/logr" "log" @@ -54,15 +53,23 @@ func NewMeizuService(cfg *config.Config, logger logr.Logger) *MeizuService { return s } -func (m *MeizuService) Send(ctx context.Context, request interface{}, opt ...push.SendOption) (*push.SendResponse, error) { - req, ok := request.(*notify.MeizuPushNotification) - if !ok { - return nil, errors.New("invalid request") - } - +func (m *MeizuService) Send(ctx context.Context, req push.SendRequest, opt ...push.SendOption) (*push.SendResponse, error) { so := &push.SendOptions{} so.ApplyOptions(opt) + var appid string + var ok bool + if req.GetAppID() != "" { + appid = req.GetAppID() + } else if req.GetAppName() != "" { + appid, ok = m.appNameToIDMap[req.GetAppName()] + if !ok { + return nil, ErrInvalidAppID + } + } else { + return nil, ErrInvalidAppID + } + if err := m.checkNotification(req); err != nil { return nil, err } @@ -72,18 +79,6 @@ func (m *MeizuService) Send(ctx context.Context, request interface{}, opt ...pus return nil, err } - var appid string - if req.AppID != "" { - appid = req.AppID - } else if req.AppName != "" { - appid, ok = m.appNameToIDMap[req.AppName] - if !ok { - return nil, ErrInvalidAppID - } - } else { - return nil, ErrInvalidAppID - } - if so.DryRun { return nil, nil } @@ -92,7 +87,7 @@ func (m *MeizuService) Send(ctx context.Context, request interface{}, opt ...pus return m.send(appid, token, notification) } - _, err = RetrySend(ctx, send, req.Tokens, so.Retry, so.RetryInterval, 100) + _, err = RetrySend(ctx, send, req.GetToken(), so.Retry, so.RetryInterval, 100) if err != nil { return nil, err } @@ -171,44 +166,44 @@ func (m *MeizuService) send(appid string, token string, message string) (*Respon //return newTokens, nil } -func (m *MeizuService) checkNotification(req *notify.MeizuPushNotification) error { - if len(req.Tokens) == 0 { +func (m *MeizuService) checkNotification(req push.SendRequest) error { + if len(req.GetToken()) == 0 { return errors.New("tokens cannot be empty") } - if req.Title == "" { + if req.GetTitle() == "" { return errors.New("title cannot be empty") } - if req.Content == "" { + if req.GetContent() == "" { return errors.New("message cannot be empty") } - if req.IsScheduled && (req.ScheduledStartTime == "" || req.ScheduledEndTime == "") { - return errors.New("scheduled time cannot be empty") - } + //if req.IsScheduled && (req.ScheduledStartTime == "" || req.ScheduledEndTime == "") { + // return errors.New("scheduled time cannot be empty") + //} return nil } -func (m *MeizuService) buildNotification(req *notify.MeizuPushNotification) (string, error) { +func (m *MeizuService) buildNotification(req push.SendRequest) (string, error) { msg := mzp.BuildNotificationMessage() - msg.NoticeBarInfo.Title = req.Title - msg.NoticeBarInfo.Content = req.Content - msg.ClickTypeInfo = mzp.ClickTypeInfo{ - ClickType: req.ClickAction.Action, - Url: req.ClickAction.Url, - Parameters: req.ClickAction.Parameters, - Activity: req.ClickAction.Activity, - } + msg.NoticeBarInfo.Title = req.GetTitle() + msg.NoticeBarInfo.Content = req.GetContent() + //msg.ClickTypeInfo = mzp.ClickTypeInfo{ + // ClickType: req.ClickAction.Action, + // Url: req.ClickAction.Url, + // Parameters: req.ClickAction.Parameters, + // Activity: req.ClickAction.Activity, + //} - offLine := 0 - if req.OffLine { - offLine = 1 - } + //offLine := 0 + //if req.OffLine { + // offLine = 1 + //} msg.PushTimeInfo = mzp.PushTimeInfo{ - OffLine: offLine, - ValidTime: req.TTL, + //OffLine: offLine, + ValidTime: int(req.GetTTL()), } message, err := json.Marshal(msg) diff --git a/pkg/push/oppo_push.go b/pkg/push/oppo_push.go index 7e6dad8..c14744b 100644 --- a/pkg/push/oppo_push.go +++ b/pkg/push/oppo_push.go @@ -9,7 +9,6 @@ import ( "github.com/cossim/hipush/api/push" "github.com/cossim/hipush/config" "github.com/cossim/hipush/pkg/consts" - "github.com/cossim/hipush/pkg/notify" "github.com/cossim/hipush/pkg/status" "github.com/go-logr/logr" "log" @@ -61,15 +60,23 @@ func NewOppoService(cfg *config.Config, logger logr.Logger) *OppoService { return s } -func (o *OppoService) Send(ctx context.Context, request interface{}, opt ...push.SendOption) (*push.SendResponse, error) { - req, ok := request.(*notify.OppoPushNotification) - if !ok { - return nil, errors.New("invalid request") - } - +func (o *OppoService) Send(ctx context.Context, req push.SendRequest, opt ...push.SendOption) (*push.SendResponse, error) { so := &push.SendOptions{} so.ApplyOptions(opt) + var appid string + var ok bool + if req.GetAppID() != "" { + appid = req.GetAppID() + } else if req.GetAppName() != "" { + appid, ok = o.appNameToIDMap[req.GetAppName()] + if !ok { + return nil, ErrInvalidAppID + } + } else { + return nil, ErrInvalidAppID + } + if err := o.checkNotification(req); err != nil { return nil, err } @@ -79,18 +86,6 @@ func (o *OppoService) Send(ctx context.Context, request interface{}, opt ...push return nil, err } - var appid string - if req.AppID != "" { - appid = req.AppID - } else if req.AppName != "" { - appid, ok = o.appNameToIDMap[req.AppName] - if !ok { - return nil, ErrInvalidAppID - } - } else { - return nil, ErrInvalidAppID - } - if so.DryRun { return nil, nil } @@ -99,7 +94,7 @@ func (o *OppoService) Send(ctx context.Context, request interface{}, opt ...push return o.send(appid, token, notification) } - resp, err := RetrySend(ctx, send, req.Tokens, so.Retry, so.RetryInterval, 100) + resp, err := RetrySend(ctx, send, req.GetToken(), so.Retry, so.RetryInterval, 100) if err != nil { return nil, err } @@ -159,7 +154,7 @@ func (o *OppoService) send(appID string, token string, notification *op.Message) resp.Code = res.Code resp.Msg = res.Message } else { - log.Printf("oppo send success: %s", res.Message) + log.Printf("oppo send success: %v", res) o.status.AddOppoSuccess(1) resp.Code = Success resp.Msg = res.Message @@ -169,36 +164,36 @@ func (o *OppoService) send(appID string, token string, notification *op.Message) return resp, err } -func (o *OppoService) checkNotification(req *notify.OppoPushNotification) error { - if len(req.Tokens) == 0 { +func (o *OppoService) checkNotification(req push.SendRequest) error { + if len(req.GetToken()) == 0 { return errors.New("tokens cannot be empty") } - if req.Title == "" { + if req.GetTitle() == "" { return errors.New("title cannot be empty") } - if req.Message == "" { - return errors.New("message cannot be empty") + if req.GetContent() == "" { + return errors.New("content cannot be empty") } return nil } -func (o *OppoService) buildNotification(req *notify.OppoPushNotification) (*op.Message, error) { - m := op.NewMessage(req.Title, req.Message). - SetSubTitle(req.Subtitle). +func (o *OppoService) buildNotification(req push.SendRequest) (*op.Message, error) { + m := op.NewMessage(req.GetTitle(), req.GetContent()). + //SetSubTitle(req.Subtitle). SetTargetType(2) - if req.ClickAction != nil { - if req.ClickAction.Action == 1 || req.ClickAction.Action == 4 { - m.SetClickActionActivity(req.ClickAction.Activity) - } - if req.ClickAction.Action == 2 { - m.SetClickActionUrl(req.ClickAction.Url) - } - m.SetClickActionType(req.ClickAction.Action) - m.SetActionParameters(req.ClickAction.Parameters) - } + //if req.ClickAction != nil { + // if req.ClickAction.Action == 1 || req.ClickAction.Action == 4 { + // m.SetClickActionActivity(req.ClickAction.Activity) + // } + // if req.ClickAction.Action == 2 { + // m.SetClickActionUrl(req.ClickAction.Url) + // } + // m.SetClickActionType(req.ClickAction.Action) + // m.SetActionParameters(req.ClickAction.Parameters) + //} return m, nil } diff --git a/pkg/push/push.go b/pkg/push/push.go index 0262675..672e03e 100644 --- a/pkg/push/push.go +++ b/pkg/push/push.go @@ -112,7 +112,7 @@ const ( type SendFunc func(ctx context.Context, token string) (*Response, error) -func RetrySend(ctx context.Context, send SendFunc, tokens []string, retry int, retryInterval int, maxConcurrent int) (*Response, error) { +func RetrySend(ctx context.Context, send SendFunc, tokens []string, retry int32, retryInterval int32, maxConcurrent int) (*Response, error) { var wg sync.WaitGroup var resp = &Response{} if retryInterval <= 0 { @@ -134,7 +134,7 @@ func RetrySend(ctx context.Context, send SendFunc, tokens []string, retry int, r <-MaxConcurrentPushes wg.Done() }() - for i := 0; i <= retry; i++ { + for i := 0; i <= int(retry); i++ { res, err := send(ctx, token) if err != nil || (res != nil && res.Code != 200) { if err == nil { diff --git a/pkg/push/vivo_push.go b/pkg/push/vivo_push.go index 0d06ee8..18b326e 100644 --- a/pkg/push/vivo_push.go +++ b/pkg/push/vivo_push.go @@ -8,13 +8,10 @@ import ( "github.com/cossim/hipush/api/push" "github.com/cossim/hipush/config" "github.com/cossim/hipush/pkg/consts" - "github.com/cossim/hipush/pkg/notify" "github.com/cossim/hipush/pkg/status" vp "github.com/cossim/vivo-push" - "github.com/go-co-op/gocron/v2" "github.com/go-logr/logr" "log" - "net/url" "strings" ) @@ -29,17 +26,14 @@ type VivoService struct { appNameToIDMap map[string]string status *status.StateStorage logger logr.Logger - - scheduler gocron.Scheduler } -func NewVivoService(cfg *config.Config, logger logr.Logger, scheduler gocron.Scheduler) *VivoService { +func NewVivoService(cfg *config.Config, logger logr.Logger) *VivoService { s := &VivoService{ clients: make(map[string]*vp.VivoPush), appNameToIDMap: make(map[string]string), status: status.StatStorage, logger: logger, - scheduler: scheduler, } for _, v := range cfg.Vivo { @@ -62,25 +56,16 @@ func NewVivoService(cfg *config.Config, logger logr.Logger, scheduler gocron.Sch return s } -func (v *VivoService) Send(ctx context.Context, request interface{}, opt ...push.SendOption) (*push.SendResponse, error) { - req, ok := request.(*notify.VivoPushNotification) - if !ok { - return nil, errors.New("invalid request") - } - +func (v *VivoService) Send(ctx context.Context, req push.SendRequest, opt ...push.SendOption) (*push.SendResponse, error) { so := &push.SendOptions{} so.ApplyOptions(opt) - notification, err := v.buildNotification(req) - if err != nil { - return nil, err - } - var appid string - if req.AppID != "" { - appid = req.AppID - } else if req.AppName != "" { - appid, ok = v.appNameToIDMap[req.AppName] + var ok bool + if req.GetAppID() != "" { + appid = req.GetAppID() + } else if req.GetAppName() != "" { + appid, ok = v.appNameToIDMap[req.GetAppName()] if !ok { return nil, ErrInvalidAppID } @@ -88,6 +73,11 @@ func (v *VivoService) Send(ctx context.Context, request interface{}, opt ...push return nil, ErrInvalidAppID } + notification, err := v.buildNotification(req, so) + if err != nil { + return nil, err + } + if so.DryRun { return nil, nil } @@ -96,7 +86,7 @@ func (v *VivoService) Send(ctx context.Context, request interface{}, opt ...push return v.send(appid, token, notification) } - resp, err := RetrySend(ctx, send, req.Tokens, so.Retry, so.RetryInterval, 100) + resp, err := RetrySend(ctx, send, req.GetToken(), so.Retry, so.RetryInterval, 100) if err != nil { return nil, err } @@ -107,39 +97,6 @@ func (v *VivoService) Send(ctx context.Context, request interface{}, opt ...push } return &push.SendResponse{TaskId: taskid}, nil - // - //if err := RetrySend(ctx, send, req.Tokens, so.Retry, so.RetryInterval, 100); err != nil { - // return nil,err - //} - // - //_, err = v.scheduler.NewJob(gocron.OneTimeJob(gocron.OneTimeJobStartImmediately()), gocron.NewTask(func(appid, taskID string) { - // fmt.Println("start vivo job") - // client, ok := v.clients[appid] - // if !ok { - // v.logger.Error(ErrInvalidAppID, ErrInvalidAppID.Error()) - // return - // } - // resp, err := client.GetMessageStatusByJobKey(taskID) - // if err != nil { - // v.logger.Error(err, "vivo get status error") - // return - // } - // if resp.Result == 0 { - // for _, ss := range resp.Statistics { - // if ss.TaskId == taskID { - // v.status.SetVivoSend(int64(ss.Send)) - // v.status.SetVivoReceive(int64(ss.Receive)) - // v.status.SetVivoDisplay(int64(ss.Display)) - // v.status.SetVivoClick(int64(ss.Click)) - // } - // } - // } - //}, appid, req.TaskID)) - //if err != nil { - // return err - //} - // - //return nil } // getTaskIDFromResponse 从 Response 结构体中获取 task_id 字段 @@ -193,77 +150,75 @@ func (v *VivoService) send(appid string, token string, notification *vp.Message) return resp, err } -func (v *VivoService) buildNotification(req *notify.VivoPushNotification) (*vp.Message, error) { +func (v *VivoService) buildNotification(req push.SendRequest, so *push.SendOptions) (*vp.Message, error) { // 检查 tokens 是否为空 - if len(req.Tokens) == 0 { + if len(req.GetToken()) == 0 { return nil, errors.New("tokens cannot be empty") } - if req.Title == "" { + if req.GetTitle() == "" { return nil, errors.New("title cannot be empty") } - if req.Message == "" { - return nil, errors.New("message cannot be empty") - } - - // 设置默认的 ClickAction - defaultClickAction := ¬ify.VivoClickAction{ - Action: 1, + if req.GetContent() == "" { + return nil, errors.New("content cannot be empty") } // 检查 ClickAction 是否为空,为空则使用默认值 - clickAction := req.ClickAction - if clickAction == nil { - clickAction = defaultClickAction - } - - if clickAction.Action == 0 { - clickAction.Action = 1 - } - - // 检查 URL 是否为合法 URL - if clickAction.Action == 2 { - _, err := url.Parse(clickAction.Url) - if err != nil { - return nil, err - } - } + //clickAction := req.GetClickAction() + //if clickAction == nil { + // clickAction.Action = 1 + //} + // + //if clickAction.Action == 0 { + // // 设置默认的 ClickAction + // clickAction.Action = 1 + //} + // + //// 检查 URL 是否为合法 URL + //if clickAction.Action == 2 { + // _, err := url.Parse(clickAction.Url) + // if err != nil { + // return nil, err + // } + //} + var notifyType = req.GetNotifyType() // 检查 NotifyType 是否为有效值 - if req.NotifyType != 0 && req.NotifyType < 1 || req.NotifyType > 4 { + if notifyType != 0 && notifyType < 1 || notifyType > 4 { return nil, errors.New("invalid notify type") } - if req.NotifyType == 0 { - req.NotifyType = 2 + if req.GetNotifyType() == 0 { + notifyType = 2 } var pushMode int - if req.Development { + if so.Development { pushMode = 1 } - if req.TTL == 0 { - req.TTL = 60 + var ttl int64 + if req.GetTTL() == 0 { + ttl = 60 } message := &vp.Message{ - RegId: strings.Join(req.Tokens, ","), - NotifyType: req.NotifyType, - Title: req.Title, - Content: req.Message, - TimeToLive: int64(req.TTL), - SkipType: clickAction.Action, - SkipContent: clickAction.Url, - NetworkType: -1, - ClientCustomMap: req.Data, + RegId: strings.Join(req.GetToken(), ","), + NotifyType: int(notifyType), + Title: req.GetTitle(), + Content: req.GetContent(), + TimeToLive: ttl, + SkipType: 1, + SkipContent: "", + NetworkType: -1, + //ClientCustomMap: req.Data, //Extra: req.Data.ExtraMap(), - RequestId: req.RequestId, - NotifyID: req.NotifyID, - Category: req.Category, + //RequestId: req.RequestId, + //NotifyID: req.NotifyID, + Category: req.GetCategory(), PushMode: pushMode, // 默认为正式推送 - ForegroundShow: req.Foreground, + ForegroundShow: req.GetForeground(), } return message, nil } diff --git a/pkg/push/xiaomi_push.go b/pkg/push/xiaomi_push.go index 6ae569d..094652d 100644 --- a/pkg/push/xiaomi_push.go +++ b/pkg/push/xiaomi_push.go @@ -8,7 +8,6 @@ import ( "github.com/cossim/hipush/api/push" "github.com/cossim/hipush/config" "github.com/cossim/hipush/pkg/consts" - "github.com/cossim/hipush/pkg/notify" "github.com/cossim/hipush/pkg/status" xp "github.com/cossim/xiaomi-push" "github.com/go-logr/logr" @@ -59,15 +58,23 @@ func NewXiaomiService(cfg *config.Config, logger logr.Logger) *XiaomiPushService return s } -func (x *XiaomiPushService) Send(ctx context.Context, request interface{}, opt ...push.SendOption) (*push.SendResponse, error) { - req, ok := request.(*notify.XiaomiPushNotification) - if !ok { - return nil, errors.New("invalid request") - } - +func (x *XiaomiPushService) Send(ctx context.Context, req push.SendRequest, opt ...push.SendOption) (*push.SendResponse, error) { so := &push.SendOptions{} so.ApplyOptions(opt) + var appid string + var ok bool + if req.GetAppID() != "" { + appid = req.GetAppID() + } else if req.GetAppName() != "" { + appid, ok = x.appNameToIDMap[req.GetAppName()] + if !ok { + return nil, ErrInvalidAppID + } + } else { + return nil, ErrInvalidAppID + } + if err := x.checkNotification(req); err != nil { return nil, err } @@ -77,18 +84,6 @@ func (x *XiaomiPushService) Send(ctx context.Context, request interface{}, opt . return nil, err } - var appid string - if req.AppID != "" { - appid = req.AppID - } else if req.AppName != "" { - appid, ok = x.appNameToIDMap[req.AppName] - if !ok { - return nil, ErrInvalidAppID - } - } else { - return nil, ErrInvalidAppID - } - if so.DryRun { return nil, nil } @@ -97,7 +92,7 @@ func (x *XiaomiPushService) Send(ctx context.Context, request interface{}, opt . return x.send(ctx, appid, token, notification) } - res, err := RetrySend(ctx, send, req.Tokens, so.Retry, so.RetryInterval, 100) + res, err := RetrySend(ctx, send, req.GetToken(), so.Retry, so.RetryInterval, 100) if err != nil { return nil, err } @@ -172,42 +167,42 @@ func (x *XiaomiPushService) GetTasksStatus(ctx context.Context, key string, task return nil } -func (x *XiaomiPushService) checkNotification(req *notify.XiaomiPushNotification) error { - if len(req.Tokens) == 0 { +func (x *XiaomiPushService) checkNotification(req push.SendRequest) error { + if len(req.GetToken()) == 0 { return errors.New("tokens cannot be empty") } - if req.Title == "" { + if req.GetTitle() == "" { return errors.New("title cannot be empty") } - if req.Content == "" { + if req.GetContent() == "" { return errors.New("content cannot be empty") } - if req.IsScheduled && req.ScheduledTime == 0 { - return errors.New("scheduled time cannot be empty") - } + //if req.IsScheduled && req.ScheduledTime == 0 { + // return errors.New("scheduled time cannot be empty") + //} return nil } -func (x *XiaomiPushService) buildNotification(req *notify.XiaomiPushNotification) (*xp.Message, error) { +func (x *XiaomiPushService) buildNotification(req push.SendRequest) (*xp.Message, error) { //msg := xp.NewAndroidMessage(req.Title, req.Content).SetPayload("this is payload1") - msg := xp.NewAndroidMessage(req.Title, req.Content) - if req.NotifyType != 0 { - msg.SetNotifyType(int32(req.NotifyType)) - } + msg := xp.NewAndroidMessage(req.GetTitle(), req.GetContent()) + //if req.NotifyType != 0 { + // msg.SetNotifyType(int32(req.NotifyType)) + //} - if req.TTL != 0 { - msg.SetTimeToLive(req.TTL) + if req.GetTTL() != 0 { + msg.SetTimeToLive(req.GetTTL()) } - if req.IsScheduled && req.ScheduledTime != 0 { - msg.SetTimeToSend(int64(req.ScheduledTime)) - } + //if req.IsScheduled && req.ScheduledTime != 0 { + // msg.SetTimeToSend(int64(req.ScheduledTime)) + //} - if req.IsShowNotify { + if req.GetForeground() { msg.Extra["notify_foreground"] = "1" } else { msg.Extra["notify_foreground"] = "0" @@ -237,7 +232,7 @@ func (x *XiaomiPushService) send(ctx context.Context, appID string, token string resp.Code = int(res.Code) resp.Msg = res.Reason } else { - log.Printf("xiaomi send success: %s", res.Reason) + log.Printf("xiaomi send success: %v", res) x.status.AddXiaomiSuccess(1) resp.Code = Success resp.Msg = res.Reason