Create & Init Project...

This commit is contained in:
2019-04-22 18:49:16 +08:00
commit fc4fa37393
25440 changed files with 4054998 additions and 0 deletions

View File

@@ -0,0 +1,21 @@
filegroup(
name = "package-srcs",
srcs = glob(["**"]),
tags = ["automanaged"],
visibility = ["//visibility:private"],
)
filegroup(
name = "all-srcs",
srcs = [
":package-srcs",
"//app/interface/main/push/cmd:all-srcs",
"//app/interface/main/push/conf:all-srcs",
"//app/interface/main/push/dao:all-srcs",
"//app/interface/main/push/http:all-srcs",
"//app/interface/main/push/model:all-srcs",
"//app/interface/main/push/service:all-srcs",
],
tags = ["automanaged"],
visibility = ["//visibility:public"],
)

View File

@@ -0,0 +1,321 @@
# push-interface
### v2.3.3
1. 支持漫画
### v2.3.1
1. 支持国际版上报
### v2.3.0
1. using push grpc
### v2.2.2
1. 更换极光callback url
2. revert v2.2.1
### v2.2.1
1. 修复iOS上报时对设备的判断
### v2.2.0
1. 增加接收旧版本APP上报token的接口
### v2.1.2
1. 根据platform判断使用何种推送SDK改为匹配前缀方式
### v2.1.1
1. 支持极光批量回执
### v2.1.0
1. 添加极光回执
### v2.0.2
1. 小米callback加barStatus
### v2.0.1
1. use bm auth middleware
### v2.0.0
1. 去除推送能力
### v1.9.1
1. report接口token为空时返回成功
### v1.9.0
1. remove RPC service
### v1.8.16
1. iOS支持image
### v1.8.15
1. 使用 go-common/env
### v1.8.14
1. 迁移model至push-service
### v1.8.13
1. 更改jobName生成规则
### v1.8.12
1. 小米接入VIP线路
### v1.8.11
1. 第三方依赖的http的prom错误码写成err
### v1.8.10
1. 加内网设置用户开关接口
### v1.8.9
1. 获取用户开关配置接口返回值调整
### v1.8.8
1. 全量推送建任务移到 admin 项目
### v1.8.7
1. fix bug
### v1.8.6
1. add setSetting rpc method
### v1.8.5
1. add ecode
### v1.8.4
1. 添加用户上报稿件和直播的开关设置
### v1.8.3
1. business add silent time & push count limit
2. add platform midValid into progress
### v1.8.2
1. add task接口加签名
2. 回执时读取report时包含已删除的信息
### v1.8.1
1. 增加任务时加 uuid 验证
### v1.8.0
1. 接入极光
2. 回调中清理华为token
### v1.7.5
1. 回调中加入品牌
### v1.7.4
1. 在任务信息中加入 job name
### v1.7.3
1. 统计中加品牌计数
### v1.7.2
1. 推送消息过滤
### v1.7.1
1. 完善后台token推送
### v1.7.0
1. 支持后台任务推送
### v1.6.0
1. 上报接口记录Android设备信息(brand/model/os version)
2. 去掉获取小米推送结果
### v1.5.16
1. 华为流控后稍后重试
### v1.5.15
1. 华为流控判断
2. http参数错误日志级别改成warn
### v1.5.14
1. 上报接口支持oppo
### v1.5.13
1. aps中tid换成device token
### v1.5.12
1. get buvid from header at click callback
### v1.5.11
1. fix ios space scheme
### v1.5.10
1. 上报缓存中添加token对应的id
### v1.5.9
1. fix service close chan
### v1.5.8
1. 改oppo为单个token推送
### v1.5.7
1. 支持全量推送
### v1.5.5
1. 优化oppo推送
### v1.5.4
1. 消息默认不响铃、不振动
### v1.5.3
1. http接口异步处理时加返回值
### v1.5.2
1. single push接口改成POST
### v1.5.1
1. 加 revover task
2. 添加任务时加 job name
### v1.5.0
1. 接入bm
### v1.4.11
1. midValid值更精确
### v1.4.10
1. 实现oppo callback
2. decode点击回执中的token
### v1.4.9
1. 查上报缓存失败不回源
### v1.4.8
1. 添加用户上报缓存RPC
### v1.4.7
1. 修复callback platform错误
### v1.4.6
1. 增加添加上报缓存RPC
### v1.4.5
1. 优化callback extra字段
### v1.4.4
1. 将送达回执的token状态写入DB
### v1.4.3
1. 优化推送计数代码
### v1.4.2
1. 对接小米卸载token接口
### v1.4.1
1. 接小米送达回执
### v1.4.0
1. 处理送达和点击回执,入库
### v1.3.10
1. 客户端点击回执
2. 程序停止时结束当前在执行的任务再退出
### v1.3.9
1. add task fix sql
### v1.3.8
1. 新建task支持group
### v1.3.7
1. 拉取小米推送结果的天数可配置
2. 去除单推测试接口mid白名单
### v1.3.6
1. 小米regid回调
2. 优化获取小米推送结果的方式
### v1.3.5
1. 实现华为回调接口
### v1.3.4
1. 修复小米老的108位token的上报问题
### v1.3.3
1. 优化新增上报缓存
### v1.3.2
1. 添加推送任务时支持定时
### v1.3.1
1. 优化批量读取上报数据
### v1.3.0
1. 接OPPO
2. 支持按token批量推送
### v1.2.20
1. fix upload name
### v1.2.13
1. 创作姬加入H5推送协议
2. 小米推送结果拉取时间改成7天
### v1.2.12
1. 优化的推送结果统计
### v1.2.11
1. 添加华为透传消息
### v1.2.10
1. 优化华为授权
### v1.2.9
1. 华为无效token的处理
2. add task支持版本判断
3. 优化推送结果统计
### v1.2.8
1. 推送接口支持pass_through参数
2. 接入华为推送
### v1.2.7
1. 调整prom
### v1.2.6
1. 补注释处理golint报错的问题
### v1.2.5
1. 获取小米无效token加日志记录调用详情
### v1.2.4
1. 没有token的mid用小米推
### v1.2.3
1. add apns-collapse-id
### v1.2.2
1. 加入按token推送的接口供测试使用
2. 调整声音和振动http参数的校验方式
3. 改变 temp task id 长度为8位
### v1.2.1
1. 修复免打扰时间计算的bug
### v1.2.0
1. pull mipush result
### v1.1.2
1. mipush add jobkey
### v1.1.1
1. 轮询token进行无效删除
2. apns换超时机制
### v1.1.0
1. iOS push加context withtimeout
2. 加入一个利用缓存中已有mid批量测试的接口
3. 免打扰时间段内不处理推送任务
4. 修复sql in查询bug (xstr.JoinInts 不能作为占位符的值)
### v1.0.2
1. push/single接口调整参数校验
2. apns是否走代理改成配置项
3. 推送时把mid和token打印出来方便项目上线前期排查问题
4. 直播iPad支持推送协议
### v1.0.1
1. device_token为空不报-400
2. 加创作姬推送协议
### v1.0.0
1. 项目初始化

View File

@@ -0,0 +1,12 @@
# Owner
renwei
zhapuyu
caoguoliang
# Author
wangjian
caoguoliang
# Reviewer
zhapuyu
caoguoliang

