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,22 @@
filegroup(
name = "package-srcs",
srcs = glob(["**"]),
tags = ["automanaged"],
visibility = ["//visibility:private"],
)
filegroup(
name = "all-srcs",
srcs = [
":package-srcs",
"//app/admin/main/aegis/cmd:all-srcs",
"//app/admin/main/aegis/conf:all-srcs",
"//app/admin/main/aegis/dao:all-srcs",
"//app/admin/main/aegis/model:all-srcs",
"//app/admin/main/aegis/server/databus:all-srcs",
"//app/admin/main/aegis/server/http:all-srcs",
"//app/admin/main/aegis/service:all-srcs",
],
tags = ["automanaged"],
visibility = ["//visibility:public"],
)

View File

@@ -0,0 +1,100 @@
#v 1.2.1
1. 任务操作数据统计
#v 1.2.0
1. 监控平台迁移,添加了监控数据接口
#v 1.1.5
1. 梳理错误日志
- 92015错误不抛出只在tips提示
- 资源列表检索默认不展示刚下发的任务,避免重复审核
- 业务回调接口http错误不重试
- next接口未登入时自动登入
2. 修复任务列表panic
#v 1.1.4
1. resource和task的databus分开
2. 业务回调错误将详细信息返回前端
#v 1.1.3
1. up-service rpc更新
#v 1.1.2
1. 提供databus导入资源方式
2. 修复指派任务导致领取不到
3. 修复不必要参数为空报错
4. 常规任务不包含停滞任务
#v 1.1.1
1. 搜索改v3 sdk
#v 1.1.0
1. v2版本对接单话审核
2. 流程网加缓存
#v 1.0.12
1. 进出审量报表
2. 去掉多余的任务日志,报错信息
3. 列表批量高亮限制长度3000并改为并发请求
4. account使用grpc
#v 1.0.11
1. 避免91025错误任务下发前根据flowid检查是否需要审核
#v 1.0.10
1. 新增role/flush接口方便角色变化时进行刷新
2. 提交时更新搜索,查列表时验证状态
3. middelware
#v 1.0.9
1. 修复周期权重配置的去重逻辑
2. 修复orm事务错误
3. 已被处理的任务延迟时进行提示
4. 资源提交错误先默认重试3次
5. 任务统计不展示空进出审
# v1.0.8
1. fix资源日志多出3个数字索引的情况改为字符串索引
2. 新增操作日志查询接口
3. 审核日志添加cancel
# v1.0.7
1. 对应上rider版本号
# v1.0.6
1. 任务抢占分布式锁可重试3次
2. 补充任务详情信息使用errorgroup
3. 审核日志增加资源添加日志
4. hash tag改为 businessid-flowid
5. 添加初始态配置,给任务创建时做判断
6. 先默认一个资源只在一个flow下分发解决目前存在flow状态与task状态不同步
# v1.0.5
1. 资源提交时实时按照rid,flow_id搜索未完成任务不能用提交的task_id搜索
# v1.0.4
1. fix bug 已取消过后的资源重新add需要更新state为正常状态
2. 先事务提交,才创建任务流转信息
3. 有权限的任务为空时不返回403
4. 使用graphviz dot和viz.js绘制流程图
# v1.0.3
1. 日志过滤null的打回理由和备注
2. 批量操作报错友好一点
# v1.0.2
1. 支持灰度策略or策略多字段and逻辑
# v1.0.1
1. 修复属性位错误
2. 任务报表flow_id改为非必传
3. 业务注册加权限点 AEGIS_REGISTER
4. 修复提交错误时,任务缓存释放
5. 批量打回添加理由和通知
6. 非管理员可查看和操作资源审核列表
7. public key使用hash tag
8. 修复领任务死循环
# v1.0.0
1. 上线功能xxx

View File

@@ -0,0 +1,14 @@
# Owner
shencen
wangzhe01
# Author
shencen
chenxuefeng
chenxi01
# Reviewer
shencen
chenxuefeng
chenxi01

View File

@@ -0,0 +1,17 @@
# See the OWNERS docs at https://go.k8s.io/owners
approvers:
- chenxi01
- chenxuefeng
- shencen
- wangzhe01
labels:
- admin
- admin/main/aegis
- main
options:
no_parent_owners: true
reviewers:
- chenxi01
- chenxuefeng
- shencen

View File

@@ -0,0 +1,12 @@
# aegis-admin
# 项目简介
宙斯盾审核平台
# 编译环境
# 依赖包
# 编译执行

View File

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

View File

