Create & Init Project...

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

View File

@@ -0,0 +1,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)
})
})
})
}

View File

@@ -0,0 +1,136 @@
package like
import (
"context"
"database/sql"
"net/url"
"strconv"
"go-common/app/job/main/activity/model/like"
"go-common/library/ecode"
"go-common/library/log"
"go-common/library/net/metadata"
"go-common/library/xstr"
"github.com/pkg/errors"
)
const (
_selLikeSQL = "SELECT id,wid FROM likes WHERE state=1 AND sid=? ORDER BY type"
_likeListSQL = "SELECT id,wid FROM likes WHERE state= 1 AND sid = ? ORDER BY id LIMIT ?,?"
_likesCntSQL = "SELECT COUNT(1) AS cnt FROM likes WHERE state = 1 AND sid = ?"
_setObjStatURI = "/x/internal/activity/object/stat/set"
_setViewRankURI = "/x/internal/activity/view/rank/set"
_setLikeContentURI = "/x/internal/activity/like/content/set"
)
// Like get like by sid
func (d *Dao) Like(c context.Context, sid int64) (ns []*like.Like, err error) {
rows, err := d.db.Query(c, _selLikeSQL, sid)
if err != nil {
log.Error("notice.Query error(%v)", err)
return
}
defer rows.Close()
for rows.Next() {
n := &like.Like{}
if err = rows.Scan(&n.ID, &n.Wid); err != nil {
log.Error("row.Scan error(%v)", err)
return
}
ns = append(ns, n)
}
return
}
// LikeList get like list by sid.
func (d *Dao) LikeList(c context.Context, sid int64, offset, limit int) (list []*like.Like, err error) {
rows, err := d.db.Query(c, _likeListSQL, sid, offset, limit)
if err != nil {
err = errors.Wrapf(err, "LikeList:d.db.Query(%d,%d,%d)", sid, offset, limit)
return
}
defer rows.Close()
for rows.Next() {
n := new(like.Like)
if err = rows.Scan(&n.ID, &n.Wid); err != nil {
err = errors.Wrapf(err, "LikeList:row.Scan row (%d,%d,%d)", sid, offset, limit)
return
}
list = append(list, n)
}
if err = rows.Err(); err != nil {
err = errors.Wrapf(err, "LikeList:rowsErr(%d,%d,%d)", sid, offset, limit)
}
return
}
// LikeCnt get like list total count by sid.
func (d *Dao) LikeCnt(c context.Context, sid int64) (count int, err error) {
row := d.db.QueryRow(c, _likesCntSQL, sid)
if err = row.Scan(&count); err != nil {
if err == sql.ErrNoRows {
err = nil
} else {
err = errors.Wrapf(err, "LikeCnt:QueryRow(%d)", sid)
}
}
return
}
// SetObjectStat .
func (d *Dao) SetObjectStat(c context.Context, sid int64, stat *like.SubjectTotalStat, count int) (err error) {
params := url.Values{}
params.Set("sid", strconv.FormatInt(sid, 10))
params.Set("like", strconv.FormatInt(stat.SumLike, 10))
params.Set("view", strconv.FormatInt(stat.SumView, 10))
params.Set("fav", strconv.FormatInt(stat.SumFav, 10))
params.Set("coin", strconv.FormatInt(stat.SumCoin, 10))
params.Set("count", strconv.Itoa(count))
var res struct {
Code int `json:"code"`
}
if err = d.httpClient.Get(c, d.setObjStatURL, metadata.String(c, metadata.RemoteIP), params, &res); err != nil {
err = errors.Wrapf(err, "SetObjectStat(%d,%v)", sid, stat)
return
}
if res.Code != ecode.OK.Code() {
err = errors.Wrapf(ecode.Int(res.Code), "SetObjectStat Code(%d,%v)", sid, stat)
}
return
}
// SetViewRank set view rank list.
func (d *Dao) SetViewRank(c context.Context, sid int64, aids []int64) (err error) {
params := url.Values{}
params.Set("sid", strconv.FormatInt(sid, 10))
params.Set("aids", xstr.JoinInts(aids))
var res struct {
Code int `json:"code"`
}
if err = d.httpClient.Get(c, d.setViewRankURL, metadata.String(c, metadata.RemoteIP), params, &res); err != nil {
err = errors.Wrapf(err, "SetViewRank(%d,%v)", sid, aids)
return
}
if res.Code != ecode.OK.Code() {
err = errors.Wrapf(ecode.Int(res.Code), "SetViewRank Code(%d,%v)", sid, aids)
}
return
}
// SetLikeContent .
func (d *Dao) SetLikeContent(c context.Context, id int64) (err error) {
var res struct {
Code int `json:"code"`
}
params := url.Values{}
params.Set("lid", strconv.FormatInt(id, 10))
if err = d.httpClient.Get(c, d.setLikeContentURL, metadata.String(c, metadata.RemoteIP), params, &res); err != nil {
err = errors.Wrapf(err, "SetLikeContent(%d)", id)
return
}
if res.Code != ecode.OK.Code() {
err = errors.Wrapf(ecode.Int(res.Code), "SetLikeContent Code(%d)", id)
}
return
}

View File

@@ -0,0 +1,115 @@
package like
import (
"context"
"testing"
"go-common/app/job/main/activity/model/like"
"github.com/smartystreets/goconvey/convey"
"gopkg.in/h2non/gock.v1"
)
func TestLikeLike(t *testing.T) {
convey.Convey("Like", t, func(ctx convey.C) {
var (
c = context.Background()
sid = int64(10297)
)
ctx.Convey("When everything gose positive", func(ctx convey.C) {
ns, err := d.Like(c, sid)
ctx.Convey("Then err should be nil.ns should not be nil.", func(ctx convey.C) {
ctx.So(err, convey.ShouldBeNil)
ctx.So(ns, convey.ShouldNotBeNil)
})
})
})
}
func TestLikeLikeList(t *testing.T) {
convey.Convey("LikeList", t, func(ctx convey.C) {
var (
c = context.Background()
sid = int64(10297)
offset = int(1)
limit = int(10)
)
ctx.Convey("When everything gose positive", func(ctx convey.C) {
list, err := d.LikeList(c, sid, offset, limit)
ctx.Convey("Then err should be nil.list should not be nil.", func(ctx convey.C) {
ctx.So(err, convey.ShouldBeNil)
ctx.So(list, convey.ShouldNotBeNil)
})
})
})
}
func TestLikeLikeCnt(t *testing.T) {
convey.Convey("LikeCnt", t, func(ctx convey.C) {
var (
c = context.Background()
sid = int64(10297)
)
ctx.Convey("When everything gose positive", func(ctx convey.C) {
count, err := d.LikeCnt(c, sid)
ctx.Convey("Then err should be nil.count should not be nil.", func(ctx convey.C) {
ctx.So(err, convey.ShouldBeNil)
ctx.So(count, convey.ShouldNotBeNil)
})
})
})
}
func TestLikeSetObjectStat(t *testing.T) {
convey.Convey("SetObjectStat", t, func(ctx convey.C) {
var (
c = context.Background()
sid = int64(10297)
stat = &like.SubjectTotalStat{}
count = int(10)
)
ctx.Convey("When everything gose positive", func(ctx convey.C) {
defer gock.OffAll()
httpMock("GET", d.setObjStatURL).Reply(200).JSON(`{"code":0}`)
err := d.SetObjectStat(c, sid, stat, count)
ctx.Convey("Then err should be nil.", func(ctx convey.C) {
ctx.So(err, convey.ShouldBeNil)
})
})
})
}
func TestLikeSetViewRank(t *testing.T) {
convey.Convey("SetViewRank", t, func(ctx convey.C) {
var (
c = context.Background()
sid = int64(10297)
aids = []int64{1, 2}
)
ctx.Convey("When everything gose positive", func(ctx convey.C) {
defer gock.OffAll()
httpMock("GET", d.setViewRankURL).Reply(200).JSON(`{"code":0}`)
err := d.SetViewRank(c, sid, aids)
ctx.Convey("Then err should be nil.", func(ctx convey.C) {
ctx.So(err, convey.ShouldBeNil)
})
})
})
}
func TestLikeSetLikeContent(t *testing.T) {
convey.Convey("SetLikeContent", t, func(ctx convey.C) {
var (
c = context.Background()
id = int64(1)
)
ctx.Convey("When everything gose positive", func(ctx convey.C) {
defer gock.OffAll()
httpMock("GET", d.setLikeContentURL).Reply(200).JSON(`{"code":0}`)
err := d.SetLikeContent(c, id)
ctx.Convey("Then err should be nil.", func(ctx convey.C) {
ctx.So(err, convey.ShouldBeNil)
})
})
})
}

View File

@@ -0,0 +1,58 @@
package like
import (
"context"
"database/sql"
"fmt"
"go-common/app/job/main/activity/model/match"
"go-common/library/log"
"go-common/library/xstr"
)
const (
_unDoMatchSQL = "SELECT mid,stake,result FROM act_match_user_log WHERE m_o_id = ? AND status = 0 LIMIT ?"
_upMatchUserSQL = "UPDATE act_match_user_log SET status = 1 WHERE m_o_id = ? AND mid IN (%s)"
_matchObjSQL = "SELECT id,match_id,sid,result FROM act_matchs_object WHERE status = 0 AND id = ?"
)
// UnDoMatchUsers un finish users.
func (d *Dao) UnDoMatchUsers(c context.Context, matchObjID int64, limit int) (list []*match.ActMatchUser, err error) {
rows, err := d.db.Query(c, _unDoMatchSQL, matchObjID, limit)
if err != nil {
log.Error("UnDoMatchUsers.Query error(%v)", err)
return
}
defer rows.Close()
for rows.Next() {
user := new(match.ActMatchUser)
if err = rows.Scan(&user.Mid, &user.Stake, &user.Result); err != nil {
log.Error("UnDoMatchUsers row.Scan error(%v)", err)
return
}
list = append(list, user)
}
return
}
// UpMatchUserResult update match user result.
func (d *Dao) UpMatchUserResult(c context.Context, matchObjID int64, mids []int64) (err error) {
if _, err = d.db.Exec(c, fmt.Sprintf(_upMatchUserSQL, xstr.JoinInts(mids)), matchObjID); err != nil {
log.Error("UpMatchUserResult d.db.Exec mids(%v) error(%v)", mids, err)
}
return
}
// MatchObjInfo get match object info from db.
func (d *Dao) MatchObjInfo(c context.Context, matchObjID int64) (data *match.ActMatchObj, err error) {
row := d.db.QueryRow(c, _matchObjSQL, matchObjID)
data = new(match.ActMatchObj)
if err = row.Scan(&data.ID, &data.MatchID, &data.SID, &data.Result); err != nil {
if err == sql.ErrNoRows {
err = nil
} else {
log.Error("MatchObjInfo row.Scan() error(%v)", err)
}
}
return
}

View File

@@ -0,0 +1,59 @@
package like
import (
"context"
"testing"
"fmt"
"github.com/smartystreets/goconvey/convey"
)
func TestLikeUnDoMatchUsers(t *testing.T) {
convey.Convey("UnDoMatchUsers", t, func(ctx convey.C) {
var (
c = context.Background()
matchObjID = int64(1)
limit = int(10)
)
ctx.Convey("When everything gose positive", func(ctx convey.C) {
list, err := d.UnDoMatchUsers(c, matchObjID, limit)
ctx.Convey("Then err should be nil.list should not be nil.", func(ctx convey.C) {
ctx.So(err, convey.ShouldBeNil)
fmt.Printf("%+v", list)
})
})
})
}
func TestLikeUpMatchUserResult(t *testing.T) {
convey.Convey("UpMatchUserResult", t, func(ctx convey.C) {
var (
c = context.Background()
matchObjID = int64(1)
mids = []int64{111}
)
ctx.Convey("When everything gose positive", func(ctx convey.C) {
err := d.UpMatchUserResult(c, matchObjID, mids)
ctx.Convey("Then err should be nil.", func(ctx convey.C) {
ctx.So(err, convey.ShouldBeNil)
})
})
})
}
func TestLikeMatchObjInfo(t *testing.T) {
convey.Convey("MatchObjInfo", t, func(ctx convey.C) {
var (
c = context.Background()
matchObjID = int64(37)
)
ctx.Convey("When everything gose positive", func(ctx convey.C) {
data, err := d.MatchObjInfo(c, matchObjID)
ctx.Convey("Then err should be nil.data should not be nil.", func(ctx convey.C) {
ctx.So(err, convey.ShouldBeNil)
ctx.So(data, convey.ShouldNotBeNil)
})
})
})
}

View File