View File

@@ -0,0 +1,17 @@
# See the OWNERS docs at https://go.k8s.io/owners
approvers:
- caoguoliang
- renwei
- wangjian
- zhapuyu
labels:
- interface
- interface/main/push
- main
options:
no_parent_owners: true
reviewers:
- caoguoliang
- wangjian
- zhapuyu

View File

@@ -0,0 +1,10 @@
#### push-interface
##### 项目简介
> 1.推送服务
##### 编译环境
> 请只用golang v1.7.x以上版本编译执行。
##### 依赖包
> 1.公共包go-common

View File

@@ -0,0 +1,43 @@
package(default_visibility = ["//visibility:public"])
load(
"@io_bazel_rules_go//go:def.bzl",
"go_binary",
"go_library",
)
go_binary(
name = "cmd",
embed = [":go_default_library"],
tags = ["automanaged"],
)
go_library(
name = "go_default_library",
srcs = ["main.go"],
data = ["push-interface-test.toml"],
importpath = "go-common/app/interface/main/push/cmd",
tags = ["automanaged"],
deps = [
"//app/interface/main/push/conf:go_default_library",
"//app/interface/main/push/http:go_default_library",
"//app/interface/main/push/service:go_default_library",
"//library/ecode/tip:go_default_library",
"//library/log:go_default_library",
"//library/net/trace:go_default_library",
],
)
filegroup(
name = "package-srcs",
srcs = glob(["**"]),
tags = ["automanaged"],
visibility = ["//visibility:private"],
)
filegroup(
name = "all-srcs",
srcs = [":package-srcs"],
tags = ["automanaged"],
visibility = ["//visibility:public"],
)

View File

@@ -0,0 +1,45 @@
package main
import (
"flag"
"os"
"os/signal"
"syscall"
"go-common/app/interface/main/push/conf"
"go-common/app/interface/main/push/http"
"go-common/app/interface/main/push/service"
ecode "go-common/library/ecode/tip"
"go-common/library/log"
"go-common/library/net/trace"
)
func main() {
flag.Parse()
if err := conf.Init(); err != nil {
panic(err)
}
log.Init(conf.Conf.Log)
defer log.Close()
trace.Init(conf.Conf.Tracer)
defer trace.Close()
log.Info("push-interface start")
ecode.Init(conf.Conf.Ecode)
svr := service.New(conf.Conf)
http.Init(conf.Conf, svr)
c := make(chan os.Signal, 1)
signal.Notify(c, syscall.SIGHUP, syscall.SIGQUIT, syscall.SIGTERM, syscall.SIGINT)
for {
s := <-c
log.Info("push-interface get a signal %s", s.String())
switch s {
case syscall.SIGQUIT, syscall.SIGTERM, syscall.SIGSTOP, syscall.SIGINT:
log.Info("push-interface exit")
svr.Close()
return
case syscall.SIGHUP:
default:
return
}
}
}

View File

@@ -0,0 +1,65 @@
version = "1.0.0"
user = "nobody"
pid = "/tmp/push.pid"
dir = "./"
family = "push"
[log]
dir = "/data/log/push/"
[HTTPServer]
addr = "0.0.0.0:7011"
maxListen = 1000
timeout = "1s"
readTimeout = "1s"
writeTimeout = "1s"
[HTTPClient]
dial = "50ms"
timeout = "200ms"
keepAlive = "60s"
key = "f265dcfa28272742"
secret = "437facc22dc8698b5544669bcc12348d"
[HTTPClient.breaker]
window ="1s"
sleep ="10ms"
bucket = 10
ratio = 0.5
request = 100
[reportPub]
key = "0QEO9F8JuuIxZzNDvklH"
secret="0QEO9F8JuuIxZzNDvklI"
group= "PushReport-Push-P"
topic= "PushReport-T"
action="pub"
name = "push-report-pub"
proto = "tcp"
addr = "172.16.33.158:6205"
idle = 100
active = 100
dialTimeout = "1s"
readTimeout = "60s"
writeTimeout = "1s"
idleTimeout = "10s"
[callbackPub]
key = "dbe67e6a4c36f877"
secret="6e6eb74cc73f2c8bff02fb40ee57da59"
group= "PushCallback-MainCommonArch-P"
topic= "PushCallback-T"
action="pub"
name = "push-callback-pub"
proto = "tcp"
addr = "172.16.33.158:6205"
idle = 100
active = 100
dialTimeout = "1s"
readTimeout = "60s"
writeTimeout = "1s"
idleTimeout = "10s"
[push]
callbackSize = 3 # callback 聚合数
callbackChanLen = 1024000
callbackGoroutines = 10

View File

@@ -0,0 +1,39 @@
package(default_visibility = ["//visibility:public"])
load(
"@io_bazel_rules_go//go:def.bzl",
"go_library",
)
go_library(
name = "go_default_library",
srcs = ["conf.go"],
importpath = "go-common/app/interface/main/push/conf",
tags = ["automanaged"],
deps = [
"//library/conf:go_default_library",
"//library/database/sql:go_default_library",
"//library/ecode/tip:go_default_library",
"//library/log:go_default_library",
"//library/net/http/blademaster:go_default_library",
"//library/net/http/blademaster/middleware/auth:go_default_library",
"//library/net/rpc/warden:go_default_library",
"//library/net/trace:go_default_library",
"//library/queue/databus:go_default_library",
"//vendor/github.com/BurntSushi/toml:go_default_library",
],
)
filegroup(
name = "package-srcs",
srcs = glob(["**"]),
tags = ["automanaged"],
visibility = ["//visibility:private"],
)
filegroup(
name = "all-srcs",
srcs = [":package-srcs"],
tags = ["automanaged"],
visibility = ["//visibility:public"],
)

View File

@@ -0,0 +1,88 @@
package conf
import (
"errors"
"flag"
"go-common/library/conf"
"go-common/library/database/sql"
ecode "go-common/library/ecode/tip"
"go-common/library/log"
bm "go-common/library/net/http/blademaster"
"go-common/library/net/http/blademaster/middleware/auth"
"go-common/library/net/rpc/warden"
"go-common/library/net/trace"
"go-common/library/queue/databus"
"github.com/BurntSushi/toml"
)
// global var
var (
confPath string
client *conf.Client
// Conf config
Conf = &Config{}
)
// Config config set
type Config struct {
Ecode *ecode.Config
Log *log.Config
HTTPServer *bm.ServerConfig
HTTPClient *bm.ClientConfig
PushRPC *warden.ClientConfig
Tracer *trace.Config
Auth *auth.Config
MySQL *sql.Config
ReportPub *databus.Config
CallbackPub *databus.Config
Push *push
}
type push struct {
CallbackSize int
CallbackChanLen int
CallbackGoroutines int
}
func init() {
flag.StringVar(&confPath, "conf", "", "default config path")
}
// Init init conf
func Init() error {
if confPath != "" {
return local()
}
return remote()
}
func local() (err error) {
_, err = toml.DecodeFile(confPath, &Conf)
return
}
func remote() (err error) {
if client, err = conf.New(); err != nil {
return
}
err = load()
return
}
func load() (err error) {
var (
s string
ok bool
tmpConf *Config
)
if s, ok = client.Toml2(); !ok {
return errors.New("load config center error")
}
if _, err = toml.Decode(s, &tmpConf); err != nil {
return errors.New("could not decode config")
}
*Conf = *tmpConf
return
}

