dao.go 10 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390
  1. package account
  2. import (
  3. "context"
  4. "go-common/app/interface/main/creative/conf"
  5. "go-common/app/interface/main/creative/model/appeal"
  6. accapi "go-common/app/service/main/account/api"
  7. relaMdl "go-common/app/service/main/relation/model"
  8. relation "go-common/app/service/main/relation/rpc/client"
  9. "go-common/library/cache/memcache"
  10. "go-common/library/ecode"
  11. "go-common/library/log"
  12. httpx "go-common/library/net/http/blademaster"
  13. "go-common/library/sync/errgroup"
  14. "net/http"
  15. "net/url"
  16. "time"
  17. )
  18. const (
  19. _pass = "/web/site/userInfo"
  20. _richRelation = "/x/account/relation/rich"
  21. _relation = "/x/internal/relation"
  22. )
  23. // Dao is account dao.
  24. type Dao struct {
  25. c *conf.Config
  26. // rpc
  27. acc accapi.AccountClient
  28. rela *relation.Service
  29. // http client
  30. client *httpx.Client
  31. fastClient *httpx.Client
  32. mc *memcache.Pool
  33. mcExpire int32
  34. // user
  35. passURI string
  36. relationURI string
  37. richRelationURI string
  38. picUpInfoURL string
  39. blinkUpInfoURL string
  40. upInfoURL string
  41. }
  42. // New new a dao.
  43. func New(c *conf.Config) (d *Dao) {
  44. d = &Dao{
  45. c: c,
  46. rela: relation.New(c.RelationRPC),
  47. // http client
  48. client: httpx.NewClient(c.HTTPClient.Normal),
  49. fastClient: httpx.NewClient(c.HTTPClient.Fast),
  50. passURI: c.Host.Passport + _pass,
  51. relationURI: c.Host.API + _relation,
  52. richRelationURI: c.Host.API + _richRelation,
  53. picUpInfoURL: c.Host.Live + _picUpInfoURL,
  54. blinkUpInfoURL: c.Host.Live + _blinkUpInfoURL,
  55. upInfoURL: c.Host.API + _upInfoURL,
  56. mc: memcache.NewPool(c.Memcache.Archive.Config),
  57. mcExpire: int32(time.Duration(c.Memcache.Archive.TplExpire) / time.Second),
  58. }
  59. var err error
  60. if d.acc, err = accapi.NewClient(c.AccClient); err != nil {
  61. panic(err)
  62. }
  63. return
  64. }
  65. // Profile get account.
  66. func (d *Dao) Profile(c context.Context, mid int64, ip string) (res *accapi.Profile, err error) {
  67. var (
  68. arg = &accapi.MidReq{
  69. Mid: mid,
  70. }
  71. rpcRes *accapi.ProfileReply
  72. )
  73. if rpcRes, err = d.acc.Profile3(c, arg); err != nil {
  74. log.Error("d.acc.Profile3 error(%v)", err)
  75. err = ecode.CreativeAccServiceErr
  76. }
  77. if rpcRes != nil {
  78. res = rpcRes.Profile
  79. }
  80. return
  81. }
  82. // ProfileWithStat get account.
  83. func (d *Dao) ProfileWithStat(c context.Context, mid int64) (res *accapi.ProfileStatReply, err error) {
  84. var (
  85. arg = &accapi.MidReq{
  86. Mid: mid,
  87. }
  88. )
  89. if res, err = d.acc.ProfileWithStat3(c, arg); err != nil {
  90. log.Error("d.acc.ProfileWithStat3() error(%v)", err)
  91. err = ecode.CreativeAccServiceErr
  92. }
  93. return
  94. }
  95. // Card get account.
  96. func (d *Dao) Card(c context.Context, mid int64, ip string) (res *accapi.Card, err error) {
  97. var (
  98. rpcRes *accapi.CardReply
  99. arg = &accapi.MidReq{
  100. Mid: mid,
  101. }
  102. )
  103. if rpcRes, err = d.acc.Card3(c, arg); err != nil {
  104. log.Error("d.acc.Card3() error(%v)", err)
  105. err = ecode.CreativeAccServiceErr
  106. }
  107. if rpcRes != nil {
  108. res = rpcRes.Card
  109. }
  110. return
  111. }
  112. // Cards get cards from rpc
  113. func (d *Dao) Cards(c context.Context, mids []int64, ip string) (cards map[int64]*accapi.Card, err error) {
  114. if len(mids) == 0 {
  115. return
  116. }
  117. arg := &accapi.MidsReq{
  118. Mids: mids,
  119. }
  120. var reply *accapi.CardsReply
  121. if reply, err = d.acc.Cards3(c, arg); err != nil {
  122. log.Error("d.acc.Cards3 error(%v) | mids(%v) ip(%s) arg(%v)", err, mids, ip, arg)
  123. err = ecode.CreativeAccServiceErr
  124. return
  125. }
  126. cards = reply.Cards
  127. return
  128. }
  129. // PhoneEmail get user email & phone
  130. func (d *Dao) PhoneEmail(c context.Context, ck, ip string) (ct *appeal.Contact, err error) {
  131. params := url.Values{}
  132. params.Set("Cookie", ck)
  133. // init req set cookie
  134. req, err := http.NewRequest("GET", d.passURI, nil)
  135. if err != nil {
  136. log.Error("passport url(%s) error(%v)", d.passURI, err)
  137. return
  138. }
  139. req.Header.Set("Cookie", ck)
  140. req.Header.Set("X-BACKEND-BILI-REAL-IP", ip)
  141. var res struct {
  142. Code int `json:"code"`
  143. Data *appeal.Contact `json:"data"`
  144. }
  145. if err = d.client.Do(c, req, &res); err != nil {
  146. log.Error("passport url(%s) response(%+v) error(%v)", d.passURI+"?"+params.Encode(), res, err)
  147. err = ecode.CreativeAccServiceErr
  148. return
  149. }
  150. if res.Code != 0 {
  151. log.Error("passport url(%s) res(%v)", d.passURI, res)
  152. err = ecode.CreativeAccServiceErr
  153. return
  154. }
  155. ct = res.Data
  156. return
  157. }
  158. // RichRelation get multi user relations
  159. func (d *Dao) RichRelation(c context.Context, owner int64, mids []int64, ip string) (richRel map[int64]int32, err error) {
  160. var rpcRes *accapi.RichRelationsReply
  161. if rpcRes, err = d.acc.RichRelations3(c, &accapi.RichRelationReq{Owner: owner, Mids: mids}); err != nil {
  162. log.Error("d.acc.RichRelations3(%d, %v) error(%v)", owner, mids, err)
  163. err = ecode.CreativeAccServiceErr
  164. }
  165. if rpcRes != nil {
  166. richRel = rpcRes.RichRelations
  167. }
  168. return
  169. }
  170. // Followers get users only follower relation which attr eq 2 with errgroup
  171. func (d *Dao) Followers(c context.Context, owner int64, mids []int64, ip string) (relations map[int64]int, err error) {
  172. relations = make(map[int64]int, len(mids))
  173. type midRel struct {
  174. mid int64
  175. rel int
  176. }
  177. rechan := make(chan midRel, len(mids)) // avoid concurrent write map
  178. g, ctx := errgroup.WithContext(c)
  179. for _, mid := range mids {
  180. var mid2 = mid // for closure, copy to avoid same mid
  181. g.Go(func() error {
  182. rl, e := d.acc.Relation3(ctx, &accapi.RelationReq{Mid: mid2, Owner: owner})
  183. if e != nil || rl == nil || !rl.Following {
  184. if e != nil {
  185. log.Error("d.acc.Relation3(mid:%d,owner:%d,relation:%v) error(%v)", mid2, owner, rl, e)
  186. }
  187. rechan <- midRel{mid2, 1}
  188. } else {
  189. rechan <- midRel{mid2, 2}
  190. }
  191. return nil
  192. })
  193. }
  194. g.Wait()
  195. for i := 0; i < len(mids); i++ {
  196. wc := <-rechan
  197. relations[wc.mid] = wc.rel
  198. }
  199. return
  200. }
  201. // Infos get user info by mids.
  202. func (d *Dao) Infos(c context.Context, mids []int64, ip string) (res map[int64]*accapi.Info, err error) {
  203. res = make(map[int64]*accapi.Info)
  204. if len(mids) == 0 {
  205. return
  206. }
  207. var arg = &accapi.MidsReq{
  208. Mids: mids,
  209. }
  210. var rpcRes *accapi.InfosReply
  211. if rpcRes, err = d.acc.Infos3(c, arg); err != nil {
  212. log.Error("d.acc.Infos3() error(%v)|ip(%s)", err, ip)
  213. err = ecode.CreativeAccServiceErr
  214. }
  215. if rpcRes != nil {
  216. res = rpcRes.Infos
  217. }
  218. return
  219. }
  220. // IdentifyInfo 获取用户实名认证状态
  221. // tel_status int 0未绑定,1已绑定有效手机号 2绑定虚拟号段170/171
  222. // identification int 身份证绑定状态,0:未绑定 1:已绑定
  223. func (d *Dao) IdentifyInfo(c context.Context, mid int64, phoneOnly int8, ip string) (ret int, err error) {
  224. var (
  225. rpcRes *accapi.ProfileReply
  226. arg = &accapi.MidReq{
  227. Mid: mid,
  228. }
  229. mf *accapi.Profile
  230. )
  231. if rpcRes, err = d.acc.Profile3(c, arg); err != nil {
  232. log.Error("d.acc.Profile3 error(%v) | mid(%d) ip(%s) arg(%v)", err, mid, ip, arg)
  233. err = ecode.CreativeAccServiceErr
  234. return
  235. }
  236. if rpcRes != nil {
  237. mf = rpcRes.Profile
  238. }
  239. //switch for FrontEnd return json format
  240. ret = d.switchPhoneRet(int(mf.TelStatus))
  241. if phoneOnly == 1 {
  242. return
  243. }
  244. if mf.TelStatus == 1 || mf.Identification == 1 {
  245. return 0, err
  246. }
  247. return
  248. }
  249. // MidByName 获取mid
  250. func (d *Dao) MidByName(c context.Context, name string) (mid int64, err error) {
  251. var (
  252. rpcRes *accapi.InfosReply
  253. arg = &accapi.NamesReq{
  254. Names: []string{name},
  255. }
  256. infos map[int64]*accapi.Info
  257. )
  258. if rpcRes, err = d.acc.InfosByName3(c, arg); err != nil {
  259. log.Error("d.acc.InfosByName3 error(%v)", err)
  260. err = ecode.CreativeAccServiceErr
  261. return
  262. }
  263. if rpcRes != nil {
  264. infos = rpcRes.Infos
  265. }
  266. for _, v := range infos {
  267. if v != nil && v.Name == name {
  268. return v.Mid, nil
  269. }
  270. }
  271. err = ecode.AccountInexistence
  272. return
  273. }
  274. // 0: "已实名认证",
  275. // 1: "根据国家实名制认证的相关要求,您需要换绑一个非170/171的手机号,才能继续进行操作。",
  276. // 2: "根据国家实名制认证的相关要求,您需要绑定手机号,才能继续进行操作。",
  277. func (d *Dao) switchPhoneRet(newV int) (oldV int) {
  278. switch newV {
  279. case 0:
  280. oldV = 2
  281. case 1:
  282. oldV = 0
  283. case 2:
  284. oldV = 1
  285. }
  286. return
  287. }
  288. // CheckIdentify fn
  289. func (d *Dao) CheckIdentify(identify int) (err error) {
  290. switch identify {
  291. case 0:
  292. err = nil
  293. case 1:
  294. err = ecode.UserCheckInvalidPhone
  295. case 2:
  296. err = ecode.UserCheckNoPhone
  297. }
  298. return
  299. }
  300. // RelationFollowers get all relation state.
  301. func (d *Dao) RelationFollowers(c context.Context, mid int64, ip string) (res map[int64]int32, err error) {
  302. var fls []*relaMdl.Following
  303. if fls, err = d.rela.Followers(c, &relaMdl.ArgMid{Mid: mid, RealIP: ip}); err != nil {
  304. log.Error("d.rela.Followers mid(%d)|ip(%s)|error(%v)", mid, ip, err)
  305. return
  306. }
  307. if len(fls) == 0 {
  308. log.Info("d.rela.Followers mid(%d)|ip(%s)", mid, ip)
  309. return
  310. }
  311. res = make(map[int64]int32, len(fls))
  312. for _, v := range fls {
  313. res[v.Mid] = int32(v.Attribute)
  314. }
  315. log.Info("d.rela.Followers mid(%d)|res(%+v)|ip(%s)", mid, res, ip)
  316. return
  317. }
  318. // Relations get all relation state.
  319. func (d *Dao) Relations(c context.Context, mid int64, fids []int64, ip string) (res map[int64]int, err error) {
  320. var rls map[int64]*relaMdl.Following
  321. if rls, err = d.rela.Relations(c, &relaMdl.ArgRelations{Mid: mid, Fids: fids, RealIP: ip}); err != nil {
  322. log.Error("d.rela.Relations mid(%d)|ip(%s)|error(%v)", mid, ip, err)
  323. err = ecode.CreativeAccServiceErr
  324. return
  325. }
  326. if len(rls) == 0 {
  327. log.Info("d.rela.Relations mid(%d)|ip(%s)", mid, ip)
  328. return
  329. }
  330. res = make(map[int64]int, len(rls))
  331. for _, v := range rls {
  332. res[v.Mid] = int(v.Attribute)
  333. }
  334. log.Info("d.rela.Relations mid(%d)|res(%+v)|rls(%+v)|ip(%s)", mid, res, rls, ip)
  335. return
  336. }
  337. // Relations2
  338. func (d *Dao) Relations2(c context.Context, mid int64, fids []int64, ip string) (res map[int64]int, err error) {
  339. if res, err = d.Relations(c, mid, fids, ip); err != nil {
  340. return
  341. }
  342. for k, v := range res {
  343. if v == 2 || v == 6 { //2表示我关注他,6表示双向关注,为了兼容客户端统一吐出6作为已关注状态.
  344. res[k] = 6
  345. } else {
  346. delete(res, k)
  347. }
  348. }
  349. return
  350. }
  351. // ShouldFollow fn
  352. func (d *Dao) ShouldFollow(c context.Context, mid int64, fids []int64, ip string) (shouldMids []int64, err error) {
  353. var rls map[int64]*relaMdl.Following
  354. if rls, err = d.rela.Relations(c, &relaMdl.ArgRelations{Mid: mid, Fids: fids, RealIP: ip}); err != nil {
  355. log.Error("d.rela.Relations mid(%d)|fids(%+v)|ip(%s)|error(%v)", mid, fids, ip, err)
  356. return
  357. }
  358. if len(rls) == 0 {
  359. shouldMids = fids
  360. return
  361. }
  362. shouldMids = make([]int64, 0)
  363. for _, v := range rls {
  364. if v.Attribute == 0 {
  365. shouldMids = append(shouldMids, v.Mid)
  366. }
  367. }
  368. log.Info("d.rela.Relations mid(%d)|shouldMids(%+v)|ip(%s)", mid, shouldMids, ip)
  369. return
  370. }