@@ -0,0 +1,154 @@
package like
import (
"strconv"
"go-common/library/cache/redis"
"go-common/library/log"
"golang.org/x/net/context"
)
const (
_prefixAttention = "lg_"
)
func redisKey(key string) string {
return _prefixAttention + key
}
//RsSet set res
func (d *Dao) RsSet(c context.Context, key string, value string) (err error) {
var (
rkey = redisKey(key)
conn = d.redis.Get(c)
)
defer conn.Close()
if _, err = conn.Do("SET", rkey, value); err != nil {
log.Error("conn.Send(SET, %s, %s) error(%v)", rkey, value, err)
return
}
return
}
// RbSet setRb
func (d *Dao) RbSet(c context.Context, key string, value []byte) (err error) {
var (
rkey = redisKey(key)
conn = d.redis.Get(c)
)
defer conn.Close()
if _, err = conn.Do("SET", rkey, value); err != nil {
log.Error("conn.Send(SET, %s, %d) error(%v)", rkey, value, err)
return
}
return
}
// RsGet getRs
func (d *Dao) RsGet(c context.Context, key string) (res string, err error) {
var (
rkey = redisKey(key)
conn = d.redis.Get(c)
)
defer conn.Close()
if res, err = redis.String(conn.Do("GET", rkey)); err != nil {
if err == redis.ErrNil {
err = nil
} else {
log.Error("conn.Do(GET key(%s)) error(%v)", rkey, err)
}
return
}
return
}
// RsSetNX NXset get
func (d *Dao) RsSetNX(c context.Context, key string) (res bool, err error) {
var (
rkey = redisKey(key)
conn = d.redis.Get(c)
)
defer conn.Close()
if res, err = redis.Bool(conn.Do("SETNX", rkey, 1)); err != nil {
log.Error("conn.Do(SETNX key(%s)) error(%v)", rkey, err)
return
}
return
}
// Incr incr
func (d *Dao) Incr(c context.Context, key string) (res bool, err error) {
var (
rkey = redisKey(key)
conn = d.redis.Get(c)
)
defer conn.Close()
if res, err = redis.Bool(conn.Do("incr", rkey)); err != nil {
log.Error("conn.Do(incr key(%s)) error(%v)", rkey, err)
return
}
return
}
// CreateSelection Create selection
func (d *Dao) CreateSelection(c context.Context, aid int64, stage int64) (err error) {
key := strconv.FormatInt(aid, 10) + ":" + strconv.FormatInt(stage, 10)
var (
rkeyYes = redisKey(key + ":yes")
rkeyNo = redisKey(key + ":no")
conn = d.redis.Get(c)
)
defer conn.Close()
if err = conn.Send("SET", rkeyYes, 0); err != nil {
log.Error("conn.Send(SET %s) error(%v)", rkeyYes, err)
return
}
if err = conn.Send("SET", rkeyNo, 0); err != nil {
log.Error("conn.Send(SET %s) error(%v)", rkeyNo, err)
return
}
if err = conn.Flush(); err != nil {
log.Error("conn.Flush() error(%v)", err)
return
}
for i := 0; i < 2; i++ {
if _, err = conn.Receive(); err != nil {
log.Error("conn.Receive() error(%v)", err)
return
}
}
return
}
// Selection selection
func (d *Dao) Selection(c context.Context, aid int64, stage int64) (yes int64, no int64, err error) {
key := strconv.FormatInt(aid, 10) + ":" + strconv.FormatInt(stage, 10)
var (
rkeyYes = redisKey(key + ":yes")
rkeyNo = redisKey(key + ":no")
conn = d.redis.Get(c)
)
defer conn.Close()
if err = conn.Send("GET", rkeyYes); err != nil {
log.Error("conn.Send(SET %s) error(%v)", rkeyYes, err)
return
}
if err = conn.Send("GET", rkeyNo); err != nil {
log.Error("conn.Send(SET %s) error(%v)", rkeyNo, err)
return
}
if err = conn.Flush(); err != nil {
log.Error("conn.Flush() error(%v)", err)
return
}
if yes, err = redis.Int64(conn.Receive()); err != nil {
log.Error("conn.Receive(yes) error(%v)", err)
return
}
if no, err = redis.Int64(conn.Receive()); err != nil {
log.Error("conn.Receive(no) error(%v)", err)
return
}
return
}

View File

