pointmatchmanager.go 9.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378
  1. package pointmatch
  2. import (
  3. "os"
  4. "bet24.com/log"
  5. "bet24.com/servers/common"
  6. micro_common "bet24.com/servers/micros/common"
  7. "encoding/json"
  8. "fmt"
  9. "strconv"
  10. "sync"
  11. "time"
  12. "bet24.com/servers/micros/matches/handler/matchbase"
  13. cash "bet24.com/servers/micros/money/proto"
  14. platformconfig "bet24.com/servers/micros/platformconfig/proto"
  15. privateroom "bet24.com/servers/micros/privateroom/proto"
  16. )
  17. const (
  18. match_timeout_not_playing = 1800
  19. match_timeout_started = 14400
  20. match_timeout_ended = 120
  21. )
  22. const config_key = "pointmatch_config"
  23. const refresh_config_sec = 600
  24. type matchmanager struct {
  25. lock *sync.RWMutex
  26. matches map[int]*matchinstance
  27. TaxRate int
  28. Timeout_Play int64
  29. Timeout_Free int64
  30. Timeout_End int64
  31. MatchConfigs []*matchconfig
  32. }
  33. var mgr *matchmanager
  34. func getMatchManager() *matchmanager {
  35. if mgr == nil {
  36. mgr = new(matchmanager)
  37. mgr.ctor()
  38. }
  39. return mgr
  40. }
  41. func (mm *matchmanager) ctor() {
  42. log.Debug("pointmatch.matchmanager.ctor")
  43. }
  44. func (mm *matchmanager) run() {
  45. mm.lock = &sync.RWMutex{}
  46. mm.matches = make(map[int]*matchinstance)
  47. mm.loadConfig()
  48. log.Release("pointmatchmanager.run taxRate = %d", mm.TaxRate)
  49. go mm.checkTimeout()
  50. go privateroom.RegisterServerStatus(mm, mm, micro_common.GetServicePort(), "pointmatch")
  51. }
  52. func (mm *matchmanager) loadConfig() {
  53. defer func() {
  54. time.AfterFunc(refresh_config_sec*time.Second, mm.loadConfig)
  55. }()
  56. configString := platformconfig.GetConfig(config_key)
  57. if configString == "" {
  58. data, err := os.ReadFile("serviceconf/pointmatch.json")
  59. if err != nil {
  60. log.Release("pointmatch.pointmatchmanager.loadData read json failed")
  61. return
  62. }
  63. configString = string(data)
  64. platformconfig.SetConfig(config_key, configString)
  65. }
  66. err := json.Unmarshal([]byte(configString), mm)
  67. if err != nil {
  68. log.Release("pointmatch.simplamatchmanager.loadData Unmarshal failed err:%v", err)
  69. return
  70. }
  71. //log.Release("matchmanager.loadConfig ok %v", mm.MatchConfigs)
  72. if mm.Timeout_Free == 0 {
  73. mm.Timeout_Free = match_timeout_not_playing
  74. }
  75. if mm.Timeout_Play == 0 {
  76. mm.Timeout_Play = match_timeout_started
  77. }
  78. if mm.Timeout_End == 0 {
  79. mm.Timeout_End = match_timeout_ended
  80. }
  81. }
  82. func (mm *matchmanager) checkTimeout() {
  83. time.AfterFunc(30*time.Second, mm.checkTimeout)
  84. var toRemove []int
  85. mm.lock.RLock()
  86. for _, v := range mm.matches {
  87. if v.isTimeout(mm.Timeout_Free, mm.Timeout_Play, mm.Timeout_End) {
  88. toRemove = append(toRemove, v.MatchNo)
  89. }
  90. }
  91. mm.lock.RUnlock()
  92. if len(toRemove) <= 0 {
  93. return
  94. }
  95. log.Debug("pointmatchmanager.checkTimeout removing matches %v", toRemove)
  96. for _, v := range toRemove {
  97. mm.closeMatch(v, "timeout")
  98. mm.lock.Lock()
  99. delete(mm.matches, v)
  100. mm.lock.Unlock()
  101. }
  102. }
  103. func (mm *matchmanager) getMatchNumber() int {
  104. return matchbase.GetMatchNo()
  105. }
  106. func (mm *matchmanager) getMatch(matchNo int) *matchinstance {
  107. mm.lock.RLock()
  108. mi, ok := mm.matches[matchNo]
  109. mm.lock.RUnlock()
  110. if !ok {
  111. return nil
  112. }
  113. return mi
  114. }
  115. func (mm *matchmanager) getMatchInfo(matchNo int) string {
  116. mi := mm.getMatch(matchNo)
  117. if mi == nil {
  118. return ""
  119. }
  120. mi.resetSecToShrink()
  121. d, _ := json.Marshal(mi)
  122. return string(d)
  123. }
  124. func (mm *matchmanager) closeMatchByOwner(userId int, matchNo int) (bool, string) {
  125. mi := mm.getMatch(matchNo)
  126. if mi == nil {
  127. log.Release("matchmanager.closeMatch failed matchNo[%d] not exist", matchNo)
  128. return false, "Invalid MatchNo"
  129. }
  130. ok, errMsg := mi.closeByOwner(userId)
  131. return ok, errMsg
  132. }
  133. func (mm *matchmanager) closeMatch(matchNo int, reason string) (bool, string) {
  134. mi := mm.getMatch(matchNo)
  135. if mi == nil {
  136. log.Release("matchmanager.closeMatch failed matchNo[%d] not exist", matchNo)
  137. return false, "Invalid MatchNo"
  138. }
  139. mi.closeMatch(reason)
  140. return true, "ok"
  141. }
  142. func (mm *matchmanager) createMatch(userId int, gameId int, gameRule string, totalUserCount int,
  143. tableUserCount int, enrollFee int, prize int, playTimeout int,
  144. eliminateScore, shrinkSec, shrinkScore, winnerCount int) (matchNo int, errMsg string) {
  145. matchNo = 0
  146. errMsg = "ok"
  147. // 自己校验
  148. mc := mm.getGameRule(gameId)
  149. if mc == nil {
  150. log.Release("matchmanager.createMatch gameId[%d] not config match", gameId)
  151. errMsg = "Invalid GameId"
  152. return
  153. }
  154. if !mc.isValidParams(gameRule, totalUserCount, tableUserCount, playTimeout, eliminateScore, shrinkSec, shrinkScore, winnerCount) {
  155. errMsg = "Invalid GameRule"
  156. return
  157. }
  158. // 扣钱,userId == -1 表示系统创建
  159. if prize > 0 && userId > 0 && !cash.ReduceMoney(userId, prize, common.LOGTYPE_POINTMATCH_CREATE, "pointmatch", "create", "") {
  160. errMsg = fmt.Sprintf("not enough cash for create match prize[%d]", prize)
  161. log.Release("createMatch failed %s", errMsg)
  162. return
  163. }
  164. matchNo = mm.getMatchNumber()
  165. mi := newMatchInstance(matchNo, userId, gameId, gameRule, totalUserCount, tableUserCount, enrollFee, prize, playTimeout, mc,
  166. eliminateScore, shrinkSec, shrinkScore, winnerCount)
  167. mm.lock.Lock()
  168. mm.matches[matchNo] = mi
  169. mm.lock.Unlock()
  170. return
  171. }
  172. func (mm *matchmanager) enrollMatch(userId int, nickname string, faceId int, faceUrl string, matchNo int) (bool, string) {
  173. mi := mm.getMatch(matchNo)
  174. if mi == nil {
  175. log.Release("matchmanager.enrollMatch user[%d] matchNo[%d] not exist", userId, matchNo)
  176. return false, fmt.Sprintf("MatchNo[%d] not found", matchNo)
  177. }
  178. ok, err := mi.addUser(userId, nickname, faceId, faceUrl)
  179. if ok {
  180. postUserEnterNotification(userId, matchNo, nickname, faceId, faceUrl)
  181. return ok, err
  182. }
  183. return ok, err
  184. }
  185. func (mm *matchmanager) quitMatch(userId int, matchNo int) bool {
  186. mi := mm.getMatch(matchNo)
  187. if mi == nil {
  188. log.Release("matchmanager.quitMatch user[%d] matchNo[%d] not exist", userId, matchNo)
  189. return false
  190. }
  191. if mi.removeUser(userId) {
  192. postUserExitNotification(userId, matchNo)
  193. return true
  194. }
  195. return false
  196. }
  197. func (mm *matchmanager) getUserMatches(userId int) string {
  198. var ret []matchinstance
  199. mm.lock.RLock()
  200. for _, v := range mm.matches {
  201. if v.Owner == userId {
  202. ret = append(ret, *v)
  203. }
  204. }
  205. mm.lock.RUnlock()
  206. d, _ := json.Marshal(ret)
  207. return string(d)
  208. }
  209. func (mm *matchmanager) dump(param1, param2 string) {
  210. log.Release("-------------------------------")
  211. log.Release("pointmatch.matchmanager.dump[%s,%s]", param1, param2)
  212. defer func() {
  213. log.Release("+++++++++++++++++++++++++++++++")
  214. log.Release("")
  215. }()
  216. if param1 == "rules" {
  217. for _, v := range mm.MatchConfigs {
  218. v.dump()
  219. }
  220. return
  221. }
  222. if param1 == "" {
  223. mm.lock.RLock()
  224. for _, v := range mm.matches {
  225. v.dump()
  226. }
  227. mm.lock.RUnlock()
  228. return
  229. }
  230. matchNo, err := strconv.Atoi(param1)
  231. if err != nil {
  232. log.Release(" atoi error %v", err)
  233. return
  234. }
  235. match := mm.getMatch(matchNo)
  236. if match == nil {
  237. log.Release(" match[%d] not exist", matchNo)
  238. return
  239. }
  240. match.dump()
  241. }
  242. func (mm *matchmanager) OnGameRuleRegistered(gameId int, gameRule string, desc string, targetOptions []int, userOptions []int, playTimeOptions []int) {
  243. for _, v := range mm.MatchConfigs {
  244. if v.GameId == gameId {
  245. v.addGameRule(gameRule, desc, targetOptions, userOptions, playTimeOptions)
  246. }
  247. }
  248. }
  249. func (mm *matchmanager) OnGameRuleDeregistered(gameId int, gameRule string) {
  250. log.Debug("matchmanager.OnGameRuleDeregistered gameId[%d] gameRule[%s]", gameId, gameRule)
  251. }
  252. func (mm *matchmanager) getGameRule(gameId int) *matchconfig {
  253. for _, v := range mm.MatchConfigs {
  254. if v.GameId == gameId {
  255. return v
  256. }
  257. }
  258. return nil
  259. }
  260. func (mm *matchmanager) getMatchConfigs() string {
  261. d, _ := json.Marshal(mm.MatchConfigs)
  262. return string(d)
  263. }
  264. func (mm *matchmanager) getEnrolledMatch(userId int) string {
  265. var matches []int
  266. mm.lock.RLock()
  267. for _, v := range mm.matches {
  268. if v.getUser(userId) != nil {
  269. matches = append(matches, v.MatchNo)
  270. }
  271. }
  272. mm.lock.RUnlock()
  273. d, _ := json.Marshal(matches)
  274. return string(d)
  275. }
  276. func (mm *matchmanager) getMatchInstance(matchNo int) matchbase.MatchInstance {
  277. ret := mm.getMatch(matchNo)
  278. if ret == nil {
  279. log.Debug("pointmatch.matchmanager.getMatchInstance [%d] is nil", matchNo)
  280. return nil
  281. }
  282. return ret
  283. }
  284. func (mm *matchmanager) dismissMatch(matchNo int) {
  285. mi := mm.getMatch(matchNo)
  286. if mi == nil {
  287. log.Release("matchmanager.dismissMatch failed matchNo[%d] not exist", matchNo)
  288. return
  289. }
  290. mi.dismiss()
  291. }
  292. func (mm *matchmanager) OnRoomStart(roomNo int) {
  293. //log.Debug("pointmatchmanager.OnRoomStart %d", roomNo)
  294. mm.lock.RLock()
  295. for _, v := range mm.matches {
  296. go func(m *matchinstance) {
  297. m.OnRoomStart(roomNo)
  298. }(v)
  299. }
  300. mm.lock.RUnlock()
  301. }
  302. func (mm *matchmanager) OnRoomEnd(roomNo int, winners []int) {
  303. //log.Debug("pointmatchmanager.OnRoomEnd %d winners%v", roomNo, winners)
  304. mm.lock.RLock()
  305. for _, v := range mm.matches {
  306. go func(m *matchinstance) {
  307. m.OnRoomEnd(roomNo, winners)
  308. }(v)
  309. }
  310. mm.lock.RUnlock()
  311. }
  312. func (mm *matchmanager) OnRoomUserScoreChanged(roomNo int, userId int, score int) {
  313. //log.Debug("pointmatchmanager.OnRoomUserScoreChanged %d UserId[%d] score[%d]", roomNo, userId, score)
  314. mm.lock.RLock()
  315. for _, v := range mm.matches {
  316. go func(m *matchinstance) {
  317. m.OnRoomUserScoreChanged(roomNo, userId, score)
  318. }(v)
  319. }
  320. mm.lock.RUnlock()
  321. }
  322. func (mm *matchmanager) OnRoomStatusChanged(roomNo int, old, new int) {
  323. //log.Debug("pointmatchmanager.OnRoomStatusChanged %d %d->%d", roomNo, old, new)
  324. mm.lock.RLock()
  325. for _, v := range mm.matches {
  326. go func(m *matchinstance) {
  327. m.OnRoomStatusChanged(roomNo, old, new)
  328. }(v)
  329. }
  330. mm.lock.RUnlock()
  331. }