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,64 @@
package(default_visibility = ["//visibility:public"])
load(
"@io_bazel_rules_go//go:def.bzl",
"go_library",
"go_test",
)
go_library(
name = "go_default_library",
srcs = [
"dao.go",
"message.go",
"mysql.go",
"push.go",
],
importpath = "go-common/app/job/main/web-goblin/dao/esports",
tags = ["automanaged"],
visibility = ["//visibility:public"],
deps = [
"//app/job/main/web-goblin/conf:go_default_library",
"//app/job/main/web-goblin/model/esports:go_default_library",
"//app/service/main/archive/api: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/xstr:go_default_library",
"//vendor/github.com/pkg/errors:go_default_library",
],
)
filegroup(
name = "package-srcs",
srcs = glob(["**"]),
tags = ["automanaged"],
visibility = ["//visibility:private"],
)
filegroup(
name = "all-srcs",
srcs = [":package-srcs"],
tags = ["automanaged"],
visibility = ["//visibility:public"],
)
go_test(
name = "go_default_test",
srcs = [
"dao_test.go",
"message_test.go",
"mysql_test.go",
"push_test.go",
],
embed = [":go_default_library"],
rundir = ".",
tags = ["automanaged"],
deps = [
"//app/job/main/web-goblin/conf:go_default_library",
"//app/job/main/web-goblin/model/esports:go_default_library",
"//app/service/main/archive/api:go_default_library",
"//vendor/github.com/smartystreets/goconvey/convey:go_default_library",
],
)

View File

@ -0,0 +1,47 @@
package esports
import (
"context"
"go-common/app/job/main/web-goblin/conf"
"go-common/library/database/sql"
bm "go-common/library/net/http/blademaster"
)
const _pushURL = "/x/internal/push-strategy/task/add"
// Dao dao
type Dao struct {
c *conf.Config
// http client
http *bm.Client
messageHTTPClient *bm.Client
// push service URL
pushURL string
// db
db *sql.DB
}
// New init mysql db
func New(c *conf.Config) (dao *Dao) {
dao = &Dao{
c: c,
http: bm.NewClient(c.HTTPClient),
messageHTTPClient: bm.NewClient(c.MessageHTTPClient),
db: sql.NewMySQL(c.DB.Esports),
pushURL: c.Host.API + _pushURL,
}
return
}
// Close close the resource.
func (d *Dao) Close() {
}
// Ping ping dao
func (d *Dao) Ping(c context.Context) (err error) {
if err = d.db.Ping(c); err != nil {
return
}
return
}

View File

@ -0,0 +1,36 @@
package esports
import (
"flag"
"os"
"testing"
"go-common/app/job/main/web-goblin/conf"
)
var (
d *Dao
)
func TestMain(m *testing.M) {
if os.Getenv("DEPLOY_ENV") != "" {
flag.Set("app_id", "main.web-svr.web-goblin-job")
flag.Set("conf_token", "12e333e44103d9cba0d6c967f37dd311")
flag.Set("tree_id", "42274")
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/web-goblin-job-test.toml")
}
flag.Parse()
if err := conf.Init(); err != nil {
panic(err)
}
d = New(conf.Conf)
m.Run()
os.Exit(0)
}

View File

@ -0,0 +1,70 @@
package esports
import (
"context"
"net/url"
mdlesp "go-common/app/job/main/web-goblin/model/esports"
"go-common/library/ecode"
"go-common/library/log"
"go-common/library/xstr"
)
var _notify = "4"
// SendMessage send system notify.
func (d *Dao) SendMessage(mids []int64, msg string, contest *mdlesp.Contest) (err error) {
params := url.Values{}
params.Set("mid_list", xstr.JoinInts(mids))
params.Set("title", d.c.Rule.AlertTitle)
params.Set("mc", d.c.Message.MC)
params.Set("data_type", _notify)
params.Set("context", msg)
var res struct {
Code int `json:"code"`
}
err = d.messageHTTPClient.Post(context.Background(), d.c.Message.URL, "", params, &res)
if err != nil {
log.Error("SendMessage d.messageHTTPClient.Post(%s) error(%+v)", d.c.Message.URL+"?"+params.Encode(), err)
return
}
if res.Code != 0 {
log.Error("SendMessage url(%s) res code(%d)", d.c.Message.URL+"?"+params.Encode(), res.Code)
err = ecode.Int(res.Code)
}
return
}
//Batch 批量处理
func (d *Dao) Batch(list []int64, msg string, contest *mdlesp.Contest, batchSize int, f func(users []int64, msg string, contest *mdlesp.Contest) error) {
if msg == "" {
log.Warn("Batch msg is empty")
return
}
retry := d.c.Push.RetryTimes
for {
var (
mids []int64
err error
)
l := len(list)
if l == 0 {
break
} else if l <= batchSize {
mids = list[:l]
} else {
mids = list[:batchSize]
l = batchSize
}
list = list[l:]
for i := 0; i < retry; i++ {
if err = f(mids, msg, contest); err == nil {
break
}
}
if err != nil {
log.Error("Batch error(%v), params(%s)", err, msg)
}
}
}

