Пример #1
0
    def readSocket(self):
        """
		Read data coming from this client socket

		:return:
		"""
        try:
            # Try to read incoming data from socket
            data = self.socket.recv(2**10)
            log.debug("[IRC] [{}:{}] -> {}".format(self.ip, self.port, data))
            quitmsg = "EOT"
        except socket.error as x:
            # Error while reading data, this client will be disconnected
            data = bytes()
            quitmsg = x

        if data:
            # Parse received data if needed
            self.__readbuffer += data.decode("latin_1")
            self.parseBuffer()
            self.__timestamp = time.time()
            self.__sentPing = False
        else:
            # No data, disconnect this socket
            self.disconnect(quitmsg)
Пример #2
0
def returnReplayFileName(scoreID=None, scoreData=None):
    if scoreID == None and scoreData == None:
        raise AttributeError(
            "Either scoreID or scoreData must be provided, not neither or both"
        )
    if scoreID == None:
        scoreID = scoreData['id']
    if scoreData == None:
        scoreData = glob.db.fetch(
            "SELECT scores.*, users.username FROM scores LEFT JOIN users ON scores.userid = users.id "
            "WHERE scores.id = %s", [scoreID])

    try:
        username = scoreData["username"]
        beatmapData = glob.db.fetch(
            "SELECT beatmap_id, song_name FROM beatmaps WHERE beatmap_md5 = %s",
            [scoreData["beatmap_md5"]])
        date = datetime.datetime.fromtimestamp(int(
            scoreData["time"])) - datetime.timedelta(
                microseconds=int(scoreData["time"]) / 10)
        fileName = "{} - {} [{}] ({})".format(username,
                                              beatmapData["song_name"],
                                              beatmapData['beatmap_id'],
                                              date.strftime("%Y-%m-%d"))
    except Exception as err:
        log.debug("ERROR WHEN: get replay fileName ({})".format(str(err)))
        fileName = scoreID

    return fileName
Пример #3
0
def cacheMap(mapFile, _beatmap):
    # Check if we have to download the .osu file
    download = False
    if not os.path.isfile(mapFile):
        # .osu file doesn't exist. We must download it
        download = True
    else:
        # File exists, check md5
        if generalUtils.fileMd5(mapFile) != _beatmap.fileMD5 or not isBeatmap(
                mapFile):
            # MD5 don't match, redownload .osu file
            download = True

    # Download .osu file if needed
    if download:
        log.debug("maps ~> Downloading {} osu file".format(_beatmap.beatmapID))

        # Get .osu file from osu servers
        fileContent = osuapiHelper.getOsuFileFromID(_beatmap.beatmapID)

        # Make sure osu servers returned something
        if fileContent is None or not isBeatmap(content=fileContent):
            raise exceptions.osuApiFailException("maps")

        # Delete old .osu file if it exists
        if os.path.isfile(mapFile):
            os.remove(mapFile)

        # Save .osu file
        with open(mapFile, "wb+") as f:
            f.write(fileContent)
    else:
        # Map file is already in folder
        log.debug("maps ~> Beatmap found in cache!")
Пример #4
0
def getRawReplayS3(scoreID):
    scoreID = int(scoreID)
    if not glob.conf.s3_enabled:
        log.warning("S3 is disabled! Using failed local")
        return _getRawReplayFailedLocal(scoreID)

    fileName = "replay_{}.osr".format(scoreID)
    log.debug("Downloading {} from s3".format(fileName))
    with io.BytesIO() as f:
        bucket = s3.getReadReplayBucketName(scoreID)
        try:
            glob.threadScope.s3.download_fileobj(bucket, fileName, f)
        except ClientError as e:
            # 404 -> no such key
            # 400 -> no such bucket
            code = e.response["Error"]["Code"]
            if code in ("404", "400"):
                log.warning(
                    "S3 replay returned {}, trying to get from failed replays".
                    format(code))
                if code == "400":
                    sentry.captureMessage(
                        "Invalid S3 replays bucket ({})! (got error 400)".
                        format(bucket))
                return _getRawReplayFailedLocal(scoreID)
            raise
        f.seek(0)
        return f.read()