@@ -0,0 +1,45 @@
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 = ["aegis-admin.toml"],
importpath = "go-common/app/admin/main/aegis/cmd",
tags = ["automanaged"],
visibility = ["//visibility:public"],
deps = [
"//app/admin/main/aegis/conf:go_default_library",
"//app/admin/main/aegis/server/http:go_default_library",
"//app/admin/main/aegis/service:go_default_library",
"//library/ecode/tip:go_default_library",
"//library/log:go_default_library",
"//library/net/trace:go_default_library",
"//library/queue/databus/report: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,201 @@
debug = "local"
bucket = "archive"
admin = "481"
[consumer]
onexp = 600
roleexp = 86400
[gray]
[[gray.biz]]
businessID = 1
[[gray.biz.options]]
[[gray.biz.options.fields]]
name = "OID"
value = "oid1,oid3"
[[gray.biz.options]]
[[gray.biz.options.fields]]
name = "MID"
value = "1,2"
[[gray.biz.options]]
[[gray.biz.options.fields]]
name = "Extra2"
value = "3,4"
[[gray.biz.options.fields]]
name = "OID"
value = "oid6"
[auditstate]
1 = "1,2"
2 = "3,4"
[log]
dir="/data/log/aegis"
[app]
key = "c1a1cb2d89c33794"
secret = "dda47eeca111e03e6845017505baea13"
[orm]
dsn = "test:test@tcp(127.0.0.1:3306)/bilibili_aegis?timeout=5s&readTimeout=5s&writeTimeout=5s&parseTime=true&loc=Local&charset=utf8,utf8mb4"
active = 5
idle = 5
idleTimeout = "4h"
[mysql]
addr = "aegis"
dsn = "test:test@tcp(127.0.0.1:3306)/bilibili_aegis?timeout=5s&readTimeout=5s&writeTimeout=5s&parseTime=true&loc=Local&charset=utf8,utf8mb4"
readDSN = ["test:test@tcp(127.0.0.1:3306)/bilibili_aegis?timeout=5s&readTimeout=5s&writeTimeout=5s&parseTime=true&loc=Local&charset=utf8,utf8mb4"]
active = 20
idle = 10
idleTimeout ="4h"
queryTimeout = "100ms"
execTimeout = "100ms"
tranTimeout = "200ms"
[redis]
netExpire = "30m"
[redis.cluster]
name = "aegis-admin"
proto = "tcp"
addr = "127.0.0.1:6379"
idle = 10
active = 10
dialTimeout = "100ms"
readTimeout = "100s"
writeTimeout = "100ms"
idleTimeout = "10s"
expire = "1m"
[memcache]
name = "aegis-admin"
proto = "tcp"
addr = "127.0.0.1:11211"
active = 50
idle = 10
dialTimeout = "1s"
readTimeout = "1s"
writeTimeout = "1s"
idleTimeout = "10s"
expire = "24h"
[bm]
addr = "0.0.0.0:8000"
maxListen = 10
timeout = "1s"
[auth]
managerHost = "http://uat-manager.bilibili.co"
dashboardHost = "http://dashboard-mng.bilibili.co"
dashboardCaller = "manager-go"
[auth.DsHTTPClient]
key = "manager-go"
secret = "949bbb2dd3178252638c2407578bc7ad"
dial = "1s"
timeout = "1s"
keepAlive = "60s"
[auth.DsHTTPClient.breaker]
window = "3s"
sleep = "100ms"
bucket = 10
ratio = 0.5
request = 100
[auth.MaHTTPClient]
key = "f6433799dbd88751"
secret = "36f8ddb1806207fe07013ab6a77a3935"
dial = "1s"
timeout = "1s"
keepAlive = "60s"
[auth.MaHTTPClient.breaker]
window = "3s"
sleep = "100ms"
bucket = 10
ratio = 0.5
request = 100
[auth.session]
sessionIDLength = 32
cookieLifeTime = 1800
cookieName = "mng-go"
domain = ".bilibili.co"
[auth.session.Memcache]
name = "go-business/auth"
proto = "unix"
addr = "/tmp/uat-manager-auth-mc.sock"
active = 10
idle = 5
dialTimeout = "1s"
readTimeout = "1s"
writeTimeout = "1s"
idleTimeout = "80s"
[rpc]
[rpc.acc]
[rpc.up]
[rpc.rel]
[host]
api = "http://uat-api.bilibili.co"
manager = "http://uat-manager.bilibili.co"
[httpClient]
[httpClient.read]
key = "b8f239ca38a53308"
secret = "5460ef72fe13c10dfb53442b9111427e"
dial = "80ms"
timeout = "800ms"
keepAlive = "60s"
[httpClient.read.breaker]
window = "10s"
sleep = "100ms"
bucket = 10
ratio = 0.5
request = 100
[httpClient.write]
key = "b8f239ca38a53308"
secret = "5460ef72fe13c10dfb53442b9111427e"
dial = "50ms"
timeout = "1s"
keepAlive = "60s"
[httpClient.write.breaker]
window = "10s"
sleep = "100ms"
bucket = 10
ratio = 0.5
request = 100
[httpClient.es]
key = "b8f239ca38a53308"
secret = "5460ef72fe13c10dfb53442b9111427e"
dial = "1s"
timeout = "2s"
keepAlive = "60s"
[httpClient.es.breaker]
window = "10s"
sleep = "1000ms"
bucket = 10
ratio = 0.5
request = 100
[aegisPub]
key = "0PtMsLLxWyyvoTgAyLCD"
secret = "0PtMsLLxWyyvoTgAyLCE"
group = "Aegis-P"
topic = "Aegis"
action = "pub"
name = "aegis-admin/databus"
proto = "tcp"
addr = "172.16.33.158:6205"
active = 1
idle = 1
dialTimeout = "1s"
readTimeout = "1s"
writeTimeout = "1s"
idleTimeout = "10s"
[bfs]
key = "ef42d94858dd49b2"
secret = "351c300573a330a5271226835be496"
host = "http://uat-bfs.bilibili.co"
timeout = 1000
maxFileSize = 5242880
[grpc]
[accRPC]
timeout = "1s"

View File

@@ -0,0 +1,54 @@
package main
import (
"flag"
"os"
"os/signal"
"syscall"
"time"
"go-common/app/admin/main/aegis/conf"
"go-common/app/admin/main/aegis/server/http"
"go-common/app/admin/main/aegis/service"
ecode "go-common/library/ecode/tip"
"go-common/library/log"
"go-common/library/net/trace"
"go-common/library/queue/databus/report"
)
func main() {
flag.Parse()
if err := conf.Init(); err != nil {
panic(err)
}
log.Init(conf.Conf.Log)
defer log.Close()
log.Info("aegis-admin start")
if conf.Conf.Debug != "local" {
trace.Init(nil)
defer trace.Close()
ecode.Init(nil)
}
// report init
report.InitManager(nil)
svc := service.New(conf.Conf)
http.Init(conf.Conf, svc)
c := make(chan os.Signal, 1)
signal.Notify(c, syscall.SIGHUP, syscall.SIGQUIT, syscall.SIGTERM, syscall.SIGINT)
for {
s := <-c
log.Info("get a signal %s", s.String())
switch s {
case syscall.SIGQUIT, syscall.SIGTERM, syscall.SIGINT:
svc.Close()
log.Info("aegis-admin exit")
time.Sleep(time.Second)
return
case syscall.SIGHUP:
default:
return
}
}
}

View File

@@ -0,0 +1,46 @@
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/admin/main/aegis/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/orm:go_default_library",
"//library/database/sql:go_default_library",
"//library/ecode/tip:go_default_library",
"//library/log:go_default_library",
"//library/net/http/blademaster:go_default_library",
"//library/net/http/blademaster/middleware/permit:go_default_library",
"//library/net/http/blademaster/middleware/verify:go_default_library",
"//library/net/rpc:go_default_library",
"//library/net/rpc/warden:go_default_library",
"//library/net/trace: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,185 @@
package conf
import (
"errors"
"flag"
"go-common/library/cache/memcache"
"go-common/library/cache/redis"
"go-common/library/conf"
"go-common/library/database/orm"
"go-common/library/database/sql"
ecode "go-common/library/ecode/tip"
"go-common/library/log"
bm "go-common/library/net/http/blademaster"
"go-common/library/net/http/blademaster/middleware/permit"
"go-common/library/net/http/blademaster/middleware/verify"
"go-common/library/net/rpc"
"go-common/library/net/rpc/warden"
"go-common/library/net/trace"
"go-common/library/queue/databus"
xtime "go-common/library/time"
"github.com/BurntSushi/toml"
)
var (
confPath string
client *conf.Client
// Conf config
Conf = &Config{}
)
// Config .
type Config struct {
Log *log.Config
BM *bm.ServerConfig
Verify *verify.Config
Auth *permit.Config
Tracer *trace.Config
Redis *Redis
Memcache *memcache.Config
Ecode *ecode.Config
RPC *RPC
Host *Host
// http client test
HTTPClient HTTPClient
// ORM
ORM *orm.Config
MySQL *sql.Config
AegisPub *databus.Config
Bfs *Bfs
Bucket string
Debug string
Admin string // 所有业务的管理员
Consumer *Consumer
Gray *Gray
Auditstate map[string]string
GRPC *GRPC
}
//GRPC .
type GRPC struct {
AccRPC *warden.ClientConfig
UpRPC *warden.ClientConfig
}
// Gray .
type Gray struct {
Biz []graybiz
}
type graybiz struct {
BusinessID int64
Options []grayoption
}
type grayoption struct {
Fields []struct {
Name string
Value string
}
}
// Consumer 在线过期时间,角色过期时间
type Consumer struct {
OnExp int32
RoleExp int32
}
// Bfs reprensents the bfs config
type Bfs struct {
Key string
Secret string
Host string
Timeout int
MaxFileSize int
}
// Host host config .
type Host struct {
API string
Manager string
MainSearch string
}
// Redis .
type Redis struct {
NetExpire xtime.Duration
Cluster *redis.Config
}
// HTTPClient str
type HTTPClient struct {
Read *bm.ClientConfig
Write *bm.ClientConfig
Es *bm.ClientConfig
}
//DB .
type DB struct {
Aegis *sql.Config
MySQL *sql.Config
}
// RPC .
type RPC struct {
Acc *rpc.ClientConfig
Rel *rpc.ClientConfig
Up *rpc.ClientConfig
}
func init() {
flag.StringVar(&confPath, "conf", "", "default config path")
}
// Init init conf
func Init() error {
if confPath != "" {
return local()
}
return remote()
}
func local() (err error) {
_, err = toml.DecodeFile(confPath, &Conf)
return
}
func remote() (err error) {
if client, err = conf.New(); err != nil {
return
}
if err = load(); err != nil {
return
}
go func() {
for range client.Event() {
log.Info("config reload")
if load() != nil {
log.Error("config reload error (%v)", err)
}
}
}()
return
}
func load() (err error) {
var (
s string
ok bool
tmpConf *Config
)
if s, ok = client.Toml2(); !ok {
return errors.New("load config center error")
}
if _, err = toml.Decode(s, &tmpConf); err != nil {
return errors.New("could not decode config")
}
*Conf = *tmpConf
return
}

View File

@@ -0,0 +1,28 @@
package(default_visibility = ["//visibility:public"])
load(
"@io_bazel_rules_go//go:def.bzl",
"go_test",
)
filegroup(
name = "package-srcs",
srcs = glob(["**"]),
tags = ["automanaged"],
visibility = ["//visibility:private"],
)
filegroup(
name = "all-srcs",
srcs = [
":package-srcs",
"//app/admin/main/aegis/dao/gorm:all-srcs",
"//app/admin/main/aegis/dao/http:all-srcs",
"//app/admin/main/aegis/dao/mc:all-srcs",
"//app/admin/main/aegis/dao/mysql:all-srcs",
"//app/admin/main/aegis/dao/redis:all-srcs",
"//app/admin/main/aegis/dao/rpc:all-srcs",
],
tags = ["automanaged"],
visibility = ["//visibility:public"],
)

View File

@@ -0,0 +1,89 @@
package(default_visibility = ["//visibility:public"])
load(
"@io_bazel_rules_go//go:def.bzl",
"go_test",
"go_library",
)
go_test(
name = "go_default_test",
srcs = [
"business_config_test.go",
"business_test.go",
"common_test.go",
"dao_test.go",
"direction_test.go",
"flow_resource_test.go",
"flow_test.go",
"net_test.go",
"report_test.go",
"resource_test.go",
"task_config_test.go",
"task_test.go",
"token_test.go",
"transition_test.go",
],
embed = [":go_default_library"],
tags = ["automanaged"],
deps = [
"//app/admin/main/aegis/conf:go_default_library",
"//app/admin/main/aegis/model/business:go_default_library",
"//app/admin/main/aegis/model/common:go_default_library",
"//app/admin/main/aegis/model/net:go_default_library",
"//app/admin/main/aegis/model/resource:go_default_library",
"//app/admin/main/aegis/model/task:go_default_library",
"//library/ecode:go_default_library",
"//vendor/github.com/jinzhu/gorm:go_default_library",
"//vendor/github.com/smartystreets/goconvey/convey:go_default_library",
],
)
go_library(
name = "go_default_library",
srcs = [
"business.go",
"business_config.go",
"common.go",
"dao.go",
"direction.go",
"flow.go",
"flow_resource.go",
"net.go",
"report.go",
"resource.go",
"task.go",
"task_config.go",
"token.go",
"transition.go",
],
importpath = "go-common/app/admin/main/aegis/dao/gorm",
tags = ["automanaged"],
visibility = ["//visibility:public"],
deps = [
"//app/admin/main/aegis/conf:go_default_library",
"//app/admin/main/aegis/model:go_default_library",
"//app/admin/main/aegis/model/business:go_default_library",
"//app/admin/main/aegis/model/net:go_default_library",
"//app/admin/main/aegis/model/resource:go_default_library",
"//app/admin/main/aegis/model/task:go_default_library",
"//library/database/orm:go_default_library",
"//library/ecode:go_default_library",
"//library/log:go_default_library",
"//vendor/github.com/jinzhu/gorm: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,66 @@
package gorm
import (
"context"
"go-common/app/admin/main/aegis/model/business"
"github.com/jinzhu/gorm"
)
// AddBusiness .
func (d *Dao) AddBusiness(c context.Context, e *business.Business) (id int64, err error) {
err = d.orm.Table("business").Create(&e).Error
id = e.ID
return
}
// UpdateBusiness .
func (d *Dao) UpdateBusiness(c context.Context, e *business.Business) (err error) {
return d.orm.Table("business").Where("id = ?", e.ID).Update(map[string]interface{}{
"name": e.Name,
"desc": e.Desc,
"developer": e.Developer,
}).Error
}
// EnableBusiness .
func (d *Dao) EnableBusiness(c context.Context, id int64) (err error) {
return d.orm.Table("business").Where("id = ?", id).Update(map[string]interface{}{
"state": business.StateEnable,
}).Error
}
// DisableBusiness .
func (d *Dao) DisableBusiness(c context.Context, id int64) (err error) {
return d.orm.Table("business").Where("id = ?", id).Update(map[string]interface{}{
"state": business.StateDisable,
}).Error
}
// Business .
func (d *Dao) Business(c context.Context, id int64) (res *business.Business, err error) {
res = &business.Business{}
if err = d.orm.Where("id = ?", id).First(&res).Error; err == gorm.ErrRecordNotFound {
res = nil
err = nil
}
return
}
// BusinessList .
func (d *Dao) BusinessList(c context.Context, tp int8, ids []int64, onlyEnable bool) (res []*business.Business, err error) {
res = []*business.Business{}
db := d.orm
if len(ids) > 0 {
db = db.Where("id in (?)", ids)
}
if onlyEnable {
db = db.Where("state=?", business.StateEnable)
}
if tp > 0 {
db = db.Where("type = ?", tp)
}
err = db.Find(&res).Error
return
}

View File

@@ -0,0 +1,68 @@
package gorm
import (
"context"
"database/sql"
"go-common/app/admin/main/aegis/model/business"
"go-common/library/log"
)
// GetConfigs .
func (d *Dao) GetConfigs(c context.Context, bizid int64) (cfgs []*business.BizCFG, err error) {
if err = d.orm.Table("business_config").Where("business_id=? AND state=0", bizid).Scan(&cfgs).Error; err != nil {
log.Error("GetURL error(%v)", err)
}
return
}
// GetConfig .
func (d *Dao) GetConfig(c context.Context, bizid int64, tp int8) (config string, err error) {
if err = d.orm.Table("business_config").Select("`config`").
Where("business_id=? AND type=? AND state=0", bizid, tp).
Order("mtime DESC").Limit(1).
Row().Scan(&config); err != nil {
if err == sql.ErrNoRows {
err = nil
return
}
log.Error("GetConfig error(%v)", err)
return
}
return
}
// ActiveConfigs 所有任务配置
func (d *Dao) ActiveConfigs(c context.Context) (configs []*business.BizCFG, err error) {
configs = []*business.BizCFG{}
if err = d.orm.Where("state=0").Find(&configs).Error; err != nil {
log.Error("ActiveConfigs find error(%v)", err)
}
return
}
// AddBizConfig 每个业务每种配置只有一条
func (d *Dao) AddBizConfig(c context.Context, cfg *business.BizCFG) (lastid int64, err error) {
if err = d.orm.Table("business_config").Where("business_id=? AND `type`=?", cfg.BusinessID, cfg.TP).
Assign(map[string]interface{}{
"config": cfg.Config,
"state": cfg.State,
}).FirstOrCreate(cfg).Error; err != nil {
log.Error("AddBizConfig error(%v)", err)
}
lastid = cfg.ID
return
}
// EditBizConfig .
func (d *Dao) EditBizConfig(c context.Context, cfg *business.BizCFG) (err error) {
if err = d.orm.Table("business_config").Where("id=?", cfg.ID).
Update(map[string]interface{}{
"config": cfg.Config,
"state": cfg.State,
}).Error; err != nil {
log.Error("EditBizConfig error(%v)", err)
}
return
}

View File

@@ -0,0 +1,94 @@
package gorm
import (
"context"
"go-common/app/admin/main/aegis/model/business"
"testing"
"github.com/smartystreets/goconvey/convey"
)
func TestGormGetConfigs(t *testing.T) {
convey.Convey("GetConfigs", t, func(ctx convey.C) {
var (
c = context.Background()
bizid = int64(1)
)
ctx.Convey("success", func(ctx convey.C) {
cfgs, err := d.GetConfigs(c, bizid)
ctx.Convey("Then err should be nil.cfgs should not be nil.", func(ctx convey.C) {
ctx.So(err, convey.ShouldBeNil)
ctx.So(cfgs, convey.ShouldNotBeNil)
})
})
ctx.Convey("empty", func(ctx convey.C) {
_, err := d.GetConfigs(c, -1)
ctx.Convey("Then err should be nil.", func(ctx convey.C) {
ctx.So(err, convey.ShouldBeNil)
})
})
})
}
func TestGormGetConfig(t *testing.T) {
convey.Convey("GetConfig", t, func(ctx convey.C) {
var (
c = context.Background()
bizid = int64(0)
tp = int8(-1)
)
ctx.Convey("When everything goes positive", func(ctx convey.C) {
config, err := d.GetConfig(c, bizid, tp)
ctx.Convey("Then err should be nil.config should not be nil.", func(ctx convey.C) {
ctx.So(err, convey.ShouldBeNil)
ctx.So(config, convey.ShouldNotBeNil)
})
})
})
}
func TestGormActiveConfigs(t *testing.T) {
convey.Convey("ActiveConfigs", t, func(ctx convey.C) {
var (
c = context.Background()
)
ctx.Convey("When everything goes positive", func(ctx convey.C) {
configs, err := d.ActiveConfigs(c)
ctx.Convey("Then err should be nil.configs should not be nil.", func(ctx convey.C) {
ctx.So(err, convey.ShouldBeNil)
ctx.So(configs, convey.ShouldNotBeNil)
})
})
})
}
func TestGormAddBizConfig(t *testing.T) {
convey.Convey("AddBizConfig", t, func(ctx convey.C) {
var (
c = context.Background()
cfg = &business.BizCFG{}
)
ctx.Convey("When everything goes positive", func(ctx convey.C) {
lastid, err := d.AddBizConfig(c, cfg)
ctx.Convey("Then err should be nil.lastid should not be nil.", func(ctx convey.C) {
ctx.So(err, convey.ShouldBeNil)
ctx.So(lastid, convey.ShouldNotBeNil)
})
})
})
}
func TestGormEditBizConfig(t *testing.T) {
convey.Convey("EditBizConfig", t, func(ctx convey.C) {
var (
c = context.Background()
cfg = &business.BizCFG{}
)
ctx.Convey("When everything goes positive", func(ctx convey.C) {
err := d.EditBizConfig(c, cfg)
ctx.Convey("Then err should be nil.", func(ctx convey.C) {
ctx.So(err, convey.ShouldBeNil)
})
})
})
}

View File

@@ -0,0 +1,80 @@
package gorm
import (
"context"
"testing"
"go-common/app/admin/main/aegis/model/business"
"github.com/smartystreets/goconvey/convey"
)
func TestEnableBusiness(t *testing.T) {
convey.Convey("EnableBusiness", t, func(ctx convey.C) {
var (
c = context.Background()
)
ctx.Convey("When everything goes positive", func(ctx convey.C) {
err := d.EnableBusiness(c, 0)
ctx.Convey("Then err should be nil.cfgs should not be nil.", func(ctx convey.C) {
ctx.So(err, convey.ShouldBeNil)
})
})
})
}
func TestDisableBusiness(t *testing.T) {
convey.Convey("DisableBusiness", t, func(ctx convey.C) {
var (
c = context.Background()
)
ctx.Convey("When everything goes positive", func(ctx convey.C) {
err := d.DisableBusiness(c, 0)
ctx.Convey("Then err should be nil.cfgs should not be nil.", func(ctx convey.C) {
ctx.So(err, convey.ShouldBeNil)
})
})
})
}
func TestBusiness(t *testing.T) {
convey.Convey("Business", t, func(ctx convey.C) {
var (
c = context.Background()
)
ctx.Convey("When everything goes positive", func(ctx convey.C) {
_, err := d.Business(c, 0)
ctx.Convey("Then err should be nil.cfgs should not be nil.", func(ctx convey.C) {
ctx.So(err, convey.ShouldBeNil)
})
})
})
}
func TestBusinessList(t *testing.T) {
convey.Convey("BusinessList", t, func(ctx convey.C) {
var (
c = context.Background()
)
ctx.Convey("When everything goes positive", func(ctx convey.C) {
_, err := d.BusinessList(c, 1, []int64{0}, true)
ctx.Convey("Then err should be nil.cfgs should not be nil.", func(ctx convey.C) {
ctx.So(err, convey.ShouldBeNil)
})
})
})
}
func TestUpdateBusiness(t *testing.T) {
convey.Convey("UpdateBusiness", t, func(ctx convey.C) {
var (
c = context.Background()
)
ctx.Convey("When everything gose positive", func(ctx convey.C) {
err := d.UpdateBusiness(c, &business.Business{})
ctx.Convey("Then err should be nil", func(ctx convey.C) {
ctx.So(err, convey.ShouldBeNil)
})
})
})
}

View File

@@ -0,0 +1,106 @@
package gorm
import (
"context"
"database/sql"
"fmt"
"strings"
"github.com/jinzhu/gorm"
"go-common/app/admin/main/aegis/model/net"
"go-common/library/log"
)
// Available .
func Available(db *gorm.DB) *gorm.DB {
return db.Where("disable_time = '0000-00-00 00:00:00'")
}
// Disable .
func Disable(db *gorm.DB) *gorm.DB {
return db.Not("disable_time = '0000-00-00 00:00:00'")
}
func state(state string) func(db *gorm.DB) *gorm.DB {
state = strings.TrimSpace(state)
if state == net.StateAvailable {
return func(db *gorm.DB) *gorm.DB {
return Available(db)
}
} else if state == net.StateDisable {
return func(db *gorm.DB) *gorm.DB {
return Disable(db)
}
} else {
return func(db *gorm.DB) *gorm.DB {
return db
}
}
}
func pager(ps int64, pn int64, sort string) func(db *gorm.DB) *gorm.DB {
offset := ps * (pn - 1)
order := fmt.Sprintf("id %s", sort)
return func(db *gorm.DB) *gorm.DB {
return db.Limit(ps).Offset(offset).Order(order)
}
}
// UpdateFields .
func (d *Dao) UpdateFields(c context.Context, db *gorm.DB, table string, id int64, fields map[string]interface{}) (err error) {
if db == nil {
db = d.orm
}
if err = db.Table(table).Where("id=?", id).Updates(fields).Error; err != nil {
log.Error("UpdateFlow(%s,%d) error(%v) changed(%+v)", table, id, err, fields)
}
return
}
// AddItem .
func (d *Dao) AddItem(c context.Context, db *gorm.DB, n interface{}) (err error) {
if db == nil {
db = d.orm
}
if err = db.Create(n).Error; err != nil {
log.Error("AddItem error(%v) (%+v)", err, n)
}
return
}
// ColumnMapString .
func (d *Dao) ColumnMapString(c context.Context, table string, column string, ids []int64, where string) (result map[int64]string, err error) {
var (
rows *sql.Rows
id int64
value string
slt = fmt.Sprintf("`id`,`%s`", column)
)
result = map[int64]string{}
db := d.orm.Table(table).Select(slt).Where("id in (?)", ids)
where = strings.TrimSpace(where)
if where != "" {
db = db.Where(where)
}
rows, err = db.Rows()
if err == sql.ErrNoRows {
err = nil
return
}
if err != nil {
log.Error("ColumnMapString(%s, %s) rows error(%v) ids(%v)", table, column, err, ids)
return
}
defer rows.Close()
for rows.Next() {
if err = rows.Scan(&id, &value); err != nil {
log.Error("ColumnMapString(%s, %s) rows.scan error(%v) ids(%v)", table, column, err, ids)
return
}
result[id] = value
}
return
}

View File

@@ -0,0 +1,61 @@
package gorm
import (
"testing"
"github.com/jinzhu/gorm"
"github.com/smartystreets/goconvey/convey"
"go-common/app/admin/main/aegis/model/net"
)
func TestDaoAvailable(t *testing.T) {
var (
db = &gorm.DB{}
)
convey.Convey("Available", t, func(ctx convey.C) {
p1 := Available(db)
ctx.Convey("Then p1 should not be nil.", func(ctx convey.C) {
ctx.So(p1, convey.ShouldNotBeNil)
})
})
}
func TestDaoDisable(t *testing.T) {
var (
db = &gorm.DB{}
)
convey.Convey("Disable", t, func(ctx convey.C) {
p1 := Disable(db)
ctx.Convey("Then p1 should not be nil.", func(ctx convey.C) {
ctx.So(p1, convey.ShouldNotBeNil)
})
})
}
func TestDaostatePager(t *testing.T) {
var (
s1 = ""
)
convey.Convey("state", t, func(ctx convey.C) {
p1 := state(s1)
ctx.Convey("Then p1 should not be nil.", func(ctx convey.C) {
ctx.So(p1, convey.ShouldNotBeNil)
})
})
}
func TestDao_ColumnMapString(t *testing.T) {
var (
table = net.TableFlow
column = "ch_name"
ids = []int64{1, 2, 3}
)
convey.Convey("ColumnMapString", t, func(ctx convey.C) {
result, err := d.ColumnMapString(cntx, table, column, ids, "")
ctx.Convey("Then err should be nil.", func(ctx convey.C) {
ctx.So(err, convey.ShouldBeNil)
})
t.Logf("result(%+v)", result)
})
}

View File

@@ -0,0 +1,47 @@
package gorm
import (
"context"
"go-common/app/admin/main/aegis/conf"
"go-common/library/database/orm"
"go-common/library/log"
"github.com/jinzhu/gorm"
)
// Dao dao
type Dao struct {
c *conf.Config
orm *gorm.DB
}
// New init mysql orm
func New(c *conf.Config) (dao *Dao) {
dao = &Dao{
c: c,
orm: orm.NewMySQL(c.ORM),
}
dao.orm.LogMode(true)
return
}
// Close close the resource.
func (d *Dao) Close() {
d.orm.Close()
}
// BeginTx .
func (d *Dao) BeginTx(c context.Context) (tx *gorm.DB, err error) {
tx = d.orm.Begin()
if err = tx.Error; err != nil {
log.Error("orm begin tx error(%v)", err)
}
return
}
// Ping dao ping
func (d *Dao) Ping(c context.Context) error {
return d.orm.DB().PingContext(c)
}

View File

@@ -0,0 +1,50 @@
package gorm
import (
"context"
"flag"
"os"
"testing"
"go-common/app/admin/main/aegis/conf"
"github.com/smartystreets/goconvey/convey"
)
var (
d *Dao
cntx context.Context
)
func TestMain(m *testing.M) {
if os.Getenv("DEPLOY_ENV") != "" {
flag.Set("app_id", "main.archive.aegis-admin")
flag.Set("conf_token", "cad913269be022e1eb8c45a8d5408d78")
flag.Set("tree_id", "60977")
flag.Set("conf_version", "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/aegis-admin.toml")
}
flag.Parse()
if err := conf.Init(); err != nil {
panic(err)
}
d = New(conf.Conf)
cntx = context.Background()
os.Exit(m.Run())
}
func TestDaoPing(t *testing.T) {
convey.Convey("Ping", t, func(ctx convey.C) {
err := d.Ping(context.TODO())
ctx.Convey("Then err should be nil", func(ctx convey.C) {
ctx.So(err, convey.ShouldBeNil)
})
})
}

View File

@@ -0,0 +1,122 @@
package gorm
import (
"context"
"github.com/jinzhu/gorm"
"go-common/app/admin/main/aegis/model/net"
"go-common/library/ecode"
"go-common/library/log"
)
// DirectionByFlowID .
func (d *Dao) DirectionByFlowID(c context.Context, flowID []int64, direction int8) (dirs []*net.Direction, err error) {
dirs = []*net.Direction{}
db := d.orm.Where("flow_id in (?)", flowID)
if direction == net.DirInput || direction == net.DirOutput {
db = db.Where("direction=?", direction)
}
err = db.Scopes(Available).Find(&dirs).Error
if err != nil {
log.Error("DirectionByFlowID find error(%v) flowid(%v) direction(%d)", err, flowID, direction)
}
return
}
// DirectionByTransitionID .
func (d *Dao) DirectionByTransitionID(c context.Context, transitionID []int64, direction int8, onlyAvailable bool) (dirs []*net.Direction, err error) {
dirs = []*net.Direction{}
db := d.orm.Where("transition_id in (?)", transitionID)
if direction == net.DirInput || direction == net.DirOutput {
db = db.Where("direction=?", direction)
}
if onlyAvailable {
db = db.Scopes(Available)
}
err = db.Find(&dirs).Error
if err != nil {
log.Error("DirectionByTransitionID find error(%v) transitionid(%v) direction(%d)", err, transitionID, direction)
}
return
}
// DirectionByID .
func (d *Dao) DirectionByID(c context.Context, id int64) (n *net.Direction, err error) {
n = &net.Direction{}
err = d.orm.Where("id=?", id).First(n).Error
if err == gorm.ErrRecordNotFound {
err = ecode.NothingFound
return
}
if err != nil {
log.Error("DirectionByID(%+v) error(%v)", id, err)
}
return
}
func (d *Dao) Directions(c context.Context, ids []int64) (n []*net.Direction, err error) {
n = []*net.Direction{}
if err = d.orm.Where("id in (?)", ids).Find(&n).Error; err != nil {
log.Error("Directions error(%v) ids(%v)", err, ids)
}
return
}
// DirectionList .
func (d *Dao) DirectionList(c context.Context, pm *net.ListDirectionParam) (result *net.ListDirectionRes, err error) {
result = &net.ListDirectionRes{
Pager: net.Pager{
Num: pm.Pn,
Size: pm.Ps,
},
}
db := d.orm.Table(net.TableDirection).Where("net_id=?", pm.NetID)
if len(pm.ID) > 0 {
db = db.Where("id in (?)", pm.ID)
}
if pm.FlowID > 0 {
db = db.Where("flow_id=?", pm.FlowID)
}
if pm.TransitionID > 0 {
db = db.Where("transition_id=?", pm.TransitionID)
}
if pm.Direction == net.DirInput || pm.Direction == net.DirOutput {
db = db.Where("direction=?", pm.Direction)
}
err = db.Scopes(state(pm.State)).Count(&result.Pager.Total).Scopes(pager(pm.Ps, pm.Pn, pm.Sort)).Find(&result.Result).Error
if err != nil {
log.Error("DirectionList find error(%v) params(%+v)", err, pm)
}
return
}
// DirectionByUnique .
func (d *Dao) DirectionByUnique(c context.Context, netID int64, flowID int64, transitionID int64, direction int8) (t *net.Direction, err error) {
t = &net.Direction{}
err = d.orm.Where("net_id=? AND flow_id=? AND transition_id=? AND direction=?", netID, flowID, transitionID, direction).
First(t).Error
if err == gorm.ErrRecordNotFound {
err = nil
t = nil
return
}
if err != nil {
log.Error("DirectionByUnique(%d,%d,%d,%d) error(%v)", netID, flowID, transitionID, direction, err)
}
return
}
// DirectionByNet .
func (d *Dao) DirectionByNet(c context.Context, netID int64) (n []*net.Direction, err error) {
n = []*net.Direction{}
err = d.orm.Where("net_id=?", netID).Scopes(Available).Find(&n).Error
if err != nil {
log.Error("DirectionByNet(%d) error(%v)", netID, err)
}
return
}

View File

@@ -0,0 +1,89 @@
package gorm
import (
"testing"
"go-common/app/admin/main/aegis/model/net"
"go-common/library/ecode"
"github.com/smartystreets/goconvey/convey"
)
func TestDaoDirectionByTransitionID(t *testing.T) {
convey.Convey("DirectionByTransitionID", t, func(ctx convey.C) {
_, err := d.DirectionByTransitionID(cntx, []int64{}, 1, true)
ctx.Convey("Then err should be nil", func(ctx convey.C) {
ctx.So(err, convey.ShouldBeNil)
})
})
}
func TestDaoDirectionByID(t *testing.T) {
convey.Convey("DirectionByID", t, func(ctx convey.C) {
_, err := d.DirectionByID(cntx, -1)
ctx.Convey("Then err should be 404", func(ctx convey.C) {
ctx.So(err, convey.ShouldEqual, ecode.NothingFound)
})
})
}
func TestDaoDirectionList(t *testing.T) {
var (
pm = &net.ListDirectionParam{
NetID: 1,
Ps: 20,
ID: []int64{1},
FlowID: 1,
TransitionID: 1,
Direction: 1,
}
)
convey.Convey("DirectionList", t, func(ctx convey.C) {
result, err := d.DirectionList(cntx, pm)
ctx.Convey("Then err should be nil.result should not be nil.", func(ctx convey.C) {
ctx.So(err, convey.ShouldBeNil)
ctx.So(result, convey.ShouldNotBeNil)
t.Logf("list result(%+v)", result)
for _, dir := range result.Result {
t.Logf("bylist dir(%+v)", dir)
}
})
})
}
func TestDaoDirectionByUnique(t *testing.T) {
convey.Convey("DirectionByUnique", t, func(ctx convey.C) {
_, err := d.DirectionByUnique(cntx, 0, 0, 0, 0)
ctx.Convey("Then err should be nil", func(ctx convey.C) {
ctx.So(err, convey.ShouldBeNil)
})
})
}
func TestDaoDirectionByFlowID(t *testing.T) {
convey.Convey("DirectionByFlowID", t, func(ctx convey.C) {
_, err := d.DirectionByFlowID(cntx, []int64{}, 1)
ctx.Convey("Then err should be nil", func(ctx convey.C) {
ctx.So(err, convey.ShouldBeNil)
})
})
}
func TestDaoDirectionByNet(t *testing.T) {
convey.Convey("DirectionByNet", t, func(ctx convey.C) {
_, err := d.DirectionByNet(cntx, 0)
ctx.Convey("Then err should be nil", func(ctx convey.C) {
ctx.So(err, convey.ShouldBeNil)
})
})
}
func TestDaoDirections(t *testing.T) {
convey.Convey("Directions", t, func(ctx convey.C) {
_, err := d.Directions(cntx, []int64{0})
ctx.Convey("Then err should be nil", func(ctx convey.C) {
ctx.So(err, convey.ShouldBeNil)
})
})
}

View File

@@ -0,0 +1,105 @@
package gorm
import (
"context"
"strings"
"github.com/jinzhu/gorm"
"go-common/app/admin/main/aegis/model/net"
"go-common/library/ecode"
"go-common/library/log"
)
// FlowByID .
func (d *Dao) FlowByID(c context.Context, id int64) (f *net.Flow, err error) {
f = &net.Flow{}
err = d.orm.Where("id=?", id).First(f).Error
if err == gorm.ErrRecordNotFound {
err = ecode.AegisFlowNotFound
return
}
if err != nil {
log.Error("FlowByID(%+v) error(%v)", id, err)
}
return
}
// FlowList .
func (d *Dao) FlowList(c context.Context, pm *net.ListNetElementParam) (result *net.ListFlowRes, err error) {
result = &net.ListFlowRes{
Pager: net.Pager{
Num: pm.Pn,
Size: pm.Ps,
},
}
db := d.orm.Table(net.TableFlow).Where("net_id=?", pm.NetID)
if len(pm.ID) > 0 {
db = db.Where("id in (?)", pm.ID)
}
pm.Name = strings.TrimSpace(pm.Name)
if pm.Name != "" {
db = db.Where("name=?", pm.Name)
}
err = db.Scopes(state(pm.State)).Count(&result.Pager.Total).Scopes(pager(pm.Ps, pm.Pn, pm.Sort)).Find(&result.Result).Error
if err != nil {
log.Error("FlowList find error(%v) params(%+v)", err, pm)
}
return
}
// FlowByUnique .
func (d *Dao) FlowByUnique(c context.Context, netID int64, name string) (f *net.Flow, err error) {
f = &net.Flow{}
err = d.orm.Where("net_id=? AND name=?", netID, name).First(f).Error
if err == gorm.ErrRecordNotFound {
err = nil
f = nil
return
}
if err != nil {
log.Error("FlowByUnique(%d,%s) error(%v)", netID, name, err)
}
return
}
// Flows .
func (d *Dao) Flows(c context.Context, ids []int64) (fs []*net.Flow, err error) {
fs = []*net.Flow{}
err = d.orm.Where("id in (?)", ids).Find(&fs).Error
if err != nil {
log.Error("Flows(%v) error(%v)", ids, err)
}
return
}
// FlowsByNet .
func (d *Dao) FlowsByNet(c context.Context, netID []int64) (fs []*net.Flow, err error) {
fs = []*net.Flow{}
err = d.orm.Scopes(Available).Where("net_id in (?)", netID).Order("id ASC").Find(&fs).Error
if err != nil {
log.Error("Flows(%d) error(%v)", netID, err)
}
return
}
func (d *Dao) FlowIDByNet(c context.Context, nid []int64) (res map[int64][]int64, err error) {
res = map[int64][]int64{}
listi := []struct {
ID int64 `gorm:"column:id"`
NetID int64 `gorm:"column:net_id"`
}{}
if err = d.orm.Table(net.TableFlow).Select("id,net_id").
Where("net_id in (?)", nid).Scopes(Available).Scan(&listi).Error; err != nil {
log.Error("FlowIDByNet error(%v) nid(%v)", err, nid)
return
}
for _, item := range listi {
res[item.NetID] = append(res[item.NetID], item.ID)
}
return
}

View File

@@ -0,0 +1,70 @@
package gorm
import (
"context"
"github.com/jinzhu/gorm"
"go-common/app/admin/main/aegis/model/net"
"go-common/library/log"
)
// FRByFlow .
func (d *Dao) FRByFlow(c context.Context, flowID []int64) (fr *net.FlowResource, err error) {
fr = &net.FlowResource{}
if err = d.orm.Where("flow_id in (?)", flowID).First(fr).Error; err == gorm.ErrRecordNotFound {
fr = nil
err = nil
return
}
if err != nil {
log.Error("FRByFlow error(%v) flowid(%v)", err, flowID)
}
return
}
// FRByNetRID .
func (d *Dao) FRByNetRID(c context.Context, netID []int64, rids []int64, onlyRunning bool) (frs []*net.FlowResource, err error) {
frs = []*net.FlowResource{}
db := d.orm.Where("rid in (?) AND net_id in (?)", rids, netID)
if onlyRunning {
db = db.Scopes(running)
}
if err = db.Find(&frs).Error; err != nil {
log.Error("FRByNetRID error(%v) netid(%v) rids(%v)", err, netID, rids)
}
return
}
// FRByUniques .
func (d *Dao) FRByUniques(c context.Context, rids []int64, flowID []int64, onlyRunning bool) (frs []*net.FlowResource, err error) {
frs = []*net.FlowResource{}
db := d.orm
if len(rids) > 0 {
db = db.Where("rid in (?)", rids)
}
if len(flowID) > 0 {
db = db.Where("flow_id in (?)", flowID)
}
if onlyRunning {
db = db.Scopes(running)
}
if err = db.Find(&frs).Error; err != nil {
log.Error("FRByUniques error(%v) rids(%+v) flowid(%d)", err, rids, flowID)
}
return
}
// CancelFlowResource .
func (d *Dao) CancelFlowResource(c context.Context, tx *gorm.DB, rids []int64) (err error) {
fields := map[string]interface{}{"state": net.FRStateDeleted}
if err = tx.Table(net.TableFlowResource).Where("rid in (?)", rids).Updates(fields).Error; err != nil {
log.Error("CancelFlowResource error(%v) rids(%+v)", err, rids)
}
return
}
func running(db *gorm.DB) *gorm.DB {
return db.Where("state!=?", net.FRStateDeleted)
}

View File

@@ -0,0 +1,45 @@
package gorm
import (
"testing"
"github.com/smartystreets/goconvey/convey"
)
func TestDaoFRByFlow(t *testing.T) {
convey.Convey("FRByFlow", t, func(ctx convey.C) {
_, err := d.FRByFlow(cntx, []int64{})
ctx.Convey("Then err should be nil", func(ctx convey.C) {
ctx.So(err, convey.ShouldBeNil)
})
})
}
func TestDaoFRByNetRID(t *testing.T) {
convey.Convey("FRByNetRID", t, func(ctx convey.C) {
_, err := d.FRByNetRID(cntx, []int64{}, []int64{}, false)
ctx.Convey("Then err should be nil", func(ctx convey.C) {
ctx.So(err, convey.ShouldBeNil)
})
})
}
func TestDaoFRByUniques(t *testing.T) {
convey.Convey("FRByUniques", t, func(ctx convey.C) {
_, err := d.FRByUniques(cntx, []int64{1}, []int64{1}, true)
ctx.Convey("Then err should be nil", func(ctx convey.C) {
ctx.So(err, convey.ShouldBeNil)
})
})
}
func TestDaoCancelFlowResource(t *testing.T) {
tx, _ := d.BeginTx(cntx)
defer tx.Commit()
convey.Convey("CancelFlowResource", t, func(ctx convey.C) {
err := d.CancelFlowResource(cntx, tx, []int64{})
ctx.Convey("Then err should be nil", func(ctx convey.C) {
ctx.So(err, convey.ShouldBeNil)
})
})
}

View File

@@ -0,0 +1,73 @@
package gorm
import (
"testing"
"github.com/smartystreets/goconvey/convey"
"go-common/app/admin/main/aegis/model/net"
)
func TestDaoFlowByID(t *testing.T) {
convey.Convey("FlowByID", t, func(ctx convey.C) {
_, err := d.FlowByID(cntx, 1)
ctx.Convey("Then err should be nil.result should not be nil.", func(ctx convey.C) {
ctx.So(err, convey.ShouldBeNil)
})
})
}
func TestDaoFlowList(t *testing.T) {
var (
pm = &net.ListNetElementParam{
NetID: 1,
State: net.StateAvailable,
Ps: 5,
Pn: 2,
ID: []int64{1},
Name: "name",
}
)
convey.Convey("FlowList", t, func(ctx convey.C) {
result, err := d.FlowList(cntx, pm)
ctx.Convey("Then err should be nil.result should not be nil.", func(ctx convey.C) {
ctx.So(err, convey.ShouldBeNil)
ctx.So(result, convey.ShouldNotBeNil)
})
})
}
func TestDaoFlowByUnique(t *testing.T) {
convey.Convey("FlowByUnique", t, func(ctx convey.C) {
_, err := d.FlowByUnique(cntx, 0, "")
ctx.Convey("Then err should be nil.result should not be nil.", func(ctx convey.C) {
ctx.So(err, convey.ShouldBeNil)
})
})
}
func TestDaoFlowsByNet(t *testing.T) {
convey.Convey("FlowsByNet", t, func(ctx convey.C) {
_, err := d.FlowsByNet(cntx, []int64{})
ctx.Convey("Then err should be nil.result should not be nil.", func(ctx convey.C) {
ctx.So(err, convey.ShouldBeNil)
})
})
}
func TestDaoFlows(t *testing.T) {
convey.Convey("Flows", t, func(ctx convey.C) {
_, err := d.Flows(cntx, []int64{})
ctx.Convey("Then err should be nil.result should not be nil.", func(ctx convey.C) {
ctx.So(err, convey.ShouldBeNil)
})
})
}
func TestDaoFlowIDByNet(t *testing.T) {
convey.Convey("FlowIDByNet", t, func(ctx convey.C) {
_, err := d.FlowIDByNet(cntx, []int64{})
ctx.Convey("Then err should be nil.result should not be nil.", func(ctx convey.C) {
ctx.So(err, convey.ShouldBeNil)
})
})
}

View File

@@ -0,0 +1,120 @@
package gorm
import (
"context"
"time"
"go-common/app/admin/main/aegis/model/net"
"go-common/library/ecode"
"go-common/library/log"
"github.com/jinzhu/gorm"
)
// NetByID .
func (d *Dao) NetByID(c context.Context, id int64) (n *net.Net, err error) {
n = &net.Net{}
err = d.orm.Where("id=?", id).First(n).Error
if err == gorm.ErrRecordNotFound {
err = ecode.NothingFound
return
}
if err != nil {
log.Error("NetByID(%+v) error(%v)", id, err)
}
return
}
func (d *Dao) Nets(c context.Context, ids []int64) (n []*net.Net, err error) {
n = []*net.Net{}
if err = d.orm.Where("id in (?)", ids).Find(&n).Error; err != nil {
log.Error("Nets error(%v) ids(%v)", err, ids)
}
return
}
// NetByUnique .
func (d *Dao) NetByUnique(c context.Context, name string) (n *net.Net, err error) {
n = &net.Net{}
err = d.orm.Where("ch_name=?", name).First(n).Error
if err == gorm.ErrRecordNotFound {
err = nil
n = nil
return
}
if err != nil {
log.Error("NetByUnique(%+v) error(%v)", name, err)
}
return
}
// NetList .
func (d *Dao) NetList(c context.Context, pm *net.ListNetParam) (result *net.ListNetRes, err error) {
result = &net.ListNetRes{
Pager: net.Pager{
Num: pm.Pn,
Size: pm.Ps,
},
}
db := d.orm.Table(net.TableNet)
if len(pm.ID) > 0 {
db = db.Where("id in (?)", pm.ID)
}
if pm.BusinessID > 0 {
db = db.Where("business_id=?", pm.BusinessID)
}
err = db.Scopes(state(pm.State)).Count(&result.Pager.Total).Scopes(pager(pm.Ps, pm.Pn, pm.Sort)).Find(&result.Result).Error
if err != nil {
log.Error("NetList find error(%v) params(%+v)", err, pm)
}
return
}
// NetBindStartFlow .
func (d *Dao) NetBindStartFlow(c context.Context, tx *gorm.DB, id int64, flowID int64) (err error) {
if err = d.UpdateFields(c, tx, net.TableNet, id, map[string]interface{}{"start_flow_id": flowID}); err != nil {
log.Error("NetBindStartFlow d.UpdateFields error(%v) id(%d) flowid(%d)", err, id, flowID)
}
return
}
// NetIDByBusiness .
func (d *Dao) NetIDByBusiness(c context.Context, businessID []int64) (bizmap map[int64][]int64, err error) {
res := []struct {
ID int64 `gorm:"column:id"`
BusinessID int64 `gorm:"column:business_id"`
}{}
list := []*net.Net{}
bizmap = map[int64][]int64{}
if err = d.orm.Select("id, business_id").Where("business_id in (?)", businessID).
Scopes(Available).Find(&list).Scan(&res).Error; err != nil {
return
}
for _, item := range res {
bizmap[item.BusinessID] = append(bizmap[item.BusinessID], item.ID)
}
return
}
// NetsByBusiness .
func (d *Dao) NetsByBusiness(c context.Context, businessID []int64, onlyAvailable bool) (list []*net.Net, err error) {
list = []*net.Net{}
db := d.orm
if len(businessID) > 0 {
db = db.Where("business_id in (?)", businessID)
}
if onlyAvailable {
db = db.Scopes(Available)
}
if err = db.Find(&list).Error; err != nil {
log.Error("NetsByBusiness(%v) error(%v) onlyavailable(%v)", businessID, err, onlyAvailable)
}
return
}
// DisableNet .
func (d *Dao) DisableNet(c context.Context, tx *gorm.DB, id int64) (err error) {
err = d.UpdateFields(c, tx, net.TableNet, id, map[string]interface{}{"disable_time": time.Now()})
return
}

View File

@@ -0,0 +1,93 @@
package gorm
import (
"testing"
"github.com/smartystreets/goconvey/convey"
"go-common/app/admin/main/aegis/model/net"
)
func TestDaoNetByID(t *testing.T) {
convey.Convey("NetByID", t, func(ctx convey.C) {
d.NetByID(cntx, 1)
ctx.Convey("Then err should be nil.", func(ctx convey.C) {
})
})
}
func TestDao_NetList(t *testing.T) {
convey.Convey("NetList", t, func(ctx convey.C) {
pm := &net.ListNetParam{
BusinessID: 1,
//State: net.StateAvailable,
Ps: 20,
Pn: 1,
ID: []int64{1},
}
_, err := d.NetList(cntx, pm)
convey.So(err, convey.ShouldBeNil)
})
}
func TestDaoNetIDByBusiness(t *testing.T) {
convey.Convey("NetIDByBusiness", t, func(ctx convey.C) {
res, err := d.NetIDByBusiness(cntx, []int64{1, 2, 3})
t.Logf("res(%+v)", res)
ctx.Convey("Then err should be nil.", func(ctx convey.C) {
ctx.So(err, convey.ShouldBeNil)
})
})
}
func TestDaoNetsByBusiness(t *testing.T) {
convey.Convey("NetsByBusiness", t, func(ctx convey.C) {
_, err := d.NetsByBusiness(cntx, []int64{1}, true)
ctx.Convey("Then err should be nil.", func(ctx convey.C) {
ctx.So(err, convey.ShouldBeNil)
})
})
}
func TestDaoNets(t *testing.T) {
convey.Convey("Nets", t, func(ctx convey.C) {
_, err := d.Nets(cntx, []int64{})
ctx.Convey("Then err should be nil.", func(ctx convey.C) {
ctx.So(err, convey.ShouldBeNil)
})
})
}
func TestDaoNetByUnique(t *testing.T) {
convey.Convey("NetByUnique", t, func(ctx convey.C) {
_, err := d.NetByUnique(cntx, "")
ctx.Convey("Then err should be nil.", func(ctx convey.C) {
ctx.So(err, convey.ShouldBeNil)
})
})
}
func TestDaoNetBindStartFlow(t *testing.T) {
var (
tx, _ = d.BeginTx(cntx)
)
defer tx.Commit()
convey.Convey("NetBindStartFlow", t, func(ctx convey.C) {
err := d.NetBindStartFlow(cntx, tx, 0, 0)
ctx.Convey("Then err should be nil.", func(ctx convey.C) {
ctx.So(err, convey.ShouldBeNil)
})
})
}
func TestDaoDisableNet(t *testing.T) {
var (
tx, _ = d.BeginTx(cntx)
)
defer tx.Commit()
convey.Convey("DisableNet", t, func(ctx convey.C) {
err := d.DisableNet(cntx, tx, 0)
ctx.Convey("Then err should be nil.", func(ctx convey.C) {
ctx.So(err, convey.ShouldBeNil)
})
})
}

View File

@@ -0,0 +1,67 @@
package gorm
import (
"context"
"database/sql"
"go-common/app/admin/main/aegis/model"
"go-common/library/log"
)
//ReportTaskMetas 任务数据统计
func (d *Dao) ReportTaskMetas(c context.Context, bt string, et string, bizid, flowid int64, uids []int64, mnames map[int64]string, tp int8) (metas []*model.ReportMeta, missuid []int64, err error) {
db := d.orm.Table("task_report").Select("mtime,uid,type,content").Where("business_id=? AND type=?", bizid, tp)
if flowid != 0 {
db.Where("flow_id=?", flowid)
}
db = db.Where("mtime>=? AND mtime<?", bt, et)
if len(uids) > 0 {
db = db.Where("uid IN (?)", uids)
}
var rows *sql.Rows
if rows, err = db.Order("mtime asc").Rows(); err != nil {
log.Error("ReportTaskFlow error(%v)", err)
return
}
defer rows.Close()
for rows.Next() {
meta := &model.ReportMeta{}
if err = rows.Scan(&meta.Mtime, &meta.UID, &meta.Type, &meta.Content); err != nil {
return
}
if uname, ok := mnames[meta.UID]; ok {
meta.Uname = uname
} else {
missuid = append(missuid, meta.UID)
}
metas = append(metas, meta)
}
return
}
//TaskReports 任务报表记录
func (d *Dao) TaskReports(c context.Context, biz int64, flowID int64, tp []int8, statdateFrom string, statdateTo string) (res []*model.TaskReport, err error) {
res = []*model.TaskReport{}
db := d.orm
if statdateFrom != "" {
db = db.Where("stat_date>=?", statdateFrom)
}
if statdateTo != "" {
db = db.Where("stat_date <=?", statdateTo)
}
db = db.Where("business_id=?", biz)
if flowID > 0 {
db = db.Where("flow_id=?", flowID)
}
if len(tp) >= 0 {
db = db.Where("type in (?)", tp)
}
db = db.Order("stat_date desc, business_id desc, flow_id desc")
if err = db.Find(&res).Error; err != nil {
log.Error("TaskReports error(%v)", err)
}
return
}

View File

@@ -0,0 +1,40 @@
package gorm
import (
"context"
"fmt"
"testing"
"github.com/smartystreets/goconvey/convey"
"time"
)
func TestGormReportTaskFlow(t *testing.T) {
convey.Convey("ReportTaskFlow", t, func(ctx convey.C) {
var (
c = context.Background()
)
ctx.Convey("When everything goes positive", func(ctx convey.C) {
metas, _, err := d.ReportTaskMetas(c, "", "", 1, 1, []int64{}, map[int64]string{}, 0)
ctx.Convey("Then err should be nil.res should not be nil.", func(ctx convey.C) {
ctx.So(err, convey.ShouldBeNil)
for _, meta := range metas {
fmt.Println("meta:", meta)
}
})
})
})
}
func TestDao_TaskReports(t *testing.T) {
time.Time{}.Unix()
t.Logf("%s", time.Duration(time.Duration(3661)*time.Second).String())
return
convey.Convey("TaskReports", t, func(ctx convey.C) {
res, err := d.TaskReports(cntx, 1, 1, []int8{2, 3, 4}, "2019-01-14", "2019-01-15")
ctx.So(err, convey.ShouldBeNil)
for _, item := range res {
t.Logf("item(%+v)", item)
}
})
}

View File

@@ -0,0 +1,304 @@
package gorm
import (
"context"
"database/sql"
"encoding/json"
"go-common/app/admin/main/aegis/model/resource"
"go-common/library/log"
"github.com/jinzhu/gorm"
"go-common/app/admin/main/aegis/model"
)
const (
_resourceResSQL = "SELECT r.id, r.business_id, r.oid, r.mid,r.content,r.extra1,r.extra2,r.extra3,r.extra4,r.extra1s,r.extra2s,r.metadata, rr.attribute, rr.note, rr.reject_reason, rr.reason_id, rr.state, rr.pubtime, rr.deltime " +
"FROM resource r LEFT JOIN resource_result rr ON r.id = rr.rid WHERE r.id = ?"
_resByOIDSQL = "SELECT r.id, r.business_id, r.oid, r.mid,r.content,r.extra1,r.extra2,r.extra3,r.extra4,r.extra1s,r.extra2s,r.metadata, rr.attribute, rr.note, rr.reject_reason, rr.reason_id, rr.state, rr.pubtime, rr.deltime " +
"FROM resource r LEFT JOIN resource_result rr ON r.id = rr.rid WHERE r.business_id = ? AND r.oid = ?"
)
var _changeableFields = map[string]struct{}{
"extra1": {},
"extra2": {},
"extra3": {},
"extra4": {},
"extra5": {},
"extra6": {},
"extra1s": {},
"extra2s": {},
"extra3s": {},
"extra4s": {},
"extratime1": {},
}
// ListHelperForTask 补充任务列表里面的oid和content
func (d *Dao) ListHelperForTask(c context.Context, rids []int64) (res map[int64][]interface{}, err error) {
var (
rows *sql.Rows
id int64
oid, content, metadata string
)
if rows, err = d.orm.Table("resource").Select("id,oid,content,metadata").Where("id IN (?)", rids).Rows(); err != nil {
log.Error("listHelperForTask err(%v)", err)
return
}
res = make(map[int64][]interface{})
defer rows.Close()
for rows.Next() {
if err = rows.Scan(&id, &oid, &content, &metadata); err != nil {
log.Error("rows.Scan error(%v)", err)
return
}
metas := make(map[string]interface{})
if len(metadata) > 0 {
if err = json.Unmarshal([]byte(metadata), &metas); err != nil {
log.Error("ListHelperForTask err(%+v)\n", err)
}
err = nil
}
res[id] = []interface{}{oid, content, metas}
}
return
}
// TxAddResource .
func (d *Dao) TxAddResource(tx *gorm.DB, r *resource.Resource, rr *resource.Result) (rid int64, err error) {
err = tx.Table("resource").Where("business_id=? AND oid=?", r.BusinessID, r.OID).
Assign(map[string]interface{}{
"oid": r.OID,
"content": r.Content,
"extra1": r.Extra1,
"extra2": r.Extra2,
"extra3": r.Extra3,
"extra4": r.Extra4,
"extra1s": r.Extra1s,
"extra2s": r.Extra2s,
"metadata": r.MetaData,
"extra5": r.Extra5,
"extra6": r.Extra6,
"extra3s": r.Extra3s,
"extra4s": r.Extra4s,
"extratime1": r.ExtraTime1,
"octime": r.OCtime,
"ptime": r.Ptime,
}).FirstOrCreate(&r).Error
if err != nil {
return
}
rid = r.ID
rr.RID = r.ID
err = tx.Table("resource_result").Where("rid=?", rr.RID).Assign(map[string]interface{}{
"attribute": rr.Attribute,
"note": rr.Note,
"reject_reason": rr.RejectReason,
"reason_id": rr.ReasonID,
"state": rr.State,
"pubtime": rr.PubTime,
"deltime": rr.DelTime,
}).FirstOrCreate(&rr).Error
return
}
// ResourceByOID .
func (d *Dao) ResourceByOID(c context.Context, OID string, bizID int64) (res *resource.Resource, err error) {
res = &resource.Resource{}
if err = d.orm.Where("oid = ? AND business_id = ?", OID, bizID).First(res).Error; err == gorm.ErrRecordNotFound {
res = nil
err = nil
}
return
}
// RidsByOids .
func (d *Dao) RidsByOids(c context.Context, bizID int64, oids []string) (rids string, err error) {
err = d.orm.Table("resource").Select("GROUP_CONCAT(id)").Where("business_id=? AND oid IN (?)", bizID, oids).Row().Scan(&rids)
return
}
// OidByRID 通过rid查到oid
func (d *Dao) OidByRID(c context.Context, rid int64) (oid string, err error) {
if err = d.orm.Table("resource").Select("oid").Where("id=?", rid).Row().Scan(&oid); err == sql.ErrNoRows {
err = nil
}
return
}
// TxUpdateResult .
func (d *Dao) TxUpdateResult(ormTx *gorm.DB, rid int64, res map[string]interface{}, rscRes *resource.Result) (err error) {
params := make(map[string]interface{})
for k, v := range res {
if k != "state" && k != "attribute" {
continue
}
params[k] = v
}
db := ormTx.Table("resource_result").
Where("rid = ?", rid)
//Update(params)
if rscRes != nil {
if rscRes.Attribute != -1 {
params["attribute"] = rscRes.Attribute
}
if rscRes.Note != "" {
params["note"] = rscRes.Note
}
if rscRes.RejectReason != "" {
params["reject_reason"] = rscRes.RejectReason
}
if rscRes.ReasonID != 0 {
params["reason_id"] = rscRes.ReasonID
}
}
return db.Update(params).Error
}
// TxUpdateResource . TODO Resource表的字段要不要直接审核提交变更 还是等待业务方同步更新?(例如单话的上线下线)
func (d *Dao) TxUpdateResource(ormTx *gorm.DB, rid int64, res map[string]interface{}) (err error) {
params := make(map[string]interface{})
for k, v := range res {
if _, ok := _changeableFields[k]; !ok {
continue
}
params[k] = v
}
return ormTx.Table("resource").Where("id = ?", rid).Update(params).Error
}
// TxUpdateState 更新状态
func (d *Dao) TxUpdateState(tx *gorm.DB, rids []int64, state int) (err error) {
return tx.Table("resource_result").Where("rid IN (?)", rids).Update("state", state).Error
}
// UpdateResource 更新资源
func (d *Dao) UpdateResource(c context.Context, bizid int64, oid string, update map[string]interface{}) (rows int64, err error) {
db := d.orm.Table("resource").Where("business_id=? AND oid=?", bizid, oid).Update(update)
return db.RowsAffected, db.Error
}
// ResourceRes .
func (d *Dao) ResourceRes(c context.Context, rid int64) (res *resource.Res, err error) {
res = &resource.Res{}
if err = d.orm.Raw(_resourceResSQL, rid).Scan(res).Error; err == gorm.ErrRecordNotFound {
res = nil
err = nil
}
return
}
// ResByOID .
func (d *Dao) ResByOID(c context.Context, bizID int64, OID string) (res *resource.Res, err error) {
res = &resource.Res{}
if err = d.orm.Raw(_resByOIDSQL, bizID, OID).Scan(res).Error; err == gorm.ErrRecordNotFound {
res = nil
err = nil
}
return
}
//ResOIDByID 根据id获取资源oid
func (d *Dao) ResOIDByID(c context.Context, rids []int64) (res map[int64]string, err error) {
list := []struct {
ID int64 `gorm:"column:id"`
OID string `gorm:"column:oid"`
}{}
res = map[int64]string{}
if err = d.orm.Table("resource").Select("id,oid").Where("id in (?)", rids).Find(&list).Error; err != nil {
log.Error("ResOIDByID error(%v) rids(%v)", err, rids)
return
}
for _, item := range list {
res[item.ID] = item.OID
}
return
}
//ResIDByOID 根据oid获取rid
func (d *Dao) ResIDByOID(C context.Context, bizID int64, oids []string) (res map[string]int64, err error) {
list := []struct {
ID int64 `gorm:"column:id"`
OID string `gorm:"column:oid"`
}{}
res = map[string]int64{}
if err = d.orm.Table("resource").Select("id,oid").Where("business_id=? and oid in (?)", bizID, oids).Find(&list).Error; err != nil {
log.Error("ResIDByOID error(%v) oids(%v)", err, oids)
return
}
for _, item := range list {
res[item.OID] = item.ID
}
return
}
//ResourceHit 根据状态筛选资源
func (d *Dao) ResourceHit(c context.Context, rids []int64) (hitids map[int64]int64, err error) {
hitids = make(map[int64]int64)
rows, err := d.orm.Table("resource_result").Select("rid,state").Where("rid IN (?)", rids).Rows()
if err != nil {
log.Error("ResourceHitState error(%v)", err)
return
}
defer rows.Close()
for rows.Next() {
var rid, state int64
if err = rows.Scan(&rid, &state); err != nil {
log.Error("ResourceHitState error(%v)", err)
}
hitids[rid] = state
}
return
}
//ResultByRID result by rid
func (d *Dao) ResultByRID(c context.Context, rid int64) (res *resource.Result, err error) {
res = &resource.Result{}
if err = d.orm.Where("rid=?", rid).First(&res).Error; err == gorm.ErrRecordNotFound {
log.Error("ResultByRID rid(%d) error(%v)", rid, err)
}
return
}
//MetaByRID .
func (d *Dao) MetaByRID(c context.Context, rids []int64) (metas map[int64]string, err error) {
var rows *sql.Rows
metas = make(map[int64]string)
rows, err = d.orm.Table("resource").Select("id,metadata").Where("id IN (?)", rids).Rows()
if err != nil {
log.Error("MetaByRID Query error(%v)", err)
return
}
defer rows.Close()
for rows.Next() {
var (
id int64
meta string
)
if err = rows.Scan(&id, &meta); err != nil {
log.Error("MetaByRID rows.Scan error(%v)", err)
return
}
metas[id] = meta
}
return
}
//UpsertByOIDs 获取需要更新到搜索部分
func (d *Dao) UpsertByOIDs(c context.Context, businessID int64, oids []string) (res []*model.UpsertItem, err error) {
res = []*model.UpsertItem{}
sqlstr := `SELECT r.id,r.extra1,r.extra2,r.extra3,r.extra4,rr.state
FROM resource r
LEFT JOIN resource_result rr ON r.id=rr.rid
WHERE r.business_id=? AND r.oid IN (?)`
if err = d.orm.Raw(sqlstr, businessID, oids).Find(&res).Error; err != nil {
log.Error("UpsertByOIDs error(%+v) businessid(%d) oids(%+v)", err, businessID, oids)
}
return
}

View File

@@ -0,0 +1,220 @@
package gorm
import (
"context"
"testing"
"go-common/app/admin/main/aegis/model/resource"
"github.com/smartystreets/goconvey/convey"
)
func TestGormListHelperForTask(t *testing.T) {
convey.Convey("ListHelperForTask", t, func(ctx convey.C) {
var (
c = context.Background()
rids = []int64{}
)
ctx.Convey("When everything goes positive", func(ctx convey.C) {
res, err := d.ListHelperForTask(c, rids)
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 TestGormResourceByOID(t *testing.T) {
var (
c = context.Background()
)
convey.Convey("ResourceByOID", t, func(ctx convey.C) {
ctx.Convey("When everything goes positive", func(ctx convey.C) {
_, err := d.ResourceByOID(c, "", 0)
ctx.Convey("Then err should be nil.res should not be nil.", func(ctx convey.C) {
ctx.So(err, convey.ShouldBeNil)
})
})
})
}
func TestGormOidByRID(t *testing.T) {
var (
c = context.Background()
)
convey.Convey("OidByRID", t, func(ctx convey.C) {
ctx.Convey("When everything goes positive", func(ctx convey.C) {
_, err := d.OidByRID(c, 0)
ctx.Convey("Then err should be nil.res should not be nil.", func(ctx convey.C) {
ctx.So(err, convey.ShouldBeNil)
})
})
})
}
func TestGormTxUpdateResult(t *testing.T) {
convey.Convey("TxUpdateResult", t, func(ctx convey.C) {
var (
tx, _ = d.BeginTx(context.TODO())
rid = int64(0)
res = map[string]interface{}{"extra1": 1}
rscRes = &resource.Result{}
)
defer tx.Commit()
ctx.Convey("When everything goes positive", func(ctx convey.C) {
err := d.TxUpdateResult(tx, rid, res, rscRes)
ctx.Convey("Then err should be nil.", func(ctx convey.C) {
ctx.So(err, convey.ShouldBeNil)
})
})
})
}
func TestGormResourceRes(t *testing.T) {
convey.Convey("ResourceRes", t, func(ctx convey.C) {
ctx.Convey("When everything goes positive", func(ctx convey.C) {
_, err := d.ResourceRes(context.TODO(), 0)
ctx.Convey("Then err should be nil.", func(ctx convey.C) {
ctx.So(err, convey.ShouldBeNil)
})
})
})
}
func TestGormResByOID(t *testing.T) {
convey.Convey("ResByOID", t, func(ctx convey.C) {
ctx.Convey("When everything goes positive", func(ctx convey.C) {
_, err := d.ResByOID(context.TODO(), 0, "")
ctx.Convey("Then err should be nil.", func(ctx convey.C) {
ctx.So(err, convey.ShouldBeNil)
})
})
})
}
func TestGormUpdateResource(t *testing.T) {
convey.Convey("UpdateResource", t, func(ctx convey.C) {
ctx.Convey("When everything gose positive", func(ctx convey.C) {
d.UpdateResource(context.TODO(), 1, "xyz", map[string]interface{}{"mid": 123})
ctx.Convey("Then err should be nil.", func(ctx convey.C) {
})
})
})
}
func TestGormResOIDByID(t *testing.T) {
convey.Convey("ResOIDByID", t, func(ctx convey.C) {
ctx.Convey("When everything gose positive", func(ctx convey.C) {
res, err := d.ResOIDByID(context.TODO(), []int64{1, 2})
t.Logf("res(%+v)", res)
ctx.Convey("Then err should be nil.", func(ctx convey.C) {
convey.So(err, convey.ShouldBeNil)
})
})
})
}
func TestGormResIDByOID(t *testing.T) {
convey.Convey("ResIDByOID", t, func(ctx convey.C) {
ctx.Convey("When everything gose positive", func(ctx convey.C) {
res, err := d.ResIDByOID(context.TODO(), 1, []string{"1", "2"})
t.Logf("res(%+v)", res)
ctx.Convey("Then err should be nil.", func(ctx convey.C) {
convey.So(err, convey.ShouldBeNil)
})
})
})
}
func TestGormResourceHit(t *testing.T) {
convey.Convey("ResourceHit", t, func(ctx convey.C) {
ctx.Convey("When everything gose positive", func(ctx convey.C) {
_, err := d.ResourceHit(context.TODO(), []int64{})
ctx.Convey("Then err should be nil.", func(ctx convey.C) {
convey.So(err, convey.ShouldBeNil)
})
})
})
}
func TestGormResultByRID(t *testing.T) {
convey.Convey("ResultByRID", t, func(ctx convey.C) {
ctx.Convey("When everything gose positive", func(ctx convey.C) {
d.ResultByRID(context.TODO(), 50)
ctx.Convey("Then err should be nil.", func(ctx convey.C) {
})
})
})
}
func TestGormRidsByOids(t *testing.T) {
convey.Convey("RidsByOids", t, func(ctx convey.C) {
ctx.Convey("When everything gose positive", func(ctx convey.C) {
d.RidsByOids(cntx, 0, []string{})
ctx.Convey("Then err should be nil.", func(ctx convey.C) {
})
})
})
}
func TestGormTxUpdateResource(t *testing.T) {
convey.Convey("TxUpdateResource", t, func(ctx convey.C) {
var (
tx, _ = d.BeginTx(context.TODO())
rid = int64(0)
res = map[string]interface{}{"extra1": 1}
)
defer tx.Commit()
ctx.Convey("When everything goes positive", func(ctx convey.C) {
err := d.TxUpdateResource(tx, rid, res)
ctx.Convey("Then err should be nil.", func(ctx convey.C) {
ctx.So(err, convey.ShouldBeNil)
})
})
})
}
func TestGormTxUpdateState(t *testing.T) {
convey.Convey("TxUpdateState", t, func(ctx convey.C) {
var (
tx, _ = d.BeginTx(context.TODO())
rids = []int64{0}
)
defer tx.Commit()
ctx.Convey("When everything goes positive", func(ctx convey.C) {
err := d.TxUpdateState(tx, rids, 0)
ctx.Convey("Then err should be nil.", func(ctx convey.C) {
ctx.So(err, convey.ShouldBeNil)
})
})
})
}
func TestGormMetaByRID(t *testing.T) {
convey.Convey("MetaByRID", t, func(ctx convey.C) {
var (
rids = []int64{0}
)
ctx.Convey("When everything goes positive", func(ctx convey.C) {
_, err := d.MetaByRID(cntx, rids)
ctx.Convey("Then err should be nil.", func(ctx convey.C) {
ctx.So(err, convey.ShouldBeNil)
})
})
})
}
func TestGormUpsertByOIDs(t *testing.T) {
convey.Convey("UpsertByOIDs", t, func(ctx convey.C) {
ctx.Convey("When everything gose positive", func(ctx convey.C) {
res, err := d.UpsertByOIDs(context.TODO(), 1, []string{"oid000001", "oid000002"})
for _, item := range res {
t.Logf("res(%+v)", item)
}
ctx.Convey("Then err should be nil.", func(ctx convey.C) {
ctx.So(err, convey.ShouldBeNil)
})
})
})
}

View File

@@ -0,0 +1,146 @@
package gorm
import (
"context"
"database/sql"
"go-common/app/admin/main/aegis/model/task"
"go-common/library/log"
"github.com/jinzhu/gorm"
)
const (
_submitSQL = "UPDATE task SET state=?,uid=?,utime=? WHERE id=? AND state=? AND uid=?"
)
// TxSubmit 提交任务
func (d *Dao) TxSubmit(tx *gorm.DB, opt *task.SubmitOptions, state int8) (rows int64, err error) {
rows = tx.Exec(_submitSQL, state, opt.UID, opt.Utime, opt.TaskID, opt.OldState, opt.OldUID).RowsAffected
return
}
// TxCloseTasks close
func (d *Dao) TxCloseTasks(tx *gorm.DB, rids []int64, uid int64) (err error) {
err = tx.Table("task").Where("rid IN (?) AND state<?", rids, task.TaskStateSubmit).Update("state", task.TaskStateClosed).Update("uid", uid).Error
return
}
// CloseTask .
func (d *Dao) CloseTask(c context.Context, id int64) (err error) {
return d.orm.Table("task").Where("id=?", id).Update("state", task.TaskStateClosed).Update("uid", 399).Error
}
// TaskByRID task by rid
func (d *Dao) TaskByRID(c context.Context, rid, flowid int64) (t *task.Task, err error) {
db := d.orm.Model(&task.Task{}).Where("rid = ? AND state<?", rid, task.TaskStateSubmit)
if flowid > 0 {
db = db.Where("flow_id=?", flowid)
}
t = &task.Task{}
if err = db.Find(t).Error; err == gorm.ErrRecordNotFound {
err = nil
t = nil
}
return
}
// MaxWeight max weight
func (d *Dao) MaxWeight(c context.Context, bizID, flowID int64) (max int64, err error) {
if err = d.orm.Table("task").Select("max(weight)").Where("business_id = ? AND flow_id = ?", bizID, flowID).
Where("state = ? OR state = ?", task.TaskStateInit, task.TaskStateDispatch).Row().Scan(&max); err != nil {
max = 0
err = nil
}
return
}
// UndoStat 未完成
func (d *Dao) UndoStat(c context.Context, bizID, flowID, UID int64) (stat *task.UnDOStat, err error) {
stat = &task.UnDOStat{}
err = d.orm.Raw(`SELECT COUNT(CASE WHEN admin_id>0 AND state = 0 THEN 1 ELSE NULL END) assign,
COUNT(CASE WHEN admin_id = 0 AND state = 2 THEN 1 ELSE NULL END) delay,
COUNT(CASE WHEN admin_id = 0 AND state = 1 THEN 1 ELSE NULL END) normal
FROM task WHERE business_id=? AND flow_id=? AND uid=?`, bizID, flowID, UID).Scan(stat).Error
return
}
// TaskStat 任务详情统计
func (d *Dao) TaskStat(c context.Context, bizID, flowID, UID int64) (stat *task.Stat, err error) {
stat = &task.Stat{}
err = d.orm.Raw(`SELECT COUNT(CASE WHEN admin_id=0 AND state = 0 THEN 1 ELSE NULL END) normal,
COUNT(CASE WHEN admin_id>0 AND state = 0 THEN 1 ELSE NULL END) assign,
COUNT(CASE WHEN state=2 THEN 1 ELSE NULL END) delayTotal,
COUNT(CASE WHEN uid=? AND state=2 THEN 1 ELSE NULL END) delayPersonal
FROM task WHERE business_id=? AND flow_id=?`, UID, bizID, flowID).Scan(stat).Error
return
}
// TaskListSeized 停滞任务
func (d *Dao) TaskListSeized(c context.Context, opt *task.ListOptions) (ids []int64, count int64, err error) {
return d.tasklist(c, "seized", opt.BusinessID, opt.FlowID, opt.UID, opt.Pn, opt.Ps)
}
// TaskListDelayd 延迟任务
func (d *Dao) TaskListDelayd(c context.Context, opt *task.ListOptions) (ids []int64, count int64, err error) {
return d.tasklist(c, "delayd", opt.BusinessID, opt.FlowID, opt.UID, opt.Pn, opt.Ps)
}
// TaskListAssignd 指派停滞任务
func (d *Dao) TaskListAssignd(c context.Context, opt *task.ListOptions) (ids []int64, count int64, err error) {
return d.tasklist(c, "assignd", opt.BusinessID, opt.FlowID, opt.UID, opt.Pn, opt.Ps)
}
func (d *Dao) tasklist(c context.Context, ltp string, bizID, flowID, UID int64, pn, ps int) (ids []int64, count int64, err error) {
db := d.orm.Table("task").Where("business_id=? AND flow_id=?", bizID, flowID)
switch ltp {
case "seized":
db = db.Where("state=?", task.TaskStateDispatch)
case "delayd":
db = db.Where("state=?", task.TaskStateDelay)
case "assignd":
db = db.Where("state=? AND admin_id>0", task.TaskStateDispatch)
}
if UID > 0 {
db = db.Where("uid=?", UID)
}
var rows *sql.Rows
rows, err = db.Count(&count).Select("id").Order("weight DESC").Offset((pn - 1) * ps).Limit(ps).Rows()
if err != nil {
log.Error("tasklist error(%v)", err)
return
}
defer rows.Close()
for rows.Next() {
var id int64
if err = rows.Scan(&id); err != nil {
log.Error("tasklist error(%v)", err)
return
}
ids = append(ids, id)
}
return
}
//TaskHitAuditing 检查资源是否正在审核
func (d *Dao) TaskHitAuditing(c context.Context, rids []int64) (map[int64]struct{}, error) {
hitids := make(map[int64]struct{})
rows, err := d.orm.Table("task").Select("rid").Where("rid IN (?)", rids).
Where("state = ? AND gtime!=0", task.TaskStateDispatch).Rows()
if err != nil {
return hitids, err
}
defer rows.Close()
for rows.Next() {
var id int64
if err = rows.Scan(&id); err != nil {
return hitids, err
}
hitids[id] = struct{}{}
}
return hitids, err
}

View File

@@ -0,0 +1,64 @@
package gorm
import (
"context"
taskmod "go-common/app/admin/main/aegis/model/task"
"go-common/library/log"
)
// AddConfig add config
func (d *Dao) AddConfig(c context.Context, config *taskmod.Config, confJSON interface{}) (err error) {
if config.ConfType == taskmod.TaskConfigRangeWeight { //粉丝数,等待时长,分组权重配置去重
name := "%" + confJSON.(*taskmod.RangeWeightConfig).Name + "%"
err = d.orm.Table("task_config").Where("business_id=? AND flow_id=? AND conf_type=? AND conf_json LIKE ?", config.BusinessID, config.FlowID, taskmod.TaskConfigRangeWeight, name).
Assign(map[string]interface{}{
"conf_json": config.ConfJSON,
"btime": config.Btime,
"etime": config.Etime,
"uid": config.UID,
"uname": config.Uname,
"description": config.Description,
}).FirstOrCreate(config).Error
return err
}
return d.orm.Create(config).Error
}
// UpdateConfig update config
func (d *Dao) UpdateConfig(c context.Context, config *taskmod.Config) (err error) {
return d.orm.Model(&taskmod.Config{}).Where("id=?", config.ID).Update(config).Error
}
// SetStateConfig update config
func (d *Dao) SetStateConfig(c context.Context, id int64, state int8) (err error) {
return d.orm.Model(&taskmod.Config{}).Where("id=?", id).Update("state", state).Error
}
// QueryConfigs list config
func (d *Dao) QueryConfigs(c context.Context, queryParams *taskmod.QueryParams) (configs []*taskmod.Config, count int64, err error) {
db := d.orm.Model(&taskmod.Config{}).Where("conf_type=?", queryParams.ConfType).Where("state=?", queryParams.State)
if queryParams.BusinessID > 0 {
db = db.Where("business_id=?", queryParams.BusinessID)
}
if queryParams.FlowID > 0 {
db = db.Where("flow_id=?", queryParams.FlowID)
}
if len(queryParams.Btime) > 0 && len(queryParams.Etime) > 0 {
db = db.Where("mtime>=? AND mtime<=?", queryParams.Btime, queryParams.Etime)
}
if len(queryParams.ConfName) > 0 {
db = db.Where("conf_json LIKE '%" + queryParams.ConfName + "%'")
}
if err = db.Count(&count).Offset((queryParams.Pn - 1) * queryParams.Ps).Order("mtime DESC").Limit(queryParams.Ps).Find(&configs).Error; err != nil {
log.Error("query error(%v)", err)
return
}
return
}
// DeleteConfig delete config
func (d *Dao) DeleteConfig(c context.Context, id int64) (err error) {
return d.orm.Where("id=?", id).Delete(&taskmod.Config{}).Error
}

View File

@@ -0,0 +1,73 @@
package gorm
import (
"context"
"testing"
"go-common/app/admin/main/aegis/model/task"
"github.com/smartystreets/goconvey/convey"
)
func TestDaoQueryConfigs(t *testing.T) {
convey.Convey("QueryConfigs", t, func(ctx convey.C) {
var (
c = context.Background()
params = &task.QueryParams{
BusinessID: 1,
FlowID: 1,
Btime: "0000-00-00 00:00:00",
Etime: "2018-12-12 12:12:12",
ConfName: "mid",
}
)
ctx.Convey("When everything goes positive", func(ctx convey.C) {
_, _, err := d.QueryConfigs(c, params)
ctx.Convey("Then err should be nil.res should not be nil.", func(ctx convey.C) {
ctx.So(err, convey.ShouldBeNil)
})
})
})
}
func TestDaoDeleteConfig(t *testing.T) {
convey.Convey("DeleteConfig", t, func(ctx convey.C) {
var (
c = context.Background()
)
ctx.Convey("When everything goes positive", func(ctx convey.C) {
err := d.DeleteConfig(c, 0)
ctx.Convey("Then err should be nil.res should not be nil.", func(ctx convey.C) {
ctx.So(err, convey.ShouldBeNil)
})
})
})
}
func TestDaoSetStateConfig(t *testing.T) {
convey.Convey("SetStateConfig", t, func(ctx convey.C) {
var (
c = context.Background()
)
ctx.Convey("When everything goes positive", func(ctx convey.C) {
err := d.SetStateConfig(c, 0, 0)
ctx.Convey("Then err should be nil.res should not be nil.", func(ctx convey.C) {
ctx.So(err, convey.ShouldBeNil)
})
})
})
}
func TestDaoUpdateConfig(t *testing.T) {
convey.Convey("UpdateConfig", t, func(ctx convey.C) {
var (
config = &task.Config{}
)
ctx.Convey("When everything goes positive", func(ctx convey.C) {
err := d.UpdateConfig(cntx, config)
ctx.Convey("Then err should be nil.res should not be nil.", func(ctx convey.C) {
ctx.So(err, convey.ShouldBeNil)
})
})
})
}

View File

@@ -0,0 +1,155 @@
package gorm
import (
"context"
"testing"
"go-common/app/admin/main/aegis/model/common"
taskmod "go-common/app/admin/main/aegis/model/task"
"github.com/smartystreets/goconvey/convey"
)
func TestUndoStat(t *testing.T) {
convey.Convey("UndoStat", t, func(ctx convey.C) {
var (
c = context.Background()
)
ctx.Convey("When everything goes positive", func(ctx convey.C) {
res, err := d.UndoStat(c, 0, 0, 0)
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 TestTaskStat(t *testing.T) {
convey.Convey("TaskStat", t, func(ctx convey.C) {
var (
c = context.Background()
)
ctx.Convey("When everything goes positive", func(ctx convey.C) {
res, err := d.TaskStat(c, 0, 0, 0)
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 TestTaskMaxWeight(t *testing.T) {
convey.Convey("MaxWeight", t, func(ctx convey.C) {
var (
c = context.Background()
)
ctx.Convey("When everything goes positive", func(ctx convey.C) {
_, err := d.MaxWeight(c, 0, 0)
ctx.Convey("Then err should be nil.res should not be nil.", func(ctx convey.C) {
ctx.So(err, convey.ShouldBeNil)
})
})
})
}
func TestTaskListSeized(t *testing.T) {
convey.Convey("TaskListSeized", t, func(ctx convey.C) {
var (
c = context.Background()
)
ctx.Convey("When everything gose positive", func(ctx convey.C) {
_, _, err := d.TaskListSeized(c, &taskmod.ListOptions{})
ctx.Convey("Then err should be nil.res should not be nil.", func(ctx convey.C) {
ctx.So(err, convey.ShouldBeNil)
})
})
})
}
func TestTxCloseTasks(t *testing.T) {
convey.Convey("TxCloseTasks", t, func(ctx convey.C) {
var (
c = context.Background()
tx, _ = d.BeginTx(c)
)
defer tx.Commit()
ctx.Convey("When everything gose positive", func(ctx convey.C) {
err := d.TxCloseTasks(tx, []int64{}, 0)
ctx.Convey("Then err should be nil.", func(ctx convey.C) {
ctx.So(err, convey.ShouldBeNil)
})
})
})
}
func TestTxSubmit(t *testing.T) {
convey.Convey("TxSubmit", t, func(ctx convey.C) {
var (
tx, _ = d.BeginTx(cntx)
opt = &taskmod.SubmitOptions{}
)
defer tx.Commit()
ctx.Convey("When everything gose positive", func(ctx convey.C) {
_, err := d.TxSubmit(tx, opt, 0)
ctx.Convey("Then err should be nil.", func(ctx convey.C) {
ctx.So(err, convey.ShouldBeNil)
})
})
})
}
func TestCloseTask(t *testing.T) {
convey.Convey("CloseTask", t, func(ctx convey.C) {
ctx.Convey("When everything gose positive", func(ctx convey.C) {
err := d.CloseTask(cntx, 0)
ctx.Convey("Then err should be nil.", func(ctx convey.C) {
ctx.So(err, convey.ShouldBeNil)
})
})
})
}
func TestTaskByRID(t *testing.T) {
convey.Convey("TaskByRID", t, func(ctx convey.C) {
ctx.Convey("When everything gose positive", func(ctx convey.C) {
_, err := d.TaskByRID(cntx, 0, 1)
ctx.Convey("Then err should be nil.", func(ctx convey.C) {
ctx.So(err, convey.ShouldBeNil)
})
})
})
}
func TestTaskListAssignd(t *testing.T) {
convey.Convey("TaskListAssignd", t, func(ctx convey.C) {
var (
opt = &taskmod.ListOptions{}
)
ctx.Convey("When everything gose positive", func(ctx convey.C) {
_, _, err := d.TaskListAssignd(cntx, opt)
ctx.Convey("Then err should be nil.", func(ctx convey.C) {
ctx.So(err, convey.ShouldBeNil)
})
})
})
}
func TestTaskListDelayd(t *testing.T) {
convey.Convey("TaskListDelayd", t, func(ctx convey.C) {
var (
opt = &taskmod.ListOptions{
BaseOptions: common.BaseOptions{
UID: 1,
},
}
)
ctx.Convey("When everything gose positive", func(ctx convey.C) {
_, _, err := d.TaskListDelayd(cntx, opt)
ctx.Convey("Then err should be nil.", func(ctx convey.C) {
ctx.So(err, convey.ShouldBeNil)
})
})
})
}

View File

@@ -0,0 +1,126 @@
package gorm
import (
"context"
"strings"
"github.com/jinzhu/gorm"
"go-common/app/admin/main/aegis/model/net"
"go-common/library/ecode"
"go-common/library/log"
)
// TokenByID .
func (d *Dao) TokenByID(c context.Context, id int64) (t *net.Token, err error) {
t = &net.Token{}
err = d.orm.Where("id=?", id).First(t).Error
if err == gorm.ErrRecordNotFound {
err = ecode.AegisTokenNotFound
return
}
if err != nil {
log.Error("TokenByID(%+v) error(%v)", id, err)
}
return
}
// Tokens .
func (d *Dao) Tokens(c context.Context, ids []int64) (list []*net.Token, err error) {
list = []*net.Token{}
err = d.orm.Where("id in (?)", ids).Find(&list).Error
if err != nil {
log.Error("Tokens(%v) error(%v)", ids, err)
}
return
}
func (d *Dao) tokenListDB(netID []int64, id []int64, name string, onlyAssign bool) (db *gorm.DB) {
db = d.orm.Table(net.TableToken).Where("net_id in (?)", netID)
if len(id) > 0 {
db = db.Where("id in (?)", id)
}
name = strings.TrimSpace(name)
if name != "" {
db = db.Where("name=?", name)
}
if onlyAssign {
db = db.Where("compare=?", net.TokenCompareAssign)
}
return
}
// TokenListWithPager .
func (d *Dao) TokenListWithPager(c context.Context, pm *net.ListTokenParam) (result *net.ListTokenRes, err error) {
result = &net.ListTokenRes{
Pager: net.Pager{
Num: pm.Pn,
Size: pm.Ps,
},
}
db := d.tokenListDB([]int64{pm.NetID}, pm.ID, pm.Name, pm.Assign)
err = db.Count(&result.Pager.Total).Scopes(pager(pm.Ps, pm.Pn, pm.Sort)).Find(&result.Result).Error
if err != nil {
log.Error("TokenListWithPager find error(%v) params(%+v)", err, pm)
}
return
}
// TokenList .
func (d *Dao) TokenList(c context.Context, netID []int64, id []int64, name string, onlyAssign bool) (list []*net.Token, err error) {
err = d.tokenListDB(netID, id, name, onlyAssign).Find(&list).Error
if err != nil {
log.Error("TokenList find error(%v)", err)
}
return
}
// TokenByUnique .
func (d *Dao) TokenByUnique(c context.Context, netID int64, name string, compare int8, value string) (t *net.Token, err error) {
t = &net.Token{}
err = d.orm.Where("net_id=? AND name=? AND compare=? AND value=?", netID, name, compare, value).First(t).Error
if err == gorm.ErrRecordNotFound {
err = nil
t = nil
return
}
if err != nil {
log.Error("TokenByUnique(%d,%s,%d,%s) error(%v)", netID, name, compare, value, err)
}
return
}
// TokenBinds .
func (d *Dao) TokenBinds(c context.Context, id []int64) (t []*net.TokenBind, err error) {
t = []*net.TokenBind{}
err = d.orm.Where("id in (?)", id).Find(&t).Error
if err != nil {
log.Error("TokenBinds(%+v) error(%v)", id, err)
}
return
}
// TokenBindByElement .
func (d *Dao) TokenBindByElement(c context.Context, elementID []int64, tp []int8, onlyAvailable bool) (binds map[int64][]*net.TokenBind, err error) {
binds = map[int64][]*net.TokenBind{}
list := []*net.TokenBind{}
db := d.orm.Where("element_id in (?) AND type in (?)", elementID, tp)
if onlyAvailable {
db = db.Scopes(Available)
}
if err = db.Find(&list).Error; err != nil {
log.Error("TokenBindByElement error(%v) elementid(%d) type(%v) onlyavailable(%v)", err, elementID, tp, onlyAvailable)
return
}
for _, item := range list {
if _, exist := binds[item.ElementID]; !exist {
binds[item.ElementID] = []*net.TokenBind{item}
continue
}
binds[item.ElementID] = append(binds[item.ElementID], item)
}
return
}

View File

@@ -0,0 +1,81 @@
package gorm
import (
"go-common/app/admin/main/aegis/model/net"
"testing"
"github.com/smartystreets/goconvey/convey"
)
func TestDaoTokens(t *testing.T) {
var (
ids = []int64{}
)
convey.Convey("Tokens", t, func(ctx convey.C) {
no, err := d.Tokens(cntx, ids)
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 TestDaoTokenList(t *testing.T) {
convey.Convey("TokenList", t, func(ctx convey.C) {
result, err := d.TokenList(cntx, []int64{1}, []int64{}, "1", true)
ctx.Convey("Then err should be nil.result should not be nil.", func(ctx convey.C) {
ctx.So(err, convey.ShouldBeNil)
ctx.So(result, convey.ShouldNotBeNil)
})
})
}
func TestDaoTokenByID(t *testing.T) {
convey.Convey("TokenByID", t, func(ctx convey.C) {
d.TokenByID(cntx, 1)
ctx.Convey("Then err should be nil.result should not be nil.", func(ctx convey.C) {
})
})
}
func TestDaoTokenListWithPager(t *testing.T) {
var (
pm = &net.ListTokenParam{}
)
convey.Convey("TokenListWithPager", t, func(ctx convey.C) {
result, err := d.TokenListWithPager(cntx, pm)
ctx.Convey("Then err should be nil.result should not be nil.", func(ctx convey.C) {
ctx.So(err, convey.ShouldBeNil)
ctx.So(result, convey.ShouldNotBeNil)
})
})
}
func TestDaoTokenByUnique(t *testing.T) {
convey.Convey("TokenByUnique", t, func(ctx convey.C) {
_, err := d.TokenByUnique(cntx, 0, "", 0, "")
ctx.Convey("Then err should be nil.result should not be nil.", func(ctx convey.C) {
ctx.So(err, convey.ShouldBeNil)
})
})
}
func TestDaoTokenBinds(t *testing.T) {
convey.Convey("TokenBinds", t, func(ctx convey.C) {
result, err := d.TokenBinds(cntx, []int64{})
ctx.Convey("Then err should be nil.result should not be nil.", func(ctx convey.C) {
ctx.So(err, convey.ShouldBeNil)
ctx.So(result, convey.ShouldNotBeNil)
})
})
}
func TestDaoTokenBindByElement(t *testing.T) {
convey.Convey("TokenBindByElement", t, func(ctx convey.C) {
result, err := d.TokenBindByElement(cntx, []int64{}, []int8{}, true)
ctx.Convey("Then err should be nil.result should not be nil.", func(ctx convey.C) {
ctx.So(err, convey.ShouldBeNil)
ctx.So(result, convey.ShouldNotBeNil)
})
})
}

View File

@@ -0,0 +1,118 @@
package gorm
import (
"context"
"strings"
"github.com/jinzhu/gorm"
"go-common/app/admin/main/aegis/model/net"
"go-common/library/ecode"
"go-common/library/log"
)
// TransitionByID .
func (d *Dao) TransitionByID(c context.Context, id int64) (n *net.Transition, err error) {
n = &net.Transition{}
err = d.orm.Where("id=?", id).First(n).Error
if err == gorm.ErrRecordNotFound {
err = ecode.AegisTranNotFound
return
}
if err != nil {
log.Error("TransitionByID(%d) error(%v)", id, err)
}
return
}
// Transitions .
func (d *Dao) Transitions(c context.Context, id []int64) (n []*net.Transition, err error) {
n = []*net.Transition{}
err = d.orm.Where("id in (?)", id).Find(&n).Error
if err != nil {
log.Error("Transitions(%v) error(%v)", id, err)
}
return
}
// TransitionList .
func (d *Dao) TransitionList(c context.Context, pm *net.ListNetElementParam) (result *net.ListTransitionRes, err error) {
result = &net.ListTransitionRes{
Pager: net.Pager{
Num: pm.Pn,
Size: pm.Ps,
},
}
db := d.orm.Table(net.TableTransition).Where("net_id=?", pm.NetID)
if len(pm.ID) > 0 {
db = db.Where("id in (?)", pm.ID)
}
pm.Name = strings.TrimSpace(pm.Name)
if pm.Name != "" {
db = db.Where("name=?", pm.Name)
}
err = db.Scopes(state(pm.State)).Count(&result.Pager.Total).Scopes(pager(pm.Ps, pm.Pn, pm.Sort)).Find(&result.Result).Error
if err != nil {
log.Error("TransitionList find error(%v) params(%+v)", err, pm)
}
return
}
// TransitionByUnique .
func (d *Dao) TransitionByUnique(c context.Context, netID int64, name string) (t *net.Transition, err error) {
t = &net.Transition{}
err = d.orm.Where("net_id=? AND name=?", netID, name).First(t).Error
if err == gorm.ErrRecordNotFound {
err = nil
t = nil
return
}
if err != nil {
log.Error("TransitionByUnique(%d,%s) error(%v)", netID, name, err)
}
return
}
// TransitionIDByNet .
func (d *Dao) TransitionIDByNet(c context.Context, netID []int64, onlyDispatch bool, onlyAvailable bool) (ids map[int64][]int64, err error) {
ids = map[int64][]int64{}
listi := []struct {
ID int64 `gorm:"column:id"`
NetID int64 `gorm:"column:net_id"`
}{}
db := d.orm.Table(net.TableTransition).Where("net_id in (?)", netID)
if onlyAvailable {
db = db.Scopes(Available)
}
if onlyDispatch {
db = db.Where("`limit`>0").Scopes(manual)
}
if err = db.Find(&listi).Error; err != nil {
log.Error("TransitionIDByNet netid(%v) error(%v)", netID, err)
return
}
for _, item := range listi {
ids[item.NetID] = append(ids[item.NetID], item.ID)
}
return
}
func manual(db *gorm.DB) *gorm.DB {
return db.Where("`trigger`=?", net.TriggerManual)
}
// TranByNet .
func (d *Dao) TranByNet(c context.Context, netID int64, onlyAvailable bool) (list []*net.Transition, err error) {
list = []*net.Transition{}
db := d.orm
if netID > 0 {
db = db.Where("net_id=?", netID)
}
if onlyAvailable {
db = db.Scopes(Available)
}
if err = db.Find(&list).Error; err != nil {
log.Error("TranByNet error(%v)", err)
}
return
}

View File

@@ -0,0 +1,83 @@
package gorm
import (
"go-common/app/admin/main/aegis/model/net"
"testing"
"github.com/smartystreets/goconvey/convey"
)
var tt = &net.Transition{
ID: 1,
NetID: 1,
Trigger: net.TriggerManual,
Name: "first",
ChName: "第一次审核",
Description: "新建变迁",
UID: 421,
}
func TestDaoTransitionByID(t *testing.T) {
convey.Convey("TransitionByID", t, func(ctx convey.C) {
n, err := d.TransitionByID(cntx, tt.ID)
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 TestDaoTransitionList(t *testing.T) {
var (
pm = &net.ListNetElementParam{
NetID: 1,
Ps: 20,
ID: []int64{1},
Name: "1",
}
)
convey.Convey("TransitionList", t, func(ctx convey.C) {
result, err := d.TransitionList(cntx, pm)
ctx.Convey("Then err should be nil.result should not be nil.", func(ctx convey.C) {
ctx.So(err, convey.ShouldBeNil)
ctx.So(result, convey.ShouldNotBeNil)
})
})
}
func TestDaoTransitions(t *testing.T) {
convey.Convey("TransitionList", t, func(ctx convey.C) {
_, err := d.Transitions(cntx, []int64{})
ctx.Convey("Then err should be nil.", func(ctx convey.C) {
ctx.So(err, convey.ShouldBeNil)
})
})
}
func TestDaoTransitionByUnique(t *testing.T) {
convey.Convey("TransitionByUnique", t, func(ctx convey.C) {
_, err := d.TransitionByUnique(cntx, 0, "")
ctx.Convey("Then err should be nil.", func(ctx convey.C) {
ctx.So(err, convey.ShouldBeNil)
})
})
}
func TestDaoTransitionIDByNet(t *testing.T) {
convey.Convey("TransitionIDByNet", t, func(ctx convey.C) {
a, err := d.TransitionIDByNet(cntx, []int64{1}, true, true)
t.Logf("a(%+v)", a)
ctx.Convey("Then err should be nil.", func(ctx convey.C) {
ctx.So(err, convey.ShouldBeNil)
})
})
}
func TestDaoTranByNet(t *testing.T) {
convey.Convey("TranByNet", t, func(ctx convey.C) {
_, err := d.TranByNet(cntx, 0, true)
ctx.Convey("Then err should be nil.", func(ctx convey.C) {
ctx.So(err, convey.ShouldBeNil)
})
})
}

View File

@@ -0,0 +1,69 @@
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",
"filter_test.go",
"log_test.go",
"resource_test.go",
"role_test.go",
"search_test.go",
"upload_test.go",
],
embed = [":go_default_library"],
rundir = ".",
tags = ["automanaged"],
deps = [
"//app/admin/main/aegis/conf:go_default_library",
"//app/admin/main/aegis/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",
"filter.go",
"log.go",
"resource.go",
"role.go",
"search.go",
"upload.go",
],
importpath = "go-common/app/admin/main/aegis/dao/http",
tags = ["automanaged"],
visibility = ["//visibility:public"],
deps = [
"//app/admin/main/aegis/conf:go_default_library",
"//app/admin/main/aegis/model:go_default_library",
"//app/admin/main/aegis/model/task:go_default_library",
"//library/database/elastic: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",
],
)
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,41 @@
package http
import (
"context"
"go-common/app/admin/main/aegis/conf"
"go-common/library/database/elastic"
bm "go-common/library/net/http/blademaster"
)
// Dao dao
type Dao struct {
c *conf.Config
clientR, clientW *bm.Client
es *elastic.Elastic
}
// New init mysql db
func New(c *conf.Config) (dao *Dao) {
dao = &Dao{
c: c,
clientR: bm.NewClient(c.HTTPClient.Read),
clientW: bm.NewClient(c.HTTPClient.Write),
es: elastic.NewElastic(&elastic.Config{
Host: c.Host.Manager,
HTTPClient: c.HTTPClient.Es,
}),
}
return
}
// Close close the resource.
func (d *Dao) Close() {
}
// Ping dao ping
func (d *Dao) Ping(c context.Context) error {
return nil
}

View File

@@ -0,0 +1,62 @@
package http
import (
"context"
"flag"
"os"
"strings"
"testing"
"go-common/app/admin/main/aegis/conf"
"github.com/smartystreets/goconvey/convey"
"gopkg.in/h2non/gock.v1"
)
var (
d *Dao
cntx context.Context
)
func TestMain(m *testing.M) {
if os.Getenv("DEPLOY_ENV") != "" {
flag.Set("app_id", "main.archive.aegis-admin")
flag.Set("conf_token", "cad913269be022e1eb8c45a8d5408d78")
flag.Set("tree_id", "60977")
flag.Set("conf_version", "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/aegis-admin.toml")
}
flag.Parse()
if err := conf.Init(); err != nil {
panic(err)
}
d = New(conf.Conf)
cntx = context.Background()
os.Exit(m.Run())
}
func httpMock(method, url string) *gock.Request {
r := gock.New(url)
d.clientR.SetTransport(gock.DefaultTransport)
d.clientW.SetTransport(gock.DefaultTransport)
r.Method = strings.ToUpper(method)
return r
}
func TestHttpPing(t *testing.T) {
convey.Convey("Ping", t, func(ctx convey.C) {
ctx.Convey("Ping", func(ctx convey.C) {
err := d.Ping(cntx)
ctx.Convey("Then err should not be nil", func(ctx convey.C) {
ctx.So(err, convey.ShouldBeNil)
})
})
})
}

View File

@@ -0,0 +1,49 @@
package http
import (
"context"
"net/url"
"go-common/library/ecode"
"go-common/library/log"
)
const (
_filterURI = "/x/internal/filter/v3/hit"
)
// Res 筛选结果
type Res struct {
Code int64 `json:"code"`
Data []struct {
Level int64 `json:"level"`
Msg string `json:"msg"`
} `json:"data"`
}
// FilterMulti .批量过滤
func (d *Dao) FilterMulti(c context.Context, area string, msg string) (hits []string, err error) {
params := url.Values{}
params.Set("area", area)
params.Set("msg", msg)
params.Set("level", "10")
res := new(Res)
log.Info("FilterMulti area(%s) msg(%s)", area, msg)
if err = d.clientR.Post(c, d.c.Host.API+_filterURI, "", params, res); err != nil {
log.Error("d.clientR.Get error(%v)", err)
return
}
if res.Code != 0 {
err = ecode.Code(res.Code)
log.Error("FilterMulti res(%+v) error(%+v)", res, err)
return
}
for _, dt := range res.Data {
hits = append(hits, dt.Msg)
}
log.Info("FilterMulti area(%s) msg(%s) hits(%v)", area, msg, hits)
return
}

View File

@@ -0,0 +1,43 @@
package http
import (
"context"
"reflect"
"testing"
"github.com/smartystreets/goconvey/convey"
)
func TestHttpFilterMulti(t *testing.T) {
convey.Convey("FilterMulti", t, func(ctx convey.C) {
var (
c = context.Background()
area = ""
msg = ""
successRes = `{"code":0,"data":[{"level":10,"msg":"女装大佬"}]}`
failRes = `{"code":200,"data":[{"level":10,"msg":"女装大佬"}]}`
)
ctx.Convey("success", func(ctx convey.C) {
httpMock("POST", d.c.Host.API+_filterURI).Reply(200).JSON(successRes)
hits, err := d.FilterMulti(c, area, msg)
ctx.Convey("Then err should be nil.hits should not be nil.", func(ctx convey.C) {
ctx.So(err, convey.ShouldBeNil)
ctx.So(reflect.DeepEqual(hits, []string{"女装大佬"}), convey.ShouldEqual, true)
})
})
ctx.Convey("request fail", func(ctx convey.C) {
httpMock("POST", d.c.Host.API+_filterURI).Reply(504)
_, err := d.FilterMulti(c, area, msg)
ctx.Convey("Then err should be nil.hits should not be nil.", func(ctx convey.C) {
ctx.So(err, convey.ShouldNotBeNil)
})
})
ctx.Convey("business fail", func(ctx convey.C) {
httpMock("POST", d.c.Host.API+_filterURI).Reply(200).JSON(failRes)
_, err := d.FilterMulti(c, area, msg)
ctx.Convey("Then err should be nil.hits should not be nil.", func(ctx convey.C) {
ctx.So(err, convey.ShouldNotBeNil)
})
})
})
}

View File

@@ -0,0 +1,182 @@
package http
import (
"context"
"fmt"
"reflect"
"strconv"
"strings"
"time"
"go-common/app/admin/main/aegis/model"
"go-common/library/database/elastic"
"go-common/library/log"
"go-common/library/xstr"
)
//const
const (
LogMinYear = 2018
LogMinTime = "2018-11-01 10:00:00"
)
func setESParams(r *elastic.Request, args interface{}, cm model.EsCommon) {
av := reflect.ValueOf(args)
if av.Kind() == reflect.Ptr {
av = av.Elem()
}
if av.Kind() != reflect.Struct {
return
}
atp := av.Type()
ranges := map[string]map[string]interface{}{}
for i := atp.NumField() - 1; i >= 0; i-- {
fdt := atp.Field(i)
tag := fdt.Tag.Get("reflect")
if tag == "ignore" || tag == "" {
continue
}
fdv := av.Field(i)
fdk := fdt.Type.Kind()
if (fdk == reflect.Slice || fdk == reflect.String) && fdv.Len() == 0 {
continue
}
//default处理
omitdefault := strings.Index(tag, ",omitdefault")
tag = strings.Replace(tag, ",omitdefault", "", -1)
fdvv := fdv.Interface()
fdvslice := false
if omitdefault > -1 && fmt.Sprintf("%v", fdvv) == fdt.Tag.Get("default") {
continue
}
//字段值处理parse额外处理
switch fdk {
case reflect.Int64, reflect.Int32, reflect.Int, reflect.Int16, reflect.Int8:
fdvv = fdv.Int()
case reflect.String:
if fdv.Len() == 0 {
continue
}
v := fdv.String()
parse := fdt.Tag.Get("parse")
if parse == "int" {
vi, err := strconv.ParseInt(v, 10, 64)
if err != nil {
log.Error("setESParams strconv.ParseInt(%s) error(%v)", v, err)
continue
}
fdvv = vi
} else if parse == "[]int" {
vi, err := xstr.SplitInts(v)
if err != nil {
log.Error("setESParams xstr.SplitInts(%s) error(%v)", v, err)
continue
}
fdvv = vi
fdvslice = true
} else {
fdvv = v
}
case reflect.Slice:
if fdv.Len() == 0 {
continue
}
fdvslice = true
default:
log.Warn("setESParams not support kind(%s) for tag(%s)", fdk.String(), tag)
continue
}
//范围处理
from := strings.Index(tag, ",from")
to := strings.Index(tag, ",to")
if from > -1 {
if _, exist := ranges[tag[:from]]; !exist {
ranges[tag[:from]] = map[string]interface{}{}
}
ranges[tag[:from]]["from"] = fdvv
continue
}
if to > -1 {
if _, exist := ranges[tag[:to]]; !exist {
ranges[tag[:to]] = map[string]interface{}{}
}
ranges[tag[:to]]["to"] = fdvv
continue
}
if fdvslice {
r.WhereIn(tag, fdvv)
} else {
r.WhereEq(tag, fdvv)
}
}
for field, items := range ranges {
r.WhereRange(field, items["from"], items["to"], elastic.RangeScopeLcRc)
}
r.Ps(cm.Ps).Pn(cm.Pn)
order := []map[string]string{}
if cm.Order != "" || cm.Sort != "" {
r.Order(cm.Order, cm.Sort)
order = append(order, map[string]string{cm.Order: cm.Sort})
}
if cm.Group != "" {
r.GroupBy(elastic.EnhancedModeDistinct, cm.Group, order)
}
}
//QueryLogSearch .
func (d *Dao) QueryLogSearch(c context.Context, args *model.ParamsQueryLog, cm model.EsCommon) (resp *model.SearchLogResult, err error) {
var (
min int = LogMinYear
max int
ctimefrom, ctimeto time.Time
)
//默认获取所有行为日志,确定了时间范围的,只查询该段范围内的日志
if args.CtimeFrom != "" {
ctimefrom, _ = time.ParseInLocation("2006-01-02 15:04:05", args.CtimeFrom, time.Local)
if ctimefrom.Year() > min {
min = ctimefrom.Year()
}
}
if args.CtimeTo != "" {
ctimeto, _ = time.ParseInLocation("2006-01-02 15:04:05", args.CtimeTo, time.Local)
if ctimeto.Year() >= min {
max = ctimeto.Year()
}
} else {
max = time.Now().Year()
}
tmpl := ",log_audit_%d_%d"
index := ""
for i := min; i <= max; i++ {
index += fmt.Sprintf(tmpl, args.Business, i)
}
index = strings.TrimLeft(index, ",")
r := d.es.NewRequest("log_audit").Index(index).Fields(
"uid",
"uname",
"oid",
"type",
"action",
"str_0",
"str_1",
"str_2",
"int_0",
"int_1",
"int_2",
"ctime",
"extra_data")
setESParams(r, args, cm)
err = r.Scan(c, &resp)
return
}

View File

@@ -0,0 +1,33 @@
package http
import (
"context"
"testing"
"go-common/app/admin/main/aegis/model"
"github.com/smartystreets/goconvey/convey"
)
func TestHttpQueryLogSearch(t *testing.T) {
convey.Convey("QueryLogSearch", t, func(ctx convey.C) {
var (
c = context.Background()
args = &model.ParamsQueryLog{
Business: 231,
Int0From: "0",
Int1: []int64{0, 1},
Int2: []int64{0},
Str0: []string{"0"},
CtimeFrom: "2019-01-01 00:00:00",
}
escm = model.EsCommon{Ps: 10, Pn: 1, Order: "ctime", Sort: "desc"}
)
ctx.Convey("success", func(ctx convey.C) {
res, err := d.QueryLogSearch(c, args, escm)
ctx.So(err, convey.ShouldBeNil)
ctx.So(res, convey.ShouldNotBeNil)
})
})
}

View File

@@ -0,0 +1,39 @@
package http
import (
"context"
"fmt"
"net/url"
"go-common/app/admin/main/aegis/model"
"go-common/library/ecode"
"go-common/library/log"
)
// SyncResource 同步到业务方
func (d *Dao) SyncResource(c context.Context, act *model.Action, ropt map[string]interface{}) (code int, err error) {
params := url.Values{}
for k, v := range ropt {
params.Set(k, fmt.Sprint(v))
}
requestParams := fmt.Sprintf("%s?%s", act.URL, params.Encode())
log.Info("SyncResource url(%v) params(%s)", act.URL, params.Encode())
if d.c.Debug == "local" || d.c.Debug == "nobusiness" {
return
}
res := new(struct {
Code int `json:"code"`
Msg string `json:"msg"`
Message string `json:"message"`
})
err = d.clientW.Post(c, act.URL, "", params, res)
code = res.Code
if err != nil || res.Code != 0 {
log.Error("clientW.Post err(%v) response(%+v) request(%s)", err, res, requestParams)
err = ecode.Errorf(ecode.AegisBusinessSyncErr, "业务回调错误 request(%s) httperror(%v) response(%+v)", requestParams, err, res)
}
return
}

View File

@@ -0,0 +1,19 @@
package http
import (
"context"
"testing"
"go-common/app/admin/main/aegis/model"
"github.com/smartystreets/goconvey/convey"
)
func TestSyncResource(t *testing.T) {
var (
c = context.TODO()
)
convey.Convey("SyncResource", t, func(ctx convey.C) {
d.SyncResource(c, &model.Action{}, map[string]interface{}{"state": 1})
})
}

View File

@@ -0,0 +1,159 @@
package http
import (
"context"
"net/url"
"strconv"
"go-common/app/admin/main/aegis/model/task"
"go-common/library/log"
"go-common/library/xstr"
)
const (
_getUIDs = "/x/admin/manager/users/uids"
_getUname = "/x/admin/manager/users/unames"
_getUdepartment = "/x/admin/manager/users/udepts"
_getRole = "/x/admin/manager/internal/user/role"
_getRoles = "/x/admin/manager/internal/user/roles"
)
// GetRole 获取用户对应业务下的角色
func (d *Dao) GetRole(c context.Context, bid, uid int64) (roles []*task.Role, err error) {
roles = []*task.Role{}
params := url.Values{}
params.Set("bid", strconv.FormatInt(bid, 10))
params.Set("uid", strconv.FormatInt(uid, 10))
res := new(struct {
Code int `json:"code"`
Data []*task.Role `json:"data"`
})
if err = d.clientR.Get(c, d.c.Host.Manager+_getRole, "", params, res); err != nil {
log.Error("GetRole error(%v) url(%s) params(%s)", err, d.c.Host.Manager+_getRole, params.Encode())
return
}
if res.Code != 0 {
log.Error("GetRole request failed res(%+v) url(%s) params(%s)", res, d.c.Host.Manager+_getRole, params.Encode())
return
}
if len(res.Data) == 0 {
return
}
roles = res.Data
return
}
// GetUserRoles 获取用户在所有业务下的角色
func (d *Dao) GetUserRoles(c context.Context, uid int64) (roles []*task.Role, err error) {
roles = []*task.Role{}
params := url.Values{}
params.Set("uid", strconv.FormatInt(uid, 10))
res := new(struct {
Code int `json:"code"`
Data []*task.Role `json:"data"`
})
if err = d.clientR.Get(c, d.c.Host.Manager+_getRoles, "", params, res); err != nil {
log.Error("GetUserRoles error(%v) url(%s) params(%s)", err, d.c.Host.Manager+_getRole, params.Encode())
return
}
if res.Code != 0 {
log.Error("GetUserRoles request failed res(%+v) url(%s) params(%s)", res, d.c.Host.Manager+_getRole, params.Encode())
return
}
if len(res.Data) == 0 {
return
}
roles = res.Data
return
}
// GetUnames .
func (d *Dao) GetUnames(c context.Context, uids []int64) (unames map[int64]string, err error) {
unames = map[int64]string{}
if len(uids) == 0 {
return
}
params := url.Values{}
params.Set("uids", xstr.JoinInts(uids))
res := new(struct {
Code int `json:"code"`
Data map[int64]string `json:"data"`
})
if err = d.clientR.Get(c, d.c.Host.Manager+_getUname, "", params, res); err != nil {
log.Error("GetUnames error(%v) url(%s) params(%s)", err, d.c.Host.Manager+_getUname, params.Encode())
return
}
if res.Code != 0 {
log.Error("GetUnames request failed res(%+v) url(%s) params(%s)", res, d.c.Host.Manager+_getUname, params.Encode())
return
}
if len(res.Data) == 0 {
return
}
unames = res.Data
return
}
// GetUIDs .
func (d *Dao) GetUIDs(c context.Context, unames string) (uids map[string]int64, err error) {
uids = map[string]int64{}
params := url.Values{}
params.Set("unames", unames)
res := new(struct {
Code int `json:"code"`
Data map[string]int64 `json:"data"`
})
if err = d.clientR.Get(c, d.c.Host.Manager+_getUIDs, "", params, res); err != nil {
log.Error("GetUIDs error(%v) url(%s) params(%s)", err, d.c.Host.Manager+_getUname, params.Encode())
return
}
if res.Code != 0 {
log.Error("GetUIDs request failed res(%+v) url(%s) params(%s)", res, d.c.Host.Manager+_getUname, params.Encode())
return
}
if len(res.Data) == 0 {
return
}
uids = res.Data
return
}
// GetUdepartment .
func (d *Dao) GetUdepartment(c context.Context, uids []int64) (udepartment map[int64]string, err error) {
udepartment = map[int64]string{}
if len(uids) == 0 {
return
}
params := url.Values{}
params.Set("uids", xstr.JoinInts(uids))
res := new(struct {
Code int `json:"code"`
Data map[int64]string `json:"data"`
})
if err = d.clientR.Get(c, d.c.Host.Manager+_getUdepartment, "", params, res); err != nil {
log.Error("GetUdepartment error(%v) url(%s) params(%s)", err, d.c.Host.Manager+_getUdepartment, params.Encode())
return
}
if res.Code != 0 {
log.Error("GetUdepartment request failed res(%+v) url(%s) params(%s)", res, d.c.Host.Manager+_getUname, params.Encode())
return
}
if len(res.Data) == 0 {
return
}
udepartment = res.Data
return
}

View File

@@ -0,0 +1,75 @@
package http
import (
"context"
"testing"
"github.com/smartystreets/goconvey/convey"
)
func TestHttpGetRole(t *testing.T) {
var (
c = context.TODO()
bid = int64(0)
uid = int64(0)
)
convey.Convey("GetRole", t, func(ctx convey.C) {
httpMock("GET", d.c.Host.Manager+_getRole).Reply(200).JSON(`{"code":0,"data":[{"id":0}]}`)
roles, err := d.GetRole(c, bid, uid)
ctx.Convey("Then err should be nil.roles should not be nil.", func(ctx convey.C) {
ctx.So(err, convey.ShouldBeNil)
ctx.So(roles, convey.ShouldNotBeNil)
})
})
}
func TestHttpGetUserRoles(t *testing.T) {
var (
c = context.TODO()
)
convey.Convey("GetUserRoles", t, func(ctx convey.C) {
httpMock("GET", d.c.Host.Manager+_getRoles).Reply(200).JSON(`{"code":0,"data":[{"id":0}]}`)
roles, err := d.GetUserRoles(c, 421)
ctx.Convey("Then err should be nil.roles should not be nil.", func(ctx convey.C) {
ctx.So(err, convey.ShouldBeNil)
ctx.So(roles, convey.ShouldNotBeNil)
})
})
}
func TestHttpGetUnames(t *testing.T) {
var (
c = context.TODO()
uids = []int64{421}
)
convey.Convey("GetUnames", t, func(ctx convey.C) {
httpMock("GET", d.c.Host.Manager+_getUname).Reply(200).JSON(`{"code":0,"data":{"421":"丝瓜"}}`)
unames, err := d.GetUnames(c, uids)
ctx.Convey("Then err should be nil.unames should not be nil.", func(ctx convey.C) {
ctx.So(err, convey.ShouldBeNil)
ctx.So(unames, convey.ShouldNotBeNil)
})
})
}
func TestHttpGetUIDs(t *testing.T) {
convey.Convey("GetUIDs", t, func(ctx convey.C) {
httpMock("GET", d.c.Host.Manager+_getUIDs).Reply(200).JSON(`{"code":0,"data":{"cxf":481}}`)
uids, err := d.GetUIDs(cntx, "cxf")
ctx.Convey("Then err should be nil.unames should not be nil.", func(ctx convey.C) {
ctx.So(err, convey.ShouldBeNil)
ctx.So(uids, convey.ShouldNotBeNil)
})
})
}
func TestHttpGetUdepartment(t *testing.T) {
convey.Convey("GetUdepartment", t, func(ctx convey.C) {
httpMock("GET", d.c.Host.Manager+_getUdepartment).Reply(200).JSON(`{"code":0,"data":{"481":"CTO"}}`)
depart, err := d.GetUdepartment(cntx, []int64{481})
ctx.Convey("Then err should be nil.unames should not be nil.", func(ctx convey.C) {
ctx.So(err, convey.ShouldBeNil)
ctx.So(depart, convey.ShouldNotBeNil)
})
})
}

View File

@@ -0,0 +1,120 @@
package http
import (
"context"
"encoding/json"
"net/url"
"strings"
"go-common/app/admin/main/aegis/model"
"go-common/library/database/elastic"
"go-common/library/ecode"
"go-common/library/log"
)
const (
_upsertES = "/x/admin/search/upsert"
)
// ResourceES search archives by es.
func (d *Dao) ResourceES(c context.Context, arg *model.SearchParams) (sres *model.SearchRes, err error) {
r := d.es.NewRequest("aegis_resource").Index("aegis_resource").Fields(
"id",
"business_id",
"flow_id",
"oid",
"mid",
"content",
"extra1",
"extra2",
"extra3",
"extra4",
"extra5",
"extra6",
"extra1s",
"extra2s",
"extra3s",
"extra4s",
"extratime1",
"octime",
"ptime",
"metadata",
"note",
"reject_reason",
"reason_id",
"state",
"ctime",
).OrderScoreFirst(false)
escm := model.EsCommon{
Ps: arg.Ps,
Pn: arg.Pn,
Order: "ctime",
Sort: strings.ToLower(arg.CtimeOrder),
}
if escm.Sort != "asc" && escm.Sort != "desc" {
escm.Sort = "desc"
}
setESParams(r, arg, escm)
if arg.KeyWord != "" { //描述
arg.KeyWord = strings.Replace(arg.KeyWord, "", ",", -1)
r.WhereLike([]string{"content"}, strings.Split(arg.KeyWord, ","), true, elastic.LikeLevelHigh)
}
log.Info("ResourceES params(%s)", r.Params())
sres = &model.SearchRes{}
if err = r.Scan(c, sres); err != nil {
log.Error("ResourceES r.Scan params(%s)|error(%v)", r.Params(), err)
return
}
arg.Pn = sres.Page.Num
arg.Ps = sres.Page.Size
arg.Total = sres.Page.Total
return
}
//UpsertES 更新搜索
func (d *Dao) UpsertES(c context.Context, rsc []*model.UpsertItem) (err error) {
if len(rsc) == 0 {
return
}
items := []*model.UpsertItem{}
for _, item := range rsc {
if item == nil || item.ID <= 0 {
continue
}
items = append(items, item)
}
data := map[string][]*model.UpsertItem{
"aegis_resource": items,
}
datab, err := json.Marshal(data)
if err != nil {
log.Error("UpsertES json.Marshal error(%v) resource(%+v)", err, rsc)
return err
}
res := new(struct {
Code int `json:"code"`
Message string `json:"message"`
})
params := url.Values{}
params.Set("business", "aegis_resource")
params.Set("insert", "false")
params.Set("data", string(datab))
if err = d.clientW.Post(c, d.c.Host.Manager+_upsertES, "", params, res); err != nil {
log.Error("UpsertES d.clientW.Post error(%v) params(%+v)", err, params)
return
}
if res.Code != ecode.OK.Code() {
log.Error("UpsertES d.clientW.Post failed, response(%+v) params(%+v)", res, params)
return
}
log.Info("response(%+v) url=%s%s?%s", res, d.c.Host.Manager, _upsertES, params.Encode())
return
}

View File

@@ -0,0 +1,58 @@
package http
import (
"context"
"testing"
"github.com/smartystreets/goconvey/convey"
"go-common/app/admin/main/aegis/model"
)
var arg = &model.SearchParams{
BusinessID: 1,
//CtimeFrom: "2018-01-01 01:01:01",
//CtimeTo: "2019-11-11 11:11:11",
OID: []string{"206137981869783258", "206137981871880409", "206129056929839317", "206117679558326449"},
KeyWord: "分享图片",
FlowID: -12345,
Extra1: "1,2,3,4,5",
Mid: -12345,
State: 0,
}
func TestHttpResourceES(t *testing.T) {
convey.Convey("ResourceES", t, func(ctx convey.C) {
var (
c = context.Background()
)
ctx.Convey("When everything goes positive", func(ctx convey.C) {
res, err := d.ResourceES(c, arg)
t.Logf("res(%+v)", res)
ctx.Convey("Then err should be nil.sres should not be nil.", func(ctx convey.C) {
ctx.So(err, convey.ShouldBeNil)
})
})
})
}
func TestUpsertES(t *testing.T) {
convey.Convey("UpsertES", t, func(ctx convey.C) {
rsc := []*model.UpsertItem{
{
ID: 47,
State: -3,
},
nil,
{
State: 0,
},
}
ctx.Convey("When everything goes positive", func(ctx convey.C) {
httpMock("POST", d.c.Host.Manager+_upsertES).Reply(200).JSON(`{"code":0,"message":"msg"}`)
err := d.UpsertES(context.Background(), rsc)
ctx.Convey("No return values", func(ctx convey.C) {
ctx.So(err, convey.ShouldBeNil)
})
})
})
}

View File

@@ -0,0 +1,86 @@
package http
import (
"bytes"
"context"
"crypto/hmac"
"crypto/sha1"
"encoding/base64"
"fmt"
"hash"
"net/http"
"strconv"
"time"
"go-common/library/ecode"
"go-common/library/log"
)
// bfs info
const (
_uploadURL = "/bfs/%s/%s"
_template = "%s\n%s\n%s\n%d\n"
_method = "PUT"
_bucket = "creative"
)
// Upload upload picture or log file to bfs
func (d *Dao) Upload(c context.Context, fileName string, fileType string, timing int64, data []byte) (location string, err error) {
var (
req *http.Request
resp *http.Response
code int
client = &http.Client{Timeout: time.Duration(d.c.Bfs.Timeout) * time.Millisecond}
url = fmt.Sprintf(d.c.Bfs.Host+_uploadURL, _bucket, fileName)
)
// prepare the data of the file and init the request
buf := new(bytes.Buffer)
_, err = buf.Write(data)
if err != nil {
log.Error("Upload.buf.Write.error(%v)", err)
err = ecode.RequestErr
return
}
if req, err = http.NewRequest(_method, url, buf); err != nil {
log.Error("http.NewRequest() Upload(%v) error(%v)", url, err)
return
}
// request setting
authorization := authorize(d.c.Bfs.Key, d.c.Bfs.Secret, _method, _bucket, fileName, timing)
req.Header.Set("Date", fmt.Sprint(timing))
req.Header.Set("Authorization", authorization)
req.Header.Set("Content-Type", fileType)
resp, err = client.Do(req)
// response treatment
if err != nil {
log.Error("Bfs client.Do(%s) error(%v)", url, err)
return
}
defer resp.Body.Close()
if resp.StatusCode != http.StatusOK {
err = fmt.Errorf("Bfs status code error:%v", resp.StatusCode)
return
}
code, err = strconv.Atoi(resp.Header.Get("code"))
if err != nil || code != 200 {
err = fmt.Errorf("Bfs response code error:%v", code)
return
}
location = resp.Header.Get("Location")
return
}
// authorize returns authorization for upload file to bfs
func authorize(key, secret, method, bucket, file string, expire int64) (authorization string) {
var (
content string
mac hash.Hash
signature string
)
content = fmt.Sprintf(_template, method, bucket, file, expire)
mac = hmac.New(sha1.New, []byte(secret))
mac.Write([]byte(content))
signature = base64.StdEncoding.EncodeToString(mac.Sum(nil))
authorization = fmt.Sprintf("%s:%s:%d", key, signature, expire)
return
}

View File

@@ -0,0 +1,41 @@
package http
import (
"context"
"testing"
"github.com/smartystreets/goconvey/convey"
)
func TestHttpauthorize(t *testing.T) {
convey.Convey("authorize", t, func(ctx convey.C) {
var (
key = ""
secret = ""
method = ""
bucket = ""
file = ""
expire = int64(0)
)
ctx.Convey("When everything goes positive", func(ctx convey.C) {
authorization := authorize(key, secret, method, bucket, file, expire)
ctx.Convey("Then authorization should not be nil.", func(ctx convey.C) {
ctx.So(authorization, convey.ShouldNotBeNil)
})
})
})
}
func TestHttpUpload(t *testing.T) {
convey.Convey("Upload", t, func(ctx convey.C) {
var (
c = context.TODO()
)
ctx.Convey("When everything gose positive", func(ctx convey.C) {
_, err := d.Upload(c, "", "", 0, []byte{})
ctx.Convey("Then authorization should not be nil.", func(ctx convey.C) {
ctx.So(err, convey.ShouldNotBeNil)
})
})
})
}

View File

@@ -0,0 +1,54 @@
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",
"task_test.go",
],
embed = [":go_default_library"],
rundir = ".",
tags = ["automanaged"],
deps = [
"//app/admin/main/aegis/conf:go_default_library",
"//app/admin/main/aegis/model/common:go_default_library",
"//vendor/github.com/smartystreets/goconvey/convey:go_default_library",
],
)
go_library(
name = "go_default_library",
srcs = [
"dao.go",
"task.go",
],
importpath = "go-common/app/admin/main/aegis/dao/mc",
tags = ["automanaged"],
visibility = ["//visibility:public"],
deps = [
"//app/admin/main/aegis/conf:go_default_library",
"//app/admin/main/aegis/model/common:go_default_library",
"//library/cache/memcache: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,36 @@
package mc
import (
"context"
"go-common/app/admin/main/aegis/conf"
"go-common/library/cache/memcache"
)
// Dao dao
type Dao struct {
c *conf.Config
mc *memcache.Pool
}
// New init mysql db
func New(c *conf.Config) (dao *Dao) {
dao = &Dao{
c: c,
mc: memcache.NewPool(c.Memcache),
}
return
}
// Close close the resource.
func (d *Dao) Close() {
d.mc.Close()
}
// Ping dao ping
func (d *Dao) Ping(c context.Context) error {
return nil
}

View File

@@ -0,0 +1,39 @@
package mc
import (
"context"
"flag"
"fmt"
"os"
"testing"
"go-common/app/admin/main/aegis/conf"
)
var (
d *Dao
ctx context.Context
)
func TestMain(m *testing.M) {
if os.Getenv("DEPLOY_ENV") != "" {
flag.Set("app_id", "main.archive.aegis-admin")
flag.Set("conf_token", "cad913269be022e1eb8c45a8d5408d78")
flag.Set("tree_id", "60977")
flag.Set("conf_version", "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/aegis-admin.toml")
}
flag.Parse()
if err := conf.Init(); err != nil {
panic(fmt.Sprintf("conf.Init() error(%v)", err))
}
d = New(conf.Conf)
ctx = context.TODO()
os.Exit(m.Run())
}

View File

@@ -0,0 +1,135 @@
package mc
import (
"context"
"encoding/json"
"fmt"
"go-common/app/admin/main/aegis/model/common"
gmc "go-common/library/cache/memcache"
"go-common/library/log"
)
// ConsumerOn 登入
func (d *Dao) ConsumerOn(c context.Context, opt *common.BaseOptions) (err error) {
conn := d.mc.Get(c)
defer conn.Close()
key := mcKey(opt)
if err = conn.Set(&gmc.Item{Key: key, Value: []byte{1}, Expiration: d.c.Consumer.OnExp}); err != nil {
log.Error("conn.Set error(%v)", err)
}
return
}
// ConsumerOff .
func (d *Dao) ConsumerOff(c context.Context, opt *common.BaseOptions) (err error) {
conn := d.mc.Get(c)
defer conn.Close()
key := mcKey(opt)
if err = conn.Delete(key); err != nil {
if err != gmc.ErrNotFound {
log.Error("conn.Delete error(%v)", err)
}
err = nil
}
return
}
// IsConsumerOn .
func (d *Dao) IsConsumerOn(c context.Context, opt *common.BaseOptions) (isOn bool, err error) {
conn := d.mc.Get(c)
defer conn.Close()
key := mcKey(opt)
if _, err = conn.Get(key); err != nil {
if err == gmc.ErrNotFound {
err = nil
} else {
log.Error("IsConsumerOn error(%v)", err)
}
return
}
isOn = true
if err = conn.Set(&gmc.Item{Key: key, Value: []byte{1}, Expiration: d.c.Consumer.OnExp}); err != nil {
log.Error("conn.Set error(%v)", err)
}
return
}
func mcKey(opt *common.BaseOptions) string {
return fmt.Sprintf("aegis%d_%d_%d", opt.BusinessID, opt.FlowID, opt.UID)
}
func roleKey(opt *common.BaseOptions) string {
return fmt.Sprintf("aegis_role%d_%d_%d", opt.BusinessID, opt.FlowID, opt.UID)
}
// Role .
type Role struct {
Role int8 `json:"role"`
Uname string `json:"uname"`
}
// GetRole TODO 目前缓存组长组员,以后扩展到存管理员
func (d *Dao) GetRole(c context.Context, opt *common.BaseOptions) (role int8, uname string, err error) {
conn := d.mc.Get(c)
defer conn.Close()
key := roleKey(opt)
var item *gmc.Item
if item, err = conn.Get(key); err != nil {
if err == gmc.ErrNotFound {
log.Info("GetRole opt(%+v) miss", opt)
err = nil
} else {
log.Error("GetRole opt(%+v) error(%v)", opt, err)
}
return
}
rt := new(Role)
if err = json.Unmarshal(item.Value, rt); err != nil {
log.Error("GetRole value(%s) error(%v)", string(item.Value), err)
return
}
role = rt.Role
uname = rt.Uname
return
}
// SetRole .
func (d *Dao) SetRole(c context.Context, opt *common.BaseOptions, role int8) (err error) {
conn := d.mc.Get(c)
defer conn.Close()
key := roleKey(opt)
val := &Role{
Role: role,
Uname: opt.Uname,
}
var roleb []byte
if roleb, err = json.Marshal(val); err != nil {
log.Error("SetRole error(%v)", err)
return
}
if err = conn.Set(&gmc.Item{Key: key, Value: roleb, Expiration: d.c.Consumer.RoleExp}); err != nil {
log.Error("conn.Set error(%v)", err)
}
return
}
//DelRole .
func (d *Dao) DelRole(c context.Context, bizid, flowid int64, uids []int64) (err error) {
conn := d.mc.Get(c)
defer conn.Close()
for _, uid := range uids {
key := roleKey(&common.BaseOptions{
BusinessID: bizid,
FlowID: flowid,
UID: uid})
conn.Delete(key)
}
return
}

View File

@@ -0,0 +1,110 @@
package mc
import (
"context"
"testing"
"go-common/app/admin/main/aegis/model/common"
"github.com/smartystreets/goconvey/convey"
)
func TestMcConsumerOn(t *testing.T) {
convey.Convey("ConsumerOn", t, func(ctx convey.C) {
var (
opt = &common.BaseOptions{}
)
ctx.Convey("When everything goes positive", func(ctx convey.C) {
err := d.ConsumerOn(context.TODO(), opt)
ctx.Convey("Then err should be nil.", func(ctx convey.C) {
ctx.So(err, convey.ShouldBeNil)
})
})
})
}
func TestMcConsumerOff(t *testing.T) {
convey.Convey("ConsumerOff", t, func(ctx convey.C) {
var (
opt = &common.BaseOptions{}
)
ctx.Convey("When everything goes positive", func(ctx convey.C) {
err := d.ConsumerOff(context.TODO(), opt)
ctx.Convey("Then err should be nil.", func(ctx convey.C) {
ctx.So(err, convey.ShouldBeNil)
})
})
})
}
func TestMcIsConsumerOn(t *testing.T) {
convey.Convey("IsConsumerOn", t, func(ctx convey.C) {
var (
opt = &common.BaseOptions{}
)
ctx.Convey("When everything goes positive", func(ctx convey.C) {
_, err := d.IsConsumerOn(context.TODO(), opt)
ctx.Convey("Then err should be nil.", func(ctx convey.C) {
ctx.So(err, convey.ShouldBeNil)
})
})
})
}
func TestMcmcKey(t *testing.T) {
convey.Convey("mcKey", t, func(ctx convey.C) {
var (
opt = &common.BaseOptions{}
)
ctx.Convey("When everything goes positive", func(ctx convey.C) {
p1 := mcKey(opt)
ctx.Convey("Then p1 should not be nil.", func(ctx convey.C) {
ctx.So(p1, convey.ShouldNotBeNil)
})
})
})
}
func TestMcroleKey(t *testing.T) {
convey.Convey("roleKey", t, func(ctx convey.C) {
var (
opt = &common.BaseOptions{}
)
ctx.Convey("When everything goes positive", func(ctx convey.C) {
p1 := roleKey(opt)
ctx.Convey("Then p1 should not be nil.", func(ctx convey.C) {
ctx.So(p1, convey.ShouldNotBeNil)
})
})
})
}
func TestMcSetRole(t *testing.T) {
convey.Convey("SetRole", t, func(ctx convey.C) {
var (
c = context.TODO()
opt = &common.BaseOptions{}
)
ctx.Convey("When everything gose positive", func(ctx convey.C) {
err := d.SetRole(c, opt, 0)
ctx.Convey("Then p1 should not be nil.", func(ctx convey.C) {
ctx.So(err, convey.ShouldBeNil)
})
})
})
}
func TestMcGetRole(t *testing.T) {
convey.Convey("GetRole", t, func(ctx convey.C) {
var (
c = context.TODO()
opt = &common.BaseOptions{}
)
ctx.Convey("When everything gose positive", func(ctx convey.C) {
_, _, err := d.GetRole(c, opt)
ctx.Convey("Then p1 should not be nil.", func(ctx convey.C) {
ctx.So(err, convey.ShouldBeNil)
})
})
})
}

View File

@@ -0,0 +1,61 @@
package(default_visibility = ["//visibility:public"])
load(
"@io_bazel_rules_go//go:def.bzl",
"go_test",
"go_library",
)
go_test(
name = "go_default_test",
srcs = [
"dao_test.go",
"monitor_test.go",
"task_test.go",
],
embed = [":go_default_library"],
rundir = ".",
tags = ["automanaged"],
deps = [
"//app/admin/main/aegis/conf:go_default_library",
"//app/admin/main/aegis/model/common:go_default_library",
"//app/admin/main/aegis/model/task:go_default_library",
"//vendor/github.com/smartystreets/goconvey/convey:go_default_library",
],
)
go_library(
name = "go_default_library",
srcs = [
"dao.go",
"monitor.go",
"task.go",
],
importpath = "go-common/app/admin/main/aegis/dao/mysql",
tags = ["automanaged"],
visibility = ["//visibility:public"],
deps = [
"//app/admin/main/aegis/conf:go_default_library",
"//app/admin/main/aegis/model/common:go_default_library",
"//app/admin/main/aegis/model/monitor:go_default_library",
"//app/admin/main/aegis/model/task:go_default_library",
"//library/database/sql:go_default_library",
"//library/log: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"],
)

View File

@@ -0,0 +1,35 @@
package mysql
import (
"context"
"go-common/app/admin/main/aegis/conf"
xsql "go-common/library/database/sql"
)
// Dao dao
type Dao struct {
c *conf.Config
db *xsql.DB
}
// New init mysql db
func New(c *conf.Config) (dao *Dao) {
dao = &Dao{
c: c,
db: xsql.NewMySQL(c.MySQL),
}
return
}
// Close close the resource.
func (d *Dao) Close() {
d.db.Close()
}
// Ping dao ping
func (d *Dao) Ping(c context.Context) error {
return d.db.Ping(c)
}

View File

@@ -0,0 +1,52 @@
package mysql
import (
"context"
"flag"
"fmt"
"os"
"testing"
"go-common/app/admin/main/aegis/conf"
"github.com/smartystreets/goconvey/convey"
)
var (
d *Dao
cntx context.Context
)
func TestMain(m *testing.M) {
if os.Getenv("DEPLOY_ENV") != "" {
flag.Set("app_id", "main.archive.aegis-admin")
flag.Set("conf_token", "cad913269be022e1eb8c45a8d5408d78")
flag.Set("tree_id", "60977")
flag.Set("conf_version", "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/aegis-admin.toml")
}
flag.Parse()
if err := conf.Init(); err != nil {
panic(fmt.Sprintf("conf.Init() error(%v)", err))
}
d = New(conf.Conf)
cntx = context.TODO()
os.Exit(m.Run())
}
func TestMysqlPing(t *testing.T) {
convey.Convey("Ping", t, func(ctx convey.C) {
ctx.Convey("When everything goes positive", func(ctx convey.C) {
err := d.Ping(cntx)
ctx.Convey("Then err should be nil.", func(ctx convey.C) {
ctx.So(err, convey.ShouldBeNil)
})
})
})
}

View File

@@ -0,0 +1,61 @@
package mysql
import (
"context"
"encoding/json"
"go-common/app/admin/main/aegis/model/monitor"
xsql "go-common/library/database/sql"
"go-common/library/log"
)
const (
_moniBizRulesSql = "SELECT id,type,bid,name,state,stime,etime,rule,uid,ctime,mtime FROM monitor_rule WHERE bid = ?"
_moniRuleSql = "SELECT id,type,bid,name,state,stime,etime,rule,uid,ctime,mtime FROM monitor_rule WHERE id = ?"
)
// MoniBizRules 获取监控业务的所有配置
func (d *Dao) MoniBizRules(c context.Context, bid int64) (rules []*monitor.Rule, err error) {
var (
rows *xsql.Rows
)
if rows, err = d.db.Query(c, _moniBizRulesSql, bid); err != nil {
log.Error("db.Query() error(%v)", err)
return
}
defer rows.Close()
for rows.Next() {
rule := &monitor.Rule{}
var confStr string
if err = rows.Scan(&rule.ID, &rule.Type, &rule.BID, &rule.Name, &rule.State, &rule.STime, &rule.ETime, &confStr, &rule.UID, &rule.CTime, &rule.MTime); err != nil {
log.Error("rows.Scan error(%v)", err)
return
}
conf := &monitor.RuleConf{}
if err = json.Unmarshal([]byte(confStr), conf); err != nil {
log.Error("json.Unmarshal(%s) error(%v)", confStr, err)
return
}
rule.RuleConf = conf
rules = append(rules, rule)
}
return
}
// MoniRule 根据id获取监控规则
func (d *Dao) MoniRule(c context.Context, rid int64) (rule *monitor.Rule, err error) {
rule = &monitor.Rule{}
var confStr string
row := d.db.QueryRow(c, _moniRuleSql, rid)
if err = row.Scan(&rule.ID, &rule.Type, &rule.BID, &rule.Name, &rule.State, &rule.STime, &rule.ETime, &confStr, &rule.UID, &rule.CTime, &rule.MTime); err != nil {
rule = nil
log.Error("row.Scan error(%v)", err)
return
}
conf := &monitor.RuleConf{}
if err = json.Unmarshal([]byte(confStr), conf); err != nil {
log.Error("json.Unmarshal(%s) error(%v)", confStr, err)
return
}
rule.RuleConf = conf
return
}

View File

@@ -0,0 +1,38 @@
package mysql
import (
"context"
"testing"
"github.com/smartystreets/goconvey/convey"
)
func TestMysqlMoniBizRules(t *testing.T) {
convey.Convey("MoniBizRules", t, func(convCtx convey.C) {
var (
c = context.Background()
bid = int64(2)
)
convCtx.Convey("When everything goes positive", func(convCtx convey.C) {
_, err := d.MoniBizRules(c, bid)
convCtx.Convey("Then err should be nil.rules should not be nil.", func(convCtx convey.C) {
convCtx.So(err, convey.ShouldBeNil)
})
})
})
}
func TestMysqlMoniRule(t *testing.T) {
convey.Convey("MoniRule", t, func(convCtx convey.C) {
var (
c = context.Background()
id = int64(1)
)
convCtx.Convey("When everything goes positive", func(convCtx convey.C) {
_, err := d.MoniRule(c, id)
convCtx.Convey("Then err should be nil.rules should not be nil.", func(convCtx convey.C) {
convCtx.So(err, convey.ShouldBeNil)
})
})
})
}

View File

@@ -0,0 +1,494 @@
package mysql
import (
"context"
"database/sql"
"fmt"
"strings"
"time"
"go-common/app/admin/main/aegis/model/common"
modtask "go-common/app/admin/main/aegis/model/task"
xsql "go-common/library/database/sql"
"go-common/library/log"
"go-common/library/xstr"
"github.com/pkg/errors"
)
const (
_taskSQL = "SELECT id,business_id,flow_id,rid,admin_id,uid,state,weight,utime,gtime,mid,fans,`group`,reason,ctime,mtime from task WHERE id=?"
_listCheckSQL = "SELECT id FROM task WHERE id IN (%s)"
_dispatchByIDSQL = "UPDATE task SET gtime=? WHERE id=? AND state=? AND uid=? AND gtime=0"
_queryGtimeSQL = "SELECT gtime FROM task WHERE id=? AND state=? AND uid=?"
_dispatchSQL = "UPDATE task SET gtime=? WHERE state=? AND uid=? AND gtime='0000-00-00 00:00:00' ORDER BY weight LIMIT ?"
_releaseSQL = "UPDATE task SET admin_id=0,uid=0,state=0,gtime='0000-00-00 00:00:00' WHERE business_id=? AND flow_id=? AND uid=? AND (state=? OR (state=0 AND admin_id>0))"
_resetGtimeSQL = "UPDATE task SET gtime='0000-00-00 00:00:00' WHERE state=? AND business_id=? AND flow_id=? AND uid=?"
_seizeSQL = "UPDATE task SET state=?,uid=? WHERE id=? AND state=?"
_submitSQL = "UPDATE task SET state=?,uid=?,utime=? WHERE id=? AND state=? AND uid=?"
_delaySQL = "UPDATE task SET state=?,uid=?,reason=?,gtime='0000-00-00 00:00:00' WHERE id=? AND state=? AND uid=?"
_consumerSQL = "INSERT INTO task_consumer (business_id,flow_id,uid,state) VALUES (?,?,?,?) ON DUPLICATE KEY UPDATE state=?"
_onlinesSQL = "SELECT uid,mtime FROM task_consumer WHERE business_id=? AND flow_id=? AND state=?"
_isconsumerOnSQL = "SELECT state FROM task_consumer WHERE business_id=? AND flow_id=? AND uid=?"
_queryTaskSQL = "SELECT id,business_id,flow_id,uid,weight FROM task WHERE state=? AND mtime<=? AND id>? ORDER BY id LIMIT ?"
_countPersonalSQL = "SELECT count(*) FROM task WHERE state=? AND business_id=? AND flow_id=? AND uid=?"
_queryForSeizeSQL = "SELECT id FROM task WHERE state=? AND business_id=? AND flow_id=? AND uid IN (0,?) ORDER BY weight DESC LIMIT ?"
_listTasksSQL = "SELECT `id`,`business_id`,`flow_id`,`rid`,`admin_id`,`uid`,`state`,`weight`,`utime`,`gtime`,`mid`,`fans`,`group`,`reason`,`ctime`,`mtime` FROM task %s ORDER BY weight DESC LIMIT ?,?"
)
// TaskFromDB .
func (d *Dao) TaskFromDB(c context.Context, id int64) (task *modtask.Task, err error) {
task = &modtask.Task{}
err = d.db.QueryRow(c, _taskSQL, id).
Scan(&task.ID, &task.BusinessID, &task.FlowID, &task.RID, &task.AdminID, &task.UID, &task.State,
&task.Weight, &task.Utime, &task.Gtime, &task.MID, &task.Fans, &task.Group, &task.Reason, &task.Ctime, &task.Mtime)
if err != nil {
task = nil
if err == sql.ErrNoRows {
log.Error("TaskFromDB(%d) norows", id)
err = nil
return
}
log.Error("TaskFromDB(%d) error(%v)", id, errors.WithStack(err))
}
return
}
// DispatchByID 派遣任务,更新gtime
func (d *Dao) DispatchByID(c context.Context, mtasks map[int64]*modtask.Task, ids []int64, args ...interface{}) (missids map[int64]struct{}, err error) {
var (
gtime = time.Now()
uid = args[0].(int64)
)
missids = make(map[int64]struct{})
for _, id := range ids {
var (
rows int64
gt time.Time
res sql.Result
)
if err = d.db.QueryRow(c, _queryGtimeSQL, id, modtask.TaskStateDispatch, uid).Scan(&gt); err != nil {
if err == sql.ErrNoRows {
missids[id] = struct{}{}
err = nil
continue
}
log.Error("d.db.QueryRow error(%v)", errors.WithStack(err))
return
}
if gt.IsZero() {
res, err = d.db.Exec(c, _dispatchByIDSQL, gtime, id, modtask.TaskStateDispatch, uid)
if err != nil {
log.Error("Exec error(%v)", errors.WithStack(err))
return
}
if rows, err = res.RowsAffected(); err != nil {
log.Error("RowsAffected error(%v)", errors.WithStack(err))
return
}
if rows == 0 {
missids[id] = struct{}{}
} else {
mtasks[id].Gtime = common.IntTime(gtime.Unix())
}
} else {
mtasks[id].Gtime = common.IntTime(gt.Unix())
}
}
return
}
// DBDispatch 直接数据库派遣
func (d *Dao) DBDispatch(c context.Context, opt *modtask.NextOptions) (tasks []*modtask.Task, count int64, err error) {
var (
res sql.Result
gtime = time.Now()
)
// 1.直接更新派遣时间
res, err = d.db.Exec(c, _dispatchSQL, gtime, modtask.TaskStateDispatch, opt.UID, opt.DispatchCount)
if err != nil {
log.Error("Exec error(%v)", errors.WithStack(err))
return
}
if count, err = res.RowsAffected(); err != nil {
log.Error("RowsAffected error(%v)", errors.WithStack(err))
return
}
// 2.读取任务
wherecache := fmt.Sprintf("WHERE state=%d AND uid=%d AND gtime!='0000-00-00 00:00:00'", modtask.TaskStateDispatch, opt.UID)
return d.listTasks(c, &modtask.ListOptions{BaseOptions: opt.BaseOptions, Pager: common.Pager{Pn: 1, Ps: int(opt.DispatchCount)}}, wherecache)
}
// Release 释放任务
func (d *Dao) Release(c context.Context, opt *common.BaseOptions, delay bool) (rows int64, err error) {
sql := _releaseSQL
if delay {
sql = _releaseSQL + " AND gtime='0000-00-00 00:00:00'"
}
log.Info("Mysql Release(%+v) delay(%v)", opt, delay)
res, err := d.db.Exec(c, sql, opt.BusinessID, opt.FlowID, opt.UID, modtask.TaskStateDispatch)
if err != nil {
log.Error("db.Exec(%s)[%d,%d,%d,%d] error(%v)", sql, opt.BusinessID, opt.FlowID, opt.UID, modtask.TaskStateDispatch, err)
return
}
// 已经下发的延迟5分钟释放
if delay {
_, err = d.db.Exec(c, _resetGtimeSQL, modtask.TaskStateDispatch, opt.BusinessID, opt.FlowID, opt.UID)
if err != nil {
log.Error("db.Exec(%s)[%d,%d,%d,%d] error(%v)", sql, modtask.TaskStateDispatch, opt.BusinessID, opt.FlowID, opt.UID, err)
}
time.AfterFunc(5*time.Minute, func() {
d.Release(context.Background(), opt, false)
})
}
return res.RowsAffected()
}
// Seize 抢占任务
func (d *Dao) Seize(c context.Context, mapids map[int64]int64) (count int64, err error) {
tx, err := d.db.Begin(c)
if err != nil {
log.Error("d.Seize.Begin error(%v)", errors.WithStack(err))
return
}
defer tx.Commit()
for tid, uid := range mapids {
var (
rows int64
res sql.Result
)
res, err = tx.Exec(_seizeSQL, modtask.TaskStateDispatch, uid, tid, modtask.TaskStateInit)
if err != nil {
log.Error("Exec error(%v)", errors.WithStack(err))
tx.Rollback()
return
}
if rows, err = res.RowsAffected(); err != nil {
log.Error("RowsAffected error(%v)", errors.WithStack(err))
tx.Rollback()
return
}
if rows == 1 {
count++
}
}
return
}
// Delay 延迟任务
func (d *Dao) Delay(c context.Context, opt *modtask.DelayOptions) (rows int64, err error) {
var (
res sql.Result
)
res, err = d.db.Exec(c, _delaySQL, modtask.TaskStateDelay, opt.UID, opt.Reason, opt.TaskID, modtask.TaskStateDispatch, opt.UID)
if err != nil {
log.Error("Exec error(%v)", errors.WithStack(err))
return
}
if rows, err = res.RowsAffected(); err != nil {
log.Error("RowsAffected error(%v)", errors.WithStack(err))
return
}
return
}
// ListCheckUnSeized .
func (d *Dao) ListCheckUnSeized(c context.Context, mtasks map[int64]*modtask.Task, ids []int64, args ...interface{}) (missids map[int64]struct{}, err error) {
wherecase := fmt.Sprintf("state = %d", modtask.TaskStateInit)
return d.listCheck(c, wherecase, ids)
}
// ListCheckSeized .
func (d *Dao) ListCheckSeized(c context.Context, mtasks map[int64]*modtask.Task, ids []int64, args ...interface{}) (missids map[int64]struct{}, err error) {
if len(args) < 1 {
return
}
uid := args[0].(int64)
wherecase := fmt.Sprintf("state = %d", modtask.TaskStateDispatch)
if uid != 0 {
wherecase += fmt.Sprintf(" AND uid=%d", uid)
}
return d.listCheck(c, wherecase, ids)
}
// ListCheckDelay .
func (d *Dao) ListCheckDelay(c context.Context, mtasks map[int64]*modtask.Task, ids []int64, args ...interface{}) (missids map[int64]struct{}, err error) {
if len(args) < 1 {
return
}
uid := args[0].(int64)
wherecase := fmt.Sprintf("state=%d", modtask.TaskStateDelay)
if uid != 0 {
wherecase += fmt.Sprintf(" AND uid=%d", uid)
}
return d.listCheck(c, wherecase, ids)
}
// ListTasks .
func (d *Dao) ListTasks(c context.Context, opt *modtask.ListOptions) (tasks []*modtask.Task, count int64, err error) {
var (
wherecase string
cases []string
state int8
isDefault bool
)
switch opt.State {
case 1:
state = modtask.TaskStateInit
case 2:
state = modtask.TaskStateDispatch
case 3:
state = modtask.TaskStateDelay
case 4:
state = modtask.TaskStateDispatch
cases = append(cases, "admin_id>0")
default:
isDefault = true
cases = append(cases, fmt.Sprintf("state<%d", modtask.TaskStateSubmit))
}
if !isDefault {
cases = append(cases, fmt.Sprintf("state=%d", state))
if !opt.BisLeader && (opt.State == 2 || opt.State == 3 || opt.State == 4) {
cases = append(cases, fmt.Sprintf("uid=%d", opt.UID))
}
}
wherecase = fmt.Sprintf("WHERE business_id=%d AND flow_id=%d AND ", opt.BusinessID, opt.FlowID) + strings.Join(cases, " AND ")
return d.listTasks(c, opt, wherecase)
}
func (d *Dao) listTasks(c context.Context, opt *modtask.ListOptions, wherecase string) (tasks []*modtask.Task, count int64, err error) {
countSQL := fmt.Sprintf("SELECT count(*) FROM task %s", wherecase)
if err = d.db.QueryRow(c, countSQL).Scan(&count); err != nil {
log.Error("QueryRow error(%v)", err)
return
}
if count > 0 {
var (
rows *xsql.Rows
listSQL = fmt.Sprintf(_listTasksSQL, wherecase)
)
if rows, err = d.db.Query(c, listSQL, (opt.Pn-1)*opt.Ps, opt.Pn*opt.Ps); err != nil {
log.Error("Query error(%v)", err)
return
}
defer rows.Close()
for rows.Next() {
task := &modtask.Task{}
if err = rows.Scan(&task.ID, &task.BusinessID, &task.FlowID, &task.RID, &task.AdminID, &task.UID, &task.State,
&task.Weight, &task.Utime, &task.Gtime, &task.MID, &task.Fans, &task.Group, &task.Reason, &task.Ctime, &task.Mtime); err != nil {
log.Error("Scan error(%v)", err)
return
}
tasks = append(tasks, task)
}
}
return
}
func (d *Dao) listCheck(c context.Context, wherecase string, ids []int64) (missids map[int64]struct{}, err error) {
if len(ids) == 0 {
return
}
missids = make(map[int64]struct{})
mapids := make(map[int64]struct{})
log.Info("listCheck ids(%v)", ids)
defer func() {
log.Info("listCheck missids(%v)", missids)
}()
for _, id := range ids {
mapids[id] = struct{}{}
}
var (
rows *xsql.Rows
sqlstring = fmt.Sprintf(_listCheckSQL, xstr.JoinInts(ids)) + " AND " + wherecase
)
if rows, err = d.db.Query(c, sqlstring); err != nil {
log.Error("db.Query(%s) error(%v)", sqlstring, errors.WithStack(err))
return
}
defer rows.Close()
for rows.Next() {
var id int64
if err = rows.Scan(&id); err != nil {
log.Error("rows.Scan error(%v)", errors.WithStack(err))
return
}
delete(mapids, id)
}
for id := range mapids {
missids[id] = struct{}{}
}
return
}
// ConsumerOn .
func (d *Dao) ConsumerOn(c context.Context, opt *common.BaseOptions) (err error) {
return d.consumer(c, opt, modtask.ActionConsumerOn)
}
// ConsumerOff .
func (d *Dao) ConsumerOff(c context.Context, opt *common.BaseOptions) (err error) {
return d.consumer(c, opt, modtask.ActionConsumerOff)
}
// IsConsumerOn .
func (d *Dao) IsConsumerOn(c context.Context, opt *common.BaseOptions) (on bool, err error) {
var state int8
if err = d.db.QueryRow(c, _isconsumerOnSQL, opt.BusinessID, opt.FlowID, opt.UID).Scan(&state); err != nil {
if err == sql.ErrNoRows {
err = nil
return
}
log.Error("d.db.QueryRow error(%v)", err)
return
}
if state == modtask.ActionConsumerOn {
on = true
}
return
}
func (d *Dao) consumer(c context.Context, opt *common.BaseOptions, action int8) (err error) {
var (
res sql.Result
)
res, err = d.db.Exec(c, _consumerSQL, opt.BusinessID, opt.FlowID, opt.UID, action, action)
if err != nil {
log.Error("Exec error(%v)", errors.WithStack(err))
return
}
if _, err = res.RowsAffected(); err != nil {
log.Error("RowsAffected error(%v)", errors.WithStack(err))
return
}
return
}
// ConsumerStat 24小时内有活动或者在线的用户
func (d *Dao) ConsumerStat(c context.Context, bizid, flowid int64) (items []*modtask.WatchItem, err error) {
var rows *xsql.Rows
sql := "SELECT uid,mtime,state from task_consumer where business_id=? AND flow_id=? AND (mtime > ? or state=1) order by mtime desc"
if rows, err = d.db.Query(c, sql, bizid, flowid, time.Now().Add(-24*time.Hour)); err != nil {
log.Error("ConsumerStat error(%v)", err)
return
}
defer rows.Close()
for rows.Next() {
item := &modtask.WatchItem{}
if err = rows.Scan(&item.UID, &item.Mtime, &item.State); err != nil {
log.Error("ConsumerStat error(%v)", err)
return
}
items = append(items, item)
}
return
}
// Onlines 在线列表
func (d *Dao) Onlines(c context.Context, opt *common.BaseOptions) (uids map[int64]time.Time, err error) {
var (
rows *xsql.Rows
)
rows, err = d.db.Query(c, _onlinesSQL, opt.BusinessID, opt.FlowID, modtask.ActionConsumerOn)
if err != nil {
log.Error("db.Query error(%v)", err)
return
}
defer rows.Close()
uids = make(map[int64]time.Time)
for rows.Next() {
var (
uid int64
mtime time.Time
)
if err = rows.Scan(&uid, &mtime); err != nil {
log.Error("rows.Scan error(%v)", err)
return
}
uids[uid] = mtime
}
return
}
// QueryTask .
func (d *Dao) QueryTask(c context.Context, state int8, mtime time.Time, id, limit int64) (tasks []*modtask.Task, lastid int64, err error) {
var rows *xsql.Rows
rows, err = d.db.Query(c, _queryTaskSQL, state, mtime, id, limit)
if err != nil {
log.Error("db.Query error(%v)", err)
return
}
defer rows.Close()
for rows.Next() {
task := &modtask.Task{}
if err = rows.Scan(&task.ID, &task.BusinessID, &task.FlowID, &task.UID, &task.Weight); err != nil {
log.Error("rows.Scan error(%v)", err)
return
}
tasks = append(tasks, task)
lastid = task.ID
}
return
}
// CountPersonal count personal task
func (d *Dao) CountPersonal(c context.Context, opt *common.BaseOptions) (count int64, err error) {
if err = d.db.QueryRow(c, _countPersonalSQL, modtask.TaskStateDispatch, opt.BusinessID, opt.FlowID, opt.UID).Scan(&count); err != nil {
log.Error("QueryRow error(%v)", errors.WithStack(err))
return
}
return
}
// QueryForSeize 查询当前可抢占的任务
func (d *Dao) QueryForSeize(c context.Context, businessID, flowID, uid, seizecount int64) (hitids []int64, err error) {
log.Info("task-QueryForSeize businessID(%d), flowID(%d), uid(%d), seizecount(%d)", businessID, flowID, uid, seizecount)
defer func() { log.Info("task-QueryForSeize hitids(%v), err(%v)", hitids, err) }()
var rows *xsql.Rows
rows, err = d.db.Query(c, _queryForSeizeSQL, modtask.TaskStateInit, businessID, flowID, uid, seizecount)
if err != nil {
log.Error("db.Query error(%v)", err)
return
}
defer rows.Close()
for rows.Next() {
var id int64
if err = rows.Scan(&id); err != nil {
log.Error("rows.Scan error(%v)", err)
return
}
hitids = append(hitids, id)
}
return
}

View File

@@ -0,0 +1,305 @@
package mysql
import (
"context"
"testing"
"time"
"go-common/app/admin/main/aegis/model/common"
modtask "go-common/app/admin/main/aegis/model/task"
"github.com/smartystreets/goconvey/convey"
)
func TestMysqlTaskFromDB(t *testing.T) {
convey.Convey("TaskFromDB", t, func(ctx convey.C) {
var (
id = int64(0)
)
ctx.Convey("When everything goes positive", func(ctx convey.C) {
task, err := d.TaskFromDB(cntx, id)
ctx.Convey("Then err should be nil.task should be nil.", func(ctx convey.C) {
ctx.So(err, convey.ShouldBeNil)
ctx.So(task, convey.ShouldBeNil)
})
})
})
}
func TestMysqlDispatchByID(t *testing.T) {
convey.Convey("DispatchByID", t, func(ctx convey.C) {
var (
mtasks map[int64]*modtask.Task
ids = []int64{0}
args = interface{}(int64(0))
)
ctx.Convey("When everything goes positive", func(ctx convey.C) {
missids, err := d.DispatchByID(cntx, mtasks, ids, args)
ctx.Convey("Then err should be nil.missids should not be nil.", func(ctx convey.C) {
ctx.So(err, convey.ShouldBeNil)
ctx.So(missids, convey.ShouldNotBeNil)
})
})
})
}
func TestMysqlDBDispatch(t *testing.T) {
convey.Convey("DBDispatch", t, func(ctx convey.C) {
var (
opt = &modtask.NextOptions{}
)
ctx.Convey("When everything goes positive", func(ctx convey.C) {
_, count, err := d.DBDispatch(cntx, opt)
ctx.Convey("Then err should be nil.tasks,count should not be nil.", func(ctx convey.C) {
ctx.So(err, convey.ShouldBeNil)
ctx.So(count, convey.ShouldNotBeNil)
})
})
})
}
func TestMysqlRelease(t *testing.T) {
convey.Convey("Release", t, func(ctx convey.C) {
var (
opt = &common.BaseOptions{}
)
ctx.Convey("When everything goes positive", func(ctx convey.C) {
rows, err := d.Release(cntx, opt, true)
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 TestMysqlSeize(t *testing.T) {
convey.Convey("Seize", t, func(ctx convey.C) {
var (
c = context.Background()
mapids = map[int64]int64{1: 1}
)
ctx.Convey("When everything goes positive", func(ctx convey.C) {
count, err := d.Seize(c, mapids)
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 TestMysqlDelay(t *testing.T) {
convey.Convey("Delay", t, func(ctx convey.C) {
var (
opt = &modtask.DelayOptions{}
)
ctx.Convey("When everything goes positive", func(ctx convey.C) {
rows, err := d.Delay(cntx, opt)
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 TestMysqlListCheckUnSeized(t *testing.T) {
convey.Convey("ListCheckUnSeized", t, func(ctx convey.C) {
var (
mtasks = map[int64]*modtask.Task{}
)
ctx.Convey("When everything goes positive", func(ctx convey.C) {
_, err := d.ListCheckUnSeized(cntx, mtasks, []int64{})
ctx.Convey("Then err should be nil.rows should not be nil.", func(ctx convey.C) {
ctx.So(err, convey.ShouldBeNil)
})
})
})
}
func TestMysqlListCheckSeized(t *testing.T) {
convey.Convey("ListCheckSeized", t, func(ctx convey.C) {
var (
mtasks = map[int64]*modtask.Task{}
)
ctx.Convey("When everything goes positive", func(ctx convey.C) {
_, err := d.ListCheckSeized(cntx, mtasks, []int64{}, int64(1))
ctx.Convey("Then err should be nil.rows should not be nil.", func(ctx convey.C) {
ctx.So(err, convey.ShouldBeNil)
})
})
})
}
func TestMysqlListCheckDelay(t *testing.T) {
convey.Convey("ListCheckDelay", t, func(ctx convey.C) {
var (
mtasks = map[int64]*modtask.Task{}
)
ctx.Convey("When everything goes positive", func(ctx convey.C) {
_, err := d.ListCheckDelay(cntx, mtasks, []int64{}, int64(1))
ctx.Convey("Then err should be nil.rows should not be nil.", func(ctx convey.C) {
ctx.So(err, convey.ShouldBeNil)
})
})
})
}
func TestMysqlListTasks(t *testing.T) {
convey.Convey("ListTasks", t, func(ctx convey.C) {
opt := &modtask.ListOptions{
State: 4,
}
ctx.Convey("When everything goes positive", func(ctx convey.C) {
_, _, err := d.ListTasks(context.TODO(), opt)
ctx.Convey("Then err should be nil.res should not be nil.", func(ctx convey.C) {
ctx.So(err, convey.ShouldBeNil)
})
})
})
}
func TestMysqllistCheck(t *testing.T) {
convey.Convey("listCheck", t, func(ctx convey.C) {
ctx.Convey("When everything goes positive", func(ctx convey.C) {
_, err := d.listCheck(context.TODO(), "state=1", []int64{1})
ctx.Convey("Then err should be nil.res should not be nil.", func(ctx convey.C) {
ctx.So(err, convey.ShouldBeNil)
})
})
})
}
func TestMysqlConsumerOn(t *testing.T) {
convey.Convey("ConsumerOn", t, func(ctx convey.C) {
var (
c = context.Background()
opt = &common.BaseOptions{}
)
ctx.Convey("When everything goes positive", func(ctx convey.C) {
err := d.ConsumerOn(c, opt)
ctx.Convey("Then err should be nil.", func(ctx convey.C) {
ctx.So(err, convey.ShouldBeNil)
})
})
})
}
func TestMysqlConsumerOff(t *testing.T) {
convey.Convey("ConsumerOff", t, func(ctx convey.C) {
var (
c = context.Background()
opt = &common.BaseOptions{}
)
ctx.Convey("When everything goes positive", func(ctx convey.C) {
err := d.ConsumerOff(c, opt)
ctx.Convey("Then err should be nil.", func(ctx convey.C) {
ctx.So(err, convey.ShouldBeNil)
})
})
})
}
func TestMysqlIsConsumerOn(t *testing.T) {
convey.Convey("IsConsumerOn", t, func(ctx convey.C) {
var (
c = context.Background()
opt = &common.BaseOptions{}
)
ctx.Convey("When everything goes positive", func(ctx convey.C) {
on, err := d.IsConsumerOn(c, opt)
ctx.Convey("Then err should be nil.on should not be nil.", func(ctx convey.C) {
ctx.So(err, convey.ShouldBeNil)
ctx.So(on, convey.ShouldNotBeNil)
})
})
})
}
func TestMysqlconsumer(t *testing.T) {
convey.Convey("consumer", t, func(ctx convey.C) {
var (
c = context.Background()
opt = &common.BaseOptions{}
action = int8(0)
)
ctx.Convey("When everything goes positive", func(ctx convey.C) {
err := d.consumer(c, opt, action)
ctx.Convey("Then err should be nil.", func(ctx convey.C) {
ctx.So(err, convey.ShouldBeNil)
})
})
})
}
func TestMysqlConsumerStat(t *testing.T) {
convey.Convey("ConsumerStat", t, func(ctx convey.C) {
var (
c = context.Background()
bizid = int64(0)
flowid = int64(0)
)
ctx.Convey("When everything goes positive", func(ctx convey.C) {
items, err := d.ConsumerStat(c, bizid, flowid)
ctx.Convey("Then err should be nil.items should not be nil.", func(ctx convey.C) {
ctx.So(err, convey.ShouldBeNil)
ctx.So(items, convey.ShouldNotBeNil)
})
})
})
}
func TestMysqlOnlines(t *testing.T) {
convey.Convey("Onlines", t, func(ctx convey.C) {
var (
c = context.Background()
opt = &common.BaseOptions{}
)
ctx.Convey("When everything goes positive", func(ctx convey.C) {
uids, err := d.Onlines(c, opt)
ctx.Convey("Then err should be nil.uids should not be nil.", func(ctx convey.C) {
ctx.So(err, convey.ShouldBeNil)
ctx.So(uids, convey.ShouldNotBeNil)
})
})
})
}
func TestMysqlQueryTask(t *testing.T) {
convey.Convey("QueryTask", t, func(ctx convey.C) {
ctx.Convey("When everything goes positive", func(ctx convey.C) {
_, _, err := d.QueryTask(context.TODO(), 0, time.Now(), 0, 0)
ctx.Convey("Then err should be nil.res should not be nil.", func(ctx convey.C) {
ctx.So(err, convey.ShouldBeNil)
})
})
})
}
func TestMysqlCountPersonal(t *testing.T) {
convey.Convey("CountPersonal", t, func(ctx convey.C) {
var (
c = context.Background()
opt = &common.BaseOptions{}
)
ctx.Convey("When everything goes positive", func(ctx convey.C) {
count, err := d.CountPersonal(c, opt)
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 TestMysqlQueryForSeize(t *testing.T) {
convey.Convey("QueryForSeize", t, func(ctx convey.C) {
ctx.Convey("When everything goes positive", func(ctx convey.C) {
_, err := d.QueryForSeize(context.TODO(), 0, 0, 0, 0)
ctx.Convey("Then err should be nil.res should not be nil.", func(ctx convey.C) {
ctx.So(err, convey.ShouldBeNil)
})
})
})
}

View File

@@ -0,0 +1,64 @@
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",
"monitor_test.go",
"net_test.go",
"task_test.go",
],
embed = [":go_default_library"],
rundir = ".",
tags = ["automanaged"],
deps = [
"//app/admin/main/aegis/conf:go_default_library",
"//app/admin/main/aegis/model/common:go_default_library",
"//app/admin/main/aegis/model/task:go_default_library",
"//vendor/github.com/smartystreets/goconvey/convey:go_default_library",
],
)
go_library(
name = "go_default_library",
srcs = [
"cluster.go",
"dao.go",
"monitor.go",
"net.go",
"task.go",
],
importpath = "go-common/app/admin/main/aegis/dao/redis",
tags = ["automanaged"],
visibility = ["//visibility:public"],
deps = [
"//app/admin/main/aegis/conf:go_default_library",
"//app/admin/main/aegis/model/common:go_default_library",
"//app/admin/main/aegis/model/monitor:go_default_library",
"//app/admin/main/aegis/model/task:go_default_library",
"//library/cache/redis:go_default_library",
"//library/ecode:go_default_library",
"//library/log: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,243 @@
package redis
import (
"context"
"encoding/json"
"fmt"
"time"
modtask "go-common/app/admin/main/aegis/model/task"
"go-common/library/cache/redis"
"go-common/library/ecode"
"go-common/library/log"
"github.com/pkg/errors"
)
func lockKey(businessID, flowID int64) string {
return fmt.Sprintf("aegis_lock_%d_%d", businessID, flowID)
}
func (d *Dao) getlock(c context.Context, bizid, flowid int64) (ok bool) {
var (
conn = d.cluster.Get(c)
key = lockKey(bizid, flowid)
err error
)
defer conn.Close()
if ok, err = redis.Bool(conn.Do("SETNX", key, "1")); err != nil {
if err == redis.ErrNil {
err = nil
} else {
log.Error("conn.Do(SETNX(%s)) error(%v)", key, err)
return
}
}
if ok {
conn.Do("EXPIRE", key, 3)
}
return
}
//SeizeTask .
func (d *Dao) SeizeTask(c context.Context, businessID, flowID, uid, count int64) (hitids []int64, missids []int64, others map[int64]int64, err error) {
var (
lock bool
pubkey = publicKey(businessID, flowID)
ids []int64
)
// 1. 抢占分布式锁
for lc := 0; lc < 3; lc++ {
if lock = d.getlock(c, businessID, flowID); lock {
break
}
time.Sleep(10 * time.Millisecond)
}
if !lock {
log.Error("getlock getlock fail(%d,%d,%d)", businessID, flowID, uid)
err = ecode.AegisTaskBusy
return
}
conn := d.cluster.Get(c)
defer conn.Close()
defer conn.Do("DEL", lockKey(businessID, flowID))
var (
head, tail = int64(0), int64(count)
)
// 2. 从 public 按权重从高到低取出一批来
for {
if ids, err = redis.Int64s(conn.Do("ZRANGE", pubkey, head, tail)); err != nil {
log.Error("redis (ZRANGE,%s,%d,%d) error(%v)", pubkey, 0, count, err)
return
}
head += count
tail += count
if len(ids) == 0 {
break
}
for _, id := range ids {
if err = conn.Send("GET", haskKey(id)); err != nil {
log.Error("redis (GET,%s) error(%v)", haskKey(id), err)
return
}
}
conn.Flush()
var enough bool
for _, id := range ids {
var (
bs []byte
e error
)
bs, e = redis.Bytes(conn.Receive())
if e != nil {
log.Error("Receive Weight(%d) error(%v)", id, errors.WithStack(e))
missids = append(missids, id)
continue
}
task := &modtask.Task{}
if e = json.Unmarshal(bs, task); err != nil {
log.Error("json.Unmarshal error(%v)", errors.WithStack(e))
missids = append(missids, id)
continue
}
if task.ID != id {
log.Error("id(%d-%d)不匹配", task.ID, id)
missids = append(missids, id)
continue
}
if task.UID != 0 && task.UID != uid {
log.Info("id(%d) 任务已经指派给(%d)", task.ID, task.UID)
missids = append(missids, id)
continue
}
hitids = append(hitids, id)
if len(hitids) >= int(count) {
enough = true
break
}
}
if enough {
break
}
}
personKey := personalKey(businessID, flowID, uid)
for _, id := range hitids {
conn.Send("ZREM", pubkey, formatID(id))
conn.Send("LREM", personKey, 0, id)
conn.Send("RPUSH", personKey, id)
}
conn.Flush()
for i := 0; i < len(hitids)*3; i++ {
conn.Receive()
}
log.Info("rangefunc count(%d) hitids(%v) missids(%v)", count, hitids, missids)
return
}
/*
遍历personal,delay,public。
在缓存中进行状态校验public还要补充缓存权重
*/
func (d *Dao) rangefuncCluster(c context.Context, listtype string, opt *modtask.ListOptions) (tasks map[int64]*modtask.Task, count int64, hitids, missids []int64, err error) {
var (
key string
LENCMD, RANGECMD = "LLEN", "LRANGE"
ids []int64
)
conn := d.cluster.Get(c)
defer conn.Close()
switch listtype {
case "public":
LENCMD, RANGECMD = "ZCARD", "ZRANGE"
key = publicKey(opt.BusinessID, opt.FlowID)
case "personal":
key = personalKey(opt.BusinessID, opt.FlowID, opt.UID)
case "delay":
key = delayKey(opt.BusinessID, opt.FlowID, opt.UID)
}
// 1. 长度
if count, err = redis.Int64(conn.Do(LENCMD, key)); err != nil {
log.Error("redis (%s,%s) error(%v)", LENCMD, key, err)
return
}
if count == 0 {
return
}
if ids, err = redis.Int64s(conn.Do(RANGECMD, key, (opt.Pn-1)*opt.Ps, opt.Pn*opt.Ps-1)); err != nil {
log.Error("redis (%s,%s,%d,%d) error(%v)", LENCMD, key, (opt.Pn-1)*opt.Ps, opt.Pn*opt.Ps, err)
return
}
for _, id := range ids {
if err = conn.Send("GET", haskKey(id)); err != nil {
log.Error("redis (GET,%s) error(%v)", haskKey(id), err)
return
}
if listtype == "public" {
if err = conn.Send("ZSCORE", key, formatID(id)); err != nil {
log.Error("redis (ZSCORE,%s,%s) error(%v)", key, formatID(id), err)
return
}
}
}
conn.Flush()
tasks = make(map[int64]*modtask.Task)
for _, id := range ids {
var (
bs []byte
e error
wt int64
)
bs, e = redis.Bytes(conn.Receive())
if listtype == "public" {
wt, _ = redis.Int64(conn.Receive())
wt = -wt
}
if e != nil {
log.Error("Receive Weight(%d) error(%v)", id, errors.WithStack(e))
missids = append(missids, id)
continue
}
task := &modtask.Task{}
if e = json.Unmarshal(bs, task); err != nil {
log.Error("json.Unmarshal error(%v)", errors.WithStack(e))
missids = append(missids, id)
continue
}
if task.ID != id {
log.Error("id(%d-%d)不匹配", task.ID, id)
missids = append(missids, id)
continue
}
// 缓存里状态同步不实时,不能用作校验
tasks[task.ID] = task
hitids = append(hitids, id)
}
log.Info("rangefunc count(%d) hitids(%v) missids(%v)", count, hitids, missids)
return
}

View File

@@ -0,0 +1,39 @@
package redis
import (
"context"
"go-common/app/admin/main/aegis/conf"
"go-common/library/cache/redis"
)
// Dao dao
type Dao struct {
c *conf.Config
cluster *redis.Pool
netExpire int64
}
// New init mysql db
func New(c *conf.Config) (dao *Dao) {
dao = &Dao{
c: c,
cluster: redis.NewPool(c.Redis.Cluster),
netExpire: int64(c.Redis.NetExpire),
}
if dao.netExpire == 0 {
dao.netExpire = int64(1800) //30m
}
return
}
// Close close the resource.
func (d *Dao) Close() {
d.cluster.Close()
}
// Ping dao ping
func (d *Dao) Ping(c context.Context) error {
return nil
}

View File

@@ -0,0 +1,52 @@
package redis
import (
"context"
"flag"
"fmt"
"os"
"testing"
"go-common/app/admin/main/aegis/conf"
"github.com/smartystreets/goconvey/convey"
)
var (
d *Dao
cntx context.Context
)
func TestMain(m *testing.M) {
if os.Getenv("DEPLOY_ENV") != "" {
flag.Set("app_id", "main.archive.aegis-admin")
flag.Set("conf_token", "cad913269be022e1eb8c45a8d5408d78")
flag.Set("tree_id", "60977")
flag.Set("conf_version", "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/aegis-admin.toml")
}
flag.Parse()
if err := conf.Init(); err != nil {
panic(fmt.Sprintf("conf.Init() error(%v)", err))
}
d = New(conf.Conf)
cntx = context.TODO()
os.Exit(m.Run())
}
func TestRedisPing(t *testing.T) {
convey.Convey("Ping", t, func(ctx convey.C) {
ctx.Convey("When everything goes positive", func(ctx convey.C) {
err := d.Ping(cntx)
ctx.Convey("Then err should be nil.", func(ctx convey.C) {
ctx.So(err, convey.ShouldBeNil)
})
})
})
}

View File

@@ -0,0 +1,65 @@
package redis
import (
"context"
"fmt"
"go-common/app/admin/main/aegis/model/monitor"
"go-common/library/cache/redis"
"go-common/library/log"
"strconv"
"time"
)
// MoniRuleStats 获取监控统计
func (d *Dao) MoniRuleStats(c context.Context, id, min, max int64) (stats *monitor.Stats, err error) {
var (
conn = d.cluster.Get(c)
key = fmt.Sprintf(monitor.RedisPrefix, id)
now = time.Now().Unix()
)
stats = &monitor.Stats{}
defer conn.Close()
if stats.TotalCount, err = redis.Int(conn.Do("ZCOUNT", key, 0, now)); err != nil {
log.Error("conn.Do(ZCOUNT,%s,0,%d) error(%v)", key, now, err)
return
}
if stats.MoniCount, err = redis.Int(conn.Do("ZCOUNT", key, min, max)); err != nil {
log.Error("conn.Do(ZCOUNT,%s,%d,%d) error(%v)", key, min, max, err)
return
}
var oldest map[string]string //进入列表最久的项
oldest, err = redis.StringMap(conn.Do("ZRANGE", key, 0, 0, "WITHSCORES"))
for _, t := range oldest {
var i int
if i, err = strconv.Atoi(t); err != nil {
return
}
stats.MaxTime = int(now) - i
}
return
}
// MoniRuleOids 获取监控符合报警时长的
func (d *Dao) MoniRuleOids(c context.Context, id, min, max int64) (oidMap map[int64]int, err error) {
var (
key = fmt.Sprintf(monitor.RedisPrefix, id)
conn = d.cluster.Get(c)
strMap map[string]int
)
oidMap = make(map[int64]int)
strMap = make(map[string]int)
defer conn.Close()
if strMap, err = redis.IntMap(conn.Do("ZRANGEBYSCORE", key, min, max, "WITHSCORES")); err != nil {
log.Error("redis.IntMap(conn.Do(\"ZRANGEBYSCORE\", %s, %d, %d, \"WITHSCORES\")) error(%v)", key, min, max, err)
return
}
for k, v := range strMap {
oid := 0
if oid, err = strconv.Atoi(k); err != nil {
log.Error("strconv.Atoi(%s) error(%v)", k, err)
}
oidMap[int64(oid)] = v
}
return
}

View File

@@ -0,0 +1,31 @@
package redis
import (
"context"
"testing"
"github.com/smartystreets/goconvey/convey"
)
func TestRedisMoniRuleStats(t *testing.T) {
var (
c = context.TODO()
)
convey.Convey("MoniRuleStats", t, func(ctx convey.C) {
_, err := d.MoniRuleStats(c, 1, 0, 0)
ctx.Convey("Then err should be nil.", func(ctx convey.C) {
ctx.So(err, convey.ShouldBeNil)
})
})
}
func TestRedisMoniRuleOids(t *testing.T) {
var (
c = context.TODO()
)
convey.Convey("MoniRuleOids", t, func(ctx convey.C) {
_, err := d.MoniRuleOids(c, 1, 0, 0)
ctx.Convey("Then err should be nil.", func(ctx convey.C) {
ctx.So(err, convey.ShouldBeNil)
})
})
}

View File

@@ -0,0 +1,71 @@
package redis
import (
"context"
"go-common/library/cache/redis"
"go-common/library/log"
)
//SetMulti setex key expire val, kvs as multi key val
func (d *Dao) SetMulti(c context.Context, kvs map[string]string) (err error) {
if len(kvs) == 0 {
return
}
conn := d.cluster.Get(c)
defer conn.Close()
//拼接参数
for key, val := range kvs {
if err = conn.Send("SETEX", key, d.netExpire, val); err != nil {
log.Error("SetMulti conn.send(SETEX) error(%v)", err)
return
}
}
if err = conn.Flush(); err != nil {
log.Error("SetMulti conn.Flush error(%v)", err)
}
return
}
//MGet get multi key value
func (d *Dao) MGet(c context.Context, keys ...string) (dest []string, err error) {
//检测参数
if len(keys) == 0 {
return
}
//拼接查询参数+ redis请求
args := redis.Args{}
for _, item := range keys {
args = args.Add(item)
}
conn := d.cluster.Get(c)
defer conn.Close()
if dest, err = redis.Strings(conn.Do("MGET", args...)); err != nil {
log.Error("MGet conn.Do(mget) error(%v) args(%+v)", err, args)
}
return
}
//DelMulti del redis keys
func (d *Dao) DelMulti(c context.Context, keys ...string) (err error) {
if len(keys) == 0 {
return
}
conn := d.cluster.Get(c)
defer conn.Close()
args := redis.Args{}
for _, k := range keys {
args = args.Add(k)
}
if _, err = redis.Int(conn.Do("DEL", args...)); err != nil {
log.Error("DelMulti conn.Do(del) error(%v) args(%+v)", err, args)
}
return
}

View File

@@ -0,0 +1,53 @@
package redis
import (
"context"
"testing"
"github.com/smartystreets/goconvey/convey"
)
var (
kvs = map[string]string{
"test:1": "test111-11",
"test:2": "test222-22",
}
ks = []string{"test:1", "test:2"}
)
func TestRedisSetMulti(t *testing.T) {
var (
c = context.TODO()
)
convey.Convey("SetMulti", t, func(ctx convey.C) {
err := d.SetMulti(c, kvs)
ctx.Convey("Then err should be nil.", func(ctx convey.C) {
ctx.So(err, convey.ShouldBeNil)
})
})
}
func TestRedisMGet(t *testing.T) {
var (
c = context.TODO()
)
convey.Convey("MGet", t, func(ctx convey.C) {
dest, err := d.MGet(c, ks...)
ctx.Convey("Then err should be nil.dest should not be nil.", func(ctx convey.C) {
ctx.So(err, convey.ShouldBeNil)
ctx.So(dest, convey.ShouldNotBeNil)
})
})
}
func TestRedisDelMulti(t *testing.T) {
var (
c = context.TODO()
)
convey.Convey("DelMulti", t, func(ctx convey.C) {
err := d.DelMulti(c, ks...)
ctx.Convey("Then err should be nil.", func(ctx convey.C) {
ctx.So(err, convey.ShouldBeNil)
})
})
}

View File

@@ -0,0 +1,303 @@
package redis
import (
"context"
"encoding/json"
"fmt"
"time"
"go-common/app/admin/main/aegis/model/common"
modtask "go-common/app/admin/main/aegis/model/task"
"go-common/library/cache/redis"
"go-common/library/log"
"github.com/pkg/errors"
)
/*
四个缓存
1. personalPool 存储每个用户的任务池 类型为List []taskid
2. publicPool 存储还未被领取的任务 类型为Sorted Set weight-taskid
3. delayPool 存储每个用户的延迟任务 类型为List
4. hashTask 存储所有任务的所有其他字段信息
*/
const (
_hashexpire = 24 * 60 * 60
)
func personalKey(businessID, flowID int64, uid int64) string {
return fmt.Sprintf("personal_%d_%d_%d", businessID, flowID, uid)
}
func publicKey(businessID, flowID int64) string {
return fmt.Sprintf("{%d-%d}public_%d_%d", businessID, flowID, businessID, flowID)
}
func delayKey(businessID, flowID int64, uid int64) string {
return fmt.Sprintf("delay_%d_%d_%d", businessID, flowID, uid)
}
func haskKey(taskid int64) string {
return fmt.Sprintf("task_%d", taskid)
}
// formatID 在sorted set里面id要扩展出来否则排序不对
func formatID(taskid int64) string {
return fmt.Sprintf("%.11d", taskid)
}
// CountPersonalTask 统计个数
func (d *Dao) CountPersonalTask(c context.Context, opt *common.BaseOptions) (count int64, err error) {
conn := d.cluster.Get(c)
defer conn.Close()
key := personalKey(opt.BusinessID, opt.FlowID, opt.UID)
if count, err = redis.Int64(conn.Do("LLEN", key)); err != nil {
log.Error("conn.Do(LLEN,%s) error(%v)", key, err)
}
return
}
// RangePersonalTask 从本人的任务池取
func (d *Dao) RangePersonalTask(c context.Context, opt *modtask.ListOptions) (tasks map[int64]*modtask.Task, count int64, hitids, missids []int64, err error) {
tasks, count, hitids, missids, err = d.rangefuncCluster(c, "personal", opt)
return
}
// RangeDealyTask .
func (d *Dao) RangeDealyTask(c context.Context, opt *modtask.ListOptions) (tasks map[int64]*modtask.Task, count int64, hitids, missids []int64, err error) {
return d.rangefuncCluster(c, "delay", opt)
}
// RangePublicTask .
func (d *Dao) RangePublicTask(c context.Context, opt *modtask.ListOptions) (tasks map[int64]*modtask.Task, count int64, hitids, missids []int64, err error) {
return d.rangefuncCluster(c, "public", opt)
}
// PushPersonalTask 放入本人任务池
func (d *Dao) PushPersonalTask(c context.Context, opt *common.BaseOptions, ids ...interface{}) (err error) {
key := personalKey(opt.BusinessID, opt.FlowID, opt.UID)
return d.pushList(c, key, ids...)
}
// RemovePersonalTask 任务延迟或完成
func (d *Dao) RemovePersonalTask(c context.Context, opt *common.BaseOptions, ids ...interface{}) (err error) {
key := personalKey(opt.BusinessID, opt.FlowID, opt.UID)
return d.removeList(c, key, ids...)
}
// RemoveDelayTask 延迟任务完成
func (d *Dao) RemoveDelayTask(c context.Context, opt *common.BaseOptions, ids ...interface{}) (err error) {
key := delayKey(opt.BusinessID, opt.FlowID, opt.UID)
return d.removeList(c, key, ids...)
}
func (d *Dao) removeList(c context.Context, key string, ids ...interface{}) (err error) {
conn := d.cluster.Get(c)
defer conn.Close()
for _, id := range ids {
if err = conn.Send("LREM", key, 1, id); err != nil {
log.Error("LREM error(%v)", errors.WithStack(err))
continue
}
}
if err = conn.Flush(); err != nil {
log.Error("Flush error(%v)", errors.WithStack(err))
return
}
for i := 0; i < len(ids); i++ {
if _, err = conn.Receive(); err != nil {
log.Error("Receive error(%v)", errors.WithStack(err))
return
}
}
return
}
// Release 清空个人任务 直接删除key
func (d *Dao) Release(c context.Context, opt *common.BaseOptions, delay bool) (err error) {
var conn = d.cluster.Get(c)
defer conn.Close()
key := personalKey(opt.BusinessID, opt.FlowID, opt.UID)
log.Info("Redis Release(%+v) delay(%v)", opt, delay)
if delay {
debug := func(msg string) {
tasks, count, hitids, missids, err1 := d.rangefuncCluster(c, "personal", &modtask.ListOptions{
BaseOptions: *opt,
Pager: common.Pager{
Pn: 1,
Ps: 10,
},
})
for id, task := range tasks {
log.Info(msg+" Release task(%d)(%+v)", id, task)
}
log.Info(msg+" Release count(%d)", count)
log.Info(msg+" Release hitids(%+v)", hitids)
log.Info(msg+" Release missids(%+v)", missids)
log.Info(msg+" Release err(%+v)", err1)
}
debug("Before")
if _, err = conn.Do("LTRIM", key, 0, 0); err != nil {
log.Error("LTRIM ReleasePersonalTask(%s), error(%v)", key, err)
}
debug("Middle")
time.AfterFunc(5*time.Minute, func() {
d.Release(context.Background(), opt, false)
})
debug("After")
} else {
log.Info("Redis DEL Release(%+v) delay(%v)", opt, delay)
if _, err = conn.Do("DEL", key); err != nil {
log.Error("DEL ReleasePersonalTask(%s), error(%v)", key, err)
}
}
return
}
// PushDelayTask 延迟任务队列
func (d *Dao) PushDelayTask(c context.Context, opt *common.BaseOptions, ids ...interface{}) (err error) {
key := delayKey(opt.BusinessID, opt.FlowID, opt.UID)
return d.pushList(c, key, ids...)
}
func (d *Dao) pushList(c context.Context, key string, values ...interface{}) (err error) {
var (
conn = d.cluster.Get(c)
)
defer conn.Close()
for _, id := range values {
if _, err = conn.Do("LREM", key, 0, id); err != nil {
log.Error("conn.Do(LREM, %v, %v, %v) error(%v)", key, 0, id, err)
return
}
}
args2 := []interface{}{key}
args2 = append(args2, values...)
if _, err = conn.Do("RPUSH", args2...); err != nil {
log.Error("conn.Do(RPUSH, %v) error(%v)", args2, err)
return
}
return
}
// RemovePublicTask 移除
func (d *Dao) RemovePublicTask(c context.Context, opt *common.BaseOptions, ids ...interface{}) (err error) {
conn := d.cluster.Get(c)
defer conn.Close()
key := publicKey(opt.BusinessID, opt.FlowID)
args := []interface{}{key}
nids := []interface{}{}
for _, id := range ids {
nids = append(nids, fmt.Sprintf("%.11d", id))
}
args = append(args, nids...)
if _, err = conn.Do("ZREM", args...); err != nil {
log.Error("(ZREM,%v) error(%v)", args, errors.WithStack(err))
}
return err
}
// PopPublicTask 从实时任务池取出来
func (d *Dao) PopPublicTask(c context.Context, businessID, flowID, count int64) (ids []int64, err error) {
conn := d.cluster.Get(c)
defer conn.Close()
key := publicKey(businessID, flowID)
var tempids []int64
if tempids, err = redis.Int64s(conn.Do("ZRANGE", key, 0, count)); err != nil {
log.Error("conn.Do(ZADD,%s) error(%v)", key, errors.WithStack(err))
}
ids = append(ids, tempids...)
return
}
// PushPublicTask 放入实时任务池
func (d *Dao) PushPublicTask(c context.Context, tasks ...*modtask.Task) (err error) {
conn := d.cluster.Get(c)
defer conn.Close()
for _, task := range tasks {
key := publicKey(task.BusinessID, task.FlowID)
id := formatID(task.ID)
fmt.Println("id:", id)
if _, err = conn.Do("ZADD", key, -task.Weight, id); err != nil {
log.Error("conn.Do(ZADD,%s) error(%v)", key, errors.WithStack(err))
}
}
return
}
// SetTask .
func (d *Dao) SetTask(c context.Context, tasks ...*modtask.Task) (err error) {
conn := d.cluster.Get(c)
defer conn.Close()
for _, task := range tasks {
var bs []byte
key := haskKey(task.ID)
if bs, err = json.Marshal(task); err != nil {
log.Error("json.Marshal(%+v) error(%v)", task, err)
continue
}
if err = conn.Send("SET", key, bs); err != nil {
log.Error("SET error(%v)", err)
continue
}
if err = conn.Send("EXPIRE", key, _hashexpire); err != nil {
log.Error("EXPIRE error(%v)", err)
continue
}
}
if err = conn.Flush(); err != nil {
log.Error("conn.Flush error(%v)", err)
return
}
for i := 0; i < 2*len(tasks); i++ {
if _, err = conn.Receive(); err != nil {
log.Error("conn.Receive error(%v)", err)
return
}
}
return
}
// GetTask .
func (d *Dao) GetTask(c context.Context, ids []int64) (tasks []*modtask.Task, err error) {
conn := d.cluster.Get(c)
defer conn.Close()
for _, id := range ids {
key := haskKey(id)
conn.Send("GET", key)
}
conn.Flush()
var data []byte
for i := 0; i < len(ids); i++ {
if data, err = redis.Bytes(conn.Receive()); err != nil {
log.Errorv(c, log.KV("event", "redis_get"), log.KV("key", haskKey(ids[i])), log.KV("error", err))
return
}
task := new(modtask.Task)
if err = json.Unmarshal(data, task); err != nil {
log.Errorv(c, log.KV("event", "json.Unmarshal"), log.KV("task", string(data)), log.KV("error", err))
return
}
tasks = append(tasks, task)
}
return
}

View File

@@ -0,0 +1,329 @@
package redis
import (
"context"
"testing"
"go-common/app/admin/main/aegis/model/common"
modtask "go-common/app/admin/main/aegis/model/task"
"github.com/smartystreets/goconvey/convey"
)
var (
task1 = &modtask.Task{
ID: 1,
BusinessID: 1,
FlowID: 1,
RID: 1,
Gtime: 0,
Weight: 10,
}
task2 = &modtask.Task{
ID: 2,
BusinessID: 1,
FlowID: 1,
RID: 2,
Gtime: 0,
Weight: 8,
}
task3 = &modtask.Task{
ID: 3,
BusinessID: 1,
FlowID: 1,
RID: 3,
Gtime: 0,
Weight: 8,
}
)
func TestRedisSetTask(t *testing.T) {
convey.Convey("SetTask", t, func(ctx convey.C) {
var (
c = context.Background()
)
ctx.Convey("When everything goes positive", func(ctx convey.C) {
err := d.SetTask(c, task1, task2, task3)
ctx.Convey("Then err should be nil.", func(ctx convey.C) {
ctx.So(err, convey.ShouldBeNil)
})
})
})
}
func TestRedisPushPublicTask(t *testing.T) {
convey.Convey("PushPublicTask", t, func(ctx convey.C) {
var (
c = context.Background()
)
ctx.Convey("When everything goes positive", func(ctx convey.C) {
err := d.PushPublicTask(c, task1, task2, task3)
ctx.Convey("Then err should be nil.", func(ctx convey.C) {
ctx.So(err, convey.ShouldBeNil)
})
})
})
}
func TestRedisRemovePublicTask(t *testing.T) {
convey.Convey("RemovePublicTask", t, func(ctx convey.C) {
var (
c = context.Background()
opt = &common.BaseOptions{
BusinessID: 1,
FlowID: 1,
}
)
ctx.Convey("When everything goes positive", func(ctx convey.C) {
err := d.RemovePublicTask(c, opt, 1, 2, 3)
ctx.Convey("Then err should be nil.", func(ctx convey.C) {
ctx.So(err, convey.ShouldBeNil)
})
})
})
}
func TestRedisPushPersonalTask(t *testing.T) {
convey.Convey("PushPersonalTask", t, func(ctx convey.C) {
var (
c = context.Background()
opt = &common.BaseOptions{
BusinessID: 1,
FlowID: 1,
UID: 1,
}
)
ctx.Convey("When everything goes positive", func(ctx convey.C) {
err := d.PushPersonalTask(c, opt, 1, 2, 3)
ctx.Convey("Then err should be nil.", func(ctx convey.C) {
ctx.So(err, convey.ShouldBeNil)
})
})
})
}
func TestRedisCountPersonalTask(t *testing.T) {
convey.Convey("CountPersonalTask", t, func(ctx convey.C) {
var (
c = context.Background()
opt = &common.BaseOptions{
BusinessID: 1,
FlowID: 1,
UID: 1,
}
)
ctx.Convey("When everything goes positive", func(ctx convey.C) {
_, err := d.CountPersonalTask(c, opt)
ctx.Convey("Then err should be nil.count should not be nil.", func(ctx convey.C) {
ctx.So(err, convey.ShouldBeNil)
})
})
})
}
func TestRedisRangePersonalTask(t *testing.T) {
convey.Convey("RangePersonalTask", t, func(ctx convey.C) {
var (
c = context.Background()
opt = &modtask.ListOptions{
BaseOptions: common.BaseOptions{
BusinessID: 1,
FlowID: 1,
UID: 1},
Pager: common.Pager{
Pn: 1,
Ps: 20,
},
}
)
ctx.Convey("When everything goes positive", func(ctx convey.C) {
_, _, _, _, err := d.RangePersonalTask(c, opt)
ctx.Convey("Then err should be nil.", func(ctx convey.C) {
ctx.So(err, convey.ShouldBeNil)
})
})
})
}
func TestRedisRemovePersonalTask(t *testing.T) {
convey.Convey("RemovePersonalTask", t, func(ctx convey.C) {
var (
c = context.Background()
opt = &common.BaseOptions{
BusinessID: 1,
FlowID: 1,
UID: 1,
}
)
ctx.Convey("When everything goes positive", func(ctx convey.C) {
err := d.RemovePersonalTask(c, opt, 1, 2, 3)
ctx.Convey("Then err should be nil.", func(ctx convey.C) {
ctx.So(err, convey.ShouldBeNil)
})
})
})
}
func TestRedisPushDelayTask(t *testing.T) {
convey.Convey("PushDelayTask", t, func(ctx convey.C) {
var (
c = context.Background()
opt = &common.BaseOptions{
BusinessID: 1,
FlowID: 1,
UID: 1,
}
)
ctx.Convey("When everything goes positive", func(ctx convey.C) {
err := d.PushDelayTask(c, opt, 1, 2, 3)
ctx.Convey("Then err should be nil.", func(ctx convey.C) {
ctx.So(err, convey.ShouldBeNil)
})
})
})
}
func TestRedisRangeDealyTask(t *testing.T) {
convey.Convey("RangeDealyTask", t, func(ctx convey.C) {
var (
c = context.Background()
opt = &modtask.ListOptions{
BaseOptions: common.BaseOptions{
BusinessID: 1,
FlowID: 1,
UID: 1},
Pager: common.Pager{
Pn: 1,
Ps: 20,
},
}
)
ctx.Convey("When everything goes positive", func(ctx convey.C) {
tasks, count, hitids, _, err := d.RangeDealyTask(c, opt)
ctx.Convey("Then err should be nil.tasks,count,hitids,missids should not be nil.", func(ctx convey.C) {
ctx.So(err, convey.ShouldBeNil)
ctx.So(hitids, convey.ShouldNotBeNil)
ctx.So(count, convey.ShouldNotBeNil)
ctx.So(tasks, convey.ShouldNotBeNil)
})
})
})
}
func TestRedisRelease(t *testing.T) {
convey.Convey("Release", t, func(ctx convey.C) {
var (
c = context.Background()
opt = &common.BaseOptions{
BusinessID: 1,
FlowID: 1,
UID: 1,
}
)
ctx.Convey("When everything goes positive", func(ctx convey.C) {
err := d.Release(c, opt, true)
ctx.Convey("Then err should be nil.", func(ctx convey.C) {
ctx.So(err, convey.ShouldBeNil)
})
})
})
}
func TestRedisrangefunc(t *testing.T) {
convey.Convey("rangefunc", t, func(ctx convey.C) {
var (
c = context.Background()
opt = &modtask.ListOptions{
BaseOptions: common.BaseOptions{
BusinessID: 1,
FlowID: 1,
UID: 1},
Pager: common.Pager{
Pn: 1,
Ps: 20,
},
}
)
ctx.Convey("When everything goes positive", func(ctx convey.C) {
_, _, _, _, err := d.rangefuncCluster(c, "public", opt)
ctx.Convey("Then err should be nil.", func(ctx convey.C) {
ctx.So(err, convey.ShouldBeNil)
})
})
})
}
func TestRedisSeize(t *testing.T) {
convey.Convey("SeizeTask", t, func(ctx convey.C) {
var (
c = context.Background()
)
ctx.Convey("When everything goes positive", func(ctx convey.C) {
_, _, _, err := d.SeizeTask(c, 1, 1, 1, 10)
ctx.Convey("Then err should be nil.tasks,count,hitids,missids should not be nil.", func(ctx convey.C) {
ctx.So(err, convey.ShouldBeNil)
})
})
})
}
func TestRedisRemoveDelayTask(t *testing.T) {
convey.Convey("RemoveDelayTask", t, func(ctx convey.C) {
var (
c = context.Background()
opt = &common.BaseOptions{}
ids = interface{}(0)
)
ctx.Convey("When everything goes positive", func(ctx convey.C) {
err := d.RemoveDelayTask(c, opt, ids)
ctx.Convey("Then err should be nil.", func(ctx convey.C) {
ctx.So(err, convey.ShouldBeNil)
})
})
})
}
func TestRedispushList(t *testing.T) {
convey.Convey("pushList", t, func(ctx convey.C) {
var (
c = context.Background()
key = ""
values = int64(0)
)
ctx.Convey("When everything goes positive", func(ctx convey.C) {
err := d.pushList(c, key, values)
ctx.Convey("Then err should be nil.", func(ctx convey.C) {
ctx.So(err, convey.ShouldBeNil)
})
})
})
}
func TestRedisremoveList(t *testing.T) {
convey.Convey("removeList", t, func(ctx convey.C) {
var (
c = context.Background()
key = ""
ids = interface{}(0)
)
ctx.Convey("When everything goes positive", func(ctx convey.C) {
err := d.removeList(c, key, ids)
ctx.Convey("Then err should be nil.", func(ctx convey.C) {
ctx.So(err, convey.ShouldBeNil)
})
})
})
}
func TestRedisGetTask(t *testing.T) {
convey.Convey("GetTask", t, func(ctx convey.C) {
ctx.Convey("When everything goes positive", func(ctx convey.C) {
_, err := d.GetTask(cntx, []int64{1, 2, 3})
ctx.Convey("Then err should be nil.", func(ctx convey.C) {
ctx.So(err, convey.ShouldBeNil)
})
})
})
}

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",
"task_test.go",
],
embed = [":go_default_library"],
rundir = ".",
tags = ["automanaged"],
deps = [
"//app/admin/main/aegis/conf:go_default_library",
"//app/service/main/account/api:go_default_library",
"//app/service/main/relation/model:go_default_library",
"//app/service/main/up/api/v1:go_default_library",
"//vendor/github.com/golang/mock/gomock:go_default_library",
"//vendor/github.com/smartystreets/goconvey/convey:go_default_library",
],
)
go_library(
name = "go_default_library",
srcs = [
"dao.go",
"rpc_mock.go",
"task.go",
],
importpath = "go-common/app/admin/main/aegis/dao/rpc",
tags = ["automanaged"],
visibility = ["//visibility:public"],
deps = [
"//app/admin/main/aegis/conf:go_default_library",
"//app/admin/main/aegis/model:go_default_library",
"//app/service/main/account/api:go_default_library",
"//app/service/main/relation/model:go_default_library",
"//app/service/main/relation/rpc/client:go_default_library",
"//app/service/main/up/api/v1:go_default_library",
"//library/log:go_default_library",
"//library/net/metadata:go_default_library",
"//vendor/github.com/golang/mock/gomock:go_default_library",
"//vendor/github.com/pkg/errors:go_default_library",
"@org_golang_google_grpc//: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 rpc
import (
"context"
"go-common/app/admin/main/aegis/conf"
account "go-common/app/service/main/account/api"
relmod "go-common/app/service/main/relation/model"
relrpc "go-common/app/service/main/relation/rpc/client"
uprpc "go-common/app/service/main/up/api/v1"
"google.golang.org/grpc"
)
// Dao dao
type Dao struct {
c *conf.Config
//gorpc
relRPC RelationRPC
//grpc
AccountClient AccRPC
UpClient UpRPC
}
// New init mysql db
func New(c *conf.Config) (dao *Dao) {
dao = &Dao{
c: c,
}
if c.Debug != "local" {
dao.relRPC = relrpc.New(c.RPC.Rel)
var err error
if dao.AccountClient, err = account.NewClient(c.GRPC.AccRPC); err != nil {
panic(err)
}
if dao.UpClient, err = uprpc.NewClient(c.GRPC.UpRPC); err != nil {
panic(err)
}
}
return
}
// Close close the resource.
func (d *Dao) Close() {
}
// Ping dao ping
func (d *Dao) Ping(c context.Context) error {
return nil
}
//RelationRPC .
type RelationRPC interface {
Stats(c context.Context, arg *relmod.ArgMids) (res map[int64]*relmod.Stat, err error)
}
//AccRPC .
type AccRPC interface {
Info3(ctx context.Context, in *account.MidReq, opts ...grpc.CallOption) (*account.InfoReply, error)
Cards3(ctx context.Context, in *account.MidsReq, opts ...grpc.CallOption) (*account.CardsReply, error)
ProfileWithStat3(ctx context.Context, in *account.MidReq, opts ...grpc.CallOption) (*account.ProfileStatReply, error)
}
//UpRPC .
type UpRPC interface {
UpSpecial(ctx context.Context, in *uprpc.UpSpecialReq, opts ...grpc.CallOption) (*uprpc.UpSpecialReply, error)
UpsSpecial(ctx context.Context, in *uprpc.UpsSpecialReq, opts ...grpc.CallOption) (*uprpc.UpsSpecialReply, error)
UpGroups(ctx context.Context, in *uprpc.NoArgReq, opts ...grpc.CallOption) (*uprpc.UpGroupsReply, error)
}

View File

@@ -0,0 +1,132 @@
package rpc
import (
"context"
"flag"
"fmt"
"os"
"testing"
"go-common/app/admin/main/aegis/conf"
api "go-common/app/service/main/account/api"
relmod "go-common/app/service/main/relation/model"
uprpc "go-common/app/service/main/up/api/v1"
"github.com/golang/mock/gomock"
)
var (
d *Dao
cntx context.Context
)
func TestMain(m *testing.M) {
if os.Getenv("DEPLOY_ENV") != "" {
flag.Set("app_id", "main.archive.aegis-admin")
flag.Set("conf_token", "cad913269be022e1eb8c45a8d5408d78")
flag.Set("tree_id", "60977")
flag.Set("conf_version", "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/aegis-admin.toml")
}
flag.Parse()
if err := conf.Init(); err != nil {
panic(fmt.Sprintf("conf.Init() error(%v)", err))
}
d = New(conf.Conf)
cntx = context.TODO()
os.Exit(m.Run())
}
var (
_Mid = int64(0)
_Mids = []int64{0, 1, 2}
)
func WithDao(t *testing.T, f func(d *Dao)) func() {
return func() {
mockCtrl := gomock.NewController(t)
accMock := NewMockAccRPC(mockCtrl)
d.AccountClient = accMock
accMock.EXPECT().Cards3(gomock.Any(), &api.MidsReq{Mids: _Mids}).Return(&api.CardsReply{Cards: map[int64]*api.Card{
10086: {
Mid: _Mid,
},
}}, nil).AnyTimes()
relMock := NewMockRelationRPC(mockCtrl)
d.relRPC = relMock
relMock.EXPECT().Stats(gomock.Any(), &relmod.ArgMids{Mids: _Mids}).Return(map[int64]*relmod.Stat{
10086: {
Mid: 10086,
},
}, nil)
f(d)
mockCtrl.Finish()
}
}
func WithMockAccount(t *testing.T, f func(d *Dao)) func() {
return func() {
mockCtrl := gomock.NewController(t)
defer mockCtrl.Finish()
accMock := NewMockAccRPC(mockCtrl)
d.AccountClient = accMock
accMock.EXPECT().Info3(gomock.Any(), &api.MidReq{Mid: _Mid}).Return(&api.InfoReply{Info: &api.Info{
Mid: 10086,
}}, nil).AnyTimes()
accMock.EXPECT().Cards3(gomock.Any(), &api.MidsReq{Mids: _Mids}).Return(&api.CardsReply{Cards: map[int64]*api.Card{
10086: {
Mid: _Mid,
},
}}, nil).AnyTimes()
accMock.EXPECT().ProfileWithStat3(gomock.Any(), &api.MidReq{Mid: _Mid}).Return(&api.ProfileStatReply{
Profile: &api.Profile{
Mid: _Mid,
},
}, nil).AnyTimes()
f(d)
}
}
func WithMockRelation(t *testing.T, f func(d *Dao)) func() {
return func() {
mockCtrl := gomock.NewController(t)
defer mockCtrl.Finish()
relMock := NewMockRelationRPC(mockCtrl)
d.relRPC = relMock
relMock.EXPECT().Stats(gomock.Any(), &relmod.ArgMids{Mids: _Mids}).Return(map[int64]*relmod.Stat{
10086: {
Mid: 10086,
},
}, nil)
f(d)
}
}
func WithMockUp(t *testing.T, f func(d *Dao)) func() {
return func() {
upspecial := &uprpc.UpSpecial{GroupIDs: []int64{1}}
upspecialreply := &uprpc.UpSpecialReply{UpSpecial: upspecial}
upspecialsreply := &uprpc.UpsSpecialReply{UpSpecials: map[int64]*uprpc.UpSpecial{0: upspecial}}
upgroupsreply := &uprpc.UpGroupsReply{UpGroups: map[int64]*uprpc.UpGroup{0: {ID: 0}}}
mockCtrl := gomock.NewController(t)
defer mockCtrl.Finish()
upMock := NewMockUpRPC(mockCtrl)
d.UpClient = upMock
upMock.EXPECT().UpSpecial(gomock.Any(), &uprpc.UpSpecialReq{Mid: _Mid}).Return(upspecialreply, nil)
upMock.EXPECT().UpsSpecial(gomock.Any(), &uprpc.UpsSpecialReq{Mids: _Mids}).Return(upspecialsreply, nil)
upMock.EXPECT().UpGroups(gomock.Any(), &uprpc.NoArgReq{}).Return(upgroupsreply, nil)
f(d)
}
}

View File

@@ -0,0 +1,207 @@
// Code generated by MockGen. DO NOT EDIT.
// Source: /Users/danbeiti/go/src/go-common/app/admin/main/aegis/dao/rpc/dao.go
// Package mock is a generated GoMock package.
package rpc
import (
context "context"
reflect "reflect"
api "go-common/app/service/main/account/api"
model "go-common/app/service/main/relation/model"
v1 "go-common/app/service/main/up/api/v1"
gomock "github.com/golang/mock/gomock"
grpc "google.golang.org/grpc"
)
// MockRelationRPC is a mock of RelationRPC interface
type MockRelationRPC struct {
ctrl *gomock.Controller
recorder *MockRelationRPCMockRecorder
}
// MockRelationRPCMockRecorder is the mock recorder for MockRelationRPC
type MockRelationRPCMockRecorder struct {
mock *MockRelationRPC
}
// NewMockRelationRPC creates a new mock instance
func NewMockRelationRPC(ctrl *gomock.Controller) *MockRelationRPC {
mock := &MockRelationRPC{ctrl: ctrl}
mock.recorder = &MockRelationRPCMockRecorder{mock}
return mock
}
// EXPECT returns an object that allows the caller to indicate expected use
func (m *MockRelationRPC) EXPECT() *MockRelationRPCMockRecorder {
return m.recorder
}
// Stats mocks base method
func (m *MockRelationRPC) Stats(c context.Context, arg *model.ArgMids) (map[int64]*model.Stat, error) {
ret := m.ctrl.Call(m, "Stats", c, arg)
ret0, _ := ret[0].(map[int64]*model.Stat)
ret1, _ := ret[1].(error)
return ret0, ret1
}
// Stats indicates an expected call of Stats
func (mr *MockRelationRPCMockRecorder) Stats(c, arg interface{}) *gomock.Call {
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "Stats", reflect.TypeOf((*MockRelationRPC)(nil).Stats), c, arg)
}
// MockAccRPC is a mock of AccRPC interface
type MockAccRPC struct {
ctrl *gomock.Controller
recorder *MockAccRPCMockRecorder
}
// MockAccRPCMockRecorder is the mock recorder for MockAccRPC
type MockAccRPCMockRecorder struct {
mock *MockAccRPC
}
// NewMockAccRPC creates a new mock instance
func NewMockAccRPC(ctrl *gomock.Controller) *MockAccRPC {
mock := &MockAccRPC{ctrl: ctrl}
mock.recorder = &MockAccRPCMockRecorder{mock}
return mock
}
// EXPECT returns an object that allows the caller to indicate expected use
func (m *MockAccRPC) EXPECT() *MockAccRPCMockRecorder {
return m.recorder
}
// Info3 mocks base method
func (m *MockAccRPC) Info3(ctx context.Context, in *api.MidReq, opts ...grpc.CallOption) (*api.InfoReply, error) {
varargs := []interface{}{ctx, in}
for _, a := range opts {
varargs = append(varargs, a)
}
ret := m.ctrl.Call(m, "Info3", varargs...)
ret0, _ := ret[0].(*api.InfoReply)
ret1, _ := ret[1].(error)
return ret0, ret1
}
// Info3 indicates an expected call of Info3
func (mr *MockAccRPCMockRecorder) Info3(ctx, in interface{}, opts ...interface{}) *gomock.Call {
varargs := append([]interface{}{ctx, in}, opts...)
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "Info3", reflect.TypeOf((*MockAccRPC)(nil).Info3), varargs...)
}
// Cards3 mocks base method
func (m *MockAccRPC) Cards3(ctx context.Context, in *api.MidsReq, opts ...grpc.CallOption) (*api.CardsReply, error) {
varargs := []interface{}{ctx, in}
for _, a := range opts {
varargs = append(varargs, a)
}
ret := m.ctrl.Call(m, "Cards3", varargs...)
ret0, _ := ret[0].(*api.CardsReply)
ret1, _ := ret[1].(error)
return ret0, ret1
}
// Cards3 indicates an expected call of Cards3
func (mr *MockAccRPCMockRecorder) Cards3(ctx, in interface{}, opts ...interface{}) *gomock.Call {
varargs := append([]interface{}{ctx, in}, opts...)
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "Cards3", reflect.TypeOf((*MockAccRPC)(nil).Cards3), varargs...)
}
// ProfileWithStat3 mocks base method
func (m *MockAccRPC) ProfileWithStat3(ctx context.Context, in *api.MidReq, opts ...grpc.CallOption) (*api.ProfileStatReply, error) {
varargs := []interface{}{ctx, in}
for _, a := range opts {
varargs = append(varargs, a)
}
ret := m.ctrl.Call(m, "ProfileWithStat3", varargs...)
ret0, _ := ret[0].(*api.ProfileStatReply)
ret1, _ := ret[1].(error)
return ret0, ret1
}
// ProfileWithStat3 indicates an expected call of ProfileWithStat3
func (mr *MockAccRPCMockRecorder) ProfileWithStat3(ctx, in interface{}, opts ...interface{}) *gomock.Call {
varargs := append([]interface{}{ctx, in}, opts...)
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "ProfileWithStat3", reflect.TypeOf((*MockAccRPC)(nil).ProfileWithStat3), varargs...)
}
// MockUpRPC is a mock of UpRPC interface
type MockUpRPC struct {
ctrl *gomock.Controller
recorder *MockUpRPCMockRecorder
}
// MockUpRPCMockRecorder is the mock recorder for MockUpRPC
type MockUpRPCMockRecorder struct {
mock *MockUpRPC
}
// NewMockUpRPC creates a new mock instance
func NewMockUpRPC(ctrl *gomock.Controller) *MockUpRPC {
mock := &MockUpRPC{ctrl: ctrl}
mock.recorder = &MockUpRPCMockRecorder{mock}
return mock
}
// EXPECT returns an object that allows the caller to indicate expected use
func (m *MockUpRPC) EXPECT() *MockUpRPCMockRecorder {
return m.recorder
}
// UpSpecial mocks base method
func (m *MockUpRPC) UpSpecial(ctx context.Context, in *v1.UpSpecialReq, opts ...grpc.CallOption) (*v1.UpSpecialReply, error) {
varargs := []interface{}{ctx, in}
for _, a := range opts {
varargs = append(varargs, a)
}
ret := m.ctrl.Call(m, "UpSpecial", varargs...)
ret0, _ := ret[0].(*v1.UpSpecialReply)
ret1, _ := ret[1].(error)
return ret0, ret1
}
// UpSpecial indicates an expected call of UpSpecial
func (mr *MockUpRPCMockRecorder) UpSpecial(ctx, in interface{}, opts ...interface{}) *gomock.Call {
varargs := append([]interface{}{ctx, in}, opts...)
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "UpSpecial", reflect.TypeOf((*MockUpRPC)(nil).UpSpecial), varargs...)
}
// UpsSpecial mocks base method
func (m *MockUpRPC) UpsSpecial(ctx context.Context, in *v1.UpsSpecialReq, opts ...grpc.CallOption) (*v1.UpsSpecialReply, error) {
varargs := []interface{}{ctx, in}
for _, a := range opts {
varargs = append(varargs, a)
}
ret := m.ctrl.Call(m, "UpsSpecial", varargs...)
ret0, _ := ret[0].(*v1.UpsSpecialReply)
ret1, _ := ret[1].(error)
return ret0, ret1
}
// UpsSpecial indicates an expected call of UpsSpecial
func (mr *MockUpRPCMockRecorder) UpsSpecial(ctx, in interface{}, opts ...interface{}) *gomock.Call {
varargs := append([]interface{}{ctx, in}, opts...)
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "UpsSpecial", reflect.TypeOf((*MockUpRPC)(nil).UpsSpecial), varargs...)
}
// UpGroups mocks base method
func (m *MockUpRPC) UpGroups(ctx context.Context, in *v1.NoArgReq, opts ...grpc.CallOption) (*v1.UpGroupsReply, error) {
varargs := []interface{}{ctx, in}
for _, a := range opts {
varargs = append(varargs, a)
}
ret := m.ctrl.Call(m, "UpGroups", varargs...)
ret0, _ := ret[0].(*v1.UpGroupsReply)
ret1, _ := ret[1].(error)
return ret0, ret1
}
// UpGroups indicates an expected call of UpGroups
func (mr *MockUpRPCMockRecorder) UpGroups(ctx, in interface{}, opts ...interface{}) *gomock.Call {
varargs := append([]interface{}{ctx, in}, opts...)
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "UpGroups", reflect.TypeOf((*MockUpRPC)(nil).UpGroups), varargs...)
}

View File

@@ -0,0 +1,181 @@
package rpc
import (
"context"
"errors"
"go-common/app/admin/main/aegis/model"
acc "go-common/app/service/main/account/api"
relmod "go-common/app/service/main/relation/model"
uprpc "go-common/app/service/main/up/api/v1"
"go-common/library/log"
"go-common/library/net/metadata"
terrors "github.com/pkg/errors"
)
//ERROR
var (
ErrEmptyReply = errors.New("rpc empty reply")
)
// FansCount 粉丝数
func (d *Dao) FansCount(c context.Context, mids []int64) (fans map[int64]int64, err error) {
arg := &relmod.ArgMids{Mids: mids}
stats, err := d.relRPC.Stats(c, arg)
if err != nil {
log.Error("FansCount error(%v)", terrors.WithStack(err))
return
}
fans = make(map[int64]int64)
for mid, item := range stats {
fans[mid] = item.Follower
}
log.Info("FansCount fans(%+v)", fans)
return
}
// UserInfos 提供给资源列表批量查
func (d *Dao) UserInfos(c context.Context, mids []int64) (res map[int64]*model.UserInfo, err error) {
arg1 := &relmod.ArgMids{Mids: mids}
stats, err := d.relRPC.Stats(c, arg1)
if err != nil {
log.Error("Stats error(%v)", terrors.WithStack(err))
return
}
midsReq := &acc.MidsReq{
Mids: mids,
RealIp: metadata.String(c, metadata.RemoteIP),
}
cardsreply, err := d.AccountClient.Cards3(c, midsReq)
if err != nil {
log.Error("Cards3(%+v) error(%v)", mids, terrors.WithStack(err))
return
}
if cardsreply == nil {
err = ErrEmptyReply
log.Error("Cards3(%+v) error(%v)", mids, terrors.WithStack(err))
return
}
cards := cardsreply.Cards
res = make(map[int64]*model.UserInfo)
for _, mid := range mids {
userinfo := &model.UserInfo{Mid: mid}
if card, ok := cards[mid]; ok {
userinfo.Name = card.Name
userinfo.Official = card.Official
}
if stat, ok := stats[mid]; ok {
userinfo.Follower = stat.Follower
}
res[mid] = userinfo
}
return
}
// Profile get account.
func (d *Dao) Profile(c context.Context, mid int64) (userinfo *model.UserInfo, err error) {
if mid <= 0 {
return
}
midReq := &acc.MidReq{
Mid: mid,
RealIp: metadata.String(c, metadata.RemoteIP),
}
res, err := d.AccountClient.ProfileWithStat3(c, midReq)
if err != nil {
log.Error("d.acc.ProfileWithStat3() error(%v) arg(%+v)", err, midReq)
}
if res == nil {
err = ErrEmptyReply
log.Error("ProfileWithStat3(%+v) error(%v)", mid, terrors.WithStack(err))
return
}
userinfo = &model.UserInfo{
Mid: mid,
Follower: res.Follower,
}
if res.Profile != nil {
userinfo.Official = res.Profile.Official
userinfo.Name = res.Profile.Name
}
return
}
// Info3 get Name.
func (d *Dao) Info3(c context.Context, mid int64) (res *acc.Info, err error) {
midReq := &acc.MidReq{
Mid: mid,
RealIp: metadata.String(c, metadata.RemoteIP),
}
info, err := d.AccountClient.Info3(c, midReq)
if err != nil {
log.Error("query info3 failed,mid(%v), err(%v)", mid, err)
return
}
if info == nil {
err = ErrEmptyReply
log.Error("Info3(%+v) error(%v)", mid, terrors.WithStack(err))
return
}
res = info.Info
log.Info("getUserInfo userbase (%v)", res)
return
}
// UpSpecial 分组信息
func (d *Dao) UpSpecial(c context.Context, mid int64) (ups *uprpc.UpSpecial, err error) {
midReq := &uprpc.UpSpecialReq{
Mid: mid,
}
var reply *uprpc.UpSpecialReply
if reply, err = d.UpClient.UpSpecial(c, midReq); err != nil {
log.Error("UpSpecial(%d) error(%v)", mid, terrors.WithStack(err))
return
}
if reply == nil {
err = ErrEmptyReply
log.Error("UpSpecial(%+v) error(%v)", mid, terrors.WithStack(err))
return
}
ups = reply.UpSpecial
return
}
//UpsSpecial 分组信息
func (d *Dao) UpsSpecial(c context.Context, mids []int64) (ups map[int64]*uprpc.UpSpecial, err error) {
midReq := &uprpc.UpsSpecialReq{
Mids: mids,
}
var reply *uprpc.UpsSpecialReply
if reply, err = d.UpClient.UpsSpecial(c, midReq); err != nil {
log.Error("UpsSpecial(%d) error(%v)", mids, terrors.WithStack(err))
return
}
if reply == nil {
err = ErrEmptyReply
log.Error("UpsSpecial(%+v) error(%v)", mids, terrors.WithStack(err))
return
}
ups = reply.UpSpecials
return
}
//UpGroups 所有分组
func (d *Dao) UpGroups(c context.Context) (upgs map[int64]*uprpc.UpGroup, err error) {
noReq := &uprpc.NoArgReq{}
var reply *uprpc.UpGroupsReply
if reply, err = d.UpClient.UpGroups(c, noReq); err != nil {
log.Error("UpGroups error(%v)", terrors.WithStack(err))
return
}
if reply == nil {
err = ErrEmptyReply
log.Error("UpGroups error(%v)", terrors.WithStack(err))
return
}
upgs = reply.UpGroups
return
}

View File

@@ -0,0 +1,53 @@
package rpc
import (
"context"
"testing"
. "github.com/smartystreets/goconvey/convey"
)
func TestRpcFansCount(t *testing.T) {
Convey("FansCount", t, WithMockRelation(t, func(d *Dao) {
res, err := d.FansCount(context.TODO(), _Mids)
So(err, ShouldBeNil)
So(res, ShouldNotBeNil)
}))
}
func TestRpcUserInfos(t *testing.T) {
Convey("UserInfos", t, WithDao(t, func(d *Dao) {
res, err := d.UserInfos(context.TODO(), _Mids)
So(err, ShouldBeNil)
So(res, ShouldNotBeNil)
}))
}
func TestRpcProfile(t *testing.T) {
Convey("Profile", t, WithMockAccount(t, func(d *Dao) {
res, err := d.Profile(context.TODO(), _Mid)
So(err, ShouldBeNil)
So(res, ShouldBeNil)
}))
}
func TestRpcInfo3(t *testing.T) {
Convey("Info3", t, WithMockAccount(t, func(d *Dao) {
res, err := d.Info3(context.TODO(), _Mid)
So(err, ShouldBeNil)
So(res, ShouldNotBeNil)
}))
}
func TestRpcUpSpecial(t *testing.T) {
Convey("UpSpecial", t, WithMockUp(t, func(d *Dao) {
res1, err := d.UpSpecial(context.TODO(), _Mid)
So(err, ShouldBeNil)
So(res1, ShouldNotBeNil)
res2, err := d.UpsSpecial(context.TODO(), _Mids)
So(err, ShouldBeNil)
So(res2, ShouldNotBeNil)
res3, err := d.UpGroups(context.TODO())
So(err, ShouldBeNil)
So(res3, ShouldNotBeNil)
}))
}

View File

@@ -0,0 +1,67 @@
package(default_visibility = ["//visibility:public"])
load(
"@io_bazel_rules_go//go:def.bzl",
"go_library",
"go_test",
)
go_library(
name = "go_default_library",
srcs = [
"engine.go",
"log.go",
"report.go",
],
importpath = "go-common/app/admin/main/aegis/model",
tags = ["automanaged"],
visibility = ["//visibility:public"],
deps = [
"//app/admin/main/aegis/model/common:go_default_library",
"//app/admin/main/aegis/model/net:go_default_library",
"//app/admin/main/aegis/model/resource:go_default_library",
"//app/admin/main/aegis/model/task:go_default_library",
"//app/service/main/account/api:go_default_library",
"//library/log: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",
"//app/admin/main/aegis/model/business:all-srcs",
"//app/admin/main/aegis/model/common:all-srcs",
"//app/admin/main/aegis/model/databus:all-srcs",
"//app/admin/main/aegis/model/middleware:all-srcs",
"//app/admin/main/aegis/model/monitor:all-srcs",
"//app/admin/main/aegis/model/net:all-srcs",
"//app/admin/main/aegis/model/resource:all-srcs",
"//app/admin/main/aegis/model/svg:all-srcs",
"//app/admin/main/aegis/model/task:all-srcs",
],
tags = ["automanaged"],
visibility = ["//visibility:public"],
)
go_test(
name = "go_default_test",
srcs = ["model_test.go"],
embed = [":go_default_library"],
rundir = ".",
tags = ["automanaged"],
deps = [
"//app/admin/main/aegis/model/common:go_default_library",
"//app/admin/main/aegis/model/resource:go_default_library",
"//library/time:go_default_library",
"//vendor/github.com/smartystreets/goconvey/convey:go_default_library",
],
)

View File

@@ -0,0 +1,38 @@
package(default_visibility = ["//visibility:public"])
load(
"@io_bazel_rules_go//go:def.bzl",
"go_library",
)
go_library(
name = "go_default_library",
srcs = [
"business.go",
"config.go",
],
importpath = "go-common/app/admin/main/aegis/model/business",
tags = ["automanaged"],
visibility = ["//visibility:public"],
deps = [
"//app/admin/main/aegis/model:go_default_library",
"//app/admin/main/aegis/model/common:go_default_library",
"//app/admin/main/aegis/model/middleware:go_default_library",
"//library/log: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,217 @@
package business
import (
"fmt"
"reflect"
"strconv"
"strings"
"go-common/app/admin/main/aegis/model"
"go-common/app/admin/main/aegis/model/common"
"go-common/library/log"
xtime "go-common/library/time"
)
const (
// StateEnable 正常
StateEnable = int8(0)
// StateDisable 删除
StateDisable = int8(1)
// TypeIframe .
TypeIframe = int8(0)
// TypeSubmit 提交接口配置
TypeSubmit = int8(1)
// TypeAction 预留给前端组件配置
TypeAction = int8(2)
// TypeManagerBID 角色配置
TypeManagerBID = int8(3)
// TypeReverse 保留字配置
TypeReverse = int8(4)
// TypeAttribute 属性位配置
TypeAttribute = int8(5)
// TypeDeleteState 删除状态配置
TypeDeleteState = int8(6)
// TypeFiler 敏感词过滤
TypeFiler = int8(7)
// TypeBizBID 业务级别用户角色
TypeBizBID = int8(8)
// TypeAdapter 适配器配置
TypeAdapter = int8(9)
// TypeRscListAdapter 资源列表适配器
TypeRscListAdapter = int8(10)
// 中间件配置,用于前后端交互的自定义数据逻辑处理
TypeMiddleware = int8(11)
// TypeTempCodes 临时错误码
TypeTempCodes = int8(12)
// TypeCallback TODO 提交接口v2版本为了兼容线上的TypeSubmit。待v2上线后再去掉该配置改为TypeSubmit
TypeCallback = int8(13)
// MngBIDMID 任务用户角色: {"manager_id":1, "flow_id":12}
MngBIDMID = "manager_id"
// MngBIDFlow .
MngBIDFlow = "flow_id"
// BizBIDMngID 业务用户角色: {"manager_id":1, "admin":12}
BizBIDMngID = "manager_id"
// BizBIDAdmin .
BizBIDAdmin = "admin"
// AccessBiz .
AccessBiz = "access_biz"
// AccessFlow .
AccessFlow = "access_flow"
)
// Business .
type Business struct {
ID int64 `json:"id" gorm:"primary_key" form:"id"`
TP int64 `json:"type" gorm:"column:type" form:"type"`
Name string `json:"name" gorm:"column:name" form:"name" validate:"max=10"`
Desc string `json:"desc" gorm:"column:desc" form:"desc" validate:"max=160"`
Developer string `json:"developer" gorm:"column:developer" form:"developer"`
UID int64 `json:"uid" gorm:"column:uid"`
Attribute int64 `json:"attribute" gorm:"column:attribute" form:"attribute"`
State int64 `json:"state" gorm:"column:state" form:"state"`
UserName string `json:"username" gorm:"-"`
Ctime xtime.Time `json:"ctime" gorm:"column:ctime"`
Mtime xtime.Time `json:"mtime" gorm:"column:mtime"`
}
// IAdapter .
type IAdapter interface {
AdaptString(val string) string
AdaptInt64(val int64) int64
}
// Adapter 业务适配器
type Adapter struct {
Name string `json:"name"`
Rule string `json:"rule"`
Value string `json:"value"`
Compare string `json:"compare"`
}
// AdaptString .
func (a Adapter) AdaptString(val string) string {
return val
}
// AdaptInt .
func (a Adapter) AdaptInt(val int64) int64 {
switch a.Rule {
case "not":
if strconv.FormatInt(val, 10) != a.Compare {
if v, e := strconv.ParseInt(a.Value, 10, 64); e != nil {
log.Error("AdaptInt strconv.ParseInt(%s)", a.Value)
} else {
val = v
}
}
default:
log.Error("AdaptInt unsupported rule(%s)", a.Rule)
}
return val
}
// AdaptAddOpt ..
func AdaptAddOpt(opt *model.AddOption, adps []*Adapter) {
if len(adps) == 0 || opt == nil {
return
}
log.Info("AdaptAddOpt before opt(%+v)", opt)
v := reflect.ValueOf(opt).Elem()
for _, adp := range adps {
val := v.FieldByName(adp.Name)
if !val.CanSet() {
log.Error("AdaptAddOpt field(%s) can't set", adp.Name)
return
}
switch val.Kind() {
case reflect.String:
val.SetString(adp.AdaptString(val.String()))
case reflect.Int8, reflect.Int64, reflect.Int:
val.SetInt(adp.AdaptInt(val.Int()))
default:
log.Error("AdaptAddOpt unsupported adp(%+v) type(%v)", adp, val.Kind())
}
}
log.Info("AdaptAddOpt after opt(%+v)", opt)
}
// AdaptUpdateOpt ..
func AdaptUpdateOpt(opt *model.UpdateOption, adps []*Adapter) {
if len(adps) == 0 || opt == nil {
return
}
log.Info("AdaptUpdateOpt before opt(%+v)", opt)
for _, adp := range adps {
key := strings.ToLower(adp.Name)
if iv, ok := opt.Update[key]; ok {
switch reflect.TypeOf(iv).Kind() {
case reflect.String:
opt.Update[key] = adp.AdaptString(iv.(string))
case reflect.Int8, reflect.Int64, reflect.Int:
intv, err := strconv.Atoi(fmt.Sprint(iv))
if err != nil {
log.Error("AdaptUpdateOpt unsupported adp(%+v)", adp)
continue
}
opt.Update[key] = adp.AdaptInt(int64(intv))
default:
log.Error("AdaptUpdateOpt unsupported adp(%+v)", adp)
}
}
}
log.Info("AdaptUpdateOpt after opt(%+v)", opt)
}
// TableName .
func (t *Business) TableName() string {
return "business"
}
// OptList .
type OptList struct {
common.Pager
TP int8 `form:"type"`
}
// ListBusiness .
type ListBusiness struct {
common.Pager
Business []*Business `json:"business"`
}
// BizItem .
type BizItem struct {
BizID int64 `json:"business_id"`
BizName string `json:"business_name"`
BizType int64 `json:"biz_type"`
Flows map[int64]string `json:"flows"`
}
// FlowItem .
type FlowItem struct {
FlowID int64 `json:"flow_id"`
NetID int64 `json:"net_id"`
Name string `json:"name"`
ChName string `json:"ch_name"`
}
// BizItemArr .
type BizItemArr []*BizItem
func (a BizItemArr) Len() int {
return len(a)
}
func (a BizItemArr) Less(i, j int) bool {
return a[i].BizID < a[j].BizID
}
func (a BizItemArr) Swap(i, j int) {
a[i], a[j] = a[j], a[i]
}

View File

@@ -0,0 +1,87 @@
package business
import (
"encoding/json"
"go-common/app/admin/main/aegis/model/middleware"
"go-common/library/log"
xtime "go-common/library/time"
)
// BizCFG .
type BizCFG struct {
ID int64 `json:"id" gorm:"primary_key" form:"id"`
BusinessID int64 `json:"business_id" gorm:"column:business_id" form:"business_id"`
TP int8 `json:"type" gorm:"column:type" form:"type"`
Config string `json:"config" gorm:"column:config" form:"config"`
State int64 `json:"state" gorm:"column:state" form:"state"`
Ctime xtime.Time `json:"ctime" gorm:"column:ctime"`
Mtime xtime.Time `json:"mtime" gorm:"column:mtime"`
}
// TableName .
func (t *BizCFG) TableName() string {
return "business_config"
}
// FormatMngBID .
func (t *BizCFG) FormatMngBID() (biz int64, roles map[int64][]int64, err error) {
var (
cfgs []map[string]int64
)
if t.TP != TypeManagerBID || t.Config == "" {
return
}
biz = t.BusinessID
roles = map[int64][]int64{}
if err = json.Unmarshal([]byte(t.Config), &cfgs); err != nil {
log.Error("FormatMngBID json.Unmarshal(%+v) error(%v)", t, err)
return
}
for _, item := range cfgs {
if item[MngBIDMID] <= 0 || item[MngBIDFlow] <= 0 {
continue
}
if _, exist := roles[item[MngBIDMID]]; !exist {
roles[item[MngBIDMID]] = []int64{}
}
roles[item[MngBIDMID]] = append(roles[item[MngBIDMID]], item[MngBIDFlow])
}
return
}
// FormatBizBID .
func (t *BizCFG) FormatBizBID() (biz int64, roles map[string]int64, err error) {
if t.TP != TypeBizBID || t.Config == "" {
return
}
biz = t.BusinessID
if err = json.Unmarshal([]byte(t.Config), &roles); err != nil {
log.Error("FormatBizBID json.Unmarshal(%+v) error(%v)", t, err)
}
return
}
//FormatAggregate 聚合配置
func (t *BizCFG) FormatAggregate() (cfgs []*middleware.Aggregate, err error) {
if t.TP != TypeMiddleware || t.Config == "" {
return
}
cfgs = []*middleware.Aggregate{}
if err = json.Unmarshal([]byte(t.Config), &cfgs); err != nil {
log.Error("FormatAggregate json.Unmarshal error(%+v)", err)
}
return
}
// ManagerRole .
type ManagerRole struct {
FlowID int64 `json:"flow_id"`
MngBid int64 `json:"manager_bid"`
}

View File

@@ -0,0 +1,37 @@
package(default_visibility = ["//visibility:public"])
load(
"@io_bazel_rules_go//go:def.bzl",
"go_library",
"go_test",
)
go_library(
name = "go_default_library",
srcs = ["common.go"],
importpath = "go-common/app/admin/main/aegis/model/common",
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"],
)
go_test(
name = "go_default_test",
srcs = ["common_test.go"],
embed = [":go_default_library"],
tags = ["automanaged"],
deps = ["//vendor/github.com/smartystreets/goconvey/convey:go_default_library"],
)

View File

@@ -0,0 +1,203 @@
package common
import (
"database/sql/driver"
"fmt"
"regexp"
"strconv"
"time"
)
// TimeFormat time format
var TimeFormat = "2006-01-02 15:04:05"
//GrayField gray config for each business
type GrayField struct {
Name string
Value string
}
// Pager .
type Pager struct {
Total int `json:"total" reflect:"ignore"`
Pn int `form:"pn" default:"1" json:"pn" reflect:"ignore"`
Ps int `form:"ps" default:"20" json:"ps" reflect:"ignore"`
}
// BaseOptions 公共参数
type BaseOptions struct {
BusinessID int64 `form:"business_id" json:"business_id"`
NetID int64 `form:"net_id" json:"net_id"`
FlowID int64 `form:"flow_id" json:"flow_id"`
UID int64 `form:"uid" json:"uid" submit:"int"`
OID string `form:"oid" json:"oid" submit:"string"`
RID int64 `form:"rid" json:"rid"`
Role int8 `form:"role" json:"role"`
Debug int8 `form:"debug" json:"debug"`
Uname string `form:"uname" json:"uname" submit:"string"`
}
// FormatTime .
type FormatTime string
// Scan .
func (f *FormatTime) Scan(src interface{}) (err error) {
switch sc := src.(type) {
case time.Time:
*f = FormatTime(sc.Format("2006-01-02 15:04:05"))
case string:
*f = FormatTime(sc)
}
return
}
// WaitTime 计算等待时长
func WaitTime(ctime time.Time) string {
wt := time.Since(ctime)
h := int(wt.Hours())
m := int(wt.Minutes()) % 60
s := int(wt.Seconds()) % 60
return fmt.Sprintf("%.2d:%.2d:%.2d", h, m, s)
}
//ParseWaitTime 。
func ParseWaitTime(ut int64) string {
h := ut / 3600
m := ut % 3600 / 60
s := ut % 60
return fmt.Sprintf("%.2d:%.2d:%.2d", h, m, s)
}
// Group .
type Group struct {
ID int64 `json:"group_id"`
Name string `json:"group_name"`
Note string `json:"group_note"`
Tag string `json:"group_tag"`
FontColor string `json:"font_color"`
BgColor string `json:"bg_color"`
}
// IntTime .
type IntTime int64
// Scan scan time.
func (jt *IntTime) Scan(src interface{}) (err error) {
switch sc := src.(type) {
case time.Time:
*jt = IntTime(sc.Unix())
case string:
var i int64
i, err = strconv.ParseInt(sc, 10, 64)
*jt = IntTime(i)
}
return
}
// Value get time value.
func (jt IntTime) Value() (driver.Value, error) {
return time.Unix(int64(jt), 0), nil
}
// Time get time.
func (jt IntTime) Time() time.Time {
return time.Unix(int64(jt), 0)
}
// UnmarshalJSON implement Unmarshaler
func (jt *IntTime) UnmarshalJSON(data []byte) error {
if data == nil || len(data) <= 1 {
*jt = 0
return nil
}
if data[0] != '"' {
// 1.直接判断数字
sti, err := strconv.Atoi(string(data))
if err == nil {
*jt = IntTime(sti)
}
return nil
}
str := string(data[1 : len(data)-1])
// 2.标准格式判断
st, err := time.ParseInLocation("2006-01-02 15:04:05", str, time.Local)
if err == nil {
*jt = IntTime(st.Unix())
return nil
}
*jt = IntTime(0)
return nil
}
// FilterName .
func FilterName(s string) (res string) {
exp := "[^a-zA-Z0-9_]+"
reg, err := regexp.Compile(exp)
if err != nil {
res = s
return
}
res = reg.ReplaceAllString(s, "")
return
}
// FilterChname .
func FilterChname(s string) (res string) {
exp := "[^0-9_\u4e00-\u9fa5]+"
reg, err := regexp.Compile(exp)
if err != nil {
res = s
return
}
res = reg.ReplaceAllString(s, "")
return
}
// FilterBusinessName .
func FilterBusinessName(s string) (res string) {
exp := "[^a-zA-Z\u4e00-\u9fa5]+"
reg, err := regexp.Compile(exp)
if err != nil {
res = s
return
}
res = reg.ReplaceAllString(s, "")
return
}
//Unique remove duplicated value from slice
func Unique(ids []int64, gthan0 bool) (res []int64) {
res = []int64{}
mm := map[int64]int64{}
for _, id := range ids {
if mm[id] == id || (gthan0 && id <= 0) {
continue
}
res = append(res, id)
mm[id] = id
}
return
}
//CopyMap copy src to dest
func CopyMap(src, dest map[int64][]int64, gthan0 bool) (res map[int64][]int64) {
if dest == nil {
dest = map[int64][]int64{}
}
for k, v := range src {
dest[k] = append(dest[k], v...)
dest[k] = Unique(dest[k], gthan0)
}
res = dest
return
}

View File

@@ -0,0 +1,97 @@
package common
import (
"github.com/smartystreets/goconvey/convey"
"testing"
"time"
)
func TestFormatTime_Scan(t *testing.T) {
convey.Convey("FormatTime_Scan", t, func(ctx convey.C) {
a := FormatTime("2018-01-01 01:00:00")
b := time.Time{}
err := a.Scan(b)
ctx.Convey("FormatTime_Scan", func(ctx convey.C) {
convey.So(err, convey.ShouldBeNil)
})
})
}
func TestWaitTime(t *testing.T) {
convey.Convey("WaitTime", t, func(ctx convey.C) {
b := time.Time{}
WaitTime(b)
})
}
func TestParseWaitTime(t *testing.T) {
convey.Convey("ParseWaitTime", t, func(ctx convey.C) {
b := time.Time{}.Unix()
ParseWaitTime(b)
})
}
var s = IntTime(time.Now().Unix())
func TestIntTime_Scan(t *testing.T) {
convey.Convey("IntTime_Scan", t, func(ctx convey.C) {
b := time.Time{}
err := s.Scan(&b)
ctx.Convey("IntTime_Scan", func(ctx convey.C) {
convey.So(err, convey.ShouldBeNil)
})
})
}
func TestIntTime_Value(t *testing.T) {
convey.Convey("IntTime_Value", t, func(ctx convey.C) {
s.Value()
})
}
func TestIntTime_UnmarshalJSON(t *testing.T) {
convey.Convey("IntTime_UnmarshalJSON", t, func(ctx convey.C) {
err := s.UnmarshalJSON(nil)
ctx.Convey("IntTime_UnmarshalJSON", func(ctx convey.C) {
convey.So(err, convey.ShouldBeNil)
})
})
}
func TestFilterName(t *testing.T) {
convey.Convey("FilterName", t, func(ctx convey.C) {
a := FilterName("hahah一个")
convey.So(a, convey.ShouldEqual, "hahah")
})
}
func TestFilterChname(t *testing.T) {
convey.Convey("FilterChname", t, func(ctx convey.C) {
a := FilterChname("hahah一个")
convey.So(a, convey.ShouldEqual, "一个")
})
}
func TestFilterBusinessName(t *testing.T) {
convey.Convey("FilterBusinessName", t, func(ctx convey.C) {
a := FilterBusinessName("hahah一个")
convey.So(a, convey.ShouldEqual, "hahah一个")
})
}
func TestUnique(t *testing.T) {
convey.Convey("Unique", t, func(ctx convey.C) {
b := []int64{1, -1, 0, 1, 1}
a := Unique(b, true)
convey.So(len(a), convey.ShouldEqual, 1)
convey.So(a[0], convey.ShouldEqual, 1)
})
}
func TestCopyMap(t *testing.T) {
convey.Convey("CopyMap", t, func(ctx convey.C) {
b := map[int64][]int64{}
a := CopyMap(map[int64][]int64{1: []int64{1}}, b, true)
convey.So(len(a), convey.ShouldEqual, 1)
})
}

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 = ["messages.go"],
importpath = "go-common/app/admin/main/aegis/model/databus",
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,9 @@
package databus
// CreateTaskMsg .
type CreateTaskMsg struct {
BizID int64 `json:"business_id"`
RID int64 `json:"rid"`
FlowID int64 `json:"flow_id"`
DispatchLimit int64 `json:"dispatch_limit"`
}

View File

@@ -0,0 +1,360 @@
package model
import (
"encoding/json"
"fmt"
"reflect"
"go-common/app/admin/main/aegis/model/common"
"go-common/app/admin/main/aegis/model/net"
"go-common/app/admin/main/aegis/model/resource"
"go-common/app/admin/main/aegis/model/task"
member "go-common/app/service/main/account/api"
"go-common/library/log"
)
const (
// DefaultZeroInt form default zero
DefaultZeroInt = int64(-12345)
)
// EngineOption .
type EngineOption struct {
common.BaseOptions
TaskID int64 `json:"task_id" form:"task_id"`
Result *resource.Result `json:"resource_result" form:"resource_result" submit:"object"` // 资源的修改内容,要传就全传,否则传空
Forbid *Forbid `json:"forbid_params" submit:"json"`
ExtraData map[string]interface{} `json:"extra_data" submit:"map"`
}
// Forbid 封禁参数
type Forbid struct {
Notify int `json:"notify"`
Reason string `json:"reason"`
Duration int64 `json:"duration"`
Comment string `json:"comment"`
Img string `json:"img"`
}
// InfoResOption .
type InfoResOption struct {
common.BaseOptions
}
// ListResOption .
type ListResOption struct {
common.Pager
common.BaseOptions
BusinessID int64 `form:"business_id"`
FlowID int64 `form:"flow_id"`
}
// SubmitOptions 审核结果提交参数
type SubmitOptions struct {
EngineOption
NewFlowID int64 `json:"newflow_id"`
BindStr string `json:"binds"`
Binds []int64 `json:"-"`
}
// BatchOption 批量提交
type BatchOption struct {
BusinessID int64 `form:"business_id" json:"business_id" validate:"required"`
NetID int64 `form:"net_id" json:"net_id"`
UID int64 `form:"uid" json:"uid"`
Debug int8 `form:"debug" json:"debug"`
Uname string `form:"uname" json:"uname"`
RIDs []int64 `form:"rids,split" json:"rids" validate:"gt=0,dive,gt=0"`
Binds []int64 `form:"binds,split" json:"binds" validate:"gt=0,dive,gt=0"`
RejectReason string `form:"reject_reason"`
ReasonID int64 `form:"reason_id" default:"0"`
Notify int8 `form:"notify"`
}
// Tip 批量提交的错误提示
type Tip struct {
Success []int64 `json:"success"`
Async []int64 `json:"async"`
Fail map[int64]string `json:"fail"`
}
// AddOption add option
type AddOption struct {
resource.Resource
State int `form:"state" json:"state"`
NetID int64 `form:"net_id" json:"net_id" validate:"required"`
}
// UpdateKeys 可更新的资源字段
var UpdateKeys = map[string]struct{}{
"mid": {},
"content": {},
"extra1": {},
"extra2": {},
"extra3": {},
"extra4": {},
"extra5": {},
"extra6": {},
"extra1s": {},
"extra2s": {},
"extra3s": {},
"extra4s": {},
"extratime1": {},
"octime": {},
"ptime": {},
"metadata": {},
}
// UpdateOption update option
type UpdateOption struct {
BusinessID int64 `form:"business_id" json:"business_id" validate:"required"`
NetID int64 `form:"net_id" json:"net_id" validate:"required"`
OID string `form:"oid" json:"oid" validate:"required"`
Update map[string]interface{} `json:"update"`
}
// AuditInfo 审核详情页
type AuditInfo struct {
UnDoStat *task.UnDOStat `json:"undo_stat"`
Task *task.Task `json:"task"`
Flow *net.TransitionInfo `json:"flow"`
Resource *resource.Res `json:"resource"`
OperHistorys []string `json:"historys"`
IFrame string `json:"iframe_url,omitempty"`
UserInfo *UserInfo `json:"user_info"`
UserGroup map[int64]*common.Group `json:"user_group"`
Hit []string `json:"hit"`
Actions []*Action `json:"actions"`
}
// UserInfo .
type UserInfo struct {
Mid int64 `json:"mid"`
Name string `json:"name"`
Official member.OfficialInfo `json:"official"`
Follower int64 `json:"follower"`
}
// SyncMessage .
type SyncMessage struct {
URL string
Uname string `json:"auditor"`
MID int64 `json:"uid"`
OID string `json:"oid"`
RejectReason string `json:"reason"`
FlowData map[string]interface{} `json:"flow_data"`
ExtraData map[string]interface{} `json:"extra_data"`
ForbidParams map[string]interface{} `json:"forbid_params"`
Attribute map[string]int8 `json:"attribute"`
}
// GetEmptyInfo empty info for debug
func GetEmptyInfo() *AuditInfo {
info := &AuditInfo{
UnDoStat: &task.UnDOStat{},
Task: &task.Task{},
Flow: &net.TransitionInfo{
Operations: []*net.TranOperation{{}},
},
UserInfo: &UserInfo{},
Resource: &resource.Res{},
OperHistorys: []string{
"wulalalal",
},
IFrame: "iframe",
}
return info
}
// SearchParams ..
type SearchParams struct {
common.Pager
Debug int8 `form:"debug" reflect:"ignore"`
FilterOff bool `form:"state_filter_off" reflect:"ignore"`
BusinessID int64 `form:"business_id" validate:"required" reflect:"business_id"`
OID []string `form:"oid,split" reflect:"oid"`
FlowID int64 `form:"flow_id" default:"-12345" reflect:"flow_id,omitdefault"`
State int64 `form:"state" default:"-12345" reflect:"state,omitdefault"`
Mid int64 `form:"mid" default:"-12345" reflect:"mid,omitdefault"`
CtimeFrom string `form:"ctime_from" reflect:"ctime,from"`
CtimeTo string `form:"ctime_to" reflect:"ctime,to"`
Extra1 string `form:"extra1" reflect:"extra1" parse:"[]int"`
Extra2 string `form:"extra2" reflect:"extra2" parse:"int"`
Extra3 string `form:"extra3" reflect:"extra3" parse:"int"`
Extra4 string `form:"extra4" reflect:"extra4" parse:"int"`
Extra5 string `form:"extra4" reflect:"extra5" parse:"int"`
Extra6 string `form:"extra4" reflect:"extra6" parse:"int"`
Extra1s string `form:"extra1s" reflect:"extra1s" `
Extra2s string `form:"extra2s" reflect:"extra2s" `
Extra3s string `form:"extra3s" reflect:"extra3s" `
Extra4s string `form:"extra4s" reflect:"extra4s" `
ExtraTime1 string `form:"extratime1" reflect:"extratime1" ` //TODO 具体用到了再看怎么解析
KeyWord string `form:"keyWords" reflect:"ignore"`
CtimeOrder string `form:"ctime_order" reflect:"ignore"` //TODO 等octime导入后要按照octime筛选
}
// SearchRes search list.
type SearchRes struct {
Resources []*ListRscItem `json:"result"`
Page struct {
Num int `json:"num"`
Size int `json:"size"`
Total int `json:"total"`
} `json:"page"`
}
//Column .
type Column struct {
Name string `json:"name"`
ChName string `json:"chname"`
Enum map[int64]string `json:"enum,omitempty"`
}
// ListRscItem .
type ListRscItem struct {
resource.Res
FlowID int64 `json:"flow_id"`
UserInfo *UserInfo `json:"user_info"`
UserGroup map[int64]*common.Group `json:"user_group"`
Hit []string `json:"hit"`
}
// ListTaskItem .
type ListTaskItem struct {
ListTask
WaitTime string `json:"wait_time"`
OID string `json:"oid"`
Content string `json:"content"`
UserInfo *UserInfo `json:"user_info"`
UserGroup map[int64]*common.Group `json:"user_group"`
Metas map[string]interface{} `json:"metas"`
}
// ListTask 转化gtime
type ListTask struct {
*task.Task
GTstr string `json:"gtime"`
CTstr string `json:"ctime"`
MTstr string `json:"mtime"`
UserName string `json:"uid"`
MidStr string `json:"mid"`
}
// EmptyListItem .
func EmptyListItem() *ListRscItem {
return &ListRscItem{
UserInfo: &UserInfo{},
}
}
// IsImgType file type is image
func IsImgType(fileType string) bool {
return fileType != "image/jpeg" && fileType != "image/png" && fileType != "image/webp"
}
//Action 下发到前端的组件
type Action struct {
Name string `json:"name"`
URL string `json:"url"`
Method string `json:"method"`
Response string `json:"response"`
Extra string `json:"extra,omitempty"`
Params map[string]*ActionParam `json:"params"`
}
//ActionParam 烦人啊,动态的打回理由是必传参数
type ActionParam struct {
Value string `json:"value"`
Default string `json:"default"`
}
//SubReflect .
func SubReflect(ot reflect.Type, ov reflect.Value, key string, vals []string, defaultval string, params map[string]interface{}) {
var result string
boommsg := fmt.Sprintf("key:%s vals:%v ot:%+v vt:%+v", key, vals, ot, reflect.TypeOf(ov).Kind())
if len(vals) == 0 {
return
}
val := vals[0]
tfield, ok := ot.FieldByName(val)
if !ok {
log.Error("SubReflect1:" + boommsg)
return
}
vfield := ov.FieldByName(val)
if !vfield.IsValid() {
log.Error("SubReflect7:" + boommsg)
return
}
switch tfield.Tag.Get("submit") {
case "object":
vals = vals[1:]
tt := tfield.Type
vv := reflect.ValueOf(vfield)
if tfield.Type.Kind() == reflect.Ptr {
tt = tfield.Type.Elem()
vv = vfield.Elem()
}
SubReflect(tt, vv, key, vals, defaultval, params)
return
case "map":
if len(vals) != 2 || tfield.Type.Kind() != reflect.Map {
log.Error("SubReflect2:" + boommsg)
}
v := vfield.MapIndex(reflect.ValueOf(vals[1]))
if !v.IsValid() { //批量操作可能会没有map的参数
log.Warn("SubReflect4:" + boommsg)
return
}
result = fmt.Sprint(v.Interface())
case "json":
bs, err := json.Marshal(vfield.Interface())
if err != nil {
log.Error("SubReflect5:" + boommsg)
return
}
result = string(bs)
case "int", "string":
result = fmt.Sprint(vfield.Interface())
default:
log.Error("SubReflect6:" + boommsg)
}
if result == "" {
result = defaultval
}
params[key] = result
}
//Auth auth
type Auth struct {
OK bool `json:"ok"`
Admin bool `json:"admin"`
Business map[int64]int64 `json:"business"`
}
//UpsertItem 更新搜索的items
type UpsertItem struct {
ID int64 `json:"id"`
State int `json:"state"`
Extra1 int64 `json:"extra1"`
Extra2 int64 `json:"extra2"`
Extra3 int64 `json:"extra3"`
Extra4 int64 `json:"extra4"`
}
//CancelOption .
type CancelOption struct {
BusinessID int64 `form:"business_id" validate:"required" json:"business_id"`
Oids []string `form:"oids,split" validate:"required" json:"oids"`
Reason string `form:"reason" json:"reason"`
}

View File

@@ -0,0 +1,296 @@
package model
import (
"encoding/json"
"fmt"
"go-common/app/admin/main/aegis/model/net"
)
//..
const (
LogBusinessAudit = int(231)
LogTypeAuditSubmit = int(1)
LogTypeAuditJump = int(2)
LogTypeAuditAdd = int(3)
LogTypeAuditCancel = int(4)
LogBusinessTask = int(232)
LogTypeTaskDispatch = int(1)
LogTypeTaskConsumer = int(2)
LogTYpeTaskWeight = int(3)
LogBusinessResource = int(233)
LogTypeFormAuditor = int(1) // 审核员提交变更
LogTypeFromAdd = int(2) // 业务添加资源
LogTypeFromCancle = int(3) // 业务注销资源
LogBusinessNet = int(234) //流程流转
LogTypeNetTrigger = int(1) //流程流转
LogFromBatch = "批量提交"
LogFromSingle = "单个提交"
LogFromStart = "启动"
LogFromJump = "跳流程"
LogFromCancle = "取消流程"
LogBusinessNetConf = int(235) //流程配置
LogTypeNetConf = int(1) //流程网配置
LogTypeTokenConf = int(2) //令牌配置
LogTypeFlowConf = int(3) //节点配置
LogTypeTranConf = int(4) //变迁配置
LogTypeTokenBindConf = int(5) //令牌绑定配置
LogTypeDirConf = int(6) //有向线配置
//流程配置的操作
LogNetActionNew = "创建"
LogNetActionUpdate = "更新"
LogNetActionDisable = "禁用"
LogNetActionAvailable = "启用"
//流程配置的更新字段
LogFieldPID = "pid"
LogFieldChName = "ch_name"
LogFieldName = "name"
LogFieldTokenID = "token_id"
LogFieldStartFlow = "start_flow"
LogFieldTrigger = "trigger"
LogFieldLimit = "limit"
LogFieldDirection = "direction"
LogFieldOrder = "order"
LogFieldGuard = "guard"
LogFieldOutput = "output"
)
//LogFieldDesc 日志中的变更字段描述
var LogFieldDesc = map[string]string{
LogFieldPID: "父网",
LogFieldChName: "中文名",
LogFieldName: "英文名",
LogFieldTokenID: "令牌",
LogFieldStartFlow: "初始节点",
LogFieldTrigger: "触发类型",
LogFieldLimit: "限制",
LogFieldDirection: "指向",
LogFieldOrder: "顺序",
LogFieldGuard: "通行条件",
LogFieldOutput: "输出规则",
}
//LogFieldTemp 指定模板和字段,组建变更日志字段
func LogFieldTemp(field string, nw interface{}, old interface{}, diffTemp bool) (s string) {
var (
desc string
exist bool
temp string
)
if desc, exist = LogFieldDesc[field]; !exist {
desc = field
}
if diffTemp {
temp = "[%s]从[%v]变成[%v]"
s = fmt.Sprintf(temp, desc, old, nw)
} else {
temp = "[%s]为[%v]"
s = fmt.Sprintf(temp, desc, nw)
}
return
}
//NetConfOper 流程配置日志
type NetConfOper struct {
OID int64 `json:"oid"`
Action string `json:"action"`
UID int64 `json:"uid"`
Uname string `json:"uname"`
NetID int64 `json:"net_id"`
ChName string `json:"ch_name"`
FlowID int64 `json:"flow_id"`
TranID int64 `json:"tran_id"`
Diff []string `json:"diff"`
}
//SearchAuditLogParam 搜索行为日志参数
type SearchAuditLogParam struct {
RID []int64
OID []string `form:"oid,split" validate:"omitempty,max=30,dive,gt=0"`
Username []string `form:"username,split"`
CtimeFrom string `form:"ctime_from"`
CtimeTo string `form:"ctime_to"`
Ps int `form:"ps" validate:"gt=0,max=50" default:"10"`
Pn int `form:"pn" validate:"gt=0" default:"1"`
TaskID []int64 `form:"task_id,split" validate:"omitempty,max=30"`
State string `form:"state"`
BusinessID int64 `form:"business_id" validate:"required,gt=0"`
}
//SearchAuditLog 审核日志记录
type SearchAuditLog struct {
RID int64 `json:"rid"`
OID string `json:"oid"`
TaskID int64 `json:"task_id"`
State string `json:"state"`
Stime string `json:"stime"`
UID int64 `json:"uid"`
Uname string `json:"uname"`
Department string `json:"department"`
Extra string `json:"extra"`
}
type SearchLogResult struct {
Result []struct {
UID int64 `json:"uid"`
Uname string `json:"uname"`
OID int64 `json:"oid"`
Type int8 `json:"type"`
Action string `json:"action"`
Str0 string `json:"str_0"`
Str1 string `json:"str_1"`
Str2 string `json:"str_2"`
Int0 int64 `json:"int_0"`
Int1 int64 `json:"int_1"`
Int2 int64 `json:"int_2"`
Ctime string `json:"ctime"`
Extra string `json:"extra_data"`
} `json:"result"`
Page struct {
Num int `json:"num"`
Size int `json:"size"`
Total int `json:"total"`
} `json:"page"`
}
// Change for log
type Change struct {
Opt *SubmitOptions `json:"opt"`
Flow *Flow `json:"flow"`
}
//GetSubmitOper .
func (change *Change) GetSubmitOper() (flowaction, submitopt string) {
if change.Flow != nil && change.Flow.ResultToken != nil {
flowaction = change.Flow.ResultToken.ChName
}
if change.Opt != nil {
if change.Opt.Result != nil {
if change.Opt.Result.ReasonID != 0 {
submitopt += fmt.Sprintf(" 理由ID:%d ", change.Opt.Result.ReasonID)
}
if change.Opt.Result.RejectReason != "" && change.Opt.Result.RejectReason != "null" {
submitopt += fmt.Sprintf(" 打回理由:%s ", change.Opt.Result.RejectReason)
}
if change.Opt.Result.Note != "" && change.Opt.Result.Note != "null" {
submitopt += fmt.Sprintf(" 备注:%s ", change.Opt.Result.Note)
}
}
if change.Opt.Forbid != nil {
if change.Opt.Forbid.Reason != "" && change.Opt.Forbid.Reason != "null" {
submitopt += fmt.Sprintf(" 封禁理由:%s ", change.Opt.Forbid.Reason)
if du := change.Opt.Forbid.Duration; du == -1 {
submitopt += " 封禁时长:永久 "
} else {
submitopt += fmt.Sprintf(" 封禁时长:%d天 ", du/86400)
}
}
if change.Opt.Forbid.Comment != "" && change.Opt.Forbid.Comment != "null" {
submitopt += fmt.Sprintf(" 备注:%s ", change.Opt.Forbid.Comment)
}
}
}
return
}
// Flow for log
type Flow struct {
SubmitToken *net.TokenPackage `json:"submit_token"`
ResultToken *net.TokenPackage `json:"result_token"`
NewFlowID int64 `json:"new_flow_id"`
OldFlowID json.Number `json:"old_flow_id"`
}
// WeightLog task log
type WeightLog struct {
UPtime string `json:"uptime"`
Mid int64 `json:"mid"`
MemName string `json:"member_name"` // up主名称
Fans int64 `json:"fans"`
FansWeight int64 `json:"fans_weight"`
Group string `json:"group"`
GroupWeight int64 `json:"group_weight"`
WaitTime string `json:"wait_time"`
WaitWeight int64 `json:"wait_weight"`
EqualWeight int64 `json:"config_weight"`
ConfigItems []*ConfigItem `json:"config_items"`
Weight int64 `json:"weight"`
}
// ConfigItem .
type ConfigItem struct {
Name string `json:"name"`
Desc string `json:"desc"`
Username string `json:"uname"`
}
//TrackRsc 资源信息追踪
type TrackRsc struct {
Ctime string `json:"ctime"`
Content string `json:"content"`
Detail map[string]interface{} `json:"detail"`
}
//TrackAudit 操作日志信息追踪
type TrackAudit struct {
Ctime string `json:"ctime"`
FlowID []int64 `json:"flow_id"`
FlowName string `json:"flow_name"`
State string `json:"state"`
Uname string `json:"uname"`
}
//TrackInfo 信息追踪汇总
type TrackInfo struct {
Add []*TrackRsc `json:"add"`
Audit []*TrackAudit `json:"audit"`
Relation [][]int `json:"relation"`
}
//TrackParam 信息追踪参数
type TrackParam struct {
BusinessID int64 `form:"business_id" validate:"required,gt=0"`
OID string `form:"oid" validate:"required,gt=0"`
Pn int `form:"pn" validate:"gt=0" default:"1"`
Ps int `form:"ps" validate:"gt=0,max=30" default:"10"`
LastPageTime string `form:"last_page_time"`
}
//ParamsQueryLog .
type ParamsQueryLog struct {
Business int `reflect:"business"`
Type int `default:"0" reflect:"type,omitdefault"`
Uname []string `reflect:"uname"`
UID []int64 `reflect:"uid"`
Oid []int64 `reflect:"oid"`
Action []string `reflect:"action"`
CtimeFrom string `reflect:"ctime,from"`
CtimeTo string `reflect:"ctime,to"`
Int0 []int64 `reflect:"int_0"`
Int0From string `reflect:"int_0,from"`
Int0To string `reflect:"int_0,to"`
Int1 []int64 `reflect:"int_1"`
Int1From string `reflect:"int_1,from"`
Int1To string `reflect:"int_1,to"`
Int2 []int64 `reflect:"int_2"`
Int2From string `reflect:"int_2,from"`
Int3To string `reflect:"int_2,to"`
Str0 []string `reflect:"str_0"`
Str1 []string `reflect:"str_1"`
Str2 []string `reflect:"str_2"`
}
//EsCommon .
type EsCommon struct {
Pn int
Ps int
Order string
Sort string
Group string
}

View File

@@ -0,0 +1,48 @@
package(default_visibility = ["//visibility:public"])
load(
"@io_bazel_rules_go//go:def.bzl",
"go_test",
"go_library",
)
go_test(
name = "go_default_test",
srcs = [
"config_test.go",
"response_test.go",
],
embed = [":go_default_library"],
tags = ["automanaged"],
deps = [
"//app/admin/main/aegis/model:go_default_library",
"//app/admin/main/aegis/model/resource:go_default_library",
"//vendor/github.com/smartystreets/goconvey/convey:go_default_library",
],
)
go_library(
name = "go_default_library",
srcs = [
"config.go",
"response.go",
],
importpath = "go-common/app/admin/main/aegis/model/middleware",
tags = ["automanaged"],
visibility = ["//visibility:public"],
deps = ["//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,163 @@
package middleware
import (
"fmt"
"reflect"
"sort"
"strconv"
"strings"
"go-common/library/log"
)
const (
//TypeMiddleAll 全部操作都允许
TypeMiddleAll = int8(0)
//TypeMiddleEncode 只允许编码,后端返回给前端的响应处理
TypeMiddleEncode = int8(1)
//TypeMiddleDecode 只允许解码,前端请求后端的请求参数处理
TypeMiddleDecode = int8(2)
)
//Aggregate 前端映射结构,对应于前后端交互的字段
type Aggregate struct {
Hitn string `json:"hitn"` //name的多个结构体用.表示分级
Hitv string `json:"hitv"` //枚举值
Mapn string `json:"mapn"` //映射字段名可以与hitname不同也可以相同
Mapv string `json:"mapv"` //映射字段值
Delimiter string `json:"delimiter"` //映射字段值的分隔符号
Order int64 `json:"order"` //顺序
Type int8 `json:"type"`
}
func (f *Aggregate) Process(data interface{}, encode bool) {
var (
field, fieldm reflect.Value
fieldExist, hited bool
)
defer func() {
if errs := recover(); errs != nil {
log.Error("Aggregate Process error(%+v)", errs)
}
}()
hitn := f.Hitn
hitv := strings.Split(f.Hitv, f.Delimiter)
mapn := f.Mapn
mapv := f.Mapv
if !encode {
hitn = f.Mapn
hitv = strings.Split(f.Mapv, f.Delimiter)
mapn = f.Hitn
mapv = f.Hitv
}
//check fields exist
fv := reflect.ValueOf(data)
if field, fieldExist = getFieldByName(fv, hitn); !fieldExist {
log.Warn("no field for hit(%s) data(%+v)", hitn, data)
return
}
if mapn == hitn {
fieldm = field
} else if fieldm, fieldExist = getFieldByName(fv, mapn); !fieldExist || !fieldm.CanSet() {
log.Warn("no field for map(%s) data(%+v)", mapn, data)
return
}
fieldv := fmt.Sprintf("%v", field.Interface())
for _, hit := range hitv {
if fieldv == hit {
hited = true
break
}
}
if !hited {
return
}
log.Info("got hit field(%s) value(%s) config(%+v)", hitn, fieldv, f)
switch fieldm.Kind() {
case reflect.String:
fieldm.SetString(mapv)
case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64:
vv, err := strconv.ParseInt(mapv, 10, 64)
if err != nil {
log.Error("strconv.ParseInt(%s) error(%v)", mapv, err)
return
}
fieldm.SetInt(vv)
default:
log.Warn("not support field.kind(%s) for field(%s)", fieldm.Kind().String(), mapn)
}
}
//getFieldByName 迭代遍历struct获取指定名字的字段
func getFieldByName(v reflect.Value, name string) (res reflect.Value, ok bool) {
tp := v.Type()
if tp.Kind() == reflect.Ptr {
v = v.Elem()
tp = tp.Elem()
}
if tp.Kind() != reflect.Struct || !v.IsValid() {
return
}
for i := 0; i < tp.NumField(); i++ {
fn := strings.ToLower(tp.Field(i).Name)
if fn == name {
res = v.Field(i)
ok = true
return
}
if vres, vok := getFieldByName(v.Field(i), name); vok {
ok = vok
res = vres
return
}
}
return
}
//MiddleAggregate 处理聚合逻辑
type MiddleAggregate struct {
Cfg []*Aggregate
Encode bool
}
//Process handle multi aggregate logists
func (m *MiddleAggregate) Process(data interface{}) {
cfgs := []*Aggregate{}
for _, item := range m.Cfg {
if item.Type == TypeMiddleAll || (m.Encode && item.Type == TypeMiddleEncode) || (!m.Encode && item.Type == TypeMiddleDecode) {
cfgs = append(cfgs, item)
}
}
if len(cfgs) == 0 {
return
}
sort.Sort(AggregateArr(cfgs))
for _, item := range cfgs {
item.Process(data, m.Encode)
}
}
//AggregateArr arr
type AggregateArr []*Aggregate
//Len .
func (f AggregateArr) Len() int {
return len(f)
}
//Less .
func (f AggregateArr) Less(i, j int) bool {
return f[i].Order < f[j].Order
}
//Swap .
func (f AggregateArr) Swap(i, j int) {
f[i], f[j] = f[j], f[i]
}

View File

@@ -0,0 +1,111 @@
package middleware
import (
"fmt"
"reflect"
"testing"
"github.com/smartystreets/goconvey/convey"
"go-common/app/admin/main/aegis/model"
"go-common/app/admin/main/aegis/model/resource"
)
var (
d = &Aggregate{
Hitn: "extra1",
Hitv: "2,3,4,5,6,7",
Mapn: "extra1",
Mapv: "2",
Order: 1,
}
ds = MiddleAggregate{
Cfg: []*Aggregate{d},
Encode: true,
}
)
func TestMiddleware_AggregateProcess(t *testing.T) {
var (
data = &model.AuditInfo{
Resource: &resource.Res{Extra1: 6},
}
encode bool = true
data2 = &model.SearchParams{
Extra1: "2",
}
)
convey.Convey("AggregateProcess", t, func(ctx convey.C) {
d.Process(data, encode) //将extra1=6替换成extra1=2
d.Process(data2, !encode) //将extra1=2替换成extra1=2,3,4,5,6,7
ctx.Convey("extra1 equal", func(ctx convey.C) {
ctx.So(fmt.Sprintf("%d", data.Resource.Extra1), convey.ShouldEqual, d.Mapv)
ctx.So(data2.Extra1, convey.ShouldEqual, d.Hitv)
})
})
}
func TestMiddlewaregetFieldByName(t *testing.T) {
var (
v = reflect.ValueOf(&model.AuditInfo{
Resource: &resource.Res{Extra1: 6},
})
name = "extra1"
)
convey.Convey("getFieldByName", t, func(ctx convey.C) {
res, ok := getFieldByName(v, name)
ctx.Convey("Then res,ok should not be nil.", func(ctx convey.C) {
ctx.So(ok, convey.ShouldEqual, true)
ctx.So(res, convey.ShouldNotBeNil)
})
})
}
func TestMiddlewareProcess(t *testing.T) {
var (
data = &model.AuditInfo{
Resource: &resource.Res{Extra1: 6},
}
)
convey.Convey("Process", t, func(ctx convey.C) {
ds.Encode = true
ds.Process(data)
ctx.Convey("No return values", func(ctx convey.C) {
//将extra1=6替换成extra1=2
ctx.So(fmt.Sprintf("%d", data.Resource.Extra1), convey.ShouldEqual, d.Mapv)
})
})
}
func TestMiddlewareLen(t *testing.T) {
convey.Convey("Len", t, func(ctx convey.C) {
p1 := AggregateArr(ds.Cfg).Len()
ctx.Convey("Then p1 should not be nil.", func(ctx convey.C) {
ctx.So(p1, convey.ShouldEqual, 1)
})
})
}
func TestMiddlewareLess(t *testing.T) {
var (
i = int(0)
j = int(0)
)
convey.Convey("Less", t, func(ctx convey.C) {
p1 := AggregateArr(ds.Cfg).Less(i, j)
ctx.Convey("Then p1 should not be nil.", func(ctx convey.C) {
ctx.So(p1, convey.ShouldEqual, false)
})
})
}
func TestMiddlewareSwap(t *testing.T) {
var (
i = int(0)
j = int(0)
)
convey.Convey("Swap", t, func(ctx convey.C) {
AggregateArr(ds.Cfg).Swap(i, j)
ctx.Convey("No return values", func(ctx convey.C) {
})
})
}

View File

@@ -0,0 +1,26 @@
package middleware
//IMiddleware handler
type IMiddleware interface {
Process(data interface{})
}
//ResponseRender .
type ResponseRender func(data interface{}, err error)
//Response response handler
func Response(data interface{}, err error, r ResponseRender, i IMiddleware) {
if data != nil && i != nil {
i.Process(data)
}
if r != nil {
r(data, err)
}
}
//Request request handler
func Request(data interface{}, i IMiddleware) {
if data != nil && i != nil {
i.Process(data)
}
}

View File

@@ -0,0 +1,44 @@
package middleware
import (
"testing"
"fmt"
"github.com/smartystreets/goconvey/convey"
"go-common/app/admin/main/aegis/model"
"go-common/app/admin/main/aegis/model/resource"
)
func TestMiddlewareRequest(t *testing.T) {
convey.Convey("Request", t, func(ctx convey.C) {
opt := new(model.SearchParams)
opt2 := &model.SearchParams{
Extra1: "2",
}
ds.Encode = false
Request(opt, &ds)
Request(opt2, &ds)
ctx.Convey("No return values", func(ctx convey.C) {
ctx.So(opt.Extra1, convey.ShouldEqual, "")
ctx.So(opt2.Extra1, convey.ShouldEqual, ds.Cfg[0].Hitv)
})
})
}
func TestMiddlewareResponse(t *testing.T) {
convey.Convey("Response", t, func(ctx convey.C) {
opt := new(model.AuditInfo)
opt2 := &model.AuditInfo{
Resource: &resource.Res{Extra1: 4},
}
ds.Encode = true
Response(opt, nil, nil, &ds)
Response(opt2, nil, nil, &ds)
ctx.Convey("No return values", func(ctx convey.C) {
ctx.So(opt.Resource, convey.ShouldBeNil)
ctx.So(fmt.Sprintf("%v", opt2.Resource.Extra1), convey.ShouldEqual, ds.Cfg[0].Mapv)
})
})
}

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