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,65 @@
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",
"memcache_test.go",
"mysql_test.go",
"redis_test.go",
"wechat_test.go",
],
embed = [":go_default_library"],
rundir = ".",
tags = ["automanaged"],
deps = [
"//app/service/main/push-strategy/conf:go_default_library",
"//app/service/main/push/model: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 = [
"dao.go",
"memcache.go",
"mysql.go",
"redis.go",
"wechat.go",
],
importpath = "go-common/app/service/main/push-strategy/dao",
tags = ["automanaged"],
visibility = ["//visibility:public"],
deps = [
"//app/service/main/push-strategy/conf:go_default_library",
"//app/service/main/push/model:go_default_library",
"//library/cache/memcache:go_default_library",
"//library/cache/redis:go_default_library",
"//library/database/sql:go_default_library",
"//library/log:go_default_library",
"//library/net/http/blademaster:go_default_library",
"//library/stat/prom:go_default_library",
],
)
filegroup(
name = "package-srcs",
srcs = glob(["**"]),
tags = ["automanaged"],
visibility = ["//visibility:private"],
)
filegroup(
name = "all-srcs",
srcs = [":package-srcs"],
tags = ["automanaged"],
visibility = ["//visibility:public"],
)

View File

@@ -0,0 +1,85 @@
package dao
import (
"context"
"time"
"go-common/app/service/main/push-strategy/conf"
"go-common/library/cache/memcache"
"go-common/library/cache/redis"
xsql "go-common/library/database/sql"
xhttp "go-common/library/net/http/blademaster"
"go-common/library/stat/prom"
)
// Dao .
type Dao struct {
c *conf.Config
db *xsql.DB
redis *redis.Pool
mc *memcache.Pool
httpClient *xhttp.Client
appsStmt *xsql.Stmt
businessesStmt *xsql.Stmt
addTaskStmt *xsql.Stmt
taskStmt *xsql.Stmt
settingsByRangeStmt *xsql.Stmt
maxSettingIDStmt *xsql.Stmt
mcUUIDExpire int32
mcCDExpire int32
redisLimitDayExpire int32
}
// New new dao.
func New(c *conf.Config) (d *Dao) {
d = &Dao{
c: c,
db: xsql.NewMySQL(c.MySQL),
httpClient: xhttp.NewClient(c.HTTPClient),
redis: redis.NewPool(c.Redis.Config),
mc: memcache.NewPool(c.Memcache.Config),
mcUUIDExpire: int32(time.Duration(c.Memcache.UUIDExpire) / time.Second),
mcCDExpire: int32(time.Duration(c.Memcache.CDExpire) / time.Second),
redisLimitDayExpire: int32(time.Duration(c.Redis.LimitDayExpire) / time.Second),
}
d.appsStmt = d.db.Prepared(_appsSQL)
d.businessesStmt = d.db.Prepared(_businessesSQL)
d.addTaskStmt = d.db.Prepared(_addTaskSQL)
d.taskStmt = d.db.Prepared(_taskSQL)
d.settingsByRangeStmt = d.db.Prepared(_settingsByRangeSQL)
d.maxSettingIDStmt = d.db.Prepared(_maxSettingIDSQL)
return
}
// PromError prom error
func PromError(name string) {
prom.BusinessErrCount.Incr(name)
}
// PromInfo add prom info
func PromInfo(name string) {
prom.BusinessInfoCount.Incr(name)
}
// BeginTx begin transaction.
func (d *Dao) BeginTx(ctx context.Context) (*xsql.Tx, error) {
return d.db.Begin(ctx)
}
// Ping .
func (d *Dao) Ping(ctx context.Context) (err error) {
if err = d.pingRedis(ctx); err != nil {
return
}
if err = d.pingMC(ctx); err != nil {
return
}
return d.db.Ping(ctx)
}
// Close .
func (d *Dao) Close() {
d.mc.Close()
d.redis.Close()
d.db.Close()
}

View File