Пример #5
0
	def checkOppaiErrors(self):
		log.debug("oppai ~> Checking oppai errors...")
		err = pyoppai.err(self._oppai_ctx)
		if err:
			log.error(str(err))
			raise OppaiError(err)
		log.debug("oppai ~> No errors!")
Пример #6
0
    def __init__(self, r, handlers):
        """
		Initialize a set of redis pubSub listeners

		:param r: redis instance (usually glob.redis)
		:param handlers: dictionary with the following structure:
		```
		{
			"redis_channel_name": handler,
			...
		}
		```
		Where handler is:
		- 	An object of a class that inherits common.redis.generalPubSubHandler.
			You can create custom behaviors for your handlers by overwriting the `handle(self, data)` method,
			that will be called when that handler receives some data.

		- 	A function *object (not call)* that accepts one argument, that'll be the data received through the channel.
			This is useful if you want to make some simple handlers through a lambda, without having to create a class.
		"""
        threading.Thread.__init__(self)
        self.redis = r
        self.pubSub = self.redis.pubsub()
        self.handlers = handlers
        channels = []
        for k, v in self.handlers.items():
            channels.append(k)
        self.pubSub.subscribe(channels)
        log.debug("Subscribed to redis pubsub channels: {}".format(channels))
Пример #7
0
    def updateCachedStats(self):
        """
		Update all cached stats for this token

		:return:
		"""
        stats = userUtils.getUserStats(self.userID, self.gameMode)
        stats_relax = userUtils.getUserStatsRx(self.userID, self.gameMode)
        log.debug(str(stats))

        if stats is None:
            log.warning("Stats query returned None")
            return
        if self.relaxing:
            self.gameRank = stats_relax["gameRank"]
            self.pp = stats_relax["pp"]
            self.rankedScore = stats_relax["rankedScore"]
            self.accuracy = stats_relax["accuracy"] / 100
            self.playcount = stats_relax["playcount"]
            self.totalScore = stats_relax["totalScore"]
        else:
            self.gameRank = stats["gameRank"]
            self.pp = stats["pp"]
            self.rankedScore = stats["rankedScore"]
            self.accuracy = stats["accuracy"] / 100
            self.playcount = stats["playcount"]
            self.totalScore = stats["totalScore"]
Пример #8
0
    def set(self,
            userID,
            rank,
            fileMd5,
            country=False,
            friends=False,
            mods=-1,
            relax=False):
        """
		Set userID's redis personal best cache

		:param userID: userID
		:param rank: leaderboard rank
		:param fileMd5: beatmap md5
		:param country: True if country leaderboard, otherwise False
		:param friends: True if friends leaderboard, otherwise False
		:param mods: leaderboard mods
		:param relax: True if relax leaderboard, False if classic
		:return:
		"""
        glob.redis.set(
            "lets:personal_best_cache:{}".format(userID),
            "{}|{}|{}|{}|{}|{}".format(rank, fileMd5, country, friends, mods,
                                       relax), 1800)
        log.debug("personalBestCache set")
Пример #9
0
def updateCountry(userID, newScore, gameMode, mode='normal'):
    """
	Update gamemode's country leaderboard.
	Doesn't do anything if userID is banned/restricted.

	:param userID: user, country is determined by the user
	:param newScore: new score or pp
	:param gameMode: gameMode number
	:return:
	"""
    if userUtils.isAllowed(userID):
        COUNTRYLESS = 'xx'
        if features.GLOBAL_COUNTRY_RANKS == 'clan':
            country = userUtils.getUserCountryClan(userID)
        else:
            country = userUtils.getCountry(userID)
        if country is not None and len(
                country) > 0 and country.lower() != COUNTRYLESS:
            log.debug("Updating {} country leaderboard...".format(country))
            if features.RANKING_SCOREV2 and mode == 'alternative':
                k = "ripple:leaderboard_alt:{}:{}"
            elif mode == 'relax':
                k = "ripple:leaderboard_relax:{}:{}"
            else:
                k = "ripple:leaderboard:{}:{}"
            k = k.format(scoreUtils.readableGameMode(gameMode),
                         country.lower())
            glob.redis.zadd(k, str(userID), str(newScore))
    else:
        log.debug(
            "Clan leaderboard update for user {} skipped (not allowed)".format(
                userID))
