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

View File

@@ -0,0 +1,10 @@
#### sug-admin
##### v1.0.0
> 番剧推荐商品管理后台
##### v1.0.1
> 更换label
##### v1.0.2
> 当 brief不存在时使用name替换

View File

@@ -0,0 +1,10 @@
# Owner
changxuanran
xucheng
liuzhan
# Author
changxuanran
# Reviewer
liuzhan

View File

@@ -0,0 +1,15 @@
# See the OWNERS docs at https://go.k8s.io/owners
approvers:
- changxuanran
- liuzhan
- xucheng
labels:
- admin
- admin/openplatform/sug
- openplatform
options:
no_parent_owners: true
reviewers:
- changxuanran
- liuzhan

View File

@@ -0,0 +1,15 @@
#### sug-admin
##### 项目简介
> 1.开放平台根据番剧推荐商品管理后台
##### 编译环境
> 请只用golang v1.9.x以上版本编译执行。
##### 依赖包
> 1.公共包go-common

View File

@@ -0,0 +1,44 @@
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 = ["local-sug-test.toml"],
importpath = "go-common/app/admin/openplatform/sug/cmd",
tags = ["automanaged"],
visibility = ["//visibility:public"],
deps = [
"//app/admin/openplatform/sug/conf:go_default_library",
"//app/admin/openplatform/sug/http:go_default_library",
"//app/admin/openplatform/sug/service:go_default_library",
"//library/ecode/tip:go_default_library",
"//library/log:go_default_library",
"//library/net/trace:go_default_library",
],
)
filegroup(
name = "package-srcs",
srcs = glob(["**"]),
tags = ["automanaged"],
visibility = ["//visibility:private"],
)
filegroup(
name = "all-srcs",
srcs = [":package-srcs"],
tags = ["automanaged"],
visibility = ["//visibility:public"],
)

View File

@@ -0,0 +1,122 @@
# This is a TOML document. Boom
env = "uat"
sourcePath = "/Users/caocao/Code/go/src/go-common/app/admin/openplatform/sug/source/"
[url]
itemSearch = "http://fat1-mall.bilibili.co/mall-items/items/itemsListByQuery"
[auth]
managerHost = "http://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 = "tcp"
addr = "172.16.33.54:11211"
active = 10
idle = 5
dialTimeout = "1s"
readTimeout = "1s"
writeTimeout = "1s"
idleTimeout = "80s"
[redis]
name = "sug-season"
proto = "tcp"
addr = "172.16.33.203:6379"
idle = 10
active = 10
dialTimeout = "1s"
readTimeout = "1s"
writeTimeout = "1s"
idleTimeout = "10s"
expire = "1m"
[httpClient]
key = "ad4bb9b8f5d9d4a7"
secret = "6912080d78d58be7cb94f57d50d438f6"
dial = "1s"
timeout = "10s"
keepAlive = "60s"
timer = 1000
[httpClient.breaker]
window = "10s"
sleep = "100ms"
bucket = 10
ratio = 0.5
request = 100
[es]
addr = ["http://172.16.38.126:9201"]
[db]
[db.mallDB]
addr = "172.22.34.101:3310"
dsn ="mall:FIb1lia9lK4UufUScJjrxvbkrEZtZD4l@tcp(172.22.34.101:3310)/open_mall?timeout=5s&readTimeout=5s&writeTimeout=5s&parseTime=true&loc=Local&charset=utf8,utf8mb4"
active = 5
idle = 5
queryTimeout = "1s"
execTimeout = "1s"
tranTimeout = "2s"
[db.mallDB.breaker]
window = "3s"
sleep = "100ms"
bucket = 10
ratio = 0.5
request = 100
[db.ticketDB]
addr = "172.22.34.101:3310"
dsn = "ticket:i9HXWAvzWiqPxMxlfsQ8DRqYydjf3pYa@tcp(172.22.34.101:3310)/open_ticket?timeout=5s&readTimeout=5s&writeTimeout=5s&parseTime=true&loc=Local&charset=utf8,utf8mb4"
active = 5
idle = 5
queryTimeout = "1s"
execTimeout = "1s"
tranTimeout = "2s"
[db.ticketDB.breaker]
window = "3s"
sleep = "100ms"
bucket = 10
ratio = 0.5
request = 100
[bfs]
timeout = "2s"
maxFileSize = 5242880
key = "c387398b08495933"
secret = "18295608cd3b8a5lbbe2b07a509705"
addr = "http://bfs.bilibili.co/bfs/openplatform/"
bucket = "openplatform"

View File