View File

@@ -0,0 +1,50 @@
package(default_visibility = ["//visibility:public"])
load(
"@io_bazel_rules_go//go:def.bzl",
"go_test",
"go_library",
)
go_test(
name = "go_default_test",
srcs = ["dao_test.go"],
embed = [":go_default_library"],
rundir = ".",
tags = ["automanaged"],
deps = [
"//app/interface/main/push/conf:go_default_library",
"//vendor/github.com/smartystreets/goconvey/convey:go_default_library",
],
)
go_library(
name = "go_default_library",
srcs = [
"dao.go",
"databus.go",
],
importpath = "go-common/app/interface/main/push/dao",
tags = ["automanaged"],
deps = [
"//app/interface/main/push/conf:go_default_library",
"//app/service/main/push/model:go_default_library",
"//library/log:go_default_library",
"//library/queue/databus:go_default_library",
"//library/stat/prom:go_default_library",
],
)
filegroup(
name = "package-srcs",
srcs = glob(["**"]),
tags = ["automanaged"],
visibility = ["//visibility:private"],
)
filegroup(
name = "all-srcs",
srcs = [":package-srcs"],
tags = ["automanaged"],
visibility = ["//visibility:public"],
)

View File

@@ -0,0 +1,44 @@
package dao
import (
"context"
"go-common/app/interface/main/push/conf"
"go-common/library/queue/databus"
"go-common/library/stat/prom"
)
// Dao .
type Dao struct {
c *conf.Config
reportPub *databus.Databus
callbackPub *databus.Databus
}
// New creates a push-service DAO instance.
func New(c *conf.Config) *Dao {
d := &Dao{
c: c,
reportPub: databus.New(c.ReportPub),
callbackPub: databus.New(c.CallbackPub),
}
return d
}
// PromError prom error
func PromError(name string) {
prom.BusinessErrCount.Incr(name)
}
// PromInfo add prom info
func PromInfo(name string) {
prom.BusinessInfoCount.Incr(name)
}
// Close dao.
func (d *Dao) Close() {}
// Ping check connection status.
func (d *Dao) Ping(c context.Context) (err error) {
return
}

View File

@@ -0,0 +1,34 @@
package dao
import (
"flag"
"path/filepath"
"testing"
"go-common/app/interface/main/push/conf"
. "github.com/smartystreets/goconvey/convey"
)
var d *Dao
func init() {
dir, _ := filepath.Abs("../cmd/push-interface-test.toml")
flag.Set("conf", dir)
conf.Init()
d = New(conf.Conf)
}
func WithDao(f func(d *Dao)) func() {
return func() {
f(d)
}
}
func Test_MiInvalidTokens(t *testing.T) {
Convey("fetch mi invalid tokens", t, WithDao(func(d *Dao) {
// 用的时候打开,消息消费完了就没了
// err := d.DelInvalidMiReports(context.TODO())
// So(err, ShouldBeNil)
}))
}

View File

@@ -0,0 +1,33 @@
package dao
import (
"context"
"strconv"
pushmdl "go-common/app/service/main/push/model"
"go-common/library/log"
)
// PubReport add report to databus.
func (d *Dao) PubReport(c context.Context, info *pushmdl.Report) (err error) {
if err = d.reportPub.Send(c, info.Buvid, info); err != nil {
PromError("databus:发送上报的设备信息")
log.Error("d.reportPub.Send(%+v) error(%v)", info, err)
return
}
PromInfo("databus:发送上报的设备信息")
log.Info("PubReport(%+v) success.", info)
return
}
// PubCallback add push arrive/click callback to databus.
func (d *Dao) PubCallback(c context.Context, v []*pushmdl.Callback) (err error) {
if err = d.callbackPub.Send(c, strconv.Itoa(len(v)), v); err != nil {
PromError("databus:发送callback")
log.Error("d.callbackPub.Send(%+v) error(%v)", v, err)
return
}
PromInfo("databus:发送callback")
log.Info("PubCallback(%+v) success.", v)
return
}

View File

@@ -0,0 +1,47 @@
package(default_visibility = ["//visibility:public"])
load(
"@io_bazel_rules_go//go:def.bzl",
"go_library",
)
go_library(
name = "go_default_library",
srcs = [
"callback.go",
"http.go",
"push.go",
"report.go",
"setting.go",
],
importpath = "go-common/app/interface/main/push/http",
tags = ["automanaged"],
deps = [
"//app/interface/main/push/conf:go_default_library",
"//app/interface/main/push/service:go_default_library",
"//app/service/main/push/dao/huawei:go_default_library",
"//app/service/main/push/dao/jpush:go_default_library",
"//app/service/main/push/dao/mi:go_default_library",
"//app/service/main/push/dao/oppo:go_default_library",
"//app/service/main/push/model:go_default_library",
"//library/ecode:go_default_library",
"//library/log:go_default_library",
"//library/net/http/blademaster:go_default_library",
"//library/net/http/blademaster/middleware/auth:go_default_library",
"//library/time:go_default_library",
],
)
filegroup(
name = "package-srcs",
srcs = glob(["**"]),
tags = ["automanaged"],
visibility = ["//visibility:private"],
)
filegroup(
name = "all-srcs",
srcs = [":package-srcs"],
tags = ["automanaged"],
visibility = ["//visibility:public"],
)

View File