@@ -0,0 +1,39 @@
package dao
import (
"flag"
"os"
"path/filepath"
"testing"
"go-common/app/service/main/push-strategy/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.push-strategy")
flag.Set("conf_token", "a626fc404c86f14654f0a74d80fc1da3")
flag.Set("tree_id", "26092")
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 {
dir, _ := filepath.Abs("../cmd/push-strategy-test.toml")
flag.Set("conf", dir)
}
flag.Parse()
if err := conf.Init(); err != nil {
panic(err)
}
d = New(conf.Conf)
d.httpClient.SetTransport(gock.DefaultTransport)
m.Run()
os.Exit(0)
}

View File

@@ -0,0 +1,115 @@
package dao
import (
"context"
"fmt"
"go-common/library/cache/memcache"
"go-common/library/log"
)
const (
_prefixUUID = "uuid_%d_%s"
_prefixCD = "cd_%d_%d"
)
func uuidKey(biz int64, uuid string) string {
return fmt.Sprintf(_prefixUUID, biz, uuid)
}
func cdKey(app, mid int64) string {
return fmt.Sprintf(_prefixCD, app, mid)
}
// pingMc ping memcache
func (d *Dao) pingMC(c context.Context) (err error) {
conn := d.mc.Get(c)
defer conn.Close()
item := memcache.Item{Key: "ping", Value: []byte{1}, Expiration: d.mcUUIDExpire}
err = conn.Set(&item)
return
}
// ExistsUUIDCache gets uuid from cache.
func (d *Dao) ExistsUUIDCache(c context.Context, biz int64, uuid string) (exist bool, err error) {
var (
conn = d.mc.Get(c)
key = uuidKey(biz, uuid)
)
defer conn.Close()
if _, err = conn.Get(key); err != nil {
if err == memcache.ErrNotFound {
err = nil
return
}
PromError("mc:get uuid")
log.Error("ExistsUUIDCache() conn.Get(%s) error(%v)", key, err)
return
}
exist = true
return
}
// AddUUIDCache adds uuid cache.
func (d *Dao) AddUUIDCache(c context.Context, biz int64, uuid string) (err error) {
var (
conn = d.mc.Get(c)
key = uuidKey(biz, uuid)
item = &memcache.Item{Key: key, Value: []byte{}, Expiration: d.mcUUIDExpire}
)
defer conn.Close()
if err = conn.Set(item); err != nil {
PromError("mc:add uuid")
log.Error("AddUUIDCache() conn.Set(%+v) error(%v)", item, err)
}
return
}
// DelUUIDCache delete uuid cache.
func (d *Dao) DelUUIDCache(c context.Context, biz int64, uuid string) (err error) {
var (
conn = d.mc.Get(c)
key = uuidKey(biz, uuid)
)
defer conn.Close()
if err = conn.Delete(key); err != nil {
PromError("mc:del uuid")
log.Error("DelUUIDCache(%s) error(%v)", key, err)
}
return
}
// ExistsCDCache gets cd from cache.
func (d *Dao) ExistsCDCache(ctx context.Context, app, mid int64) (exist bool, err error) {
var (
conn = d.mc.Get(ctx)
key = cdKey(app, mid)
)
defer conn.Close()
if _, err = conn.Get(key); err != nil {
if err == memcache.ErrNotFound {
err = nil
return
}
PromError("mc:get cd")
log.Error("ExistsCDCache() conn.Get(%s) error(%v)", key, err)
return
}
exist = true
return
}
// AddCDCache adds cd cache.
func (d *Dao) AddCDCache(ctx context.Context, app, mid int64) (err error) {
var (
conn = d.mc.Get(ctx)
key = cdKey(app, mid)
item = &memcache.Item{Key: key, Value: []byte{}, Expiration: d.mcCDExpire}
)
defer conn.Close()
if err = conn.Set(item); err != nil {
PromError("mc:add cd")
log.Error("AddCDCache() conn.Set(%+v) error(%v)", item, err)
}
return
}

View File

