You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
390 lines
10 KiB
390 lines
10 KiB
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 |
|
}
|
|
|