Пример #10
0
def osuApiRequest(request, params, getFirst=True):
	"""
	Send a request to osu!api.

	request -- request type, string (es: get_beatmaps)
	params -- GET parameters, without api key or trailing ?/& (es: h=a5b99395a42bd55bc5eb1d2411cbdf8b&limit=10)
	return -- dictionary with json response if success, None if failed or empty response.
	"""
	# Make sure osuapi is enabled
	if not generalUtils.stringToBool(glob.conf.config["osuapi"]["enable"]):
		log.warning("osu!api is disabled")
		return None

	# Api request
	resp = None
	try:
		finalURL = "{}/api/{}?k={}&{}".format(glob.conf.config["osuapi"]["apiurl"], request, glob.conf.config["osuapi"]["apikey"], params)
		log.debug(finalURL)
		resp = requests.get(finalURL, timeout=5).text
		data = json.loads(resp)
		if getFirst:
			if len(data) >= 1:
				resp = data[0]
			else:
				resp = None
		else:
			resp = data
	finally:
		glob.dog.increment(glob.DATADOG_PREFIX+".osu_api.requests")
		log.debug(str(resp).encode("utf-8"))
		return resp
Пример #11
0
    def usersTimeoutCheckLoop(self):
        """
		Start timed out users disconnect loop.
		This function will be called every `checkTime` seconds and so on, forever.
		CALL THIS FUNCTION ONLY ONCE!
		:return:
		"""
        log.debug("Checking timed out clients")
        timedOutTokens = []  # timed out users
        timeoutLimit = int(time.time()) - 100
        for key, value in self.tokens.items():
            # Check timeout (fokabot is ignored)
            if value.pingTime < timeoutLimit and value.userID != 999 and value.irc == False and value.tournament == False:
                # That user has timed out, add to disconnected tokens
                # We can't delete it while iterating or items() throws an error
                timedOutTokens.append(key)

        # Delete timed out users from self.tokens
        # i is token string (dictionary key)
        for i in timedOutTokens:
            log.debug("{} timed out!!".format(self.tokens[i].username))
            self.tokens[i].enqueue(
                serverPackets.notification(
                    "Your connection to the server timed out."))
            logoutEvent.handle(self.tokens[i], None)
        del timedOutTokens

        # Schedule a new check (endless loop)
        threading.Timer(100, self.usersTimeoutCheckLoop).start()