@@ -0,0 +1,56 @@
package dao
import (
"context"
"testing"
"github.com/smartystreets/goconvey/convey"
)
var (
biz = int64(1)
uuid = "uuid"
)
func TestDaopingMC(t *testing.T) {
convey.Convey("pingMC", t, func(ctx convey.C) {
err := d.pingMC(context.Background())
ctx.Convey("Then err should be nil.", func(ctx convey.C) {
ctx.So(err, convey.ShouldBeNil)
})
})
}
func addUUIDCache() error {
return d.AddUUIDCache(context.Background(), biz, uuid)
}
func TestDaoExistsUUIDCache(t *testing.T) {
addUUIDCache()
convey.Convey("ExistsUUIDCache", t, func(ctx convey.C) {
exist, err := d.ExistsUUIDCache(context.Background(), biz, uuid)
ctx.Convey("Then err should be nil.exist should not be nil.", func(ctx convey.C) {
ctx.So(err, convey.ShouldBeNil)
ctx.So(exist, convey.ShouldNotBeNil)
})
})
}
func TestDaoAddUUIDCache(t *testing.T) {
convey.Convey("AddUUIDCache", t, func(ctx convey.C) {
err := addUUIDCache()
ctx.Convey("Then err should be nil.", func(ctx convey.C) {
ctx.So(err, convey.ShouldBeNil)
})
})
}
func TestDaoDelUUIDCache(t *testing.T) {
addUUIDCache()
convey.Convey("DelUUIDCache", t, func(ctx convey.C) {
err := d.DelUUIDCache(context.Background(), biz, uuid)
ctx.Convey("Then err should be nil.", func(ctx convey.C) {
ctx.So(err, convey.ShouldBeNil)
})
})
}

View File

