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,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
}