391 lines
10 KiB
Go
391 lines
10 KiB
Go
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
|
||
}
|