@@ -0,0 +1,178 @@
package dao
import (
"context"
"database/sql"
"encoding/json"
"strconv"
"time"
pushmdl "go-common/app/service/main/push/model"
xsql "go-common/library/database/sql"
"go-common/library/log"
)
const (
// task
_addTaskSQL = "INSERT INTO push_tasks (job,type,app_id,business_id,platform,title,summary,link_type,link_value,build,sound,vibration,pass_through,mid_file,progress,push_time,expire_time,status,`group`,image_url,extra) VALUES (?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?)"
_taskSQL = "SELECT id,job,type,app_id,business_id,platform,title,summary,link_type,link_value,build,sound,vibration,pass_through,mid_file,progress,push_time,expire_time,status,`group`,image_url,extra FROM push_tasks WHERE id=?"
// app && business
_appsSQL = "SELECT id,name,push_limit_user FROM push_apps WHERE dtime=0"
_businessesSQL = "SELECT id,app_id,name,description,token,sound,vibration,receive_switch,push_switch,silent_time,push_limit_user,whitelist FROM push_business WHERE dtime=0"
// setting
_settingsByRangeSQL = "SELECT mid,value FROM push_user_settings WHERE id>? AND id<=? AND dtime=0"
_maxSettingIDSQL = "SELECT MAX(id) FROM push_user_settings"
)
// Apps get all app info
func (d *Dao) Apps(ctx context.Context) (res map[int64]*pushmdl.APP, err error) {
rows, err := d.appsStmt.Query(ctx)
if err != nil {
log.Error("d.appsStmt.Query() error(%v)", err)
PromError("mysql:查询应用")
return
}
defer rows.Close()
res = make(map[int64]*pushmdl.APP)
for rows.Next() {
app := new(pushmdl.APP)
if err = rows.Scan(&app.ID, &app.Name, &app.PushLimitUser); err != nil {
log.Error("d.Apps() Scan() error(%v)", err)
PromError("mysql:查询应用Scan")
return
}
res[app.ID] = app
}
err = rows.Err()
return
}
// Businesses gets all business info.
func (d *Dao) Businesses(ctx context.Context) (res map[int64]*pushmdl.Business, err error) {
rows, err := d.businessesStmt.Query(ctx)
if err != nil {
log.Error("d.businessesStmt.Query() error(%v)", err)
PromError("mysql:查询业务方")
return
}
defer rows.Close()
res = make(map[int64]*pushmdl.Business)
for rows.Next() {
var (
silentTime string
b = &pushmdl.Business{}
)
if err = rows.Scan(&b.ID, &b.APPID, &b.Name, &b.Desc, &b.Token,
&b.Sound, &b.Vibration, &b.ReceiveSwitch, &b.PushSwitch, &silentTime, &b.PushLimitUser, &b.Whitelist); err != nil {
PromError("mysql:查询业务方Scan")
log.Error("d.Business() Scan() error(%v)", err)
return
}
b.SilentTime = pushmdl.ParseSilentTime(silentTime)
res[b.ID] = b
}
err = rows.Err()
return
}
// AddTask adds task.
func (d *Dao) AddTask(ctx context.Context, t *pushmdl.Task) (id int64, err error) {
var (
res sql.Result
platform = pushmdl.JoinInts(t.Platform)
build, _ = json.Marshal(t.Build)
progress, _ = json.Marshal(t.Progress)
extra, _ = json.Marshal(t.Extra)
)
if res, err = d.addTaskStmt.Exec(ctx, t.Job, t.Type, t.APPID, t.BusinessID, platform, t.Title, t.Summary, t.LinkType, t.LinkValue,
build, t.Sound, t.Vibration, t.PassThrough, t.MidFile, progress, t.PushTime, t.ExpireTime, t.Status, t.Group, t.ImageURL, extra); err != nil {
log.Error("d.AddTask(%+v) error(%v)", t, err)
PromError("mysql:添加推送任务")
return
}
id, err = res.LastInsertId()
return
}
// Task loads task by id.
func (d *Dao) Task(ctx context.Context, id int64) (t *pushmdl.Task, err error) {
var (
platform string
build string
progress string
extra string
now = time.Now()
)
t = &pushmdl.Task{Progress: &pushmdl.Progress{}, Extra: &pushmdl.TaskExtra{}}
if err = d.taskStmt.QueryRow(ctx, id).Scan(&id, &t.Job, &t.Type, &t.APPID, &t.BusinessID, &platform, &t.Title, &t.Summary, &t.LinkType, &t.LinkValue, &build,
&t.Sound, &t.Vibration, &t.PassThrough, &t.MidFile, &progress, &t.PushTime, &t.ExpireTime, &t.Status, &t.Group, &t.ImageURL, &extra); err != nil {
if err == sql.ErrNoRows {
t = nil
err = nil
return
}
log.Error("d.taskStmt.QueryRow(%d) error(%v)", id, now, err)
PromError("mysql:按ID查询任务")
return
}
t.ID = strconv.FormatInt(id, 10)
t.Platform = pushmdl.SplitInts(platform)
t.Build = pushmdl.ParseBuild(build)
if progress != "" {
if err = json.Unmarshal([]byte(progress), t.Progress); err != nil {
log.Error("json.Unmarshal(%s) error(%v)", progress, err)
PromError("mysql:unmarshal progress")
}
}
if extra != "" {
if err = json.Unmarshal([]byte(extra), t.Extra); err != nil {
log.Error("json.Unmarshal(%s) extra error(%v)", extra, err)
PromError("mysql:unmarshal extra")
}
}
return
}
// MaxSettingID gets max setting id in DB.
func (d *Dao) MaxSettingID(ctx context.Context) (id int64, err error) {
if err = d.maxSettingIDStmt.QueryRow(ctx).Scan(&id); err != nil {
if err == sql.ErrNoRows {
err = nil
return
}
log.Error("d.maxSettingIDStmt.QueryRow.Scan error(%v)", err)
PromError("db:max setting id")
}
return
}
// SettingsByRange gets user setting by range.
func (d *Dao) SettingsByRange(ctx context.Context, start, end int64) (res map[int64]map[int]int, err error) {
var rows *xsql.Rows
if rows, err = d.settingsByRangeStmt.Query(ctx, start, end); err != nil {
log.Error("d.settingsStmt.Query(%d,%d) error(%v)", start, end, err)
PromError("mysql:Settings")
return
}
defer rows.Close()
res = make(map[int64]map[int]int)
for rows.Next() {
var (
mid int64
v string
st = make(map[int]int)
)
if err = rows.Scan(&mid, &v); err != nil {
PromError("mysql:Settings scan")
log.Error("d.Settings() Scan() error(%v)", err)
return
}
if e := json.Unmarshal([]byte(v), &st); e != nil {
log.Error("d.Settings() json unmarshal(%s) error(%v)", v, st)
continue
}
res[mid] = st
}
err = rows.Err()
return
}