@@ -0,0 +1,136 @@
package like
import (
"context"
"testing"
"github.com/smartystreets/goconvey/convey"
)
func TestLikeredisKey(t *testing.T) {
convey.Convey("redisKey", t, func(ctx convey.C) {
var (
key = "1"
)
ctx.Convey("When everything gose positive", func(ctx convey.C) {
p1 := redisKey(key)
ctx.Convey("Then p1 should not be nil.", func(ctx convey.C) {
ctx.So(p1, convey.ShouldNotBeNil)
})
})
})
}
func TestLikeRsSet(t *testing.T) {
convey.Convey("RsSet", t, func(ctx convey.C) {
var (
c = context.Background()
key = "111"
value = "1"
)
ctx.Convey("When everything gose positive", func(ctx convey.C) {
err := d.RsSet(c, key, value)
ctx.Convey("Then err should be nil.ok should not be nil.", func(ctx convey.C) {
ctx.So(err, convey.ShouldBeNil)
})
})
})
}
func TestLikeRbSet(t *testing.T) {
convey.Convey("RbSet", t, func(ctx convey.C) {
var (
c = context.Background()
key = "111"
value = []byte("1")
)
ctx.Convey("When everything gose positive", func(ctx convey.C) {
err := d.RbSet(c, key, value)
ctx.Convey("Then err should be nil.ok should not be nil.", func(ctx convey.C) {
ctx.So(err, convey.ShouldBeNil)
})
})
})
}
func TestLikeRsGet(t *testing.T) {
convey.Convey("RsGet", t, func(ctx convey.C) {
var (
c = context.Background()
key = "1"
)
ctx.Convey("When everything gose positive", func(ctx convey.C) {
res, err := d.RsGet(c, key)
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 TestLikeRsSetNX(t *testing.T) {
convey.Convey("RsSetNX", t, func(ctx convey.C) {
var (
c = context.Background()
key = "2"
)
ctx.Convey("When everything gose positive", func(ctx convey.C) {
res, err := d.RsSetNX(c, key)
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 TestLikeIncr(t *testing.T) {
convey.Convey("Incr", t, func(ctx convey.C) {
var (
c = context.Background()
key = "1"
)
ctx.Convey("When everything gose positive", func(ctx convey.C) {
res, err := d.Incr(c, key)
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 TestLikeCreateSelection(t *testing.T) {
convey.Convey("CreateSelection", t, func(ctx convey.C) {
var (
c = context.Background()
aid = int64(1)
stage = int64(1)
)
ctx.Convey("When everything gose positive", func(ctx convey.C) {
err := d.CreateSelection(c, aid, stage)
ctx.Convey("Then err should be nil.", func(ctx convey.C) {
ctx.So(err, convey.ShouldBeNil)
})
})
})
}
func TestLikeSelection(t *testing.T) {
convey.Convey("Selection", t, func(ctx convey.C) {
var (
c = context.Background()
aid = int64(1)
stage = int64(1)
)
ctx.Convey("When everything gose positive", func(ctx convey.C) {
yes, no, err := d.Selection(c, aid, stage)
ctx.Convey("Then err should be nil.yes,no should not be nil.", func(ctx convey.C) {
ctx.So(err, convey.ShouldBeNil)
ctx.So(no, convey.ShouldNotBeNil)
ctx.So(yes, convey.ShouldNotBeNil)
})
})
})
}

View File

@@ -0,0 +1,127 @@
package like
import (
"context"
"database/sql"
"fmt"
"net/url"
"strconv"
"time"
"go-common/app/job/main/activity/model/like"
"go-common/library/ecode"
"go-common/library/log"
"go-common/library/net/metadata"
"go-common/library/xstr"
"github.com/pkg/errors"
)
const (
_selSubjectSQL = "SELECT s.id,s.name,s.dic,s.cover,s.stime,f.interval,f.ltime,f.tlimit FROM act_subject s INNER JOIN act_time_config f ON s.id=f.sid WHERE s.id=?"
_inOnlineLogSQL = "INSERT INTO act_online_vote_end_log(sid,aid,stage,yes,no) VALUES(?,?,?,?,?)"
_subjectsSQL = "SELECT id,name,dic,cover,stime,etime FROM act_subject WHERE state = 1 AND type IN (%s) AND stime <= ? AND etime>= ?"
_addLotteryTimesURI = "/matsuri/api/add/times"
)
// Subject subject
func (dao *Dao) Subject(c context.Context, sid int64) (n *like.Subject, err error) {
rows := dao.subjectStmt.QueryRow(c, sid)
n = &like.Subject{}
if err = rows.Scan(&n.ID, &n.Name, &n.Dic, &n.Cover, &n.Stime, &n.Interval, &n.Ltime, &n.Tlimit); err != nil {
if err == sql.ErrNoRows {
n = nil
err = nil
} else {
log.Error("row.Scan error(%v)", err)
}
return
}
return
}
// InOnlinelog InOnlinelog
func (dao *Dao) InOnlinelog(c context.Context, sid, aid, stage, yes, no int64) (rows int64, err error) {
rs, err := dao.inOnlineLog.Exec(c, sid, aid, stage, yes, no)
if err != nil {
log.Error("d.InOnlinelog.Exec(%d, %d, %d, %d, %d) error(%v)", sid, aid, stage, yes, no, err)
return
}
return rs.RowsAffected()
}
// SubjectList get online subject list by type.
func (dao *Dao) SubjectList(c context.Context, types []int64, ts time.Time) (res []*like.Subject, err error) {
rows, err := dao.db.Query(c, fmt.Sprintf(_subjectsSQL, xstr.JoinInts(types)), ts, ts)
if err != nil {
err = errors.Wrapf(err, "SubjectList:d.db.Query(%v,%d)", types, ts.Unix())
return
}
defer rows.Close()
for rows.Next() {
n := new(like.Subject)
if err = rows.Scan(&n.ID, &n.Name, &n.Dic, &n.Cover, &n.Stime, &n.Etime); err != nil {
err = errors.Wrapf(err, "SubjectList:row.Scan row (%v,%d)", types, ts.Unix())
return
}
res = append(res, n)
}
if err = rows.Err(); err != nil {
err = errors.Wrapf(err, "SubjectList:rowsErr(%v,%d)", types, ts.Unix())
}
return
}
// SubjectTotalStat total stat.
func (dao *Dao) SubjectTotalStat(c context.Context, sid int64) (rs *like.SubjectTotalStat, err error) {
req := dao.es.NewRequest(_activity).Index(_activity).WhereEq("state", 1).WhereEq("sid", sid).Sum("click").Sum("likes").Sum("fav").Sum("coin")
res := new(struct {
Result struct {
SumCoin []struct {
Value float64 `json:"value"`
} `json:"sum_coin"`
SumFav []struct {
Value float64 `json:"value"`
} `json:"sum_fav"`
SumLikes []struct {
Value float64 `json:"value"`
} `json:"sum_likes"`
SumClick []struct {
Value float64 `json:"value"`
} `json:"sum_click"`
}
Page struct {
Total int `json:"total"`
}
})
if err = req.Scan(c, &res); err != nil || res == nil {
log.Error("SearchArc req.Scan error(%v)", err)
return
}
rs = &like.SubjectTotalStat{
SumCoin: int64(res.Result.SumCoin[0].Value),
SumFav: int64(res.Result.SumFav[0].Value),
SumLike: int64(res.Result.SumLikes[0].Value),
SumView: int64(res.Result.SumClick[0].Value),
Count: res.Page.Total,
}
return
}
// AddLotteryTimes .
func (dao *Dao) AddLotteryTimes(c context.Context, sid, mid int64) (err error) {
params := url.Values{}
params.Set("act_id", strconv.FormatInt(sid, 10))
params.Set("mid", strconv.FormatInt(mid, 10))
var res struct {
Code int `json:"code"`
}
if err = dao.httpClient.Get(c, dao.addLotteryTimesURL, metadata.String(c, metadata.RemoteIP), params, &res); err != nil {
err = errors.Wrapf(err, "dao.client.Get(%s)", dao.addLotteryTimesURL+"?"+params.Encode())
return
}
if res.Code != ecode.OK.Code() {
err = ecode.Int(res.Code)
}
return
}

View File

@@ -0,0 +1,99 @@
package like
import (
"context"
"testing"
"time"
"github.com/smartystreets/goconvey/convey"
"gopkg.in/h2non/gock.v1"
)
func TestLikeSubject(t *testing.T) {
convey.Convey("Subject", t, func(ctx convey.C) {
var (
c = context.Background()
sid = int64(10193)
)
ctx.Convey("When everything gose positive", func(ctx convey.C) {
n, err := d.Subject(c, sid)
ctx.Convey("Then err should be nil.n should not be nil.", func(ctx convey.C) {
ctx.So(err, convey.ShouldBeNil)
ctx.So(n, convey.ShouldNotBeNil)
})
})
})
}
func TestLikeInOnlinelog(t *testing.T) {
convey.Convey("InOnlinelog", t, func(ctx convey.C) {
var (
c = context.Background()
sid = int64(10193)
aid = int64(1)
stage = int64(1)
yes = int64(1)
no = int64(1)
)
ctx.Convey("When everything gose positive", func(ctx convey.C) {
rows, err := d.InOnlinelog(c, sid, aid, stage, yes, no)
ctx.Convey("Then err should be nil.rows should not be nil.", func(ctx convey.C) {
ctx.So(err, convey.ShouldBeNil)
ctx.So(rows, convey.ShouldNotBeNil)
})
})
})
}
func TestLikeSubjectList(t *testing.T) {
convey.Convey("SubjectList", t, func(ctx convey.C) {
var (
c = context.Background()
types = []int64{1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 14, 13, 15, 16, 17, 18, 19}
ts = time.Now()
)
ctx.Convey("When everything gose positive", func(ctx convey.C) {
res, err := d.SubjectList(c, types, ts)
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 TestLikeSubjectTotalStat(t *testing.T) {
convey.Convey("SubjectTotalStat", t, func(ctx convey.C) {
var (
c = context.Background()
sid = int64(10338)
)
ctx.Convey("When everything gose positive", func(ctx convey.C) {
rs, err := d.SubjectTotalStat(c, sid)
ctx.Convey("Then err should be nil.rs should not be nil.", func(ctx convey.C) {
ctx.So(err, convey.ShouldBeNil)
ctx.So(rs, convey.ShouldNotBeNil)
})
})
})
}
func TestLikeAddLotteryTimes(t *testing.T) {
convey.Convey("AddLotteryTimes", t, func(ctx convey.C) {
var (
c = context.Background()
sid = int64(315)
mid = int64(1)
)
ctx.Convey("When everything gose positive", func(ctx convey.C) {
defer gock.OffAll()
httpMock("GET", d.addLotteryTimesURL).Reply(200).SetHeaders(map[string]string{
"Code": "0",
})
err := d.AddLotteryTimes(c, sid, mid)
ctx.Convey("Then err should be nil.", func(ctx convey.C) {
ctx.So(err, convey.ShouldBeNil)
})
})
})
}

View File

@@ -0,0 +1,50 @@
package like
import (
"context"
"database/sql"
"go-common/app/job/main/activity/model/like"
"github.com/pkg/errors"
)
const (
_webDataCntSQL = "SELECT COUNT(1) AS cnt FROM act_web_data WHERE state = 1 AND vid = ?"
_webDataListSQL = "SELECT id,vid,data FROM act_web_data WHERE state= 1 AND vid = ? ORDER BY id LIMIT ?,?"
)
// WebDataCnt get web data count.
func (d *Dao) WebDataCnt(c context.Context, vid int64) (count int, err error) {
row := d.db.QueryRow(c, _webDataCntSQL, vid)
if err = row.Scan(&count); err != nil {
if err == sql.ErrNoRows {
err = nil
} else {
err = errors.Wrapf(err, "WebDataCnt:QueryRow(%d)", vid)
}
}
return
}
// WebDataList get web data list by vid.
func (d *Dao) WebDataList(c context.Context, vid int64, offset, limit int) (list []*like.WebData, err error) {
rows, err := d.db.Query(c, _webDataListSQL, vid, offset, limit)
if err != nil {
err = errors.Wrapf(err, "WebDataList:d.db.Query(%d,%d,%d)", vid, offset, limit)
return
}
defer rows.Close()
for rows.Next() {
n := new(like.WebData)
if err = rows.Scan(&n.ID, &n.Vid, &n.Data); err != nil {
err = errors.Wrapf(err, "WebDataList:row.Scan row (%d,%d,%d)", vid, offset, limit)
return
}
list = append(list, n)
}
if err = rows.Err(); err != nil {
err = errors.Wrapf(err, "LikeList:rowsErr(%d,%d,%d)", vid, offset, limit)
}
return
}

View File

@@ -0,0 +1,41 @@
package like
import (
"context"
"testing"
"github.com/smartystreets/goconvey/convey"
)
func TestLikeWebDataCnt(t *testing.T) {
convey.Convey("WebDataCnt", t, func(ctx convey.C) {
var (
c = context.Background()
vid = int64(0)
)
ctx.Convey("When everything gose positive", func(ctx convey.C) {
_, err := d.WebDataCnt(c, vid)
ctx.Convey("Then err should be nil.count should not be nil.", func(ctx convey.C) {
ctx.So(err, convey.ShouldBeNil)
})
})
})
}
func TestLikeWebDataList(t *testing.T) {
convey.Convey("WebDataList", t, func(ctx convey.C) {
var (
c = context.Background()
vid = int64(36)
offset = int(1)
limit = int(10)
)
ctx.Convey("When everything gose positive", func(ctx convey.C) {
list, err := d.WebDataList(c, vid, offset, limit)
ctx.Convey("Then err should be nil.list should not be nil.", func(ctx convey.C) {
ctx.So(err, convey.ShouldBeNil)
ctx.So(list, convey.ShouldNotBeNil)
})
})
})
}

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/activity/http",
tags = ["automanaged"],
visibility = ["//visibility:public"],
deps = [
"//app/job/main/activity/conf:go_default_library",
"//app/job/main/activity/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,45 @@
package http
import (
"net/http"
"go-common/app/job/main/activity/conf"
"go-common/app/job/main/activity/service"
"go-common/library/log"
bm "go-common/library/net/http/blademaster"
)
var ajSrv *service.Service
// Init .
func Init(conf *conf.Config, srv *service.Service) {
ajSrv = srv
engine := bm.DefaultServer(conf.BM)
outerRouter(engine)
if err := engine.Start(); err != nil {
log.Error("httpx.Serve(%v) error(%+v)", conf.BM, err)
panic(err)
}
}
func outerRouter(e *bm.Engine) {
e.Ping(ping)
e.GET("/match/finish", finishMatch)
}
func ping(c *bm.Context) {
if err := ajSrv.Ping(c); err != nil {
log.Error("activity-job ping error")
c.AbortWithStatus(http.StatusServiceUnavailable)
}
}
func finishMatch(c *bm.Context) {
v := new(struct {
MoID int64 `form:"mo_id" validate:"min=1"`
})
if err := c.Bind(v); err != nil {
return
}
c.JSON(nil, ajSrv.FinishMatch(c, v.MoID))
}

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 = ["bnj.go"],
importpath = "go-common/app/job/main/activity/model/bnj",
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,15 @@
package bnj
// ResetMsg .
type ResetMsg struct {
Mid int64 `json:"mid"`
Ts int64 `json:"ts"`
}
// Push .
type Push struct {
Second int64 `json:"second"`
Name string `json:"name"`
TimelinePic string `json:"timeline_pic,omitempty"`
H5TimelinePic string `json:"h5_timeline_pic,omitempty"`
}

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 = ["dm_post.go"],
importpath = "go-common/app/job/main/activity/model/dm",
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,46 @@
package dm
import "encoding/json"
const (
// ActionPost dm action
ActionPost = "post"
// BroadcastCMD dm broadcast command
BroadcastCMD = "DM"
// BroadcastCMDACT BroadcastCMDACT
BroadcastCMDACT = "ACT"
)
// XML dm xml info
type XML struct {
PlayTime float32 `json:"playtime"`
Mode int32 `json:"mode"`
FontSize int32 `json:"fontsize"`
Color int32 `json:"color"`
Times int64 `json:"times"`
PoolID int32 `json:"poolid"`
Hash string `json:"hash"`
DMID int64 `json:"dmid"`
Msg string `json:"msg"`
Random string `json:"rnd"`
}
// Broadcast dm broadcast
type Broadcast struct {
RoomID int64 `json:"roomid"`
CMD string `json:"cmd"`
Info json.RawMessage `json:"info"`
}
// ActDM ActDM
type ActDM struct {
Act int64 `json:"act"`
Aid int64 `json:"aid"`
Next int64 `json:"next"`
No int64 `json:"no"`
Yes int64 `json:"yes"`
Stage int64 `json:"stage"`
Title string `json:"title"`
Author string `json:"author"`
Tname string `json:"tname"`
}

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 = ["kfc.go"],
importpath = "go-common/app/job/main/activity/model/kfc",
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,7 @@
package kfc
// CouponMsg .
type CouponMsg struct {
CouponID int64 `json:"coupon_id"`
UID int64 `json:"uid"`
}

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 = [
"like.go",
"subject.go",
],
importpath = "go-common/app/job/main/activity/model/like",
tags = ["automanaged"],
visibility = ["//visibility:public"],
deps = [
"//app/service/main/archive/api: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,93 @@
package like
import (
"database/sql/driver"
"go-common/app/service/main/archive/api"
"time"
)
// Like like
type Like struct {
ID int64 `json:"id"`
Wid int64 `json:"wid"`
Archive *api.Arc `json:"archive,omitempty"`
}
// Item like item struct.
type Item struct {
ID int64 `json:"id"`
Wid int64 `json:"wid"`
Ctime wocaoTime `json:"ctime"`
Sid int64 `json:"sid"`
Type int `json:"type"`
Mid int64 `json:"mid"`
State int `json:"state"`
StickTop int `json:"stick_top"`
Mtime wocaoTime `json:"mtime"`
}
// Content like_content.
type Content struct {
ID int64 `json:"id"`
Message string `json:"message"`
IP int64 `json:"ip"`
Plat int `json:"plat"`
Device int `json:"device"`
Ctime wocaoTime `json:"ctime"`
Mtime wocaoTime `json:"mtime"`
Image string `json:"image"`
Reply string `json:"reply"`
Link string `json:"link"`
ExName string `json:"ex_name"`
}
// WebData act web data.
type WebData struct {
ID int64 `json:"id"`
Vid int64 `json:"vid"`
Data string `json:"data"`
}
// Action like_action .
type Action struct {
ID int64 `json:"id"`
Lid int64 `json:"lid"`
Mid int64 `json:"mid"`
Action int64 `json:"action"`
Ctime wocaoTime `json:"ctime"`
Mtime wocaoTime `json:"mtime"`
Sid int64 `json:"sid"`
IP int64 `json:"ip"`
}
// Extend .
type Extend struct {
ID int64 `json:"id"`
Lid int64 `json:"lid"`
Like int64 `json:"like"`
Ctime wocaoTime `json:"ctime"`
Mtime wocaoTime `json:"mtime"`
}
// LastTmStat .
type LastTmStat struct {
Last int64
}
type wocaoTime string
// Scan scan time.
func (jt *wocaoTime) Scan(src interface{}) (err error) {
switch sc := src.(type) {
case time.Time:
*jt = wocaoTime(sc.Format("2006-01-02 15:04:05"))
case string:
*jt = wocaoTime(sc)
}
return
}
// Value get time value.
func (jt wocaoTime) Value() (driver.Value, error) {
return time.Parse("2006-01-02 15:04:05", string(jt))
}

View File

@@ -0,0 +1,65 @@
package like
import xtime "go-common/library/time"
// Subject subject
type Subject struct {
ID int64 `json:"id"`
Name string `json:"name"`
Dic string `json:"dic"`
Cover string `json:"cover"`
Stime xtime.Time `json:"stime"`
Etime xtime.Time `json:"etime"`
Interval int64 `json:"interval"`
Tlimit int64 `json:"tlimit"`
Ltime int64 `json:"ltime"`
List []*Like `json:"list"`
}
// ActSubject .
type ActSubject struct {
ID int64 `json:"id"`
Oid int64 `json:"oid"`
Type int `json:"type"`
State int `json:"state"`
Stime wocaoTime `json:"stime"`
Etime wocaoTime `json:"etime"`
Ctime wocaoTime `json:"ctime"`
Mtime wocaoTime `json:"mtime"`
Name string `json:"name"`
Author string `json:"author"`
ActURL string `json:"act_url"`
Lstime wocaoTime `json:"lstime"`
Letime wocaoTime `json:"letime"`
Cover string `json:"cover" `
Dic string `json:"dic"`
Flag int64 `json:"flag"`
Uetime wocaoTime `json:"uetime"`
Ustime wocaoTime `json:"ustime"`
Level int `json:"level"`
H5Cover string `json:"h5_cover"`
Rank int64 `json:"rank"`
LikeLimit int `json:"like_limit"`
}
// SubjectTotalStat .
type SubjectTotalStat struct {
SumCoin int64 `json:"sum_coin"`
SumFav int64 `json:"sum_fav"`
SumLike int64 `json:"sum_like"`
SumView int64 `json:"sum_view"`
Count int `json:"count"`
}
// VipActOrder .
type VipActOrder struct {
ID int64 `json:"id"`
Mid int64 `json:"mid"`
OrderNo string `json:"order_no"`
ProductID string `json:"product_id"`
Ctime wocaoTime `json:"ctime"`
Mtime wocaoTime `json:"mtime"`
PanelType string `json:"panel_type"`
Months int `json:"months"`
AssociateState int `json:"associate_state"`
}

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 = ["match.go"],
importpath = "go-common/app/job/main/activity/model/match",
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,37 @@
package match
import "encoding/json"
// ActUpdate .
const (
ActUpdate = "update"
ActInsert = "insert"
ActDelete = "delete"
ResultNo = 0
ResultHome = 1
ResultDraw = 2
ResultAway = 3
)
// Message canal binlog message.
type Message struct {
Action string `json:"action"`
Table string `json:"table"`
New json.RawMessage `json:"new"`
Old json.RawMessage `json:"old"`
}
// ActMatchObj match object struct.
type ActMatchObj struct {
ID int64 `json:"id"`
MatchID int64 `json:"match_id"`
SID int64 `json:"sid"`
Result int `json:"result"`
}
// ActMatchUser match user.
type ActMatchUser struct {
Mid int64
Result int
Stake int64
}

View File

@@ -0,0 +1,80 @@
package(default_visibility = ["//visibility:public"])
load(
"@io_bazel_rules_go//go:def.bzl",
"go_test",
"go_library",
)
go_test(
name = "go_default_test",
srcs = [
"match_test.go",
"service_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",
],
)
go_library(
name = "go_default_library",
srcs = [
"action.go",
"archive.go",
"bnj.go",
"kfc.go",
"like.go",
"match.go",
"service.go",
"subject.go",
],
importpath = "go-common/app/job/main/activity/service",
tags = ["automanaged"],
visibility = ["//visibility:public"],
deps = [
"//app/admin/main/activity/model:go_default_library",
"//app/interface/main/activity/model/like:go_default_library",
"//app/interface/main/activity/rpc/client:go_default_library",
"//app/interface/openplatform/article/model:go_default_library",
"//app/interface/openplatform/article/rpc/client:go_default_library",
"//app/job/main/activity/conf:go_default_library",
"//app/job/main/activity/dao/bnj:go_default_library",
"//app/job/main/activity/dao/dm:go_default_library",
"//app/job/main/activity/dao/kfc:go_default_library",
"//app/job/main/activity/dao/like:go_default_library",
"//app/job/main/activity/model/bnj:go_default_library",
"//app/job/main/activity/model/kfc:go_default_library",
"//app/job/main/activity/model/like:go_default_library",
"//app/job/main/activity/model/match:go_default_library",
"//app/service/main/account/api:go_default_library",
"//app/service/main/archive/api:go_default_library",
"//app/service/main/archive/api/gorpc:go_default_library",
"//app/service/main/archive/model/archive:go_default_library",
"//app/service/main/coin/api/gorpc:go_default_library",
"//app/service/main/coin/model:go_default_library",
"//library/ecode:go_default_library",
"//library/log:go_default_library",
"//library/queue/databus:go_default_library",
"//vendor/github.com/robfig/cron: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,137 @@
package service
import (
"bytes"
"context"
"encoding/json"
"strconv"
"time"
"go-common/app/job/main/activity/model/like"
"go-common/library/log"
)
// actionDealProc .
func (s *Service) actionDealProc(i int) {
defer s.waiter.Done()
var (
ch = s.subActionCh[i]
sm = s.actionSM[i]
ls *like.LastTmStat
)
for {
ms, ok := <-ch
if !ok {
s.multiUpActDB(i, sm)
log.Warn("s.actionDealProc(%d) quit", i)
return
}
if ls, ok = sm[ms.Lid]; !ok {
ls = &like.LastTmStat{Last: time.Now().Unix()}
sm[ms.Lid] = ls
// the first time update db.
s.updateActDB([]int64{ms.Lid})
}
if time.Now().Unix()-ls.Last > 60 {
s.updateActDB([]int64{ms.Lid})
delete(sm, ms.Lid)
}
log.Info("s.actionDealProc(%d) lid:%d time:%d", i, ms.Lid, ls.Last)
}
}
// updateActDB batch to deal like_extend.
func (s *Service) updateActDB(lids []int64) {
var (
c = context.Background()
insertExt []*like.Extend
)
if len(lids) == 0 {
return
}
lidLike, err := s.dao.BatchLikeActSum(c, lids)
if err != nil {
log.Error("s.dao.BatchLikeActSum(%v) error(%+v)", lids, err)
return
}
insertExt = make([]*like.Extend, 0, len(lids))
for _, v := range lids {
if _, ok := lidLike[v]; ok {
insertExt = append(insertExt, &like.Extend{Lid: v, Like: lidLike[v]})
} else {
log.Warn("s.updateActDB() data has not found")
}
}
if len(insertExt) == 0 {
return
}
s.BatchInsertLikeExtend(c, insertExt)
}
// multiUpActDB division sm data .
func (s *Service) multiUpActDB(yu int, sm map[int64]*like.LastTmStat) {
var (
i int
startLids = [1000]int64{}
lids = startLids[:0]
)
log.Info("start close(%d) multiUpActDB start", yu)
for lid := range sm {
lids = append(lids, lid)
i++
if i%1000 == 0 {
s.updateActDB(lids)
lids = startLids[:0]
}
}
if len(lids) > 0 {
s.updateActDB(lids)
}
log.Info("start close(%d) multiUpActDB end", yu)
}
// BatchInsertLikeExtend batch insert like_extend table.
func (s *Service) BatchInsertLikeExtend(c context.Context, extends []*like.Extend) (res int64, err error) {
var buf bytes.Buffer
cnt := 0
rows := int64(0)
for _, v := range extends {
buf.WriteString("(")
buf.WriteString(strconv.FormatInt(v.Lid, 10))
buf.WriteString(",")
buf.WriteString(strconv.FormatInt(v.Like, 10))
buf.WriteString("),")
cnt++
if cnt%500 == 0 {
buf.Truncate(buf.Len() - 1)
if rows, err = s.dao.AddExtend(c, buf.String()); err != nil {
log.Error("s.dao.dealAddExtend() error(%+v)", err)
return
}
res += rows
buf.Reset()
}
}
if buf.Len() > 0 {
buf.Truncate(buf.Len() - 1)
if rows, err = s.dao.AddExtend(c, buf.String()); err != nil {
log.Error("s.dao.dealAddExtend() error(%+v)", err)
return
}
res += rows
}
return
}
// actionProc .
func (s *Service) actionProc(c context.Context, msg json.RawMessage) (err error) {
var (
act = new(like.Action)
)
if err = json.Unmarshal(msg, act); err != nil {
log.Error("actionProc json.Unmarshal(%s) error(%v)", msg, err)
return
}
s.subActionCh[act.Lid%_sharding] <- act
return
}

View File

@@ -0,0 +1,124 @@
package service
import (
"context"
"sort"
"time"
likemdl "go-common/app/interface/main/activity/model/like"
"go-common/app/job/main/activity/model/like"
"go-common/app/service/main/archive/api"
"go-common/app/service/main/archive/model/archive"
"go-common/library/log"
)
const (
_rankViewPieceSize = 100
_rankCount = 50
)
func (s *Service) subsRankproc() {
for {
if s.closed {
return
}
var (
subs []*like.Subject
err error
)
now := time.Now()
if subs, err = s.dao.SubjectList(context.Background(), []int64{likemdl.PHONEVIDEO, likemdl.SMALLVIDEO}, now); err != nil {
log.Error("viewRankproc s.dao.SubjectList error(%+v)", err)
time.Sleep(100 * time.Millisecond)
continue
}
if len(subs) == 0 {
log.Warn("viewRankproc no subjects time(%d)", now.Unix())
time.Sleep(time.Duration(s.c.Interval.ViewRankInterval))
continue
}
for _, v := range subs {
s.viewRankproc(v.ID)
time.Sleep(100 * time.Millisecond)
}
time.Sleep(time.Duration(s.c.Interval.ViewRankInterval))
}
}
func (s *Service) viewRankproc(sid int64) {
var (
likeCnt int
likes []*like.Like
rankArcs []*api.Arc
err error
)
if likeCnt, err = s.dao.LikeCnt(context.Background(), sid); err != nil {
log.Error("viewRankproc s.dao.LikeCnt(sid:%d) error(%v)", sid, err)
return
}
if likeCnt == 0 {
log.Warn("viewRankproc s.dao.LikeCnt(sid:%d) likeCnt == 0", sid)
return
}
for i := 0; i < likeCnt; i += _rankViewPieceSize {
if likes, err = s.likeList(context.Background(), sid, i, _objectPieceSize, _retryTimes); err != nil {
log.Error("viewRankproc s.likeList(%d,%d,%d) error(%+v)", sid, i, _objectPieceSize, err)
time.Sleep(100 * time.Millisecond)
continue
} else {
var aids []int64
for _, v := range likes {
if v.Wid > 0 {
aids = append(aids, v.Wid)
}
}
var arcs map[int64]*api.Arc
if arcs, err = s.arcs(context.Background(), aids, _retryTimes); err != nil {
log.Error("viewRankproc s.arcs(%v) error(%v)", aids, err)
time.Sleep(100 * time.Millisecond)
continue
} else {
for _, aid := range aids {
if arc, ok := arcs[aid]; ok && arc.IsNormal() {
rankArcs = append(rankArcs, arc)
}
}
sort.Slice(rankArcs, func(i, j int) bool {
return rankArcs[i].Stat.View > rankArcs[j].Stat.View
})
if len(rankArcs) > _rankCount {
rankArcs = rankArcs[:_rankCount]
}
}
}
}
if len(rankArcs) > 0 {
var rankAids []int64
for _, v := range rankArcs {
rankAids = append(rankAids, v.Aid)
}
if err = s.setViewRank(context.Background(), sid, rankAids, _retryTimes); err != nil {
log.Error("viewRankproc s.setObjectStat(%d,%v) error(%+v)", sid, rankAids, err)
}
}
}
func (s *Service) arcs(c context.Context, aids []int64, retryCnt int) (arcs map[int64]*api.Arc, err error) {
for i := 0; i < retryCnt; i++ {
if arcs, err = s.arcRPC.Archives3(c, &archive.ArgAids2{Aids: aids}); err == nil {
break
}
time.Sleep(100 * time.Millisecond)
}
return
}
func (s *Service) setViewRank(c context.Context, sid int64, aids []int64, retryTime int) (err error) {
for i := 0; i < retryTime; i++ {
if err = s.dao.SetViewRank(c, sid, aids); err == nil {
break
}
time.Sleep(100 * time.Millisecond)
}
return
}

View File

@@ -0,0 +1,434 @@
package service
import (
"context"
"encoding/json"
"fmt"
"sync/atomic"
"time"
"go-common/app/admin/main/activity/model"
"go-common/app/job/main/activity/model/bnj"
"go-common/app/service/main/account/api"
"go-common/library/log"
)
const (
_preScore = 20000
_stepOne = 1
_stepTwo = 2
_stepThree = 3
_stepFour = 4
_stepFlagValue = "1"
)
var bnjSteps = []int{_stepOne, _stepTwo, _stepThree, _stepFour}
func (s *Service) bnjproc() {
defer s.waiter.Done()
var (
c = context.Background()
lastTs int64
)
for {
if s.closed {
return
}
if s.bnjTimeFinish == 1 {
log.Warn("bnjproc bnjTimeFinish")
return
}
msg, ok := <-s.bnjSub.Messages()
if !ok {
log.Info("bnjproc: databus consumer exit!")
return
}
msg.Commit()
m := &bnj.ResetMsg{}
if err := json.Unmarshal(msg.Value, m); err != nil {
log.Error("bnjproc json.Unmarshal(%s) error(%+v)", msg.Value, err)
continue
}
if m.Mid <= 0 {
continue
}
// broadcast max every 1s
if m.Ts-lastTs < 1 {
continue
}
lastTs = m.Ts
atomic.StoreInt64(&s.bnjLessSecond, s.bnjMaxSecond)
// default name
pushMsg := &bnj.Push{Second: s.bnjLessSecond, Name: ""}
if info, err := s.accClient.Info3(c, &api.MidReq{Mid: m.Mid}); err != nil || info == nil {
log.Error("bnjproc s.accClient.Info3(%d) error(%v)", m.Mid, err)
} else {
var name []rune
runes := []rune(info.Info.Name)
nameLen := len(runes)
if nameLen == 2 {
name = append(runes[0:1], []rune("*")...)
} else if nameLen > 2 {
for i, v := range runes {
if i == 0 {
name = append(name, v)
} else if i == nameLen-1 {
name = append(name, runes[nameLen-1:]...)
} else if i == 1 {
name = append(name, []rune("*")...)
}
}
} else {
name = runes
}
pushMsg.Name = string(name)
if pushStr, err := json.Marshal(pushMsg); err != nil {
log.Error("bnjproc json.Marshal(%+v) error(%v)", pushMsg, err)
} else {
atomic.StoreInt64(&s.bnjLessSecond, s.bnjMaxSecond)
log.Info("bnjproc mid(%d) reset lessTime(%d) maxTime(%d)", m.Mid, s.bnjLessSecond, s.bnjMaxSecond)
if err := s.retryPushAll(context.Background(), string(pushStr), _retryTimes); err != nil {
log.Error("bnjproc s.bnj.PushAll(%s) error(%v)", string(pushStr), err)
}
}
}
log.Info("bnjproc key:%s partition:%d offset:%d", msg.Key, msg.Partition, msg.Offset)
}
}
func bnjWxFlagKey(lid int64, step int) string {
return fmt.Sprintf("bnj_wx_%d_%d", lid, step)
}
func bnjMsgFlagKey(lid int64, step int) string {
return fmt.Sprintf("bnj_msg_%d_%d", lid, step)
}
func (s *Service) initBnjSecond() {
for {
time.Sleep(time.Second)
if time.Now().Unix() < s.c.Bnj2019.StartTime.Unix() {
continue
}
break
}
if value, err := s.retryCacheTimeFinish(context.Background(), _retryTimes); err != nil {
log.Error("initBnjSecond s.dao.retryCacheTimeFinish error(%v)", err)
return
} else if value > 0 {
log.Warn("initBnjSecond time finish")
atomic.StoreInt64(&s.bnjTimeFinish, value)
return
}
// init step flag
for _, v := range s.c.Bnj2019.Time {
if v.Step > 0 {
if value, err := s.retryRsGet(context.Background(), bnjMsgFlagKey(s.c.Bnj2019.LID, v.Step), _retryTimes); err != nil {
log.Error("initBnjSecond msg s.dao.retryRsGet error(%v)")
} else if value != "" {
log.Info("initBnjSecond msg bnjMsgFlagMap[step:%d]", v.Step)
s.bnjMsgFlagMap[v.Step] = 1
}
if value, err := s.retryRsGet(context.Background(), bnjWxFlagKey(s.c.Bnj2019.LID, v.Step), _retryTimes); err != nil {
log.Error("initBnjSecond wx s.dao.retryRsGet error(%v)")
} else if value != "" {
log.Info("initBnjSecond wx bnjWxMsgFlagMap[step:%d]", v.Step)
s.bnjWxMsgFlagMap[v.Step] = 1
}
}
}
scores, err := s.retryBatchLikeActSum(context.Background(), []int64{s.c.Bnj2019.LID}, _retryTimes)
if err != nil {
// TODO need to restart
log.Error("initBnjSecond failed s.dao.BatchLikeActSum(%d) error(%v)", s.c.Bnj2019.LID, err)
return
}
if score, ok := scores[s.c.Bnj2019.LID]; ok {
for i, v := range s.c.Bnj2019.Time {
if score >= v.Score {
atomic.StoreInt64(&s.bnjMaxSecond, v.Second)
atomic.StoreInt64(&s.bnjLessSecond, v.Second)
break
}
if i == len(s.c.Bnj2019.Time)-1 {
atomic.StoreInt64(&s.bnjMaxSecond, v.Second)
atomic.StoreInt64(&s.bnjLessSecond, v.Second)
}
}
} else {
// max second
atomic.StoreInt64(&s.bnjMaxSecond, s.c.Bnj2019.Time[len(s.c.Bnj2019.Time)-1].Second)
atomic.StoreInt64(&s.bnjLessSecond, s.c.Bnj2019.Time[len(s.c.Bnj2019.Time)-1].Second)
}
if lessSecond, err := s.bnj.CacheLessTime(context.Background()); err != nil {
log.Error("initBnjSecond s.dao.CacheLessTime error(%v)", err)
} else if lessSecond > 0 {
atomic.StoreInt64(&s.bnjLessSecond, lessSecond)
}
log.Warn("initBnjSecond maxSecond(%d) lessSecond(%d)", s.bnjMaxSecond, s.bnjLessSecond)
go s.maxSecondproc()
go s.lessSecondproc()
s.waiter.Add(1)
go s.bnjproc()
}
func (s *Service) maxSecondproc() {
ctx := context.Background()
for {
if s.closed {
return
}
time.Sleep(time.Second)
if scores, err := s.dao.BatchLikeActSum(context.Background(), []int64{s.c.Bnj2019.LID}); err != nil {
log.Error("maxSecondproc s.dao.BatchLikeActSum(%d) error(%v)", s.c.Bnj2019.LID, err)
} else {
if score, ok := scores[s.c.Bnj2019.LID]; ok {
for _, v := range s.c.Bnj2019.Time {
if score >= v.Score {
atomic.StoreInt64(&s.bnjMaxSecond, v.Second)
if s.bnjLessSecond > s.bnjMaxSecond {
atomic.StoreInt64(&s.bnjLessSecond, s.bnjMaxSecond)
}
msg := v.Msg
mc := v.MsgMc
msgTitle := v.MsgTitle
step := v.Step
if step > 0 && s.bnjMsgFlagMap[step] == 0 {
if err = s.retryRsSet(ctx, bnjMsgFlagKey(s.c.Bnj2019.LID, step), _stepFlagValue, _retryTimes); err != nil {
log.Error("s.retryRsSet(%d,%d) error(%v)", s.c.Bnj2019.LID, step, err)
break
}
if msg != "" && msgTitle != "" && mc != "" {
go s.sendMessageToSubs(ctx, s.c.Bnj2019.LID, mc, msgTitle, msg, _retryTimes)
} else {
log.Error("bnj msg conf step(%d) error", step)
break
}
log.Info("bnj send msg step:%d finish", step)
s.bnjMsgFlagMu.Lock()
s.bnjMsgFlagMap[step] = 1
s.bnjMsgFlagMu.Unlock()
}
break
}
}
for _, v := range s.c.Bnj2019.Time {
if score+_preScore >= v.Score {
wxMsg := v.WxMsg
step := v.Step
if step > 0 && s.bnjWxMsgFlagMap[step] == 0 {
if err = s.retryRsSet(ctx, bnjWxFlagKey(s.c.Bnj2019.LID, step), _stepFlagValue, _retryTimes); err != nil {
log.Error("s.retryRsSet(%d,%d) error(%v)", s.c.Bnj2019.LID, step, err)
break
}
if wxMsg != "" && s.c.Bnj2019.WxUser != "" {
if err = s.retrySendWechat(ctx, s.c.Bnj2019.WxTitle, wxMsg, s.c.Bnj2019.WxUser, _retryTimes); err != nil {
log.Error("s.retrySendWechat(%s,%s) error(%v)", s.c.Bnj2019.WxTitle, wxMsg, err)
break
}
} else {
log.Error("bnj wx msg conf step(%d) error", step)
break
}
log.Info("bnj send wx step:%d finish", step)
s.bnjWxMsgFlagMu.Lock()
s.bnjWxMsgFlagMap[step] = 1
s.bnjWxMsgFlagMu.Unlock()
}
break
}
}
} else {
log.Warn("maxSecondproc lid not found")
}
}
}
}
func (s *Service) lessSecondproc() {
for {
if s.closed {
return
}
time.Sleep(time.Second)
atomic.AddInt64(&s.bnjLessSecond, -1)
if s.c.Bnj2019.GameCancel != 0 {
log.Warn("lessSecondproc bnj game cancel")
atomic.StoreInt64(&s.bnjLessSecond, 0)
}
if s.bnjLessSecond <= 0 {
if err := s.retryAddCacheTimeFinish(context.Background(), 1, _retryTimes); err != nil {
log.Error("lessSecondproc s.bnj.AddCacheTimeFinish error(%v)", err)
continue
}
log.Warn("lessSecondproc bnj time Finish")
atomic.StoreInt64(&s.bnjTimeFinish, 1)
pushMsg := &bnj.Push{Second: 0, Name: "", TimelinePic: s.c.Bnj2019.TimelinePic, H5TimelinePic: s.c.Bnj2019.H5TimelinePic}
if pushStr, err := json.Marshal(pushMsg); err != nil {
log.Error("lessSecondproc json.Marshal(%+v) error(%v)", pushMsg, err)
} else {
atomic.StoreInt64(&s.bnjLessSecond, s.bnjMaxSecond)
if err := s.retryPushAll(context.Background(), string(pushStr), _retryTimes); err != nil {
log.Error("lessSecondproc s.bnj.PushAll error(%v)", err)
}
}
return
}
pushMsg := &bnj.Push{Second: s.bnjLessSecond, Name: ""}
if pushStr, err := json.Marshal(pushMsg); err != nil {
log.Error("lessSecondproc json.Marshal(%+v) error(%v)", pushMsg, err)
} else {
if err := s.retryPushAll(context.Background(), string(pushStr), 1); err != nil {
log.Error("lessSecondproc s.bnj.PushAll error(%v)", err)
}
}
}
}
func (s *Service) retryBatchLikeActSum(c context.Context, lids []int64, retryCnt int) (res map[int64]int64, err error) {
for i := 0; i < retryCnt; i++ {
if res, err = s.dao.BatchLikeActSum(c, lids); err == nil {
break
}
time.Sleep(100 * time.Millisecond)
}
return
}
func (s *Service) retryAddCacheTimeFinish(c context.Context, value int64, retryCnt int) (err error) {
for i := 0; i < retryCnt; i++ {
if err = s.bnj.AddCacheTimeFinish(c, value); err == nil {
break
}
time.Sleep(100 * time.Millisecond)
}
return
}
func (s *Service) retryCacheTimeFinish(c context.Context, retryCnt int) (value int64, err error) {
for i := 0; i < retryCnt; i++ {
if value, err = s.bnj.CacheTimeFinish(c); err == nil {
break
}
time.Sleep(100 * time.Millisecond)
}
return
}
func (s *Service) retryPushAll(c context.Context, msg string, retryCnt int) (err error) {
for i := 0; i < retryCnt; i++ {
if err = s.bnj.PushAll(c, msg); err == nil {
break
}
time.Sleep(10 * time.Millisecond)
}
return
}
func (s *Service) cronInformationMessage() {
log.Info("cronInformationMessage start cron")
if s.c.Bnj2019.LID == 0 || s.c.Bnj2019.MidLimit == 0 {
log.Error("cronInformationMessage conf error")
return
}
var (
c = context.Background()
title, msg, mc string
)
for _, v := range s.c.Bnj2019.Message {
if time.Now().Unix() >= v.Start.Unix() {
title = v.Title
msg = v.Content
mc = v.Mc
break
}
}
if title == "" || msg == "" || mc == "" {
log.Error("cronInformationMessage message conf error")
return
}
s.sendMessageToSubs(c, s.c.Bnj2019.LID, mc, title, msg, _retryTimes)
log.Info("cronInformationMessage finish title(%s)", title)
}
func (s *Service) sendMessageToSubs(c context.Context, lid int64, mc, title, msg string, retryCnt int) {
var minID int64
log.Info("sendMessageToSubs mc:%s title:%s start", mc, title)
for {
time.Sleep(100 * time.Millisecond)
actions, err := s.retryLikeActList(c, lid, minID, s.c.Bnj2019.MidLimit, retryCnt)
if err != nil {
log.Error("sendMessageToSubs s.dao.LikeActList(%d,%d,%d) error(%v)", lid, minID, s.c.Bnj2019.MidLimit, err)
continue
}
if len(actions) == 0 {
log.Info("sendMessageToSubs finish")
break
}
var mids []int64
for i, v := range actions {
if v.Mid > 0 {
mids = append(mids, v.Mid)
}
if i == len(actions)-1 {
minID = v.ID
}
}
if len(mids) == 0 {
continue
}
if err = s.retrySendMessage(c, mids, mc, title, msg, _retryTimes); err != nil {
log.Error("sendMessageToSubs s.dao.SendMessage(mids:%v) error(%v)", mids, err)
}
}
}
func (s *Service) retryLikeActList(c context.Context, lid, minID, limit int64, retryCnt int) (list []*model.LikeAction, err error) {
for i := 0; i < retryCnt; i++ {
if list, err = s.dao.LikeActList(c, lid, minID, limit); err == nil {
break
}
time.Sleep(10 * time.Millisecond)
}
return
}
func (s *Service) retrySendMessage(c context.Context, mids []int64, mc, title, msg string, retryCnt int) (err error) {
for i := 0; i < retryCnt; i++ {
if err = s.bnj.SendMessage(c, mids, mc, title, msg); err == nil {
break
}
time.Sleep(10 * time.Millisecond)
}
return
}
func (s *Service) retryRsSet(c context.Context, key, value string, retryCnt int) (err error) {
for i := 0; i < retryCnt; i++ {
if err = s.dao.RsSet(c, key, value); err == nil {
break
}
time.Sleep(10 * time.Millisecond)
}
return
}
func (s *Service) retryRsGet(c context.Context, key string, retryCnt int) (value string, err error) {
for i := 0; i < retryCnt; i++ {
if value, err = s.dao.RsGet(c, key); err == nil {
break
}
time.Sleep(10 * time.Millisecond)
}
return
}
func (s *Service) retrySendWechat(c context.Context, title, msg, user string, retryCnt int) (err error) {
for i := 0; i < retryCnt; i++ {
if err = s.bnj.SendWechat(c, title, msg, user); err == nil {
break
}
time.Sleep(10 * time.Millisecond)
}
return
}

View File

@@ -0,0 +1,29 @@
package service
import (
"context"
"go-common/library/log"
)
// kfcActionDeal.
func (s *Service) kfcActionDeal(j int) {
defer s.waiter.Done()
var (
ch = s.kfcActionCh[j]
c = context.Background()
)
log.Info("kfcActionDeal goroutine(%d) start", j)
for {
ms, ok := <-ch
if !ok {
log.Warn("kfcActionDeal(%d): quit", j)
return
}
if err := s.kfcDao.KfcDelver(c, ms.CouponID, ms.UID); err != nil {
log.Error("kfcActionDeal(%d):s.kfcDao.KfcDelver(%d %d) error(%v)", j, ms.CouponID, ms.UID, err)
return
}
log.Info("kfcActionDeal(%d) success id(%d) uid(%d)", j, ms.CouponID, ms.UID)
}
}

View File

@@ -0,0 +1,116 @@
package service
import (
"context"
"encoding/json"
actmdl "go-common/app/interface/main/activity/model/like"
l "go-common/app/job/main/activity/model/like"
"go-common/library/log"
)
// AddLike like add data update cache .
func (s *Service) AddLike(c context.Context, addMsg json.RawMessage) (err error) {
var (
likeObj = new(l.Item)
)
if err = json.Unmarshal(addMsg, likeObj); err != nil {
log.Error("AddLike json.Unmarshal(%s) error(%+v)", addMsg, err)
return
}
if err = s.actRPC.LikeUp(c, &actmdl.ArgLikeUp{Lid: likeObj.ID}); err != nil {
log.Error("s.actRPC.LikeUp(%d) error(%+v)", likeObj.ID, err)
return
}
if err = s.actRPC.AddLikeCtimeCache(c, &actmdl.ArgLikeUp{Lid: likeObj.ID}); err != nil {
log.Error("s.actRPC.AddLikeCtimeCache(%d) error(%+v)", likeObj.ID, err)
return
}
log.Info("AddLike success s.actRPC.LikeUp(%d)", likeObj.ID)
return
}
// UpLike update likes data update cahce
func (s *Service) UpLike(c context.Context, newMsg, oldMsg json.RawMessage) (err error) {
var (
likeObj = new(l.Item)
oldObj = new(l.Item)
)
if err = json.Unmarshal(newMsg, likeObj); err != nil {
log.Error("UpLike json.Unmarshal(%s) error(%+v)", newMsg, err)
return
}
if err = json.Unmarshal(oldMsg, oldObj); err != nil {
log.Error("UpLike json.Unmarshal(%s) error(%+v)", oldMsg, err)
return
}
if err = s.actRPC.LikeUp(c, &actmdl.ArgLikeUp{Lid: likeObj.ID}); err != nil {
log.Error("s.actRPC.LikeUp(%d) error(%+v)", likeObj.ID, err)
return
}
if oldObj.State != likeObj.State {
if likeObj.State == 1 {
//add ctime cache
if err = s.actRPC.AddLikeCtimeCache(c, &actmdl.ArgLikeUp{Lid: likeObj.ID}); err != nil {
log.Error("s.actRPC.AddLikeCtimeCache(%d) error(%+v)", likeObj.ID, err)
return
}
} else {
//del ctime cahce
delItem := &actmdl.ArgLikeItem{
ID: likeObj.ID,
Sid: likeObj.Sid,
Type: likeObj.Type,
}
if err = s.actRPC.DelLikeCtimeCache(c, delItem); err != nil {
log.Error("s.actRPC.DelLikeCtimeCache(%v) error(%+v)", likeObj, err)
return
}
}
}
log.Info("UpLike success s.actRPC.LikeUp(%d)", likeObj.ID)
return
}
// DelLike delete like update cache
func (s *Service) DelLike(c context.Context, oldMsg json.RawMessage) (err error) {
var (
likeObj = new(l.Item)
)
if err = json.Unmarshal(oldMsg, likeObj); err != nil {
log.Error("DelLike json.Unmarshal(%s) error(%+v)", oldMsg, err)
return
}
if err = s.actRPC.LikeUp(c, &actmdl.ArgLikeUp{Lid: likeObj.ID}); err != nil {
log.Error("s.actRPC.LikeUp(%d) error(%+v)", likeObj.ID, err)
return
}
//del ctime cahce
delItem := &actmdl.ArgLikeItem{
ID: likeObj.ID,
Sid: likeObj.Sid,
Type: likeObj.Type,
}
if err = s.actRPC.DelLikeCtimeCache(c, delItem); err != nil {
log.Error("s.actRPC.DelLikeCtimeCache(%v) error(%+v)", likeObj, err)
return
}
log.Info("DelLike success s.actRPC.LikeUp(%d)", likeObj.ID)
return
}
// upLikeContent .
func (s *Service) upLikeContent(c context.Context, upMsg json.RawMessage) (err error) {
var (
cont = new(l.Content)
)
if err = json.Unmarshal(upMsg, cont); err != nil {
log.Error("upLikeContent json.Unmarshal(%s) error(%+v)", upMsg, err)
return
}
if err = s.dao.SetLikeContent(c, cont.ID); err != nil {
log.Error("s.dao.SetLikeContent(%d) error(%+v)", cont.ID, err)
}
log.Info("upLikeContent success s.dao.SetLikeContent(%d)", cont.ID)
return
}

View File

@@ -0,0 +1,106 @@
package service
import (
"context"
"encoding/json"
"time"
"go-common/app/interface/main/activity/model/like"
"go-common/app/job/main/activity/model/match"
"go-common/app/service/main/coin/model"
"go-common/library/ecode"
"go-common/library/log"
)
const (
_upMatchUserLimit = 100
_reason = "竞猜奖励"
)
func (s *Service) upMatchUser(c context.Context, newMsg, oldMsg json.RawMessage) {
var (
err error
newMatchObj = new(match.ActMatchObj)
oldMatchObj = new(match.ActMatchObj)
)
if err = json.Unmarshal(newMsg, newMatchObj); err != nil {
log.Error("upMatchUser json.Unmarshal(%s) error(%+v)", newMsg, err)
return
}
if err = json.Unmarshal(oldMsg, oldMatchObj); err != nil {
log.Error("upMatchUser json.Unmarshal(%s) error(%+v)", oldMsg, err)
return
}
if oldMatchObj.Result == match.ResultNo {
if newMatchObj.Result == match.ResultNo {
return
}
s.upUsers(c, newMatchObj)
}
}
// FinishMatch finish match.
func (s *Service) FinishMatch(c context.Context, moID int64) (err error) {
var matchObj *match.ActMatchObj
if matchObj, err = s.dao.MatchObjInfo(c, moID); err != nil || matchObj == nil {
return
}
if matchObj.Result == match.ResultNo {
log.Error("FinishMatch moID(%d) result error", moID)
err = ecode.RequestErr
return
}
go s.upUsers(context.Background(), matchObj)
return
}
func (s *Service) upUsers(c context.Context, matchObj *match.ActMatchObj) {
var (
matchs []*like.Match
list []*match.ActMatchUser
stake int64
err error
)
if matchs, err = s.actRPC.Matchs(c, &like.ArgMatch{Sid: matchObj.SID}); err != nil {
log.Error("upMatchUser s.actRPC.Matchs(%d) error(%v)", matchObj.SID, err)
return
}
for _, v := range matchs {
if v.ID == matchObj.MatchID {
stake = v.Stake
}
}
if stake == 0 {
log.Error("upMatchUser match_id(%d) not found", matchObj.MatchID)
return
}
for {
if list, err = s.dao.UnDoMatchUsers(context.Background(), matchObj.ID, _upMatchUserLimit); err != nil {
time.Sleep(time.Duration(s.c.Interval.QueryInterval))
continue
} else if len(list) == 0 {
log.Info("upMatchUser finish m_o_id(%d)", matchObj.ID)
return
}
var resultMids []int64
for _, v := range list {
if v.Result == matchObj.Result {
count := float64(v.Stake * stake)
if _, err = s.coinRPC.ModifyCoin(context.Background(), &model.ArgModifyCoin{Mid: v.Mid, Count: count, Reason: _reason}); err != nil {
log.Error("upMatchUser coin error s.coinRPC.ModifyCoin mid(%d) coin(%v) error(%v)", v.Mid, count, err)
continue
}
log.Info("upMatchUser s.coinRPC.ModifyCoin mid(%d) coin(%v)", v.Mid, count)
resultMids = append(resultMids, v.Mid)
time.Sleep(time.Duration(s.c.Interval.CoinInterval))
} else {
resultMids = append(resultMids, v.Mid)
}
}
if err = s.dao.UpMatchUserResult(context.Background(), matchObj.ID, resultMids); err != nil {
continue
}
log.Info("upMatchUser s.dao.UpMatchUserResult matchID(%d) mids(%+v)", matchObj.ID, resultMids)
time.Sleep(time.Duration(s.c.Interval.QueryInterval))
}
}

View File

@@ -0,0 +1,16 @@
package service
import (
"context"
"testing"
. "github.com/smartystreets/goconvey/convey"
)
func TestService_FinishMatch(t *testing.T) {
Convey("test finish match", t, WithService(func(s *Service) {
moID := int64(3)
err := s.FinishMatch(context.Background(), moID)
So(err, ShouldBeNil)
}))
}

View File

@@ -0,0 +1,729 @@
package service
import (
"context"
"encoding/json"
"runtime"
"strconv"
"sync"
"time"
actrpc "go-common/app/interface/main/activity/rpc/client"
artmdl "go-common/app/interface/openplatform/article/model"
artrpc "go-common/app/interface/openplatform/article/rpc/client"
"go-common/app/job/main/activity/conf"
"go-common/app/job/main/activity/dao/bnj"
"go-common/app/job/main/activity/dao/dm"
"go-common/app/job/main/activity/dao/kfc"
"go-common/app/job/main/activity/dao/like"
kfcmdl "go-common/app/job/main/activity/model/kfc"
l "go-common/app/job/main/activity/model/like"
"go-common/app/job/main/activity/model/match"
"go-common/app/service/main/account/api"
arcapi "go-common/app/service/main/archive/api"
arcrpc "go-common/app/service/main/archive/api/gorpc"
comarcmdl "go-common/app/service/main/archive/model/archive"
"go-common/app/service/main/coin/api/gorpc"
"go-common/library/log"
"go-common/library/queue/databus"
"github.com/robfig/cron"
)
const (
//_startVoteP = 2
//_startVote = 3
//_endingVote = 4
//_endVote = 5
//_goOn = 6
//_next = 7
_matchObjTable = "act_matchs_object"
_subjectTable = "act_subject"
_likesTable = "likes"
_likeContentTable = "like_content"
_likeActionTable = "like_action"
//_vipActOrderTable = "vip_order_activity_record"
_objectPieceSize = 100
_retryTimes = 3
_typeArc = "archive"
_typeArt = "article"
_sharding = 10
)
// Service service
type Service struct {
c *conf.Config
dao *like.Dao
bnj *bnj.Dao
dm *dm.Dao
kfcDao *kfc.Dao
// waiter
waiter sync.WaitGroup
closed bool
// cache: type, upper
// arc rpc
arcRPC *arcrpc.Service2
coinRPC *coin.Service
actRPC *actrpc.Service
articleRPC *artrpc.Service
//grpc
accClient api.AccountClient
// databus
actSub *databus.Databus
bnjSub *databus.Databus
// vip binlog databus
//vipSub *databus.Databus
kfcSub *databus.Databus
kfcActionCh []chan *kfcmdl.CouponMsg
kfcShare int
subActionCh []chan *l.Action
actionSM []map[int64]*l.LastTmStat
// bnj
bnjMaxSecond int64
bnjLessSecond int64
bnjTimeFinish int64
bnjMsgFlagMap map[int]int64
bnjMsgFlagMu sync.Mutex
bnjWxMsgFlagMap map[int]int64
bnjWxMsgFlagMu sync.Mutex
// cron
cron *cron.Cron
}
// New is archive service implementation.
func New(c *conf.Config) (s *Service) {
s = &Service{
c: c,
dao: like.New(c),
dm: dm.New(c),
bnj: bnj.New(c),
kfcDao: kfc.New(c),
arcRPC: arcrpc.New2(c.ArchiveRPC),
articleRPC: artrpc.New(c.ArticleRPC),
coinRPC: coin.New(c.CoinRPC),
actRPC: actrpc.New(c.ActRPC),
actSub: databus.New(c.ActSub),
bnjSub: databus.New(c.BnjSub),
//vipSub: databus.New(c.VipSub),
kfcSub: databus.New(c.KfcSub),
cron: cron.New(),
}
var err error
if s.accClient, err = api.NewClient(c.AccClient); err != nil {
panic(err)
}
if s.c.Bnj2019.MsgSpec != "" {
if err = s.cron.AddFunc(s.c.Bnj2019.MsgSpec, s.cronInformationMessage); err != nil {
panic(err)
}
log.Info("cronInformationMessage init")
s.cron.Start()
}
//time.Sleep(2 * time.Second)
//subject, err := s.sub(context.Background(), c.Rule.BroadcastSid)
//if err != nil {
// log.Error("error(%v)", err)
// return
//}
//log.Info("start-subject")
//log.Info("subject(%v)", subject)
//log.Info("end-subject")
//if subject != nil {
// go s.genesis(subject)
//}
s.bnjMsgFlagMap = make(map[int]int64, len(bnjSteps))
s.bnjWxMsgFlagMap = make(map[int]int64, len(bnjSteps))
for _, step := range bnjSteps {
s.bnjMsgFlagMap[step] = 0
s.bnjWxMsgFlagMap[step] = 0
}
for i := 0; i < _sharding; i++ {
s.subActionCh = append(s.subActionCh, make(chan *l.Action, 10240))
s.actionSM = append(s.actionSM, map[int64]*l.LastTmStat{})
s.waiter.Add(1)
go s.actionDealProc(i)
}
//s.waiter.Add(1)
//go s.vipCanal()
s.waiter.Add(1)
go s.consumeCanal()
go s.subjectStat(s.c.Rule.ArcObjStatSid, _typeArc)
go s.subjectStat(s.c.Rule.ArtObjStatSid, _typeArt)
go s.kingStoryTotalStat(s.c.Rule.KingStorySid)
go s.subsRankproc()
go s.initBnjSecond()
if runtime.NumCPU() <= 4 {
s.kfcShare = 4
} else if runtime.NumCPU() > 32 {
s.kfcShare = 32
} else {
s.kfcShare = runtime.NumCPU()
}
for j := 0; j < s.kfcShare; j++ {
s.kfcActionCh = append(s.kfcActionCh, make(chan *kfcmdl.CouponMsg, 10240))
s.waiter.Add(1)
go s.kfcActionDeal(j)
}
s.waiter.Add(1)
go s.kfcCanal()
return s
}
func (s *Service) likeArc(c context.Context, sub *l.Subject) (res *l.Subject, err error) {
if sub != nil {
if sub.ID == 0 {
res = nil
} else {
res = sub
var (
ok bool
arcs map[int64]*arcapi.Arc
aids []int64
)
for _, l := range res.List {
aids = append(aids, l.Wid)
}
argAids := &comarcmdl.ArgAids2{
Aids: aids,
}
if arcs, err = s.arcRPC.Archives3(c, argAids); err != nil {
log.Error("s.arcRPC.Archives(arcAids:(%v), arcs), err(%v)", aids, err)
return
}
for _, l := range res.List {
if l.Archive, ok = arcs[l.Wid]; !ok {
log.Info("s.arcs.wid:(%d), (%v)", l.Wid, ok)
continue
}
}
}
}
return
}
//func (s *Service) genesis(l *l.Subject) {
// var (
// index int
// nowTime, stage, yes, no, next int64
// err error
// c = context.Background()
// )
// log.Info("st")
// for {
// if time.Now().Unix() >= l.Stime.Time().Unix() {
// break
// }
// time.Sleep(time.Second)
// }
// lstime := map[string]interface{}{
// "aid": 0,
// "time": 0,
// "index": 0,
// "stage": 0,
// }
// go s.inLtime(lstime, l.ID)
// for i, a := range l.List {
// arg1 := &comarcmdl.ArgAid2{Aid: a.Archive.Aid}
// arc, errRPC := s.arcRPC.Archive3(c, arg1)
// if errRPC != nil {
// log.Error("act-job s.arcRPC.Archive3(%v) error(%v)", arg1, errRPC)
// errRPC = nil
// continue
// }
// if arc.State < 0 && arc.State != -6 {
// log.Error("act-job s.arcRPC.Archive3(%v) stat err", arg1)
// }
// index = i
// nowTime = 0
// stage = 0
// next = 0
// time.Sleep(time.Duration(l.Ltime) * time.Second)
// log.Info("aid sleep")
// aidTime := time.Now().Unix()
// ltime := map[string]interface{}{
// "aid": a.Archive.Aid,
// "time": aidTime,
// "index": i,
// "stage": stage,
// "title": arc.Title,
// "author": arc.Author.Name,
// "tname": arc.TypeName,
// }
// go s.inLtime(ltime, l.ID)
// for {
// fmt.Println(stage)
// log.Info("s.stage{%d}", stage)
// //演出开始
// ltime := map[string]interface{}{
// "aid": a.Archive.Aid,
// "time": aidTime,
// "index": i,
// "stage": stage,
// "title": arc.Title,
// "author": arc.Author.Name,
// "tname": arc.TypeName,
// }
// go s.inLtime(ltime, l.ID)
// tp := l.Interval - l.Ltime
// nowTime += tp
// time.Sleep(time.Duration(tp) * time.Second)
// //预备投票
// sdm := &dmm.ActDM{Act: _startVoteP, Aid: a.Archive.Aid, Next: next, Yes: 0, No: 0, Stage: stage, Title: arc.Title, Author: arc.Author.Name, Tname: arc.TypeName}
// go s.brodcast(sdm)
// log.Info("act:1")
// go s.dao.CreateSelection(c, a.Archive.Aid, stage)
// nowTime += l.Ltime
// time.Sleep(time.Duration(l.Ltime) * time.Second)
// //投票开始
// interval := &dmm.ActDM{Act: _startVote, Aid: a.Archive.Aid, Next: next, Yes: 0, No: 0, Stage: stage, Title: arc.Title, Author: arc.Author.Name, Tname: arc.TypeName}
// go s.brodcast(interval)
// log.Info("act:2")
// tl := l.Tlimit - l.Ltime
// nowTime += tl
// time.Sleep(time.Duration(tl) * time.Second)
// //投票预结束
// intervalP := &dmm.ActDM{Act: _endingVote, Aid: a.Archive.Aid, Next: next, Yes: 0, No: 0, Stage: stage, Title: arc.Title, Author: arc.Author.Name, Tname: arc.TypeName}
// log.Info("act:3")
// go s.brodcast(intervalP)
// nowTime += l.Ltime
// time.Sleep(time.Duration(l.Ltime) * time.Second)
// //投票结果
// if yes, no, err = s.dao.Selection(c, a.Archive.Aid, stage); err != nil {
// log.Error("s.dao.Selection() error(%v)", err)
// return
// }
// goNext := true
// if yes != 0 || no != 0 {
// goNext = (float64(no)/float64(yes+no)*100 > 40)
// }
// if goNext {
// next = 1
// } else {
// next = 0
// }
// intervalEnd := &dmm.ActDM{Act: _endVote, Aid: a.Archive.Aid, Next: next, Yes: yes, No: no, Stage: stage, Title: arc.Title, Author: arc.Author.Name, Tname: arc.TypeName}
// go s.brodcast(intervalEnd)
// log.Info("act:4")
// nowTime += l.Ltime
// time.Sleep(time.Duration(l.Ltime) * time.Second)
// go s.inOnlinelog(c, l.ID, a.Archive.Aid, stage, yes, no)
// if goNext {
// tlimit := &dmm.ActDM{Act: _next, Aid: a.Archive.Aid, Next: next, Yes: yes, No: no, Stage: stage, Title: arc.Title, Author: arc.Author.Name, Tname: arc.TypeName}
// go s.brodcast(tlimit)
// log.Info("act:6")
// nowTime += l.Ltime
// ldtime := map[string]interface{}{
// "aid": 0,
// "time": time.Now().Unix() + l.Ltime,
// "index": i + 1,
// "stage": 0,
// "title": arc.Title,
// "author": arc.Author.Name,
// "tname": arc.TypeName,
// }
// go s.inLtime(ldtime, l.ID)
// time.Sleep(time.Duration(l.Ltime) * time.Second)
// break
// }
// tlimit := &dmm.ActDM{Act: _goOn, Aid: a.Archive.Aid, Next: next, Yes: yes, No: no, Stage: stage, Title: arc.Title, Author: arc.Author.Name, Tname: arc.TypeName}
// log.Info("bro:%v", tlimit)
// go s.brodcast(tlimit)
// log.Info("act:5")
// //投票结果判断
// stage++
// if a.Archive.Duration-nowTime < 60 {
// go s.inOnlinelog(c, l.ID, a.Archive.Aid, 100, 0, 0)
// time.Sleep(time.Duration(a.Archive.Duration-nowTime) * time.Second)
// break
// }
// }
// }
// ltime := map[string]interface{}{
// "aid": 0,
// "time": time.Now().Unix(),
// "index": index + 1,
// "stage": 0,
// "title": "",
// "author": "",
// "tname": "",
// }
// go s.inLtime(ltime, l.ID)
// log.Info("end")
//}
//
//func (s *Service) inOnlinelog(c context.Context, sid, aid, stage, yes, no int64) {
// if row, err := s.dao.InOnlinelog(c, sid, aid, stage, yes, no); err != nil {
// log.Error("s.dao.inOnlinelog, err(%v) row(%v)", err, row)
// }
//}
//
//func (s *Service) inLtime(lt map[string]interface{}, sid int64) {
// var v, err = json.Marshal(lt)
// if err != nil {
// log.Error("s.genesis.inLtime.json.Marshal(dm:(%v)), err(%v)", v, err)
// return
// }
// s.dao.RbSet(context.Background(), "ltime:"+strconv.FormatInt(sid, 10), v)
//}
//
//func (s *Service) brodcast(d *dmm.ActDM) {
// var ds, err = json.Marshal(d)
// if err != nil {
// log.Error("s.genesis.json.Marshal(dm:(%v)), err(%v)", d, err)
// return
// }
// var m = &dmm.Broadcast{
// RoomID: s.c.Rule.BroadcastCid,
// CMD: dmm.BroadcastCMDACT,
// Info: ds,
// }
// s.dm.Broadcast(context.Background(), m)
//}
//
//func (s *Service) sub(c context.Context, sid int64) (res *l.Subject, err error) {
// var (
// eg errgroup.Group
// ls []*l.Like
// )
// eg.Go(func() (err error) {
// res, err = s.dao.Subject(c, sid)
// return
// })
// eg.Go(func() (err error) {
// ls, err = s.dao.Like(c, sid)
// return
// })
// if err = eg.Wait(); err != nil {
// log.Error("eg.Wait error(%v)", err)
// return
// }
// if res != nil {
// res.List = ls
// }
// if res, err = s.likeArc(c, res); err != nil {
// return
// }
// return
//}
//func (s *Service) vipCanal() {
// defer s.waiter.Done()
// var c = context.Background()
// for {
// msg, ok := <-s.vipSub.Messages()
// if !ok {
// log.Info("databus:activity-job vip binlog consumer exit!")
// return
// }
// msg.Commit()
// m := &match.Message{}
// if err := json.Unmarshal(msg.Value, m); err != nil {
// log.Error("json.Unmarshal(%s) error(%+v)", msg.Value, err)
// continue
// }
// switch m.Table {
// case _vipActOrderTable:
// if m.Action == match.ActInsert {
// s.addElemeLottery(c, m.New)
// }
// }
// log.Info("vipCanal key:%s partition:%d offset:%d table:%s", msg.Key, msg.Partition, msg.Offset, m.Table)
// }
//}
func (s *Service) consumeCanal() {
defer s.waiter.Done()
var c = context.Background()
for {
msg, ok := <-s.actSub.Messages()
if !ok {
log.Info("databus: activity-job binlog consumer exit!")
return
}
msg.Commit()
m := &match.Message{}
if err := json.Unmarshal(msg.Value, m); err != nil {
log.Error("json.Unmarshal(%s) error(%+v)", msg.Value, err)
continue
}
switch m.Table {
case _matchObjTable:
if m.Action == match.ActUpdate {
s.upMatchUser(c, m.New, m.Old)
}
case _subjectTable:
if m.Action == match.ActInsert || m.Action == match.ActUpdate {
s.upSubject(c, m.New)
} else if m.Action == match.ActDelete {
s.upSubject(c, m.Old)
}
case _likesTable:
if m.Action == match.ActInsert {
s.AddLike(c, m.New)
} else if m.Action == match.ActUpdate {
s.UpLike(c, m.New, m.Old)
} else if m.Action == match.ActDelete {
s.DelLike(c, m.Old)
}
case _likeContentTable:
if m.Action == match.ActDelete {
s.upLikeContent(c, m.Old)
} else {
s.upLikeContent(c, m.New)
}
case _likeActionTable:
if m.Action == match.ActInsert {
s.actionProc(c, m.New)
}
}
log.Info("consumeCanal key:%s partition:%d offset:%d table:%s", msg.Key, msg.Partition, msg.Offset, m.Table)
}
}
func (s *Service) kfcCanal() {
defer s.waiter.Done()
for {
if s.closed {
return
}
msg, ok := <-s.kfcSub.Messages()
if !ok {
log.Info("databus: activity-job binlog consumer exit!")
return
}
msg.Commit()
m := &kfcmdl.CouponMsg{}
if err := json.Unmarshal(msg.Value, m); err != nil {
log.Error("kfcCanal:json.Unmarshal(%s) error(%+v)", msg.Value, err)
continue
}
j := m.CouponID % int64(s.kfcShare)
select {
case s.kfcActionCh[j] <- m:
default:
log.Info("kfcCanal cache full (%d)", j)
}
log.Info("kfcCanal key:%s partition:%d offset:%d value %s goroutine(%d) all(%d)", msg.Key, msg.Partition, msg.Offset, msg.Value, j, s.kfcShare)
}
}
func (s *Service) subjectStat(sid int64, typ string) {
var err error
for {
if s.closed {
return
}
var (
statLike int64
likeCnt int
likes []*l.Like
)
if sid <= 0 {
log.Warn("conf sid == 0 typ(%s)", typ)
time.Sleep(time.Duration(s.c.Interval.ObjStatInterval))
continue
}
if likeCnt, err = s.dao.LikeCnt(context.Background(), sid); err != nil {
log.Error("s.dao.LikeCnt(sid:%d) error(%v)", sid, err)
time.Sleep(time.Duration(s.c.Interval.ObjStatInterval))
continue
}
if likeCnt == 0 {
log.Warn("s.dao.LikeCnt(sid:%d) likeCnt == 0", sid)
time.Sleep(time.Duration(s.c.Interval.ObjStatInterval))
continue
}
for i := 0; i < likeCnt; i += _objectPieceSize {
if likes, err = s.likeList(context.Background(), sid, i, _objectPieceSize, _retryTimes); err != nil {
log.Error("objectStatproc s.likeList(%d,%d,%d) error(%+v)", sid, i, _objectPieceSize, err)
time.Sleep(100 * time.Millisecond)
continue
} else {
var aids []int64
for _, v := range likes {
if v.Wid > 0 {
aids = append(aids, v.Wid)
}
}
switch typ {
case _typeArc:
var arcs map[int64]*arcapi.Arc
if arcs, err = s.arcs(context.Background(), aids, _retryTimes); err != nil {
log.Error("objectStatproc s.arcs(%v) error(%v)", aids, err)
time.Sleep(100 * time.Millisecond)
continue
} else {
for _, aid := range aids {
if arc, ok := arcs[aid]; ok && arc.IsNormal() {
statLike += int64(arc.Stat.Like)
} else {
likeCnt--
}
}
}
case _typeArt:
var arts map[int64]*artmdl.Meta
if arts, err = s.arts(context.Background(), aids, _retryTimes); err != nil {
log.Error("objectStatproc s.arcs(%v) error(%v)", aids, err)
time.Sleep(100 * time.Microsecond)
continue
} else {
for _, aid := range aids {
if art, ok := arts[aid]; ok && art.IsNormal() {
statLike += art.Stats.Like
} else {
likeCnt--
}
}
}
}
}
}
if err = s.setSubjectStat(context.Background(), sid, &l.SubjectTotalStat{SumLike: statLike}, likeCnt, _retryTimes); err != nil {
log.Error("objectStatproc s.setObjectStat(%d,%d) error(%+v)", sid, statLike, err)
time.Sleep(time.Duration(s.c.Interval.ObjStatInterval))
continue
}
time.Sleep(time.Duration(s.c.Interval.ObjStatInterval))
}
}
func (s *Service) likeList(c context.Context, sid int64, offset, limit, retryCnt int) (list []*l.Like, err error) {
for i := 0; i < retryCnt; i++ {
if list, err = s.dao.LikeList(c, sid, offset, limit); err == nil {
break
}
time.Sleep(100 * time.Millisecond)
}
return
}
func (s *Service) webDataList(c context.Context, vid int64, offset, limit, retryCnt int) (list []*l.WebData, err error) {
for i := 0; i < retryCnt; i++ {
if list, err = s.dao.WebDataList(c, vid, offset, limit); err == nil {
break
}
time.Sleep(100 * time.Millisecond)
}
return
}
func (s *Service) arts(c context.Context, aids []int64, retryCnt int) (arcs map[int64]*artmdl.Meta, err error) {
for i := 0; i < retryCnt; i++ {
if arcs, err = s.articleRPC.ArticleMetas(c, &artmdl.ArgAids{Aids: aids}); err == nil {
break
}
time.Sleep(100 * time.Millisecond)
}
return
}
func (s *Service) kingStoryTotalStat(vid int64) {
var err error
for {
if s.closed {
return
}
var (
statView, statLike, statFav, StatCoin int64
likeCnt int
likes []*l.WebData
)
if vid <= 0 {
log.Warn("conf vid == 0")
time.Sleep(time.Duration(s.c.Interval.KingStoryInterval))
continue
}
if likeCnt, err = s.dao.WebDataCnt(context.Background(), vid); err != nil {
log.Error("kingStoryTotalStat s.dao.WebDataCnt(sid:%d) error(%v)", vid, err)
time.Sleep(time.Duration(s.c.Interval.KingStoryInterval))
continue
}
if likeCnt == 0 {
log.Warn("kingStoryTotalStat s.dao.LikeCnt(sid:%d) likeCnt == 0", vid)
time.Sleep(time.Duration(s.c.Interval.KingStoryInterval))
continue
}
for i := 0; i < likeCnt; i += _objectPieceSize {
if likes, err = s.webDataList(context.Background(), vid, i, _objectPieceSize, _retryTimes); err != nil {
log.Error("kingStoryTotalStat s.webDataList(%d,%d,%d) error(%+v)", vid, i, _objectPieceSize, err)
time.Sleep(100 * time.Millisecond)
continue
} else {
var (
aids []int64
aidStruct = new(struct {
Aid string `json:"AID"`
})
)
for _, v := range likes {
if v.Data != "" {
if e := json.Unmarshal([]byte(v.Data), &aidStruct); e != nil {
log.Warn("kingStoryTotalStat json.Unmarshal(%s) error(%v)", v.Data, e)
continue
}
if aid, e := strconv.ParseInt(aidStruct.Aid, 10, 64); e != nil {
log.Warn("kingStoryTotalStat strconv.ParseInt(%s) error(%v)", aidStruct, e)
continue
} else {
aids = append(aids, aid)
}
}
}
var arcs map[int64]*arcapi.Arc
if arcs, err = s.arcs(context.Background(), aids, _retryTimes); err != nil {
log.Error("kingStoryTotalStat s.arcs(%v) error(%v)", aids, err)
time.Sleep(100 * time.Millisecond)
continue
} else {
for _, aid := range aids {
if arc, ok := arcs[aid]; ok && arc.IsNormal() {
statView += int64(arc.Stat.View)
statLike += int64(arc.Stat.Like)
statFav += int64(arc.Stat.Fav)
StatCoin += int64(arc.Stat.Coin)
}
}
}
}
}
if err = s.setSubjectStat(context.Background(), vid, &l.SubjectTotalStat{SumView: statView, SumLike: statLike, SumFav: statFav, SumCoin: StatCoin}, likeCnt, _retryTimes); err != nil {
log.Error("kingStoryTotalStat s.setObjectStat(%d,%d) error(%+v)", vid, statLike, err)
time.Sleep(time.Duration(s.c.Interval.KingStoryInterval))
continue
}
time.Sleep(time.Duration(s.c.Interval.KingStoryInterval))
}
}
func (s *Service) setSubjectStat(c context.Context, sid int64, stat *l.SubjectTotalStat, count, retryCnt int) (err error) {
for i := 0; i < retryCnt; i++ {
if err = s.dao.SetObjectStat(c, sid, stat, count); err == nil {
break
}
time.Sleep(100 * time.Millisecond)
}
return
}
// Ping reports the heath of services.
func (s *Service) Ping(c context.Context) (err error) {
return s.dao.Ping(c)
}
// Close kafaka consumer close.
func (s *Service) Close() (err error) {
defer s.waiter.Wait()
s.closed = true
if s.bnjTimeFinish == 0 {
s.bnj.AddCacheLessTime(context.Background(), s.bnjLessSecond)
}
s.cron.Stop()
s.dao.Close()
s.actSub.Close()
s.bnjSub.Close()
//s.vipSub.Close()
s.kfcSub.Close()
s.closed = true
return
}

View File

@@ -0,0 +1,44 @@
package service
import (
"context"
"flag"
"path/filepath"
"testing"
"time"
"go-common/app/job/main/activity/conf"
l "go-common/app/job/main/activity/model/like"
. "github.com/smartystreets/goconvey/convey"
)
var svf *Service
func init() {
dir, _ := filepath.Abs("../../cmd/activity-job-test.toml")
flag.Set("conf", dir)
if err := conf.Init(); err != nil {
panic(err)
}
if svf == nil {
svf = New(conf.Conf)
}
time.Sleep(time.Second)
}
func WithService(f func(s *Service)) func() {
return func() {
f(svf)
}
}
func TestService_LikeArc(t *testing.T) {
Convey("test archive view", t, WithService(func(s *Service) {
sub := &l.Subject{
ID: 1,
}
res, err := s.likeArc(context.Background(), sub)
So(err, ShouldBeNil)
So(res, ShouldNotBeNil)
}))
}

View File

@@ -0,0 +1,45 @@
package service
import (
"context"
"encoding/json"
actmdl "go-common/app/interface/main/activity/model/like"
l "go-common/app/job/main/activity/model/like"
"go-common/library/log"
)
// upSubject update act_subject cache .
func (s *Service) upSubject(c context.Context, upMsg json.RawMessage) (err error) {
var (
subObj = new(l.ActSubject)
)
if err = json.Unmarshal(upMsg, subObj); err != nil {
log.Error("upSubject json.Unmarshal(%s) error(%+v)", upMsg, err)
return
}
if err = s.actRPC.SubjectUp(c, &actmdl.ArgSubjectUp{Sid: subObj.ID}); err != nil {
log.Error("s.actRPC.SubjectUp(%d) error(%+v)", subObj.ID, err)
return
}
log.Info("upSubject success s.actRPC.SubjectUp(%d)", subObj.ID)
return
}
//func (s *Service) addElemeLottery(c context.Context, msg json.RawMessage) {
// var (
// vipContent = &l.VipActOrder{}
// )
// if err := json.Unmarshal(msg, vipContent); err != nil {
// log.Error("addElemeLottery json.Unmarshal(%s) error(%v)", msg, err)
// return
// }
// if vipContent.PanelType == "ele" {
// if err := s.dao.AddLotteryTimes(c, s.c.Rule.EleLotteryID, vipContent.Mid); err != nil {
// log.Error("s.dao.AddLotteryTimes(%d,%d) error(%v)", s.c.Rule.EleLotteryID, vipContent.Mid, err)
// return
// }
// log.Info("addElemeLottery has AddLotteryTimes %d", vipContent.Mid)
// }
// log.Info("addElemeLottery success id:%d,panee:%s", vipContent.ID, vipContent.PanelType)
//}