@@ -0,0 +1,46 @@
package main
import (
"flag"
"os"
"os/signal"
"syscall"
"go-common/app/admin/openplatform/sug/conf"
"go-common/app/admin/openplatform/sug/http"
"go-common/app/admin/openplatform/sug/service"
ecode "go-common/library/ecode/tip"
"go-common/library/log"
"go-common/library/net/trace"
)
func main() {
flag.Parse()
if err := conf.Init(); err != nil {
log.Error("conf.Init() error(%v)", err)
panic(err)
}
log.Init(conf.Conf.Log)
defer log.Close()
trace.Init(conf.Conf.Tracer)
defer trace.Close()
log.Info("sug-season start")
ecode.Init(conf.Conf.Ecode)
s := service.New(conf.Conf)
http.Init(conf.Conf, s)
c := make(chan os.Signal, 1)
signal.Notify(c, syscall.SIGHUP, syscall.SIGQUIT, syscall.SIGTERM, syscall.SIGINT)
for {
s := <-c
log.Info("open-sug get a signal %s", s.String())
switch s {
case syscall.SIGQUIT, syscall.SIGTERM, syscall.SIGINT:
log.Info("open-sug exit")
return
case syscall.SIGHUP:
default:
return
}
}
}

View File

@@ -0,0 +1,40 @@
package(default_visibility = ["//visibility:public"])
load(
"@io_bazel_rules_go//go:def.bzl",
"go_library",
)
go_library(
name = "go_default_library",
srcs = ["conf.go"],
importpath = "go-common/app/admin/openplatform/sug/conf",
tags = ["automanaged"],
visibility = ["//visibility:public"],
deps = [
"//library/cache/redis:go_default_library",
"//library/conf: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/trace: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,119 @@
package conf
import (
"errors"
"flag"
"github.com/BurntSushi/toml"
"go-common/library/cache/redis"
"go-common/library/conf"
"go-common/library/database/sql"
ecode "go-common/library/ecode/tip"
"go-common/library/log"
bm "go-common/library/net/http/blademaster"
"go-common/library/net/http/blademaster/middleware/permit"
"go-common/library/net/trace"
xtime "go-common/library/time"
)
// global var
var (
confPath string
client *conf.Client
// Conf config
Conf = &Config{}
)
// Config config set
type Config struct {
Log *log.Config
BM *bm.ServerConfig
Tracer *trace.Config
Redis *redis.Config
Ecode *ecode.Config
Auth *permit.Config
HTTPClient *bm.ClientConfig
Es *ElasticSearch
DB *DB
URL *URL
Env string
SourcePath string
Bfs *Bfs
}
// URL search items
type URL struct {
ItemSearch string
}
// DB db config
type DB struct {
MallDB *sql.Config
TicketDB *sql.Config
}
// ElasticSearch config
type ElasticSearch struct {
Addr []string
}
// Bfs config
type Bfs struct {
Timeout xtime.Duration
MaxFileSize int
Bucket string
Addr string
Key string
Secret string
}
func init() {
flag.StringVar(&confPath, "conf", "", "default config path")
}
// Init init conf
func Init() error {
if confPath != "" {
return local()
}
return remote()
}
func local() (err error) {
_, err = toml.DecodeFile(confPath, &Conf)
return
}
func remote() (err error) {
if client, err = conf.New(); err != nil {
return
}
if err = load(); err != nil {
return
}
go func() {
for range client.Event() {
log.Info("config reload")
if load() != nil {
log.Error("config reload error (%v)", err)
}
}
}()
return
}
func load() (err error) {
var (
s string
ok bool
tmpConf *Config
)
if s, ok = client.Toml2(); !ok {
return errors.New("load config center error")
}
if _, err = toml.Decode(s, &tmpConf); err != nil {
return errors.New("could not decode config")
}
*Conf = *tmpConf
return
}

View File

@@ -0,0 +1,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 = [
"mysql_test.go",
"redis_test.go",
],
embed = [":go_default_library"],
rundir = ".",
tags = ["automanaged"],
)
go_library(
name = "go_default_library",
srcs = [
"bfs.go",
"dao.go",
"image.go",
"mysql.go",
"redis.go",
"season_es.go",
],
importpath = "go-common/app/admin/openplatform/sug/dao",
tags = ["automanaged"],
visibility = ["//visibility:public"],
deps = [
"//app/admin/openplatform/sug/conf:go_default_library",
"//app/admin/openplatform/sug/model:go_default_library",
"//library/cache/redis:go_default_library",
"//library/database/sql:go_default_library",
"//library/ecode:go_default_library",
"//library/log:go_default_library",
"//library/net/http/blademaster:go_default_library",
"//vendor/code.google.com/p/graphics-go/graphics:go_default_library",
"//vendor/github.com/golang/freetype:go_default_library",
"//vendor/golang.org/x/image/font:go_default_library",
"//vendor/golang.org/x/image/math/fixed:go_default_library",
"//vendor/gopkg.in/olivere/elastic.v5: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,72 @@
package dao
import (
"context"
"crypto/hmac"
"crypto/sha1"
"encoding/base64"
"fmt"
"hash"
"io"
"net/http"
"strconv"
"time"
"go-common/library/ecode"
"go-common/library/log"
)
const _method = "PUT"
// Upload upload bfs.
func (d *Dao) Upload(c context.Context, fileType string, fileName string, body io.Reader) (location string, err error) {
req, err := http.NewRequest(_method, d.c.Bfs.Addr+fileName, body)
if err != nil {
log.Error("http.NewRequest error (%v) | fileType(%s) body(%v)", err, fileType, body)
return
}
expire := time.Now().Unix()
authorization := authorize(d.c.Bfs.Key, d.c.Bfs.Secret, _method, d.c.Bfs.Bucket, fileName, expire)
req.Header.Set("Host", d.c.Bfs.Addr)
req.Header.Add("Date", fmt.Sprint(expire))
req.Header.Add("Authorization", authorization)
req.Header.Add("Content-Type", fileType)
// timeout
c, cancel := context.WithTimeout(c, time.Duration(d.c.Bfs.Timeout))
req = req.WithContext(c)
defer cancel()
resp, err := d.client.Do(req)
if err != nil {
log.Error("d.Client.Do error(%v) | _url(%s) req(%v)", err, d.c.Bfs.Addr, req)
err = ecode.BfsUploadServiceUnavailable
return
}
if resp.StatusCode != http.StatusOK {
log.Error("Upload http.StatusCode nq http.StatusOK (%d) | url(%s)", resp.StatusCode, d.c.Bfs.Addr)
err = ecode.BfsUploadStatusErr
return
}
header := resp.Header
code := header.Get("Code")
if code != strconv.Itoa(http.StatusOK) {
log.Error("strconv.Itoa err, code(%s) | url(%s)", code, d.c.Bfs.Addr)
err = ecode.BfsUploadCodeErr
return
}
location = header.Get("Location")
return
}
func authorize(key, secret, method, bucket string, fileName string, expire int64) (authorization string) {
var (
content string
mac hash.Hash
signature string
)
content = fmt.Sprintf("%s\n%s\n%s\n%d\n", method, bucket, fileName, 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,85 @@
package dao
import (
"context"
"net/http"
"time"
"go-common/app/admin/openplatform/sug/conf"
"go-common/library/cache/redis"
"go-common/library/database/sql"
"go-common/library/log"
xhttp "go-common/library/net/http/blademaster"
elastic "gopkg.in/olivere/elastic.v5"
)
// Dao dao
type Dao struct {
c *conf.Config
redis *redis.Pool
es *elastic.Client
client *http.Client
xclient *xhttp.Client
dbMall *sql.DB
dbTicket *sql.DB
}
// New init redis,es
func New(c *conf.Config) (dao *Dao) {
dao = &Dao{
c: c,
redis: redis.NewPool(c.Redis),
xclient: xhttp.NewClient(c.HTTPClient),
client: &http.Client{Timeout: time.Second * 5},
dbMall: sql.NewMySQL(c.DB.MallDB),
dbTicket: sql.NewMySQL(c.DB.TicketDB),
}
es, err := elastic.NewClient(
elastic.SetURL(c.Es.Addr...),
)
if err != nil {
panic(err)
}
dao.es = es
return
}
// Close close the resource.
func (d *Dao) Close() {
d.redis.Close()
}
// Ping dao ping
func (d *Dao) Ping(c context.Context) (err error) {
if err = d.dbTicket.Ping(c); err != nil {
log.Error("Ping ticket DB error(%v)", err)
return
}
if err = d.dbMall.Ping(c); err != nil {
log.Error("Ping mall DB error(%v)", err)
return
}
if err = d.pingESCluster(c); err != nil {
log.Error("es:ping", "ping %v", err)
return
}
redisConn := d.redis.Get(c)
defer redisConn.Close()
if _, err = redisConn.Do("SET", "ping", "pong"); err != nil {
redisConn.Close()
log.Error("redis.SET error(%v)", err)
return
}
return
}
// pingEsCluster ping es cluster
func (d *Dao) pingESCluster(ctx context.Context) (err error) {
_, _, err = d.es.Ping(d.c.Es.Addr[0]).Do(ctx)
if err != nil {
log.Error("Es:Ping", "%s:Ping error(%v)", d.c.Es.Addr[0], err)
return
}
return
}

View File

@@ -0,0 +1,156 @@
package dao
import (
"bufio"
"bytes"
"context"
"fmt"
"go-common/app/admin/openplatform/sug/model"
"go-common/library/log"
"image"
"image/color"
"image/draw"
"image/jpeg"
"image/png"
"io/ioutil"
"net/http"
"os"
"regexp"
"code.google.com/p/graphics-go/graphics"
"github.com/golang/freetype"
"golang.org/x/image/font"
"golang.org/x/image/math/fixed"
)
const (
_Width = 1125
_Height = 234
_HeaderLength = 168
)
var (
_RGBA = []int{244, 245, 247, 255}
_HeadArea = []int{36, 33, 204, 201}
_LabelArea = []int{234, 156, 348, 201}
_BriefText = []int{234, 72}
_NameText = []int{234, 129}
_BriefSize = 44
_NameSize = 36
_BriefRGBA = []int{33, 33, 33, 255}
_NameRGBA = []int{153, 153, 153, 255}
_BriefLimit = 1000
_NameLimit = 1000
)
// CreateItemPNG make a pic for sug
func (d *Dao) CreateItemPNG(item model.Item) (location string, err error) {
var r *image.NRGBA64
if r, err = d.makeBoard(item.Img); err != nil {
log.Error("Create picture board error(%v)", err)
return
}
if item.Brief == "" {
item.Brief = item.Name
}
r = d.drawText(r, item.Brief, item.Name)
buf := new(bytes.Buffer)
png.Encode(buf, r)
bufReader := bufio.NewReader(buf)
if location, err = d.Upload(context.TODO(), "image/png", fmt.Sprintf("season_sug_%s/%d.png", d.c.Env, item.ItemsID), bufReader); err != nil {
log.Error("Upload pic png error (%v)", err)
return
}
reg, _ := regexp.CompilePOSIX(`//(.*)+`)
location = reg.FindString(location)
return
}
func (d *Dao) makeBoard(headerURL string) (board *image.NRGBA64, err error) {
var header image.Image
radius, _ := os.Open(d.c.SourcePath + "radius.png")
label, _ := os.Open(d.c.SourcePath + "label.png")
defer radius.Close()
defer label.Close()
resp, err := http.Get("http:" + headerURL)
bs, err := ioutil.ReadAll(resp.Body)
if err != nil {
log.Error("ioutil.ReadAll img error(%v)", err)
return
}
imgType := http.DetectContentType(bs)
buf := bytes.NewBuffer(bs)
resp.Body = ioutil.NopCloser(buf)
if err != nil {
log.Error("http download head img error(%v)", err)
return
}
defer resp.Body.Close()
switch imgType {
case "image/png":
header, err = png.Decode(resp.Body)
if err != nil {
log.Error("png picture decode error(%v)", err)
return
}
case "image/jpeg", "image/jpg":
header, err = jpeg.Decode(resp.Body)
if err != nil {
log.Error("jpg picture decode err(%v)", err)
return
}
default:
log.Error("invaild picture type (%s)", headerURL)
return
}
board = image.NewNRGBA64(image.Rect(0, 0, _Width, _Height))
draw.Draw(board, board.Bounds(), image.White, image.ZP, draw.Src)
radiusPNG, _ := png.Decode(radius)
cover := image.NewRGBA64(image.Rect(0, 0, _HeaderLength, _HeaderLength))
border := image.NewNRGBA64(image.Rect(0, 0, _HeaderLength, _HeaderLength))
headBoard := image.NewRGBA64(image.Rect(0, 0, _HeaderLength, _HeaderLength))
draw.Draw(headBoard, headBoard.Bounds(), image.NewUniform(color.NRGBA{uint8(_RGBA[0]), uint8(_RGBA[1]), uint8(_RGBA[2]), uint8(_RGBA[3])}), image.ZP, draw.Over)
graphics.Thumbnail(border, radiusPNG)
graphics.Thumbnail(cover, header)
labelPNG, _ := png.Decode(label)
draw.Draw(headBoard, headBoard.Bounds(), cover, image.ZP, draw.Over)
draw.Draw(headBoard, headBoard.Bounds(), border, image.ZP, draw.Over)
draw.Draw(board, image.Rect(_HeadArea[0], _HeadArea[1], _HeadArea[2], _HeadArea[3]), headBoard, image.ZP, draw.Over)
draw.Draw(board, image.Rect(_LabelArea[0], _LabelArea[1], _LabelArea[2], _LabelArea[3]), labelPNG, image.ZP, draw.Over)
return
}
func (d *Dao) drawText(r *image.NRGBA64, brief string, name string) *image.NRGBA64 {
ptBrief := fixed.P(_BriefText[0], _BriefText[1])
ptName := fixed.P(_NameText[0], _NameText[1])
freetypeC := d.Context(r)
d.Text(freetypeC, brief, &ptBrief, _BriefSize, image.NewUniform(color.NRGBA{uint8(_BriefRGBA[0]), uint8(_BriefRGBA[1]), uint8(_BriefRGBA[2]), uint8(_BriefRGBA[3])}), fixed.I(_BriefLimit))
d.Text(freetypeC, name, &ptName, _NameSize, image.NewUniform(color.NRGBA{uint8(_NameRGBA[0]), uint8(_NameRGBA[1]), uint8(_NameRGBA[2]), uint8(_RGBA[3])}), fixed.I(_NameLimit))
return r
}
// Context get font for drawing
func (d *Dao) Context(r *image.NRGBA64) (c *freetype.Context) {
c = freetype.NewContext()
c.SetClip(r.Bounds())
c.SetDst(r)
c.SetHinting(font.HintingNone)
return
}
// Text draw letters on pic
func (d *Dao) Text(c *freetype.Context, s string, pt *fixed.Point26_6, size int, color image.Image, length fixed.Int26_6) (err error) {
c.SetFontSize(float64(size))
c.SetSrc(color)
ttf, _ := ioutil.ReadFile(d.c.SourcePath + "font.ttf")
font, _ := freetype.ParseFont(ttf)
c.SetFont(font)
for _, r := range s {
c.DrawString(string(r), *pt)
pt.X += font.HMetric(fixed.Int26_6(size*64), font.Index(r)).AdvanceWidth
if pt.X > length {
break
}
}
return
}

View File

@@ -0,0 +1,100 @@
package dao
import (
"context"
"fmt"
"encoding/json"
"go-common/app/admin/openplatform/sug/model"
"go-common/library/database/sql"
"go-common/library/log"
"time"
)
const (
_getItem = "SELECT `items_id`,`name`,`brief`,`img` FROM `items` WHERE `items_id` = ? AND `is_lastest_version` = 1"
_insertMatch = "INSERT INTO `sug_filter` (`season_id`,`items_id`,`type`,`sort`,`season_name`,`items_name`,`head_pic`,`sug_pic`) VALUE (?,?,?,?,?,?,?,?)"
_updateMatch = "UPDATE `sug_filter` SET `type` = ?,`season_name`=?,`items_name`=?,`sort`=?,`sug_pic`=? WHERE `season_id` = ? AND `items_id` = ?"
_matchExist = "SELECT `type` FROM `sug_filter` WHERE `season_id` = ? AND `items_id` = ?"
)
var _selectMatch = "SELECT `season_id`,`items_id`,`sort`,`season_name`,`items_name`,`head_pic`,`sug_pic` FROM `sug_filter` where type = 1"
// GetItem get mall items from db.
func (d *Dao) GetItem(c context.Context, itemsID int64) (item model.Item, err error) {
row := d.dbMall.QueryRow(c, _getItem, itemsID)
if err = row.Scan(&item.ItemsID, &item.Name, &item.Brief, &item.Img); err != nil {
log.Error("Get item %d error,err(%v)", itemsID, err)
return
}
if item.Brief == "" {
item.Brief = item.Name
item.Name = ""
}
var imgListArr []string
if err = json.Unmarshal([]byte(item.Img), &imgListArr); err != nil {
log.Error("get first img err[%s] (%v)", item.Img, err)
return
}
item.Img = imgListArr[0]
return
}
// UpdateMatch update match.
func (d *Dao) UpdateMatch(c context.Context, season model.Season, item model.Item, typeInt int8, sugPic string) (affect int64, err error) {
res, err := d.dbTicket.Exec(c, _updateMatch, typeInt, season.Title, item.Name, time.Now().Unix(), sugPic, season.ID, item.ItemsID)
if err != nil {
log.Error("row.exec error(%v)", err)
return
}
affect, err = res.RowsAffected()
return
}
// InsertMatch insert match.
func (d *Dao) InsertMatch(c context.Context, season model.Season, item model.Item, typeInt int8, sort int64, location string) (affect int64, err error) {
res, err := d.dbTicket.Exec(c, _insertMatch, season.ID, item.ItemsID, typeInt, sort, season.Title, item.Name, item.Img, location)
if err != nil {
log.Error("row.exec error(%v)", err)
return
}
affect, err = res.RowsAffected()
return
}
// GetMatchType get match type.
func (d *Dao) GetMatchType(c context.Context, seasonID, itemsID int64) (matchType int8, err error) {
row := d.dbTicket.QueryRow(c, _matchExist, seasonID, itemsID)
if err = row.Scan(&matchType); err != nil {
if err == sql.ErrNoRows {
return -1, nil
}
return
}
return
}
// SearchV2 search match from db
func (d *Dao) SearchV2(c context.Context, params *model.Search) (list []model.SugList, err error) {
var rows *sql.Rows
sqlStr := _selectMatch
if params.ItemsID > 0 {
sqlStr += fmt.Sprintf(" and items_id = %d", params.ItemsID)
}
if params.SeasonID > 0 {
sqlStr += fmt.Sprintf(" and season_id = %d", params.SeasonID)
}
if rows, err = d.dbTicket.Query(c, sqlStr); err != nil {
log.Error("d._selectMatchSQL.Query error(%v)", err)
return
}
for rows.Next() {
sug := new(model.SugList)
if err = rows.Scan(&sug.SeasonId, &sug.ItemsID, &sug.Score, &sug.SeasonName, &sug.ItemsName, &sug.PicURL, &sug.SugURL); err != nil {
log.Error("row.Scan() error(%v)", err)
continue
}
list = append(list, *sug)
}
return
}

View File

@@ -0,0 +1,19 @@
package dao
import "testing"
func TestDao_GetItem(t *testing.T) {
}
func TestDao_GetMatchType(t *testing.T) {
}
func TestDao_InsertMatch(t *testing.T) {
}
func TestDao_UpdateMatch(t *testing.T) {
}

View File

@@ -0,0 +1,74 @@
package dao
import (
"context"
"fmt"
//
"go-common/app/admin/openplatform/sug/model"
"go-common/library/cache/redis"
)
const (
_sugSeason = "SUG:SEASON:%d"
_sugItem = "SUGITEM:%d"
_expire = 93600
)
// SetSug set redis sug
func (d *Dao) SetSug(c context.Context, seasonID int64, ItemID int64, score int64) (err error) {
conn := d.redis.Get(c)
defer conn.Close()
key := fmt.Sprintf(_sugSeason, seasonID)
if err = conn.Send("ZADD", key, score, ItemID); err != nil {
return
}
if err = conn.Send("EXPIRE", key, _expire); err != nil {
return
}
if err = conn.Flush(); err != nil {
return
}
return
}
// DelSug del redis sug
func (d *Dao) DelSug(c context.Context, seasonID, itemsID int64) (err error) {
conn := d.redis.Get(c)
defer conn.Close()
if _, err = conn.Do("ZREM", fmt.Sprintf(_sugSeason, seasonID), itemsID); err != nil {
return
}
return
}
// SetItem set redis item
func (d *Dao) SetItem(c context.Context, item *model.Item, location string) (b bool, err error) {
conn := d.redis.Get(c)
defer conn.Close()
if err = conn.Send("HSET", fmt.Sprintf(_sugItem, item.ItemsID), "items_id", item.ItemsID); err != nil {
return
}
if err = conn.Send("HSET", fmt.Sprintf(_sugItem, item.ItemsID), "name", item.Name); err != nil {
return
}
if err = conn.Send("HSET", fmt.Sprintf(_sugItem, item.ItemsID), "brief", item.Brief); err != nil {
return
}
if err = conn.Send("HSET", fmt.Sprintf(_sugItem, item.ItemsID), "head", item.Img); err != nil {
return
}
if err = conn.Send("HSET", fmt.Sprintf(_sugItem, item.ItemsID), "pic", location); err != nil {
return
}
if err = conn.Send("EXPIRE", fmt.Sprintf(_sugItem, item.ItemsID), _expire); err != nil {
return
}
if err = conn.Flush(); err != nil {
return
}
if b, err = redis.Bool(conn.Receive()); err != nil {
return
}
conn.Receive()
return
}

View File

@@ -0,0 +1,19 @@
package dao
import "testing"
func TestDao_DelSug(t *testing.T) {
}
func TestDao_SetItem(t *testing.T) {
}
func TestDao_SetSug(t *testing.T) {
}
func TestDao_DelItem(t *testing.T) {
}

View File

@@ -0,0 +1,93 @@
package dao
import (
"bytes"
"context"
"encoding/json"
"fmt"
"strconv"
"go-common/app/admin/openplatform/sug/model"
"go-common/library/log"
"gopkg.in/olivere/elastic.v5"
"io/ioutil"
)
const (
_seasonIndex = "%s_sug_job_season"
_seasonType = "sug_job_season"
)
// GetSeason get season from es.
func (d *Dao) GetSeason(ctx context.Context, seasonID int64) (season model.Season, err error) {
seasonTermQuery := elastic.NewTermQuery("id", seasonID)
searchResult, err := d.es.Search().Index(fmt.Sprintf(_seasonIndex, d.c.Env)).Type(_seasonType).Query(seasonTermQuery).From(0).Size(1).Timeout("1s").Do(ctx)
if err != nil {
log.Error("es search error(%v)", err)
return
}
if searchResult.Hits.TotalHits > 0 {
for _, hit := range searchResult.Hits.Hits {
err = json.Unmarshal(*hit.Source, &season)
if err != nil {
log.Error("json.Unmarshal err(%v)", err)
return season, err
}
}
}
return
}
// SeasonList search season list.
func (d *Dao) SeasonList(ctx context.Context, params *model.SourceSearch) (list []model.Season, err error) {
query := elastic.NewBoolQuery()
matchQuery := elastic.NewMatchQuery("title", params.Keyword).Fuzziness("40")
sid, _ := strconv.Atoi(params.Keyword)
termQuery := elastic.NewMatchQuery("id", sid).Boost(100)
query.Should(matchQuery)
query.Should(termQuery)
searchResult, err := d.es.Search().Index(fmt.Sprintf(_seasonIndex, d.c.Env)).Type(_seasonType).Query(query).From(0).Size(10).Timeout("1s").Do(ctx)
if err != nil {
return
}
list = []model.Season{}
if searchResult.Hits.TotalHits > 0 {
var season model.Season
for _, hit := range searchResult.Hits.Hits {
err := json.Unmarshal(*hit.Source, &season)
if err != nil {
log.Error("json.Unmarshal error(%v)", err)
continue
}
list = append(list, season)
}
}
return
}
// ItemList mall items list from http.
func (d *Dao) ItemList(ctx context.Context, params *model.SourceSearch) (itemsList []model.Items, err error) {
query := make(map[string]interface{})
query["pageNum"] = params.PageNum
query["pageSize"] = params.PageSize
query["shopId"] = 0
query["keyword"] = params.Keyword
jsonQuery, _ := json.Marshal(query)
resp, err := d.client.Post(d.c.URL.ItemSearch, "application/json", bytes.NewReader(jsonQuery))
if err != nil {
log.Error("Request error(%v)", err)
return
}
HTTPResponse := model.HTTPResponse{}
bodyJSON, _ := ioutil.ReadAll(resp.Body)
if err = json.Unmarshal(bodyJSON, &HTTPResponse); err != nil {
log.Error("json.Unmarshal error(%v)", err)
}
if HTTPResponse.Code != 0 {
log.Error("Request (%s) search error(%v)", d.c.URL.ItemSearch, err)
return
}
itemsList = HTTPResponse.Data.List
return
}

View File

@@ -0,0 +1,39 @@
package(default_visibility = ["//visibility:public"])
load(
"@io_bazel_rules_go//go:def.bzl",
"go_library",
)
go_library(
name = "go_default_library",
srcs = [
"http.go",
"season.go",
],
importpath = "go-common/app/admin/openplatform/sug/http",
tags = ["automanaged"],
visibility = ["//visibility:public"],
deps = [
"//app/admin/openplatform/sug/conf:go_default_library",
"//app/admin/openplatform/sug/model:go_default_library",
"//app/admin/openplatform/sug/service:go_default_library",
"//library/log:go_default_library",
"//library/net/http/blademaster:go_default_library",
"//library/net/http/blademaster/middleware/permit: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,49 @@
package http
import (
"go-common/app/admin/openplatform/sug/conf"
"go-common/app/admin/openplatform/sug/service"
"go-common/library/log"
bm "go-common/library/net/http/blademaster"
"go-common/library/net/http/blademaster/middleware/permit"
)
var (
srv *service.Service
authSrv *permit.Permit
)
// Init init
func Init(c *conf.Config, s *service.Service) {
srv = s
authSrv = permit.New(c.Auth)
engine := bm.DefaultServer(c.BM)
router(engine)
if err := engine.Start(); err != nil {
log.Error("engine.Start error(%v)", err)
panic(err)
}
}
// outerRouter init outer router api path.
func router(e *bm.Engine) {
//init api
e.Ping(ping)
group := e.Group("/x/admin/sug")
{
seasonGroup := group.Group("/season")
{
seasonGroup.GET("/source/search", sourceSearch)
seasonGroup.GET("/match/search", search)
seasonGroup.POST("/match/operate", matchOperate)
}
}
}
// ping check server ok.
func ping(c *bm.Context) {
if err := srv.Ping(c); err != nil {
c.Error = err
c.AbortWithStatus(503)
}
}

View File

@@ -0,0 +1,24 @@
package http
import (
"go-common/app/admin/openplatform/sug/model"
bm "go-common/library/net/http/blademaster"
)
func matchOperate(c *bm.Context) {
v := &model.MatchOperate{}
c.Bind(v)
c.JSON(srv.MatchOperate(c, v))
}
func search(c *bm.Context) {
v := &model.Search{}
c.Bind(v)
c.JSON(srv.Search(c, v))
}
func sourceSearch(c *bm.Context) {
v := &model.SourceSearch{}
c.Bind(v)
c.JSON(srv.SourceSearch(c, v))
}

View File

@@ -0,0 +1,31 @@
package(default_visibility = ["//visibility:public"])
load(
"@io_bazel_rules_go//go:def.bzl",
"go_library",
)
go_library(
name = "go_default_library",
srcs = [
"params.go",
"sug.go",
],
importpath = "go-common/app/admin/openplatform/sug/model",
tags = ["automanaged"],
visibility = ["//visibility:public"],
)
filegroup(
name = "package-srcs",
srcs = glob(["**"]),
tags = ["automanaged"],
visibility = ["//visibility:private"],
)
filegroup(
name = "all-srcs",
srcs = [":package-srcs"],
tags = ["automanaged"],
visibility = ["//visibility:public"],
)

View File

@@ -0,0 +1,22 @@
package model
// SourceSearch params
type SourceSearch struct {
Type string `form:"type"`
Keyword string `form:"keyword"`
PageSize int `form:"pageSize"`
PageNum int `form:"pageNum"`
}
// Search params
type Search struct {
SeasonID int64 `form:"season_id"`
ItemsID int64 `form:"items_id"`
}
// MatchOperate params
type MatchOperate struct {
OpType int8 `form:"op_type"`
SeasonID int64 `form:"season_id"`
ItemsID int64 `form:"items_id"`
}

View File

@@ -0,0 +1,61 @@
package model
const (
// TypeSeason ...
TypeSeason = "season"
// TypeItems ...
TypeItems = "items"
)
// SugList sug list
type SugList struct {
SeasonId int64 `json:"season_id"`
SeasonName string `json:"season_name"`
ItemsID int64 `json:"items_id"`
ItemsName string `json:"items_name"`
PicURL string `json:"head_url"`
Score float64 `json:"score"`
SugURL string `json:"pic_url"`
}
// Season .
type Season struct {
ID int64 `json:"id"`
Title string `json:"title"`
}
// Item .
type Item struct {
ItemsID int64
Name string
Brief string
Img string
}
// Match .
type Match struct {
SeasonID int64
ItemsID int64
Type int
}
// Items .
type Items struct {
ItemsID int64 `json:"itemsId"`
Name string `json:"name"`
Img []string `json:"img"`
}
// ItemsList .
type ItemsList struct {
Total int `json:"total"`
PageNum int `json:"pageNum"`
PageSize int `json:"pageSize"`
List []Items `json:"list"`
}
// HTTPResponse .
type HTTPResponse struct {
Code int `json:"code"`
Data ItemsList `json:"data"`
}

View File

@@ -0,0 +1,47 @@
package(default_visibility = ["//visibility:public"])
load(
"@io_bazel_rules_go//go:def.bzl",
"go_test",
"go_library",
)
go_test(
name = "go_default_test",
srcs = ["season_test.go"],
embed = [":go_default_library"],
rundir = ".",
tags = ["automanaged"],
)
go_library(
name = "go_default_library",
srcs = [
"season.go",
"service.go",
],
importpath = "go-common/app/admin/openplatform/sug/service",
tags = ["automanaged"],
visibility = ["//visibility:public"],
deps = [
"//app/admin/openplatform/sug/conf:go_default_library",
"//app/admin/openplatform/sug/dao:go_default_library",
"//app/admin/openplatform/sug/model:go_default_library",
"//library/ecode: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,119 @@
package service
import (
"context"
"time"
"go-common/app/admin/openplatform/sug/model"
"go-common/library/ecode"
"go-common/library/log"
)
const (
_setup int8 = 1
_remove int8 = 0
_none int8 = -1
)
// SourceSearch search season or items.
func (s *Service) SourceSearch(c context.Context, params *model.SourceSearch) (interface{}, error) {
switch params.Type {
case model.TypeSeason:
return s.dao.SeasonList(c, params)
case model.TypeItems:
return s.dao.ItemList(c, params)
}
return nil, ecode.SugSearchTypeErr
}
// Search search season and items match list.
func (s *Service) Search(c context.Context, params *model.Search) (list []model.SugList, err error) {
list, err = s.dao.SearchV2(c, params)
if err != nil {
err = ecode.SugEsSearchErr
}
if listLen := len(list); listLen > 0 {
for i := 0; i < listLen-1; i++ {
for j := 0; j < listLen-i-1; j++ {
if list[j].Score < list[j+1].Score {
list[j], list[j+1] = list[j+1], list[j]
}
}
}
}
return
}
// MatchOperate match operate.
func (s *Service) MatchOperate(c context.Context, params *model.MatchOperate) (result interface{}, err error) {
item, err := s.dao.GetItem(c, params.ItemsID)
if err != nil {
err = ecode.SugItemNone
return
}
season, err := s.dao.GetSeason(c, params.SeasonID)
if err != nil || season.ID == 0 {
err = ecode.SugSeasonNone
return
}
switch params.OpType {
case _setup:
if _, err = s.AddMatch(c, item, season); err != nil {
err = ecode.SugOpErr
return
}
case _remove:
if err = s.DelMatch(c, item, season); err != nil {
err = ecode.SugOpErr
return
}
default:
err = ecode.SugOpTypeErr
}
return
}
// DbOperate db operate.
func (s *Service) DbOperate(c context.Context, op int8, item model.Item, season model.Season, location string) (err error) {
matchType, err := s.dao.GetMatchType(c, season.ID, item.ItemsID)
if err != nil {
return err
}
if matchType == _none {
if _, err = s.dao.InsertMatch(c, season, item, op, time.Now().Unix(), location); err != nil {
return err
}
}
if _, err = s.dao.UpdateMatch(c, season, item, op, location); err != nil {
return err
}
return
}
// AddMatch add match.
func (s *Service) AddMatch(c context.Context, item model.Item, season model.Season) (location string, err error) {
if location, _ = s.dao.CreateItemPNG(item); location == "" {
return
}
if err = s.DbOperate(c, _setup, item, season, location); err != nil {
return
}
if _, err := s.dao.SetItem(c, &item, location); err != nil {
log.Error("set item(%v) error(%v)", item, err)
}
if err := s.dao.SetSug(c, season.ID, item.ItemsID, time.Now().Unix()); err != nil {
log.Error("zAdd season(%v) error(%v)", season, err)
}
return
}
// DelMatch del match.
func (s *Service) DelMatch(c context.Context, item model.Item, season model.Season) (err error) {
if err = s.DbOperate(c, _remove, item, season, ""); err != nil {
return
}
if err = s.dao.DelSug(c, season.ID, item.ItemsID); err != nil {
log.Error("zRem item(%d) error(%v)", item, err)
}
return
}

View File

@@ -0,0 +1,19 @@
package service
import "testing"
func TestService_AddMatch(t *testing.T) {
}
func TestService_DbOperate(t *testing.T) {
}
func TestService_DelMatch(t *testing.T) {
}
func TestService_MatchOperate(t *testing.T) {
}

View File

@@ -0,0 +1,33 @@
package service
import (
"context"
"go-common/app/admin/openplatform/sug/conf"
"go-common/app/admin/openplatform/sug/dao"
)
// Service struct
type Service struct {
c *conf.Config
dao *dao.Dao
}
// New init
func New(c *conf.Config) (s *Service) {
s = &Service{
c: c,
dao: dao.New(c),
}
return s
}
// Ping Service
func (s *Service) Ping(c context.Context) (err error) {
return s.dao.Ping(c)
}
// Close Service
func (s *Service) Close() {
s.dao.Close()
}

Binary file not shown.

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.9 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.8 KiB