@@ -0,0 +1,271 @@
package http
import (
"encoding/json"
"io/ioutil"
"net/url"
"strconv"
"strings"
"go-common/app/service/main/push/dao/huawei"
"go-common/app/service/main/push/dao/jpush"
"go-common/app/service/main/push/dao/mi"
"go-common/app/service/main/push/dao/oppo"
pushmdl "go-common/app/service/main/push/model"
"go-common/library/ecode"
"go-common/library/log"
bm "go-common/library/net/http/blademaster"
)
var mobis = map[string]int{
"android": pushmdl.MobiAndroid,
"android_i": pushmdl.MobiAndroid,
"iphone": pushmdl.MobiIPhone,
"ipad": pushmdl.MobiIPad,
"android_comic": pushmdl.MobiAndroidComic,
}
func huaweiCallback(c *bm.Context) {
var (
err error
res = make(map[string]interface{})
)
defer func() {
c.JSONMap(res, err)
}()
bs, err := ioutil.ReadAll(c.Request.Body)
if err != nil {
res["errno"] = ecode.RequestErr
res["errmsg"] = "param error"
log.Error("huawei callback param(%s) error", bs)
return
}
cb := new(huawei.Callback)
if err = json.Unmarshal(bs, &cb); err != nil {
res["errno"] = ecode.RequestErr
res["errmsg"] = "param error"
log.Error("huawei callback param(%s) error(%v)", bs, err)
return
}
if err = pushSrv.CallbackHuawei(c, cb); err != nil {
res["errno"] = err
res["errmsg"] = err.Error()
log.Error("huawei callback param(%s) error(%v)", bs, err)
return
}
res["errno"] = ecode.OK
res["errmsg"] = "success"
}
func miCallback(c *bm.Context) {
param := c.Request.Form
d := param.Get("data")
if d == "" {
c.JSON(nil, ecode.RequestErr)
log.Error("xiaomi callback param empty")
return
}
m := map[string]*mi.Callback{}
if err := json.Unmarshal([]byte(d), &m); err != nil {
c.JSON(nil, ecode.RequestErr)
log.Error("xiaomi callback param(%s) error(%v)", d, err)
return
}
c.JSON(nil, pushSrv.CallbackXiaomi(c, m))
}
func miRegidCallback(c *bm.Context) {
params := c.Request.Form
appID := params.Get("app_id")
if appID == "" {
c.JSON(nil, ecode.RequestErr)
log.Error("app_id is empty")
return
}
appVer := params.Get("app_version")
if appVer == "" {
c.JSON(nil, ecode.RequestErr)
log.Error("app_version is empty")
return
}
appPkg := params.Get("app_pkg")
if appPkg == "" {
c.JSON(nil, ecode.RequestErr)
log.Error("app_pkg is empty")
return
}
regid := params.Get("regid")
if regid == "" {
c.JSON(nil, ecode.RequestErr)
log.Error("regid is empty")
return
}
auth := strings.TrimPrefix(c.Request.Header.Get("Authorization"), "key=")
if auth == "" {
c.JSON(nil, ecode.RequestErr)
log.Error("auth is empty")
return
}
cb := &mi.RegidCallback{
AppID: appID,
AppVer: appVer,
AppPkg: appPkg,
AppSecret: auth,
Regid: regid,
}
c.JSON(nil, pushSrv.CallbackXiaomiRegid(c, cb))
}
func oppoCallback(c *bm.Context) {
bs, err := ioutil.ReadAll(c.Request.Body)
if err != nil {
c.JSON(nil, ecode.RequestErr)
log.Error("huawei callback param(%s) error", bs)
return
}
var cb []*oppo.Callback
if err = json.Unmarshal(bs, &cb); err != nil {
c.JSON(nil, ecode.RequestErr)
log.Error("oppo callback param(%s) error(%v)", bs, err)
return
}
param := c.Request.Form
task := param.Get("task")
if task == "" {
c.JSON(nil, ecode.RequestErr)
log.Error("oppo callback task empty")
return
}
c.JSON(nil, pushSrv.CallbackOppo(c, task, cb))
}
func jpushCallback(ctx *bm.Context) {
bs, err := ioutil.ReadAll(ctx.Request.Body)
if err != nil {
log.Error("jpush batch callback param(%s) error(%v)", bs, err)
ctx.JSON(nil, ecode.RequestErr)
return
}
var cbs []*jpush.CallbackReply
if err = json.Unmarshal(bs, &cbs); err != nil {
log.Error("jpush batch callback param(%s) error(%v)", bs, err)
ctx.JSON(nil, ecode.RequestErr)
return
}
ctx.JSON(nil, pushSrv.CallbackJpush(ctx, cbs))
}
func iOSCallback(c *bm.Context) {
params := c.Request.Form
task := params.Get("task")
if task == "" {
c.JSON(nil, ecode.RequestErr)
log.Error("task is empty")
return
}
p := params.Get("mobi_app")
if p == "" {
c.JSON(nil, ecode.RequestErr)
log.Error("mobi_app is empty")
return
}
token := params.Get("tid")
if token == "" {
c.JSON(nil, ecode.RequestErr)
log.Error("tid is empty")
return
}
c.JSON(nil, pushSrv.CallbackIOS(c, task, token, mobis[p]))
}
func androidCallback(c *bm.Context) {
// Warn: 刚开始接极光时,极光没有回执功能,只能客户端来做送达回执,数据不准确
// 如今极光提供了送达回执的功能数据不能重复记录所以这里直接return
// 目前这个方法只有极光送达回执在调用(调用方是客户端),直接停用
c.JSON(nil, nil)
}
func clickCallback(c *bm.Context) {
var (
err error
pid int
platform int
params = c.Request.Form
)
task := params.Get("task")
if task == "" {
c.JSON(nil, ecode.RequestErr)
log.Error("task is empty")
return
}
app, _ := strconv.ParseInt(params.Get("app"), 10, 64)
if app <= 0 {
c.JSON(nil, ecode.RequestErr)
log.Error("app error(%s)", params.Get("app"))
return
}
mid, _ := strconv.ParseInt(params.Get("mid"), 10, 64)
p := params.Get("mobi_app")
if p == "" {
c.JSON(nil, ecode.RequestErr)
log.Error("mobi_app is empty")
return
}
pid, ok := mobis[p]
if !ok {
c.JSON(nil, ecode.RequestErr)
log.Error("mobi_app error(%s)", params.Get("mobi_app"))
return
}
sdk, _ := strconv.Atoi(params.Get("push_sdk"))
if sdk == 0 {
c.JSON(nil, ecode.RequestErr)
log.Error("push_sdk error(%s)", params.Get("push_sdk"))
return
}
switch sdk {
case pushmdl.PushSDKApns:
if pid == pushmdl.MobiIPhone {
platform = pushmdl.PlatformIPhone
} else if pid == pushmdl.MobiIPad {
platform = pushmdl.PlatformIPad
}
case pushmdl.PushSDKXiaomi:
platform = pushmdl.PlatformXiaomi
case pushmdl.PushSDKHuawei:
platform = pushmdl.PlatformHuawei
case pushmdl.PushSDKOppo:
platform = pushmdl.PlatformOppo
case pushmdl.PushSDKJpush:
platform = pushmdl.PlatformJpush
default:
c.JSON(nil, ecode.RequestErr)
log.Error("invalid push_sdk value(%d)", sdk)
return
}
token, err := url.QueryUnescape(params.Get("token"))
if err != nil || token == "" {
c.JSON(nil, ecode.RequestErr)
log.Error("token(%s) error(%v)", params.Get("token"), err)
return
}
buvid := c.Request.Header.Get("Buvid")
if buvid == "" {
if buvid, err = url.QueryUnescape(params.Get("buvid")); buvid == "" {
c.JSON(nil, ecode.RequestErr)
log.Error("buvid(%s) error(%v)", params.Get("buvid"), err)
return
}
}
cb := &pushmdl.Callback{
Task: task,
APP: app,
Platform: platform,
Mid: mid,
Pid: pid,
Token: token,
Buvid: buvid,
Click: 1,
}
c.JSON(nil, pushSrv.CallbackClick(c, cb))
}

View File