Пример #12
0
    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:
		"""
        log.debug("Checking empty matches")
        t = int(time.time())
        emptyMatches = []

        # 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)

        # Dispose all empty matches
        for matchID in emptyMatches:
            self.disposeMatch(matchID)

        # Schedule a new check (endless loop)
        threading.Timer(30, self.cleanupLoop).start()
Пример #13
0
	def get(self, userID, fileMd5, country=False, friends=False, mods=-1):
		"""
		Get cached personal best rank

		:param userID: userID
		:param fileMd5: beatmap md5
		:param country: True if country leaderboard, otherwise False
		:param friends: True if friends leaderboard, otherwise False
		:param mods: leaderboard mods
		:return: 0 if cache miss, otherwise rank number
		"""
		try:
			# Make sure the value is in cache
			data = glob.redis.get("lets:personal_best_cache_relax:{}".format(userID))
			if data is None:
				raise cacheMiss()

			# Unpack cached data
			data = data.decode("utf-8").split("|")
			cachedpersonalBestRankRX = int(data[0])
			cachedfileMd5 = str(data[1])
			cachedCountry = generalUtils.stringToBool(data[2])
			cachedFriends = generalUtils.stringToBool(data[3])
			cachedMods = int(data[4])

			# Check if everything matches
			if fileMd5 != cachedfileMd5 or country != cachedCountry or friends != cachedFriends or mods != cachedMods:
				raise cacheMiss()

			# Cache hit
			log.debug("personalBestCacheRX hit")
			return cachedpersonalBestRankRX
		except cacheMiss:
			log.debug("personalBestCacheRX miss")
			return 0
Пример #14
0
def getRankInfo(userID, gameMode):
    """
	Get userID's current rank, user above us and pp/score difference

	:param userID: user
	:param gameMode: gameMode number
	:return: {"nextUsername": "", "difference": 0, "currentRank": 0}
	"""
    data = {"nextUsername": "", "difference": 0, "currentRank": 0}
    k = "ripple:leaderboard_auto:{}".format(
        scoreUtils.readableGameMode(gameMode))
    position = userUtils.getGameRankAP(userID, gameMode) - 1
    log.debug("Our position is {}".format(position))
    if position is not None and position > 0:
        aboveUs = glob.redis.zrevrange(k, position - 1, position)
        log.debug("{} is above us".format(aboveUs))
        if aboveUs is not None and len(aboveUs) > 0 and aboveUs[0].isdigit():
            # Get our rank, next rank username and pp/score difference
            myScore = glob.redis.zscore(k, userID)
            otherScore = glob.redis.zscore(k, aboveUs[0])
            nextUsername = userUtils.getUsername(aboveUs[0])
            if nextUsername is not None and myScore is not None and otherScore is not None:
                data["nextUsername"] = nextUsername
                data["difference"] = int(myScore) - int(otherScore)
    else:
        position = 0

    data["currentRank"] = position + 1
    return data
Пример #15
0
def handle(userToken, _=None, deleteToken=True):
    # get usertoken data
    userID = userToken.userID
    username = userToken.username
    requestToken = userToken.token

    # Big client meme here. If someone logs out and logs in right after,
    # the old logout packet will still be in the queue and will be sent to
    # the server, so we accept logout packets sent at least 5 seconds after login
    # if the user logs out before 5 seconds, he will be disconnected later with timeout check
    if int(time.time() - userToken.loginTime) >= 5 or userToken.irc:
        # Stop spectating
        userToken.stopSpectating()

        # Part matches
        userToken.leaveMatch()

        # Part all joined channels
        for i in userToken.joinedChannels:
            chat.partChannel(token=userToken, channel=i)

        # Leave all joined streams
        userToken.leaveAllStreams()

        # Enqueue our disconnection to everyone else
        glob.streams.broadcast("main", serverPackets.userLogout(userID))

        # Disconnect from IRC if needed
        if userToken.irc and glob.irc:
            glob.ircServer.forceDisconnection(userToken.username)

        # Delete token
        if deleteToken:
            glob.tokens.deleteToken(requestToken)
        else:
            userToken.kicked = True

        # Change username if needed
        newUsername = glob.redis.get(
            "ripple:change_username_pending:{}".format(userID))
        if newUsername is not None:
            log.debug(
                "Sending username change request for user {}".format(userID))
            glob.redis.publish(
                "peppy:change_username",
                json.dumps({
                    "userID": userID,
                    "newUsername": newUsername.decode("utf-8")
                }))

        # Console output
        url = glob.conf.extra["webhook"]
        embed = Webhook(url, color=123123)
        embed.set_author(name=username,
                         icon='https://a.themansions.nl/u/{}',
                         url='http://osu.themansions.nl/u/{}'.format(
                             userID, userID))
        embed.set_title(title='{} has logged out!'.format(username))
        embed.post()
        log.info("{} has been disconnected. (logout)".format(username))
Пример #16
0
    def __init__(self,
                 beatmap_,
                 score_=None,
                 acc=None,
                 mods_=None,
                 tillerino=False,
                 gameMode=gameModes.STD,
                 tillerinoOnlyPP=False):
        """
            Set peace params.

            beatmap_ -- beatmap object
            score_ -- score object
            acc -- manual acc. Used in tillerino-like bot. You don't need this if you pass __score object
            mods_ -- manual mods. Used in tillerino-like bot. You don't need this if you pass __score object
            tillerino -- If True, self.pp will be a list with pp values for 100%, 99%, 98% and 95% acc. Optional.
        """
        # Default values
        self.pp = None
        self.score = None
        self.acc = 0
        self.mods = mods.NOMOD
        self.combo = -1  # FC
        self.misses = 0
        self.stars = 0
        self.tillerino = tillerino
        self.tillerinoOnlyPP = tillerinoOnlyPP

        # Beatmap object
        self.beatmap = beatmap_
        self.map = "{}.osu".format(self.beatmap.beatmapID)

        # If passed, set everything from score object
        if score_ is not None:
            self.score = score_
            self.acc = self.score.accuracy * 100
            self.mods = self.score.mods
            self.combo = self.score.maxCombo
            self.misses = self.score.cMiss
            self.gameMode = self.score.gameMode
        else:
            # Otherwise, set acc and mods from params (tillerino)
            self.acc = acc
            self.mods = mods_
            if gameMode is not None:
                self.gameMode = gameMode
            elif self.beatmap.starsStd > 0:
                self.gameMode = gameModes.STD
            elif self.beatmap.starsTaiko > 0:
                self.gameMode = gameModes.TAIKO
            elif self.beatmap.starsCtb > 0:
                self.gameMode = gameModes.CTB
            elif self.beatmap.starsMania > 0:
                self.gameMode = gameModes.MANIA
            else:
                self.gameMode = None

        # Calculate pp
        log.debug("ezPeace ~> Initialized rust stuff diffcalc")
        self.calculatePP()
Пример #17
0
def cacheMap(mapFile, _beatmap):
    # Check if we have to download the .osu file
    download = shouldDownloadMap(mapFile, _beatmap)

    # Download .osu file if needed
    if download:
        log.debug("maps ~> Downloading {} osu file".format(_beatmap.beatmapId))

        # Get .osu file from osu servers
        fileContent = osuapiHelper.getOsuFileFromID(_beatmap.beatmapId)

        # Make sure osu servers returned something
        if fileContent is None or not isBeatmap(content=fileContent):
            raise exceptions.osuApiFailException("maps")

        # Delete old .osu file if it exists
        if os.path.isfile(mapFile):
            os.remove(mapFile)

        # Save .osu file
        with open(mapFile, "wb+") as f:
            f.write(fileContent)
    else:
        # Map file is already in folder
        log.debug("maps ~> Beatmap found in cache!")
Пример #18
0
    def asyncPost(self):
        statusCode = 400
        data = {"message": "unknown error"}
        try:
            # Check arguments
            if not requestsManager.checkArguments(self.request.arguments,
                                                  ["sid", "refresh"]):
                raise exceptions.invalidArgumentsException(MODULE_NAME)

            # Get beatmap set data from osu api
            beatmapSetID = self.get_argument("sid")
            refresh = int(self.get_argument("refresh"))
            if refresh == 1:
                log.debug("Forced refresh")
            apiResponse = osuapiHelper.osuApiRequest(
                "get_beatmaps", "s={}".format(beatmapSetID), False)
            if len(apiResponse) == 0:
                raise exceptions.invalidBeatmapException

            # Loop through all beatmaps in this set and save them in db
            data["maps"] = []
            for i in apiResponse:
                log.debug("Saving beatmap {} in db".format(i["file_md5"]))
                bmap = beatmap.beatmap(i["file_md5"],
                                       int(i["beatmapset_id"]),
                                       refresh=refresh)
                pp = glob.db.fetch(
                    "SELECT pp_100 FROM beatmaps WHERE beatmap_id = %s LIMIT 1",
                    [bmap.beatmapID])
                if pp is None:
                    pp = 0
                else:
                    pp = pp["pp_100"]
                data["maps"].append({
                    "id": bmap.beatmapID,
                    "name": bmap.songName,
                    "status": bmap.rankedStatus,
                    "frozen": bmap.rankedStatusFrozen,
                    "pp": pp,
                })

            # Set status code and message
            statusCode = 200
            data["message"] = "ok"
        except exceptions.invalidArgumentsException:
            # Set error and message
            statusCode = 400
            data["message"] = "missing required arguments"
        except exceptions.invalidBeatmapException:
            statusCode = 400
            data["message"] = "beatmap not found from osu!api."
        finally:
            # Add status code to data
            data["status"] = statusCode

            # Send response
            self.write(json.dumps(data))
            self.set_header("Content-Type", "application/json")
            #self.add_header("Access-Control-Allow-Origin", "*")
            self.set_status(statusCode)
Пример #19
0
    def reload(self):
        """
        Reloads the AQL thresholds configuration from DB

        :return:
        """
        log.debug("Reloading AQL thresholds")
        self._thresholds = {}
        for x in glob.db.fetchAll(
                "SELECT `name`, value_string FROM system_settings WHERE `name` LIKE 'aql\_threshold\_%%'"
        ):
            parts = x["name"].split("aql_threshold_")
            if len(parts) < 1:
                continue
            m = gameModes.getGameModeFromDB(parts[1])
            if m is None:
                continue
            try:
                self._thresholds[m] = float(x["value_string"])
            except ValueError:
                continue
        log.debug([(gameModes.getGameModeForDB(x), self[x]) for x in self])
        if not all(x in self._thresholds
                   for x in range(gameModes.STD, gameModes.MANIA)):
            raise RuntimeError(
                "Invalid AQL thresholds. Please check your system_settings table."
            )
Пример #20
0
def handle(userToken, _=None, deleteToken=True):
    # get usertoken data
    userID = userToken.userID
    username = userToken.username
    requestToken = userToken.token

    # Big client meme here. If someone logs out and logs in right after,
    # the old logout packet will still be in the queue and will be sent to
    # the server, so we accept logout packets sent at least 5 seconds after login
    # if the user logs out before 5 seconds, he will be disconnected later with timeout check
    if int(time.time() - userToken.loginTime) >= 5 or userToken.irc:
        # Stop spectating
        userToken.stopSpectating()

        # Part matches
        userToken.leaveMatch()

        # Check if a users login/logouts are being tracked. If so, log to discord
        tracked = userUtils.getUserTracked(userID)
        if tracked:
            log.cmyui(
                'Tracked user {} ({}) has logged out.'.format(
                    username, userID), 'cm')

        # Part all joined channels
        for i in userToken.joinedChannels:
            chat.partChannel(token=userToken, channel=i)

        # Leave all joined streams
        userToken.leaveAllStreams()

        # Enqueue our disconnection to everyone else
        glob.streams.broadcast("main", serverPackets.userLogout(userID))

        # Disconnect from IRC if needed
        if userToken.irc and glob.irc:
            glob.ircServer.forceDisconnection(userToken.username)

        # Delete token
        if deleteToken:
            glob.tokens.deleteToken(requestToken)
        else:
            userToken.kicked = True

        # Change username if needed
        newUsername = glob.redis.get(
            "ripple:change_username_pending:{}".format(userID))
        if newUsername is not None:
            log.debug(
                "Sending username change request for user {}".format(userID))
            glob.redis.publish(
                "peppy:change_username",
                json.dumps({
                    "userID": userID,
                    "newUsername": newUsername.decode("utf-8")
                }))

        # Console output
        log.info("{} has been disconnected. (logout)".format(username))
Пример #21
0
 def asyncPost(self):
     statusCode = 200
     data = {"response": "empty", "status": 200}
     # Debug output
     log.debug(str(data))
     # Send response
     #self.clear()
     self.write(json.dumps(data))
     self.set_header("Content-Type", "application/json")
     self.set_status(statusCode)
Пример #22
0
def getReadReplayBucketName(scoreID):
    r = objects.glob.db.fetch(
        "SELECT `name`, max_score_id FROM s3_replay_buckets WHERE max_score_id IS NOT NULL "
        "ORDER BY abs(max_score_id - %s) LIMIT 1", (scoreID, ))
    if r is not None and scoreID <= r["max_score_id"]:
        log.debug("s3 replay buckets resolve: {} -> {}".format(
            scoreID, r["name"]))
        return r["name"]
    log.debug("s3 replay buckets resolve: {} -> WRITE BUCKET".format(scoreID))
    return getWriteReplayBucketName()
Пример #23
0
def handle(userToken, packetData):
    # get token data
    userID = userToken.userID

    # Send spectator frames to every spectator
    streamName = "spect/{}".format(userID)
    glob.streams.broadcast(streamName,
                           serverPackets.spectatorFrames(packetData[7:]))
    log.debug("Broadcasting {}'s frames to {} clients.".format(
        userID, len(glob.streams.streams[streamName].clients)))
Пример #24
0
def printArguments(t):
    """
	Print passed arguments, for debug purposes

	:param t: tornado object (self)
	"""
    msg = "ARGS::"
    for i in t.request.arguments:
        msg += "{}={}\r\n".format(i, t.get_argument(i))
    log.debug(msg)
Пример #25
0
def update(userID, newScore, gameMode):
	"""
	Update gamemode's leaderboard the leaderboard

	userID --
	newScore -- new score or pp
	gameMode -- gameMode number
	"""
	log.debug("Updating leaderboard...")
	mode = scoreUtils.readableGameMode(gameMode)

	newPlayer = False
	us = glob.db.fetch("SELECT * FROM leaderboard_{} WHERE user=%s LIMIT 1".format(mode), [userID])
	if us is None:
		newPlayer = True

	# Find player who is right below our score
	target = glob.db.fetch("SELECT * FROM leaderboard_{} WHERE v <= %s ORDER BY position ASC LIMIT 1".format(mode), [newScore])
	plus = 0
	if target is None:
		# Wow, this user completely sucks at this game.
		target = glob.db.fetch("SELECT * FROM leaderboard_{} ORDER BY position DESC LIMIT 1".format(mode))
		plus = 1

	# Set newT
	if target is None:
		# Okay, nevermind. It's not this user to suck. It's just that no-one has ever entered the leaderboard thus far.
		# So, the player is now #1. Yay!
		newT = 1
	else:
		# Otherwise, just give them the position of the target.
		newT = target["position"] + plus

	# Make some place for the new "place holder".
	if newPlayer:
		glob.db.execute("UPDATE leaderboard_{} SET position = position + 1 WHERE position >= %s ORDER BY position DESC".format(mode), [newT])
	else:
		glob.db.execute("DELETE FROM leaderboard_{} WHERE user = %s".format(mode), [userID])
		glob.db.execute("UPDATE leaderboard_{} SET position = position + 1 WHERE position < %s AND position >= %s ORDER BY position DESC".format(mode), [us["position"], newT])

	#if newT <= 1:
	#	log.info("{} is now #{} ({})".format(userID, newT, mode), "bunker")

	# Finally, insert the user back.
	glob.db.execute("INSERT INTO leaderboard_{} (position, user, v) VALUES (%s, %s, %s);".format(mode), [newT, userID, newScore])
	if gameMode == 0:
		newPlayer = False
		us = glob.db.fetch("SELECT * FROM users_peak_rank WHERE userid = %s LIMIT 1", [userID])
		if us is None:
			newPlayer = True
		if newPlayer:
			glob.db.execute("INSERT INTO users_peak_rank (userid, peak_rank) VALUES (%s, %s);", [userID, newT])
		else:
			if us["peak_rank"] > newT:
				glob.db.execute("UPDATE users_peak_rank SET peak_rank = %s WHERE userid = %s", [newT,userID]) 
Пример #26
0
    def _execute(self, query, params=None, cb=None):
        if params is None:
            params = ()
        attempts = 0
        result = None
        lastExc = None
        while attempts < self.maxAttempts:
            # cur is needed in except (linter complains)
            cur = None

            # Calling objects.glob.threadScope.db may create a new connection
            # and we need to except OperationalErorrs raised by it as well
            try:
                conn = objects.glob.threadScope.db
                cur = conn.cursor(pymysql.cursors.DictCursor)

                log.debug("{} ({})".format(query, params))
                cur.execute(query, params)
                if callable(cb):
                    result = cb(cur)

                # Clear any exception we may have due to previously
                # failed attempts to execute the query
                lastExc = None
                break
            except (pymysql.err.OperationalError,
                    pymysql.err.InternalError) as e:
                lastExc = e
                log.error(
                    "MySQL operational/internal error on Thread {} ({}). Trying to recover"
                    .format(threading.get_ident(), e))

                # Close cursor now
                try:
                    cur.close()
                except:
                    pass

                # Sleep if necessary
                if attempts > 0:
                    time.sleep(1)

                # Reset connection (this closes the connection as well)
                objects.glob.threadScope.dbClose()
                attempts += 1
            finally:
                # Try to close the cursor (will except if there was a failure)
                try:
                    cur.close()
                except:
                    pass
        if lastExc is not None:
            raise lastExc
        return result
Пример #27
0
	def writeSocket(self):
		"""
		Write buffer to socket

		:return:
		"""
		try:
			sent = self.socket.send(self.__writebuffer.encode())
			log.debug("[IRC] [{}:{}] <- {}".format(self.ip, self.port, self.__writebuffer[:sent]))
			self.__writebuffer = self.__writebuffer[sent:]
		except socket.error as x:
			self.disconnect(str(x))
Пример #28
0
    def __init__(self,
                 __beatmap,
                 __score=None,
                 acc=0,
                 mods=0,
                 tillerino=False,
                 combo: int = -1):
        """
		Set oppai params.

		__beatmap -- beatmap object
		__score -- score object
		acc -- manual acc. Used in tillerino-like bot. You don't need this if you pass __score object
		mods -- manual mods. Used in tillerino-like bot. You don't need this if you pass __score object
		tillerino -- If True, self.pp will be a list with pp values for 100%, 99%, 98% and 95% acc. Optional.
		combo -- The maximum combo achieved by the user, used for PP api. Optional. Set to -1 for FC.
		"""
        # Default values
        self.pp = None
        self.score = None
        self.acc = 0
        self.mods = 0
        self.combo = combo  #FC
        self.misses = 0
        self.stars = 0
        self.tillerino = tillerino

        # Beatmap object
        self.beatmap = __beatmap

        # If passed, set everything from score object
        if __score is not None:
            self.score = __score
            self.acc = self.score.accuracy * 100
            self.mods = self.score.mods
            self.combo = self.score.maxCombo
            self.misses = self.score.cMiss
            self.gameMode = self.score.gameMode
        else:
            # Otherwise, set acc and mods from params (tillerino)
            self.acc = acc
            self.mods = mods
            if self.beatmap.starsStd > 0:
                self.gameMode = gameModes.STD
            elif self.beatmap.starsTaiko > 0:
                self.gameMode = gameModes.TAIKO
            else:
                self.gameMode = None

        # Calculate pp
        log.debug("oppai-relax ~> Initialized oppai diffcalc")
        self.calculatePP()
Пример #29
0
def handle(userToken, packetData):
    # Read userIDs list
    packetData = clientPackets.userPanelRequest(packetData)

    # Process lists with length <= 32
    if len(packetData) > 256:
        log.warning("Received userPanelRequest with length > 256.")
        return

    for i in packetData["users"]:
        # Enqueue userpanel packets relative to this user
        log.debug("Sending panel for user {}.".format(i))
        userToken.enqueue(serverPackets.userPanel(i))
Пример #30
0
def update(userID, newScore, gameMode):
	"""
	Update gamemode's leaderboard.
	Doesn't do anything if userID is banned/restricted.
	:param userID: user
	:param newScore: new score or pp
	:param gameMode: gameMode number
	"""
	if userUtils.isAllowed(userID):
		log.debug("Updating leaderboard...")
		glob.redis.zadd("ripple:leaderboard_auto:{}".format(scoreUtils.readableGameMode(gameMode)), str(userID), str(newScore))
	else:
		log.debug("Leaderboard update for user {} skipped (not allowed)".format(userID))