dmpost.go 22 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768
  1. package service
  2. import (
  3. "context"
  4. "encoding/json"
  5. "fmt"
  6. "regexp"
  7. "strconv"
  8. "strings"
  9. "time"
  10. "go-common/app/interface/main/dm2/model"
  11. "go-common/app/interface/main/dm2/model/oplog"
  12. account "go-common/app/service/main/account/api"
  13. "go-common/app/service/main/archive/api"
  14. arcMdl "go-common/app/service/main/archive/model/archive"
  15. figureMdl "go-common/app/service/main/figure/model"
  16. filterMdl "go-common/app/service/main/filter/api/grpc/v1"
  17. locmdl "go-common/app/service/main/location/model"
  18. spyMdl "go-common/app/service/main/spy/model"
  19. ugcPayMdl "go-common/app/service/main/ugcpay/api/grpc/v1"
  20. seasonMbl "go-common/app/service/openplatform/pgc-season/api/grpc/season/v1"
  21. "go-common/library/ecode"
  22. "go-common/library/log"
  23. "go-common/library/net/metadata"
  24. )
  25. var (
  26. msgRegex = regexp.MustCompile(`^(\s|\xE3\x80\x80)*$`) // 全文仅空格
  27. _dateFormat = "20060102"
  28. )
  29. //Post dm post
  30. func (s *Service) Post(c context.Context, dm *model.DM, aid, rnd int64) (err error) {
  31. // 验证主题是否存在
  32. sub, err := s.subject(c, dm.Type, dm.Oid)
  33. if err != nil {
  34. return
  35. }
  36. if sub.State == model.SubStateClosed {
  37. err = ecode.DMForbidPost
  38. return
  39. }
  40. if sub.Maxlimit == 0 {
  41. return
  42. }
  43. // 验证海外用户
  44. if err = s.checkOverseasUser(c); err != nil {
  45. return
  46. }
  47. // 验证账号信息
  48. myinfo, err := s.checkAccountInfo(c, dm.Mid)
  49. if err != nil {
  50. return
  51. }
  52. // 验证弹幕内容
  53. if err = s.checkMsg(c, dm, myinfo); err != nil {
  54. return
  55. }
  56. // 验证弹幕progress
  57. duration, err := s.videoDuration(c, aid, dm.Oid)
  58. if err != nil {
  59. return
  60. }
  61. if duration > 0 && int64(dm.Progress) > duration {
  62. return ecode.DMProgressTooBig
  63. }
  64. // 验证稿件信息
  65. arc, err := s.checkArchiveInfo(c, aid, dm.Oid, myinfo.GetRank(), dm.Content.Mode)
  66. if err != nil {
  67. return
  68. }
  69. if sub.Mid != dm.Mid && arc.Rights.UGCPay == arcMdl.AttrYes {
  70. if err = s.archiveUgcPay(c, dm.Mid, aid); err != nil {
  71. return
  72. }
  73. }
  74. // 验证弹幕发送速率
  75. if err = s.checkPubRate(c, dm, sub.Mid, rnd, myinfo.GetRank()); err != nil {
  76. return
  77. }
  78. // 判定用户发送速率
  79. if err = s.checkRateLimit(c, myinfo.GetRank(), dm.Mid); err != nil {
  80. return
  81. }
  82. // 验证弹幕颜色
  83. if err = s.checkMsgColor(sub.Mid, myinfo, dm); err != nil {
  84. return
  85. }
  86. // 判定弹幕字体大小
  87. if err = s.checkFontsize(dm, sub.Mid, myinfo.GetRank()); err != nil {
  88. return
  89. }
  90. // 验证mode 1、4、5、6
  91. if err = s.checkNormalMode(sub.Mid, myinfo, dm); err != nil {
  92. return
  93. }
  94. // 验证mode 7发送权限
  95. if err = s.checkAdvanceMode(c, dm, sub.Mid, myinfo); err != nil {
  96. return
  97. }
  98. // 验证特殊弹幕池(pool=1 pool=2)发送权限
  99. if err = s.checkSpecialPool(c, dm, sub.Mid, myinfo); err != nil {
  100. return
  101. }
  102. // 生成弹幕id
  103. if err = s.genDMID(c, dm); err != nil {
  104. return
  105. }
  106. // 弹幕屏蔽词过滤
  107. if err = s.checkFilterService(c, dm, arc); err != nil {
  108. return
  109. }
  110. // 检查up的全局屏蔽词
  111. if err = s.checkUpFilter(c, dm, sub.Mid, myinfo.GetRank()); err != nil {
  112. return
  113. }
  114. // 弹幕的先审后发和先发后审
  115. if err = s.checkMonitor(c, sub, dm); err != nil {
  116. return
  117. }
  118. // 垃圾弹幕过滤
  119. if err = s.checkUnusualAction(c, dm, myinfo); err != nil {
  120. return
  121. }
  122. // bnj专用 黑名单过滤
  123. s.checkShield(c, aid, dm)
  124. // 发消息给job异步落库
  125. if err = s.asyncAddDM(dm, arc.Aid, arc.TypeID); err != nil {
  126. return
  127. }
  128. remark := fmt.Sprintf("新增弹幕,ip:%s,port:%s", metadata.String(c, metadata.RemoteIP), metadata.String(c, metadata.RemotePort))
  129. s.OpLog(c, dm.Oid, dm.Mid, time.Now().Add(time.Second).Unix(), 1, []int64{dm.ID}, "status", "", strconv.FormatInt(int64(dm.State), 10), remark, oplog.SourcePlayer, oplog.OperatorMember)
  130. // 弹幕行为日志
  131. s.dao.ReportDmLog(c, dm)
  132. // 弹幕广播
  133. select {
  134. case s.broadcastChan <- &broadcast{Aid: arc.Aid, Rnd: rnd, DM: dm}:
  135. default:
  136. log.Error("broadcast channel is full")
  137. }
  138. return
  139. }
  140. // checkUnusualAction check unusual post dm
  141. func (s *Service) checkUnusualAction(c context.Context, dm *model.DM, accInfo *account.Profile) (err error) {
  142. var (
  143. ip = metadata.String(c, metadata.RemoteIP)
  144. userScore *spyMdl.UserScore
  145. figureWithRank *figureMdl.FigureWithRank
  146. dmDailyLimit *model.DailyLimiter
  147. )
  148. if !s.garbageDanmu {
  149. return
  150. }
  151. if userScore, err = s.spyRPC.UserScore(c, &spyMdl.ArgUserScore{
  152. Mid: accInfo.GetMid(),
  153. IP: ip,
  154. }); err != nil {
  155. // dragrade spy service
  156. err = nil
  157. return
  158. }
  159. if figureWithRank, err = s.figureRPC.UserFigure(c, &figureMdl.ArgUserFigure{
  160. Mid: accInfo.GetMid(),
  161. }); err != nil {
  162. if ecode.Cause(err).Code() != ecode.FigureNotFound.Code() {
  163. log.Error("checkUnusualAction.UserFigure(mid:%v) error(%v)", accInfo.GetMid(), err)
  164. return
  165. }
  166. err = nil
  167. return
  168. }
  169. if accInfo.GetMid() > 50000000 && accInfo.GetLevel() <= 2 && figureWithRank.Percentage > 40 && userScore.Score < 90 {
  170. if dmDailyLimit, err = s.dao.GetDmDailyLimitCache(c, accInfo.GetMid()); err != nil {
  171. return
  172. }
  173. now := time.Now().Format(_dateFormat)
  174. if dmDailyLimit == nil || now > dmDailyLimit.Date {
  175. dmDailyLimit = &model.DailyLimiter{
  176. Date: time.Now().Format(_dateFormat),
  177. Count: 0,
  178. }
  179. }
  180. dmDailyLimit.Count++
  181. if dmDailyLimit.Count > 5 {
  182. dm.State = model.StateDelete
  183. s.OpLog(c, dm.Oid, dm.Mid, time.Now().Unix(), 1, []int64{dm.ID}, "status", "", strconv.FormatInt(int64(dm.State), 10), "垃圾弹幕发送", oplog.SourcePlayer, oplog.OperatorMember)
  184. s.dao.ReportDmGarbageLog(c, dm)
  185. }
  186. if err = s.dao.SetDmDailyLimitCache(c, accInfo.GetMid(), dmDailyLimit); err != nil {
  187. return
  188. }
  189. return
  190. }
  191. return
  192. }
  193. func (s *Service) checkFontsize(dm *model.DM, upid int64, rank int32) (err error) {
  194. if !s.isSuperUser(rank) && dm.Content.Mode != model.ModeSpecial {
  195. if dm.Content.FontSize != 18 && dm.Content.FontSize != 25 {
  196. dm.Content.FontSize = 25
  197. }
  198. }
  199. return
  200. }
  201. func (s *Service) checkMsgColor(upid int64, profile *account.Profile, dm *model.DM) (err error) {
  202. if s.isSuperUser(profile.GetRank()) || dm.Mid == upid {
  203. return
  204. }
  205. if profile.GetLevel() <= 1 && dm.Content.Color != 0xffffff {
  206. err = ecode.DMMsgNoColorPerm
  207. }
  208. return
  209. }
  210. // 验证mode 1、4、5、6
  211. func (s *Service) checkNormalMode(upid int64, profile *account.Profile, dm *model.DM) (err error) {
  212. if s.isSuperUser(profile.GetRank()) {
  213. return
  214. }
  215. switch dm.Content.Mode {
  216. case 1:
  217. if profile.GetLevel() < 1 && upid != dm.Mid {
  218. err = ecode.DMMsgNoPubPerm
  219. }
  220. case 4:
  221. if profile.GetLevel() < 3 && upid != dm.Mid {
  222. err = ecode.DMMsgNoPubBottomPerm
  223. }
  224. case 5:
  225. if profile.GetLevel() < 3 && upid != dm.Mid {
  226. err = ecode.DMMsgNoPubTopPerm
  227. }
  228. case 6:
  229. err = ecode.DMMsgNoPubAdvancePerm
  230. }
  231. return
  232. }
  233. // 验证 mode 7
  234. func (s *Service) checkAdvanceMode(c context.Context, dm *model.DM, upid int64, profile *account.Profile) (err error) {
  235. if dm.Content.Mode != 7 || dm.Mid == upid || s.isSuperUser(profile.GetRank()) {
  236. return
  237. }
  238. if profile.GetLevel() <= 1 {
  239. err = ecode.DMMsgNoPubStylePerm
  240. return
  241. }
  242. var adv *model.AdvanceCmt
  243. if adv, err = s.advanceComment(c, dm.Oid, dm.Mid, "sp"); err != nil {
  244. return
  245. }
  246. if adv.Type != "buy" && adv.Type != "accept" {
  247. err = ecode.DMMsgNoPubStylePerm
  248. }
  249. return
  250. }
  251. // 验证 pool 1、2
  252. func (s *Service) checkSpecialPool(c context.Context, dm *model.DM, upid int64, profile *account.Profile) (err error) {
  253. if (dm.Pool != 1 && dm.Pool != 2) || dm.Mid == upid || s.isSuperUser(profile.Rank) {
  254. return
  255. }
  256. if dm.Pool == model.PoolSubtitle {
  257. dm.Pool = model.PoolNormal
  258. log.Warn("force change(%+v) pool to normal", dm)
  259. return
  260. }
  261. if profile.Level <= 1 {
  262. err = ecode.DMMsgNoPubStylePerm
  263. return
  264. }
  265. var adv *model.AdvanceCmt
  266. if dm.Pool == model.PoolSpecial {
  267. if adv, err = s.advanceComment(c, dm.Oid, dm.Mid, "advance"); err != nil {
  268. return
  269. }
  270. if adv.Type != "buy" && adv.Type != "accept" {
  271. err = ecode.DMMsgNoPubStylePerm
  272. return
  273. }
  274. if profile.Rank <= 10000 {
  275. err = ecode.DMMsgNoPubStylePerm
  276. }
  277. }
  278. return
  279. }
  280. func (s *Service) checkFilterService(c context.Context, dm *model.DM, arc *api.Arc) (err error) {
  281. if dm.Content.Mode == 7 || dm.Content.Mode == 8 || dm.Content.Mode == 9 {
  282. return
  283. }
  284. var (
  285. sid int32
  286. pid int64
  287. rid = arc.TypeID
  288. keys []string
  289. filterReply *filterMdl.FilterReply
  290. seasonReply *seasonMbl.CardsInfoReply
  291. )
  292. if v, ok := s.arcTypes[int16(rid)]; ok {
  293. pid = int64(v)
  294. }
  295. if arc.AttrVal(arcMdl.AttrBitIsBangumi) == arcMdl.AttrYes {
  296. if seasonReply, err = s.seasonRPC.CardsByAids(c, &seasonMbl.SeasonAidReq{
  297. Aids: []int32{int32(arc.Aid)},
  298. }); err != nil || seasonReply == nil {
  299. log.Error("s.seasonRPC.CardsByAids(%d) error(%v)", arc.Aid, err) // NOTE ignore error and continue
  300. } else if seasonInfo, ok := seasonReply.Cards[int32(arc.Aid)]; !ok {
  301. log.Error("seasonReply.Cards(%d) don't exist", arc.Aid)
  302. } else {
  303. sid = seasonInfo.SeasonId
  304. }
  305. }
  306. if sid > 0 {
  307. keys = append(keys, fmt.Sprintf("season:%d", sid))
  308. }
  309. keys = append(keys, fmt.Sprintf("typeid:%d", rid))
  310. keys = append(keys, fmt.Sprintf("typeid:%d", pid))
  311. keys = append(keys, fmt.Sprintf("cid:%d", dm.Oid))
  312. keys = append(keys, fmt.Sprintf("aid:%d", arc.Aid))
  313. if filterReply, err = s.filterRPC.Filter(c, &filterMdl.FilterReq{
  314. Area: "danmu",
  315. Message: dm.Content.Msg,
  316. TypeId: int64(rid),
  317. Id: dm.ID,
  318. Oid: dm.Oid,
  319. Mid: dm.Mid,
  320. Keys: keys,
  321. }); err != nil {
  322. log.Error("checkFilterService(dm:%+v),err(%v)", dm, err)
  323. return
  324. }
  325. if filterReply.Level > 0 || filterReply.Limit == model.SpamBlack || filterReply.Limit == model.SpamOverflow {
  326. dm.State = model.StateFilter
  327. log.Info("filter service delete(dmid:%d,data:+%v)", dm.ID, filterReply)
  328. remark := filterReply.Result
  329. if filterReply.Limit == model.SpamBlack {
  330. remark = "命中反垃圾黑名单"
  331. }
  332. if filterReply.Limit == model.SpamOverflow {
  333. remark = "超过反垃圾限制次数"
  334. }
  335. s.OpLog(c, dm.Oid, dm.Mid, time.Now().Unix(), 1, []int64{dm.ID}, "status", "", strconv.FormatInt(int64(dm.State), 10), remark, oplog.SourcePlayer, oplog.OperatorMember)
  336. return
  337. }
  338. if filterReply.Ai != nil && len(filterReply.Ai.Scores) > 0 && filterReply.Ai.Scores[0] > filterReply.Ai.Threshold {
  339. dm.State = model.StateAiDelete
  340. s.OpLog(c, dm.Oid, dm.Mid, time.Now().Unix(), 1, []int64{dm.ID}, "status", "", strconv.FormatInt(int64(dm.State), 10), "ai 反垃圾屏蔽", oplog.SourcePlayer, oplog.OperatorMember)
  341. return
  342. }
  343. return
  344. }
  345. // checkUpFilter up主屏蔽词过滤
  346. func (s *Service) checkUpFilter(c context.Context, dm *model.DM, upid int64, rank int32) (err error) {
  347. // 命中屏蔽词系统 或者 mode 8 9 后则不再进行校验up主屏蔽词
  348. if dm.State == model.StateFilter || dm.Content.Mode == model.ModeCode || dm.Content.Mode == model.ModeBAS {
  349. return
  350. }
  351. var (
  352. msg string
  353. fltModes []int32
  354. texts, regexs, users []string
  355. )
  356. // up主全局屏蔽词
  357. filters, err := s.UpFilters(c, upid)
  358. if err != nil {
  359. return
  360. }
  361. for _, f := range filters {
  362. switch f.Type {
  363. case 0: // 文本类型
  364. texts = append(texts, f.Filter)
  365. case 1: // 正则类型
  366. f.Filter = strings.Replace(f.Filter, "/", "\\/", -1)
  367. regexs = append(regexs, f.Filter)
  368. case 2: // 用户黑名单
  369. f.Filter = strings.ToLower(f.Filter)
  370. users = append(users, f.Filter)
  371. case 4, 5, 6, 7: // 4:down,5:up,6:reverse,7:special
  372. fltModes = append(fltModes, int32(f.Type))
  373. }
  374. }
  375. // check content filter
  376. if dm.Content.Mode == model.ModeSpecial {
  377. strs := strings.Split(dm.Content.Msg, ",")
  378. if len(strs) < 4 || len(strs[4]) < 2 {
  379. log.Error("s.checkUpFilter(%s) error(spec content format err)", dm)
  380. return
  381. }
  382. msg = strs[4][1 : len(strs[4])-1]
  383. } else {
  384. msg = dm.Content.Msg
  385. }
  386. // 验证up设置的mode屏蔽
  387. for _, mode := range fltModes {
  388. if mode == dm.Content.Mode {
  389. dm.State = model.StateBlock
  390. s.OpLog(c, dm.Oid, dm.Mid, time.Now().Unix(), 1, []int64{dm.ID}, "status", "", strconv.FormatInt(int64(dm.State), 10), "命中类型屏蔽("+fmt.Sprint(mode)+")", oplog.SourcePlayer, oplog.OperatorMember)
  391. return
  392. }
  393. }
  394. // 关键字过滤
  395. for _, text := range texts {
  396. if strings.Contains(strings.ToLower(msg), strings.ToLower(text)) {
  397. dm.State = model.StateBlock
  398. s.OpLog(c, dm.Oid, dm.Mid, time.Now().Unix(), 1, []int64{dm.ID}, "status", "", strconv.FormatInt(int64(dm.State), 10), "命中关键字屏蔽("+text+")", oplog.SourcePlayer, oplog.OperatorMember)
  399. return
  400. }
  401. }
  402. // 正则过滤
  403. for _, reg := range regexs {
  404. rc, rErr := regexp.Compile(reg)
  405. if rErr != nil {
  406. log.Error("regexp.Compile(%s) error(%v)", reg, rErr)
  407. continue
  408. }
  409. if rc.MatchString(msg) {
  410. dm.State = model.StateBlock
  411. s.OpLog(c, dm.Oid, dm.Mid, time.Now().Unix(), 1, []int64{dm.ID}, "status", "", strconv.FormatInt(int64(dm.State), 10), "命中正则屏蔽("+reg+")", oplog.SourcePlayer, oplog.OperatorMember)
  412. return
  413. }
  414. }
  415. // 验证up设置的屏蔽用户
  416. hashID := model.Hash(dm.Mid, uint32(dm.Content.IP))
  417. for _, user := range users {
  418. if hashID == user {
  419. dm.State = model.StateBlock
  420. s.OpLog(c, dm.Oid, dm.Mid, time.Now().Unix(), 1, []int64{dm.ID}, "status", "", strconv.FormatInt(int64(dm.State), 10), "屏蔽黑名单屏蔽("+hashID+")", oplog.SourcePlayer, oplog.OperatorMember)
  421. return
  422. }
  423. }
  424. return
  425. }
  426. func (s *Service) checkRateLimit(c context.Context, rank int32, mid int64) (err error) {
  427. now := time.Now().Unix()
  428. ltime, ok := model.LimitPerMin[rank]
  429. if !ok {
  430. ltime = model.LimitPerMin[0]
  431. }
  432. limiter, err := s.dao.DMLimitCache(c, mid)
  433. if err != nil {
  434. return
  435. }
  436. if limiter == nil {
  437. limiter = &model.Limiter{Allowance: ltime, Timestamp: now}
  438. }
  439. allowance := limiter.Allowance + ((now - limiter.Timestamp) * ltime / 600)
  440. if allowance > ltime {
  441. allowance = ltime
  442. }
  443. if allowance < 1 {
  444. err = ecode.DMMsgPubTooFast
  445. allowance = 0
  446. } else {
  447. allowance--
  448. }
  449. limiter = &model.Limiter{Allowance: allowance, Timestamp: now}
  450. s.dao.AddDMLimitCache(c, mid, limiter) // NOTE omit error
  451. return
  452. }
  453. func (s *Service) checkAccountInfo(c context.Context, mid int64) (profile *account.Profile, err error) {
  454. var (
  455. profileReply *account.ProfileReply
  456. )
  457. if profileReply, err = s.accountRPC.Profile3(c, &account.MidReq{
  458. Mid: mid,
  459. }); err != nil {
  460. log.Error("accRPC.UserInfo(%v) error(%v)", mid, err)
  461. return
  462. }
  463. if profileReply.GetProfile().GetIdentification() == 0 && profileReply.GetProfile().GetTelStatus() == 0 {
  464. err = ecode.UserCheckNoPhone
  465. return
  466. }
  467. if profileReply.GetProfile().GetIdentification() == 0 && profileReply.GetProfile().GetTelStatus() == 2 {
  468. err = ecode.UserCheckInvalidPhone
  469. return
  470. }
  471. if profileReply.GetProfile().GetEmailStatus() == 0 && profileReply.GetProfile().GetTelStatus() == 0 {
  472. err = ecode.UserCheckNoPhone
  473. return
  474. }
  475. if profileReply.GetProfile().GetSilence() == 1 {
  476. err = ecode.UserDisabled
  477. return
  478. }
  479. if profileReply.GetProfile().GetMoral() < 60 {
  480. err = ecode.LackOfScores
  481. }
  482. if profile = profileReply.GetProfile(); profile == nil {
  483. err = ecode.UserNotExist
  484. }
  485. return
  486. }
  487. func (s *Service) checkMsg(c context.Context, dm *model.DM, profile *account.Profile) (err error) {
  488. var (
  489. msg = dm.Content.Msg
  490. msgLen = len([]rune(dm.Content.Msg))
  491. isNormalMode = s.isNormalMode(dm.Content.Mode)
  492. )
  493. if msgRegex.MatchString(msg) { // 空白弹幕
  494. err = ecode.DMMsgIlleagel
  495. return
  496. }
  497. if profile.GetRank() < 20000 && profile.GetLevel() == 1 && msgLen > 20 {
  498. err = ecode.DMMsgTooLongLevel1
  499. return
  500. }
  501. if (msgLen > model.MaxLenDefMsg && isNormalMode) || (msgLen > model.MaxLen7Msg && dm.Content.Mode == 7) {
  502. err = ecode.DMMsgTooLong
  503. return
  504. }
  505. if isNormalMode && (strings.Contains(msg, `\n`) || strings.Contains(msg, `/n`)) {
  506. err = ecode.DMMsgIlleagel
  507. return
  508. }
  509. // 校验单字符刷屏
  510. if msgLen == 1 {
  511. var count int64
  512. if count, err = s.dao.CharPubCnt(c, dm.Mid, dm.Oid); err != nil {
  513. return
  514. }
  515. if count+1 > 3 {
  516. err = ecode.DMMsgPubTooFast
  517. return
  518. }
  519. if err = s.dao.IncrCharPubCnt(c, dm.Mid, dm.Oid); err != nil {
  520. return
  521. }
  522. } else {
  523. if err = s.dao.DelCharPubCnt(c, dm.Mid, dm.Oid); err != nil {
  524. return
  525. }
  526. }
  527. return
  528. }
  529. func (s *Service) checkPubRate(c context.Context, dm *model.DM, upid, rnd int64, rank int32) (err error) {
  530. ip := metadata.String(c, metadata.RemoteIP)
  531. cached, err := s.dao.MsgPublock(c, dm.Mid, dm.Content.Color, rnd, dm.Content.Mode, dm.Content.FontSize, ip, dm.Content.Msg)
  532. if err != nil {
  533. return
  534. }
  535. if cached {
  536. err = ecode.DMMsgPubTooFast
  537. return
  538. }
  539. s.dao.AddMsgPubLock(c, dm.Mid, dm.Content.Color, rnd, dm.Content.Mode, dm.Content.FontSize, ip, dm.Content.Msg)
  540. if !s.isSuperUser(rank) {
  541. if cached, err = s.dao.OidPubLock(c, dm.Mid, dm.Oid, ip); err != nil {
  542. return
  543. }
  544. if cached {
  545. err = ecode.DMMsgPubTooFast
  546. return
  547. }
  548. s.dao.AddOidPubLock(c, dm.Mid, dm.Oid, ip)
  549. }
  550. if rank <= 15000 {
  551. var count int64
  552. count, err = s.dao.PubCnt(c, dm.Mid, dm.Content.Color, dm.Content.Mode, dm.Content.FontSize, ip, dm.Content.Msg)
  553. if err != nil {
  554. return
  555. }
  556. if count >= 8 && dm.Mid != upid {
  557. arg := &account.MoralReq{
  558. Mid: dm.Mid,
  559. Moral: -0.25,
  560. Oper: "",
  561. Reason: "恶意刷弹幕",
  562. Remark: "云屏蔽",
  563. RealIp: ip,
  564. }
  565. if _, err = s.accountRPC.AddMoral3(c, arg); err != nil {
  566. log.Error("s.accRPC.AddMoral2(%v) error(%v)", arg, err)
  567. return
  568. }
  569. err = ecode.DMMsgPubTooFast
  570. return
  571. }
  572. if err = s.dao.IncrPubCnt(c, dm.Mid, dm.Content.Color, dm.Content.Mode, dm.Content.FontSize, ip, dm.Content.Msg); err != nil {
  573. return
  574. }
  575. }
  576. return
  577. }
  578. func (s *Service) checkArchiveInfo(c context.Context, aid, oid int64, rank, mode int32) (arc *api.Arc, err error) {
  579. // if _, err = s.arcRPC.Video3(c, &arcMdl.ArgVideo2{
  580. // Aid: aid,
  581. // Cid: oid,
  582. // RealIP: metadata.String(c, metadata.RemoteIP),
  583. // }); err != nil {
  584. // log.Error("s.arcRPC.Video3(aid:%v,oid:%v) error(%v)", aid, oid, err)
  585. // return
  586. // }
  587. arg := &arcMdl.ArgAid2{
  588. Aid: aid,
  589. RealIP: metadata.String(c, metadata.RemoteIP),
  590. }
  591. if arc, err = s.arcRPC.Archive3(c, arg); err != nil {
  592. log.Error("s.arcRPC.Archive3(%v) error(%v)", arg, err)
  593. return
  594. }
  595. if arc.State < 0 && arc.State != -6 {
  596. err = ecode.DMArchiveIlleagel // 禁止向未审核的视频发送弹幕
  597. return
  598. }
  599. return
  600. }
  601. func (s *Service) archiveUgcPay(c context.Context, mid int64, aid int64) (err error) {
  602. var (
  603. resp *ugcPayMdl.AssetRelationResp
  604. )
  605. resp, err = s.ugcPayRPC.AssetRelation(c, &ugcPayMdl.AssetRelationReq{
  606. Mid: mid,
  607. Oid: aid,
  608. Otype: model.UgcPayTypeArchive,
  609. })
  610. if err != nil {
  611. log.Error("archiveUgcPay(aid:%d,mid:%d),error(%v)", aid, mid, err)
  612. return
  613. }
  614. if resp.State != model.UgcPayRelationStatePaid {
  615. err = ecode.DMNotpayForPost
  616. return
  617. }
  618. return
  619. }
  620. func (s *Service) advanceComment(c context.Context, oid, mid int64, mode string) (adv *model.AdvanceCmt, err error) {
  621. if adv, err = s.dao.AdvanceCmtCache(c, oid, mid, mode); err != nil {
  622. log.Error("s.dao.AdvanceCmtCache mid=%d oid=%d mode=%s error(%v)", mid, oid, mode, err)
  623. return
  624. }
  625. if adv == nil {
  626. if adv, err = s.dao.AdvanceCmt(c, oid, mid, mode); err != nil {
  627. log.Error("s.dao.AdvanceCmt mid=%d oid=%d mode=%s error(%v)", mid, oid, mode, err)
  628. return
  629. }
  630. if adv == nil {
  631. adv = &model.AdvanceCmt{}
  632. }
  633. if err = s.dao.AddAdvanceCmtCache(c, oid, mid, mode, adv); err != nil {
  634. log.Error("s.dao.AddAdvanceCmtCache mid=%d oid=%d mode=%s error(%v)", mid, oid, mode, err)
  635. return
  636. }
  637. }
  638. return
  639. }
  640. func (s *Service) genDMID(c context.Context, dm *model.DM) (err error) {
  641. dmid, err := s.seqRPC.ID(c, s.seqDmArg)
  642. if err != nil {
  643. return
  644. }
  645. dm.ID = dmid
  646. dm.Content.ID = dmid
  647. if dm.ContentSpe != nil {
  648. dm.ContentSpe.ID = dmid
  649. }
  650. return
  651. }
  652. // checkMonitor check the oid is monitored
  653. func (s *Service) checkMonitor(c context.Context, sub *model.Subject, dm *model.DM) (err error) {
  654. if dm.State != model.StateNormal {
  655. return
  656. }
  657. if sub.AttrVal(model.AttrSubMonitorBefore) == model.AttrYes {
  658. dm.State = model.StateMonitorBefore
  659. } else if sub.AttrVal(model.AttrSubMonitorAfter) == model.AttrYes {
  660. dm.State = model.StateMonitorAfter
  661. } else {
  662. return
  663. }
  664. return
  665. }
  666. func (s *Service) asyncAddDM(dm *model.DM, aid int64, tid int32) (err error) {
  667. var (
  668. data []byte
  669. msg = &struct {
  670. *model.DM
  671. Aid int64 `json:"aid"`
  672. Tid int32 `json:"tid"`
  673. }{
  674. DM: dm,
  675. Aid: aid,
  676. Tid: tid,
  677. }
  678. c = context.TODO()
  679. )
  680. if data, err = json.Marshal(msg); err != nil {
  681. log.Error("json.Marshal(%+v) error(%v)", msg, err)
  682. return
  683. }
  684. act := &model.Action{Action: model.ActAddDM, Data: data}
  685. for i := 0; i < 3; i++ {
  686. if err = s.dao.SendAction(c, fmt.Sprint(dm.Oid), act); err != nil {
  687. continue
  688. } else {
  689. break
  690. }
  691. }
  692. return
  693. }
  694. // 用户是否是特权用户
  695. func (s *Service) isSuperUser(rank int32) bool {
  696. return rank >= 20000
  697. }
  698. // 判断弹幕模式是否是普通弹幕模式
  699. func (s *Service) isNormalMode(mode int32) bool {
  700. if mode == 1 || mode == 4 || mode == 5 || mode == 6 {
  701. return true
  702. }
  703. return false
  704. }
  705. func (s *Service) checkOverseasUser(c context.Context) (err error) {
  706. if s.conf.Supervision.Completed {
  707. err = ecode.ServiceUpdate
  708. return
  709. }
  710. now := time.Now()
  711. loc, _ := time.LoadLocation("Asia/Shanghai")
  712. startTime, _ := time.ParseInLocation("2006-01-02 15:04:05", s.conf.Supervision.StartTime, loc)
  713. endTime, _ := time.ParseInLocation("2006-01-02 15:04:05", s.conf.Supervision.EndTime, loc)
  714. if now.Before(startTime) || now.After(endTime) {
  715. err = nil
  716. return
  717. }
  718. arg := &locmdl.ArgIP{IP: metadata.String(c, metadata.RemoteIP)}
  719. zone, err := s.locationRPC.Info(c, arg)
  720. if err != nil {
  721. log.Error("s.locationRPC.Info(%s) error(%v)", metadata.String(c, metadata.RemoteIP), err)
  722. err = nil
  723. return
  724. }
  725. if !strings.EqualFold(zone.Country, s.conf.Supervision.Location) {
  726. err = ecode.ServiceUpdate
  727. }
  728. return
  729. }
  730. func (s *Service) checkShield(c context.Context, aid int64, dm *model.DM) {
  731. if _, ok := s.aidSheild[aid]; !ok {
  732. return
  733. }
  734. if _, ok := s.midsSheild[dm.Mid]; !ok {
  735. return
  736. }
  737. // hit
  738. dm.State = model.StateBlock
  739. s.OpLog(c, dm.Oid, dm.Mid, time.Now().Unix(), 1, []int64{dm.ID}, "status", "", strconv.FormatInt(int64(dm.State), 10), "弹幕指定稿件黑名单屏蔽", oplog.SourcePlayer, oplog.OperatorMember)
  740. }