Initial commit

This commit is contained in:
Donny
2019-04-22 20:46:32 +08:00
commit 49ab8aadd1
25441 changed files with 4055000 additions and 0 deletions

View File

@@ -0,0 +1,27 @@
filegroup(
name = "package-srcs",
srcs = glob(["**"]),
tags = ["automanaged"],
visibility = ["//visibility:private"],
)
filegroup(
name = "all-srcs",
srcs = [
":package-srcs",
"//app/interface/main/web-goblin/cmd:all-srcs",
"//app/interface/main/web-goblin/conf:all-srcs",
"//app/interface/main/web-goblin/dao/share:all-srcs",
"//app/interface/main/web-goblin/dao/web:all-srcs",
"//app/interface/main/web-goblin/dao/wechat:all-srcs",
"//app/interface/main/web-goblin/http:all-srcs",
"//app/interface/main/web-goblin/model/share:all-srcs",
"//app/interface/main/web-goblin/model/web:all-srcs",
"//app/interface/main/web-goblin/model/wechat:all-srcs",
"//app/interface/main/web-goblin/service/share:all-srcs",
"//app/interface/main/web-goblin/service/web:all-srcs",
"//app/interface/main/web-goblin/service/wechat:all-srcs",
],
tags = ["automanaged"],
visibility = ["//visibility:public"],
)

View File

@@ -0,0 +1,47 @@
### web-goblin
#### Version 1.3.4
##### Features
> 1.增加bilibili招聘接口
#### Version 1.3.3
##### Features
> 1.全网搜索吐出字段新增评论总数,点赞总数
#### Version 1.3.2
##### Features
> 1.全网搜索httpclient单独分开
#### Version 1.3.1
##### Features
> 1.吐出的weburl加上标识
#### Version 1.3.0
##### Features
> 1.新增微信二维码接口
#### Version 1.2.0
##### Features
> 1.新增channel接口
#### Version 1.1.1
##### Features
> 1.添加全网搜索接口
#### Version 1.1.0
##### Features
> 1.add share api
#### Version 1.0.2
##### Features
> 1.使用bm
> 2.改用metadata.RemoteIP方法
#### Version 1.0.1
##### Features
> 1.修改全量接口为短视频
#### Version 1.0.0
##### Features
> 1.项目初始化
> 2.新增小米搜索全量接口

View File

@@ -0,0 +1,14 @@
# Owner
liweijia
renwei
# Author
guanyanliang
wuhao02
liuxuan
liweijia
# Reviewer
guanyanliang
liweijia
zhapuyu

View File

@@ -0,0 +1,20 @@
# See the OWNERS docs at https://go.k8s.io/owners
approvers:
- guanyanliang
- liuxuan
- liweijia
- renwei
- wuhao02
labels:
- interface
- interface/main/web-goblin
- main
options:
no_parent_owners: true
reviewers:
- guanyanliang
- liuxuan
- liweijia
- wuhao02
- zhapuyu

View File

@@ -0,0 +1,18 @@
#### web-goblin
##### 项目简介
> 1.提供web端附加功能接口
##### 编译环境
> 请使用golang v1.7.x以上版本编译执行。
##### 依赖包
> 1.公共包go-common
##### 编译执行
> 在主目录执行go build。
> 编译后可执行 ./cmd/cmd -conf web-goblin-test.toml 使用项目本地配置文件启动服务。
> 也可执行 ./web-goblin -conf_appid=web-goblin -conf_version=v2.1.0 -conf_host=172.16.33.134:9011 -conf_path=/data/conf/web-goblin -conf_env=10 -conf_token=*** 使用配置中心测试环境配置启动服务如无法启动可检查token是否正确。
##### 特别说明
> http接口文档可参考 http://info.bilibili.co/pages/viewpage.action?pageId=9843305

View File