@@ -0,0 +1,61 @@
package http
import (
"net/http"
"go-common/app/interface/main/push/conf"
"go-common/app/interface/main/push/service"
"go-common/library/log"
bm "go-common/library/net/http/blademaster"
"go-common/library/net/http/blademaster/middleware/auth"
)
var (
pushSrv *service.Service
authSrv *auth.Auth
)
// Init init http.
func Init(c *conf.Config, srv *service.Service) {
pushSrv = srv
authSrv = auth.New(c.Auth)
engine := bm.DefaultServer(c.HTTPServer)
route(engine)
if err := engine.Start(); err != nil {
log.Error("engine.Start() error(%v)", err)
panic(err)
}
}
func route(e *bm.Engine) {
e.Ping(ping)
g := e.Group("/x/push", bm.CORS())
{
// for APP client
g.POST("/report", authSrv.GuestMobile, report)
g.GET("/report_old", reportOld)
g.POST("/setting/set", authSrv.UserMobile, setSetting)
g.GET("/setting/get", authSrv.UserMobile, setting)
// for test
g.POST("/test/token", testToken)
// for callback
cg := g.Group("/callback")
{
cg.POST("/huawei", huaweiCallback) // 华为送达回执
cg.POST("/xiaomi", miCallback) // 小米送达回执
cg.POST("/xiaomi/regid", miRegidCallback) // 小米token注册回执
cg.POST("/oppo", oppoCallback) // oppo送达回执
cg.POST("/jpush", jpushCallback) // 极光送达回执
cg.POST("/ios", iOSCallback) // iOS送达回执
cg.POST("/android", androidCallback) // Android送达回执
cg.POST("/click", clickCallback) // 所有平台的点击回执
}
}
}
func ping(c *bm.Context) {
if err := pushSrv.Ping(c); err != nil {
log.Error("push-interface ping error(%v)", err)
c.AbortWithStatus(http.StatusServiceUnavailable)
}
}

View File

@@ -0,0 +1,80 @@
package http
import (
"context"
"strconv"
"time"
pushmdl "go-common/app/service/main/push/model"
"go-common/library/ecode"
"go-common/library/log"
bm "go-common/library/net/http/blademaster"
xtime "go-common/library/time"
)
func testToken(c *bm.Context) {
params := c.Request.Form
appID, _ := strconv.ParseInt(params.Get("app_id"), 10, 64)
if appID < 1 {
c.JSON(nil, ecode.RequestErr)
log.Error("app_id is wrong: %s", params.Get("app_id"))
return
}
alertTitle := params.Get("alert_title")
if alertTitle == "" {
alertTitle = "哔哩哔哩消息"
}
alertBody := params.Get("alert_body")
if alertBody == "" {
c.JSON(nil, ecode.RequestErr)
log.Error("alert_body is empty")
return
}
token := params.Get("token")
if token == "" {
c.JSON(nil, ecode.RequestErr)
log.Error("token is empty")
return
}
linkType, _ := strconv.Atoi(params.Get("link_type"))
if linkType < 1 {
c.JSON(nil, ecode.RequestErr)
log.Error("link_type is wrong: %s", params.Get("link_type"))
return
}
linkValue := params.Get("link_value")
expireTime, _ := strconv.ParseInt(params.Get("expire_time"), 10, 64)
if expireTime == 0 {
expireTime = time.Now().Add(7 * 24 * time.Hour).Unix()
}
sound, vibration := pushmdl.SwitchOn, pushmdl.SwitchOn
if params.Get("sound") != "" {
if sd, _ := strconv.Atoi(params.Get("sound")); sd == pushmdl.SwitchOff {
sound = pushmdl.SwitchOff
}
}
if params.Get("vibration") != "" {
if vr, _ := strconv.Atoi(params.Get("vibration")); vr == pushmdl.SwitchOff {
vibration = pushmdl.SwitchOff
}
}
passThrough, _ := strconv.Atoi(params.Get("pass_through"))
if passThrough != pushmdl.SwitchOn {
passThrough = pushmdl.SwitchOff
}
img := params.Get("image_url")
info := &pushmdl.PushInfo{
TaskID: pushmdl.TempTaskID(),
APPID: appID,
Title: alertTitle,
Summary: alertBody,
LinkType: int8(linkType),
LinkValue: linkValue,
ExpireTime: xtime.Time(expireTime),
PassThrough: passThrough,
Sound: sound,
Vibration: vibration,
ImageURL: img,
}
c.JSON(nil, pushSrv.TestToken(context.Background(), info, token))
}

View File

@@ -0,0 +1,119 @@
package http
import (
"net/url"
"strconv"
pushmdl "go-common/app/service/main/push/model"
"go-common/library/ecode"
"go-common/library/log"
bm "go-common/library/net/http/blademaster"
)
const (
timeZoneMin = -12
timeZoneMax = 14
)
func report(c *bm.Context) {
var (
mid int64
params = c.Request.Form
)
midItf, _ := c.Get("mid")
if midItf != nil {
mid = midItf.(int64)
}
platform := params.Get("mobi_app")
if platform == "" {
c.JSON(nil, ecode.RequestErr)
log.Warn("mobi_app is empty")
return
}
buvid := params.Get("buvid")
if buvid == "" {
c.JSON(nil, ecode.RequestErr)
log.Warn("buvid is empty")
return
}
dt := params.Get("device_token")
build, _ := strconv.Atoi(params.Get("build"))
if build < 1 {
c.JSON(nil, ecode.RequestErr)
log.Warn("build is wrong: %s", params.Get("build"))
return
}
pushSDK, _ := strconv.Atoi(params.Get("push_sdk"))
platformID := pushmdl.Platform(platform, pushSDK)
if platformID == pushmdl.PlatformUnknown {
c.JSON(nil, ecode.RequestErr)
log.Warn("push_sdk is wrong: %s", params.Get("push_sdk"))
return
}
tm, _ := strconv.Atoi(params.Get("time_zone"))
if tm < timeZoneMin || tm > timeZoneMax {
c.JSON(nil, ecode.RequestErr)
log.Warn("time_zone is wrong: %s", params.Get("time_zone"))
return
}
ns, _ := strconv.Atoi(params.Get("notify_switch"))
if ns != 0 && ns != 1 {
c.JSON(nil, ecode.RequestErr)
log.Warn("notify_switch is wrong: %s", params.Get("notify_switch"))
return
}
// tp, _ := strconv.Atoi(params.Get("type"))
appID, _ := strconv.ParseInt(params.Get("app_id"), 10, 64)
if appID == 0 {
appID = pushmdl.APPIDBBPhone
}
deviceBrand, _ := url.QueryUnescape(params.Get("mobile_brand"))
deviceModel, _ := url.QueryUnescape(params.Get("mobile_model"))
osVersion, _ := url.QueryUnescape(params.Get("mobile_version"))
r := &pushmdl.Report{
APPID: appID,
PlatformID: platformID,
Mid: mid,
Buvid: buvid,
DeviceToken: dt,
Build: build,
TimeZone: tm,
NotifySwitch: ns,
DeviceBrand: deviceBrand,
DeviceModel: deviceModel,
OSVersion: osVersion,
}
if dt == "" {
log.Warn("device_token is empty(%+v)", r)
c.JSON(nil, nil) // iOS可能取不到device token
return
}
c.JSON(nil, pushSrv.PubReport(c, r))
}
func reportOld(ctx *bm.Context) {
var params = ctx.Request.Form
buvid := params.Get("buvid")
if buvid == "" {
log.Warn("buvid is empty")
ctx.JSON(nil, nil)
return
}
token := params.Get("device_token")
if token == "" {
log.Warn("device_token is empty")
ctx.JSON(nil, nil)
return
}
ma := params.Get("mobi_app")
if ma != "" && ma != "android" && ma != "iphone" && ma != "ipad" {
log.Warn("invalid mobi_app(%s)", ma)
ctx.JSON(nil, nil)
return
}
mid, _ := strconv.ParseInt(params.Get("mid"), 10, 64)
pid, _ := strconv.Atoi(params.Get("pid"))
timezone, _ := strconv.Atoi(params.Get("time_zone"))
version := params.Get("ver")
ctx.JSON(nil, pushSrv.ReportOld(ctx, token, buvid, version, mid, pid, timezone))
}

