pep.py/objects/matchList.py

113 lines
3.5 KiB
Python
Raw Normal View History

2018-03-23 19:59:04 +00:00
import threading
import time
from common.sentry import sentry
from constants.exceptions import periodicLoopException
2016-05-18 17:12:46 +00:00
from objects import match
from objects import glob
from constants import serverPackets
from common.log import logUtils as log
2016-04-19 17:40:59 +00:00
2016-09-02 15:45:10 +00:00
class matchList:
2016-04-19 17:40:59 +00:00
def __init__(self):
"""Initialize a matchList object"""
self.matches = {}
self.lastID = 1
2017-08-01 22:22:57 +00:00
def createMatch(self, matchName, matchPassword, beatmapID, beatmapName, beatmapMD5, gameMode, hostUserID, isTourney=False):
2016-04-19 17:40:59 +00:00
"""
Add a new match to matches list
:param matchName: match name, string
:param matchPassword: match md5 password. Leave empty for no password
:param beatmapID: beatmap ID
:param beatmapName: beatmap name, string
:param beatmapMD5: beatmap md5 hash, string
:param gameMode: game mode ID. See gameModes.py
:param hostUserID: user id of who created the match
:return: match ID
2016-04-19 17:40:59 +00:00
"""
# Add a new match to matches list and create its stream
2016-04-19 17:40:59 +00:00
matchID = self.lastID
self.lastID+=1
2017-08-01 22:22:57 +00:00
self.matches[matchID] = match.match(matchID, matchName, matchPassword, beatmapID, beatmapName, beatmapMD5, gameMode, hostUserID, isTourney)
2016-04-19 17:40:59 +00:00
return matchID
def disposeMatch(self, matchID):
2016-04-19 17:40:59 +00:00
"""
Destroy match object with id = matchID
2016-04-19 17:40:59 +00:00
:param matchID: ID of match to dispose
:return:
2016-04-19 17:40:59 +00:00
"""
# Make sure the match exists
if matchID not in self.matches:
2016-04-19 17:40:59 +00:00
return
# Get match and disconnect all players
_match = self.matches[matchID]
for slot in _match.slots:
_token = glob.tokens.getTokenFromUserID(slot.userID, ignoreIRC=True)
if _token is None:
continue
_match.userLeft(_token, disposeMatch=False) # don't dispose the match twice when we remove all players
# Delete chat channel
glob.channels.removeChannel("#multi_{}".format(_match.matchID))
# Send matchDisposed packet before disposing streams
glob.streams.broadcast(_match.streamName, serverPackets.disposeMatch(_match.matchID))
# Dispose all streams
2016-12-26 09:33:05 +00:00
glob.streams.dispose(_match.streamName)
glob.streams.dispose(_match.playingStreamName)
glob.streams.remove(_match.streamName)
glob.streams.remove(_match.playingStreamName)
2016-04-19 17:40:59 +00:00
# Send match dispose packet to everyone in lobby
glob.streams.broadcast("lobby", serverPackets.disposeMatch(matchID))
del self.matches[matchID]
2018-03-23 19:59:04 +00:00
log.info("MPROOM{}: Room disposed manually".format(_match.matchID))
@sentry.capture()
2018-03-23 19:59:04 +00:00
def cleanupLoop(self):
"""
Start match cleanup loop.
Empty matches that have been created more than 60 seconds ago will get deleted.
Useful when people create useless lobbies with `!mp make`.
The check is done every 30 seconds.
This method starts an infinite loop, call it only once!
:return:
"""
try:
log.debug("Checking empty matches")
t = int(time.time())
emptyMatches = []
exceptions = []
2018-03-23 19:59:04 +00:00
# Collect all empty matches
for key, m in self.matches.items():
if [x for x in m.slots if x.user is not None]:
continue
if t - m.createTime >= 120:
log.debug("Match #{} marked for cleanup".format(m.matchID))
emptyMatches.append(m.matchID)
2018-03-23 19:59:04 +00:00
# Dispose all empty matches
for matchID in emptyMatches:
try:
self.disposeMatch(matchID)
except Exception as e:
exceptions.append(e)
log.error(
"Something wrong happened while disposing a timed out match. Reporting to Sentry when "
"the loop ends."
)
2018-03-23 19:59:04 +00:00
# Re-raise exception if needed
if exceptions:
raise periodicLoopException(exceptions)
finally:
# Schedule a new check (endless loop)
threading.Timer(30, self.cleanupLoop).start()