View File

@@ -0,0 +1,69 @@
package dao
import (
"context"
"testing"
pushmdl "go-common/app/service/main/push/model"
"github.com/smartystreets/goconvey/convey"
)
func TestDaoBusinesses(t *testing.T) {
convey.Convey("Businesses", t, func(ctx convey.C) {
res, err := d.Businesses(context.Background())
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 addTask() (id int64, err error) {
t := &pushmdl.Task{APPID: 1}
return d.AddTask(context.Background(), t)
}
func TestDaoAddTask(t *testing.T) {
convey.Convey("AddTask", t, func(ctx convey.C) {
id, err := addTask()
ctx.Convey("Then err should be nil.id should not be nil.", func(ctx convey.C) {
ctx.So(err, convey.ShouldBeNil)
ctx.So(id, convey.ShouldBeGreaterThan, 0)
})
})
}
func TestDaoTask(t *testing.T) {
id, _ := addTask()
convey.Convey("Task", t, func(ctx convey.C) {
no, err := d.Task(context.Background(), id)
ctx.Convey("Then err should be nil.no should not be nil.", func(ctx convey.C) {
ctx.So(err, convey.ShouldBeNil)
ctx.So(no, convey.ShouldNotBeNil)
})
})
}
func TestDaoMaxSettingID(t *testing.T) {
convey.Convey("MaxSettingID", t, func(ctx convey.C) {
_, err := d.MaxSettingID(context.Background())
ctx.Convey("Then err should be nil.", func(ctx convey.C) {
ctx.So(err, convey.ShouldBeNil)
})
})
}
func TestDaoSettingsByRange(t *testing.T) {
var (
start = int64(0)
end = int64(1000)
)
convey.Convey("SettingsByRange", t, func(ctx convey.C) {
res, err := d.SettingsByRange(context.Background(), start, end)
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,155 @@
package dao
import (
"context"
"fmt"
"go-common/library/cache/redis"
"go-common/library/log"
)
const (
_prefixLimitDay = "ld_%d_%d_%s"
_prefixLimitBiz = "lb_%d_%d_%s_%d"
_prefixLimitNotLive = "lnl_%d_%s"
)
func limitDayKey(day string, app, mid int64) string {
return fmt.Sprintf(_prefixLimitDay, app, mid, day)
}
func limitBizKey(day string, app, mid, biz int64) string {
return fmt.Sprintf(_prefixLimitBiz, app, mid, day, biz)
}
func limitNotLiveKey(day string, mid int64) string {
return fmt.Sprintf(_prefixLimitNotLive, mid, day)
}
// pingRedis ping redis.
func (d *Dao) pingRedis(ctx context.Context) (err error) {
conn := d.redis.Get(ctx)
defer conn.Close()
if _, err = conn.Do("SET", "PING", "PONG"); err != nil {
PromError("redis: ping remote")
log.Error("remote redis: conn.Do(SET,PING,PONG) error(%v)", err)
}
return
}
// LimitDayCache gets limit cache by day & mid.
// 测试用,业务用不着
func (d *Dao) LimitDayCache(ctx context.Context, day string, app, mid int64) (count int, err error) {
var (
key = limitDayKey(day, app, mid)
conn = d.redis.Get(ctx)
)
defer conn.Close()
if count, err = redis.Int(conn.Do("GET", key)); err != nil {
PromError("redis:LimitDayCache")
log.Error("LimitDayCache(%s,%d,%d) error(%v)", day, app, mid, err)
}
return
}
// IncrLimitDayCache increases and gets limit cache by day & mid.
func (d *Dao) IncrLimitDayCache(ctx context.Context, day string, app, mid int64) (count int, err error) {
var (
key = limitDayKey(day, app, mid)
conn = d.redis.Get(ctx)
)
defer conn.Close()
if err = conn.Send("INCR", key); err != nil {
PromError("redis:IncrLimitDayCache")
log.Error("IncrLimitDayCache(%s,%d,%d) error(%v)", day, app, mid, err)
return
}
if err = conn.Send("EXPIRE", key, d.redisLimitDayExpire); err != nil {
PromError("redis:IncrLimitDayCache:expire")
log.Error("IncrLimitDayCache(%s,%d,%d) expire error(%v)", day, app, mid, err)
return
}
if err = conn.Flush(); err != nil {
PromError("redis:IncrLimitDayCache:flush")
log.Error("IncrLimitDayCache(%s,%d,%d) flush error(%v)", day, app, mid, err)
return
}
if count, err = redis.Int(conn.Receive()); err != nil {
PromError("redis:IncrLimitDayCache:receive:incr")
log.Error("IncrLimitDayCache(%s,%d,%d) receive incr error(%+v)", day, app, mid, err)
return
}
if _, err = conn.Receive(); err != nil {
PromError("redis:IncrLimitDayCache:receive:expire")
log.Error("IncrLimitDayCache(%s,%d,%d) receive expire error(%+v)", day, app, mid, err)
}
return
}
// IncrLimitBizCache increases and gets limit cache by day & mid & bisiness.
func (d *Dao) IncrLimitBizCache(ctx context.Context, day string, app, mid, biz int64) (count int, err error) {
var (
key = limitBizKey(day, app, mid, biz)
conn = d.redis.Get(ctx)
)
defer conn.Close()
if err = conn.Send("INCR", key); err != nil {
PromError("redis:IncrLimitBizCache")
log.Error("IncrLimitBizCache(%s,%d,%d,%d) error(%v)", day, app, mid, biz, err)
return
}
if err = conn.Send("EXPIRE", key, d.redisLimitDayExpire); err != nil {
PromError("redis:IncrLimitBizCache:expire")
log.Error("IncrLimitBizCache(%s,%d,%d,%d) expire error(%v)", day, app, mid, biz, err)
return
}
if err = conn.Flush(); err != nil {
PromError("redis:IncrLimitBizCache:flush")
log.Error("IncrLimitBizCache(%s,%d,%d,%d) flush error(%v)", day, app, mid, biz, err)
return
}
if count, err = redis.Int(conn.Receive()); err != nil {
PromError("redis:IncrLimitBizCache:receive:incr")
log.Error("IncrLimitBizCache(%s,%d,%d,%d) receive incr error(%+v)", day, app, mid, biz, err)
return
}
if _, err = conn.Receive(); err != nil {
PromError("redis:IncrLimitBizCache:receive:expire")
log.Error("IncrLimitBizCache(%s,%d,%d,%d) receive expire error(%+v)", day, app, mid, biz, err)
}
return
}
// IncrLimitNotLiveCache increases and gets not live limit cache by day & mid.
func (d *Dao) IncrLimitNotLiveCache(ctx context.Context, day string, mid int64) (count int, err error) {
var (
key = limitNotLiveKey(day, mid)
conn = d.redis.Get(ctx)
)
defer conn.Close()
if err = conn.Send("INCR", key); err != nil {
PromError("redis:IncrLimitNotLiveCache")
log.Error("IncrLimitNotLiveCache(%s,%d) error(%v)", day, mid, err)
return
}
if err = conn.Send("EXPIRE", key, d.redisLimitDayExpire); err != nil {
PromError("redis:IncrLimitNotLiveCache:expire")
log.Error("IncrLimitNotLiveCache(%s,%d) expire error(%v)", day, mid, err)
return
}
if err = conn.Flush(); err != nil {
PromError("redis:IncrLimitNotLiveCache:flush")
log.Error("IncrLimitNotLiveCache(%s,%d) flush error(%v)", day, mid, err)
return
}
if count, err = redis.Int(conn.Receive()); err != nil {
PromError("redis:IncrLimitNotLiveCache:receive:incr")
log.Error("IncrLimitNotLiveCache(%s,%d) receive incr error(%+v)", day, mid, err)
return
}
if _, err = conn.Receive(); err != nil {
PromError("redis:IncrLimitNotLiveCache:receive:expire")
log.Error("IncrLimitNotLiveCache(%s,%d) receive expire error(%+v)", day, mid, err)
}
return
}

View File

@@ -0,0 +1,64 @@
package dao
import (
"context"
"testing"
"github.com/smartystreets/goconvey/convey"
)
var (
day = "20180808"
mid = int64(91221505)
app = int64(1)
)
func incrLimitDayCache() (int, error) {
return d.IncrLimitDayCache(context.Background(), day, app, mid)
}
func TestDaoLimitDayCache(t *testing.T) {
incrLimitDayCache()
convey.Convey("LimitDayCache", t, func(ctx convey.C) {
count, err := d.LimitDayCache(context.Background(), day, app, mid)
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.ShouldBeGreaterThan, 0)
})
})
}
func TestDaoIncrLimitDayCache(t *testing.T) {
convey.Convey("IncrLimitDayCache", t, func(ctx convey.C) {
count, err := incrLimitDayCache()
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.ShouldBeGreaterThan, 0)
})
})
}
func incrLimitNotLiveCache() (int, error) {
return d.IncrLimitNotLiveCache(context.Background(), day, mid)
}
func TestDaoIncrLimitBizCache(t *testing.T) {
incrLimitNotLiveCache()
convey.Convey("IncrLimitBizCache", t, func(ctx convey.C) {
count, err := d.IncrLimitBizCache(context.Background(), day, app, mid, biz)
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.ShouldBeGreaterThan, 0)
})
})
}
func TestDaoIncrLimitNotLiveCache(t *testing.T) {
convey.Convey("IncrLimitNotLiveCache", t, func(ctx convey.C) {
count, err := incrLimitNotLiveCache()
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.ShouldBeGreaterThan, 0)
})
})
}