View File

@@ -0,0 +1,64 @@
package http
import (
"strconv"
pushmdl "go-common/app/service/main/push/model"
"go-common/library/ecode"
"go-common/library/log"
bm "go-common/library/net/http/blademaster"
)
var settingBizMap = map[int32]string{
pushmdl.UserSettingArchive: "archive",
pushmdl.UserSettingLive: "live",
}
func setSetting(c *bm.Context) {
var (
params = c.Request.Form
midStr, _ = c.Get("mid")
)
mid, _ := midStr.(int64)
if mid <= 0 {
log.Warn("mid(%s) is wrong", midStr)
c.JSON(nil, ecode.RequestErr)
return
}
typ, _ := strconv.Atoi(params.Get("type"))
if _, ok := pushmdl.Settings[typ]; !ok {
log.Warn("type(%s) is wrong", params.Get("type"))
c.JSON(nil, ecode.RequestErr)
return
}
val, _ := strconv.Atoi(params.Get("value"))
if val != pushmdl.SwitchOn && val != pushmdl.SwitchOff {
log.Warn("value(%s) is wrong", params.Get("value"))
c.JSON(nil, ecode.RequestErr)
return
}
c.JSON(nil, pushSrv.SetSetting(c, mid, typ, val))
}
func setting(c *bm.Context) {
midStr, _ := c.Get("mid")
mid, _ := midStr.(int64)
if mid <= 0 {
log.Warn("mid(%s) is wrong", midStr)
c.JSON(nil, ecode.RequestErr)
return
}
setting, err := pushSrv.Setting(c, mid)
if err != nil {
c.JSON(nil, err)
return
}
res := make(map[string]int32)
for t, v := range setting {
if _, ok := settingBizMap[t]; !ok {
continue
}
res[settingBizMap[t]] = v
}
c.JSON(res, nil)
}

View File

@@ -0,0 +1,27 @@
package(default_visibility = ["//visibility:public"])
load(
"@io_bazel_rules_go//go:def.bzl",
"go_library",
)
go_library(
name = "go_default_library",
srcs = ["model.go"],
importpath = "go-common/app/interface/main/push/model",
tags = ["automanaged"],
)
filegroup(
name = "package-srcs",
srcs = glob(["**"]),
tags = ["automanaged"],
visibility = ["//visibility:private"],
)
filegroup(
name = "all-srcs",
srcs = [":package-srcs"],
tags = ["automanaged"],
visibility = ["//visibility:public"],
)

View File

@@ -0,0 +1,104 @@
package model
const (
// OldPlatformIPhone old report iPhone.
OldPlatformIPhone = 1
// OldPlatformIPad old report iPad.
OldPlatformIPad = 2
// OldPlatformAndroid old report Android.
OldPlatformAndroid = 3
// OldPlatformIPadHD old report iPad HD.
OldPlatformIPadHD = 4
// OldPlatformAndroidNow old report Android Now.
OldPlatformAndroidNow = 13
)
// VersionsIPhone iPhone versions.
var VersionsIPhone = map[string]int{
"5.16": 6140,
"5.15": 6100,
"5.14.1": 6090,
"5.14": 6070,
"5.13": 6060,
"5.12.1": 6050,
"5.12": 6040,
"5.11.2": 6010,
"5.11.1": 5990,
"5.11": 5980,
"5.10": 5960,
"5.9": 5910,
"5.8": 5800,
"5.7.1": 5730,
"5.7": 5710,
"5.6": 5570,
"5.5.1": 4470,
"5.5": 4430,
"5.4": 4360,
"5.3": 4350,
"5.2": 4310,
"5.1.1": 4280,
"5.1": 4270,
"5.0.1": 4250,
"5.0": 4240,
"4.38": 4230,
"4.37": 4180,
"4.36.1": 4170,
"4.36": 4160,
"4.35.2": 4140,
"4.35.1": 4130,
"4.34": 4070,
"4.33": 4040,
"4.32": 4000,
"4.31.1": 3970,
"4.30": 3940,
"4.29": 3910,
"4.28": 3870,
"4.27": 3710,
"4.26": 3620,
"4.25": 3600,
"4.24.1": 3480,
"4.24": 3470,
"4.23.1": 3440,
"4.23": 3430,
"4.22.1": 3390,
"4.22": 3380,
"4.21.1": 3360,
"4.21": 3350,
"4.20": 3300,
"4.19": 3220,
"4.18": 3170,
"4.17.1": 3110,
"4.16": 3060,
"4.15": 3010,
"4.14.1": 2930,
"4.13.1": 2840,
"4.13": 2790,
"4.12.1": 2710,
"4.12": 2640,
"4.11": 2530,
"4.9": 2310,
}
// VersionsIPad iPad versions.
var VersionsIPad = map[string]int{
"1.50": 12040,
"1.20": 12020,
"1.19": 11900,
"1.18": 10450,
"1.17": 10430,
"1.16.1": 10420,
"1.16": 10410,
"1.15": 10400,
"1.14": 10390,
"1.13": 10370,
"1.12": 10350,
"1.11": 10340,
"1.10": 10330,
"1.9": 10320,
"1.8": 10280,
"1.7": 10270,
"1.6": 10260,
"1.5": 10180,
"1.3": 10070,
"1.0": 10030,
}

View File

@@ -0,0 +1,61 @@
package(default_visibility = ["//visibility:public"])
load(
"@io_bazel_rules_go//go:def.bzl",
"go_test",
"go_library",
)
go_test(
name = "go_default_test",
srcs = ["service_test.go"],
embed = [":go_default_library"],
rundir = ".",
tags = ["automanaged"],
deps = [
"//app/interface/main/push/conf:go_default_library",
"//app/service/main/push/model:go_default_library",
"//vendor/github.com/smartystreets/goconvey/convey:go_default_library",
],
)
go_library(
name = "go_default_library",
srcs = [
"callback.go",
"push.go",
"report.go",
"service.go",
"setting.go",
],
importpath = "go-common/app/interface/main/push/service",
tags = ["automanaged"],
deps = [
"//app/interface/main/push/conf:go_default_library",
"//app/interface/main/push/dao:go_default_library",
"//app/interface/main/push/model:go_default_library",
"//app/service/main/push/api/grpc/v1:go_default_library",
"//app/service/main/push/dao/huawei:go_default_library",
"//app/service/main/push/dao/jpush:go_default_library",
"//app/service/main/push/dao/mi:go_default_library",
"//app/service/main/push/dao/oppo:go_default_library",
"//app/service/main/push/model:go_default_library",
"//library/cache:go_default_library",
"//library/log:go_default_library",
"//library/net/http/blademaster:go_default_library",
],
)
filegroup(
name = "package-srcs",
srcs = glob(["**"]),
tags = ["automanaged"],
visibility = ["//visibility:private"],
)
filegroup(
name = "all-srcs",
srcs = [":package-srcs"],
tags = ["automanaged"],
visibility = ["//visibility:public"],
)

View File