View File

@ -0,0 +1,40 @@
package esports
import (
"testing"
mdlesp "go-common/app/job/main/web-goblin/model/esports"
"github.com/smartystreets/goconvey/convey"
)
func TestEsportsSendMessage(t *testing.T) {
var (
mids = []int64{}
msg = "2018 LPL 春季赛 中你订阅的赛程“2018-01-25 19:00 RNG VS SNG”即将开播快前去观看比赛吧 点击前往直播间"
contest = &mdlesp.Contest{}
)
mids = append(mids, 111)
mids = append(mids, 222)
convey.Convey("SendMessage", t, func(ctx convey.C) {
err := d.SendMessage(mids, msg, contest)
ctx.Convey("Then err should be nil.", func(ctx convey.C) {
ctx.So(err, convey.ShouldBeNil)
})
})
}
func TestEsportsBatch(t *testing.T) {
var (
list = []int64{}
msg = ""
contest = &mdlesp.Contest{}
batchSize = int(0)
f func(users []int64, msg string, contest *mdlesp.Contest) error
)
convey.Convey("Batch", t, func(ctx convey.C) {
d.Batch(list, msg, contest, batchSize, f)
ctx.Convey("No return values", func(ctx convey.C) {
})
})
}

View File

@ -0,0 +1,135 @@
package esports
import (
"context"
"fmt"
"strconv"
"time"
mdlesp "go-common/app/job/main/web-goblin/model/esports"
arcmdl "go-common/app/service/main/archive/api"
xsql "go-common/library/database/sql"
"go-common/library/log"
"go-common/library/xstr"
"github.com/pkg/errors"
)
const (
_contestsSQL = "SELECT c.id,c.stime,c.live_room,c.home_id,c.away_id,c.success_team,c.special,c.special_name,c.special_tips,s.title,s.sub_title FROM `es_contests` as c INNER JOIN `es_seasons` as s ON c.sid=s.id WHERE c.status = 0 AND c.stime >= ? and c.stime < ? "
_teamSQL = "SELECT id,title,sub_title FROM `es_teams` WHERE is_deleted = 0 AND (id = ? or id = ?)"
_arcSQL = "SELECT id,aid,score,is_deleted FROM `es_archives` WHERE is_deleted = 0 AND id > ? ORDER BY id ASC LIMIT ? "
_arcEditSQL = "UPDATE es_archives SET score = CASE %s END WHERE aid IN (%s)"
)
// Contests contests by time.
func (d *Dao) Contests(c context.Context, stime, etime int64) (res []*mdlesp.Contest, err error) {
var (
rows *xsql.Rows
)
if rows, err = d.db.Query(c, _contestsSQL, stime, etime); err != nil {
log.Error("Contests:d.db.Query(%d) error(%v)", stime, err)
return
}
defer rows.Close()
for rows.Next() {
r := new(mdlesp.Contest)
if err = rows.Scan(&r.ID, &r.Stime, &r.LiveRoom, &r.HomeID, &r.AwayID, &r.SuccessTeam, &r.Special, &r.SpecialName, &r.SpecialTips, &r.SeasonTitle, &r.SeasonSubTitle); err != nil {
log.Error("Contests:row.Scan() error(%v)", err)
return
}
res = append(res, r)
}
if err = rows.Err(); err != nil {
log.Error("rows.Err() error(%v)", err)
}
return
}
// Teams teams by id.
func (d *Dao) Teams(c context.Context, homeID, awayID int64) (res []*mdlesp.Team, err error) {
var (
rows *xsql.Rows
)
if rows, err = d.db.Query(c, _teamSQL, homeID, awayID); err != nil {
log.Error("Teams:d.db.Query homeID(%d) awayID(%d) error(%v)", homeID, awayID, err)
return
}
defer rows.Close()
for rows.Next() {
r := new(mdlesp.Team)
if err = rows.Scan(&r.ID, &r.Title, &r.SubTitle); err != nil {
log.Error("Teams:row.Scan() error(%v)", err)
return
}
res = append(res, r)
}
if err = rows.Err(); err != nil {
log.Error("rows.Err() error(%v)", err)
}
return
}
// Arcs archives by ids.
func (d *Dao) Arcs(c context.Context, id int64, limit int) (res []*mdlesp.Arc, err error) {
var (
rows *xsql.Rows
)
if rows, err = d.db.Query(c, _arcSQL, id, limit); err != nil {
log.Error("Arcs:d.db.Query id(%d) limit(%d) error(%v)", id, limit, err)
return
}
defer rows.Close()
for rows.Next() {
r := new(mdlesp.Arc)
if err = rows.Scan(&r.ID, &r.Aid, &r.Score, &r.IsDeleted); err != nil {
log.Error("Arcs:row.Scan() error(%v)", err)
return
}
res = append(res, r)
}
if err = rows.Err(); err != nil {
log.Error("rows.Err() error(%v)", err)
}
return
}
// UpArcScore update archive score.
func (d *Dao) UpArcScore(c context.Context, partArcs []*mdlesp.Arc, arcs map[int64]*arcmdl.Arc) (err error) {
var (
caseStr string
aids []int64
score int64
)
for _, v := range partArcs {
if arc, ok := arcs[v.Aid]; ok {
score = d.score(arc)
} else {
continue
}
caseStr = fmt.Sprintf("%s WHEN aid = %d THEN %d", caseStr, v.Aid, score)
aids = append(aids, v.Aid)
}
if len(aids) == 0 {
return
}
if _, err = d.db.Exec(c, fmt.Sprintf(_arcEditSQL, caseStr, xstr.JoinInts(aids))); err != nil {
err = errors.Wrapf(err, "UpArcScore d.db.Exec")
}
return
}
func (d *Dao) score(arc *arcmdl.Arc) (res int64) {
tmpRs := float64(arc.Stat.Coin)*d.c.Rule.CoinPercent +
float64(arc.Stat.Fav)*d.c.Rule.FavPercent + float64(arc.Stat.Danmaku)*d.c.Rule.DmPercent +
float64(arc.Stat.Reply)*d.c.Rule.ReplyPercent + float64(arc.Stat.View)*d.c.Rule.ViewPercent +
float64(arc.Stat.Like)*d.c.Rule.LikePercent + float64(arc.Stat.Share)*d.c.Rule.SharePercent
now := time.Now()
hours := now.Sub(arc.PubDate.Time()).Hours()
if hours/24 <= d.c.Rule.NewDay {
tmpRs = tmpRs * 1.5
}
decimal, _ := strconv.ParseFloat(fmt.Sprintf("%.2f", tmpRs), 64)
res = int64(decimal * 100)
return
}