@@ -0,0 +1,43 @@
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 = ["web-goblin-test.toml"],
importpath = "go-common/app/interface/main/web-goblin/cmd",
tags = ["automanaged"],
visibility = ["//visibility:public"],
deps = [
"//app/interface/main/web-goblin/conf:go_default_library",
"//app/interface/main/web-goblin/http: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,42 @@
package main
import (
"flag"
"os"
"os/signal"
"syscall"
"go-common/app/interface/main/web-goblin/conf"
"go-common/app/interface/main/web-goblin/http"
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 {
panic(err)
}
log.Init(conf.Conf.Log)
defer log.Close()
log.Info("web-goblin start")
trace.Init(conf.Conf.Tracer)
defer trace.Close()
ecode.Init(conf.Conf.Ecode)
http.Init(conf.Conf)
c := make(chan os.Signal, 1)
signal.Notify(c, syscall.SIGHUP, syscall.SIGQUIT, syscall.SIGTERM, syscall.SIGINT)
for {
s := <-c
log.Info("web-goblin get a signal %s", s.String())
switch s {
case syscall.SIGQUIT, syscall.SIGTERM, syscall.SIGINT:
log.Info("web-goblin exit")
return
case syscall.SIGHUP:
default:
return
}
}
}

View File

@@ -0,0 +1,120 @@
[log]
dir = "/data/log/web-goblin/"
[app]
key = "7c7ac0db1aa05587"
secret = "9a6d62d93290c5f771ad381e9ca23f26"
[memcache]
name = "web-goblin"
proto = "tcp"
addr = ""
active = 50
idle = 10
dialTimeout = "1s"
readTimeout = "1s"
writeTimeout = "1s"
idleTimeout = "10s"
[db]
[db.goblin]
addr = "172.22.34.101:3308"
dsn = "goblin_reader:apKhkA0X1L6UnWZ25rGcfVo4FizYQ3I9@tcp(172.22.34.101:3308)/bilibili_goblin?timeout=5s&readTimeout=5s&writeTimeout=5s&parseTime=true&loc=Local&charset=utf8,utf8mb4"
active = 5
idle = 2
idleTimeout = "4h"
queryTimeout = "100ms"
execTimeout = "100ms"
tranTimeout = "200ms"
[db.goblin.breaker]
window = "3s"
sleep = "100ms"
bucket = 10
ratio = 0.5
request = 100
[db.show]
addr = "172.16.33.205:3308"
dsn = "test:test@tcp(172.16.33.205:3308)/bilibili_show?timeout=5s&readTimeout=5s&writeTimeout=5s&parseTime=true&loc=Local&charset=utf8,utf8mb4"
active = 5
idle = 2
idleTimeout = "4h"
queryTimeout = "100ms"
execTimeout = "100ms"
tranTimeout = "200ms"
[db.show.breaker]
window = "3s"
sleep = "100ms"
bucket = 10
ratio = 0.5
request = 100
[redis]
name = "web-goblin"
proto = "tcp"
addr = "172.22.33.137:6819"
idle = 10
active = 10
dialTimeout = "1s"
readTimeout = "1s"
writeTimeout = "1s"
idleTimeout = "10s"
[httpclient]
key = "6aa4286456d16b97"
secret = "351cf022e1ae8296109c3c524faafcc8"
dial = "1s"
timeout = "1s"
keepAlive = "60s"
timer = 1000
[tagRPC]
timeout = "1s"
[suitRPC]
timeout = "1s"
[archiveRPC]
timeout = "1s"
[rule]
gid = 6
chCardInterval = "1m"
[host]
wechat = "https://api.weixin.qq.com"
pgcURI = "http://bangumi.bilibili.co"
[wechat]
appid = "wx7564fd5313d24844"
secret = "7f19aa432134132bd15248863254f117"
[[pendants]]
pid = 1
level = 7
[[pendants]]
pid = 2
level = 15
[[pendants]]
pid = 3
level = 28
[searchClient]
key = "6aa4286456d16b97"
secret = "351cf022e1ae8296109c3c524faafcc8"
dial = "2s"
timeout = "30s"
keepAlive = "60s"
timer = 1000
[outSearch]
rspan = 3600
acPgcFull = ["youku","iqiyi","tencent","acfun"]
acPgcIncre = ["youku","iqiyi","tencent","acfun"]
acUgcFull = ["youku","iqiyi","tencent","acfun"]
acUgcIncre = ["youku","iqiyi","tencent","acfun"]
dealCommFull = 100
dealLikeFull = 200
[recruit]
mokaURI = "https://api.mokahr.com"
orgid = "bilibili"

View File

@@ -0,0 +1,43 @@
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/interface/main/web-goblin/conf",
tags = ["automanaged"],
visibility = ["//visibility:public"],
deps = [
"//library/cache/memcache:go_default_library",
"//library/cache/redis:go_default_library",
"//library/conf:go_default_library",
"//library/database/elastic:go_default_library",
"//library/database/sql:go_default_library",
"//library/ecode/tip:go_default_library",
"//library/log:go_default_library",
"//library/net/http/blademaster:go_default_library",
"//library/net/http/blademaster/middleware/auth:go_default_library",
"//library/net/rpc: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,162 @@
package conf
import (
"errors"
"flag"
"go-common/library/cache/memcache"
"go-common/library/cache/redis"
"go-common/library/conf"
"go-common/library/database/elastic"
"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/auth"
"go-common/library/net/rpc"
"go-common/library/net/trace"
"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
Tracer *trace.Config
Memcache *memcache.Config
Ecode *ecode.Config
// ArchiveRPC
ArchiveRPC *rpc.ClientConfig
TagRPC *rpc.ClientConfig
SuitRPC *rpc.ClientConfig
AccountRPC *rpc.ClientConfig
// auth
Auth *auth.Config
// Mysql
DB *DB
// Redis
Redis *Redis
// http client
HTTPClient *bm.ClientConfig
SearchClient *bm.ClientConfig
// Rule
Rule *Rule
// Pendants
Pendants []*Pendant
// Host
Host host
Wechat wechat
Es *elastic.Config
OutSearch OutSearch
Recruit *Recruit
}
// Recruit .
type Recruit struct {
MokaURI string
Orgid string
}
// OutSearch search out .
type OutSearch struct {
Rspan int64
AcPgcFull []string
AcPgcIncre []string
AcUgcFull []string
AcUgcIncre []string
DealCommFull int32
DealLikeFull int32
}
// Redis redis struct .
type Redis struct {
*redis.Config
}
// Rule .
type Rule struct {
Gid int64
ChCardInterval time.Duration
}
// Pendant .
type Pendant struct {
Pid int64
Level int64
}
// DB .
type DB struct {
Goblin *sql.Config
Show *sql.Config
}
type host struct {
Wechat string
PgcURI string
}
type wechat struct {
AppID 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,40 @@
package(default_visibility = ["//visibility:public"])
load(
"@io_bazel_rules_go//go:def.bzl",
"go_library",
)
go_library(
name = "go_default_library",
srcs = [
"dao.go",
"mysql.go",
"redis.go",
],
importpath = "go-common/app/interface/main/web-goblin/dao/share",
tags = ["automanaged"],
visibility = ["//visibility:public"],
deps = [
"//app/interface/main/web-goblin/conf:go_default_library",
"//app/interface/main/web-goblin/model/share:go_default_library",
"//library/cache/redis:go_default_library",
"//library/database/sql:go_default_library",
"//library/log:go_default_library",
"//library/stat/prom:go_default_library",
],
)
filegroup(
name = "package-srcs",
srcs = glob(["**"]),
tags = ["automanaged"],
visibility = ["//visibility:private"],
)
filegroup(
name = "all-srcs",
srcs = [":package-srcs"],
tags = ["automanaged"],
visibility = ["//visibility:public"],
)

View File

@@ -0,0 +1,46 @@
package share
import (
"context"
"go-common/app/interface/main/web-goblin/conf"
"go-common/library/cache/redis"
"go-common/library/database/sql"
"go-common/library/log"
"go-common/library/stat/prom"
)
// Dao dao struct.
type Dao struct {
// config
c *conf.Config
// db
db *sql.DB
// redis
redis *redis.Pool
}
// New new dao.
func New(c *conf.Config) (d *Dao) {
d = &Dao{
// config
c: c,
db: sql.NewMySQL(c.DB.Goblin),
redis: redis.NewPool(c.Redis.Config),
}
return
}
// Ping ping dao
func (d *Dao) Ping(c context.Context) (err error) {
if err = d.db.Ping(c); err != nil {
return
}
return
}
// PromError stat and log.
func PromError(name string, format string, args ...interface{}) {
prom.BusinessErrCount.Incr(name)
log.Error(format, args...)
}

View File

@@ -0,0 +1,44 @@
package share
import (
"context"
"fmt"
"time"
shamdl "go-common/app/interface/main/web-goblin/model/share"
xsql "go-common/library/database/sql"
"go-common/library/log"
)
const (
_shaSub = 100
_shasSQL = "SELECT id,mid,day_count,cycle,share_date,ctime,mtime FROM gb_share_%s WHERE mid = ? and cycle = ?"
)
func shaHit(mid int64) string {
return fmt.Sprintf("%02d", mid%_shaSub)
}
// Shares get shares.
func (d *Dao) Shares(c context.Context, mid int64) (res []*shamdl.Share, err error) {
var (
rows *xsql.Rows
)
if rows, err = d.db.Query(c, fmt.Sprintf(_shasSQL, shaHit(mid)), mid, time.Now().Format("200601")); err != nil {
log.Error("Shares d.db.Query(%d) error(%v)", mid, err)
return
}
defer rows.Close()
for rows.Next() {
r := new(shamdl.Share)
if err = rows.Scan(&r.ID, &r.Mid, &r.DayCount, &r.Cycle, &r.ShareDate, &r.Ctime, &r.Mtime); err != nil {
log.Error("Shares:row.Scan() error(%v)", err)
return
}
res = append(res, r)
}
if err = rows.Err(); err != nil {
log.Error("rows.Err() error(%v)", err)
}
return
}

View File

@@ -0,0 +1,60 @@
package share
import (
"context"
"fmt"
"go-common/library/cache/redis"
"go-common/library/log"
)
const _keySha = "sm_%d"
func keyShare(mid int64) string {
return fmt.Sprintf(_keySha, mid)
}
// SharesCache get shares from cache.
func (d *Dao) SharesCache(c context.Context, mid int64) (res map[string]int64, err error) {
var (
key = keyShare(mid)
conn = d.redis.Get(c)
)
defer conn.Close()
if res, err = redis.Int64Map(conn.Do("HGETALL", key)); err != nil {
log.Error("HGETALL %v failed error(%v)", key, err)
}
return
}
// SetSharesCache back cache from db.
func (d *Dao) SetSharesCache(c context.Context, expire int, mid int64, shares map[string]int64) (err error) {
var (
key = keyShare(mid)
conn = d.redis.Get(c)
)
defer conn.Close()
args := redis.Args{}.Add(key)
for k, v := range shares {
args = args.Add(k).Add(v)
}
if err = conn.Send("HMSET", args...); err != nil {
log.Error("conn.Send(HMSET, %s, %d) error(%v)", key, err)
return
}
if err = conn.Send("EXPIRE", key, expire); err != nil {
log.Error("conn.Send(Expire, %s, %d) error(%v)", key, expire, err)
return
}
if err = conn.Flush(); err != nil {
log.Error("conn.Flush error(%v)", err)
return
}
for i := 0; i < 2; i++ {
if _, err = conn.Receive(); err != nil {
log.Error("conn.Receive() error(%v)", err)
return
}
}
return
}

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 = [
"channel_test.go",
"dao_test.go",
"pgc_test.go",
"recruit_test.go",
"ugc_test.go",
],
embed = [":go_default_library"],
tags = ["automanaged"],
deps = [
"//app/interface/main/web-goblin/conf:go_default_library",
"//app/interface/main/web-goblin/model/web: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 = [
"channel.go",
"dao.go",
"pgc.go",
"recruit.go",
"ugc.go",
],
importpath = "go-common/app/interface/main/web-goblin/dao/web",
tags = ["automanaged"],
visibility = ["//visibility:public"],
deps = [
"//app/interface/main/web-goblin/conf:go_default_library",
"//app/interface/main/web-goblin/model/web:go_default_library",
"//library/database/elastic:go_default_library",
"//library/database/sql:go_default_library",
"//library/ecode:go_default_library",
"//library/log:go_default_library",
"//library/net/http/blademaster:go_default_library",
"//library/net/metadata:go_default_library",
"//library/stat/prom:go_default_library",
],
)
filegroup(
name = "package-srcs",
srcs = glob(["**"]),
tags = ["automanaged"],
visibility = ["//visibility:private"],
)
filegroup(
name = "all-srcs",
srcs = [":package-srcs"],
tags = ["automanaged"],
visibility = ["//visibility:public"],
)

View File

@@ -0,0 +1,31 @@
package web
import (
"context"
"time"
"go-common/app/interface/main/web-goblin/model/web"
)
const _cardSQL = "SELECT id,title,tag_id,card_type,card_value,recommand_reason,recommand_state,priority FROM channel_card WHERE stime<? AND etime>? AND `check`=2 AND is_delete=0 ORDER BY priority DESC"
// ChCard channel card.
func (d *Dao) ChCard(ctx context.Context, now time.Time) (res map[int64][]*web.ChCard, err error) {
res = map[int64][]*web.ChCard{}
rows, err := d.showDB.Query(ctx, _cardSQL, now, now)
if err != nil {
return
}
defer rows.Close()
for rows.Next() {
c := &web.ChCard{}
if err = rows.Scan(&c.ID, &c.Title, &c.ChannelID, &c.Type, &c.Value, &c.Reason, &c.ReasonType, &c.Pos); err != nil {
return
}
res[c.ChannelID] = append(res[c.ChannelID], c)
}
if err = rows.Err(); err != nil {
return
}
return
}

View File

@@ -0,0 +1,22 @@
package web
import (
"context"
"testing"
"time"
"github.com/smartystreets/goconvey/convey"
)
func TestWebChCard(t *testing.T) {
convey.Convey("ChCard", t, func(c convey.C) {
var (
ctx = context.Background()
now = time.Now()
)
res, err := d.ChCard(ctx, now)
convey.So(err, convey.ShouldBeNil)
convey.So(res, convey.ShouldNotBeNil)
convey.Printf("%+v", res)
})
}

View File

@@ -0,0 +1,56 @@
package web
import (
"context"
"go-common/app/interface/main/web-goblin/conf"
"go-common/library/database/elastic"
"go-common/library/database/sql"
"go-common/library/log"
bm "go-common/library/net/http/blademaster"
"go-common/library/stat/prom"
)
const (
_pgcFullURL = "/ext/internal/archive/channel/content"
_pgcIncreURL = "/ext/internal/archive/channel/content/change"
)
// Dao dao .
type Dao struct {
c *conf.Config
db *sql.DB
showDB *sql.DB
httpR *bm.Client
pgcFullURL, pgcIncreURL string
ela *elastic.Elastic
}
// New init mysql db .
func New(c *conf.Config) (dao *Dao) {
dao = &Dao{
c: c,
db: sql.NewMySQL(c.DB.Goblin),
showDB: sql.NewMySQL(c.DB.Show),
httpR: bm.NewClient(c.SearchClient),
pgcFullURL: c.Host.PgcURI + _pgcFullURL,
pgcIncreURL: c.Host.PgcURI + _pgcIncreURL,
ela: elastic.NewElastic(c.Es),
}
return
}
// Close close the resource .
func (d *Dao) Close() {
}
// Ping dao ping .
func (d *Dao) Ping(c context.Context) error {
return nil
}
// PromError stat and log .
func PromError(name string, format string, args ...interface{}) {
prom.BusinessErrCount.Incr(name)
log.Error(format, args...)
}

View File

@@ -0,0 +1,44 @@
package web
import (
"flag"
"os"
"strings"
"testing"
"go-common/app/interface/main/web-goblin/conf"
"gopkg.in/h2non/gock.v1"
)
var (
d *Dao
)
func TestMain(m *testing.M) {
if os.Getenv("DEPLOY_ENV") != "" {
flag.Set("app_id", "main.web-svr.web-goblin")
flag.Set("conf_token", "b2850ed0834343a9e435809857f5670d")
flag.Set("tree_id", "41730")
flag.Set("conf_version", "docker-1")
flag.Set("deploy_env", "uat")
flag.Set("conf_host", "config.bilibili.co")
flag.Set("conf_path", "/tmp")
flag.Set("region", "sh")
flag.Set("zone", "sh001")
} else {
flag.Set("conf", "../../cmd/web-goblin-test.toml")
}
flag.Parse()
if err := conf.Init(); err != nil {
panic(err)
}
d = New(conf.Conf)
os.Exit(m.Run())
}
func httpMock(method, url string) *gock.Request {
r := gock.New(url)
r.Method = strings.ToUpper(method)
return r
}

View File

@@ -0,0 +1,65 @@
package web
import (
"context"
"net/url"
"strconv"
"go-common/library/ecode"
"go-common/library/log"
"go-common/library/net/metadata"
)
// PgcFull pgc full .
func (d *Dao) PgcFull(ctx context.Context, tp int, pn, ps int64, source string) (res interface{}, err error) {
var (
param = url.Values{}
ip = metadata.String(ctx, metadata.RemoteIP)
rs struct {
Code int `json:"code"`
Data interface{} `json:"result"`
}
)
param.Set("bsource", source)
param.Set("season_type", strconv.Itoa(tp))
param.Set("page_no", strconv.FormatInt(pn, 10))
param.Set("page_size", strconv.FormatInt(ps, 10))
if err = d.httpR.Get(ctx, d.pgcFullURL, ip, param, &rs); err != nil {
log.Error("d.httpR.Get err(%v)", err)
return
}
if rs.Code != ecode.OK.Code() {
err = ecode.Int(rs.Code)
return
}
res = rs.Data
return
}
// PgcIncre pgc increment .
func (d *Dao) PgcIncre(ctx context.Context, tp int, pn, ps, start, end int64, source string) (res interface{}, err error) {
var (
param = url.Values{}
ip = metadata.String(ctx, metadata.RemoteIP)
)
var rs struct {
Code int `json:"code"`
Data interface{} `json:"result"`
}
param.Set("bsource", source)
param.Set("season_type", strconv.Itoa(tp))
param.Set("page_no", strconv.FormatInt(pn, 10))
param.Set("page_size", strconv.FormatInt(ps, 10))
param.Set("start_ts", strconv.FormatInt(start, 10))
param.Set("end_ts", strconv.FormatInt(end, 10))
if err = d.httpR.Get(ctx, d.pgcIncreURL, ip, param, &rs); err != nil {
log.Error("d.httpR.Get url(%s) err(%s)", d.pgcIncreURL+"?"+param.Encode(), err)
return
}
if rs.Code != ecode.OK.Code() {
err = ecode.Int(rs.Code)
return
}
res = rs.Data
return
}

View File

@@ -0,0 +1,48 @@
package web
import (
"context"
"testing"
"github.com/smartystreets/goconvey/convey"
)
func TestWebPgcFull(t *testing.T) {
convey.Convey("PgcFull", t, func(ctx convey.C) {
var (
c = context.Background()
tp = int(1)
pn = int64(1)
ps = int64(10)
source = "youku"
)
ctx.Convey("When everything goes positive", func(ctx convey.C) {
res, err := d.PgcFull(c, tp, pn, ps, source)
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 TestWebPgcIncre(t *testing.T) {
convey.Convey("PgcIncre", t, func(ctx convey.C) {
var (
c = context.Background()
tp = int(2)
pn = int64(1)
ps = int64(10)
start = int64(1505876448)
end = int64(1505876450)
source = "youku"
)
ctx.Convey("When everything goes positive", func(ctx convey.C) {
res, err := d.PgcIncre(c, tp, pn, ps, start, end, source)
ctx.Convey("Then err should be nil.res should not be nil.", func(ctx convey.C) {
ctx.So(err, convey.ShouldBeNil)
ctx.So(res, convey.ShouldNotBeNil)
})
})
})
}

View File

@@ -0,0 +1,37 @@
package web
import (
"context"
"encoding/json"
xhttp "net/http"
"net/url"
"go-common/app/interface/main/web-goblin/model/web"
"go-common/library/ecode"
"go-common/library/log"
)
// Recruit .
func (d *Dao) Recruit(ctx context.Context, param url.Values, route *web.Params) (res json.RawMessage, err error) {
var (
req *xhttp.Request
rs json.RawMessage
mokaURI = d.c.Recruit.MokaURI + "/" + route.Route + "/" + d.c.Recruit.Orgid
)
if route.JobID != "" {
mokaURI = mokaURI + "/" + route.JobID
}
param.Del("route")
param.Del("job_id")
if req, err = xhttp.NewRequest("GET", mokaURI+"?"+param.Encode(), nil); err != nil {
log.Error("Recruit xhttp.NewRequest url(%s) error(%v)", mokaURI, err)
return
}
if err = d.httpR.Do(ctx, req, &rs); err != nil {
log.Error("Recruit d.httpR.Do url(%s) error(%v)", mokaURI, err)
err = ecode.NothingFound
return
}
res = rs
return
}

View File

@@ -0,0 +1,32 @@
package web
import (
"context"
"net/url"
"testing"
"go-common/app/interface/main/web-goblin/model/web"
"github.com/smartystreets/goconvey/convey"
)
func TestWebRecruit(t *testing.T) {
convey.Convey("Recruit", t, func(ctx convey.C) {
var (
c = context.Background()
params = url.Values{}
ru = &web.Params{
Route: "v1/jobs",
}
)
params.Set("mode", "social")
ctx.Convey("When everything gose positive", func(ctx convey.C) {
httpMock("GET", "https://api.mokahr.com/v1/jobs/bilibili").Reply(200).JSON(`{jobs:[], "total": 245}`)
res, err := d.Recruit(c, params, ru)
ctx.Convey("Then err should be nil.res should not be nil.", func(ctx convey.C) {
ctx.So(err, convey.ShouldBeNil)
ctx.So(res, convey.ShouldNotBeNil)
})
})
})
}

View File

@@ -0,0 +1,31 @@
package web
import (
"context"
"time"
webmdl "go-common/app/interface/main/web-goblin/model/web"
"go-common/library/database/elastic"
"go-common/library/log"
)
const _ugcIncre = "web_goblin"
// UgcIncre ugc increment .
func (d *Dao) UgcIncre(ctx context.Context, pn, ps int, start, end int64) (res []*webmdl.SearchAids, err error) {
var (
startStr, endStr string
rs struct {
Result []*webmdl.SearchAids `json:"result"`
}
)
startStr = time.Unix(start, 0).Format("2006-01-02 15:04:05")
endStr = time.Unix(end, 0).Format("2006-01-02 15:04:05")
r := d.ela.NewRequest(_ugcIncre).WhereRange("mtime", startStr, endStr, elastic.RangeScopeLoRo).Fields("aid").Fields("action").Index(_ugcIncre).Pn(pn).Ps(ps)
if err = r.Scan(ctx, &rs); err != nil {
log.Error("r.Scan error(%v)", err)
return
}
res = rs.Result
return
}

View File

@@ -0,0 +1,27 @@
package web
import (
"context"
"testing"
"github.com/smartystreets/goconvey/convey"
)
func TestWebUgcIncre(t *testing.T) {
convey.Convey("UgcIncre", t, func(ctx convey.C) {
var (
c = context.Background()
pn = int(1)
ps = int(10)
start = int64(1505876448)
end = int64(1505876450)
)
ctx.Convey("When everything goes positive", func(ctx convey.C) {
res, err := d.UgcIncre(c, pn, ps, start, end)
ctx.Convey("Then err should be nil.res should not be nil.", func(ctx convey.C) {
ctx.So(err, convey.ShouldBeNil)
ctx.So(res, convey.ShouldNotBeNil)
})
})
})
}

View File

@@ -0,0 +1,62 @@
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",
"qrcode_test.go",
],
embed = [":go_default_library"],
rundir = ".",
tags = ["automanaged"],
deps = [
"//app/interface/main/web-goblin/conf:go_default_library",
"//app/interface/main/web-goblin/model/wechat:go_default_library",
"//library/ecode:go_default_library",
"//vendor/github.com/smartystreets/goconvey/convey:go_default_library",
],
)
go_library(
name = "go_default_library",
srcs = [
"cache.go",
"dao.cache.go",
"dao.go",
"qrcode.go",
],
importpath = "go-common/app/interface/main/web-goblin/dao/wechat",
tags = ["automanaged"],
visibility = ["//visibility:public"],
deps = [
"//app/interface/main/web-goblin/conf:go_default_library",
"//app/interface/main/web-goblin/model/wechat:go_default_library",
"//library/cache:go_default_library",
"//library/cache/redis:go_default_library",
"//library/ecode:go_default_library",
"//library/log:go_default_library",
"//library/net/http/blademaster:go_default_library",
"//library/net/metadata:go_default_library",
"//library/stat/prom:go_default_library",
],
)
filegroup(
name = "package-srcs",
srcs = glob(["**"]),
tags = ["automanaged"],
visibility = ["//visibility:private"],
)
filegroup(
name = "all-srcs",
srcs = [":package-srcs"],
tags = ["automanaged"],
visibility = ["//visibility:public"],
)

View File

@@ -0,0 +1,13 @@
package wechat
import (
"context"
"go-common/app/interface/main/web-goblin/model/wechat"
)
//go:generate $GOPATH/src/go-common/app/tool/cache/gen
type _cache interface {
// cache
AccessToken(c context.Context) (*wechat.AccessToken, error)
}

View File

@@ -0,0 +1,49 @@
// Code generated by $GOPATH/src/go-common/app/tool/cache/gen. DO NOT EDIT.
/*
Package wechat is a generated cache proxy package.
It is generated from:
type _cache interface {
// cache
AccessToken(c context.Context) (*wechat.AccessToken, error)
}
*/
package wechat
import (
"context"
"go-common/app/interface/main/web-goblin/model/wechat"
"go-common/library/net/metadata"
"go-common/library/stat/prom"
)
var _ _cache
// AccessToken get data from cache if miss will call source method, then add to cache.
func (d *Dao) AccessToken(c context.Context) (res *wechat.AccessToken, err error) {
addCache := true
res, err = d.CacheAccessToken(c)
if err != nil {
addCache = false
err = nil
}
if res != nil {
prom.CacheHit.Incr("AccessToken")
return
}
prom.CacheMiss.Incr("AccessToken")
res, err = d.RawAccessToken(c)
if err != nil {
return
}
var miss = res
if !addCache {
return
}
d.cache.Save(func() {
d.AddCacheAccessToken(metadata.WithContext(c), miss)
})
return
}

View File

@@ -0,0 +1,36 @@
package wechat
import (
"go-common/app/interface/main/web-goblin/conf"
"go-common/library/cache"
"go-common/library/cache/redis"
bm "go-common/library/net/http/blademaster"
)
// Dao dao struct.
type Dao struct {
// config
c *conf.Config
// redis
redis *redis.Pool
// httpClient
httpClient *bm.Client
// url
wxAccessTokenURL string
wxQrcodeURL string
cache *cache.Cache
}
// New new dao.
func New(c *conf.Config) (d *Dao) {
d = &Dao{
// config
c: c,
redis: redis.NewPool(c.Redis.Config),
httpClient: bm.NewClient(c.HTTPClient),
cache: cache.New(1, 1024),
}
d.wxAccessTokenURL = d.c.Host.Wechat + _accessTokenURI
d.wxQrcodeURL = d.c.Host.Wechat + _qrcodeURI
return
}

View File

@@ -0,0 +1,35 @@
package wechat
import (
"flag"
"os"
"testing"
"go-common/app/interface/main/web-goblin/conf"
)
var (
d *Dao
)
func TestMain(m *testing.M) {
if os.Getenv("DEPLOY_ENV") != "" {
flag.Set("app_id", "main.web-svr.web-goblin")
flag.Set("conf_token", "b2850ed0834343a9e435809857f5670d")
flag.Set("tree_id", "41730")
flag.Set("conf_version", "docker-1")
flag.Set("deploy_env", "uat")
flag.Set("conf_host", "config.bilibili.co")
flag.Set("conf_path", "/tmp")
flag.Set("region", "sh")
flag.Set("zone", "sh001")
} else {
flag.Set("conf", "../../cmd/web-goblin-test.toml")
}
flag.Parse()
if err := conf.Init(); err != nil {
panic(err)
}
d = New(conf.Conf)
os.Exit(m.Run())
}

View File

@@ -0,0 +1,137 @@
package wechat
import (
"context"
"encoding/json"
"net/http"
"net/url"
"strings"
"go-common/app/interface/main/web-goblin/model/wechat"
"go-common/library/cache/redis"
"go-common/library/ecode"
"go-common/library/log"
)
const (
_accessTokenKey = "a_t_k"
_accessTokenURI = "/cgi-bin/token"
_qrcodeURI = "/wxa/getwxacodeunlimit"
)
// RawAccessToken get wechat access token.
func (d *Dao) RawAccessToken(c context.Context) (data *wechat.AccessToken, err error) {
params := url.Values{}
params.Set("grant_type", "client_credential")
params.Set("appid", d.c.Wechat.AppID)
params.Set("secret", d.c.Wechat.Secret)
var req *http.Request
if req, err = http.NewRequest(http.MethodGet, d.wxAccessTokenURL+"?"+params.Encode(), nil); err != nil {
log.Error("AccessToken http.NewRequest error(%v)", err)
return
}
var res struct {
Errcode int `json:"errcode"`
Errmsg string `json:"errmsg"`
AccessToken string `json:"access_token"`
ExpiresIN int64 `json:"expires_in"`
}
if err = d.httpClient.Do(c, req, &res); err != nil {
log.Error("AccessToken d.httpClient.Do error(%v)", err)
return
}
if res.Errcode != ecode.OK.Code() {
log.Error("AccessToken errcode error(%d) msg(%s)", res.Errcode, res.Errmsg)
err = ecode.RequestErr
return
}
data = &wechat.AccessToken{AccessToken: res.AccessToken, ExpiresIn: res.ExpiresIN}
return
}
// Qrcode get qrcode.
func (d *Dao) Qrcode(c context.Context, accessToken, arg string) (qrcode []byte, err error) {
var (
req *http.Request
bs []byte
jsonErr error
)
params := url.Values{}
params.Set("access_token", accessToken)
if req, err = http.NewRequest(http.MethodPost, d.wxQrcodeURL+"?"+params.Encode(), strings.NewReader(arg)); err != nil {
log.Error("Qrcode http.NewRequest error(%v)", err)
return
}
if bs, err = d.httpClient.Raw(c, req); err != nil {
log.Error("Qrcode d.httpClient.Do error(%v)", err)
return
}
var res struct {
Errcode int `json:"errcode"`
Errmsg string `json:"errmsg"`
}
if jsonErr = json.Unmarshal(bs, &res); jsonErr == nil && res.Errcode != ecode.OK.Code() {
log.Error("Qrcode errcode error(%d) msg(%s)", res.Errcode, res.Errmsg)
err = ecode.RequestErr
return
}
qrcode = bs
return
}
// CacheAccessToken cache access token
func (d *Dao) CacheAccessToken(c context.Context) (data *wechat.AccessToken, err error) {
var (
value []byte
key = _accessTokenKey
conn = d.redis.Get(c)
)
defer conn.Close()
if value, err = redis.Bytes(conn.Do("GET", key)); err != nil {
if err == redis.ErrNil {
err = nil
} else {
log.Error("CacheAccessToken conn.Do(GET, %s) error(%v)", key, err)
}
return
}
data = new(wechat.AccessToken)
if err = json.Unmarshal(value, &data); err != nil {
log.Error("CacheAccessToken json.Unmarshal(%v) error(%v)", value, err)
}
return
}
// AddCacheAccessToken add access token cache
func (d *Dao) AddCacheAccessToken(c context.Context, data *wechat.AccessToken) (err error) {
var (
bs []byte
key = _accessTokenKey
conn = d.redis.Get(c)
)
defer conn.Close()
if bs, err = json.Marshal(data); err != nil {
log.Error("AddCacheAccessToken json.Marshal(%v) error (%v)", data, err)
return
}
if err = conn.Send("SET", key, bs); err != nil {
log.Error("conn.Send(SET, %s, %s) error(%v)", key, string(bs), err)
return
}
expire := data.ExpiresIn - 60
if err = conn.Send("EXPIRE", key, expire); err != nil {
log.Error("conn.Send(Expire, %s, %d) error(%v)", key, expire, err)
return
}
if err = conn.Flush(); err != nil {
log.Error("conn.Flush error(%v)", err)
return
}
for i := 0; i < 2; i++ {
if _, err = conn.Receive(); err != nil {
log.Error("conn.Receive() error(%v)", err)
return
}
}
return
}

View File

@@ -0,0 +1,58 @@
package wechat
import (
"context"
"testing"
"go-common/app/interface/main/web-goblin/model/wechat"
"go-common/library/ecode"
"github.com/smartystreets/goconvey/convey"
)
func TestWechatQrcode(t *testing.T) {
convey.Convey("Qrcode", t, func(ctx convey.C) {
var (
c = context.Background()
accessToken = "14_LZVbKTtstzal_T-AfG-EgkUI2WlCdRvKUqhiYKMhNyxsGjzc1K_a1GGWuMPCbX"
arg = `{"page":"","scene":"?avid=34188644"}`
)
ctx.Convey("When everything goes positive", func(ctx convey.C) {
qrcode, err := d.Qrcode(c, accessToken, arg)
ctx.Convey("Then err should be nil.qrcode should not be nil.", func(ctx convey.C) {
ctx.So(err, convey.ShouldEqual, ecode.RequestErr)
ctx.Println(qrcode)
})
})
})
}
func TestWechatAddCacheAccessToken(t *testing.T) {
convey.Convey("AddCacheAccessToken", t, func(ctx convey.C) {
var (
c = context.Background()
data = &wechat.AccessToken{AccessToken: "string", ExpiresIn: 1111}
)
ctx.Convey("When everything goes positive", func(ctx convey.C) {
err := d.AddCacheAccessToken(c, data)
ctx.Convey("Then err should be nil.", func(ctx convey.C) {
ctx.So(err, convey.ShouldBeNil)
})
})
})
}
func TestWechatCacheAccessToken(t *testing.T) {
convey.Convey("CacheAccessToken", t, func(ctx convey.C) {
var (
c = context.Background()
)
ctx.Convey("When everything goes positive", func(ctx convey.C) {
data, err := d.CacheAccessToken(c)
ctx.Convey("Then err should be nil.data should not be nil.", func(ctx convey.C) {
ctx.So(err, convey.ShouldBeNil)
ctx.So(data, convey.ShouldNotBeNil)
})
})
})
}

View File

@@ -0,0 +1,48 @@
package(default_visibility = ["//visibility:public"])
load(
"@io_bazel_rules_go//go:def.bzl",
"go_library",
)
go_library(
name = "go_default_library",
srcs = [
"channel.go",
"full.go",
"http.go",
"pgc.go",
"recruit.go",
"share.go",
"ugc.go",
"wechat.go",
],
importpath = "go-common/app/interface/main/web-goblin/http",
tags = ["automanaged"],
visibility = ["//visibility:public"],
deps = [
"//app/interface/main/web-goblin/conf:go_default_library",
"//app/interface/main/web-goblin/model/web:go_default_library",
"//app/interface/main/web-goblin/service/share:go_default_library",
"//app/interface/main/web-goblin/service/web:go_default_library",
"//app/interface/main/web-goblin/service/wechat:go_default_library",
"//library/ecode:go_default_library",
"//library/log:go_default_library",
"//library/net/http/blademaster:go_default_library",
"//library/net/http/blademaster/middleware/auth: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,23 @@
package http
import bm "go-common/library/net/http/blademaster"
func channel(c *bm.Context) {
var (
mid int64
buvid string
)
v := new(struct {
ID int64 `form:"id" validate:"min=1"`
})
if err := c.Bind(v); err != nil {
return
}
if midInter, ok := c.Get("mid"); ok {
mid = midInter.(int64)
}
if ck, err := c.Request.Cookie("buvid3"); err == nil {
buvid = ck.Value
}
c.JSON(srvWeb.Channel(c, v.ID, mid, buvid))
}

View File

@@ -0,0 +1,38 @@
package http
import (
"time"
webmdl "go-common/app/interface/main/web-goblin/model/web"
bm "go-common/library/net/http/blademaster"
)
const (
_appName = `哔哩哔哩`
_packageName = `tv.danmaku.bili`
)
func fullshort(c *bm.Context) {
var (
err error
items []*webmdl.Mi
)
v := new(struct {
Pn int64 `form:"pn" validate:"min=1"`
Ps int64 `form:"ps" validate:"min=1,max=50"`
Source string `form:"bsource"`
})
if err = c.Bind(v); err != nil {
return
}
if items, err = srvWeb.FullShort(c, v.Pn, v.Ps, v.Source); err != nil {
c.JSON(nil, err)
return
}
data := make(map[string]interface{}, 4)
data["app_name"] = _appName
data["package_name"] = _packageName
data["update_time"] = time.Now().Format("2006-01-02 15:04:05")
data["shortvideos"] = items
c.JSONMap(data, nil)
}

View File

@@ -0,0 +1,77 @@
package http
import (
"net/http"
"go-common/app/interface/main/web-goblin/conf"
"go-common/app/interface/main/web-goblin/service/share"
"go-common/app/interface/main/web-goblin/service/web"
"go-common/app/interface/main/web-goblin/service/wechat"
"go-common/library/log"
bm "go-common/library/net/http/blademaster"
"go-common/library/net/http/blademaster/middleware/auth"
)
var (
srvWeb *web.Service
srvShare *share.Service
srvWechat *wechat.Service
authSvr *auth.Auth
)
// Init init .
func Init(c *conf.Config) {
authSvr = auth.New(c.Auth)
srvWeb = web.New(c)
srvShare = share.New(c)
srvWechat = wechat.New(c)
engine := bm.DefaultServer(c.BM)
router(engine)
if err := engine.Start(); err != nil {
log.Error("engine.Start error(%v)", err)
panic(err)
}
}
func router(e *bm.Engine) {
e.Ping(ping)
e.Register(register)
group := e.Group("/x/web-goblin")
{
miGroup := group.Group("/mi")
{
miGroup.GET("/full", fullshort)
}
channelGroup := group.Group("/channel")
{
channelGroup.GET("", authSvr.Guest, channel)
}
ugcGroup := group.Group("ugc")
{
ugcGroup.GET("/full", ugcfull)
ugcGroup.GET("/increment", ugcincre)
}
pgcGroup := group.Group("pgc")
{
pgcGroup.GET("/full", pgcfull)
pgcGroup.GET("/increment", pgcincre)
}
group.GET("/share/encourage", authSvr.User, encourage)
group.GET("/recruit", recruit)
weChatGroup := group.Group("/wechat")
{
weChatGroup.GET("/qrcode", qrcode)
}
}
}
func ping(c *bm.Context) {
if err := srvWeb.Ping(c); err != nil {
log.Error("web-goblin ping error(%v)", err)
c.AbortWithStatus(http.StatusServiceUnavailable)
}
}
func register(c *bm.Context) {
c.JSON(map[string]interface{}{}, nil)
}

View File

@@ -0,0 +1,78 @@
package http
import (
"time"
"go-common/library/ecode"
bm "go-common/library/net/http/blademaster"
)
func pgcfull(c *bm.Context) {
var (
err error
items interface{}
)
v := new(struct {
Pn int64 `form:"pn" validate:"min=1"`
Ps int64 `form:"ps" validate:"min=1,max=50"`
Tp int `form:"season_type" validate:"min=1,max=5"`
Source string `form:"bsource" validate:"required"`
})
if err = c.Bind(v); err != nil {
return
}
if !accessCard(_pgcFull, v.Source) {
c.JSON(nil, ecode.AccessDenied)
return
}
if items, err = srvWeb.PgcFull(c, v.Tp, v.Pn, v.Ps, v.Source); err != nil {
c.JSON(nil, err)
return
}
if items == nil {
items = struct{}{}
}
data := make(map[string]interface{}, 5)
data["app_name"] = _appName
data["package_name"] = _packageName
data["update_time"] = time.Now().Format("2006-01-02 15:04:05")
data["source"] = v.Source
data["shortvideos"] = items
c.JSONMap(data, nil)
}
func pgcincre(c *bm.Context) {
var (
err error
items interface{}
)
v := new(struct {
Pn int64 `form:"pn" validate:"min=1"`
Ps int64 `form:"ps" validate:"min=1,max=50"`
Tp int `form:"season_type" validate:"min=1,max=5"`
StartTime int64 `form:"start_ts" validate:"required"`
EndTime int64 `form:"end_ts" validate:"required"`
Source string `form:"bsource" validate:"required"`
})
if err = c.Bind(v); err != nil {
return
}
if !accessCard(_pgcIncre, v.Source) {
c.JSON(nil, ecode.AccessDenied)
return
}
if items, err = srvWeb.PgcIncre(c, v.Tp, v.Pn, v.Ps, v.StartTime, v.EndTime, v.Source); err != nil {
c.JSON(nil, err)
return
}
if items == nil {
items = struct{}{}
}
data := make(map[string]interface{}, 5)
data["app_name"] = _appName
data["package_name"] = _packageName
data["update_time"] = time.Now().Format("2006-01-02 15:04:05")
data["source"] = v.Source
data["shortvideos"] = items
c.JSONMap(data, nil)
}

View File

@@ -0,0 +1,23 @@
package http
import (
"go-common/app/interface/main/web-goblin/model/web"
"go-common/library/ecode"
bm "go-common/library/net/http/blademaster"
)
func recruit(c *bm.Context) {
var (
param = c.Request.Form
err error
v = &web.Params{}
)
if err = c.Bind(v); err != nil {
return
}
if v.Mode == "social" || v.Mode == "campus" {
c.JSON(srvWeb.Recruit(c, param, v))
return
}
c.JSON("mode 只能为 社招(social) 或者 校招(campus", ecode.RequestErr)
}

View File

@@ -0,0 +1,14 @@
package http
import (
bm "go-common/library/net/http/blademaster"
)
func encourage(c *bm.Context) {
var (
mid int64
)
midStr, _ := c.Get("mid")
mid = midStr.(int64)
c.JSON(srvShare.Encourage(c, mid))
}

View File

@@ -0,0 +1,109 @@
package http
import (
"time"
"go-common/app/interface/main/web-goblin/conf"
webmdl "go-common/app/interface/main/web-goblin/model/web"
"go-common/library/ecode"
bm "go-common/library/net/http/blademaster"
)
const (
_lmt = 10000
_pgcFull = "pgcfull"
_pgcIncre = "pgcincre"
_ugcFull = "ugcfull"
_ugcIncre = "ugcincre"
)
func ugcfull(c *bm.Context) {
var (
err error
items []*webmdl.Mi
)
v := new(struct {
Pn int64 `form:"pn" validate:"min=1"`
Ps int64 `form:"ps" validate:"min=1,max=50"`
Source string `form:"bsource" validate:"required"`
})
if err = c.Bind(v); err != nil {
return
}
if !accessCard(_ugcFull, v.Source) {
c.JSON(nil, ecode.AccessDenied)
return
}
source := "?bsource=" + v.Source
if items, err = srvWeb.UgcFull(c, v.Pn, v.Ps, source); err != nil {
c.JSON(nil, err)
return
}
data := make(map[string]interface{}, 5)
data["app_name"] = _appName
data["package_name"] = _packageName
data["update_time"] = time.Now().Format("2006-01-02 15:04:05")
data["source"] = v.Source
data["shortvideos"] = items
c.JSONMap(data, nil)
}
func ugcincre(c *bm.Context) {
var (
err error
item []*webmdl.Mi
)
v := new(struct {
Pn int `form:"pn" validate:"min=1"`
Ps int `form:"ps" validate:"min=1,max=50"`
StartTs int64 `form:"start_ts" validate:"required"`
EndTs int64 `form:"end_ts" validate:"required"`
Source string `form:"bsource" validate:"required"`
})
if err = c.Bind(v); err != nil {
return
}
if !accessCard(_ugcIncre, v.Source) {
c.JSON(nil, ecode.AccessDenied)
return
}
if v.StartTs >= v.EndTs || v.EndTs-v.StartTs >= conf.Conf.OutSearch.Rspan {
c.JSON(nil, ecode.RequestErr)
return
}
if v.Ps*v.Pn > _lmt {
c.JSON(nil, ecode.RequestErr)
return
}
source := "?bsource=" + v.Source
if item, err = srvWeb.UgcIncre(c, v.Pn, v.Ps, v.StartTs, v.EndTs, source); err != nil {
c.JSON(nil, err)
return
}
data := make(map[string]interface{}, 5)
data["app_name"] = _appName
data["package_name"] = _packageName
data["update_time"] = time.Now().Format("2006-01-02 15:04:05")
data["source"] = v.Source
data["shortvideos"] = item
c.JSONMap(data, nil)
}
func accessCard(flag, arg string) bool {
var (
b = false
m = map[string][]string{
_pgcFull: conf.Conf.OutSearch.AcPgcFull,
_pgcIncre: conf.Conf.OutSearch.AcPgcIncre,
_ugcFull: conf.Conf.OutSearch.AcUgcFull,
_ugcIncre: conf.Conf.OutSearch.AcUgcIncre,
}
)
for _, v := range m[flag] {
if v == arg {
b = true
break
}
}
return b
}

View File

@@ -0,0 +1,22 @@
package http
import (
"net/http"
bm "go-common/library/net/http/blademaster"
)
func qrcode(c *bm.Context) {
v := new(struct {
JSON string `form:"json" validate:"required"`
})
if err := c.Bind(v); err != nil {
return
}
qrcode, err := srvWechat.Qrcode(c, v.JSON)
if err != nil {
c.JSON(nil, err)
return
}
c.Bytes(http.StatusOK, "", qrcode)
}

View File

@@ -0,0 +1,32 @@
package(default_visibility = ["//visibility:public"])
load(
"@io_bazel_rules_go//go:def.bzl",
"go_library",
)
go_library(
name = "go_default_library",
srcs = ["share.go"],
importpath = "go-common/app/interface/main/web-goblin/model/share",
tags = ["automanaged"],
visibility = ["//visibility:public"],
deps = [
"//app/service/main/usersuit/model: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,31 @@
package share
import (
suitmdl "go-common/app/service/main/usersuit/model"
xtime "go-common/library/time"
)
// Share share .
type Share struct {
ID int64 `json:"id"`
Mid int64 `json:"mid"`
DayCount int64 `json:"day_count"`
Cycle int64 `json:"cycle"`
ShareDate int64 `json:"share_date"`
Ctime xtime.Time `json:"ctime"`
Mtime xtime.Time `json:"mtime"`
}
// Encourage encourage .
type Encourage struct {
UserInfo interface{} `json:"user_info"`
TodayShare int64 `json:"today_share"`
ShareDays int64 `json:"share_days"`
Pendants interface{} `json:"pendants"`
}
// GroupPendant groupPendant .
type GroupPendant struct {
NeedDays int64 `json:"need_days"`
Pendant *suitmdl.GroupPendantList `json:"pendant"`
}

View File

@@ -0,0 +1,37 @@
package(default_visibility = ["//visibility:public"])
load(
"@io_bazel_rules_go//go:def.bzl",
"go_library",
)
go_library(
name = "go_default_library",
srcs = [
"channel.go",
"full.go",
"recruit.go",
],
importpath = "go-common/app/interface/main/web-goblin/model/web",
tags = ["automanaged"],
visibility = ["//visibility:public"],
deps = [
"//app/interface/main/tag/model:go_default_library",
"//app/interface/main/web-goblin/conf:go_default_library",
"//app/service/main/archive/api: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,25 @@
package web
import (
tagmdl "go-common/app/interface/main/tag/model"
"go-common/app/service/main/archive/api"
)
// ChCard channel card .
type ChCard struct {
ID int64 `json:"-"`
Title string `json:"-"`
ChannelID int64 `json:"-"`
Type string `json:"-"`
Value int64 `json:"-"`
Reason string `json:"-"`
ReasonType int8 `json:"-"`
Pos int `json:"-"`
FromType string `json:"-"`
}
// Channel .
type Channel struct {
*tagmdl.Tag
Archives []*api.Arc `json:"archives"`
}

View File

@@ -0,0 +1,122 @@
package web
import (
"fmt"
"math/rand"
"time"
"go-common/app/interface/main/web-goblin/conf"
"go-common/app/service/main/archive/api"
)
const (
_deal = 100
)
// Mi mi common .
type Mi struct {
ID int64 `json:"id"`
Name string `json:"name"`
Op string `json:"op"`
AlternativeNames string `json:"alternative_names"`
Cover Img `json:"cover"`
Thumbnail Img `json:"thumbnail"`
Description string `json:"description"`
Tags string `json:"tags"`
CreateTime string `json:"create_time"`
ModifyTime string `json:"modify_time"`
PublishTime string `json:"publish_time"`
Author string `json:"author"`
Category string `json:"category"`
Rating float32 `json:"rating"`
PlayCount int32 `json:"play_count"`
PlayCountMonth int `json:"play_count_month"`
PlayCountWeek int `json:"play_count_week"`
PlayLength int64 `json:"play_length"`
Language string `json:"language"`
Images Img `json:"images"`
Weburl string `json:"weburl"`
Appurl string `json:"appurl"`
MinVersion int `json:"min_version"`
Pages []*PageInfo `json:"pages"`
CommentCount int32 `json:"comment_count"`
LikeCount int32 `json:"like_count"`
}
// PageInfo page3 .
type PageInfo struct {
Cid int64 `json:"cid"`
Page int32 `json:"page"`
}
// Img img .
type Img struct {
URL string `json:"url"`
Height int `json:"height"`
Width int `json:"width"`
}
// SearchAids return aids .
type SearchAids struct {
Aid int64 `json:"aid"`
Action string `json:"action"`
}
// FromArchive .
func (f *Mi) FromArchive(a *api.Arc, p []*api.Page, op, source string) {
f.ID = a.Aid
f.Name = a.Title
f.Author = a.Author.Name
f.Category = a.TypeName
f.Weburl = fmt.Sprintf("https://www.bilibili.com/video/av%d%s", a.Aid, source)
f.Appurl = fmt.Sprintf("bilibili://video/%d", a.Aid)
f.ModifyTime = a.PubDate.Time().Format("2006-01-02 15:04:05")
f.Description = a.Desc
f.CreateTime = a.Ctime.Time().Format("2006-01-02 15:04:05")
f.Images.URL = a.Pic
f.PlayLength = a.Duration
f.Cover.URL = a.Pic
f.Thumbnail.URL = a.Pic
f.PlayCount = a.Stat.View
f.PublishTime = a.PubDate.Time().Format("2006-01-02 15:04:05")
f.MinVersion = 1
f.Op = op
f.CommentCount = a.Stat.Reply
f.LikeCount = a.Stat.Like
pLen := len(p)
if pLen > 0 {
f.Pages = make([]*PageInfo, pLen)
for i := 0; i < pLen; i++ {
f.Pages[i] = &PageInfo{}
f.Pages[i].Page = p[i].Page
f.Pages[i].Cid = p[i].Cid
}
} else {
f.Pages = []*PageInfo{}
}
}
// UgcFullDeal .
func (f *Mi) UgcFullDeal() {
var (
lCount = conf.Conf.OutSearch.DealLikeFull
commCount = conf.Conf.OutSearch.DealCommFull
commRes = f.CommentCount + commCount
likeRes = f.LikeCount + lCount
)
if f.PlayCount+f.CommentCount > 0 {
commRes = commRes + (f.PlayCount/(f.PlayCount+f.CommentCount))*f.CommentCount
}
if f.PlayCount+f.LikeCount > 0 {
likeRes = likeRes + (f.PlayCount/(f.PlayCount+f.LikeCount))*f.LikeCount
}
f.CommentCount = commRes
f.LikeCount = likeRes
}
// UgcIncreDeal .
func (f *Mi) UgcIncreDeal() {
rand.Seed(time.Now().UnixNano())
f.CommentCount = int32(rand.Intn(_deal))
f.LikeCount = int32(rand.Intn(_deal)) + _deal
}

View File

@@ -0,0 +1,8 @@
package web
// Params .
type Params struct {
Route string `form:"route" validate:"required"`
Mode string `form:"mode" validate:"required"`
JobID string `form:"job_id"`
}

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 = ["wechat.go"],
importpath = "go-common/app/interface/main/web-goblin/model/wechat",
tags = ["automanaged"],
visibility = ["//visibility:public"],
)
filegroup(
name = "package-srcs",
srcs = glob(["**"]),
tags = ["automanaged"],
visibility = ["//visibility:private"],
)
filegroup(
name = "all-srcs",
srcs = [":package-srcs"],
tags = ["automanaged"],
visibility = ["//visibility:public"],
)

View File

@@ -0,0 +1,7 @@
package wechat
// AccessToken wechat access token.
type AccessToken struct {
AccessToken string `json:"access_token"`
ExpiresIn int64 `json:"expires_in"`
}

View File

@@ -0,0 +1,43 @@
package(default_visibility = ["//visibility:public"])
load(
"@io_bazel_rules_go//go:def.bzl",
"go_library",
)
go_library(
name = "go_default_library",
srcs = [
"service.go",
"share.go",
],
importpath = "go-common/app/interface/main/web-goblin/service/share",
tags = ["automanaged"],
visibility = ["//visibility:public"],
deps = [
"//app/interface/main/web-goblin/conf:go_default_library",
"//app/interface/main/web-goblin/dao/share:go_default_library",
"//app/interface/main/web-goblin/model/share:go_default_library",
"//app/service/main/account/model:go_default_library",
"//app/service/main/account/rpc/client:go_default_library",
"//app/service/main/usersuit/model:go_default_library",
"//app/service/main/usersuit/rpc/client:go_default_library",
"//library/cache:go_default_library",
"//library/log:go_default_library",
"//library/sync/errgroup:go_default_library",
],
)
filegroup(
name = "package-srcs",
srcs = glob(["**"]),
tags = ["automanaged"],
visibility = ["//visibility:private"],
)
filegroup(
name = "all-srcs",
srcs = [":package-srcs"],
tags = ["automanaged"],
visibility = ["//visibility:public"],
)

View File

@@ -0,0 +1,45 @@
package share
import (
"context"
"go-common/app/interface/main/web-goblin/conf"
"go-common/app/interface/main/web-goblin/dao/share"
accrpc "go-common/app/service/main/account/rpc/client"
suitrpc "go-common/app/service/main/usersuit/rpc/client"
"go-common/library/cache"
"go-common/library/log"
)
// Service service struct.
type Service struct {
c *conf.Config
dao *share.Dao
// cache proc
cache *cache.Cache
suit *suitrpc.Service2
accRPC *accrpc.Service3
Pendants map[int64]int64
}
// New new service.
func New(c *conf.Config) *Service {
s := &Service{
c: c,
dao: share.New(c),
cache: cache.New(1, 1024),
suit: suitrpc.New(c.SuitRPC),
accRPC: accrpc.New3(c.AccountRPC),
Pendants: make(map[int64]int64),
}
s.loadPendant()
return s
}
// Ping ping service.
func (s *Service) Ping(c context.Context) (err error) {
if err = s.dao.Ping(c); err != nil {
log.Error("s.dao.Ping error(%v)", err)
}
return
}

View File

@@ -0,0 +1,98 @@
package share
import (
"context"
"strconv"
"time"
shamdl "go-common/app/interface/main/web-goblin/model/share"
accmdl "go-common/app/service/main/account/model"
suitmdl "go-common/app/service/main/usersuit/model"
"go-common/library/log"
"go-common/library/sync/errgroup"
)
// Encourage share encourage.
func (s *Service) Encourage(c context.Context, mid int64) (res *shamdl.Encourage, err error) {
var (
mcShare map[string]int64
shares []*shamdl.Share
key string
info *accmdl.Info
gps []*suitmdl.GroupPendantList
shaPend []*shamdl.GroupPendant
group = errgroup.Group{}
)
group.Go(func() (e error) {
if info, e = s.accRPC.Info3(context.Background(), &accmdl.ArgMid{Mid: mid}); e != nil {
log.Error("s.accRPC.Info mid(%d) error(%v)", mid, e)
}
return
})
group.Go(func() (e error) {
if mcShare, e = s.dao.SharesCache(context.Background(), mid); e != nil {
log.Error("s.dao.SharesCache mid(%d) error(%v)", mid, e)
if shares, e = s.dao.Shares(context.Background(), mid); e != nil {
log.Error("s.dao.Shares mid(%d) error(%v)", mid, e)
return
}
count := len(shares)
if count > 0 {
mcShare = make(map[string]int64, count)
for _, share := range shares {
key = strconv.FormatInt(share.ShareDate, 10)
mcShare[key] = share.DayCount
}
s.cache.Save(func() {
expire := monthShare()
s.dao.SetSharesCache(context.Background(), expire, mid, mcShare)
})
}
}
return
})
group.Go(func() (e error) {
if gps, e = s.suit.GroupPendantMid(context.Background(), &suitmdl.ArgGPMID{MID: mid, GID: s.c.Rule.Gid}); e != nil {
log.Error("s.suit.GroupPendantMid mid(%d) error(%v)", mid, e)
}
return
})
group.Wait()
res = new(shamdl.Encourage)
if len(gps) > 0 {
for _, gp := range gps {
shaPend = append(shaPend, &shamdl.GroupPendant{NeedDays: s.Pendants[gp.ID], Pendant: gp})
}
}
if info == nil || info.Mid == 0 {
res.UserInfo = struct{}{}
} else {
res.UserInfo = info
}
days := int64(len(mcShare))
if days > 0 {
res.TodayShare = mcShare[time.Now().Format("20060102")]
res.ShareDays = int64(days)
}
if len(shaPend) == 0 {
res.Pendants = struct{}{}
} else {
res.Pendants = shaPend
}
return
}
func monthShare() int {
now := time.Now()
currentYear, currentMonth, _ := now.Date()
currentLocation := now.Location()
firstOfMonth := time.Date(currentYear, currentMonth, 1, 23, 59, 59, 0, currentLocation)
lastOfMonth := firstOfMonth.AddDate(0, 1, -1)
return int(lastOfMonth.Sub(now).Seconds())
}
func (s *Service) loadPendant() {
for _, p := range s.c.Pendants {
s.Pendants[p.Pid] = p.Level
}
}

View File

@@ -0,0 +1,70 @@
package(default_visibility = ["//visibility:public"])
load(
"@io_bazel_rules_go//go:def.bzl",
"go_test",
"go_library",
)
go_test(
name = "go_default_test",
srcs = [
"full_test.go",
"pgc_test.go",
"recruit_test.go",
"service_test.go",
"ugc_test.go",
],
embed = [":go_default_library"],
rundir = ".",
tags = ["automanaged"],
deps = [
"//app/interface/main/web-goblin/conf:go_default_library",
"//app/interface/main/web-goblin/model/web:go_default_library",
"//vendor/github.com/smartystreets/goconvey/convey:go_default_library",
],
)
go_library(
name = "go_default_library",
srcs = [
"channel.go",
"full.go",
"pgc.go",
"recruit.go",
"service.go",
"ugc.go",
],
importpath = "go-common/app/interface/main/web-goblin/service/web",
tags = ["automanaged"],
visibility = ["//visibility:public"],
deps = [
"//app/interface/main/tag/model:go_default_library",
"//app/interface/main/tag/rpc/client:go_default_library",
"//app/interface/main/web-goblin/conf:go_default_library",
"//app/interface/main/web-goblin/dao/web:go_default_library",
"//app/interface/main/web-goblin/model/web:go_default_library",
"//app/service/main/archive/api:go_default_library",
"//app/service/main/archive/api/gorpc:go_default_library",
"//app/service/main/archive/model/archive:go_default_library",
"//library/ecode:go_default_library",
"//library/log:go_default_library",
"//library/net/metadata:go_default_library",
"//library/sync/errgroup: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,86 @@
package web
import (
"context"
tagmdl "go-common/app/interface/main/tag/model"
"go-common/app/interface/main/web-goblin/model/web"
"go-common/app/service/main/archive/api"
"go-common/app/service/main/archive/model/archive"
"go-common/library/log"
"go-common/library/net/metadata"
"go-common/library/sync/errgroup"
)
const (
_chRqCnt = 40
_chDisplayID = 1
_chTypeArc = 3
_chFrom = 1
)
var _emptyArcs = make([]*api.Arc, 0)
// Channel .
func (s *Service) Channel(c context.Context, id, mid int64, buvid string) (channel *web.Channel, err error) {
var (
aids []int64
arcs map[int64]*api.Arc
tagErr error
)
ip := metadata.String(c, metadata.RemoteIP)
channel = new(web.Channel)
if cards, ok := s.channelCards[id]; ok {
for _, card := range cards {
aids = append(aids, card.Value)
}
}
group, errCtx := errgroup.WithContext(c)
group.Go(func() error {
arg := &tagmdl.ArgChannelResource{
Tid: id,
Mid: mid,
RequestCNT: int32(_chRqCnt),
DisplayID: _chDisplayID,
Type: _chTypeArc,
Buvid: buvid,
From: _chFrom,
RealIP: ip,
}
if channelResource, chErr := s.tag.ChannelResources(errCtx, arg); chErr != nil {
log.Error("Channel s.tag.Resources error(%v)", chErr)
} else if channelResource != nil {
aids = append(aids, channelResource.Oids...)
}
return nil
})
group.Go(func() error {
if channel.Tag, tagErr = s.tag.InfoByID(errCtx, &tagmdl.ArgID{ID: id, Mid: mid}); tagErr != nil {
log.Error("Channel s.tag.InfoByID(%d, %d) error(%v)", id, mid, err)
return tagErr
}
return nil
})
if err = group.Wait(); err != nil {
return
}
if len(aids) == 0 {
channel.Archives = _emptyArcs
return
}
if arcs, err = s.arc.Archives3(c, &archive.ArgAids2{Aids: aids, RealIP: ip}); err != nil {
log.Error("Channel s.arc.Archives3(%v) error(%v)", aids, err)
err = nil
channel.Archives = _emptyArcs
return
}
for _, aid := range aids {
if arc, ok := arcs[aid]; ok && arc.IsNormal() {
channel.Archives = append(channel.Archives, arc)
}
}
if len(channel.Archives) > _chRqCnt {
channel.Archives = channel.Archives[:_chRqCnt]
}
return
}

View File

@@ -0,0 +1,164 @@
package web
import (
"context"
"strings"
"sync"
"sync/atomic"
"time"
tagmdl "go-common/app/interface/main/tag/model"
"go-common/app/interface/main/web-goblin/dao/web"
webmdl "go-common/app/interface/main/web-goblin/model/web"
"go-common/app/service/main/archive/api"
"go-common/app/service/main/archive/model/archive"
"go-common/library/ecode"
"go-common/library/log"
"go-common/library/net/metadata"
"go-common/library/sync/errgroup"
)
var (
_emptyMiArc = make([]*webmdl.Mi, 0)
)
const (
_tagBlkSize = 50
_tagArcType = 3
)
// FullShort xiao mi FullShort .
func (s *Service) FullShort(c context.Context, pn, ps int64, source string) (res []*webmdl.Mi, err error) {
var (
aids []int64
ip = metadata.String(c, metadata.RemoteIP)
m = make(map[int64]string)
)
if aids, err = s.aids(c, pn, ps); err != nil {
return
}
if res, err = s.archiveWithTag(c, aids, ip, m, source); err != nil {
log.Error("s.archiveWithTag error(%v)", err)
}
return
}
func (s *Service) archiveWithTag(c context.Context, aids []int64, ip string, op map[int64]string, source string) (list []*webmdl.Mi, err error) {
var (
arcErr, tagErr error
archives map[int64]*api.Arc
pages []*api.Page
pageInfo map[int64][]*api.Page
tags map[int64][]*tagmdl.Tag
mutex = sync.Mutex{}
tempTags []string
)
group := new(errgroup.Group)
group.Go(func() error {
if archives, arcErr = s.arc.Archives3(context.Background(), &archive.ArgAids2{Aids: aids, RealIP: ip}); arcErr != nil {
web.PromError("Archives3接口错误", "s.arc.Archives3(%d,%s) error %v", aids, ip, err)
return arcErr
}
return nil
})
pageInfo = make(map[int64][]*api.Page)
for _, aid := range aids {
group.Go(func() error {
pages = []*api.Page{}
if pages, err = s.arc.Page3(context.Background(), &archive.ArgAid2{Aid: aid, RealIP: ip}); err != nil {
log.Error("s.arc.Page3 error(%v)", err)
return err
}
mutex.Lock()
pageInfo[aid] = pages
mutex.Unlock()
return nil
})
}
aidsLen := len(aids)
tags = make(map[int64][]*tagmdl.Tag, aidsLen)
for i := 0; i < aidsLen; i += _tagBlkSize {
var partAids []int64
if i+_tagBlkSize > aidsLen {
partAids = aids[i:]
} else {
partAids = aids[i : i+_tagBlkSize]
}
group.Go(func() (err error) {
var tmpRes map[int64][]*tagmdl.Tag
arg := &tagmdl.ArgResTags{Oids: partAids, Type: _tagArcType, RealIP: ip}
if tmpRes, tagErr = s.tag.ResTags(context.Background(), arg); tagErr != nil {
web.PromError("ResTags接口错误", "s.tag.ResTag(%+v) error(%v)", arg, tagErr)
return
}
mutex.Lock()
for aid, tmpTags := range tmpRes {
tags[aid] = tmpTags
}
mutex.Unlock()
return nil
})
}
if err = group.Wait(); err != nil {
return
}
for _, aid := range aids {
if arc, ok := archives[aid]; ok && arc.IsNormal() {
miArc := new(webmdl.Mi)
tempTags = []string{}
miArc.FromArchive(arc, pageInfo[aid], op[aid], source)
if tag, ok := tags[aid]; ok {
for _, v := range tag {
tempTags = append(tempTags, v.Name)
}
}
if len(tempTags) == 0 {
miArc.Tags = ""
} else {
miArc.Tags = strings.Join(tempTags, ",")
}
list = append(list, miArc)
}
}
if len(list) == 0 {
list = _emptyMiArc
}
return
}
func (s *Service) aids(c context.Context, pn, ps int64) (res []int64, err error) {
var start, end int64
if pn > 1 {
start = pn*ps + 1
} else {
start = 1
}
end = start + ps
if s.maxAid > 0 && end > s.maxAid {
log.Warn("aids(%d,%d) maxAid(%d)", pn, ps, s.maxAid)
err = ecode.RequestErr
return
}
for i := start; i < end; i++ {
res = append(res, i)
}
return
}
func (s *Service) justAID() {
var (
maxAid int64
err error
)
for {
if maxAid, err = s.arc.MaxAID(context.Background()); err != nil {
web.PromError("MaxAID接口错误", "s.arc.MaxAID error(%v)", err)
time.Sleep(time.Second)
continue
}
if maxAid > 0 {
atomic.StoreInt64(&s.maxAid, maxAid+100)
}
time.Sleep(time.Minute)
}
}

View File

@@ -0,0 +1,20 @@
package web
import (
"context"
"testing"
. "github.com/smartystreets/goconvey/convey"
)
func TestService_Full(t *testing.T) {
Convey("test Full", t, WithService(func(s *Service) {
var (
pn int64 = 1
ps int64 = 10
)
res, err := s.FullShort(context.Background(), pn, ps, "")
So(err, ShouldBeNil)
So(res, ShouldNotBeNil)
}))
}

View File

@@ -0,0 +1,23 @@
package web
import (
"context"
"go-common/library/log"
)
// PgcFull pgc full .
func (s *Service) PgcFull(ctx context.Context, tp int, pn, ps int64, source string) (res interface{}, err error) {
if res, err = s.dao.PgcFull(ctx, tp, pn, ps, source); err != nil {
log.Error("s.dao.PgcFull error(%v)", err)
}
return
}
// PgcIncre pgc incre .
func (s *Service) PgcIncre(ctx context.Context, tp int, pn, ps, start, end int64, source string) (res interface{}, err error) {
if res, err = s.dao.PgcIncre(ctx, tp, pn, ps, start, end, source); err != nil {
log.Error("s.dao.PgcIncre error(%s)", err)
}
return
}

View File

@@ -0,0 +1,40 @@
package web
import (
"context"
"testing"
. "github.com/smartystreets/goconvey/convey"
)
func TestService_PgcFull(t *testing.T) {
Convey("pgc full", t, WithService(func(s *Service) {
var (
c = context.Background()
tp = int(2)
pn = int64(1)
ps = int64(10)
source = "youku"
)
res, err := s.PgcFull(c, tp, pn, ps, source)
So(err, ShouldBeNil)
So(res, ShouldNotBeNil)
}))
}
func TestService_PgcIncre(t *testing.T) {
Convey("pgc incre", t, WithService(func(s *Service) {
var (
c = context.Background()
tp = int(2)
pn = int64(1)
ps = int64(10)
start = int64(1505876448)
end = int64(1505876450)
source = "youku"
)
res, err := s.PgcIncre(c, tp, pn, ps, start, end, source)
So(err, ShouldBeNil)
So(res, ShouldNotBeNil)
}))
}

View File

@@ -0,0 +1,18 @@
package web
import (
"context"
"encoding/json"
"net/url"
"go-common/app/interface/main/web-goblin/model/web"
"go-common/library/log"
)
// Recruit .
func (s *Service) Recruit(ctx context.Context, param url.Values, route *web.Params) (res json.RawMessage, err error) {
if res, err = s.dao.Recruit(ctx, param, route); err != nil {
log.Error("s.dao.Recruit route(%s) error(%v)", route.Route, err)
}
return
}

View File

@@ -0,0 +1,27 @@
package web
import (
"context"
"net/url"
"testing"
"go-common/app/interface/main/web-goblin/model/web"
. "github.com/smartystreets/goconvey/convey"
)
func TestService_Recruit(t *testing.T) {
Convey("test recruit", t, WithService(func(s *Service) {
var (
ctx = context.Background()
param = url.Values{}
ru = &web.Params{
Route: "v1/jobs",
}
)
param.Set("mode", "social")
res, err := s.Recruit(ctx, param, ru)
So(len(res), ShouldBeGreaterThan)
So(err, ShouldBeNil)
}))
}

View File

@@ -0,0 +1,74 @@
package web
import (
"context"
"time"
tagrpc "go-common/app/interface/main/tag/rpc/client"
"go-common/app/interface/main/web-goblin/conf"
"go-common/app/interface/main/web-goblin/dao/web"
webmdl "go-common/app/interface/main/web-goblin/model/web"
arcrpc "go-common/app/service/main/archive/api/gorpc"
"go-common/library/log"
)
const _chCardTypeAv = "av"
// Service struct .
type Service struct {
c *conf.Config
dao *web.Dao
arc *arcrpc.Service2
tag *tagrpc.Service
maxAid int64
channelCards map[int64][]*webmdl.ChCard
}
// New init .
func New(c *conf.Config) (s *Service) {
s = &Service{
c: c,
dao: web.New(c),
arc: arcrpc.New2(c.ArchiveRPC),
tag: tagrpc.New2(c.TagRPC),
}
go s.justAID()
go s.chCardproc()
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()
}
func (s *Service) chCardproc() {
for {
now := time.Now()
cardMap, err := s.dao.ChCard(context.Background(), now)
if err != nil {
log.Error("chCardproc s.dao.ChCard() error(%v)", err)
time.Sleep(time.Second)
}
l := len(cardMap)
if l == 0 {
time.Sleep(time.Duration(s.c.Rule.ChCardInterval))
continue
}
tmp := make(map[int64][]*webmdl.ChCard, l)
for channelID, card := range cardMap {
for _, v := range card {
if v.Type == _chCardTypeAv {
tmp[channelID] = append(tmp[channelID], v)
}
}
}
s.channelCards = tmp
time.Sleep(time.Duration(s.c.Rule.ChCardInterval))
}
}

View File

@@ -0,0 +1,29 @@
package web
import (
"flag"
"path/filepath"
"time"
"go-common/app/interface/main/web-goblin/conf"
)
var svf *Service
func init() {
dir, _ := filepath.Abs("../cmd/web-goblin-test.toml")
flag.Set("conf", dir)
if err := conf.Init(); err != nil {
panic(err)
}
if svf == nil {
svf = New(conf.Conf)
}
time.Sleep(time.Second)
}
func WithService(f func(s *Service)) func() {
return func() {
f(svf)
}
}

View File

@@ -0,0 +1,67 @@
package web
import (
"context"
webmdl "go-common/app/interface/main/web-goblin/model/web"
"go-common/library/log"
"go-common/library/net/metadata"
"go-common/library/xstr"
)
const (
_del = "del"
)
// UgcFull search all ugc .
func (s *Service) UgcFull(ctx context.Context, pn, ps int64, source string) (res []*webmdl.Mi, err error) {
if res, err = s.FullShort(ctx, pn, ps, source); err != nil {
log.Error("UgcFull error (%v)", err)
return
}
if len(res) > 0 {
for idx := range res {
res[idx].UgcFullDeal()
}
}
return
}
// UgcIncre search ugc after a certain time .
func (s *Service) UgcIncre(ctx context.Context, pn, ps int, start, end int64, source string) (res []*webmdl.Mi, err error) {
var (
aids []*webmdl.SearchAids
opmap map[int64]string
delaids []int64
tmpAids []int64
ip = metadata.String(ctx, metadata.RemoteIP)
)
if aids, err = s.dao.UgcIncre(ctx, pn, ps, start, end); err != nil {
log.Error("s.dao.UgcIncre error (%v)", err)
return
}
opmap = make(map[int64]string, len(aids))
for _, v := range aids {
opmap[v.Aid] = v.Action
if v.Action == _del {
delaids = append(delaids, v.Aid)
} else {
tmpAids = append(tmpAids, v.Aid)
}
}
if res, err = s.archiveWithTag(ctx, tmpAids, ip, opmap, source); err != nil {
log.Warn("s.archiveWithTag ip(%s) aids(%s) error(%v)", err, ip, xstr.JoinInts(tmpAids))
}
for _, v := range delaids {
m := &webmdl.Mi{}
m.Op = _del
m.ID = v
res = append(res, m)
}
if len(res) > 0 {
for idx := range res {
res[idx].UgcIncreDeal()
}
}
return
}

View File

@@ -0,0 +1,36 @@
package web
import (
"context"
"testing"
. "github.com/smartystreets/goconvey/convey"
)
func TestService_UgcFull(t *testing.T) {
Convey("ugc full", t, WithService(func(s *Service) {
var (
c = context.Background()
pn = int64(1)
ps = int64(10)
)
res, err := s.UgcFull(c, pn, ps, "")
So(err, ShouldBeNil)
So(res, ShouldNotBeNil)
}))
}
func TestService_UgcIncre(t *testing.T) {
Convey("pgc incre", t, WithService(func(s *Service) {
var (
c = context.Background()
pn = 1
ps = 10
start = int64(1505876448)
end = int64(1505876450)
)
res, err := s.UgcIncre(c, pn, ps, start, end, "")
So(err, ShouldBeNil)
So(res, ShouldNotBeNil)
}))
}

View File

@@ -0,0 +1,37 @@
package(default_visibility = ["//visibility:public"])
load(
"@io_bazel_rules_go//go:def.bzl",
"go_library",
)
go_library(
name = "go_default_library",
srcs = [
"service.go",
"wechat.go",
],
importpath = "go-common/app/interface/main/web-goblin/service/wechat",
tags = ["automanaged"],
visibility = ["//visibility:public"],
deps = [
"//app/interface/main/web-goblin/conf:go_default_library",
"//app/interface/main/web-goblin/dao/wechat:go_default_library",
"//app/interface/main/web-goblin/model/wechat: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,21 @@
package wechat
import (
"go-common/app/interface/main/web-goblin/conf"
"go-common/app/interface/main/web-goblin/dao/wechat"
)
// Service struct .
type Service struct {
c *conf.Config
dao *wechat.Dao
}
// New init wechat service.
func New(c *conf.Config) (s *Service) {
s = &Service{
c: c,
dao: wechat.New(c),
}
return s
}

View File

@@ -0,0 +1,19 @@
package wechat
import (
"context"
"go-common/app/interface/main/web-goblin/model/wechat"
"go-common/library/log"
)
// Qrcode get qrcode from wechat.
func (s *Service) Qrcode(c context.Context, arg string) (qrcode []byte, err error) {
var accessToken *wechat.AccessToken
if accessToken, err = s.dao.AccessToken(c); err != nil {
log.Error("Qrcode s.dao.AccessToken error(%v) arg(%s)", err, arg)
return
}
qrcode, err = s.dao.Qrcode(c, accessToken.AccessToken, arg)
return
}