View File

@@ -0,0 +1,81 @@
package dao
import (
"bytes"
"context"
"crypto/md5"
"encoding/json"
"fmt"
"io"
"net/http"
"net/url"
"sort"
"strconv"
"time"
"go-common/library/log"
)
type wechatResp struct {
Status int `json:"status"`
Msg string `json:"msg"`
}
const (
// http://info.bilibili.co/pages/viewpage.action?pageId=5406728
_url = "http://bap.bilibili.co/api/v1/message/add"
)
// SendWechat 发送企业微信消息
func (d *Dao) SendWechat(msg string) (err error) {
log.Error("SendWechat logged error(%s)", msg)
params := map[string]string{
"content": msg,
"timestamp": strconv.FormatInt(time.Now().Unix(), 10),
"token": d.c.Wechat.Token,
"type": "wechat",
"username": d.c.Wechat.Username,
"url": "",
}
params["signature"] = d.sign(params)
b, err := json.Marshal(params)
if err != nil {
log.Error("SendWechat json.Marshal error(%v)", err)
return
}
req, err := http.NewRequest(http.MethodPost, _url, bytes.NewReader(b))
if err != nil {
log.Error("SendWechat NewRequest error(%v), params(%s)", err, string(b))
return
}
req.Header.Set("Content-Type", "application/json; charset=utf-8")
res := wechatResp{}
if err = d.httpClient.Do(context.TODO(), req, &res); err != nil {
log.Error("SendWechat Do error(%v), params(%s)", err, string(b))
return
}
if res.Status != 0 {
err = fmt.Errorf("status(%d) msg(%s)", res.Status, res.Msg)
log.Error("SendWechat response error(%v), params(%s)", err, string(b))
}
return
}
func (d *Dao) sign(params map[string]string) string {
var 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()+d.c.Wechat.Secret)
return fmt.Sprintf("%x", h.Sum(nil))
}

View File

@@ -0,0 +1,27 @@
package dao
import (
"testing"
"github.com/smartystreets/goconvey/convey"
)
func TestDaoSendWechat(t *testing.T) {
msg := "push strategy test wechat message"
convey.Convey("SendWechat", t, func(ctx convey.C) {
err := d.SendWechat(msg)
ctx.Convey("Then err should be nil.", func(ctx convey.C) {
ctx.So(err, convey.ShouldBeNil)
})
})
}
func TestDaosign(t *testing.T) {
params := map[string]string{"a": "b"}
convey.Convey("sign", t, func(ctx convey.C) {
p1 := d.sign(params)
ctx.Convey("Then p1 should not be nil.", func(ctx convey.C) {
ctx.So(p1, convey.ShouldNotBeEmpty)
})
})
}