first commit
This commit is contained in:
19
service/offline-push/CHANGELOG.md
Normal file
19
service/offline-push/CHANGELOG.md
Normal file
@@ -0,0 +1,19 @@
|
||||
版本号`major.minor.patch`具体规则如下:
|
||||
- major:主版本号,如有重大版本重构则该字段递增,通常各主版本间接口不兼容。
|
||||
- minor:次版本号,各次版本号间接口保持兼容,如有接口新增或优化则该字段递增。
|
||||
- patch:补丁号,如有功能改善或缺陷修复则该字段递增。
|
||||
|
||||
## version 0.0.2
|
||||
|
||||
init offline-push
|
||||
|
||||
|
||||
## example x.x.x @yy.mm.dd
|
||||
|
||||
**Feature**
|
||||
|
||||
**Bug Fixes**
|
||||
|
||||
**Improvement**
|
||||
|
||||
**Breaking Change**
|
||||
37
service/offline-push/Makefile
Normal file
37
service/offline-push/Makefile
Normal file
@@ -0,0 +1,37 @@
|
||||
# golang1.9 or latest
|
||||
# 1. make help
|
||||
# 2. make dep
|
||||
# 3. make build
|
||||
# ...
|
||||
|
||||
VERSION := $(shell echo $(shell cat version.go | grep "Version =" | cut -d '=' -f2))
|
||||
APP_NAME := offline-push
|
||||
BUILD_DIR := build
|
||||
APP := ${BUILD_DIR}/${APP_NAME}_v${VERSION}
|
||||
PKG_NAME := ${APP_NAME}_v${VERSION}
|
||||
PKG := ${PKG_NAME}.tar.gz
|
||||
|
||||
LDFLAGS := -ldflags "-w -s -X gitlab.33.cn/chat/dtalk/service/$(APP_NAME).GitCommit=`git rev-parse --short=8 HEAD`"
|
||||
LDGRPC := -ldflags "-X google.golang.org/protobuf/reflect/protoregistry.conflictPolicy=warn"
|
||||
|
||||
.PHONY: clean build pkg
|
||||
|
||||
clean: ## Remove previous build
|
||||
@rm -rf ${BUILD_DIR}
|
||||
@go clean
|
||||
|
||||
build: #checkgofmt ## Build the binary file
|
||||
GOOS=linux GOARCH=amd64 GO111MODULE=on GOPROXY=https://goproxy.cn,direct GOSUMDB="sum.golang.google.cn" go build -v $(LDGRPC) $(LDFLAGS) -o $(APP) cmd/main.go
|
||||
|
||||
pkg: build ## Package
|
||||
mkdir -p ${PKG_NAME}/bin
|
||||
mkdir -p ${PKG_NAME}/etc
|
||||
cp ${APP} ${PKG_NAME}/bin/
|
||||
cp etc/* ${PKG_NAME}/etc/
|
||||
tar zvcf ${PKG} ${PKG_NAME}
|
||||
rm -rf ${PKG_NAME}
|
||||
|
||||
REMOTE_BIN_PATH := /opt/dtalk/srv/app/bin
|
||||
upload: build
|
||||
rsync -r $(APP) 107:$(REMOTE_BIN_PATH)
|
||||
ssh 107 "cd $(REMOTE_BIN_PATH) && chmod 777 $(PKG_NAME) && ln -sf $(PKG_NAME) $(APP_NAME) && supervisorctl restart $(APP_NAME)"
|
||||
268
service/offline-push/api/api.pb.go
Normal file
268
service/offline-push/api/api.pb.go
Normal file
@@ -0,0 +1,268 @@
|
||||
// protoc -I=. -I=$GOPATH/src --go_out=plugins=grpc:. *.proto
|
||||
|
||||
// Code generated by protoc-gen-go. DO NOT EDIT.
|
||||
// versions:
|
||||
// protoc-gen-go v1.27.1
|
||||
// protoc v3.19.1
|
||||
// source: api.proto
|
||||
|
||||
package offlinepush
|
||||
|
||||
import (
|
||||
protoreflect "google.golang.org/protobuf/reflect/protoreflect"
|
||||
protoimpl "google.golang.org/protobuf/runtime/protoimpl"
|
||||
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 Device int32
|
||||
|
||||
const (
|
||||
Device_Android Device = 0
|
||||
Device_IOS Device = 1
|
||||
)
|
||||
|
||||
// Enum value maps for Device.
|
||||
var (
|
||||
Device_name = map[int32]string{
|
||||
0: "Android",
|
||||
1: "IOS",
|
||||
}
|
||||
Device_value = map[string]int32{
|
||||
"Android": 0,
|
||||
"IOS": 1,
|
||||
}
|
||||
)
|
||||
|
||||
func (x Device) Enum() *Device {
|
||||
p := new(Device)
|
||||
*p = x
|
||||
return p
|
||||
}
|
||||
|
||||
func (x Device) String() string {
|
||||
return protoimpl.X.EnumStringOf(x.Descriptor(), protoreflect.EnumNumber(x))
|
||||
}
|
||||
|
||||
func (Device) Descriptor() protoreflect.EnumDescriptor {
|
||||
return file_api_proto_enumTypes[0].Descriptor()
|
||||
}
|
||||
|
||||
func (Device) Type() protoreflect.EnumType {
|
||||
return &file_api_proto_enumTypes[0]
|
||||
}
|
||||
|
||||
func (x Device) Number() protoreflect.EnumNumber {
|
||||
return protoreflect.EnumNumber(x)
|
||||
}
|
||||
|
||||
// Deprecated: Use Device.Descriptor instead.
|
||||
func (Device) EnumDescriptor() ([]byte, []int) {
|
||||
return file_api_proto_rawDescGZIP(), []int{0}
|
||||
}
|
||||
|
||||
// record --> mq
|
||||
type OffPushMsg struct {
|
||||
state protoimpl.MessageState
|
||||
sizeCache protoimpl.SizeCache
|
||||
unknownFields protoimpl.UnknownFields
|
||||
|
||||
AppId string `protobuf:"bytes,1,opt,name=appId,proto3" json:"appId,omitempty"`
|
||||
Device Device `protobuf:"varint,2,opt,name=device,proto3,enum=dtalk.offline_push.Device" json:"device,omitempty"`
|
||||
Title string `protobuf:"bytes,3,opt,name=title,proto3" json:"title,omitempty"`
|
||||
Content string `protobuf:"bytes,4,opt,name=content,proto3" json:"content,omitempty"`
|
||||
Token string `protobuf:"bytes,5,opt,name=token,proto3" json:"token,omitempty"`
|
||||
ChannelType int32 `protobuf:"varint,6,opt,name=channelType,proto3" json:"channelType,omitempty"`
|
||||
Target string `protobuf:"bytes,7,opt,name=target,proto3" json:"target,omitempty"`
|
||||
Timeout int64 `protobuf:"varint,8,opt,name=timeout,proto3" json:"timeout,omitempty"`
|
||||
}
|
||||
|
||||
func (x *OffPushMsg) Reset() {
|
||||
*x = OffPushMsg{}
|
||||
if protoimpl.UnsafeEnabled {
|
||||
mi := &file_api_proto_msgTypes[0]
|
||||
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
|
||||
ms.StoreMessageInfo(mi)
|
||||
}
|
||||
}
|
||||
|
||||
func (x *OffPushMsg) String() string {
|
||||
return protoimpl.X.MessageStringOf(x)
|
||||
}
|
||||
|
||||
func (*OffPushMsg) ProtoMessage() {}
|
||||
|
||||
func (x *OffPushMsg) ProtoReflect() protoreflect.Message {
|
||||
mi := &file_api_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 OffPushMsg.ProtoReflect.Descriptor instead.
|
||||
func (*OffPushMsg) Descriptor() ([]byte, []int) {
|
||||
return file_api_proto_rawDescGZIP(), []int{0}
|
||||
}
|
||||
|
||||
func (x *OffPushMsg) GetAppId() string {
|
||||
if x != nil {
|
||||
return x.AppId
|
||||
}
|
||||
return ""
|
||||
}
|
||||
|
||||
func (x *OffPushMsg) GetDevice() Device {
|
||||
if x != nil {
|
||||
return x.Device
|
||||
}
|
||||
return Device_Android
|
||||
}
|
||||
|
||||
func (x *OffPushMsg) GetTitle() string {
|
||||
if x != nil {
|
||||
return x.Title
|
||||
}
|
||||
return ""
|
||||
}
|
||||
|
||||
func (x *OffPushMsg) GetContent() string {
|
||||
if x != nil {
|
||||
return x.Content
|
||||
}
|
||||
return ""
|
||||
}
|
||||
|
||||
func (x *OffPushMsg) GetToken() string {
|
||||
if x != nil {
|
||||
return x.Token
|
||||
}
|
||||
return ""
|
||||
}
|
||||
|
||||
func (x *OffPushMsg) GetChannelType() int32 {
|
||||
if x != nil {
|
||||
return x.ChannelType
|
||||
}
|
||||
return 0
|
||||
}
|
||||
|
||||
func (x *OffPushMsg) GetTarget() string {
|
||||
if x != nil {
|
||||
return x.Target
|
||||
}
|
||||
return ""
|
||||
}
|
||||
|
||||
func (x *OffPushMsg) GetTimeout() int64 {
|
||||
if x != nil {
|
||||
return x.Timeout
|
||||
}
|
||||
return 0
|
||||
}
|
||||
|
||||
var File_api_proto protoreflect.FileDescriptor
|
||||
|
||||
var file_api_proto_rawDesc = []byte{
|
||||
0x0a, 0x09, 0x61, 0x70, 0x69, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x12, 0x12, 0x64, 0x74, 0x61,
|
||||
0x6c, 0x6b, 0x2e, 0x6f, 0x66, 0x66, 0x6c, 0x69, 0x6e, 0x65, 0x5f, 0x70, 0x75, 0x73, 0x68, 0x22,
|
||||
0xf0, 0x01, 0x0a, 0x0a, 0x4f, 0x66, 0x66, 0x50, 0x75, 0x73, 0x68, 0x4d, 0x73, 0x67, 0x12, 0x14,
|
||||
0x0a, 0x05, 0x61, 0x70, 0x70, 0x49, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x05, 0x61,
|
||||
0x70, 0x70, 0x49, 0x64, 0x12, 0x32, 0x0a, 0x06, 0x64, 0x65, 0x76, 0x69, 0x63, 0x65, 0x18, 0x02,
|
||||
0x20, 0x01, 0x28, 0x0e, 0x32, 0x1a, 0x2e, 0x64, 0x74, 0x61, 0x6c, 0x6b, 0x2e, 0x6f, 0x66, 0x66,
|
||||
0x6c, 0x69, 0x6e, 0x65, 0x5f, 0x70, 0x75, 0x73, 0x68, 0x2e, 0x44, 0x65, 0x76, 0x69, 0x63, 0x65,
|
||||
0x52, 0x06, 0x64, 0x65, 0x76, 0x69, 0x63, 0x65, 0x12, 0x14, 0x0a, 0x05, 0x74, 0x69, 0x74, 0x6c,
|
||||
0x65, 0x18, 0x03, 0x20, 0x01, 0x28, 0x09, 0x52, 0x05, 0x74, 0x69, 0x74, 0x6c, 0x65, 0x12, 0x18,
|
||||
0x0a, 0x07, 0x63, 0x6f, 0x6e, 0x74, 0x65, 0x6e, 0x74, 0x18, 0x04, 0x20, 0x01, 0x28, 0x09, 0x52,
|
||||
0x07, 0x63, 0x6f, 0x6e, 0x74, 0x65, 0x6e, 0x74, 0x12, 0x14, 0x0a, 0x05, 0x74, 0x6f, 0x6b, 0x65,
|
||||
0x6e, 0x18, 0x05, 0x20, 0x01, 0x28, 0x09, 0x52, 0x05, 0x74, 0x6f, 0x6b, 0x65, 0x6e, 0x12, 0x20,
|
||||
0x0a, 0x0b, 0x63, 0x68, 0x61, 0x6e, 0x6e, 0x65, 0x6c, 0x54, 0x79, 0x70, 0x65, 0x18, 0x06, 0x20,
|
||||
0x01, 0x28, 0x05, 0x52, 0x0b, 0x63, 0x68, 0x61, 0x6e, 0x6e, 0x65, 0x6c, 0x54, 0x79, 0x70, 0x65,
|
||||
0x12, 0x16, 0x0a, 0x06, 0x74, 0x61, 0x72, 0x67, 0x65, 0x74, 0x18, 0x07, 0x20, 0x01, 0x28, 0x09,
|
||||
0x52, 0x06, 0x74, 0x61, 0x72, 0x67, 0x65, 0x74, 0x12, 0x18, 0x0a, 0x07, 0x74, 0x69, 0x6d, 0x65,
|
||||
0x6f, 0x75, 0x74, 0x18, 0x08, 0x20, 0x01, 0x28, 0x03, 0x52, 0x07, 0x74, 0x69, 0x6d, 0x65, 0x6f,
|
||||
0x75, 0x74, 0x2a, 0x1e, 0x0a, 0x06, 0x44, 0x65, 0x76, 0x69, 0x63, 0x65, 0x12, 0x0b, 0x0a, 0x07,
|
||||
0x41, 0x6e, 0x64, 0x72, 0x6f, 0x69, 0x64, 0x10, 0x00, 0x12, 0x07, 0x0a, 0x03, 0x49, 0x4f, 0x53,
|
||||
0x10, 0x01, 0x42, 0x2d, 0x5a, 0x2b, 0x67, 0x69, 0x74, 0x6c, 0x61, 0x62, 0x2e, 0x33, 0x33, 0x2e,
|
||||
0x63, 0x6e, 0x2f, 0x63, 0x68, 0x61, 0x74, 0x2f, 0x64, 0x74, 0x61, 0x6c, 0x6b, 0x2f, 0x73, 0x65,
|
||||
0x72, 0x76, 0x69, 0x63, 0x65, 0x2f, 0x6f, 0x66, 0x66, 0x6c, 0x69, 0x6e, 0x65, 0x70, 0x75, 0x73,
|
||||
0x68, 0x62, 0x06, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x33,
|
||||
}
|
||||
|
||||
var (
|
||||
file_api_proto_rawDescOnce sync.Once
|
||||
file_api_proto_rawDescData = file_api_proto_rawDesc
|
||||
)
|
||||
|
||||
func file_api_proto_rawDescGZIP() []byte {
|
||||
file_api_proto_rawDescOnce.Do(func() {
|
||||
file_api_proto_rawDescData = protoimpl.X.CompressGZIP(file_api_proto_rawDescData)
|
||||
})
|
||||
return file_api_proto_rawDescData
|
||||
}
|
||||
|
||||
var file_api_proto_enumTypes = make([]protoimpl.EnumInfo, 1)
|
||||
var file_api_proto_msgTypes = make([]protoimpl.MessageInfo, 1)
|
||||
var file_api_proto_goTypes = []interface{}{
|
||||
(Device)(0), // 0: dtalk.offline_push.Device
|
||||
(*OffPushMsg)(nil), // 1: dtalk.offline_push.OffPushMsg
|
||||
}
|
||||
var file_api_proto_depIdxs = []int32{
|
||||
0, // 0: dtalk.offline_push.OffPushMsg.device:type_name -> dtalk.offline_push.Device
|
||||
1, // [1:1] is the sub-list for method output_type
|
||||
1, // [1:1] is the sub-list for method input_type
|
||||
1, // [1:1] is the sub-list for extension type_name
|
||||
1, // [1:1] is the sub-list for extension extendee
|
||||
0, // [0:1] is the sub-list for field type_name
|
||||
}
|
||||
|
||||
func init() { file_api_proto_init() }
|
||||
func file_api_proto_init() {
|
||||
if File_api_proto != nil {
|
||||
return
|
||||
}
|
||||
if !protoimpl.UnsafeEnabled {
|
||||
file_api_proto_msgTypes[0].Exporter = func(v interface{}, i int) interface{} {
|
||||
switch v := v.(*OffPushMsg); 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_api_proto_rawDesc,
|
||||
NumEnums: 1,
|
||||
NumMessages: 1,
|
||||
NumExtensions: 0,
|
||||
NumServices: 0,
|
||||
},
|
||||
GoTypes: file_api_proto_goTypes,
|
||||
DependencyIndexes: file_api_proto_depIdxs,
|
||||
EnumInfos: file_api_proto_enumTypes,
|
||||
MessageInfos: file_api_proto_msgTypes,
|
||||
}.Build()
|
||||
File_api_proto = out.File
|
||||
file_api_proto_rawDesc = nil
|
||||
file_api_proto_goTypes = nil
|
||||
file_api_proto_depIdxs = nil
|
||||
}
|
||||
22
service/offline-push/api/api.proto
Normal file
22
service/offline-push/api/api.proto
Normal file
@@ -0,0 +1,22 @@
|
||||
// protoc -I=. -I=$GOPATH/src --go_out=plugins=grpc:. *.proto
|
||||
syntax = "proto3";
|
||||
|
||||
package dtalk.offline_push;
|
||||
option go_package = "gitlab.33.cn/chat/dtalk/service/offlinepush";
|
||||
|
||||
enum Device {
|
||||
Android = 0;
|
||||
IOS = 1;
|
||||
}
|
||||
|
||||
// record --> mq
|
||||
message OffPushMsg {
|
||||
string appId = 1;
|
||||
Device device = 2;
|
||||
string title = 3;
|
||||
string content = 4;
|
||||
string token = 5;
|
||||
int32 channelType = 6;
|
||||
string target = 7;
|
||||
int64 timeout = 8;
|
||||
}
|
||||
6
service/offline-push/api/create.sh
Normal file
6
service/offline-push/api/create.sh
Normal file
@@ -0,0 +1,6 @@
|
||||
#!/bin/sh
|
||||
|
||||
protoc -I. -I$GOPATH/src \
|
||||
--go_out=. --go_opt=paths=source_relative \
|
||||
--go-grpc_out=. --go-grpc_opt=paths=source_relative \
|
||||
*.proto
|
||||
87
service/offline-push/cmd/main.go
Normal file
87
service/offline-push/cmd/main.go
Normal file
@@ -0,0 +1,87 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
"flag"
|
||||
"fmt"
|
||||
"os"
|
||||
"os/signal"
|
||||
"syscall"
|
||||
"time"
|
||||
|
||||
"github.com/inconshreveable/log15"
|
||||
"gitlab.33.cn/chat/dtalk/service/offline-push/config"
|
||||
_ "gitlab.33.cn/chat/dtalk/service/offline-push/pusher/android"
|
||||
_ "gitlab.33.cn/chat/dtalk/service/offline-push/pusher/ios"
|
||||
"gitlab.33.cn/chat/dtalk/service/offline-push/service"
|
||||
)
|
||||
|
||||
const srvName = "offline-push"
|
||||
|
||||
var log = log15.New("cmd", srvName)
|
||||
|
||||
var (
|
||||
// projectVersion 项目版本
|
||||
projectVersion = "0.0.2"
|
||||
// goVersion go版本
|
||||
goVersion = ""
|
||||
// gitCommit git提交commit id
|
||||
gitCommit = ""
|
||||
// buildTime 编译时间
|
||||
buildTime = ""
|
||||
|
||||
isShowVersion = flag.Bool("v", false, "show project version")
|
||||
)
|
||||
|
||||
// showVersion 显示项目版本信息
|
||||
func showVersion(isShow bool) {
|
||||
if isShow {
|
||||
fmt.Printf("Project: %s\n", srvName)
|
||||
fmt.Printf(" Version: %s\n", projectVersion)
|
||||
fmt.Printf(" Go Version: %s\n", goVersion)
|
||||
fmt.Printf(" Git Commit: %s\n", gitCommit)
|
||||
fmt.Printf(" Build Time: %s\n", buildTime)
|
||||
os.Exit(0)
|
||||
}
|
||||
}
|
||||
|
||||
// @Title 聊天单模块集成测试
|
||||
// @Version 0.1
|
||||
// @Description
|
||||
// @SecurityDefinitions.ApiKey ApiKeyAuth
|
||||
// @In header
|
||||
// @Name Authorization
|
||||
// @BasePath /
|
||||
func main() {
|
||||
flag.Parse()
|
||||
showVersion(*isShowVersion)
|
||||
|
||||
if err := config.Init(); err != nil {
|
||||
panic(err)
|
||||
}
|
||||
log.Info("config info:",
|
||||
"AppId", config.Conf.AppId,
|
||||
"Pushers Android", config.Conf.Pushers["Android"],
|
||||
"Pushers iOS", config.Conf.Pushers["iOS"],
|
||||
"MQSub", config.Conf.MQSub)
|
||||
// service init
|
||||
svc := service.New(config.Conf)
|
||||
svc.ListenMQ()
|
||||
|
||||
// init signal
|
||||
c := make(chan os.Signal, 1)
|
||||
signal.Notify(c, syscall.SIGHUP, syscall.SIGQUIT, syscall.SIGTERM, syscall.SIGINT)
|
||||
for {
|
||||
s := <-c
|
||||
log.Info("service get a signal %s", s.String())
|
||||
switch s {
|
||||
case syscall.SIGQUIT, syscall.SIGTERM, syscall.SIGINT:
|
||||
time.Sleep(time.Second * 2)
|
||||
log.Info(srvName + " server exit")
|
||||
return
|
||||
case syscall.SIGHUP:
|
||||
// TODO reload
|
||||
default:
|
||||
return
|
||||
}
|
||||
}
|
||||
}
|
||||
53
service/offline-push/config/config.go
Normal file
53
service/offline-push/config/config.go
Normal file
@@ -0,0 +1,53 @@
|
||||
package config
|
||||
|
||||
import (
|
||||
"flag"
|
||||
"github.com/BurntSushi/toml"
|
||||
)
|
||||
|
||||
var (
|
||||
confPath string
|
||||
|
||||
// Conf config
|
||||
Conf *Config
|
||||
)
|
||||
|
||||
func init() {
|
||||
flag.StringVar(&confPath, "conf", "offline-push.toml", "default config path.")
|
||||
}
|
||||
|
||||
// Init init config.
|
||||
func Init() (err error) {
|
||||
Conf = Default()
|
||||
_, err = toml.DecodeFile(confPath, &Conf)
|
||||
return
|
||||
}
|
||||
|
||||
// Default new a config with specified defualt value.
|
||||
func Default() *Config {
|
||||
return &Config{
|
||||
MQSub: &MQSubClient{
|
||||
Brokers: nil,
|
||||
Number: 0,
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
type Config struct {
|
||||
//push config
|
||||
AppId string
|
||||
Pushers map[string]*Pusher
|
||||
MQSub *MQSubClient
|
||||
}
|
||||
|
||||
type Pusher struct {
|
||||
Env string
|
||||
AppKey string
|
||||
AppMasterSecret string
|
||||
MiActivity string
|
||||
}
|
||||
|
||||
type MQSubClient struct {
|
||||
Brokers []string
|
||||
Number uint32
|
||||
}
|
||||
22
service/offline-push/config/offline-push.toml
Normal file
22
service/offline-push/config/offline-push.toml
Normal file
@@ -0,0 +1,22 @@
|
||||
AppId= "dtalk"
|
||||
|
||||
[server]
|
||||
addr="0.0.0.0:18100"
|
||||
|
||||
[MQSub]
|
||||
Brokers=["127.0.0.1:9092"]
|
||||
Number=16
|
||||
|
||||
# 友盟离线推送物料
|
||||
[pushers]
|
||||
[pushers.Android]
|
||||
Env = "debug"
|
||||
AppKey = ""
|
||||
AppMasterSecret = ""
|
||||
MiActivity = ""
|
||||
|
||||
[pushers.iOS]
|
||||
Env = "debug"
|
||||
AppKey = ""
|
||||
AppMasterSecret = ""
|
||||
MiActivity = ""
|
||||
9
service/offline-push/model/error.go
Normal file
9
service/offline-push/model/error.go
Normal file
@@ -0,0 +1,9 @@
|
||||
package model
|
||||
|
||||
import "errors"
|
||||
|
||||
var (
|
||||
ErrAppId = errors.New("appId not compared")
|
||||
ErrConsumeRedo = errors.New("process msg failed")
|
||||
ErrCustomNotSupport = errors.New("pusher device type not support")
|
||||
)
|
||||
18
service/offline-push/pusher/android/plugin.go
Normal file
18
service/offline-push/pusher/android/plugin.go
Normal file
@@ -0,0 +1,18 @@
|
||||
package android
|
||||
|
||||
import "gitlab.33.cn/chat/dtalk/service/offline-push/pusher"
|
||||
|
||||
const Name = "Android"
|
||||
|
||||
func init() {
|
||||
pusher.Register(Name, New)
|
||||
}
|
||||
|
||||
func New(cfg pusher.Config) pusher.IPusher {
|
||||
return &androidPusher{
|
||||
AppKey: cfg.AppKey,
|
||||
AppMasterSecret: cfg.AppMasterSecret,
|
||||
MiActivity: cfg.MiActivity,
|
||||
environment: cfg.Environment,
|
||||
}
|
||||
}
|
||||
74
service/offline-push/pusher/android/push.go
Normal file
74
service/offline-push/pusher/android/push.go
Normal file
@@ -0,0 +1,74 @@
|
||||
package android
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"gitlab.33.cn/chat/dtalk/pkg/util"
|
||||
"strconv"
|
||||
|
||||
push "github.com/oofpgDLD/u-push"
|
||||
android_push "github.com/oofpgDLD/u-push/android"
|
||||
"gitlab.33.cn/chat/dtalk/service/offline-push/pusher"
|
||||
)
|
||||
|
||||
type androidPusher struct {
|
||||
AppKey string
|
||||
AppMasterSecret string
|
||||
MiActivity string
|
||||
environment string
|
||||
}
|
||||
|
||||
func (t *androidPusher) SinglePush(deviceToken, title, text string, extra *pusher.Extra) error {
|
||||
var client push.PushClient
|
||||
unicast := android_push.NewAndroidUnicast(t.AppKey, t.AppMasterSecret)
|
||||
|
||||
//fmt.Println(t.AppKey, t.AppMasterSecret, t.DeviceToken, title, text)
|
||||
unicast.SetDeviceToken(deviceToken)
|
||||
unicast.SetTitle(title)
|
||||
unicast.SetText(text)
|
||||
unicast.GoCustomAfterOpen("")
|
||||
unicast.SetDisplayType(push.NOTIFICATION)
|
||||
unicast.SetMipush(true, t.MiActivity)
|
||||
unicast.SetExpireTime(util.UnixToTime(extra.TimeOutTime).In(util.Shanghai()).Format("2006-01-02 15:04:05"))
|
||||
switch t.environment {
|
||||
case "debug":
|
||||
// 测试模式
|
||||
unicast.SetTestMode()
|
||||
case "release":
|
||||
// 线上模式
|
||||
unicast.SetReleaseMode()
|
||||
default:
|
||||
return errors.New("unknown environment")
|
||||
}
|
||||
// Set customized fields
|
||||
unicast.SetExtraField("address", extra.Address)
|
||||
unicast.SetExtraField("channelType", strconv.FormatInt(int64(extra.ChannelType), 10))
|
||||
return client.Send(unicast)
|
||||
}
|
||||
|
||||
func (t *androidPusher) SingleCustomPush(address, title, text string, extra *pusher.Extra) error {
|
||||
var client push.PushClient
|
||||
unicast := android_push.NewAndroidCustomizedcast(t.AppKey, t.AppMasterSecret)
|
||||
|
||||
//fmt.Println(t.AppKey, t.AppMasterSecret, t.DeviceToken, title, text)
|
||||
unicast.SetAlias(address, "ADDRESS")
|
||||
unicast.SetTitle(title)
|
||||
unicast.SetText(text)
|
||||
unicast.GoCustomAfterOpen("")
|
||||
unicast.SetDisplayType(push.NOTIFICATION)
|
||||
unicast.SetMipush(true, t.MiActivity)
|
||||
unicast.SetExpireTime(util.UnixToTime(extra.TimeOutTime).In(util.Shanghai()).Format("2006-01-02 15:04:05"))
|
||||
switch t.environment {
|
||||
case "debug":
|
||||
// 测试模式
|
||||
unicast.SetTestMode()
|
||||
case "release":
|
||||
// 线上模式
|
||||
unicast.SetReleaseMode()
|
||||
default:
|
||||
return errors.New("unknown environment")
|
||||
}
|
||||
// Set customized fields
|
||||
unicast.SetExtraField("address", extra.Address)
|
||||
unicast.SetExtraField("channelType", strconv.FormatInt(int64(extra.ChannelType), 10))
|
||||
return client.Send(unicast)
|
||||
}
|
||||
60
service/offline-push/pusher/android/push_test.go
Normal file
60
service/offline-push/pusher/android/push_test.go
Normal file
@@ -0,0 +1,60 @@
|
||||
package android
|
||||
|
||||
import (
|
||||
"gitlab.33.cn/chat/dtalk/service/offline-push/pusher"
|
||||
"testing"
|
||||
)
|
||||
|
||||
func Test_androidPusher_SinglePush(t1 *testing.T) {
|
||||
type fields struct {
|
||||
AppKey string
|
||||
AppMasterSecret string
|
||||
MiActivity string
|
||||
environment string
|
||||
}
|
||||
type args struct {
|
||||
deviceToken string
|
||||
title string
|
||||
text string
|
||||
extra *pusher.Extra
|
||||
}
|
||||
tests := []struct {
|
||||
name string
|
||||
fields fields
|
||||
args args
|
||||
wantErr bool
|
||||
}{
|
||||
{
|
||||
name: "test android offline push",
|
||||
fields: fields{
|
||||
AppKey: "606ebf176a23f17dcf15b2cd",
|
||||
AppMasterSecret: "uengh9mzrvm5zdclyt5ean05ckqc2lxl",
|
||||
MiActivity: "",
|
||||
environment: "debug",
|
||||
},
|
||||
args: args{
|
||||
deviceToken: "Apjwo_0X0-y0sGcWPxzGrY1dl2qvv_uE7LAeCoivoHjf",
|
||||
title: "测试title",
|
||||
text: "测试text",
|
||||
extra: &pusher.Extra{
|
||||
Address: "1FdnxKR4r952x2HQA2BTTpFH6tgHYYNs3M",
|
||||
ChannelType: 0,
|
||||
},
|
||||
},
|
||||
wantErr: false,
|
||||
},
|
||||
}
|
||||
for _, tt := range tests {
|
||||
t1.Run(tt.name, func(t1 *testing.T) {
|
||||
t := &androidPusher{
|
||||
AppKey: tt.fields.AppKey,
|
||||
AppMasterSecret: tt.fields.AppMasterSecret,
|
||||
MiActivity: tt.fields.MiActivity,
|
||||
environment: tt.fields.environment,
|
||||
}
|
||||
if err := t.SinglePush(tt.args.deviceToken, tt.args.title, tt.args.text, tt.args.extra); (err != nil) != tt.wantErr {
|
||||
t1.Errorf("SinglePush() error = %v, wantErr %v", err, tt.wantErr)
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
18
service/offline-push/pusher/ios/plugin.go
Normal file
18
service/offline-push/pusher/ios/plugin.go
Normal file
@@ -0,0 +1,18 @@
|
||||
package ios
|
||||
|
||||
import "gitlab.33.cn/chat/dtalk/service/offline-push/pusher"
|
||||
|
||||
const Name = "iOS"
|
||||
|
||||
func init() {
|
||||
pusher.Register(Name, New)
|
||||
}
|
||||
|
||||
func New(cfg pusher.Config) pusher.IPusher {
|
||||
return &iOSPusher{
|
||||
AppKey: cfg.AppKey,
|
||||
AppMasterSecret: cfg.AppMasterSecret,
|
||||
MiActivity: cfg.MiActivity,
|
||||
environment: cfg.Environment,
|
||||
}
|
||||
}
|
||||
82
service/offline-push/pusher/ios/push.go
Normal file
82
service/offline-push/pusher/ios/push.go
Normal file
@@ -0,0 +1,82 @@
|
||||
package ios
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"gitlab.33.cn/chat/dtalk/pkg/util"
|
||||
"strconv"
|
||||
|
||||
push "github.com/oofpgDLD/u-push"
|
||||
ios_push "github.com/oofpgDLD/u-push/ios"
|
||||
"gitlab.33.cn/chat/dtalk/service/offline-push/pusher"
|
||||
)
|
||||
|
||||
type iOSPusher struct {
|
||||
AppKey string
|
||||
AppMasterSecret string
|
||||
MiActivity string
|
||||
environment string
|
||||
}
|
||||
|
||||
func (t *iOSPusher) SinglePush(deviceToken, title, text string, extra *pusher.Extra) error {
|
||||
var client push.PushClient
|
||||
unicast := ios_push.NewIOSUnicast(t.AppKey, t.AppMasterSecret)
|
||||
|
||||
//fmt.Println(t.AppKey, t.AppMasterSecret, t.DeviceToken, title, text)
|
||||
unicast.SetDeviceToken(deviceToken)
|
||||
|
||||
//unicast.SetAlert("IOS 单播测试")
|
||||
unicast.SetAlertJson(push.IOSAlert{
|
||||
Title: title,
|
||||
Body: text,
|
||||
})
|
||||
//unicast.SetBadge(0)
|
||||
unicast.SetSound("default")
|
||||
unicast.SetExpireTime(util.UnixToTime(extra.TimeOutTime).In(util.Shanghai()).Format("2006-01-02 15:04:05"))
|
||||
|
||||
switch t.environment {
|
||||
case "debug":
|
||||
// 测试模式
|
||||
unicast.SetTestMode()
|
||||
case "release":
|
||||
// 线上模式
|
||||
unicast.SetReleaseMode()
|
||||
default:
|
||||
return errors.New("unknown environment")
|
||||
}
|
||||
// Set customized fields
|
||||
unicast.SetCustomizedField("address", extra.Address)
|
||||
unicast.SetCustomizedField("channelType", strconv.FormatInt(int64(extra.ChannelType), 10))
|
||||
return client.Send(unicast)
|
||||
}
|
||||
|
||||
func (t *iOSPusher) SingleCustomPush(address, title, text string, extra *pusher.Extra) error {
|
||||
var client push.PushClient
|
||||
unicast := ios_push.NewIOSCustomizedcast(t.AppKey, t.AppMasterSecret)
|
||||
|
||||
//fmt.Println(t.AppKey, t.AppMasterSecret, t.DeviceToken, title, text)
|
||||
unicast.SetAlias(address, "ADDRESS")
|
||||
|
||||
//unicast.SetAlert("IOS 单播测试")
|
||||
unicast.SetAlertJson(push.IOSAlert{
|
||||
Title: title,
|
||||
Body: text,
|
||||
})
|
||||
//unicast.SetBadge(0)
|
||||
unicast.SetSound("default")
|
||||
unicast.SetExpireTime(util.UnixToTime(extra.TimeOutTime).In(util.Shanghai()).Format("2006-01-02 15:04:05"))
|
||||
|
||||
switch t.environment {
|
||||
case "debug":
|
||||
// 测试模式
|
||||
unicast.SetTestMode()
|
||||
case "release":
|
||||
// 线上模式
|
||||
unicast.SetReleaseMode()
|
||||
default:
|
||||
return errors.New("unknown environment")
|
||||
}
|
||||
// Set customized fields
|
||||
unicast.SetCustomizedField("address", extra.Address)
|
||||
unicast.SetCustomizedField("channelType", strconv.FormatInt(int64(extra.ChannelType), 10))
|
||||
return client.Send(unicast)
|
||||
}
|
||||
44
service/offline-push/pusher/push.go
Normal file
44
service/offline-push/pusher/push.go
Normal file
@@ -0,0 +1,44 @@
|
||||
package pusher
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"errors"
|
||||
)
|
||||
|
||||
var execPusher = make(map[string]CreateFunc)
|
||||
|
||||
type CreateFunc func(cfg Config) IPusher
|
||||
|
||||
func Register(name string, exec CreateFunc) {
|
||||
execPusher[name] = exec
|
||||
}
|
||||
|
||||
func Load(name string) (CreateFunc, error) {
|
||||
exec, ok := execPusher[name]
|
||||
if !ok {
|
||||
return nil, errors.New("pusher not find")
|
||||
}
|
||||
return exec, nil
|
||||
}
|
||||
|
||||
type Config struct {
|
||||
AppKey string
|
||||
AppMasterSecret string
|
||||
MiActivity string
|
||||
Environment string
|
||||
}
|
||||
|
||||
type IPusher interface {
|
||||
SinglePush(deviceToken, title, text string, extra *Extra) error
|
||||
SingleCustomPush(address, title, text string, extra *Extra) error
|
||||
}
|
||||
|
||||
type Extra struct {
|
||||
Address string `json:"address"`
|
||||
ChannelType int32 `json:"channelType"`
|
||||
TimeOutTime int64 `json:"-"`
|
||||
}
|
||||
|
||||
func (e *Extra) ToBytes() ([]byte, error) {
|
||||
return json.Marshal(e)
|
||||
}
|
||||
49
service/offline-push/service/kafka/consumer.go
Normal file
49
service/offline-push/service/kafka/consumer.go
Normal file
@@ -0,0 +1,49 @@
|
||||
package kafka
|
||||
|
||||
import (
|
||||
cluster "github.com/bsm/sarama-cluster"
|
||||
"github.com/golang/protobuf/proto"
|
||||
"github.com/inconshreveable/log15"
|
||||
offlinepush "gitlab.33.cn/chat/dtalk/service/offline-push/api"
|
||||
"gitlab.33.cn/chat/dtalk/service/offline-push/model"
|
||||
)
|
||||
|
||||
var log = log15.New("model", "offputhtest")
|
||||
|
||||
type Process interface {
|
||||
Deal(m *offlinepush.OffPushMsg) error
|
||||
}
|
||||
|
||||
type Consumer struct {
|
||||
*cluster.Consumer
|
||||
}
|
||||
|
||||
func (c *Consumer) Listen(p Process) {
|
||||
for {
|
||||
select {
|
||||
case err := <-c.Errors():
|
||||
log.Error("consumer error", "err", err)
|
||||
case n := <-c.Notifications():
|
||||
log.Info("consumer rebalanced", "number", n)
|
||||
case msg, ok := <-c.Messages():
|
||||
if !ok {
|
||||
log.Debug("consume not ok", "topic", msg.Topic, "partition", msg.Partition, "offset", msg.Offset, "key", msg.Key)
|
||||
return
|
||||
}
|
||||
bizMsg := new(offlinepush.OffPushMsg)
|
||||
if err := proto.Unmarshal(msg.Value, bizMsg); err != nil {
|
||||
log.Error("proto.Unmarshal error", "err", err, "msg", msg)
|
||||
continue
|
||||
}
|
||||
log.Debug("consume process", "topic", msg.Topic, "partition", msg.Partition, "offset", msg.Offset, "key", msg.Key, "bizMsg", bizMsg)
|
||||
err := p.Deal(bizMsg)
|
||||
if err != nil {
|
||||
log.Debug("p.Deal error", "err", err, "bizMsg", bizMsg)
|
||||
if err == model.ErrConsumeRedo {
|
||||
//TODO redo consume message
|
||||
}
|
||||
}
|
||||
c.MarkOffset(msg, "")
|
||||
}
|
||||
}
|
||||
}
|
||||
34
service/offline-push/service/kafka/creator.go
Normal file
34
service/offline-push/service/kafka/creator.go
Normal file
@@ -0,0 +1,34 @@
|
||||
package kafka
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
cluster "github.com/bsm/sarama-cluster"
|
||||
"gitlab.33.cn/chat/dtalk/service/offline-push/config"
|
||||
"strconv"
|
||||
)
|
||||
|
||||
func NewKafkaConsumers(appId string, cfg *config.MQSubClient, groupIdx int) map[string]*Consumer {
|
||||
store := make(map[string]*Consumer)
|
||||
num := int(cfg.Number)
|
||||
for i := 0; i < num; i++ {
|
||||
store[strconv.Itoa(i)] = &Consumer{Consumer: newKafkaSub(appId, groupIdx, cfg.Brokers)}
|
||||
}
|
||||
return store
|
||||
}
|
||||
|
||||
func newKafkaSub(appId string, groupIdx int, brokers []string) *cluster.Consumer {
|
||||
c := cluster.NewConfig()
|
||||
c.Consumer.Return.Errors = true
|
||||
c.Group.Return.Notifications = true
|
||||
|
||||
topic := fmt.Sprintf("offpush-%s-topic", appId)
|
||||
group := fmt.Sprintf("offpush-%s-group", appId)
|
||||
if groupIdx > 0 {
|
||||
group = fmt.Sprintf("%s-%d", group, groupIdx)
|
||||
}
|
||||
consumer, err := cluster.NewConsumer(brokers, group, []string{topic}, c)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
return consumer
|
||||
}
|
||||
95
service/offline-push/service/service.go
Normal file
95
service/offline-push/service/service.go
Normal file
@@ -0,0 +1,95 @@
|
||||
package service
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"time"
|
||||
|
||||
"github.com/inconshreveable/log15"
|
||||
offlinepush "gitlab.33.cn/chat/dtalk/service/offline-push/api"
|
||||
"gitlab.33.cn/chat/dtalk/service/offline-push/config"
|
||||
"gitlab.33.cn/chat/dtalk/service/offline-push/model"
|
||||
"gitlab.33.cn/chat/dtalk/service/offline-push/pusher"
|
||||
"gitlab.33.cn/chat/dtalk/service/offline-push/pusher/android"
|
||||
"gitlab.33.cn/chat/dtalk/service/offline-push/pusher/ios"
|
||||
"gitlab.33.cn/chat/dtalk/service/offline-push/service/kafka"
|
||||
)
|
||||
|
||||
type Service struct {
|
||||
log log15.Logger
|
||||
cfg *config.Config
|
||||
consumers map[string]*kafka.Consumer
|
||||
pushers map[offlinepush.Device]pusher.IPusher
|
||||
}
|
||||
|
||||
func New(c *config.Config) *Service {
|
||||
s := &Service{
|
||||
log: log15.New("module", "offline-push/service"),
|
||||
cfg: c,
|
||||
consumers: kafka.NewKafkaConsumers(c.AppId, c.MQSub, 0),
|
||||
pushers: make(map[offlinepush.Device]pusher.IPusher),
|
||||
}
|
||||
s.loadPushers()
|
||||
return s
|
||||
}
|
||||
|
||||
func (s Service) Config() *config.Config {
|
||||
return s.cfg
|
||||
}
|
||||
|
||||
func (s *Service) ListenMQ() {
|
||||
for i, c := range s.consumers {
|
||||
s.log.Debug(fmt.Sprintf("accept %v", i))
|
||||
go c.Listen(s)
|
||||
}
|
||||
}
|
||||
func (s *Service) loadPushers() {
|
||||
androidCreator, err := pusher.Load(android.Name)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
iOSCreator, err := pusher.Load(ios.Name)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
s.pushers[offlinepush.Device_Android] = androidCreator(pusher.Config{
|
||||
AppKey: s.cfg.Pushers[android.Name].AppKey,
|
||||
AppMasterSecret: s.cfg.Pushers[android.Name].AppMasterSecret,
|
||||
MiActivity: s.cfg.Pushers[android.Name].MiActivity,
|
||||
Environment: s.cfg.Pushers[android.Name].Env,
|
||||
})
|
||||
s.pushers[offlinepush.Device_IOS] = iOSCreator(pusher.Config{
|
||||
AppKey: s.cfg.Pushers[ios.Name].AppKey,
|
||||
AppMasterSecret: s.cfg.Pushers[ios.Name].AppMasterSecret,
|
||||
MiActivity: s.cfg.Pushers[ios.Name].MiActivity,
|
||||
Environment: s.cfg.Pushers[ios.Name].Env,
|
||||
})
|
||||
}
|
||||
|
||||
func (s *Service) Deal(m *offlinepush.OffPushMsg) error {
|
||||
if m.AppId != s.cfg.AppId {
|
||||
return model.ErrAppId
|
||||
}
|
||||
|
||||
p, ok := s.pushers[m.Device]
|
||||
if !ok {
|
||||
s.log.Error("pusher exec not find", "deviceType", m.Device.String(), "pushers", s.pushers)
|
||||
return model.ErrCustomNotSupport
|
||||
}
|
||||
if tm := time.Now().Unix(); tm > m.Timeout {
|
||||
s.log.Info("message offline push timeout",
|
||||
"appId", m.GetAppId(),
|
||||
"deviceType", m.GetDevice().String(),
|
||||
"deviceToken", m.GetToken(),
|
||||
"channelType", m.GetChannelType(),
|
||||
"target", m.GetTarget(),
|
||||
"timeout time", m.GetTimeout(),
|
||||
"now time", tm,
|
||||
)
|
||||
return nil
|
||||
}
|
||||
return p.SinglePush(m.Token, m.Title, m.Content, &pusher.Extra{
|
||||
Address: m.Target,
|
||||
ChannelType: m.ChannelType,
|
||||
TimeOutTime: m.Timeout,
|
||||
})
|
||||
}
|
||||
21
service/offline-push/tools/mock/Makefile
Normal file
21
service/offline-push/tools/mock/Makefile
Normal file
@@ -0,0 +1,21 @@
|
||||
# golang1.9 or latest
|
||||
# 1. make help
|
||||
# 2. make dep
|
||||
# 3. make build
|
||||
# ...
|
||||
|
||||
APP_NAME := client
|
||||
BUILD_DIR := build
|
||||
APP := ${BUILD_DIR}/${APP_NAME}
|
||||
|
||||
LDFLAGS := -ldflags "-w -s -X gitlab.33.cn/chat/dtalk/version.GitCommit=`git rev-parse --short=8 HEAD`"
|
||||
LDGRPC := -ldflags "-X google.golang.org/protobuf/reflect/protoregistry.conflictPolicy=warn"
|
||||
|
||||
.PHONY: clean build
|
||||
|
||||
clean: ## Remove previous build
|
||||
@rm -rf ${BUILD_DIR}
|
||||
@go clean
|
||||
|
||||
build: #checkgofmt ## Build the binary file
|
||||
GOOS=linux GOARCH=amd64 GO111MODULE=on GOPROXY=https://goproxy.cn,direct GOSUMDB="sum.golang.google.cn" go build -v $(LDGRPC) $(LDFLAGS) -o $(APP) cmd/main.go
|
||||
38
service/offline-push/tools/mock/client.go
Normal file
38
service/offline-push/tools/mock/client.go
Normal file
@@ -0,0 +1,38 @@
|
||||
package mock
|
||||
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
"gitlab.33.cn/chat/dtalk/service/record/kafka/publisher"
|
||||
"gopkg.in/Shopify/sarama.v1"
|
||||
kafka "gopkg.in/Shopify/sarama.v1"
|
||||
)
|
||||
|
||||
type Client struct {
|
||||
brokers []string
|
||||
appId string
|
||||
offPushPub kafka.SyncProducer
|
||||
}
|
||||
|
||||
func NewClient(appId string, brokers []string) *Client {
|
||||
c := &Client{
|
||||
appId: appId,
|
||||
brokers: brokers,
|
||||
offPushPub: publisher.NewKafkaPub(brokers),
|
||||
}
|
||||
return c
|
||||
}
|
||||
|
||||
func (c *Client) PublishOfflineMsg(ctx context.Context, fromId string, b []byte) error {
|
||||
if c.offPushPub == nil {
|
||||
return fmt.Errorf("kafka publish client not init")
|
||||
}
|
||||
appTopic := fmt.Sprintf("offpush-%s-topic", c.appId)
|
||||
m := &sarama.ProducerMessage{
|
||||
Key: sarama.StringEncoder(fromId),
|
||||
Topic: appTopic,
|
||||
Value: sarama.ByteEncoder(b),
|
||||
}
|
||||
_, _, err := c.offPushPub.SendMessage(m)
|
||||
return err
|
||||
}
|
||||
31
service/offline-push/tools/mock/cmd/main.go
Normal file
31
service/offline-push/tools/mock/cmd/main.go
Normal file
@@ -0,0 +1,31 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"os"
|
||||
|
||||
"github.com/spf13/cobra"
|
||||
"gitlab.33.cn/chat/dtalk/service/offline-push/tools/mock/cmd/push"
|
||||
)
|
||||
|
||||
var rootCmd = &cobra.Command{
|
||||
Use: "tools",
|
||||
Short: "offline push mock tools",
|
||||
Example: " tools auth -d <data>\n",
|
||||
}
|
||||
|
||||
func init() {
|
||||
rootCmd.AddCommand(push.SinglePushCmd)
|
||||
}
|
||||
|
||||
// Execute executes the root command and its subcommands.
|
||||
func Execute() {
|
||||
if err := rootCmd.Execute(); err != nil {
|
||||
fmt.Println(err)
|
||||
os.Exit(1)
|
||||
}
|
||||
}
|
||||
|
||||
func main() {
|
||||
Execute()
|
||||
}
|
||||
50
service/offline-push/tools/mock/cmd/push/push.go
Normal file
50
service/offline-push/tools/mock/cmd/push/push.go
Normal file
@@ -0,0 +1,50 @@
|
||||
package push
|
||||
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
"github.com/spf13/cobra"
|
||||
offlinepush "gitlab.33.cn/chat/dtalk/service/offline-push/api"
|
||||
"gitlab.33.cn/chat/dtalk/service/offline-push/tools/mock"
|
||||
config "gitlab.33.cn/chat/dtalk/service/offline-push/tools/mock/etc"
|
||||
)
|
||||
|
||||
var SinglePushCmd = &cobra.Command{
|
||||
Use: "single",
|
||||
Short: "single push",
|
||||
Long: "single push",
|
||||
Example: "single -n 1 --hm=true -d true",
|
||||
Run: singlePush,
|
||||
}
|
||||
|
||||
func init() {
|
||||
SinglePushCmd.Flags().StringVarP(&config.ConfPath, "conf", "c", "config.toml", "default config path.")
|
||||
}
|
||||
|
||||
func singlePush(cmd *cobra.Command, args []string) {
|
||||
err := config.Init()
|
||||
if err != nil {
|
||||
fmt.Printf("config init error:%v\n", err)
|
||||
return
|
||||
}
|
||||
fmt.Printf("Client Config: %v\n Msg Config: %v\n", config.Conf.Client, config.Conf.Msg)
|
||||
c := mock.NewClient(config.Conf.Client.AppId, config.Conf.Client.Brokers)
|
||||
m := mock.Msg{
|
||||
AppId: config.Conf.Msg.AppId,
|
||||
DeviceType: offlinepush.Device(config.Conf.Msg.DeviceType),
|
||||
Nickname: config.Conf.Msg.Nickname,
|
||||
TargetId: config.Conf.Msg.TargetId,
|
||||
DeviceToken: config.Conf.Msg.DeviceToken,
|
||||
}
|
||||
data, err := m.Data()
|
||||
if err != nil {
|
||||
fmt.Printf("msg data error:%v\n", err)
|
||||
return
|
||||
}
|
||||
err = c.PublishOfflineMsg(context.Background(), config.Conf.Client.FromId, data)
|
||||
if err != nil {
|
||||
fmt.Printf("push msg error:%v\n", err)
|
||||
return
|
||||
}
|
||||
fmt.Println("success")
|
||||
}
|
||||
53
service/offline-push/tools/mock/etc/config.go
Normal file
53
service/offline-push/tools/mock/etc/config.go
Normal file
@@ -0,0 +1,53 @@
|
||||
package config
|
||||
|
||||
import (
|
||||
"github.com/BurntSushi/toml"
|
||||
)
|
||||
|
||||
var (
|
||||
ConfPath string
|
||||
Conf *Config
|
||||
)
|
||||
|
||||
// Init init config.
|
||||
func Init() (err error) {
|
||||
Conf = Default()
|
||||
_, err = toml.DecodeFile(ConfPath, &Conf)
|
||||
return
|
||||
}
|
||||
|
||||
func Default() *Config {
|
||||
return &Config{
|
||||
Client: Client{
|
||||
AppId: "",
|
||||
FromId: "",
|
||||
Brokers: nil,
|
||||
},
|
||||
Msg: Msg{
|
||||
AppId: "",
|
||||
DeviceType: 0,
|
||||
Nickname: "",
|
||||
TargetId: "",
|
||||
DeviceToken: "",
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
type Config struct {
|
||||
Client Client
|
||||
Msg Msg
|
||||
}
|
||||
|
||||
type Client struct {
|
||||
AppId string
|
||||
FromId string
|
||||
Brokers []string
|
||||
}
|
||||
|
||||
type Msg struct {
|
||||
AppId string
|
||||
DeviceType int32
|
||||
Nickname string
|
||||
TargetId string
|
||||
DeviceToken string
|
||||
}
|
||||
11
service/offline-push/tools/mock/etc/config.toml
Normal file
11
service/offline-push/tools/mock/etc/config.toml
Normal file
@@ -0,0 +1,11 @@
|
||||
[client]
|
||||
AppId = ""
|
||||
FromId="test"
|
||||
Brokers=[""]
|
||||
|
||||
[msg]
|
||||
AppId = ""
|
||||
DeviceType = 0
|
||||
Nickname = ""
|
||||
TargetId = ""
|
||||
DeviceToken = ""
|
||||
31
service/offline-push/tools/mock/msg.go
Normal file
31
service/offline-push/tools/mock/msg.go
Normal file
@@ -0,0 +1,31 @@
|
||||
package mock
|
||||
|
||||
import (
|
||||
"github.com/golang/protobuf/proto"
|
||||
offlinepush "gitlab.33.cn/chat/dtalk/service/offline-push/api"
|
||||
xproto "gitlab.33.cn/chat/imparse/proto"
|
||||
"time"
|
||||
)
|
||||
|
||||
type Msg struct {
|
||||
AppId string
|
||||
DeviceType offlinepush.Device
|
||||
Nickname string
|
||||
TargetId string
|
||||
DeviceToken string
|
||||
}
|
||||
|
||||
func (m *Msg) Data() ([]byte, error) {
|
||||
//需要推送
|
||||
pushMsg := &offApi.OffPushMsg{
|
||||
AppId: m.AppId,
|
||||
Device: m.DeviceType,
|
||||
Title: m.Nickname,
|
||||
Content: "[你收到一条消息]",
|
||||
Token: m.DeviceToken,
|
||||
ChannelType: int32(xproto.Channel_ToUser),
|
||||
Target: m.TargetId,
|
||||
Timeout: time.Now().Add(time.Minute * 7).Unix(),
|
||||
}
|
||||
return proto.Marshal(pushMsg)
|
||||
}
|
||||
16
service/offline-push/version.go
Normal file
16
service/offline-push/version.go
Normal file
@@ -0,0 +1,16 @@
|
||||
package version
|
||||
|
||||
//var (
|
||||
// // The full version string
|
||||
// Version = "0.0.2"
|
||||
//
|
||||
// // GitCommit is set with --ldflags "-X main.gitCommit=$(git rev-parse --short=8 HEAD)"
|
||||
// GitCommit string
|
||||
//)
|
||||
//
|
||||
//func GetVersion() string {
|
||||
// if GitCommit != "" {
|
||||
// return Version + "-" + GitCommit
|
||||
// }
|
||||
// return Version
|
||||
//}
|
||||
Reference in New Issue
Block a user