@@ -0,0 +1,179 @@
package service
import (
"context"
"errors"
"strconv"
"strings"
"time"
"go-common/app/interface/main/push/dao"
"go-common/app/service/main/push/dao/huawei"
"go-common/app/service/main/push/dao/jpush"
"go-common/app/service/main/push/dao/mi"
"go-common/app/service/main/push/dao/oppo"
pushmdl "go-common/app/service/main/push/model"
"go-common/library/log"
)
func (s *Service) callbackproc() {
defer s.waiter.Done()
var data []*pushmdl.Callback
for {
v, ok := <-s.callbackCh
if !ok {
log.Info("callbackCh has been closed.")
if len(data) > 0 {
s.sendCallback(data)
}
return
}
data = append(data, v)
if len(data) >= s.c.Push.CallbackSize {
s.sendCallback(data)
data = []*pushmdl.Callback{}
}
}
}
func (s *Service) sendCallback(v []*pushmdl.Callback) (err error) {
for i := 0; i < 3; i++ {
if err = s.dao.PubCallback(context.TODO(), v); err == nil {
break
}
time.Sleep(20 * time.Millisecond)
}
return
}
func (s *Service) addCallbackChan(cb *pushmdl.Callback) (err error) {
if s.closed {
log.Warn("addCallbackChan, channel is closed")
return
}
select {
case s.callbackCh <- cb:
default:
err = errors.New("callbackCh full")
log.Error("callbackCh full. data(%+v)", cb)
dao.PromError("callbackCh full")
}
return
}
// CallbackXiaomiRegid xiaomi regid callback.
func (s *Service) CallbackXiaomiRegid(c context.Context, cb *mi.RegidCallback) (err error) {
// 小米token注册回调暂时没用
log.Info("s.CallbackXiaomiRegid(%+v)", cb)
return
}
// CallbackHuawei huawei callback.
func (s *Service) CallbackHuawei(c context.Context, hcb *huawei.Callback) (err error) {
for _, v := range hcb.Statuses {
log.Info("huawei callback task(%s) token(%s)", v.BiTag, v.Token)
appid, _ := strconv.ParseInt(v.AppID, 10, 64)
cb := &pushmdl.Callback{
Task: v.BiTag,
APP: appid,
Platform: pushmdl.PlatformHuawei,
Pid: pushmdl.MobiAndroid,
Token: v.Token,
Extra: &pushmdl.CallbackExtra{Status: v.Status},
}
s.addCallbackChan(cb)
}
return
}
// CallbackXiaomi xiaomi callback.
func (s *Service) CallbackXiaomi(c context.Context, m map[string]*mi.Callback) (err error) {
for _, v := range m {
log.Info("callback xiaomi task(%s)", v.Jobkey)
barStatus := mi.CallbackBarStatusEnable
if v.BarStatus == mi.CallbackBarStatusDisableStr {
barStatus = mi.CallbackBarStatusDisable
} else if v.BarStatus == mi.CallbackBarStatusUnknownStr {
barStatus = mi.CallbackBarStatusUnknown
}
sp := strings.Split(v.Targets, ",")
appid, _ := strconv.ParseInt(v.Param, 10, 64)
for _, t := range sp {
if t == "" {
continue
}
cb := &pushmdl.Callback{
Task: v.Jobkey,
APP: appid,
Platform: pushmdl.PlatformXiaomi,
Pid: pushmdl.MobiAndroid,
Token: t,
Extra: &pushmdl.CallbackExtra{Status: barStatus},
}
log.Info("xiaomi callback task(%s) token(%s)", v.Jobkey, t)
s.addCallbackChan(cb)
}
}
return
}
// CallbackOppo oppo callback.
func (s *Service) CallbackOppo(c context.Context, task string, cbs []*oppo.Callback) (err error) {
for _, v := range cbs {
for _, t := range strings.Split(v.Tokens, ",") {
log.Info("oppo callback task(%s) token(%s)", task, t)
cb := &pushmdl.Callback{
Task: task,
Platform: pushmdl.PlatformOppo,
Pid: pushmdl.MobiAndroid,
Token: t,
}
s.addCallbackChan(cb)
}
}
return
}
// CallbackJpush jpush callback batch.
func (s *Service) CallbackJpush(c context.Context, cbs []*jpush.CallbackReply) (err error) {
for _, cb := range cbs {
var (
task string
appid int64
)
if cb.Params != nil {
task = cb.Params["task"]
appid, _ = strconv.ParseInt(cb.Params["appid"], 10, 64)
}
log.Info("jpush callback task(%s) token(%s) channel(%d)", task, cb.Token, cb.Channel)
status := jpush.StatusSwitchOn
if !cb.Switch {
status = jpush.StatusSwitchOff
}
s.addCallbackChan(&pushmdl.Callback{
Task: task,
APP: appid,
Platform: pushmdl.PlatformJpush,
Pid: pushmdl.MobiAndroid,
Token: cb.Token,
Extra: &pushmdl.CallbackExtra{Status: status, Channel: cb.Channel},
})
}
return
}
// CallbackIOS ios arrived callback.
func (s *Service) CallbackIOS(c context.Context, task, token string, pid int) (err error) {
cb := &pushmdl.Callback{
Task: task,
Pid: pid,
Token: token,
}
err = s.addCallbackChan(cb)
return
}
// CallbackClick click callback.
func (s *Service) CallbackClick(c context.Context, cb *pushmdl.Callback) error {
return s.addCallbackChan(cb)
}

View File

@@ -0,0 +1,33 @@
package service
import (
"context"
"net/url"
"strconv"
pushmdl "go-common/app/service/main/push/model"
"go-common/library/log"
)
const (
_testTokenURL = "http://api.bilibili.co/x/internal/push-service/test/token"
)
// TestToken for test via push token.
func (s *Service) TestToken(ctx context.Context, info *pushmdl.PushInfo, token string) (err error) {
params := url.Values{}
params.Add("app_id", strconv.FormatInt(info.APPID, 10))
params.Add("alert_title", info.Title)
params.Add("alert_body", info.Summary)
params.Add("token", token)
params.Add("link_type", strconv.FormatInt(int64(info.LinkType), 10))
params.Add("link_value", info.LinkValue)
params.Add("sound", strconv.Itoa(info.Sound))
params.Add("vibration", strconv.Itoa(info.Vibration))
params.Add("expire_time", strconv.FormatInt(int64(info.ExpireTime), 10))
params.Add("image_url", info.ImageURL)
if err = s.httpClient.Post(ctx, _testTokenURL, "", params, nil); err != nil {
log.Error("s.TestToken(%+v) error(%v)", info, err)
}
return
}

View File

