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

90
app/job/main/BUILD Normal file
View File

@@ -0,0 +1,90 @@
filegroup(
name = "package-srcs",
srcs = glob(["**"]),
tags = ["automanaged"],
visibility = ["//visibility:private"],
)
filegroup(
name = "all-srcs",
srcs = [
":package-srcs",
"//app/job/main/account-recovery:all-srcs",
"//app/job/main/account-summary:all-srcs",
"//app/job/main/activity:all-srcs",
"//app/job/main/aegis:all-srcs",
"//app/job/main/answer:all-srcs",
"//app/job/main/app:all-srcs",
"//app/job/main/app-player:all-srcs",
"//app/job/main/app-wall:all-srcs",
"//app/job/main/appstatic:all-srcs",
"//app/job/main/archive:all-srcs",
"//app/job/main/archive-shjd:all-srcs",
"//app/job/main/block:all-srcs",
"//app/job/main/broadcast:all-srcs",
"//app/job/main/card:all-srcs",
"//app/job/main/click:all-srcs",
"//app/job/main/coin:all-srcs",
"//app/job/main/coupon:all-srcs",
"//app/job/main/creative:all-srcs",
"//app/job/main/credit:all-srcs",
"//app/job/main/credit-timer:all-srcs",
"//app/job/main/dm:all-srcs",
"//app/job/main/dm2:all-srcs",
"//app/job/main/favorite:all-srcs",
"//app/job/main/feed:all-srcs",
"//app/job/main/figure:all-srcs",
"//app/job/main/figure-timer:all-srcs",
"//app/job/main/growup:all-srcs",
"//app/job/main/history:all-srcs",
"//app/job/main/identify:all-srcs",
"//app/job/main/mcn:all-srcs",
"//app/job/main/member:all-srcs",
"//app/job/main/member-cache:all-srcs",
"//app/job/main/passport:all-srcs",
"//app/job/main/passport-auth:all-srcs",
"//app/job/main/passport-encrypt:all-srcs",
"//app/job/main/passport-game-cloud:all-srcs",
"//app/job/main/passport-game-data:all-srcs",
"//app/job/main/passport-game-local:all-srcs",
"//app/job/main/passport-sns/cmd:all-srcs",
"//app/job/main/passport-sns/conf:all-srcs",
"//app/job/main/passport-sns/dao:all-srcs",
"//app/job/main/passport-sns/http:all-srcs",
"//app/job/main/passport-sns/model:all-srcs",
"//app/job/main/passport-sns/service:all-srcs",
"//app/job/main/passport-user:all-srcs",
"//app/job/main/passport-user-compare:all-srcs",
"//app/job/main/playlist:all-srcs",
"//app/job/main/point:all-srcs",
"//app/job/main/push:all-srcs",
"//app/job/main/relation:all-srcs",
"//app/job/main/relation-cache:all-srcs",
"//app/job/main/reply:all-srcs",
"//app/job/main/reply-feed:all-srcs",
"//app/job/main/search:all-srcs",
"//app/job/main/sms:all-srcs",
"//app/job/main/spy:all-srcs",
"//app/job/main/stat:all-srcs",
"//app/job/main/tag:all-srcs",
"//app/job/main/thumbup/cmd:all-srcs",
"//app/job/main/thumbup/conf:all-srcs",
"//app/job/main/thumbup/dao:all-srcs",
"//app/job/main/thumbup/model:all-srcs",
"//app/job/main/thumbup/server/http:all-srcs",
"//app/job/main/thumbup/service:all-srcs",
"//app/job/main/tv:all-srcs",
"//app/job/main/ugcpay:all-srcs",
"//app/job/main/up:all-srcs",
"//app/job/main/up-rating:all-srcs",
"//app/job/main/upload:all-srcs",
"//app/job/main/usersuit:all-srcs",
"//app/job/main/videoup:all-srcs",
"//app/job/main/videoup-report:all-srcs",
"//app/job/main/vip:all-srcs",
"//app/job/main/web-goblin:all-srcs",
"//app/job/main/workflow:all-srcs",
],
tags = ["automanaged"],
visibility = ["//visibility:public"],
)

6
app/job/main/OWNERS Normal file
View File

@@ -0,0 +1,6 @@
# See the OWNERS docs at https://go.k8s.io/owners
labels:
- job
- main
- new-job-main-project

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/job/main/account-recovery/cmd:all-srcs",
"//app/job/main/account-recovery/conf:all-srcs",
"//app/job/main/account-recovery/dao:all-srcs",
"//app/job/main/account-recovery/model:all-srcs",
"//app/job/main/account-recovery/server/http:all-srcs",
"//app/job/main/account-recovery/service:all-srcs",
],
tags = ["automanaged"],
visibility = ["//visibility:public"],
)

View File

@@ -0,0 +1,7 @@
## account-recovery-job
#### v1.1.0
> 1.去除错误的日志
#### v1.0.0
1. 账号申诉找回

View File

@@ -0,0 +1,8 @@
# Owner
wanghuan01
zhoujiahui
# Author
# Reviewer
wanghuan01

View File

@@ -0,0 +1,13 @@
# See the OWNERS docs at https://go.k8s.io/owners
approvers:
- wanghuan01
- zhoujiahui
labels:
- job
- job/main/account-recovery
- main
options:
no_parent_owners: true
reviewers:
- wanghuan01

View File

@@ -0,0 +1,12 @@
# account-recovery-job
# 项目简介
1.
# 编译环境
# 依赖包
# 编译执行

View File

@@ -0,0 +1 @@
# HTTP API文档

View File

@@ -0,0 +1,42 @@
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 = ["account-recovery-job.toml"],
importpath = "go-common/app/job/main/account-recovery/cmd",
tags = ["automanaged"],
visibility = ["//visibility:public"],
deps = [
"//app/job/main/account-recovery/conf:go_default_library",
"//app/job/main/account-recovery/server/http: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,61 @@
[databus]
[databus.compareDatabus]
key = "4ba46ba31f9a44ef"
secret = "e4c5a7fce28695209e6b4f0af8cf91c5"
group = "AccountRecovery-MainAccount-S"
topic = "AccountRecovery-T"
action = "sub"
offset = "new"
buffer = 2048
name = "account-recovery-job/databus"
proto = "tcp"
addr = "172.16.33.50:6205"
idle = 1
active = 1
dialTimeout = "1s"
readTimeout = "60s"
writeTimeout = "1s"
idleTimeout = "10s"
[databus.compareDatabus.discovery]
domain = "api.bilibili.co"
key = "7634436ea852e3f4"
secret = "test"
[databus.sendMailDatabus]
key = "4ba46ba31f9a44ef"
secret = "e4c5a7fce28695209e6b4f0af8cf91c5"
group = "AccountRecovery-MainAccount-SendMail-S"
topic = "AccountRecovery-T"
action = "sub"
offset = "new"
buffer = 2048
name = "account-recovery-job/databus"
proto = "tcp"
addr = "172.16.33.50:6205"
idle = 1
active = 1
dialTimeout = "1s"
readTimeout = "60s"
writeTimeout = "1s"
idleTimeout = "10s"
[databus.sendMailDatabus.discovery]
domain = "api.bilibili.co"
key = "7634436ea852e3f4"
secret = "test"
[HttpClientConfig]
key = "7d9f6f6fe2a898e8"
secret = "4de2ccdbd9db69be0c2c6437bfe6eb69"
dial = "100ms"
timeout = "350ms"
keepAlive = "60s"
timer = 1024
[HttpClientConfig.breaker]
window = "3s"
sleep = "100ms"
bucket = 10
ratio = 1.0
request = 100
[AccRecover]
CompareURL = "http://api.bilibili.co/x/internal/account-recovery/compare"
SendMailURL = "http://api.bilibili.co/x/internal/account-recovery/sendMail"

View File

@@ -0,0 +1,40 @@
package main
import (
"flag"
"os"
"os/signal"
"syscall"
"go-common/app/job/main/account-recovery/conf"
"go-common/app/job/main/account-recovery/server/http"
"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()
log.Info("start")
trace.Init(conf.Conf.Tracer)
defer trace.Close()
http.Init(conf.Conf)
c := make(chan os.Signal, 1)
signal.Notify(c, syscall.SIGHUP, syscall.SIGQUIT, syscall.SIGTERM, syscall.SIGINT)
for {
s := <-c
log.Info("get a signal %s", s.String())
switch s {
case syscall.SIGQUIT, syscall.SIGTERM, syscall.SIGINT:
log.Info("exit")
return
case syscall.SIGHUP:
default:
return
}
}
}

View File

@@ -0,0 +1,37 @@
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/job/main/account-recovery/conf",
tags = ["automanaged"],
visibility = ["//visibility:public"],
deps = [
"//library/conf:go_default_library",
"//library/database/sql:go_default_library",
"//library/log:go_default_library",
"//library/net/http/blademaster: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,100 @@
package conf
import (
"errors"
"flag"
"go-common/library/conf"
"go-common/library/database/sql"
"go-common/library/log"
bm "go-common/library/net/http/blademaster"
"go-common/library/net/trace"
"go-common/library/queue/databus"
"github.com/BurntSushi/toml"
)
var (
confPath string
client *conf.Client
// Conf config
Conf = &Config{}
)
// Config .
type Config struct {
Log *log.Config
BM *bm.ServerConfig
Tracer *trace.Config
MySQL *sql.Config
// databus
DataBus *DataBus
// HTTPClientConfig
HTTPClientConfig *bm.ClientConfig
// AccRecover request URL info
AccRecover *AccRecover
}
// AccRecover http request
type AccRecover struct {
CompareURL string
SendMailURL string
}
// DataBus config
type DataBus struct {
CompareDatabus *databus.Config
SendMailDatabus *databus.Config
}
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
}
if err = load(); err != nil {
return
}
go func() {
for range client.Event() {
log.Info("config reload")
if load() != nil {
log.Error("config reload error (%v)", err)
}
}
}()
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,55 @@
package(default_visibility = ["//visibility:public"])
load(
"@io_bazel_rules_go//go:def.bzl",
"go_library",
"go_test",
)
go_library(
name = "go_default_library",
srcs = [
"dao.go",
"req_http.go",
],
importpath = "go-common/app/job/main/account-recovery/dao",
tags = ["automanaged"],
visibility = ["//visibility:public"],
deps = [
"//app/job/main/account-recovery/conf:go_default_library",
"//app/job/main/account-recovery/model:go_default_library",
"//library/ecode:go_default_library",
"//library/log:go_default_library",
"//library/net/http/blademaster:go_default_library",
"//library/net/metadata: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"],
)
go_test(
name = "go_default_test",
srcs = [
"dao_test.go",
"req_http_test.go",
],
embed = [":go_default_library"],
rundir = ".",
tags = ["automanaged"],
deps = [
"//app/job/main/account-recovery/conf:go_default_library",
"//vendor/github.com/smartystreets/goconvey/convey:go_default_library",
],
)

View File

@@ -0,0 +1,23 @@
package dao
import (
"go-common/app/job/main/account-recovery/conf"
bm "go-common/library/net/http/blademaster"
)
// Dao dao
type Dao struct {
c *conf.Config
// httpClient
httpClient *bm.Client
}
// New init mysql db
func New(c *conf.Config) (dao *Dao) {
dao = &Dao{
c: c,
// httpClient
httpClient: bm.NewClient(c.HTTPClientConfig),
}
return
}

View File

@@ -0,0 +1,36 @@
package dao
import (
"flag"
"os"
"testing"
"go-common/app/job/main/account-recovery/conf"
)
var (
d *Dao
)
func TestMain(m *testing.M) {
if os.Getenv("DEPLOY_ENV") != "dev" {
flag.Set("app_id", "main.account.account-recovery-job")
flag.Set("conf_token", "cf691261b587f3735c1ceec1f27f8177")
flag.Set("tree_id", "55366")
flag.Set("conf_version", "docker-1")
flag.Set("deploy_env", "uat")
flag.Set("conf_host", "config.bilibili.co")
flag.Set("conf_path", "/tmp")
flag.Set("region", "sh")
flag.Set("zone", "sh001")
} else {
flag.Set("conf", "../cmd/account-recovery-job.toml")
}
flag.Parse()
if err := conf.Init(); err != nil {
panic(err)
}
d = New(conf.Conf)
m.Run()
os.Exit(0)
}

View File

@@ -0,0 +1,47 @@
package dao
import (
"context"
"net/url"
"strconv"
"go-common/app/job/main/account-recovery/model"
"go-common/library/ecode"
"go-common/library/log"
"go-common/library/net/metadata"
)
// CompareInfo compare info
func (d *Dao) CompareInfo(c context.Context, rid int64) (err error) {
params := url.Values{}
params.Set("rid", strconv.FormatInt(rid, 10))
res := new(model.CommonResq)
if err = d.httpClient.Post(c, d.c.AccRecover.CompareURL, metadata.String(c, metadata.RemoteIP), params, &res); err != nil {
log.Error("CompareInfo HTTP request err %v", err)
return
}
if res.Code != 0 {
log.Error("CompareInfo server err_code %d", res.Code)
err = ecode.Int(int(res.Code))
return
}
return
}
// SendMail send mail
func (d *Dao) SendMail(c context.Context, rid, status int64) (err error) {
params := url.Values{}
params.Set("rid", strconv.FormatInt(rid, 10))
params.Set("status", strconv.FormatInt(status, 10))
res := new(model.CommonResq)
if err = d.httpClient.Post(c, d.c.AccRecover.SendMailURL, metadata.String(c, metadata.RemoteIP), params, &res); err != nil {
log.Error("SendMail HTTP request err %v", err)
return
}
if res.Code != 0 {
log.Error("SendMail server err_code %d", res.Code)
err = ecode.Int(int(res.Code))
return
}
return
}

View File

@@ -0,0 +1,35 @@
package dao
import (
"context"
"testing"
"github.com/smartystreets/goconvey/convey"
)
func TestDaoCompareInfo(t *testing.T) {
var (
c = context.Background()
rid = int64(1)
)
convey.Convey("CompareInfo", t, func(ctx convey.C) {
err := d.CompareInfo(c, rid)
ctx.Convey("Then err should be nil.", func(ctx convey.C) {
ctx.So(err, convey.ShouldBeNil)
})
})
}
func TestDaoSendMail(t *testing.T) {
var (
c = context.Background()
rid = int64(1)
status = int64(1)
)
convey.Convey("SendMail", t, func(ctx convey.C) {
err := d.SendMail(c, rid, status)
ctx.Convey("Then err should be nil.", func(ctx convey.C) {
ctx.So(err, convey.ShouldBeNil)
})
})
}

View File

@@ -0,0 +1,28 @@
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/job/main/account-recovery/model",
tags = ["automanaged"],
visibility = ["//visibility:public"],
)
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,26 @@
package model
import (
"encoding/json"
)
// RecoveryInfo recoveryInfo.
type RecoveryInfo struct {
Rid int64 `json:"rid" params:"rid;Required"` // 用户rid列表
Status int64 `json:"status"`
}
// Message is databus message.
type Message struct {
Action string `json:"action"`
Table string `json:"table"`
New json.RawMessage `json:"new"`
Old json.RawMessage `json:"old"`
}
// CommonResq CommonResq
type CommonResq struct {
Code int64 `json:"code"`
TS int64 `json:"ts"`
Message string `json:"message"`
}

View File

