matchmgr.go 9.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419
  1. package match
  2. import (
  3. "encoding/json"
  4. "os"
  5. "sort"
  6. "sync"
  7. "time"
  8. "bet24.com/log"
  9. "bet24.com/servers/common"
  10. "bet24.com/servers/micros/guess/handler/team"
  11. pb "bet24.com/servers/micros/guess/proto"
  12. platformconfig "bet24.com/servers/micros/platformconfig/proto"
  13. )
  14. const config_key = "guess_config"
  15. var mgr *matchmgr
  16. // 赛事
  17. type matchmgr struct {
  18. matchList map[string]*match
  19. lock *sync.RWMutex
  20. configString string
  21. pb.GuessCfg // 竞猜配置
  22. }
  23. func getMatchManager() *matchmgr {
  24. if mgr == nil {
  25. mgr = new(matchmgr)
  26. mgr.ctor()
  27. }
  28. return mgr
  29. }
  30. func (this *matchmgr) ctor() {
  31. mgr.matchList = make(map[string]*match)
  32. mgr.lock = &sync.RWMutex{}
  33. this.readConf()
  34. this.loadMatchList()
  35. mgr.doCheck()
  36. log.Debug("matchmgr.ctor starting ...")
  37. return
  38. }
  39. func (this *matchmgr) readConf() {
  40. time.AfterFunc(time.Second*600, this.readConf)
  41. configString := platformconfig.GetConfig(config_key)
  42. if configString == "" {
  43. data, err := os.ReadFile("serviceconf/guess_config.json")
  44. if err != nil {
  45. log.Release("matchmgr.readConf read config failed")
  46. return
  47. }
  48. configString = string(data)
  49. if configString != "" {
  50. platformconfig.SetConfig(config_key, configString)
  51. }
  52. }
  53. if configString == this.configString {
  54. return
  55. }
  56. this.configString = configString
  57. // 读取配置
  58. err := json.Unmarshal([]byte(configString), &this.GuessCfg)
  59. if err != nil {
  60. log.Release("matchmgr.readConf Unmarshal failed %s", configString)
  61. }
  62. }
  63. // 获取赛事配置
  64. func (this *matchmgr) getConfig() pb.GuessCfg {
  65. return this.GuessCfg
  66. }
  67. // 加载赛事列表
  68. func (this *matchmgr) loadMatchList() {
  69. list := trans_GetMatchList()
  70. for _, sn := range list {
  71. this.getMatch(sn)
  72. }
  73. return
  74. }
  75. func (this *matchmgr) doCheck() {
  76. ticker := time.NewTicker(1 * time.Second)
  77. go func(t *time.Ticker) {
  78. for {
  79. select {
  80. case <-t.C:
  81. go this.checkMatchExpire()
  82. }
  83. }
  84. }(ticker)
  85. }
  86. // 获取赛事
  87. func (this *matchmgr) getMatch(serialNumber string) *match {
  88. if serialNumber == "" {
  89. log.Release("matchmgr.getMatch serialNumber is invalid")
  90. return nil
  91. }
  92. this.lock.RLock()
  93. m, ok := this.matchList[serialNumber]
  94. this.lock.RUnlock()
  95. if ok {
  96. return m
  97. }
  98. m = newMatch(serialNumber)
  99. // 无效数据
  100. if m.isInvalid() {
  101. return m
  102. }
  103. this.lock.Lock()
  104. this.matchList[serialNumber] = m
  105. this.lock.Unlock()
  106. return m
  107. }
  108. // 是否允许修改
  109. func (this *matchmgr) isMatchUpdate(serialNumber string) bool {
  110. this.lock.RLock()
  111. m, ok := this.matchList[serialNumber]
  112. this.lock.RUnlock()
  113. if !ok {
  114. return true
  115. }
  116. // 赛事开始了,不允许修改
  117. if m.StartAt <= common.GetTimeStamp() {
  118. return false
  119. }
  120. return true
  121. }
  122. // 刷新赛事
  123. func (this *matchmgr) refreshMatch(serialNumber string) {
  124. this.lock.RLock()
  125. _, ok := this.matchList[serialNumber]
  126. this.lock.RUnlock()
  127. if !ok {
  128. return
  129. }
  130. // 删除
  131. this.lock.Lock()
  132. delete(this.matchList, serialNumber)
  133. this.lock.Unlock()
  134. // 重新获取
  135. this.getMatch(serialNumber)
  136. return
  137. }
  138. // 检查赛事
  139. func (this *matchmgr) checkMatchExpire() {
  140. this.lock.Lock()
  141. defer this.lock.Unlock()
  142. for _, v := range this.matchList {
  143. if !v.isExpire() {
  144. continue
  145. }
  146. delete(this.matchList, v.SerialNumber)
  147. log.Debug("matchmgr.checkMatchExpire serialNumber=%s 已完成清理", v.SerialNumber)
  148. }
  149. return
  150. }
  151. // 获取赛事列表(0=所有赛事 1=展示的赛事 2=正在进行的赛事 3=结束的赛事 4=预热的赛事
  152. func (this *matchmgr) getMatchList(userId, matchType int) []pb.Response_Match {
  153. var list []pb.Response_Match
  154. for _, v := range this.matchList {
  155. // 赛事类型
  156. if !v.getMatchType(matchType) {
  157. continue
  158. }
  159. list = append(list, this.getMatchInfo(userId, v.SerialNumber))
  160. }
  161. sort.SliceStable(list, func(i, j int) bool {
  162. return list[i].StartAt > list[j].StartAt
  163. })
  164. return list
  165. }
  166. // 获取赛事信息
  167. func (this *matchmgr) getMatchInfo(userId int, serialNumber string) pb.Response_Match {
  168. //log.Debug("getMatchInfo userId=%d serialNumber=%s", userId, serialNumber)
  169. m := this.getMatch(serialNumber)
  170. if m == nil {
  171. log.Debug("matchmgr.getMatchInfo serialNumber=%s is not exist", serialNumber)
  172. return pb.Response_Match{}
  173. }
  174. var userBets []pb.UserBet
  175. if userId > 0 {
  176. userBets = this.getUserBet(userId, m.SerialNumber)
  177. }
  178. return pb.Response_Match{
  179. Match: m.getInfo(),
  180. UserBets: userBets,
  181. }
  182. }
  183. // 获取用户投注
  184. func (this *matchmgr) getUserBet(userId int, serialNumber string) []pb.UserBet {
  185. m := this.getMatch(serialNumber)
  186. if m == nil {
  187. log.Debug("matchmgr.getUserBet serialNumber=%s is not exist", serialNumber)
  188. return nil
  189. }
  190. return m.getUserBet(userId)
  191. }
  192. // 投注
  193. func (this *matchmgr) bet(serialNumber string, userId, betId, amount int, ipAddress string) (ret pb.RetMsg) {
  194. m := this.getMatch(serialNumber)
  195. if m == nil {
  196. log.Debug("matchmgr.bet serialNumber=%s is not exist", serialNumber)
  197. return
  198. }
  199. return m.bet(userId, betId, amount, ipAddress)
  200. }
  201. // 设置结果
  202. func (this *matchmgr) setResult(serialNumber string, betId int, result string, op pb.OpUser) (ret pb.RetMsg) {
  203. m := this.getMatch(serialNumber)
  204. if m == nil {
  205. log.Debug("matchmgr.setResult serialNumber=%s is not exist", serialNumber)
  206. return
  207. }
  208. return m.setResult(betId, result, op)
  209. }
  210. // 派奖
  211. func (this *matchmgr) award(serialNumber string, op pb.OpUser) (ret pb.RetMsg) {
  212. m := this.getMatch(serialNumber)
  213. if m == nil {
  214. log.Debug("matchmgr.award serialNumber=%s is not exist", serialNumber)
  215. return
  216. }
  217. return m.award(op, this.GuessCfg)
  218. }
  219. // 添加赛事
  220. func (this *matchmgr) addMatch(title, startAt, endAt, showStartAt, showEndAt string, op pb.OpUser) pb.RetMsg {
  221. return trans_AddMatch(title, startAt, endAt, showStartAt, showEndAt, op)
  222. }
  223. // 修改赛事
  224. func (this *matchmgr) updateMatch(serialNumber, title, startAt, endAt, showStartAt, showEndAt string, op pb.OpUser) pb.RetMsg {
  225. // 判断是否允许修改
  226. if !this.isMatchUpdate(serialNumber) {
  227. return pb.RetMsg{
  228. RetCode: 500,
  229. Message: "The event has started and cannot be modified",
  230. }
  231. }
  232. // 修改完后
  233. defer this.refreshMatch(serialNumber)
  234. return trans_UpdateMatch(serialNumber, title, startAt, endAt, showStartAt, showEndAt, op)
  235. }
  236. // 添加赛事球队
  237. func (this *matchmgr) addMatchTeam(serialNumber string, teamId int, op pb.OpUser) pb.RetMsg {
  238. if info := team.GetTeam(teamId); info.Id <= 0 {
  239. return pb.RetMsg{
  240. RetCode: 501,
  241. Message: "",
  242. }
  243. }
  244. return trans_AddMatchTeam(serialNumber, teamId, op)
  245. }
  246. // 修改赛事球队
  247. func (this *matchmgr) updateMatchTeam(rId int, serialNumber string, teamId int, op pb.OpUser) pb.RetMsg {
  248. // 判断是否允许修改
  249. if !this.isMatchUpdate(serialNumber) {
  250. return pb.RetMsg{
  251. RetCode: 500,
  252. Message: "The event has started and cannot be modified",
  253. }
  254. }
  255. if info := team.GetTeam(teamId); info.Id <= 0 {
  256. return pb.RetMsg{
  257. RetCode: 501,
  258. Message: "",
  259. }
  260. }
  261. // 修改完后
  262. defer this.refreshMatch(serialNumber)
  263. return trans_UpdateMatchTeam(rId, serialNumber, teamId, op)
  264. }
  265. // 刷新赛事球队
  266. func (this *matchmgr) refreshMatchTeam(teamId int) {
  267. for _, m := range this.matchList {
  268. m.refreshTeam(teamId)
  269. }
  270. return
  271. }
  272. // 添加赛事投注选项
  273. func (this *matchmgr) addMatchBet(serialNumber, betName string, betOdds float64, op pb.OpUser) pb.RetMsg {
  274. return trans_AddMatchBet(serialNumber, betName, betOdds, op)
  275. }
  276. // 修改赛事投注选项
  277. func (this *matchmgr) updateMatchBet(betId int, serialNumber, betName string, betOdds float64, op pb.OpUser) pb.RetMsg {
  278. // 判断是否允许修改
  279. if !this.isMatchUpdate(serialNumber) {
  280. return pb.RetMsg{
  281. RetCode: 500,
  282. Message: "The event has started and cannot be modified",
  283. }
  284. }
  285. // 修改完后
  286. defer this.refreshMatch(serialNumber)
  287. return trans_UpdateMatchBet(betId, serialNumber, betName, betOdds, op)
  288. }
  289. // 设置赛事开启
  290. func (this *matchmgr) setMatchOpen(serialNumber string, status int) (ret pb.RetMsg) {
  291. // TODO:数据库处理
  292. if retCode := trans_UpdateMatchStatus(serialNumber, status); retCode != 1 {
  293. ret.RetCode = 501
  294. ret.Message = "Setting open failed"
  295. return
  296. }
  297. // 设置完后
  298. this.refreshMatch(serialNumber)
  299. ret.RetCode = 1
  300. ret.Message = "success"
  301. return
  302. }
  303. // 获取用户投注记录
  304. func (this *matchmgr) getUserBetRecordList(userId, pageIndex, pageSize int) (int, []pb.BetRecord) {
  305. // TODO:数据库处理
  306. recordCount, list := trans_GetUserBetRecordList(userId, "", pageIndex, pageSize)
  307. for k, v := range list {
  308. m := this.getMatch(v.SerialNumber)
  309. if m == nil {
  310. continue
  311. }
  312. list[k].Title = m.Title
  313. list[k].StartTime = m.StartAt
  314. list[k].Status = m.Status
  315. list[k].Teams = m.Teams
  316. list[k].Result = m.Result
  317. info := m.getBetInfo(v.BetId)
  318. if info.Id <= 0 {
  319. continue
  320. }
  321. list[k].BetName = info.Name
  322. }
  323. return recordCount, list
  324. }
  325. // 打印赛事
  326. func (this *matchmgr) dumpMatch(param1 string) {
  327. var sn string
  328. if param1 != "" {
  329. sn = param1
  330. }
  331. log.Debug(" ^_^ 开始打印赛事数据,房间(%d)个", len(this.matchList))
  332. this.lock.RLock()
  333. for k, v := range this.matchList {
  334. if sn != "" && k != sn {
  335. continue
  336. }
  337. v.dump()
  338. }
  339. this.lock.RUnlock()
  340. log.Debug("完成赛事数据打印 ^_^")
  341. }