@@ -0,0 +1,113 @@
package service
import (
"context"
"fmt"
"regexp"
"strconv"
"strings"
"go-common/app/interface/main/push/model"
pushmdl "go-common/app/service/main/push/model"
"go-common/library/log"
)
// PubReport pub report.
func (s *Service) PubReport(c context.Context, r *pushmdl.Report) (err error) {
err = s.dao.PubReport(c, r)
return
}
// ReportOld report old version app
func (s *Service) ReportOld(ctx context.Context, token, buvid, version string, mid int64, pid, timezone int) (err error) {
platform := translatePlatform(pid)
build := ver2build(version, platform)
if build == 0 {
return
}
// 接新上报后的版本不再使用老的上报数据了
switch platform {
case pushmdl.PlatformXiaomi:
// version 5.16
if build >= 516000 {
return
}
case pushmdl.PlatformIPhone:
// version 5.16
if build >= 6140 {
return
}
case pushmdl.PlatformIPad:
// version 1.50
if build >= 12040 {
return
}
default:
// 未识别的平台
return
}
if platform == pushmdl.PlatformIPad && build < 10000 {
platform = pushmdl.PlatformIPhone
}
r := &pushmdl.Report{
APPID: pushmdl.APPIDBBPhone,
PlatformID: platform,
Mid: mid,
Buvid: buvid,
Build: build,
DeviceToken: token,
TimeZone: timezone,
NotifySwitch: 1,
}
err = s.dao.PubReport(ctx, r)
log.Info("pub old report(%+v)", r)
return
}
func translatePlatform(platformID int) int {
switch platformID {
case model.OldPlatformIPhone, model.OldPlatformIPad:
return pushmdl.PlatformIPhone
case model.OldPlatformAndroid, model.OldPlatformAndroidNow:
return pushmdl.PlatformXiaomi
case model.OldPlatformIPadHD:
return pushmdl.PlatformIPad
}
return pushmdl.PlatformUnknown
}
var buildRegex, _ = regexp.Compile(`\((\d+)\)`)
func ver2build(versionAndBuild string, platform int) (res int) {
version := versionAndBuild
// example: 5.12.1(6050) remove '(' suffix
i := strings.Index(version, "(")
if i != -1 {
version = version[0:i]
}
// example: 5.14.0-preview remove '-' suffix
i = strings.Index(version, "-")
if i != -1 {
version = version[0:i]
}
switch platform {
case pushmdl.PlatformIPhone:
res = model.VersionsIPhone[version]
case pushmdl.PlatformIPad:
res = model.VersionsIPad[version]
default:
p := strings.Split(version, ".")
if len(p) < 3 {
return
}
res, _ = strconv.Atoi(p[0] + p[1] + fmt.Sprintf("%03s", p[2]))
}
if res == 0 {
// match as 2_5.10(5960)
matches := buildRegex.FindSubmatch([]byte(versionAndBuild))
if len(matches) > 1 {
res, _ = strconv.Atoi(string(matches[1]))
}
}
return
}

View File

@@ -0,0 +1,59 @@
package service
import (
"context"
"sync"
"go-common/app/interface/main/push/conf"
"go-common/app/interface/main/push/dao"
pushrpc "go-common/app/service/main/push/api/grpc/v1"
pushmdl "go-common/app/service/main/push/model"
"go-common/library/cache"
httpx "go-common/library/net/http/blademaster"
)
// Service push service.
type Service struct {
c *conf.Config
dao *dao.Dao
cache *cache.Cache
pushRPC pushrpc.PushClient
callbackCh chan *pushmdl.Callback
httpClient *httpx.Client
waiter sync.WaitGroup
closed bool
}
// New creates a push service instance.
func New(c *conf.Config) *Service {
s := &Service{
c: c,
dao: dao.New(c),
cache: cache.New(1, 10240),
callbackCh: make(chan *pushmdl.Callback, c.Push.CallbackChanLen),
httpClient: httpx.NewClient(c.HTTPClient),
}
var err error
if s.pushRPC, err = pushrpc.NewClient(c.PushRPC); err != nil {
panic(err)
}
for i := 0; i < s.c.Push.CallbackGoroutines; i++ {
s.waiter.Add(1)
go s.callbackproc()
}
return s
}
// Close closes service.
func (s *Service) Close() {
s.closed = true
close(s.callbackCh)
s.waiter.Wait()
s.dao.Close()
}
// Ping checks service.
func (s *Service) Ping(c context.Context) (err error) {
err = s.dao.Ping(c)
return
}

View File

@@ -0,0 +1,92 @@
package service
import (
"context"
"flag"
"path/filepath"
"testing"
"time"
"go-common/app/interface/main/push/conf"
pushmdl "go-common/app/service/main/push/model"
. "github.com/smartystreets/goconvey/convey"
)
var (
srv *Service
)
func init() {
dir, _ := filepath.Abs("../cmd/push-interface-test.toml")
flag.Set("conf", dir)
conf.Init()
srv = New(conf.Conf)
time.Sleep(time.Second)
}
func WithService(f func(s *Service)) func() {
return func() {
f(srv)
}
}
func Test_Setting(t *testing.T) {
Convey("setting", t, WithService(func(s *Service) {
var (
c = context.Background()
mid = int64(91221505)
)
err := s.SetSetting(c, mid, pushmdl.UserSettingArchive, pushmdl.SwitchOff)
So(err, ShouldBeNil)
setting, err := s.Setting(c, mid)
So(err, ShouldBeNil)
st := make(map[int]int, len(pushmdl.Settings))
for k, v := range pushmdl.Settings {
st[k] = v
}
st[pushmdl.UserSettingArchive] = pushmdl.SwitchOff
So(setting, ShouldResemble, st)
}))
Convey("get default setting", t, WithService(func(s *Service) {
setting, err := s.Setting(context.TODO(), 8888888888888)
t.Logf("setting(%+v)", pushmdl.Settings)
So(err, ShouldBeNil)
So(setting, ShouldResemble, pushmdl.Settings)
}))
}
func Benchmark_Callback(b *testing.B) {
Convey("callback", b, WithService(func(s *Service) {
// for n := 0; n < b.N; n++ {
// s.CallbackClick(context.TODO(), &pushmdl.Callback{
// Type: pushmdl.CallbackTypeClick,
// })
// }
}))
}
func TestServicever2build(t *testing.T) {
version := "5.7.1(5730)"
res := ver2build(version, pushmdl.PlatformIPhone)
if res != 5730 {
t.FailNow()
}
version = "5.7.1"
res = ver2build(version, pushmdl.PlatformIPhone)
if res != 5730 {
t.FailNow()
}
version = "5.14.0"
res = ver2build(version, pushmdl.PlatformAndroid)
if res != 514000 {
t.FailNow()
}
version = "5.14.0-preview"
res = ver2build(version, pushmdl.PlatformAndroid)
if res != 514000 {
t.FailNow()
}
}

View File

@@ -0,0 +1,28 @@
package service
import (
"context"
pb "go-common/app/service/main/push/api/grpc/v1"
"go-common/library/log"
)
// Setting gets user notify setting.
func (s *Service) Setting(ctx context.Context, mid int64) (st map[int32]int32, err error) {
arg := &pb.SettingRequest{Mid: mid}
reply, err := s.pushRPC.Setting(ctx, arg)
if err != nil {
log.Error("s.pushRPC.Setting(%+v) error(%v)", arg, err)
return
}
return reply.Settings, nil
}
// SetSetting saves setting.
func (s *Service) SetSetting(ctx context.Context, mid int64, typ, val int) (err error) {
arg := &pb.SetSettingRequest{Mid: mid, Type: int32(typ), Value: int32(val)}
if _, err = s.pushRPC.SetSetting(ctx, arg); err != nil {
log.Error("s.pushRPC.SetSetting(%+v) error(%v)", arg, err)
}
return
}