@@ -0,0 +1,34 @@
package(default_visibility = ["//visibility:public"])
load(
"@io_bazel_rules_go//go:def.bzl",
"go_library",
)
go_library(
name = "go_default_library",
srcs = ["http.go"],
importpath = "go-common/app/job/main/account-recovery/server/http",
tags = ["automanaged"],
visibility = ["//visibility:public"],
deps = [
"//app/job/main/account-recovery/conf:go_default_library",
"//app/job/main/account-recovery/service: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,39 @@
package http
import (
"go-common/app/job/main/account-recovery/conf"
"go-common/app/job/main/account-recovery/service"
"go-common/library/log"
bm "go-common/library/net/http/blademaster"
)
var (
srv *service.Service
)
// Init init
func Init(c *conf.Config) {
srv = service.New(c)
engine := bm.DefaultServer(c.BM)
router(engine)
if err := engine.Start(); err != nil {
log.Error("engine.Start error(%v)", err)
panic(err)
}
}
func router(e *bm.Engine) {
e.Ping(ping)
e.Register(register)
g := e.Group("/x/account-recovery")
{
g.GET("/test", ping)
}
}
func ping(c *bm.Context) {
}
func register(c *bm.Context) {
c.JSON(map[string]interface{}{}, nil)
}

View File

@@ -0,0 +1,35 @@
package(default_visibility = ["//visibility:public"])
load(
"@io_bazel_rules_go//go:def.bzl",
"go_library",
)
go_library(
name = "go_default_library",
srcs = ["service.go"],
importpath = "go-common/app/job/main/account-recovery/service",
tags = ["automanaged"],
visibility = ["//visibility:public"],
deps = [
"//app/job/main/account-recovery/conf:go_default_library",
"//app/job/main/account-recovery/dao:go_default_library",
"//app/job/main/account-recovery/model:go_default_library",
"//library/log:go_default_library",
"//library/queue/databus: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,159 @@
package service
import (
"context"
"encoding/json"
"strings"
"time"
"go-common/app/job/main/account-recovery/conf"
"go-common/app/job/main/account-recovery/dao"
"go-common/app/job/main/account-recovery/model"
"go-common/library/log"
"go-common/library/queue/databus"
)
const (
_recoveryLog = "account_recovery_info"
//_retry = 10
_retrySleep = time.Second * 1
)
// Service struct
type Service struct {
c *conf.Config
dao *dao.Dao
compareDatabus *databus.Databus
sendMailDatabus *databus.Databus
}
// New init
func New(c *conf.Config) (s *Service) {
s = &Service{
c: c,
dao: dao.New(c),
compareDatabus: databus.New(c.DataBus.CompareDatabus),
sendMailDatabus: databus.New(c.DataBus.SendMailDatabus),
}
go s.compareConsumeproc()
go s.sendMailConsumeproc()
return
}
func (s *Service) compareConsumeproc() {
var (
msg *databus.Message
err error
ok bool
)
for {
if msg, ok = <-s.compareDatabus.Messages(); !ok {
log.Error("s.compareDatabus.Message err(%v)", err)
return
}
log.Info("receive msg (%v)", msg.Key)
mu := &model.Message{}
if err = json.Unmarshal(msg.Value, &mu); err != nil {
log.Error("s.compareDatabus.Message err(%v)", err)
continue
}
for {
switch {
case strings.HasPrefix(mu.Table, _recoveryLog):
if mu.Action == "insert" {
log.Info("begin compare (%v)", msg.Key)
err = s.compare(context.TODO(), mu.New)
log.Info("end compare (%v)", msg.Key)
}
}
log.Info("compare switch case (%v), (%v), (%v), (%v), (%v)", strings.HasPrefix(mu.Table, _recoveryLog), mu.Action == "insert", mu.Table, msg.Key, mu.Action)
if err != nil {
log.Error("s.flush error(%v)", err)
time.Sleep(_retrySleep)
continue
}
break
}
log.Info("subproc key:%v,topic: %v, part:%v offset:%v,message %s,", msg.Key, msg.Topic, msg.Partition, msg.Offset, msg.Value)
err = msg.Commit()
if err != nil {
log.Error("commit err: %v", err)
}
}
}
func (s *Service) sendMailConsumeproc() {
var (
msg *databus.Message
err error
ok bool
)
for {
if msg, ok = <-s.sendMailDatabus.Messages(); !ok {
log.Error("s.sendMailDatabus.Message err(%v)", err)
return
}
log.Info("receive msg (%v)", msg.Key)
mu := &model.Message{}
if err = json.Unmarshal(msg.Value, &mu); err != nil {
log.Error("s.sendMailDatabus.Message err(%v)", err)
continue
}
for {
switch {
case strings.HasPrefix(mu.Table, _recoveryLog):
if mu.Action == "update" {
log.Info("begin sendMail (%v)", msg.Key)
err = s.sendMail(context.TODO(), mu.New, mu.Old)
}
}
log.Info("sendMail switch case (%v), (%v), (%v), (%v), (%v)", strings.HasPrefix(mu.Table, _recoveryLog), mu.Action == "update", mu.Table, msg.Key, mu.Action)
if err != nil {
log.Error("s.flush error(%v)", err)
time.Sleep(_retrySleep)
continue
}
break
}
log.Info("subproc key:%v,topic: %v, part:%v offset:%v,message %s,", msg.Key, msg.Topic, msg.Partition, msg.Offset, msg.Value)
err = msg.Commit()
if err != nil {
log.Error("commit err: %v", err)
}
}
}
// compare compare
func (s *Service) compare(c context.Context, msg []byte) (err error) {
r := &model.RecoveryInfo{}
if err = json.Unmarshal(msg, r); err != nil {
log.Error("s.compare err(%v)", err)
return
}
err = s.dao.CompareInfo(c, r.Rid)
return
}
// sendMail send mail
func (s *Service) sendMail(c context.Context, new []byte, old []byte) (err error) {
oldInfo := &model.RecoveryInfo{}
newInfo := &model.RecoveryInfo{}
if err = json.Unmarshal(old, oldInfo); err != nil {
log.Error("failed to oldInfo unmarshal err(%v)", err)
return
}
if err = json.Unmarshal(new, newInfo); err != nil {
log.Error("failed to newInfo unmarshal err(%v)", err)
return
}
if oldInfo.Status == 0 && (newInfo.Status == 1 || newInfo.Status == 2) {
err = s.dao.SendMail(c, newInfo.Rid, newInfo.Status)
}
return
}
// Close Service
func (s *Service) Close() {
s.compareDatabus.Close()
s.sendMailDatabus.Close()
}

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/job/main/account-summary/cmd:all-srcs",
"//app/job/main/account-summary/conf:all-srcs",
"//app/job/main/account-summary/dao:all-srcs",
"//app/job/main/account-summary/http:all-srcs",
"//app/job/main/account-summary/model:all-srcs",
"//app/job/main/account-summary/service:all-srcs",
],
tags = ["automanaged"],
visibility = ["//visibility:public"],
)

View File

@@ -0,0 +1,21 @@
# v1.3.3
1. 直接使用 API 里的数据
# v1.3.2
1. member 与 block 变更时依旧全量更新
# v1.3.1
1. 根据不同 binlog 同步不同数据
# v1.3.0
1. 添加来自 passport 的部分注册信息
# v1.2.0
1. 去除 block 依赖
2. 去除 block 导入
# v1.0.0
1. 第一次上线
# v1.0.1
1. 暂时数据更新进行全同步

View File

@@ -0,0 +1,8 @@
# Owner
zhoujiahui
# Author
zhoujiahui
# Reviewer
zhoujiahui

View File

@@ -0,0 +1,12 @@
# See the OWNERS docs at https://go.k8s.io/owners
approvers:
- zhoujiahui
labels:
- job
- job/main/account-summary
- main
options:
no_parent_owners: true
reviewers:
- zhoujiahui

View File

@@ -0,0 +1,12 @@
# account-summary
# 项目简介
1. 用户账号信息聚合 job
# 编译环境
# 依赖包
# 编译执行

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 = ["test.toml"],
importpath = "go-common/app/job/main/account-summary/cmd",
tags = ["automanaged"],
visibility = ["//visibility:public"],
deps = [
"//app/job/main/account-summary/conf:go_default_library",
"//app/job/main/account-summary/http: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,42 @@
package main
import (
"flag"
"os"
"os/signal"
"syscall"
"go-common/app/job/main/account-summary/conf"
"go-common/app/job/main/account-summary/http"
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()
log.Info("account-summary start")
trace.Init(conf.Conf.Tracer)
defer trace.Close()
ecode.Init(conf.Conf.Ecode)
http.Init(conf.Conf)
c := make(chan os.Signal, 1)
signal.Notify(c, syscall.SIGHUP, syscall.SIGQUIT, syscall.SIGTERM, syscall.SIGINT)
for {
s := <-c
log.Info("account-summary get a signal %s", s.String())
switch s {
case syscall.SIGQUIT, syscall.SIGTERM, syscall.SIGINT:
log.Info("account-summary exit")
return
case syscall.SIGHUP:
default:
return
}
}
}

View File

@@ -0,0 +1,133 @@
# This is a TOML document. Boom
[Log]
stdout=true
[MemberBinLog]
key = "4ba46ba31f9a44ef"
secret = "e4c5a7fce28695209e6b4f0af8cf91c5"
group = "MemberBinlog-MainAccount-AccountSummary-S"
topic = "MemberBinlog-T"
action = "sub"
offset = "old"
buffer = 2048
name = "account-summary/member-binlog"
proto = "tcp"
addr = "172.18.33.50:6205"
idle = 1
active = 1
dialTimeout = "1s"
readTimeout = "60s"
writeTimeout = "1s"
idleTimeout = "10s"
[BlockBinLog]
key = "4ba46ba31f9a44ef"
secret = "e4c5a7fce28695209e6b4f0af8cf91c5"
group = "BlockUserBinlog-MainAccount-S"
topic = "BlockUserBinlog-T"
action = "sub"
offset = "old"
buffer = 2048
name = "account-summary/member-binlog"
proto = "tcp"
addr = "172.18.33.50:6205"
idle = 1
active = 1
dialTimeout = "1s"
readTimeout = "60s"
writeTimeout = "1s"
idleTimeout = "10s"
[PassportBinLog]
key = "4ba46ba31f9a44ef"
secret = "e4c5a7fce28695209e6b4f0af8cf91c5"
group = "PassportPurgeCache-MainAccount-AccountSummary-S"
topic = "PassportPurgeCache-T"
action = "sub"
offset = "old"
buffer = 2048
name = "account-summary/member-binlog"
proto = "tcp"
addr = "172.18.33.50:6205"
idle = 1
active = 1
dialTimeout = "1s"
readTimeout = "60s"
writeTimeout = "1s"
idleTimeout = "10s"
[AccountSummaryProducer]
key = "4ba46ba31f9a44ef"
secret = "e4c5a7fce28695209e6b4f0af8cf91c5"
group = "AccountSummary-MainAccount-P"
topic = "AccountSummary-T"
action = "pub"
offset = "old"
buffer = 2048
name = "account-summary/account-summary-producer"
proto = "tcp"
addr = "172.18.33.50:6205"
idle = 10
active = 10
dialTimeout = "1s"
readTimeout = "60s"
writeTimeout = "1s"
idleTimeout = "10s"
[AccountSummaryHBase]
master = ""
meta = ""
dialTimeout = "1s"
readTimeout = "10s"
readsTimeout = "10s"
writeTimeout = "10s"
writesTimeout = "10s"
[AccountSummaryHBase.zookeeper]
root = ""
addrs = ["172.18.33.131:2181","172.18.33.168:2181","172.18.33.169:2181"]
timeout = "30s"
[MemberDB]
addr = "172.16.33.205"
dsn = "test:test@tcp(172.16.33.205:3308)/bilibili_member?timeout=5s&readTimeout=5s&writeTimeout=5s&parseTime=true&loc=Local&charset=utf8,utf8mb4"
active = 5
idle = 2
IdleTimeout ="4h"
queryTimeout = "100ms"
execTimeout = "100ms"
tranTimeout = "200ms"
[MemberDB.breaker]
window = "3s"
sleep = "100ms"
bucket = 10
ratio = 0.5
request = 100
[HTTPClient]
key = "c1a1cb2d89c33794"
secret = "dda47eeca111e03e6845017505baea13"
dial = "1s"
timeout = "3s"
keepAlive = "60s"
timer = 16
[HTTPClient.breaker]
window = "10s"
sleep = "100ms"
bucket = 10
ratio = 0.5
request = 100
[Host]
Passport="http://uat-passport.bilibili.co"
[AccountSummary]
SubProcessWorker=1
SyncRangeStart=0
SyncRangeEnd=300000000
SyncRangeWorker=4
[FeatureGate]
DisableSubProcess=false
SyncRange=false
Initial=true

View File

@@ -0,0 +1,40 @@
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/job/main/account-summary/conf",
tags = ["automanaged"],
visibility = ["//visibility:public"],
deps = [
"//library/conf:go_default_library",
"//library/database/hbase.v2: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/rpc: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,130 @@
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/rpc"
"go-common/library/net/trace"
"go-common/library/queue/databus"
"go-common/library/database/hbase.v2"
"github.com/BurntSushi/toml"
)
var (
confPath string
client *conf.Client
// Conf config
Conf = &Config{}
)
// Config .
type Config struct {
Log *log.Config
BM *bm.ServerConfig
Tracer *trace.Config
Ecode *ecode.Config
AccountSummaryHBase *hbase.Config
MemberBinLog *databus.Config
BlockBinLog *databus.Config
PassportBinLog *databus.Config
RelationBinLog *databus.Config
AccountSummaryProducer *databus.Config
MemberService *rpc.ClientConfig
RelationService *rpc.ClientConfig
HTTPClient *bm.ClientConfig
Host *Host
FeatureGate *FeatureGate
AccountSummary *AccountSummary
MemberDB *sql.Config
RelationDB *sql.Config
PassportDB *sql.Config
}
// AccountSummary is
type AccountSummary struct {
SubProcessWorker uint64
SyncRangeStart int64
SyncRangeEnd int64
SyncRangeWorker uint64
InitialWriteWorker uint64
}
// FeatureGate is
type FeatureGate struct {
DisableSubProcess bool
Initial bool
InitialMemberBase bool
InitialMemberExp bool
InitialMemberOfficial bool
InitialRelationStat bool
InitialBlock bool
InitialPassport bool
SyncRange bool
}
// Host is
type Host struct {
Passport string
}
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
}
if err = load(); err != nil {
return
}
go func() {
for range client.Event() {
log.Info("config reload")
if load() != nil {
log.Error("config reload error (%v)", err)
}
}
}()
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,65 @@
package(default_visibility = ["//visibility:public"])
load(
"@io_bazel_rules_go//go:def.bzl",
"go_library",
"go_test",
)
go_library(
name = "go_default_library",
srcs = [
"dao.go",
"member.go",
"passport.go",
"relation.go",
"summary.go",
],
importpath = "go-common/app/job/main/account-summary/dao",
tags = ["automanaged"],
visibility = ["//visibility:public"],
deps = [
"//app/job/main/account-summary/conf:go_default_library",
"//app/job/main/account-summary/model:go_default_library",
"//app/service/main/member/api/gorpc:go_default_library",
"//app/service/main/relation/rpc/client:go_default_library",
"//library/database/hbase.v2:go_default_library",
"//library/database/sql:go_default_library",
"//library/ecode:go_default_library",
"//library/log:go_default_library",
"//library/net/http/blademaster:go_default_library",
"//vendor/github.com/pkg/errors: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"],
)
go_test(
name = "go_default_test",
srcs = [
"dao_test.go",
"member_test.go",
"passport_test.go",
"relation_test.go",
"summary_test.go",
],
embed = [":go_default_library"],
rundir = ".",
tags = ["automanaged"],
deps = [
"//app/job/main/account-summary/conf:go_default_library",
"//vendor/github.com/smartystreets/goconvey/convey:go_default_library",
],
)

View File

@@ -0,0 +1,49 @@
package dao
import (
"context"
"go-common/app/job/main/account-summary/conf"
member "go-common/app/service/main/member/api/gorpc"
relation "go-common/app/service/main/relation/rpc/client"
"go-common/library/database/sql"
bm "go-common/library/net/http/blademaster"
"go-common/library/database/hbase.v2"
)
// Dao dao
type Dao struct {
c *conf.Config
AccountSumHBase *hbase.Client
MemberService *member.Service
RelationService *relation.Service
httpClient *bm.Client
MemberDB *sql.DB
RelationDB *sql.DB
PassportDB *sql.DB
}
// New init mysql db
func New(c *conf.Config) *Dao {
dao := &Dao{
c: c,
AccountSumHBase: hbase.NewClient(c.AccountSummaryHBase),
MemberService: member.New(c.MemberService),
RelationService: relation.New(c.RelationService),
httpClient: bm.NewClient(c.HTTPClient),
MemberDB: sql.NewMySQL(c.MemberDB),
RelationDB: sql.NewMySQL(c.RelationDB),
PassportDB: sql.NewMySQL(c.PassportDB),
}
return dao
}
// Close close the resource.
func (d *Dao) Close() {
}
// Ping dao ping
func (d *Dao) Ping(ctx context.Context) error {
return nil
}

View File

@@ -0,0 +1,33 @@
package dao
import (
"flag"
"go-common/app/job/main/account-summary/conf"
"os"
"testing"
)
var (
d *Dao
)
func TestMain(m *testing.M) {
if os.Getenv("DEPLOY_ENV") != "" {
flag.Set("app_id", "main.account.account-summary")
flag.Set("conf_token", "5761c1b876ef2941fe4b63f621b3d74a")
flag.Set("tree_id", "51697")
flag.Set("conf_version", "docker-1")
flag.Set("deploy_env", "uat")
flag.Set("conf_host", "config.bilibili.co")
flag.Set("conf_path", "/tmp")
flag.Set("region", "sh")
flag.Set("zone", "sh001")
}
flag.Parse()
if err := conf.Init(); err != nil {
panic(err)
}
d = New(conf.Conf)
m.Run()
os.Exit(0)
}

View File

@@ -0,0 +1,133 @@
package dao
// import (
// "context"
// "fmt"
// "go-common/app/job/main/account-summary/model"
// member "go-common/app/service/main/member/model"
// "go-common/library/log"
// "github.com/pkg/errors"
// )
// const (
// _AllBase = `SELECT mid,name,sex,face,sign,rank FROM user_base_%02d`
// _AllExp = `SELECT mid,exp FROM user_exp_%02d`
// _AllOfficial = `SELECT mid,role,title,description FROM user_official`
// )
// func (d *Dao) allMemberBaseFromTable(ctx context.Context, no int64) ([]*model.MemberBase, error) {
// rows, err := d.MemberDB.Query(ctx, fmt.Sprintf(_AllBase, no))
// if err != nil {
// return nil, errors.WithStack(err)
// }
// defer rows.Close()
// res := make([]*model.MemberBase, 0)
// for rows.Next() {
// mb := &member.BaseInfo{}
// if err = rows.Scan(&mb.Mid, &mb.Name, &mb.Sex, &mb.Face, &mb.Sign, &mb.Rank); err != nil {
// log.Error("Failed to scan row in query all member base: %+v", err)
// err = nil
// continue
// }
// mb.RandFaceURL()
// b := &model.MemberBase{
// EmbedMid: model.EmbedMid{Mid: mb.Mid},
// Birthday: model.Date(mb.Birthday),
// Face: mb.Face,
// Name: mb.Name,
// Rank: mb.Rank,
// Sex: mb.Sex,
// Sign: mb.Sign,
// }
// res = append(res, b)
// }
// return res, nil
// }
// func (d *Dao) allMemberExpFromTable(ctx context.Context, no int64) ([]*model.MemberExp, error) {
// rows, err := d.MemberDB.Query(ctx, fmt.Sprintf(_AllExp, no))
// if err != nil {
// return nil, err
// }
// defer rows.Close()
// res := make([]*model.MemberExp, 0)
// for rows.Next() {
// mid := int64(0)
// exp := int64(0)
// if err = rows.Scan(&mid, &exp); err != nil {
// log.Error("Failed to scan row in query all member exp: %+v", err)
// err = nil
// continue
// }
// e := &model.MemberExp{
// EmbedMid: model.EmbedMid{Mid: mid},
// Exp: exp / 100,
// }
// res = append(res, e)
// }
// return res, nil
// }
// // AllMemberBase is
// func (d *Dao) AllMemberBase(ctx context.Context) <-chan []*model.MemberBase {
// resCh := make(chan []*model.MemberBase)
// go func() {
// for i := 0; i < 100; i++ {
// res, err := d.allMemberBaseFromTable(context.Background(), int64(i))
// if err != nil {
// log.Error("Failed to get all member base from table with table id: %d: %+v", i, err)
// continue
// }
// resCh <- res
// }
// close(resCh)
// }()
// return resCh
// }
// // AllMemberExp is
// func (d *Dao) AllMemberExp(ctx context.Context) <-chan []*model.MemberExp {
// resCh := make(chan []*model.MemberExp)
// go func() {
// for i := 0; i < 100; i++ {
// res, err := d.allMemberExpFromTable(context.Background(), int64(i))
// if err != nil {
// log.Error("Failed to get all member exp from table with table id: %d: %+v", i, err)
// continue
// }
// resCh <- res
// }
// close(resCh)
// }()
// return resCh
// }
// // AllOfficial is
// func (d *Dao) AllOfficial(ctx context.Context) ([]*model.MemberOfficial, error) {
// rows, err := d.MemberDB.Query(ctx, _AllOfficial)
// if err != nil {
// return nil, err
// }
// defer rows.Close()
// res := make([]*model.MemberOfficial, 0)
// for rows.Next() {
// o := &model.MemberOfficial{}
// if err = rows.Scan(&o.Mid, &o.Role, &o.Title, &o.Description); err != nil {
// log.Error("Failed to scan row in query all member official: %+v", err)
// err = nil
// continue
// }
// res = append(res, o)
// }
// return res, nil
// }

View File

@@ -0,0 +1 @@
package dao

View File

@@ -0,0 +1,51 @@
package dao
import (
"context"
"fmt"
"net/url"
"strconv"
"go-common/app/job/main/account-summary/model"
"go-common/library/ecode"
"go-common/library/log"
)
const (
queryByMidURI = "/intranet/acc/queryByMid"
// _AsoAccountByMid = `SELECT mid,email FROM aso_account WHERE mid=?`
// _AsoAccountInfoByMid = `SELECT mid,join_ip,join_time FROM aso_account_info%d WHERE mid=?`
_AsoAccountRegOriginByMid = `SELECT mid,origintype,regtype FROM aso_account_reg_origin_%d WHERE mid=?`
// _AllCountryID = `SELECT id,code FROM aso_country_code`
)
// PassportProfile is
func (d *Dao) PassportProfile(ctx context.Context, mid int64) (*model.PassportProfile, error) {
params := url.Values{}
params.Set("mid", strconv.FormatInt(mid, 10))
var res struct {
Code int `json:"code"`
Data *model.PassportProfile `json:"data"`
}
if err := d.httpClient.Get(ctx, d.c.Host.Passport+queryByMidURI, "", params, &res); err != nil {
log.Error("Failed to query by mid: %+v: %+v", params, err)
return nil, err
}
if res.Code != 0 {
log.Error("Failed to query by mid with code: %+v: %d", params, res.Code)
return nil, ecode.Int(res.Code)
}
return res.Data, nil
}
// AsoAccountRegOrigin is
func (d *Dao) AsoAccountRegOrigin(ctx context.Context, mid int64) (*model.AsoAccountRegOrigin, error) {
row := d.PassportDB.QueryRow(ctx, fmt.Sprintf(_AsoAccountRegOriginByMid, mid%20), mid)
origin := new(model.AsoAccountRegOrigin)
if err := row.Scan(&origin.Mid, &origin.OriginType, &origin.RegType); err != nil {
return nil, err
}
return origin, nil
}

View File

@@ -0,0 +1,36 @@
package dao
import (
"context"
"testing"
"github.com/smartystreets/goconvey/convey"
)
func TestDaoPassportProfile(t *testing.T) {
var (
// ctx = context.Background()
mid = int64(0)
)
convey.Convey("PassportProfile", t, func(ctx convey.C) {
p1, err := d.PassportProfile(context.TODO(), mid)
ctx.Convey("Then err should be nil.p1 should not be nil.", func(ctx convey.C) {
ctx.So(err, convey.ShouldBeNil)
ctx.So(p1, convey.ShouldNotBeNil)
})
})
}
func TestDaoAsoAccountRegOrigin(t *testing.T) {
var (
// ctx = context.Background()
mid = int64(0)
)
convey.Convey("AsoAccountRegOrigin", t, func(ctx convey.C) {
p1, err := d.AsoAccountRegOrigin(context.TODO(), mid)
ctx.Convey("Then err should be nil.p1 should not be nil.", func(ctx convey.C) {
ctx.So(err, convey.ShouldBeNil)
ctx.So(p1, convey.ShouldNotBeNil)
})
})
}

View File

@@ -0,0 +1,51 @@
package dao
// import (
// "context"
// "fmt"
// "go-common/app/job/main/account-summary/model"
// "go-common/library/log"
// )
// var (
// _AllStat = `SELECT mid,following,whisper,black,follower FROM user_relation_stat_%02d`
// )
// func (d *Dao) allRelationStatFromTable(ctx context.Context, no int64) ([]*model.RelationStat, error) {
// rows, err := d.RelationDB.Query(ctx, fmt.Sprintf(_AllStat, no))
// if err != nil {
// return nil, err
// }
// res := make([]*model.RelationStat, 0)
// defer rows.Close()
// for rows.Next() {
// rs := &model.RelationStat{}
// if err = rows.Scan(&rs.Mid, &rs.Following, &rs.Whisper, &rs.Black, &rs.Follower); err != nil {
// log.Error("Failed to scan row in query all relation stat: %+v", err)
// err = nil
// continue
// }
// res = append(res, rs)
// }
// return res, nil
// }
// // AllRelationStat is
// func (d *Dao) AllRelationStat(ctx context.Context) <-chan []*model.RelationStat {
// resCh := make(chan []*model.RelationStat)
// go func() {
// for i := 0; i < 50; i++ {
// res, err := d.allRelationStatFromTable(ctx, int64(i))
// if err != nil {
// log.Error("Failed to get all relation stat from table with table id: %d: %+v", i, err)
// continue
// }
// resCh <- res
// }
// close(resCh)
// }()
// return resCh
// }

View File

@@ -0,0 +1 @@
package dao

View File

@@ -0,0 +1,100 @@
package dao
import (
"context"
"strconv"
"go-common/app/job/main/account-summary/model"
"github.com/pkg/errors"
)
const (
_SummaryTable = "ugc:AccountSum"
_ColFamily = "accountsum"
)
// Save is
func (d *Dao) Save(ctx context.Context, key string, data map[string][]byte) error {
values := map[string]map[string][]byte{
_ColFamily: data,
}
_, err := d.AccountSumHBase.PutStr(ctx, _SummaryTable, key, values)
return err
}
// GetByKey is
func (d *Dao) GetByKey(ctx context.Context, key string) (*model.AccountSummary, error) {
res, err := d.AccountSumHBase.GetStr(ctx, _SummaryTable, key)
if err != nil {
return nil, errors.WithStack(err)
}
sum := model.NewAccountSummary()
for _, c := range res.Cells {
v := string(c.Value)
switch string(c.Qualifier) {
case "birthday":
sum.Birthday = v
case "face":
sum.Face = v
case "mid":
sum.Mid, _ = strconv.ParseInt(v, 10, 64)
case "name":
sum.Name = v
case "rank":
sum.Rank, _ = strconv.ParseInt(v, 10, 64)
case "sex":
sum.Sex, _ = strconv.ParseInt(v, 10, 64)
case "sign":
sum.Sign = v
case "official.role":
sum.Official.Role, _ = strconv.ParseInt(v, 10, 64)
case "official.mid":
sum.Official.Mid, _ = strconv.ParseInt(v, 10, 64)
case "official.title":
sum.Official.Title = v
case "official.description":
sum.Official.Description = v
case "exp.mid":
sum.Exp.Mid, _ = strconv.ParseInt(v, 10, 64)
case "exp.exp":
sum.Exp.Exp, _ = strconv.ParseInt(v, 10, 64)
case "relation.mid":
sum.RelationStat.Mid, _ = strconv.ParseInt(v, 10, 64)
case "relation.follower":
sum.RelationStat.Follower, _ = strconv.ParseInt(v, 10, 64)
case "relation.following":
sum.RelationStat.Following, _ = strconv.ParseInt(v, 10, 64)
case "relation.black":
sum.RelationStat.Black, _ = strconv.ParseInt(v, 10, 64)
case "relation.whisper":
sum.RelationStat.Whisper, _ = strconv.ParseInt(v, 10, 64)
case "block.mid":
sum.Block.Mid, _ = strconv.ParseInt(v, 10, 64)
case "block.block_status":
sum.Block.BlockStatus, _ = strconv.ParseInt(v, 10, 64)
case "block.start_time":
sum.Block.StartTime = v
case "block.end_time":
sum.Block.EndTime = v
case "passport.mid":
sum.Passport.Mid, _ = strconv.ParseInt(v, 10, 64)
case "passport.tel_status":
sum.Passport.TelStatus, _ = strconv.ParseInt(v, 10, 64)
case "passport.country_id":
sum.Passport.CountryID, _ = strconv.ParseInt(v, 10, 64)
case "passport.join_ip":
sum.Passport.JoinIP = v
case "passport.join_time":
sum.Passport.JoinTime = v
case "passport.email_suffix":
sum.Passport.EmailSuffix = v
case "passport.origin_type":
sum.Passport.OriginType, _ = strconv.ParseInt(v, 10, 64)
case "passport.reg_type":
sum.Passport.RegType, _ = strconv.ParseInt(v, 10, 64)
}
}
return sum, nil
}

View File

@@ -0,0 +1,36 @@
package dao
import (
"context"
"testing"
"github.com/smartystreets/goconvey/convey"
)
func TestDaoSave(t *testing.T) {
var (
// ctx = context.Background()·
key = ""
data map[string][]byte
)
convey.Convey("Save", t, func(ctx convey.C) {
err := d.Save(context.TODO(), key, data)
ctx.Convey("Then err should be nil.", func(ctx convey.C) {
ctx.So(err, convey.ShouldBeNil)
})
})
}
func TestDaoGetByKey(t *testing.T) {
var (
// ctx = context.Background()
key = ""
)
convey.Convey("GetByKey", t, func(ctx convey.C) {
p1, err := d.GetByKey(context.TODO(), key)
ctx.Convey("Then err should be nil.p1 should not be nil.", func(ctx convey.C) {
ctx.So(err, convey.ShouldBeNil)
ctx.So(p1, convey.ShouldNotBeNil)
})
})
}

View File

@@ -0,0 +1,38 @@
package(default_visibility = ["//visibility:public"])
load(
"@io_bazel_rules_go//go:def.bzl",
"go_library",
)
go_library(
name = "go_default_library",
srcs = [
"http.go",
"summary.go",
],
importpath = "go-common/app/job/main/account-summary/http",
tags = ["automanaged"],
visibility = ["//visibility:public"],
deps = [
"//app/job/main/account-summary/conf:go_default_library",
"//app/job/main/account-summary/model:go_default_library",
"//app/job/main/account-summary/service: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,46 @@
package http
import (
"net/http"
"go-common/app/job/main/account-summary/conf"
"go-common/app/job/main/account-summary/service"
"go-common/library/log"
bm "go-common/library/net/http/blademaster"
)
var (
srv *service.Service
)
// Init init
func Init(c *conf.Config) {
srv = service.New(c)
engine := bm.DefaultServer(c.BM)
router(engine)
if err := engine.Start(); err != nil {
log.Error("bm.DefaultServer error(%v)", err)
panic(err)
}
}
func router(e *bm.Engine) {
e.Ping(ping)
e.Register(register)
g := e.Group("/x/internal/account-summary")
{
g.GET("/sync/one", syncOne)
g.GET("/get/one", getOne)
}
}
func ping(c *bm.Context) {
if err := srv.Ping(c); err != nil {
log.Error("account-summary-job ping error(%v)", err)
c.AbortWithStatus(http.StatusServiceUnavailable)
}
}
func register(c *bm.Context) {
c.JSON(map[string]interface{}{}, nil)
}

View File

@@ -0,0 +1,27 @@
package http
import (
"go-common/app/job/main/account-summary/model"
bm "go-common/library/net/http/blademaster"
)
func syncOne(ctx *bm.Context) {
arg := &model.ArgMid{}
if err := ctx.Bind(arg); err != nil {
return
}
if err := srv.SyncOne(ctx, arg.Mid); err != nil {
ctx.JSON(nil, err)
return
}
ctx.JSON(srv.GetOne(ctx, arg.Mid))
}
func getOne(ctx *bm.Context) {
arg := &model.ArgMid{}
if err := ctx.Bind(arg); err != nil {
return
}
ctx.JSON(srv.GetOne(ctx, arg.Mid))
}

View File

@@ -0,0 +1,34 @@
package(default_visibility = ["//visibility:public"])
load(
"@io_bazel_rules_go//go:def.bzl",
"go_library",
)
go_library(
name = "go_default_library",
srcs = [
"canal.go",
"model.go",
"param.go",
"passport.go",
],
importpath = "go-common/app/job/main/account-summary/model",
tags = ["automanaged"],
visibility = ["//visibility:public"],
deps = ["//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,18 @@
package model
import (
"encoding/json"
)
// CanalBinLog is
type CanalBinLog struct {
Action string `json:"action"`
Table string `json:"table"`
Old json.RawMessage `json:"old"`
New json.RawMessage `json:"new"`
}
// MidBinLog is
type MidBinLog struct {
Mid int64 `json:"mid"`
}

View File

@@ -0,0 +1,208 @@
package model
import (
"encoding/json"
"errors"
xtime "go-common/library/time"
"strconv"
"strings"
)
// EmbedMid is
type EmbedMid struct {
Mid int64 `json:"mid"`
}
// PassportSummary is
type PassportSummary struct {
EmbedMid
TelStatus int64 `json:"tel_status"`
CountryID int64 `json:"country_id"`
JoinIP string `json:"join_ip"`
JoinTime string `json:"join_time"`
EmailSuffix string `json:"email_suffix"`
OriginType int64 `json:"origin_type"`
RegType int64 `json:"reg_type"`
}
// RelationStat is
type RelationStat struct {
EmbedMid
Following int64 `json:"following"`
Whisper int64 `json:"whisper"`
Black int64 `json:"black"`
Follower int64 `json:"follower"`
}
// BlockSummary is
type BlockSummary struct {
EmbedMid
BlockStatus int64 `json:"block_status"`
StartTime string `json:"start_time"`
EndTime string `json:"end_time"`
}
// MemberBase is
type MemberBase struct {
EmbedMid
Birthday string `json:"birthday"`
Face string `json:"face"`
Name string `json:"name"`
Rank int64 `json:"rank"`
Sex int64 `json:"sex"`
Sign string `json:"sign"`
}
// MemberOfficial is
type MemberOfficial struct {
EmbedMid
Role int64 `json:"role"`
Title string `json:"title"`
Description string `json:"description"`
}
// MemberExp is
type MemberExp struct {
EmbedMid
Exp int64 `json:"exp"`
}
// AccountSummary is
type AccountSummary struct {
MemberBase
Exp *MemberExp `json:"exp"`
Official *MemberOfficial `json:"official"`
RelationStat *RelationStat `json:"relation_stat"`
Block *BlockSummary `json:"block"`
Passport *PassportSummary `json:"passport"`
}
// NewAccountSummary is
func NewAccountSummary() *AccountSummary {
return &AccountSummary{
Exp: &MemberExp{},
Official: &MemberOfficial{},
Passport: &PassportSummary{},
RelationStat: &RelationStat{},
Block: &BlockSummary{},
}
}
func (sum *AccountSummary) String() string {
b, _ := json.Marshal(sum)
return string(b)
}
// Key is
func (e *EmbedMid) Key() (string, error) {
if e.Mid == 0 {
return "", errors.New("Empty mid")
}
return MidKey(e.Mid), nil
}
// Marshal is
func (b *MemberBase) Marshal() (map[string][]byte, error) {
data := map[string][]byte{
"birthday": []byte(b.Birthday),
"face": []byte(b.Face),
"mid": []byte(strconv.FormatInt(b.Mid, 10)),
"name": []byte(b.Name),
"rank": []byte(strconv.FormatInt(b.Rank, 10)),
"sex": []byte(strconv.FormatInt(b.Sex, 10)),
"sign": []byte(b.Sign),
}
return data, nil
}
// Marshal is
func (o *MemberOfficial) Marshal() (map[string][]byte, error) {
data := map[string][]byte{
"official.mid": []byte(strconv.FormatInt(o.Mid, 10)),
"official.role": []byte(strconv.FormatInt(o.Role, 10)),
"official.title": []byte(o.Title),
"official.description": []byte(o.Description),
}
return data, nil
}
// Marshal is
func (e *MemberExp) Marshal() (map[string][]byte, error) {
data := map[string][]byte{
"exp.mid": []byte(strconv.FormatInt(e.Mid, 10)),
"exp.exp": []byte(strconv.FormatInt(e.Exp, 10)),
}
return data, nil
}
// reverse returns its argument string reversed rune-wise left to right.
func reverse(s string) string {
r := []rune(s)
for i, j := 0, len(r)-1; i < len(r)/2; i, j = i+1, j-1 {
r[i], r[j] = r[j], r[i]
}
return string(r)
}
func rpad(s string, c string, l int) string {
dt := l - len(s)
if dt <= 0 {
return s
}
return s + strings.Repeat(c, dt)
}
// MidKey is
func MidKey(mid int64) string {
ms := strconv.FormatInt(mid, 10)
return rpad(reverse(ms), "0", 16)
}
// Marshal is
func (r *RelationStat) Marshal() (map[string][]byte, error) {
data := map[string][]byte{
"relation.mid": []byte(strconv.FormatInt(r.Mid, 10)),
"relation.following": []byte(strconv.FormatInt(r.Following, 10)),
"relation.whisper": []byte(strconv.FormatInt(r.Whisper, 10)),
"relation.black": []byte(strconv.FormatInt(r.Black, 10)),
"relation.follower": []byte(strconv.FormatInt(r.Follower, 10)),
}
return data, nil
}
// Marshal is
func (b *BlockSummary) Marshal() (map[string][]byte, error) {
data := map[string][]byte{
"block.mid": []byte(strconv.FormatInt(b.Mid, 10)),
"block.block_status": []byte(strconv.FormatInt(b.BlockStatus, 10)),
"block.start_time": []byte(b.StartTime),
"block.end_time": []byte(b.EndTime),
}
return data, nil
}
// Marshal is
func (p *PassportSummary) Marshal() (map[string][]byte, error) {
data := map[string][]byte{
"passport.mid": []byte(strconv.FormatInt(p.Mid, 10)),
"passport.tel_status": []byte(strconv.FormatInt(p.TelStatus, 10)),
"passport.country_id": []byte(strconv.FormatInt(p.CountryID, 10)),
"passport.join_ip": []byte(p.JoinIP),
"passport.join_time": []byte(p.JoinTime),
"passport.email_suffix": []byte(p.EmailSuffix),
"passport.reg_type": []byte(strconv.FormatInt(p.RegType, 10)),
"passport.origin_type": []byte(strconv.FormatInt(p.OriginType, 10)),
}
return data, nil
}
// Date convert timestamp to date
func Date(in xtime.Time) string {
return in.Time().Format("2006-01-02")
}
// Datetime convert timestamp to date time
func Datetime(in xtime.Time) string {
return in.Time().Format("2006-01-02 15:04:05")
}

View File

@@ -0,0 +1,6 @@
package model
// ArgMid is
type ArgMid struct {
Mid int64 `form:"mid" validate:"required"`
}

View File

@@ -0,0 +1,53 @@
package model
import (
xtime "go-common/library/time"
"strings"
)
// PassportProfile is
type PassportProfile struct {
Mid int64 `json:"mid"`
UName string `json:"uname"`
UserID string `json:"user_id"`
Telphone string `json:"telphone"`
Email string `json:"email"`
NickLock int `json:"nick_lock"`
BindQQ bool `json:"bind_qq"`
BindSina bool `json:"bind_sina"`
SpaceSta int `json:"spacesta"`
LoginTime xtime.Time `json:"login_time"`
LoginIP string `json:"login_ip"`
JoinIP string `json:"join_ip"`
JoinTime xtime.Time `json:"join_time"`
SafeQuestion int `json:"safe_question"`
CountryCode int64 `json:"country_code"`
}
func bool2int(in bool) int64 {
if in {
return 1
}
return 0
}
// TelStatus is
func (p *PassportProfile) TelStatus() int64 {
return bool2int(p.Telphone != "")
}
// EmailSuffix is
func (p *PassportProfile) EmailSuffix() string {
if !strings.Contains(p.Email, "@") {
return p.Email
}
parts := strings.SplitN(p.Email, "@", 2)
return parts[1]
}
// AsoAccountRegOrigin is
type AsoAccountRegOrigin struct {
Mid int64 `json:"mid"`
OriginType int64 `json:"origin_type"`
RegType int64 `json:"reg_type"`
}

View File

@@ -0,0 +1,48 @@
package(default_visibility = ["//visibility:public"])
load(
"@io_bazel_rules_go//go:def.bzl",
"go_library",
)
go_library(
name = "go_default_library",
srcs = [
"block.go",
"initial.go",
"member.go",
"passport.go",
"relation.go",
"service.go",
"summary.go",
"sync.go",
],
importpath = "go-common/app/job/main/account-summary/service",
tags = ["automanaged"],
visibility = ["//visibility:public"],
deps = [
"//app/job/main/account-summary/conf:go_default_library",
"//app/job/main/account-summary/dao:go_default_library",
"//app/job/main/account-summary/model:go_default_library",
"//app/service/main/member/model:go_default_library",
"//app/service/main/member/model/block:go_default_library",
"//app/service/main/relation/model:go_default_library",
"//library/log:go_default_library",
"//library/queue/databus: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,47 @@
package service
import (
"context"
"encoding/json"
"go-common/app/job/main/account-summary/model"
"go-common/library/log"
)
func (s *Service) blockBinLogproc(ctx context.Context) {
for msg := range s.BlockBinLog.Messages() {
blog := &model.CanalBinLog{}
if err := json.Unmarshal(msg.Value, blog); err != nil {
log.Error("Failed to unmarshal canal bin log: %+v, value: %s: %+v", msg, string(msg.Value), err)
msg.Commit()
continue
}
log.Info("Handling message key: %s, value: %s", msg.Key, string(msg.Value))
s.blockBinLogHandle(ctx, blog)
msg.Commit()
}
}
func (s *Service) blockBinLogHandle(ctx context.Context, blog *model.CanalBinLog) {
if len(blog.New) == 0 {
log.Error("Failed to sync to hbase with empty new field: %+v", blog)
return
}
switch blog.Table {
case "block_user":
midl := &model.MidBinLog{}
if err := json.Unmarshal(blog.New, midl); err != nil {
log.Error("Failed to unmarsha new data: %s: %+v", string(blog.New), err)
return
}
// FIXME: 一段时间后改用 syncBlock
if err := s.SyncOne(ctx, midl.Mid); err != nil {
log.Error("Failed to sync block with mid: %d: %+v", midl.Mid, err)
return
}
default:
log.Warn("Unable to hanlde binlog: %+v, old: %s, new: %s", blog, string(blog.Old), string(blog.New))
}
}

View File

@@ -0,0 +1,122 @@
package service
// import (
// "context"
// "sync"
// "time"
// "go-common/library/log"
// )
// func (s *Service) initialproc(ctx context.Context) {
// dataWg := sync.WaitGroup{}
// workerWg := sync.WaitGroup{}
// jobQueue := make(chan func(), 4096)
// initialWorker := func() {
// worker := uint64(50)
// if s.c.AccountSummary.InitialWriteWorker > 0 {
// worker = s.c.AccountSummary.InitialWriteWorker
// }
// log.Info("Start %d initial write worker", worker)
// for i := uint64(0); i < worker; i++ {
// workerWg.Add(1)
// go func() {
// defer workerWg.Done()
// for job := range jobQueue {
// job()
// }
// }()
// }
// }
// initialWorker()
// initBase := func() {
// log.Info("Start to initial member base")
// defer dataWg.Done()
// baseCh := s.dao.AllMemberBase(ctx)
// for chunk := range baseCh {
// for _, b := range chunk {
// b := b
// jobQueue <- func() {
// if err := s.SyncToHBase(ctx, b); err != nil {
// log.Error("Failed to sync member base in initial process: base: %+v: %+v", b, err)
// }
// }
// }
// }
// }
// initExp := func() {
// log.Info("Start to initial member exp")
// defer dataWg.Done()
// expCh := s.dao.AllMemberExp(ctx)
// for chunk := range expCh {
// for _, e := range chunk {
// e := e
// jobQueue <- func() {
// if err := s.SyncToHBase(ctx, e); err != nil {
// log.Error("Failed to sync member exp in initial process: exp: %+v: %+v", e, err)
// }
// }
// }
// time.Sleep(time.Second)
// }
// }
// initOfficial := func() {
// log.Info("Start to initial member official")
// defer dataWg.Done()
// official, err := s.dao.AllOfficial(ctx)
// if err != nil {
// log.Error("Failed to get all member official: %+v", err)
// return
// }
// for _, o := range official {
// o := o
// jobQueue <- func() {
// if err := s.SyncToHBase(ctx, o); err != nil {
// log.Error("Failed to sync member official in initial process: official: %+v: %+v", o, err)
// }
// }
// }
// }
// initStat := func() {
// log.Info("Start to initial relation stat")
// defer dataWg.Done()
// statsCh := s.dao.AllRelationStat(ctx)
// for chunk := range statsCh {
// for _, stat := range chunk {
// stat := stat
// jobQueue <- func() {
// if err := s.SyncToHBase(ctx, stat); err != nil {
// log.Error("Failed to sync relation stat in initial process: stat: %+v: %+v", stat, err)
// }
// }
// }
// time.Sleep(time.Second)
// }
// }
// if s.c.FeatureGate.InitialMemberBase {
// dataWg.Add(1)
// go initBase()
// }
// if s.c.FeatureGate.InitialMemberExp {
// dataWg.Add(1)
// go initExp()
// }
// if s.c.FeatureGate.InitialMemberOfficial {
// dataWg.Add(1)
// go initOfficial()
// }
// if s.c.FeatureGate.InitialRelationStat {
// dataWg.Add(1)
// go initStat()
// }
// dataWg.Wait()
// close(jobQueue) // all job is enqueued
// workerWg.Wait()
// }

View File

@@ -0,0 +1,48 @@
package service
import (
"context"
"encoding/json"
"strings"
"go-common/app/job/main/account-summary/model"
"go-common/library/log"
)
func (s *Service) memberBinLogproc(ctx context.Context) {
for msg := range s.MemberBinLog.Messages() {
blog := &model.CanalBinLog{}
if err := json.Unmarshal(msg.Value, blog); err != nil {
log.Error("Failed to unmarshal canal bin log: %+v, value: %s: %+v", msg, string(msg.Value), err)
msg.Commit()
continue
}
log.Info("Handling message key: %s, value: %s", msg.Key, string(msg.Value))
s.memberBinLogHandle(ctx, blog)
msg.Commit()
}
}
func (s *Service) memberBinLogHandle(ctx context.Context, blog *model.CanalBinLog) {
if len(blog.New) == 0 {
log.Error("Failed to sync to hbase with empty new field: %+v", blog)
return
}
switch {
case strings.HasPrefix(blog.Table, "user_base_") || strings.HasPrefix(blog.Table, "user_official") || strings.HasPrefix(blog.Table, "user_exp_"):
midl := &model.MidBinLog{}
if err := json.Unmarshal(blog.New, midl); err != nil {
log.Error("Failed to unmarsha new data: %s: %+v", string(blog.New), err)
return
}
// FIXME: 一段时间后该用 syncMember
if err := s.SyncOne(ctx, midl.Mid); err != nil {
log.Error("Failed to sync member with mid: %d: %+v", midl.Mid, err)
return
}
default:
log.Warn("Unable to hanlde binlog: %+v, old: %s, new: %s", blog, string(blog.Old), string(blog.New))
}
}

View File

@@ -0,0 +1,47 @@
package service
import (
"context"
"encoding/json"
"strings"
"go-common/app/job/main/account-summary/model"
"go-common/library/log"
)
func (s *Service) passportBinLogproc(ctx context.Context) {
for msg := range s.PassportBinLog.Messages() {
blog := &model.CanalBinLog{}
if err := json.Unmarshal(msg.Value, blog); err != nil {
log.Error("Failed to unmarshal canal bin log: %+v, value: %s: %+v", msg, string(msg.Value), err)
msg.Commit()
continue
}
log.Info("Handling message key: %s, value: %s", msg.Key, string(msg.Value))
s.passportBinLogHandle(ctx, blog)
msg.Commit()
}
}
func (s *Service) passportBinLogHandle(ctx context.Context, blog *model.CanalBinLog) {
if len(blog.New) == 0 {
log.Error("Failed to sync to hbase with empty new field: %+v", blog)
return
}
switch {
case strings.HasPrefix(blog.Table, "aso_account"):
midl := &model.MidBinLog{}
if err := json.Unmarshal(blog.New, midl); err != nil {
log.Error("Failed to unmarsha new data: %s: %+v", string(blog.New), err)
return
}
if err := s.syncPassportSummary(ctx, midl.Mid); err != nil {
log.Error("Failed to sync passport summary with mid: %d: %+v", midl.Mid, err)
return
}
default:
log.Warn("Unable to hanlde binlog: %+v, old: %s, new: %s", blog, string(blog.Old), string(blog.New))
}
}

View File

@@ -0,0 +1,47 @@
package service
import (
"context"
"encoding/json"
"strings"
"go-common/app/job/main/account-summary/model"
"go-common/library/log"
)
func (s *Service) relationBinLogproc(ctx context.Context) {
for msg := range s.RelationBinLog.Messages() {
blog := &model.CanalBinLog{}
if err := json.Unmarshal(msg.Value, blog); err != nil {
log.Error("Failed to unmarshal canal bin log: %+v, value: %s: %+v", msg, string(msg.Value), err)
msg.Commit()
continue
}
log.Info("Handling message key: %s, value: %s", msg.Key, string(msg.Value))
s.relationBinLogHandle(ctx, blog)
msg.Commit()
}
}
func (s *Service) relationBinLogHandle(ctx context.Context, blog *model.CanalBinLog) {
if len(blog.New) == 0 {
log.Error("Failed to sync to hbase with empty new field: %+v", blog)
return
}
switch {
case strings.HasPrefix(blog.Table, "user_relation_stat_"):
midl := &model.MidBinLog{}
if err := json.Unmarshal(blog.New, midl); err != nil {
log.Error("Failed to unmarsha new data: %s: %+v", string(blog.New), err)
return
}
if err := s.syncRelationStat(ctx, midl.Mid); err != nil {
log.Error("Failed to sync relation stat with mid: %d: %+v", midl.Mid, err)
return
}
default:
log.Warn("Unable to hanlde binlog: %+v, old: %s, new: %s", blog, string(blog.Old), string(blog.New))
}
}

View File

@@ -0,0 +1,96 @@
package service
import (
"context"
"go-common/app/job/main/account-summary/conf"
"go-common/app/job/main/account-summary/dao"
"go-common/library/log"
"go-common/library/queue/databus"
)
// Service struct
type Service struct {
c *conf.Config
dao *dao.Dao
MemberBinLog *databus.Databus
BlockBinLog *databus.Databus
PassportBinLog *databus.Databus
RelationBinLog *databus.Databus
AccountSummaryProducer *databus.Databus
}
// New init
func New(c *conf.Config) *Service {
s := &Service{
c: c,
dao: dao.New(c),
RelationBinLog: databus.New(c.RelationBinLog),
MemberBinLog: databus.New(c.MemberBinLog),
BlockBinLog: databus.New(c.BlockBinLog),
PassportBinLog: databus.New(c.PassportBinLog),
AccountSummaryProducer: databus.New(c.AccountSummaryProducer),
}
s.Main()
return s
}
// Ping Service
func (s *Service) Ping(c context.Context) error {
return s.dao.Ping(c)
}
// Close Service
func (s *Service) Close() {
s.dao.Close()
}
// Main is
func (s *Service) Main() {
subproc := func() {
worker := s.c.AccountSummary.SubProcessWorker
if worker <= 0 {
worker = 1
}
log.Info("Starting sub process with %d workers", worker)
for i := uint64(0); i < worker; i++ {
go s.memberBinLogproc(context.Background())
go s.blockBinLogproc(context.Background())
go s.passportBinLogproc(context.Background())
go s.relationBinLogproc(context.Background())
}
}
syncrange := func() {
start := s.c.AccountSummary.SyncRangeStart
if start <= 0 {
start = 1
}
end := s.c.AccountSummary.SyncRangeEnd
if end <= 0 {
end = 1
}
worker := s.c.AccountSummary.SyncRangeWorker
if worker <= 0 {
worker = 1
}
go s.syncRangeproc(context.Background(), start, end, worker)
}
// initial := func() {
// go s.initialproc(context.Background())
// }
if !s.c.FeatureGate.DisableSubProcess {
subproc()
}
if s.c.FeatureGate.SyncRange {
syncrange()
}
// if s.c.FeatureGate.Initial {
// initial()
// }
}

View File

@@ -0,0 +1,65 @@
package service
import (
"context"
"go-common/app/job/main/account-summary/model"
"go-common/library/log"
)
// Syncable is
type Syncable interface {
Key() (string, error)
Marshal() (map[string][]byte, error)
}
// SyncToHBase is
func (s *Service) SyncToHBase(ctx context.Context, body Syncable) error {
key, err := body.Key()
if err != nil {
log.Error("Failed to struct key with body: %+v: %+v", body, err)
return err
}
data, err := body.Marshal()
if err != nil {
log.Error("Failed to sync to hbase with key: %s, body: %+v: %+v", key, body, err)
return err
}
defer s.logging(ctx, key)
return s.dao.Save(ctx, key, data)
}
func (s *Service) logging(ctx context.Context, key string) {
sum, _ := s.dao.GetByKey(ctx, key)
log.Info("Sync to hbase result: key: %s, summary: %+v", key, sum)
}
// SyncOne is
func (s *Service) SyncOne(ctx context.Context, mid int64) error {
// member
if err := s.syncMember(ctx, mid); err != nil {
log.Error("Failed to sync member with mid: %d: %+v", mid, err)
}
// relation
if err := s.syncRelationStat(ctx, mid); err != nil {
log.Error("Failed to sync relation stat with mid: %d: %+v", mid, err)
}
// block
if err := s.syncBlock(ctx, mid); err != nil {
log.Error("Failed to sync block with mid: %d: %+v", mid, err)
}
// passport
if err := s.syncPassportSummary(ctx, mid); err != nil {
log.Error("Failed to sync passport summary with mid: %d: %+v", mid, err)
}
return nil
}
// GetOne is
func (s *Service) GetOne(ctx context.Context, mid int64) (*model.AccountSummary, error) {
return s.dao.GetByKey(ctx, model.MidKey(mid))
}

View File

@@ -0,0 +1,208 @@
package service
import (
"context"
"sync"
"go-common/app/job/main/account-summary/model"
member "go-common/app/service/main/member/model"
"go-common/app/service/main/member/model/block"
relation "go-common/app/service/main/relation/model"
"go-common/library/log"
xtime "go-common/library/time"
)
func (s *Service) block(ctx context.Context, mid int64) (*model.BlockSummary, error) {
bl, err := s.dao.MemberService.BlockInfo(ctx, &block.RPCArgInfo{MID: mid})
if err != nil {
return nil, err
}
blSummary := &model.BlockSummary{
EmbedMid: model.EmbedMid{Mid: bl.MID},
BlockStatus: int64(bl.BlockStatus),
StartTime: model.Datetime(xtime.Time(bl.StartTime)),
EndTime: model.Datetime(xtime.Time(bl.EndTime)),
}
return blSummary, nil
}
func (s *Service) relationStat(ctx context.Context, mid int64) (*model.RelationStat, error) {
stat, err := s.dao.RelationService.Stat(ctx, &relation.ArgMid{Mid: mid})
if err != nil {
return nil, err
}
reStat := &model.RelationStat{
EmbedMid: model.EmbedMid{Mid: stat.Mid},
Follower: stat.Follower,
Following: stat.Following,
Whisper: stat.Whisper,
Black: stat.Black,
}
return reStat, nil
}
func (s *Service) passportSummary(ctx context.Context, mid int64) (*model.PassportSummary, error) {
ps := &model.PassportSummary{
EmbedMid: model.EmbedMid{Mid: mid},
}
wg := &sync.WaitGroup{}
wg.Add(1)
go func() error {
defer wg.Done()
pp, err := s.dao.PassportProfile(ctx, mid)
if err != nil {
log.Error("Failed to fetch passport profile: %+v", err)
return err
}
ps.TelStatus = pp.TelStatus()
ps.CountryID = pp.CountryCode
ps.JoinIP = pp.JoinIP
ps.JoinTime = model.Datetime(pp.JoinTime)
ps.EmailSuffix = pp.EmailSuffix()
return nil
}()
wg.Add(1)
go func() error {
defer wg.Done()
origin, err := s.dao.AsoAccountRegOrigin(ctx, mid)
if err != nil {
log.Error("Failed to fetch passport aso account reg origin: %+v", err)
return err
}
ps.RegType = origin.RegType
ps.OriginType = origin.OriginType
return nil
}()
wg.Wait()
return ps, nil
}
func (s *Service) member(ctx context.Context, mid int64) (*model.MemberBase, *model.MemberExp, *model.MemberOfficial, error) {
mb, err := s.dao.MemberService.Member(ctx, &member.ArgMemberMid{Mid: mid})
if err != nil {
return nil, nil, nil, err
}
var base *model.MemberBase
if mb.BaseInfo != nil {
base = &model.MemberBase{
EmbedMid: model.EmbedMid{Mid: mb.Mid},
Name: mb.Name,
Face: mb.Face,
Rank: int64(mb.Rank),
Sex: mb.Sex,
Sign: mb.Sign,
Birthday: model.Date(mb.Birthday),
}
}
var exp *model.MemberExp
if mb.LevelInfo != nil {
exp = &model.MemberExp{
EmbedMid: model.EmbedMid{Mid: mb.Mid},
Exp: int64(mb.NowExp),
}
}
var of *model.MemberOfficial
if mb.OfficialInfo != nil {
of = &model.MemberOfficial{
EmbedMid: model.EmbedMid{Mid: mb.Mid},
Role: int64(mb.Role),
Title: mb.Title,
Description: mb.Desc,
}
}
return base, exp, of, nil
}
func (s *Service) syncMember(ctx context.Context, mid int64) error {
base, exp, of, err := s.member(ctx, mid)
if err != nil {
return err
}
syncable := make([]Syncable, 0, 3)
if base != nil {
syncable = append(syncable, base)
}
if exp != nil {
syncable = append(syncable, exp)
}
if of != nil {
syncable = append(syncable, of)
}
for _, data := range syncable {
if err := s.SyncToHBase(ctx, data); err != nil {
return err
}
}
return nil
}
func (s *Service) syncRelationStat(ctx context.Context, mid int64) error {
reStat, err := s.relationStat(ctx, mid)
if err != nil {
return err
}
if err := s.SyncToHBase(ctx, reStat); err != nil {
return err
}
return nil
}
func (s *Service) syncBlock(ctx context.Context, mid int64) error {
blSummary, err := s.block(ctx, mid)
if err != nil {
return err
}
if err := s.SyncToHBase(ctx, blSummary); err != nil {
return err
}
return nil
}
func (s *Service) syncPassportSummary(ctx context.Context, mid int64) error {
ps, err := s.passportSummary(ctx, mid)
if err != nil {
return err
}
if err := s.SyncToHBase(ctx, ps); err != nil {
return err
}
return nil
}
func (s *Service) syncRangeproc(ctx context.Context, start, end int64, worker uint64) {
log.Info("Sync with range: start: %d, end %d, worker: %d", start, end, worker)
syncChan := make(chan int64, worker*128)
defer close(syncChan)
// initial
wg := sync.WaitGroup{}
wg.Add(1)
for i := uint64(0); i < worker; i++ {
go func() {
defer wg.Done()
for mid := range syncChan {
if err := s.SyncOne(context.Background(), mid); err != nil {
log.Error("Failed to sync user with mid: %d: %+v", mid, err)
}
}
}()
}
for j := start; j <= end; j++ {
syncChan <- j
}
wg.Wait()
}

View File

@@ -0,0 +1,28 @@
filegroup(
name = "package-srcs",
srcs = glob(["**"]),
tags = ["automanaged"],
visibility = ["//visibility:private"],
)
filegroup(
name = "all-srcs",
srcs = [
":package-srcs",
"//app/job/main/activity/cmd:all-srcs",
"//app/job/main/activity/conf:all-srcs",
"//app/job/main/activity/dao/bnj:all-srcs",
"//app/job/main/activity/dao/dm:all-srcs",
"//app/job/main/activity/dao/kfc:all-srcs",
"//app/job/main/activity/dao/like:all-srcs",
"//app/job/main/activity/http:all-srcs",
"//app/job/main/activity/model/bnj:all-srcs",
"//app/job/main/activity/model/dm:all-srcs",
"//app/job/main/activity/model/kfc:all-srcs",
"//app/job/main/activity/model/like:all-srcs",
"//app/job/main/activity/model/match:all-srcs",
"//app/job/main/activity/service:all-srcs",
],
tags = ["automanaged"],
visibility = ["//visibility:public"],
)

View File

@@ -0,0 +1,133 @@
# activity-job
##### Version 1.8.4
##### Features
> 1.bnj preview add new msg.
##### Version 1.8.3
##### Features
> 1.eleme cancel.
##### Version 1.8.2
##### Features
> 1.bnj preview game cancel.
##### Version 1.8.1
##### Features
> 1.bnj preview wechat fix.
##### Version 1.8.0
##### Features
> 1.bnj preview wechat message
##### Version 1.7.2
##### Features
> 1.kfc发券多goroutine处理
##### Version 1.7.1
##### Features
> 1.bnj no sub fix.
##### Version 1.7.0
##### Features
> 1.bnj preview.
##### Version 1.6.5
##### Features
> 1.kfc发券脚本
##### Version 1.6.4
##### Features
> 1.eleme抽奖接入databus
##### Version 1.6.3
##### Bug fix
> 1.waiter add fix.
##### Version 1.6.2
##### Features
> 1.like_action点赞总数入库
##### Version 1.6.1
##### Features
> 1.独立故事王计数更新时间
##### Version 1.6.0
##### Features
> 1.计算故事王总计数
##### Version 1.5.3
##### Features
> 1.databus接入日志增加表名
##### Version 1.5.2
##### Features
> 1.同步like_content,增加日志
##### Version 1.5.1
##### Features
> 1.故事王活动同步like_content表信息
##### Version 1.5.0
##### Features
> 1.新增获取拍摄活动稿件播放量排行榜.
##### Version 1.4.5
##### Features
> 1.新增获取活动总计数逻辑.
##### Version 1.4.4
##### Features
> 1.增加act_subject和likes表同步脚本.
##### Version 1.4.3
##### Features
> 1.fix context.
##### Version 1.4.2
##### Features
> 1.修改配置文件
##### Version 1.4.1
##### Features
> 1.sleep 时间迁移到配置文件.
##### Version 1.4.0
##### Features
> 1.新增手动方法触发比赛结算.
##### Version 1.3.3
##### Bug
> 1.fix result and stake.
##### Version 1.3.2
##### Bug
> 1.新增日志
##### Version 1.3.1
##### Bug
> 1.databus 关闭
##### Version 1.3.0
##### Features
> 1.世界杯硬币竞猜结算
##### Version 1.2.2
##### Bug
> 1.fix MonitorPing bug
##### Version 1.2.1
##### Features
> 1.加MonitorPing
##### Version 1.2.0
##### Features
> 1.迁移main目录
##### Version 1.1.0
##### Features
> 1.合并进大仓库
##### Version 1.0.0
##### Features
> 1.直播活动相关job

View File

@@ -0,0 +1,8 @@
# Owner
liweijia
# Author
all
# Reviewer
all

View File

@@ -0,0 +1,10 @@
# See the OWNERS docs at https://go.k8s.io/owners
approvers:
- liweijia
labels:
- job
- job/main/activity
- main
options:
no_parent_owners: true

View File

View File

@@ -0,0 +1,42 @@
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 = ["activity-job-test.toml"],
importpath = "go-common/app/job/main/activity/cmd",
tags = ["automanaged"],
visibility = ["//visibility:public"],
deps = [
"//app/job/main/activity/conf:go_default_library",
"//app/job/main/activity/http:go_default_library",
"//app/job/main/activity/service:go_default_library",
"//library/log: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,173 @@
version = "1.0.0"
user = "nobody"
pid = "/tmp/activity-job.pid"
dir = "./"
perf = "0.0.0.0:7750"
trace = false
debug = false
env = "test"
[interval]
coinInterval = "30ms"
queryInterval = "100ms"
objStatInterval = "5m"
viewRankInterval = "5m"
kingStoryInterval = "5m"
[log]
dir = "/data/log/activity-job/"
[app]
key = "BjeiOXmiL363sAt8"
secret = "0J18o2qCeuWzo6ScBpm4QZJO8Ij5kcvz"
[HTTPServer]
addrs = ["0.0.0.0:7751"]
readTimeout = "1s"
writeTimeout = "1s"
maxListen = 10
[HttpClient]
key = "7c7ac0db1aa05587"
secret = "9a6d62d93290c5f771ad381e9ca23f26"
dial = "500ms"
timeout = "2s"
keepAlive = "60s"
timer = 1000
[httpClient.breaker]
window ="10s"
sleep ="10ms"
bucket = 10
ratio = 0.1
request = 10
[mysql]
[mysql.like]
addr = "172.16.33.205:3308"
dsn = "test:test@tcp(172.16.33.205:3308)/bilibili_lottery?timeout=5s&readTimeout=5s&writeTimeout=5s&parseTime=true&loc=Local&charset=utf8,utf8mb4"
active = 5
idle = 2
idleTimeout ="4h"
queryTimeout = "100ms"
execTimeout = "100ms"
tranTimeout = "200ms"
[mysql.like.breaker]
window ="3s"
sleep ="100ms"
bucket = 10
ratio = 0.5
request = 100
[memcache]
accessExpire = "10s"
likeExpire = "3s"
[memcache.like]
name = "activity/test"
proto = "tcp"
addr = "172.18.33.61:11220"
idle = 5
active = 10
dialTimeout = "1s"
readTimeout = "1s"
writeTimeout = "1s"
idleTimeout = "80s"
[redis]
name = "activity-job"
proto = "tcp"
addr = "172.16.33.104:6379"
idle = 100
active = 100
dialTimeout = "1s"
readTimeout = "1s"
writeTimeout = "1s"
idleTimeout = "10s"
expire = "10s"
[host]
apiCo = "http://api.bilibili.co"
activity = "http://uat-www.bilibili.com"
[rule]
broadcastSid = 0
[actSub]
key = "9765cdac5894f2ba"
secret = "f4237d712c3ed1e7fab0137b81418b14"
group = "Lottery-MainWebSvr-S"
topic = "Lottery-T"
action = "sub"
[bnjSub]
key = "9765cdac5894f2ba"
secret = "f4237d712c3ed1e7fab0137b81418b14"
group = "ActBnjPreview-MainWebSvr-S"
topic = "ActBnjPreview-T"
action = "sub"
[bnj2019]
lid = 1
startTime = "2018-12-11T15:04:05+08:00"
timelinePic = ""
msgSpec = "1 42,43 15 * * *"
midLimit = 1000
wxTitle = "【拜年祭必看!】拜年祭预约人数到达预警"
wxUser = "zhangshuyi,huangyukun,xuwenqi01,wuhao02,liweijia"
[[bnj2019.time]]
second = 60
score = 95
step = 4
wxMsg = ""
msg = "拜年祭预约人数即将到达200w请及时准备拜年祭抽奖事项。"
[[bnj2019.time]]
second = 120
score = 90
step = 3
wxMsg = ""
msg = "拜年祭预约人数即将到达150w请及时准备拜年祭抽奖事项。"
[[bnj2019.message]]
start = "2018-12-24T15:40:00+08:00"
title = "【bilibili2019拜年祭档案揭秘】001"
content = "飞雪连天射白鹿笑书神侠倚碧鸳。当V家碰到金庸会碰撞出怎样的火花来拜年祭后台看看吧~"
mc = "1_21_1"
[[bnj2019.message]]
start = "2018-12-24T15:43:00+08:00"
title = "【bilibili2019拜年祭档案揭秘】002"
content = "前有某任乱斗今有b站混战。小电视妈妈快看神仙打架链接"
mc = "1_21_2"
[[bnj2019.message]]
start = "2019-01-31T00:00:00+08:00"
title = "【bilibili2019拜年祭档案揭秘】003"
content = "站内最强甜美系女歌手,真情翻唱哥哥凄美情歌。请跟随小电视到她的休息室看看吧~链接"
mc = "1_21_3"
[[bnj2019.message]]
start = "2019-02-01T00:00:00+08:00"
title = "【bilibili2019拜年祭档案揭秘】004"
content = "什么?我喜欢的动画小哥哥和小姐姐们要来上海一日游?!快来和小电视一起研究哪些地方偶遇他们吧!链接"
mc = "1_21_4"
[[bnj2019.message]]
start = "2019-02-02T00:00:00+08:00"
title = "【bilibili2019拜年祭档案揭秘】005"
content = "妹子眼里的钢铁直男?不,是冷冷的狗粮在脸上胡乱地拍。来,今日份的狗粮。链接"
mc = "1_21_5"
[[bnj2019.message]]
start = "2019-02-03T00:00:00+08:00"
title = "【bilibili2019拜年祭档案揭秘】006"
content = "真相只有一个喵!点击开始解谜。链接"
mc = "1_21_6"
[vipSub]
key = "9765cdac5894f2ba"
secret = "f4237d712c3ed1e7fab0137b81418b14"
group = "VipBinlog-MainWebSvr-S"
topic = "VipBinlog-T"
action = "sub"
[kfcSub]
key = "9765cdac5894f2ba"
secret = "f4237d712c3ed1e7fab0137b81418b14"
group = "KfcCouponAward-MainWebSvr-S"
topic = "KfcCouponAward-T"
action = "sub"

View File

@@ -0,0 +1,57 @@
package main
import (
"flag"
"os"
"os/signal"
"syscall"
"time"
"go-common/app/job/main/activity/conf"
"go-common/app/job/main/activity/http"
"go-common/app/job/main/activity/service"
"go-common/library/log"
)
var (
srv *service.Service
)
func main() {
flag.Parse()
if err := conf.Init(); err != nil {
log.Error("conf.Init() error(%v)", err)
log.Info("conf.Init() error(%v)", err)
panic(err)
}
// init log
log.Init(conf.Conf.Log)
defer log.Close()
log.Info("activity-job start")
srv = service.New(conf.Conf)
http.Init(conf.Conf, srv)
signalHandler()
}
func signalHandler() {
var (
err error
ch = make(chan os.Signal, 1)
)
signal.Notify(ch, syscall.SIGHUP, syscall.SIGQUIT, syscall.SIGTERM, syscall.SIGINT)
for {
si := <-ch
switch si {
case syscall.SIGQUIT, syscall.SIGTERM, syscall.SIGINT:
log.Info("get a signal %s, stop the consume process", si.String())
if err = srv.Close(); err != nil {
log.Error("srv close consumer error(%v)", err)
}
time.Sleep(5 * time.Second)
return
case syscall.SIGHUP:
default:
return
}
}
}

View File

@@ -0,0 +1,42 @@
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/job/main/activity/conf",
tags = ["automanaged"],
visibility = ["//visibility:public"],
deps = [
"//library/cache/memcache:go_default_library",
"//library/cache/redis:go_default_library",
"//library/conf:go_default_library",
"//library/database/elastic:go_default_library",
"//library/database/sql:go_default_library",
"//library/log:go_default_library",
"//library/net/http/blademaster:go_default_library",
"//library/net/rpc:go_default_library",
"//library/net/rpc/warden:go_default_library",
"//library/queue/databus:go_default_library",
"//library/time: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,186 @@
package conf
import (
"errors"
"flag"
xtime "time"
"go-common/library/cache/memcache"
"go-common/library/cache/redis"
"go-common/library/conf"
"go-common/library/database/elastic"
"go-common/library/database/sql"
"go-common/library/log"
bm "go-common/library/net/http/blademaster"
"go-common/library/net/rpc"
"go-common/library/net/rpc/warden"
"go-common/library/queue/databus"
"go-common/library/time"
"github.com/BurntSushi/toml"
)
var (
confPath string
// Conf conf
Conf = &Config{}
client *conf.Client
)
// Config so config
type Config struct {
// interface Log
Log *log.Config
//HTTPClient
HTTPClient *bm.ClientConfig
// BM
BM *bm.ServerConfig
// rpc
ArchiveRPC *rpc.ClientConfig
ArticleRPC *rpc.ClientConfig
CoinRPC *rpc.ClientConfig
ActRPC *rpc.ClientConfig
// grpc
AccClient *warden.ClientConfig
// DB
MySQL *MySQL
// mc
Memcache *Memcache
// redis
Redis *Redis
// databus
ActSub *databus.Config
BnjSub *databus.Config
// vip binlog databus
//VipSub *databus.Config
KfcSub *databus.Config
// Interval
Interval *interval
// Rule
Rule *rule
// Host
Host *host
// Elastic
Elastic *elastic.Config
// bnj
Bnj2019 *bnj2019
}
type bnj2019 struct {
GameCancel int
LID int64
StartTime xtime.Time
TimelinePic string
H5TimelinePic string
MsgSpec string
MidLimit int64
WxKey string
WxTitle string
WxUser string
Time []*struct {
Score int64
Second int64
Step int
WxMsg string
MsgTitle string
MsgMc string
Msg string
}
Message []*struct {
Start xtime.Time
Title string
Content string
Mc string
}
}
type interval struct {
CoinInterval time.Duration
QueryInterval time.Duration
ObjStatInterval time.Duration
ViewRankInterval time.Duration
KingStoryInterval time.Duration
}
// MySQL is db config.
type MySQL struct {
Like *sql.Config
}
// Redis config
type Redis struct {
*redis.Config
Expire time.Duration
}
// Memcache config
type Memcache struct {
Like *memcache.Config
LikeExpire time.Duration
TimeFinishExpire time.Duration
LessTimeExpire time.Duration
}
type rule struct {
BroadcastCid int64
BroadcastSid int64
ArcObjStatSid int64
ArtObjStatSid int64
KingStorySid int64
EleLotteryID int64
}
type host struct {
APICo string
Activity string
MsgCo string
}
func init() {
flag.StringVar(&confPath, "conf", "", "default config path")
}
// Init init config.
func Init() (err error) {
if confPath != "" {
_, err = toml.DecodeFile(confPath, &Conf)
return
}
err = remote()
return
}
func remote() (err error) {
if client, err = conf.New(); err != nil {
return
}
if err = load(); err != nil {
return
}
client.Watch("activity-job.toml")
go func() {
for range client.Event() {
log.Info("config reload")
if load() != nil {
log.Error("config reload error (%v)", err)
}
}
}()
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,62 @@
package(default_visibility = ["//visibility:public"])
load(
"@io_bazel_rules_go//go:def.bzl",
"go_library",
"go_test",
)
go_library(
name = "go_default_library",
srcs = [
"cache.go",
"dao.go",
"mc.cache.go",
"push.go",
"wechat.go",
],
importpath = "go-common/app/job/main/activity/dao/bnj",
tags = ["automanaged"],
visibility = ["//visibility:public"],
deps = [
"//app/job/main/activity/conf:go_default_library",
"//library/cache/memcache:go_default_library",
"//library/ecode:go_default_library",
"//library/log:go_default_library",
"//library/net/http/blademaster:go_default_library",
"//library/stat/prom:go_default_library",
"//library/xstr: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"],
)
go_test(
name = "go_default_test",
srcs = [
"cache_test.go",
"dao_test.go",
"mc.cache_test.go",
"push_test.go",
"wechat_test.go",
],
embed = [":go_default_library"],
tags = ["automanaged"],
deps = [
"//app/job/main/activity/conf:go_default_library",
"//vendor/github.com/smartystreets/goconvey/convey:go_default_library",
"//vendor/gopkg.in/h2non/gock.v1:go_default_library",
],
)

View File

@@ -0,0 +1,23 @@
package bnj
import "context"
func timeFinishKey() string {
return "time_finish"
}
func lessTimeKey() string {
return "time_less"
}
//go:generate $GOPATH/src/go-common/app/tool/cache/mc
type _mc interface {
// mc: -key=timeFinishKey
CacheTimeFinish(c context.Context) (int64, error)
// mc: -key=timeFinishKey -expire=d.timeFinishExpire -encode=raw
AddCacheTimeFinish(c context.Context, value int64) error
// mc: -key=lessTimeKey
CacheLessTime(c context.Context) (int64, error)
// mc: -key=lessTimeKey -expire=d.lessTimeExpire -encode=raw
AddCacheLessTime(c context.Context, value int64) error
}

View File

@@ -0,0 +1,29 @@
package bnj
import (
"testing"
"github.com/smartystreets/goconvey/convey"
)
func TestBnjtimeFinishKey(t *testing.T) {
convey.Convey("timeFinishKey", t, func(ctx convey.C) {
ctx.Convey("When everything gose positive", func(ctx convey.C) {
p1 := timeFinishKey()
ctx.Convey("Then p1 should not be nil.", func(ctx convey.C) {
ctx.So(p1, convey.ShouldNotBeNil)
})
})
})
}
func TestBnjlessTimeKey(t *testing.T) {
convey.Convey("lessTimeKey", t, func(ctx convey.C) {
ctx.Convey("When everything gose positive", func(ctx convey.C) {
p1 := lessTimeKey()
ctx.Convey("Then p1 should not be nil.", func(ctx convey.C) {
ctx.So(p1, convey.ShouldNotBeNil)
})
})
})
}

View File

@@ -0,0 +1,34 @@
package bnj
import (
"time"
"go-common/app/job/main/activity/conf"
"go-common/library/cache/memcache"
"go-common/library/net/http/blademaster"
)
// Dao .
type Dao struct {
c *conf.Config
client *blademaster.Client
mc *memcache.Pool
broadcastURL string
messageURL string
timeFinishExpire int32
lessTimeExpire int32
}
// New .
func New(c *conf.Config) *Dao {
d := &Dao{
c: c,
client: blademaster.NewClient(c.HTTPClient),
mc: memcache.NewPool(c.Memcache.Like),
}
d.broadcastURL = d.c.Host.APICo + _broadURL
d.messageURL = d.c.Host.MsgCo + _messageURL
d.timeFinishExpire = int32(time.Duration(c.Memcache.TimeFinishExpire) / time.Second)
d.lessTimeExpire = int32(time.Duration(c.Memcache.LessTimeExpire) / time.Second)
return d
}

View File

@@ -0,0 +1,45 @@
package bnj
import (
"flag"
"os"
"strings"
"testing"
"gopkg.in/h2non/gock.v1"
"go-common/app/job/main/activity/conf"
)
var (
d *Dao
)
func TestMain(m *testing.M) {
if os.Getenv("DEPLOY_ENV") != "dev" {
flag.Set("app_id", "main.web-svr.activity-job")
flag.Set("conf_token", "7c164822b6da4198f6348599bedf1797")
flag.Set("tree_id", "2703")
flag.Set("conf_version", "docker-1")
flag.Set("deploy_env", "uat")
flag.Set("conf_host", "config.bilibili.co")
flag.Set("conf_path", "/tmp")
flag.Set("region", "sh")
flag.Set("zone", "sh001")
} else {
flag.Set("conf", "../../cmd/activity-job-test.toml")
}
flag.Parse()
if err := conf.Init(); err != nil {
panic(err)
}
d = New(conf.Conf)
d.client.SetTransport(gock.DefaultTransport)
os.Exit(m.Run())
}
func httpMock(method, url string) *gock.Request {
r := gock.New(url)
r.Method = strings.ToUpper(method)
return r
}

View File

@@ -0,0 +1,124 @@
// Code generated by $GOPATH/src/go-common/app/tool/cache/mc. DO NOT EDIT.
/*
Package bnj is a generated mc cache package.
It is generated from:
type _mc interface {
// mc: -key=timeFinishKey
CacheTimeFinish(c context.Context) (int64, error)
// mc: -key=timeFinishKey -expire=d.timeFinishExpire -encode=raw
AddCacheTimeFinish(c context.Context, value int64) error
// mc: -key=lessTimeKey
CacheLessTime(c context.Context) (int64, error)
// mc: -key=lessTimeKey -expire=d.lessTimeExpire -encode=raw
AddCacheLessTime(c context.Context, value int64) error
}
*/
package bnj
import (
"context"
"fmt"
"strconv"
"go-common/library/cache/memcache"
"go-common/library/log"
"go-common/library/stat/prom"
)
var _ _mc
// CacheTimeFinish get data from mc
func (d *Dao) CacheTimeFinish(c context.Context) (res int64, err error) {
conn := d.mc.Get(c)
defer conn.Close()
key := timeFinishKey()
reply, err := conn.Get(key)
if err != nil {
if err == memcache.ErrNotFound {
err = nil
return
}
prom.BusinessErrCount.Incr("mc:CacheTimeFinish")
log.Errorv(c, log.KV("CacheTimeFinish", fmt.Sprintf("%+v", err)), log.KV("key", key))
return
}
var v string
err = conn.Scan(reply, &v)
if err != nil {
prom.BusinessErrCount.Incr("mc:CacheTimeFinish")
log.Errorv(c, log.KV("CacheTimeFinish", fmt.Sprintf("%+v", err)), log.KV("key", key))
return
}
r, err := strconv.ParseInt(v, 10, 64)
if err != nil {
prom.BusinessErrCount.Incr("mc:CacheTimeFinish")
log.Errorv(c, log.KV("CacheTimeFinish", fmt.Sprintf("%+v", err)), log.KV("key", key))
return
}
res = int64(r)
return
}
// AddCacheTimeFinish Set data to mc
func (d *Dao) AddCacheTimeFinish(c context.Context, val int64) (err error) {
conn := d.mc.Get(c)
defer conn.Close()
key := timeFinishKey()
bs := []byte(strconv.FormatInt(int64(val), 10))
item := &memcache.Item{Key: key, Value: bs, Expiration: d.timeFinishExpire, Flags: memcache.FlagRAW}
if err = conn.Set(item); err != nil {
prom.BusinessErrCount.Incr("mc:AddCacheTimeFinish")
log.Errorv(c, log.KV("AddCacheTimeFinish", fmt.Sprintf("%+v", err)), log.KV("key", key))
return
}
return
}
// CacheLessTime get data from mc
func (d *Dao) CacheLessTime(c context.Context) (res int64, err error) {
conn := d.mc.Get(c)
defer conn.Close()
key := lessTimeKey()
reply, err := conn.Get(key)
if err != nil {
if err == memcache.ErrNotFound {
err = nil
return
}
prom.BusinessErrCount.Incr("mc:CacheLessTime")
log.Errorv(c, log.KV("CacheLessTime", fmt.Sprintf("%+v", err)), log.KV("key", key))
return
}
var v string
err = conn.Scan(reply, &v)
if err != nil {
prom.BusinessErrCount.Incr("mc:CacheLessTime")
log.Errorv(c, log.KV("CacheLessTime", fmt.Sprintf("%+v", err)), log.KV("key", key))
return
}
r, err := strconv.ParseInt(v, 10, 64)
if err != nil {
prom.BusinessErrCount.Incr("mc:CacheLessTime")
log.Errorv(c, log.KV("CacheLessTime", fmt.Sprintf("%+v", err)), log.KV("key", key))
return
}
res = int64(r)
return
}
// AddCacheLessTime Set data to mc
func (d *Dao) AddCacheLessTime(c context.Context, val int64) (err error) {
conn := d.mc.Get(c)
defer conn.Close()
key := lessTimeKey()
bs := []byte(strconv.FormatInt(int64(val), 10))
item := &memcache.Item{Key: key, Value: bs, Expiration: d.lessTimeExpire, Flags: memcache.FlagRAW}
if err = conn.Set(item); err != nil {
prom.BusinessErrCount.Incr("mc:AddCacheLessTime")
log.Errorv(c, log.KV("AddCacheLessTime", fmt.Sprintf("%+v", err)), log.KV("key", key))
return
}
return
}

View File

@@ -0,0 +1,68 @@
package bnj
import (
"context"
"testing"
"github.com/smartystreets/goconvey/convey"
)
func TestBnjAddCacheTimeFinish(t *testing.T) {
convey.Convey("AddCacheTimeFinish", t, func(ctx convey.C) {
var (
c = context.Background()
val = int64(0)
)
ctx.Convey("When everything gose positive", func(ctx convey.C) {
err := d.AddCacheTimeFinish(c, val)
ctx.Convey("Then err should be nil.", func(ctx convey.C) {
ctx.So(err, convey.ShouldBeNil)
})
})
})
}
func TestBnjCacheTimeFinish(t *testing.T) {
convey.Convey("CacheTimeFinish", t, func(ctx convey.C) {
var (
c = context.Background()
)
ctx.Convey("When everything gose positive", func(ctx convey.C) {
res, err := d.CacheTimeFinish(c)
ctx.Convey("Then err should be nil.res should not be nil.", func(ctx convey.C) {
ctx.So(err, convey.ShouldBeNil)
ctx.So(res, convey.ShouldNotBeNil)
})
})
})
}
func TestBnjCacheLessTime(t *testing.T) {
convey.Convey("CacheLessTime", t, func(ctx convey.C) {
var (
c = context.Background()
)
ctx.Convey("When everything gose positive", func(ctx convey.C) {
res, err := d.CacheLessTime(c)
ctx.Convey("Then err should be nil.res should not be nil.", func(ctx convey.C) {
ctx.So(err, convey.ShouldBeNil)
ctx.So(res, convey.ShouldNotBeNil)
})
})
})
}
func TestBnjAddCacheLessTime(t *testing.T) {
convey.Convey("AddCacheLessTime", t, func(ctx convey.C) {
var (
c = context.Background()
val = int64(0)
)
ctx.Convey("When everything gose positive", func(ctx convey.C) {
err := d.AddCacheLessTime(c, val)
ctx.Convey("Then err should be nil.", func(ctx convey.C) {
ctx.So(err, convey.ShouldBeNil)
})
})
})
}

View File

@@ -0,0 +1,60 @@
package bnj
import (
"context"
"net/url"
"go-common/library/ecode"
"go-common/library/log"
"go-common/library/xstr"
)
const (
_opt = "1004"
_platform = "web"
_broadURL = "/x/internal/broadcast/push/all"
_messageURL = "/api/notify/send.user.notify.do"
_notify = "4"
)
// PushAll broadcast push all
func (d *Dao) PushAll(c context.Context, msg string) (err error) {
params := url.Values{}
params.Set("operation", _opt)
params.Set("platform", _platform)
params.Set("message", msg)
var res struct {
Code int `json:"code"`
}
if err = d.client.Post(c, d.broadcastURL, "", params, &res); err != nil {
log.Error("PushAll url(%s) error(%v)", d.broadcastURL+"?"+params.Encode(), err)
return
}
if res.Code != ecode.OK.Code() {
err = ecode.Int(res.Code)
}
return
}
// SendMessage send system notify.
func (d *Dao) SendMessage(c context.Context, mids []int64, mc, title, msg string) (err error) {
params := url.Values{}
params.Set("mid_list", xstr.JoinInts(mids))
params.Set("title", title)
params.Set("mc", mc)
params.Set("data_type", _notify)
params.Set("context", msg)
var res struct {
Code int `json:"code"`
}
err = d.client.Post(c, d.messageURL, "", params, &res)
if err != nil {
log.Error("SendMessage d.client.Post(%s) error(%+v)", d.messageURL+"?"+params.Encode(), err)
return
}
if res.Code != 0 {
log.Error("SendMessage url(%s) res code(%d)", d.messageURL+"?"+params.Encode(), res.Code)
err = ecode.Int(res.Code)
}
return
}

View File

@@ -0,0 +1,45 @@
package bnj
import (
"context"
"testing"
"gopkg.in/h2non/gock.v1"
"github.com/smartystreets/goconvey/convey"
)
func TestBnjPushAll(t *testing.T) {
convey.Convey("PushAll", t, func(ctx convey.C) {
var (
c = context.Background()
msg = `{"second":100,"name":"啊*"}`
)
ctx.Convey("When everything gose positive", func(ctx convey.C) {
err := d.PushAll(c, msg)
ctx.Convey("Then err should be nil.", func(ctx convey.C) {
ctx.So(err, convey.ShouldBeNil)
})
})
})
}
func TestBnjSendMessage(t *testing.T) {
convey.Convey("SendMessage", t, func(ctx convey.C) {
var (
c = context.Background()
mids = []int64{2089809}
mc = "1_21_1"
title = "【bilibili2019拜年祭档案揭秘】001"
msg = "飞雪连天射白鹿笑书神侠倚碧鸳。当V家碰到金庸会碰撞出怎样的火花来拜年祭后台看看吧~"
)
ctx.Convey("When everything gose positive", func(ctx convey.C) {
defer gock.OffAll()
httpMock("POST", d.messageURL).Reply(200).JSON(`{"code":0}`)
err := d.SendMessage(c, mids, mc, title, msg)
ctx.Convey("Then err should be nil.", func(ctx convey.C) {
ctx.So(err, convey.ShouldBeNil)
})
})
})
}

View File

@@ -0,0 +1,56 @@
package bnj
import (
"context"
"encoding/json"
"net/http"
"strings"
"go-common/library/ecode"
"go-common/library/log"
)
const (
_wechatAction = "NotifyCreate"
_wechatType = "wechat_message"
_wechatURL = "http://merak.bilibili.co"
)
// SendWechat send wechat work message.
func (d *Dao) SendWechat(c context.Context, title, msg, user string) (err error) {
var msgBytes []byte
params := map[string]interface{}{
"Action": _wechatAction,
"SendType": _wechatType,
"PublicKey": d.c.Bnj2019.WxKey,
"UserName": user,
"Content": map[string]string{
"subject": title,
"body": title + "\n" + msg,
},
"TreeId": "",
"Signature": "1",
"Severity": "P5",
}
if msgBytes, err = json.Marshal(params); err != nil {
return
}
var req *http.Request
if req, err = http.NewRequest(http.MethodPost, _wechatURL, strings.NewReader(string(msgBytes))); err != nil {
return
}
req.Header.Add("content-type", "application/json; charset=UTF-8")
res := &struct {
RetCode int `json:"RetCode"`
}{}
if err = d.client.Do(c, req, &res); err != nil {
log.Error("SendWechat d.client.Do(title:%s,msg:%s,user:%s) error(%v)", title, msg, user, err)
return
}
if res.RetCode != 0 {
err = ecode.Int(res.RetCode)
log.Error("SendWechat d.client.Do(title:%s,msg:%s,user:%s) error(%v)", title, msg, user, err)
return
}
return
}

View File

@@ -0,0 +1,29 @@
package bnj
import (
"context"
"testing"
"github.com/smartystreets/goconvey/convey"
"gopkg.in/h2non/gock.v1"
)
func TestBnjSendWechat(t *testing.T) {
convey.Convey("SendWechat", t, func(ctx convey.C) {
var (
c = context.Background()
title = "【拜年祭必看!】拜年祭预约人数到达预警"
msg = "拜年祭预约人数即将到达50w请及时准备拜年祭抽奖事项。"
user = "wuhao02"
)
ctx.Convey("When everything gose positive", func(ctx convey.C) {
defer gock.OffAll()
httpMock("POST", _wechatURL).Reply(200).JSON(`{"RetCode":0}`)
err := d.SendWechat(c, title, msg, user)
ctx.Convey("Then err should be nil.", func(ctx convey.C) {
ctx.So(err, convey.ShouldBeNil)
})
})
})
}

View File

@@ -0,0 +1,55 @@
package(default_visibility = ["//visibility:public"])
load(
"@io_bazel_rules_go//go:def.bzl",
"go_test",
"go_library",
)
go_test(
name = "go_default_test",
srcs = [
"broadcast_test.go",
"dao_test.go",
],
embed = [":go_default_library"],
rundir = ".",
tags = ["automanaged"],
deps = [
"//app/job/main/activity/conf:go_default_library",
"//app/job/main/activity/model/dm:go_default_library",
"//vendor/github.com/smartystreets/goconvey/convey:go_default_library",
"//vendor/gopkg.in/h2non/gock.v1:go_default_library",
],
)
go_library(
name = "go_default_library",
srcs = [
"broadcast.go",
"dao.go",
],
importpath = "go-common/app/job/main/activity/dao/dm",
tags = ["automanaged"],
visibility = ["//visibility:public"],
deps = [
"//app/job/main/activity/conf:go_default_library",
"//app/job/main/activity/model/dm: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,51 @@
package dm
import (
"bytes"
"context"
"encoding/json"
"fmt"
"net/http"
"time"
model "go-common/app/job/main/activity/model/dm"
"go-common/library/log"
)
// Broadcast dm broadcast.
func (d *Dao) Broadcast(c context.Context, dm *model.Broadcast) (err error) {
var (
b []byte
req *http.Request
res struct {
Code int64 `json:"code"`
}
)
url := fmt.Sprintf("%s?cids=%d", d.broadcastURL, dm.RoomID)
for i := 0; i < 50; i++ {
if b, err = json.Marshal(dm); err != nil {
log.Error("json.Marshal(%+v) error(%v)", dm, err)
return
}
req, err = http.NewRequest("POST", url, bytes.NewReader(b))
if err != nil {
log.Error("NewRequest.Do(%d)(%s) error(%v)", dm.RoomID, url, err)
}
req.Header.Set("Content-type", "application/json")
err = d.httpCli.Do(c, req, &res)
if err == nil {
break
}
log.Error("http.Do(%d)(%s) error(%v)", dm.RoomID, url, err)
time.Sleep(50 * time.Millisecond)
}
if err != nil {
log.Error("http.Do(%s) error(%v)", url, err)
return
}
if res.Code != 0 {
log.Error("http.Do(%s) res code(%d)", url, res.Code)
}
return
}

View File

@@ -0,0 +1,34 @@
package dm
import (
"context"
"encoding/json"
"fmt"
"testing"
model "go-common/app/job/main/activity/model/dm"
"github.com/smartystreets/goconvey/convey"
"gopkg.in/h2non/gock.v1"
)
func TestDmBroadcast(t *testing.T) {
convey.Convey("Broadcast", t, func(ctx convey.C) {
var (
c = context.Background()
ds, _ = json.Marshal("ttt")
dm = &model.Broadcast{RoomID: 10344, CMD: "act", Info: ds}
)
ctx.Convey("When everything gose positive", func(ctx convey.C) {
defer gock.OffAll()
url := fmt.Sprintf("%s?cids=%d", d.broadcastURL, 10344)
httpMock("POST", url).Reply(200).SetHeaders(map[string]string{
"Code": "0",
})
err := d.Broadcast(c, dm)
ctx.Convey("Then err should be nil.", func(ctx convey.C) {
ctx.So(err, convey.ShouldBeNil)
})
})
})
}

View File

@@ -0,0 +1,22 @@
package dm
import (
"go-common/app/job/main/activity/conf"
bm "go-common/library/net/http/blademaster"
)
// Dao dao struct.
type Dao struct {
// http
broadcastURL string
httpCli *bm.Client
}
// New return dm dao instance.
func New(c *conf.Config) (d *Dao) {
d = &Dao{
broadcastURL: "http://api.bilibili.co/x/internal/chat/push/room",
httpCli: bm.NewClient(c.HTTPClient),
}
return
}

View File

@@ -0,0 +1,44 @@
package dm
import (
"flag"
"os"
"strings"
"testing"
"go-common/app/job/main/activity/conf"
"gopkg.in/h2non/gock.v1"
)
var (
d *Dao
)
func TestMain(m *testing.M) {
if os.Getenv("DEPLOY_ENV") != "" {
flag.Set("app_id", "main.web-svr.activity-job")
flag.Set("conf_token", "7c164822b6da4198f6348599bedf1797")
flag.Set("tree_id", "2703")
flag.Set("conf_version", "docker-1")
flag.Set("deploy_env", "uat")
flag.Set("conf_host", "config.bilibili.co")
flag.Set("conf_path", "/tmp")
flag.Set("region", "sh")
flag.Set("zone", "sh001")
} else {
flag.Set("conf", "../../cmd/activity-job-test.toml")
}
flag.Parse()
if err := conf.Init(); err != nil {
panic(err)
}
d = New(conf.Conf)
os.Exit(m.Run())
}
func httpMock(method, url string) *gock.Request {
r := gock.New(url)
r.Method = strings.ToUpper(method)
return r
}

View File

@@ -0,0 +1,53 @@
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",
"kfc_test.go",
],
embed = [":go_default_library"],
tags = ["automanaged"],
deps = [
"//app/job/main/activity/conf:go_default_library",
"//vendor/github.com/smartystreets/goconvey/convey:go_default_library",
],
)
go_library(
name = "go_default_library",
srcs = [
"dao.go",
"kfc.go",
],
importpath = "go-common/app/job/main/activity/dao/kfc",
tags = ["automanaged"],
visibility = ["//visibility:public"],
deps = [
"//app/job/main/activity/conf:go_default_library",
"//library/ecode:go_default_library",
"//library/net/http/blademaster:go_default_library",
"//library/net/metadata:go_default_library",
"//vendor/github.com/pkg/errors: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,21 @@
package kfc
import (
"go-common/app/job/main/activity/conf"
"go-common/library/net/http/blademaster"
)
// Dao .
type Dao struct {
httpClient *blademaster.Client
kfcDelURL string
}
// New init
func New(c *conf.Config) (d *Dao) {
d = &Dao{
httpClient: blademaster.NewClient(c.HTTPClient),
kfcDelURL: c.Host.APICo + _kfcDelURI,
}
return
}

View File

@@ -0,0 +1,34 @@
package kfc
import (
"flag"
"go-common/app/job/main/activity/conf"
"os"
"testing"
)
var (
d *Dao
)
func TestMain(m *testing.M) {
if os.Getenv("DEPLOY_ENV") != "" {
flag.Set("app_id", "main.web-svr.activity-job")
flag.Set("conf_token", "7c164822b6da4198f6348599bedf1797")
flag.Set("tree_id", "2703")
flag.Set("conf_version", "docker-1")
flag.Set("deploy_env", "uat")
flag.Set("conf_host", "config.bilibili.co")
flag.Set("conf_path", "/tmp")
flag.Set("region", "sh")
flag.Set("zone", "sh001")
} else {
flag.Set("conf", "../../cmd/activity-job-test.toml")
}
flag.Parse()
if err := conf.Init(); err != nil {
panic(err)
}
d = New(conf.Conf)
os.Exit(m.Run())
}

View File

@@ -0,0 +1,36 @@
package kfc
import (
"context"
"net/url"
"strconv"
"go-common/library/ecode"
"go-common/library/net/metadata"
"github.com/pkg/errors"
)
const (
_kfcDelURI = "/x/internal/activity/kfc/deliver"
)
// KfcDelver .
func (d *Dao) KfcDelver(c context.Context, id, mid int64) (err error) {
var httpRes struct {
Code int `json:"code"`
Data map[string]int64 `json:"data"`
Message string `json:"message"`
}
params := url.Values{}
params.Set("id", strconv.FormatInt(id, 10))
params.Set("mid", strconv.FormatInt(mid, 10))
if err = d.httpClient.Post(c, d.kfcDelURL, metadata.String(c, metadata.RemoteIP), params, &httpRes); err != nil {
err = errors.Wrap(err, "KfcDelver http")
return
}
if httpRes.Code != ecode.OK.Code() {
err = errors.Wrapf(ecode.Int(httpRes.Code), "KfcDelver msg(%s)", httpRes.Message)
}
return
}

View File

@@ -0,0 +1,24 @@
package kfc
import (
"context"
"testing"
"github.com/smartystreets/goconvey/convey"
)
func TestKfcKfcDelver(t *testing.T) {
convey.Convey("KfcDelver", t, func(ctx convey.C) {
var (
c = context.Background()
id = int64(1)
mid = int64(5248758)
)
ctx.Convey("When everything gose positive", func(ctx convey.C) {
err := d.KfcDelver(c, id, mid)
ctx.Convey("Then err should be nil.", func(ctx convey.C) {
ctx.So(err, convey.ShouldNotBeNil)
})
})
})
}

View File

@@ -0,0 +1,78 @@
package(default_visibility = ["//visibility:public"])
load(
"@io_bazel_rules_go//go:def.bzl",
"go_test",
"go_library",
)
go_test(
name = "go_default_test",
srcs = [
"action_test.go",
"dao_test.go",
"extend_test.go",
"like_test.go",
"match_test.go",
"redis_test.go",
"subject_test.go",
"web_data_test.go",
],
embed = [":go_default_library"],
rundir = ".",
tags = ["automanaged"],
deps = [
"//app/job/main/activity/conf:go_default_library",
"//app/job/main/activity/model/like:go_default_library",
"//vendor/github.com/smartystreets/goconvey/convey:go_default_library",
"//vendor/gopkg.in/h2non/gock.v1:go_default_library",
],
)
go_library(
name = "go_default_library",
srcs = [
"action.go",
"dao.go",
"extend.go",
"like.go",
"match.go",
"redis.go",
"subject.go",
"web_data.go",
],
importpath = "go-common/app/job/main/activity/dao/like",
tags = ["automanaged"],
visibility = ["//visibility:public"],
deps = [
"//app/admin/main/activity/model:go_default_library",
"//app/job/main/activity/conf:go_default_library",
"//app/job/main/activity/model/like:go_default_library",
"//app/job/main/activity/model/match:go_default_library",
"//library/cache/memcache:go_default_library",
"//library/cache/redis:go_default_library",
"//library/database/elastic:go_default_library",
"//library/database/sql:go_default_library",
"//library/ecode:go_default_library",
"//library/log:go_default_library",
"//library/net/http/blademaster:go_default_library",
"//library/net/metadata:go_default_library",
"//library/xstr:go_default_library",
"//vendor/github.com/pkg/errors:go_default_library",
"@org_golang_x_net//context: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,71 @@
package like
import (
"context"
"database/sql"
"fmt"
"go-common/app/admin/main/activity/model"
"go-common/library/xstr"
"github.com/pkg/errors"
)
const (
_likeActSumSQL = "SELECT SUM(`action`) AS `like`,lid FROM like_action WHERE lid IN(%s) GROUP BY lid"
_likeActListSQL = "SELECT id,mid FROM like_action WHERE lid = ? AND id > ? ORDER BY id LIMIT ?"
)
// BatchLikeActSum .
func (d *Dao) BatchLikeActSum(c context.Context, lids []int64) (res map[int64]int64, err error) {
rows, err := d.db.Query(c, fmt.Sprintf(_likeActSumSQL, xstr.JoinInts(lids)))
if err != nil {
if err == sql.ErrNoRows {
err = nil
} else {
err = errors.Wrap(err, "d.db.Query()")
}
return
}
defer rows.Close()
res = make(map[int64]int64)
for rows.Next() {
like := sql.NullInt64{}
lid := sql.NullInt64{}
if err = rows.Scan(&like, &lid); err != nil {
err = errors.Wrap(err, "rows.Scan()")
return
}
res[lid.Int64] = like.Int64
}
if err = rows.Err(); err != nil {
err = errors.Wrap(err, "rows.Err()")
}
return
}
// LikeActList .
func (d *Dao) LikeActList(c context.Context, lid, minID, limit int64) (res []*model.LikeAction, err error) {
rows, err := d.db.Query(c, _likeActListSQL, lid, minID, limit)
if err != nil {
if err == sql.ErrNoRows {
err = nil
} else {
err = errors.Wrap(err, "d.db.Query()")
}
return
}
defer rows.Close()
for rows.Next() {
action := new(model.LikeAction)
if err = rows.Scan(&action.ID, &action.Mid); err != nil {
err = errors.Wrap(err, "rows.Scan()")
return
}
res = append(res, action)
}
if err = rows.Err(); err != nil {
err = errors.Wrap(err, "rows.Err()")
}
return
}

View File

@@ -0,0 +1,24 @@
package like
import (
"context"
"testing"
"github.com/smartystreets/goconvey/convey"
)
func TestLikeBatchLikeActSum(t *testing.T) {
convey.Convey("BatchLikeActSum", t, func(ctx convey.C) {
var (
c = context.Background()
lids = []int64{13511, 13512, 13510}
)
ctx.Convey("When everything gose positive", func(ctx convey.C) {
res, err := d.BatchLikeActSum(c, lids)
ctx.Convey("Then err should be nil.res should not be nil.", func(ctx convey.C) {
ctx.So(err, convey.ShouldBeNil)
ctx.So(res, convey.ShouldNotBeNil)
})
})
})
}

View File

@@ -0,0 +1,62 @@
package like
import (
"context"
"time"
"go-common/app/job/main/activity/conf"
"go-common/library/cache/memcache"
"go-common/library/cache/redis"
"go-common/library/database/elastic"
"go-common/library/database/sql"
"go-common/library/net/http/blademaster"
)
const _activity = "activity"
// Dao dao
type Dao struct {
db *sql.DB
subjectStmt *sql.Stmt
inOnlineLog *sql.Stmt
mcLike *memcache.Pool
mcLikeExpire int32
redis *redis.Pool
redisExpire int32
httpClient *blademaster.Client
es *elastic.Elastic
setObjStatURL string
setViewRankURL string
setLikeContentURL string
addLotteryTimesURL string
}
// New init
func New(c *conf.Config) (d *Dao) {
d = &Dao{
db: sql.NewMySQL(c.MySQL.Like),
mcLike: memcache.NewPool(c.Memcache.Like),
mcLikeExpire: int32(time.Duration(c.Memcache.LikeExpire) / time.Second),
redis: redis.NewPool(c.Redis.Config),
redisExpire: int32(time.Duration(c.Redis.Expire) / time.Second),
httpClient: blademaster.NewClient(c.HTTPClient),
es: elastic.NewElastic(c.Elastic),
setObjStatURL: c.Host.APICo + _setObjStatURI,
setViewRankURL: c.Host.APICo + _setViewRankURI,
setLikeContentURL: c.Host.APICo + _setLikeContentURI,
addLotteryTimesURL: c.Host.Activity + _addLotteryTimesURI,
}
d.subjectStmt = d.db.Prepared(_selSubjectSQL)
d.inOnlineLog = d.db.Prepared(_inOnlineLogSQL)
return
}
// Close close
func (d *Dao) Close() {
d.db.Close()
}
// Ping ping
func (d *Dao) Ping(c context.Context) error {
return d.db.Ping(c)
}

View File

@@ -0,0 +1,44 @@
package like
import (
"flag"
"os"
"strings"
"testing"
"go-common/app/job/main/activity/conf"
"gopkg.in/h2non/gock.v1"
)
var (
d *Dao
)
func TestMain(m *testing.M) {
if os.Getenv("DEPLOY_ENV") != "" {
flag.Set("app_id", "main.web-svr.activity-job")
flag.Set("conf_token", "7c164822b6da4198f6348599bedf1797")
flag.Set("tree_id", "2703")
flag.Set("conf_version", "docker-1")
flag.Set("deploy_env", "uat")
flag.Set("conf_host", "config.bilibili.co")
flag.Set("conf_path", "/tmp")
flag.Set("region", "sh")
flag.Set("zone", "sh001")
} else {
flag.Set("conf", "../../cmd/activity-job-test.toml")
}
flag.Parse()
if err := conf.Init(); err != nil {
panic(err)
}
d = New(conf.Conf)
os.Exit(m.Run())
}
func httpMock(method, url string) *gock.Request {
r := gock.New(url)
r.Method = strings.ToUpper(method)
return r
}

View File

@@ -0,0 +1,22 @@
package like
import (
"context"
"fmt"
"github.com/pkg/errors"
)
var (
_batchUpExtSQL = "INSERT INTO like_extend (`lid`,`like`) VALUES %s ON DUPLICATE KEY UPDATE `like`=values(`like`)"
)
// AddExtend .
func (dao *Dao) AddExtend(c context.Context, query string) (res int64, err error) {
rows, err := dao.db.Exec(c, fmt.Sprintf(_batchUpExtSQL, query))
if err != nil {
err = errors.Wrap(err, " dao.db.Exec()")
return
}
return rows.RowsAffected()
}

View File

@@ -0,0 +1,24 @@
package like
import (
"context"
"testing"
"github.com/smartystreets/goconvey/convey"
)
func TestLikeAddExtend(t *testing.T) {
convey.Convey("AddExtend", t, func(ctx convey.C) {
var (
c = context.Background()
query = "(13511,100)"
)
ctx.Convey("When everything gose positive", func(ctx convey.C) {
res, err := d.AddExtend(c, query)
ctx.Convey("Then err should be nil.res should not be nil.", func(ctx convey.C) {
ctx.So(err, convey.ShouldBeNil)
ctx.So(res, convey.ShouldNotBeNil)
})
})
})
}

Some files were not shown because too many files have changed in this diff Show More