View File

@ -0,0 +1,82 @@
package esports
import (
"context"
"testing"
mdlesp "go-common/app/job/main/web-goblin/model/esports"
arcmdl "go-common/app/service/main/archive/api"
"github.com/smartystreets/goconvey/convey"
)
func TestEsportsContests(t *testing.T) {
var (
c = context.Background()
stime = int64(1539590040)
etime = int64(1539590040)
)
convey.Convey("Contests", t, func(ctx convey.C) {
res, err := d.Contests(c, stime, etime)
ctx.Convey("Then err should be nil.res should not be nil.", func(ctx convey.C) {
ctx.So(err, convey.ShouldBeNil)
ctx.So(len(res), convey.ShouldBeGreaterThanOrEqualTo, 0)
})
})
}
func TestEsportsTeams(t *testing.T) {
var (
c = context.Background()
homeID = int64(1)
awayID = int64(2)
)
convey.Convey("Teams", t, func(ctx convey.C) {
res, err := d.Teams(c, homeID, awayID)
ctx.Convey("Then err should be nil.res should not be nil.", func(ctx convey.C) {
ctx.So(err, convey.ShouldBeNil)
ctx.So(len(res), convey.ShouldBeGreaterThanOrEqualTo, 0)
})
})
}
func TestEsportsArcs(t *testing.T) {
var (
c = context.Background()
id = int64(1)
limit = int(50)
)
convey.Convey("Arcs", t, func(ctx convey.C) {
res, err := d.Arcs(c, id, limit)
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 TestEsportsUpArcScore(t *testing.T) {
var (
c = context.Background()
partArcs = []*mdlesp.Arc{}
arcs map[int64]*arcmdl.Arc
)
convey.Convey("UpArcScore", t, func(ctx convey.C) {
err := d.UpArcScore(c, partArcs, arcs)
ctx.Convey("Then err should be nil.", func(ctx convey.C) {
ctx.So(err, convey.ShouldBeNil)
})
})
}
func TestEsportsscore(t *testing.T) {
var (
arc = &arcmdl.Arc{}
)
convey.Convey("score", t, func(ctx convey.C) {
res := d.score(arc)
ctx.Convey("Then res should not be nil.", func(ctx convey.C) {
ctx.So(res, convey.ShouldNotBeNil)
})
})
}

View File

@ -0,0 +1,112 @@
package esports
import (
"bytes"
"context"
"crypto/md5"
"encoding/hex"
"fmt"
"io"
"mime/multipart"
"net/http"
"net/url"
"sort"
"strconv"
"time"
mdlesp "go-common/app/job/main/web-goblin/model/esports"
"go-common/library/log"
"go-common/library/xstr"
)
const (
_pinkVersion = 1
_linkLive = 3
)
type _response struct {
Code int `json:"code"`
Data int `json:"data"`
}
// NoticeUser pushs the notification to users.
func (d *Dao) NoticeUser(mids []int64, body string, contest *mdlesp.Contest) (err error) {
var strMids string
if d.c.Push.OnlyMids == "" {
strMids = xstr.JoinInts(mids)
} else {
strMids = d.c.Push.OnlyMids
}
uuid := d.getUUID(strMids, contest)
buf := new(bytes.Buffer)
w := multipart.NewWriter(buf)
w.WriteField("app_id", strconv.Itoa(_pinkVersion))
w.WriteField("business_id", strconv.Itoa(d.c.Push.BusinessID))
w.WriteField("alert_title", d.c.Push.Title)
w.WriteField("alert_body", body)
w.WriteField("mids", strMids)
w.WriteField("link_type", strconv.Itoa(_linkLive))
w.WriteField("link_value", strconv.FormatInt(contest.LiveRoom, 10))
w.WriteField("uuid", uuid)
w.Close()
//签名
query := map[string]string{
"ts": strconv.FormatInt(time.Now().Unix(), 10),
"appkey": d.c.App.Key,
}
query["sign"] = d.signature(query, d.c.App.Secret)
url := fmt.Sprintf("%s?ts=%s&appkey=%s&sign=%s", d.pushURL, query["ts"], query["appkey"], query["sign"])
req, err := http.NewRequest(http.MethodPost, url, buf)
if err != nil {
log.Error("http.NewRequest(%s) error(%v)", url, err)
return
}
req.Header.Set("Content-Type", w.FormDataContentType())
req.Header.Set("Authorization", fmt.Sprintf("token=%s", d.c.Push.BusinessToken))
res := &_response{}
if err = d.http.Do(context.TODO(), req, &res); err != nil {
log.Error("httpClient.Do() error(%v)", err)
return
}
if res.Code != 0 || res.Data == 0 {
log.Error("push failed mids_total(%d) body(%s) response(%+v)", len(mids), body, res)
} else {
log.Info("push success mids_total(%d) body(%s) response(%+v)", len(mids), body, res)
}
return
}
//signature 加密算法
func (d *Dao) signature(params map[string]string, secret string) string {
keys := []string{}
for k := range params {
keys = append(keys, k)
}
sort.Strings(keys)
buf := bytes.Buffer{}
for _, k := range keys {
if buf.Len() > 0 {
buf.WriteByte('&')
}
buf.WriteString(url.QueryEscape(k) + "=")
buf.WriteString(url.QueryEscape(params[k]))
}
//加密
h := md5.New()
io.WriteString(h, buf.String()+secret)
return fmt.Sprintf("%x", h.Sum(nil))
}
func (d *Dao) getUUID(mids string, contest *mdlesp.Contest) string {
var b bytes.Buffer
b.WriteString(strconv.Itoa(d.c.Push.BusinessID))
b.WriteString(strconv.FormatInt(contest.ID, 10))
b.WriteString(strconv.FormatInt(contest.Stime, 10))
b.WriteString(strconv.FormatInt(time.Now().UnixNano(), 10))
b.WriteString(mids)
mh := md5.Sum(b.Bytes())
uuid := hex.EncodeToString(mh[:])
return uuid
}

View File

@ -0,0 +1,49 @@
package esports
import (
"testing"
mdlesp "go-common/app/job/main/web-goblin/model/esports"
"github.com/smartystreets/goconvey/convey"
)
func TestEsportsNoticeUser(t *testing.T) {
var (
mids = []int64{11, 22, 33}
body = ""
contest = &mdlesp.Contest{}
)
convey.Convey("NoticeUser", t, func(ctx convey.C) {
err := d.NoticeUser(mids, body, contest)
ctx.Convey("Then err should be nil.", func(ctx convey.C) {
ctx.So(err, convey.ShouldBeNil)
})
})
}
func TestEsportssignature(t *testing.T) {
var (
params map[string]string
secret = ""
)
convey.Convey("signature", t, func(ctx convey.C) {
p1 := d.signature(params, secret)
ctx.Convey("Then p1 should not be nil.", func(ctx convey.C) {
ctx.So(p1, convey.ShouldNotBeNil)
})
})
}
func TestEsportsgetUUID(t *testing.T) {
var (
mids = "11,22,33"
contest = &mdlesp.Contest{}
)
convey.Convey("getUUID", t, func(ctx convey.C) {
p1 := d.getUUID(mids, contest)
ctx.Convey("Then p1 should not be nil.", func(ctx convey.C) {
ctx.So(p1, convey.ShouldNotBeNil)
})
})
}