go-common/app/interface/main/creative/dao/account/dao.go

391 lines
10 KiB
Go
Raw Normal View History

2019-04-22 10:49:16 +00:00
package account
import (
"context"
"go-common/app/interface/main/creative/conf"
"go-common/app/interface/main/creative/model/appeal"
accapi "go-common/app/service/main/account/api"
relaMdl "go-common/app/service/main/relation/model"
relation "go-common/app/service/main/relation/rpc/client"
"go-common/library/cache/memcache"
"go-common/library/ecode"
"go-common/library/log"
httpx "go-common/library/net/http/blademaster"
"go-common/library/sync/errgroup"
"net/http"
"net/url"
"time"
)
const (
_pass = "/web/site/userInfo"
_richRelation = "/x/account/relation/rich"
_relation = "/x/internal/relation"
)
// Dao is account dao.
type Dao struct {
c *conf.Config
// rpc
acc accapi.AccountClient
rela *relation.Service
// http client
client *httpx.Client
fastClient *httpx.Client
mc *memcache.Pool
mcExpire int32
// user
passURI string
relationURI string
richRelationURI string
picUpInfoURL string
blinkUpInfoURL string
upInfoURL string
}
// New new a dao.
func New(c *conf.Config) (d *Dao) {
d = &Dao{
c: c,
rela: relation.New(c.RelationRPC),
// http client
client: httpx.NewClient(c.HTTPClient.Normal),
fastClient: httpx.NewClient(c.HTTPClient.Fast),
passURI: c.Host.Passport + _pass,
relationURI: c.Host.API + _relation,
richRelationURI: c.Host.API + _richRelation,
picUpInfoURL: c.Host.Live + _picUpInfoURL,
blinkUpInfoURL: c.Host.Live + _blinkUpInfoURL,
upInfoURL: c.Host.API + _upInfoURL,
mc: memcache.NewPool(c.Memcache.Archive.Config),
mcExpire: int32(time.Duration(c.Memcache.Archive.TplExpire) / time.Second),
}
var err error
if d.acc, err = accapi.NewClient(c.AccClient); err != nil {
panic(err)
}
return
}
// Profile get account.
func (d *Dao) Profile(c context.Context, mid int64, ip string) (res *accapi.Profile, err error) {
var (
arg = &accapi.MidReq{
Mid: mid,
}
rpcRes *accapi.ProfileReply
)
if rpcRes, err = d.acc.Profile3(c, arg); err != nil {
log.Error("d.acc.Profile3 error(%v)", err)
err = ecode.CreativeAccServiceErr
}
if rpcRes != nil {
res = rpcRes.Profile
}
return
}
// ProfileWithStat get account.
func (d *Dao) ProfileWithStat(c context.Context, mid int64) (res *accapi.ProfileStatReply, err error) {
var (
arg = &accapi.MidReq{
Mid: mid,
}
)
if res, err = d.acc.ProfileWithStat3(c, arg); err != nil {
log.Error("d.acc.ProfileWithStat3() error(%v)", err)
err = ecode.CreativeAccServiceErr
}
return
}
// Card get account.
func (d *Dao) Card(c context.Context, mid int64, ip string) (res *accapi.Card, err error) {
var (
rpcRes *accapi.CardReply
arg = &accapi.MidReq{
Mid: mid,
}
)
if rpcRes, err = d.acc.Card3(c, arg); err != nil {
log.Error("d.acc.Card3() error(%v)", err)
err = ecode.CreativeAccServiceErr
}
if rpcRes != nil {
res = rpcRes.Card
}
return
}
// Cards get cards from rpc
func (d *Dao) Cards(c context.Context, mids []int64, ip string) (cards map[int64]*accapi.Card, err error) {
if len(mids) == 0 {
return
}
arg := &accapi.MidsReq{
Mids: mids,
}
var reply *accapi.CardsReply
if reply, err = d.acc.Cards3(c, arg); err != nil {
log.Error("d.acc.Cards3 error(%v) | mids(%v) ip(%s) arg(%v)", err, mids, ip, arg)
err = ecode.CreativeAccServiceErr
return
}
cards = reply.Cards
return
}
// PhoneEmail get user email & phone
func (d *Dao) PhoneEmail(c context.Context, ck, ip string) (ct *appeal.Contact, err error) {
params := url.Values{}
params.Set("Cookie", ck)
// init req set cookie
req, err := http.NewRequest("GET", d.passURI, nil)
if err != nil {
log.Error("passport url(%s) error(%v)", d.passURI, err)
return
}
req.Header.Set("Cookie", ck)
req.Header.Set("X-BACKEND-BILI-REAL-IP", ip)
var res struct {
Code int `json:"code"`
Data *appeal.Contact `json:"data"`
}
if err = d.client.Do(c, req, &res); err != nil {
log.Error("passport url(%s) response(%+v) error(%v)", d.passURI+"?"+params.Encode(), res, err)
err = ecode.CreativeAccServiceErr
return
}
if res.Code != 0 {
log.Error("passport url(%s) res(%v)", d.passURI, res)
err = ecode.CreativeAccServiceErr
return
}
ct = res.Data
return
}
// RichRelation get multi user relations
func (d *Dao) RichRelation(c context.Context, owner int64, mids []int64, ip string) (richRel map[int64]int32, err error) {
var rpcRes *accapi.RichRelationsReply
if rpcRes, err = d.acc.RichRelations3(c, &accapi.RichRelationReq{Owner: owner, Mids: mids}); err != nil {
log.Error("d.acc.RichRelations3(%d, %v) error(%v)", owner, mids, err)
err = ecode.CreativeAccServiceErr
}
if rpcRes != nil {
richRel = rpcRes.RichRelations
}
return
}
// Followers get users only follower relation which attr eq 2 with errgroup
func (d *Dao) Followers(c context.Context, owner int64, mids []int64, ip string) (relations map[int64]int, err error) {
relations = make(map[int64]int, len(mids))
type midRel struct {
mid int64
rel int
}
rechan := make(chan midRel, len(mids)) // avoid concurrent write map
g, ctx := errgroup.WithContext(c)
for _, mid := range mids {
var mid2 = mid // for closure, copy to avoid same mid
g.Go(func() error {
rl, e := d.acc.Relation3(ctx, &accapi.RelationReq{Mid: mid2, Owner: owner})
if e != nil || rl == nil || !rl.Following {
if e != nil {
log.Error("d.acc.Relation3(mid:%d,owner:%d,relation:%v) error(%v)", mid2, owner, rl, e)
}
rechan <- midRel{mid2, 1}
} else {
rechan <- midRel{mid2, 2}
}
return nil
})
}
g.Wait()
for i := 0; i < len(mids); i++ {
wc := <-rechan
relations[wc.mid] = wc.rel
}
return
}
// Infos get user info by mids.
func (d *Dao) Infos(c context.Context, mids []int64, ip string) (res map[int64]*accapi.Info, err error) {
res = make(map[int64]*accapi.Info)
if len(mids) == 0 {
return
}
var arg = &accapi.MidsReq{
Mids: mids,
}
var rpcRes *accapi.InfosReply
if rpcRes, err = d.acc.Infos3(c, arg); err != nil {
log.Error("d.acc.Infos3() error(%v)|ip(%s)", err, ip)
err = ecode.CreativeAccServiceErr
}
if rpcRes != nil {
res = rpcRes.Infos
}
return
}
// IdentifyInfo 获取用户实名认证状态
// tel_status int 0未绑定1已绑定有效手机号 2绑定虚拟号段170/171
// identification int 身份证绑定状态0:未绑定 1:已绑定
func (d *Dao) IdentifyInfo(c context.Context, mid int64, phoneOnly int8, ip string) (ret int, err error) {
var (
rpcRes *accapi.ProfileReply
arg = &accapi.MidReq{
Mid: mid,
}
mf *accapi.Profile
)
if rpcRes, err = d.acc.Profile3(c, arg); err != nil {
log.Error("d.acc.Profile3 error(%v) | mid(%d) ip(%s) arg(%v)", err, mid, ip, arg)
err = ecode.CreativeAccServiceErr
return
}
if rpcRes != nil {
mf = rpcRes.Profile
}
//switch for FrontEnd return json format
ret = d.switchPhoneRet(int(mf.TelStatus))
if phoneOnly == 1 {
return
}
if mf.TelStatus == 1 || mf.Identification == 1 {
return 0, err
}
return
}
// MidByName 获取mid
func (d *Dao) MidByName(c context.Context, name string) (mid int64, err error) {
var (
rpcRes *accapi.InfosReply
arg = &accapi.NamesReq{
Names: []string{name},
}
infos map[int64]*accapi.Info
)
if rpcRes, err = d.acc.InfosByName3(c, arg); err != nil {
log.Error("d.acc.InfosByName3 error(%v)", err)
err = ecode.CreativeAccServiceErr
return
}
if rpcRes != nil {
infos = rpcRes.Infos
}
for _, v := range infos {
if v != nil && v.Name == name {
return v.Mid, nil
}
}
err = ecode.AccountInexistence
return
}
// 0: "已实名认证",
// 1: "根据国家实名制认证的相关要求您需要换绑一个非170/171的手机号才能继续进行操作。",
// 2: "根据国家实名制认证的相关要求,您需要绑定手机号,才能继续进行操作。",
func (d *Dao) switchPhoneRet(newV int) (oldV int) {
switch newV {
case 0:
oldV = 2
case 1:
oldV = 0
case 2:
oldV = 1
}
return
}
// CheckIdentify fn
func (d *Dao) CheckIdentify(identify int) (err error) {
switch identify {
case 0:
err = nil
case 1:
err = ecode.UserCheckInvalidPhone
case 2:
err = ecode.UserCheckNoPhone
}
return
}
// RelationFollowers get all relation state.
func (d *Dao) RelationFollowers(c context.Context, mid int64, ip string) (res map[int64]int32, err error) {
var fls []*relaMdl.Following
if fls, err = d.rela.Followers(c, &relaMdl.ArgMid{Mid: mid, RealIP: ip}); err != nil {
log.Error("d.rela.Followers mid(%d)|ip(%s)|error(%v)", mid, ip, err)
return
}
if len(fls) == 0 {
log.Info("d.rela.Followers mid(%d)|ip(%s)", mid, ip)
return
}
res = make(map[int64]int32, len(fls))
for _, v := range fls {
res[v.Mid] = int32(v.Attribute)
}
log.Info("d.rela.Followers mid(%d)|res(%+v)|ip(%s)", mid, res, ip)
return
}
// Relations get all relation state.
func (d *Dao) Relations(c context.Context, mid int64, fids []int64, ip string) (res map[int64]int, err error) {
var rls map[int64]*relaMdl.Following
if rls, err = d.rela.Relations(c, &relaMdl.ArgRelations{Mid: mid, Fids: fids, RealIP: ip}); err != nil {
log.Error("d.rela.Relations mid(%d)|ip(%s)|error(%v)", mid, ip, err)
err = ecode.CreativeAccServiceErr
return
}
if len(rls) == 0 {
log.Info("d.rela.Relations mid(%d)|ip(%s)", mid, ip)
return
}
res = make(map[int64]int, len(rls))
for _, v := range rls {
res[v.Mid] = int(v.Attribute)
}
log.Info("d.rela.Relations mid(%d)|res(%+v)|rls(%+v)|ip(%s)", mid, res, rls, ip)
return
}
// Relations2
func (d *Dao) Relations2(c context.Context, mid int64, fids []int64, ip string) (res map[int64]int, err error) {
if res, err = d.Relations(c, mid, fids, ip); err != nil {
return
}
for k, v := range res {
if v == 2 || v == 6 { //2表示我关注他,6表示双向关注,为了兼容客户端统一吐出6作为已关注状态.
res[k] = 6
} else {
delete(res, k)
}
}
return
}
// ShouldFollow fn
func (d *Dao) ShouldFollow(c context.Context, mid int64, fids []int64, ip string) (shouldMids []int64, err error) {
var rls map[int64]*relaMdl.Following
if rls, err = d.rela.Relations(c, &relaMdl.ArgRelations{Mid: mid, Fids: fids, RealIP: ip}); err != nil {
log.Error("d.rela.Relations mid(%d)|fids(%+v)|ip(%s)|error(%v)", mid, fids, ip, err)
return
}
if len(rls) == 0 {
shouldMids = fids
return
}
shouldMids = make([]int64, 0)
for _, v := range rls {
if v.Attribute == 0 {
shouldMids = append(shouldMids, v.Mid)
}
}
log.Info("d.rela.Relations mid(%d)|shouldMids(%+v)|ip(%s)", mid, shouldMids, ip)
return
}