go-common/app/interface/main/creative/dao/account/dao.go
2019-04-22 18:49:16 +08:00

391 lines
10 KiB
Go
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

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
}