diff --git a/.gitignore b/.gitignore index 8659240..fa921d3 100644 --- a/.gitignore +++ b/.gitignore @@ -2,3 +2,4 @@ config.ini filters.txt .data +.idea \ No newline at end of file diff --git a/constants/clientPackets.py b/constants/clientPackets.py index 8e8309c..ecd8da1 100644 --- a/constants/clientPackets.py +++ b/constants/clientPackets.py @@ -57,13 +57,12 @@ def addRemoveFriend(stream): return packetHelper.readPacketData(stream, [["friendID", dataTypes.sInt32]]) - -""" SPECTATOR PACKETS """ +""" Spectator packets """ def startSpectating(stream): return packetHelper.readPacketData(stream,[["userID", dataTypes.sInt32]]) -""" MULTIPLAYER PACKETS """ +""" Multiplayer packets """ def matchSettings(stream): # Data to return, will be merged later data = [] @@ -115,9 +114,6 @@ def matchSettings(stream): # Read last part data.append(packetHelper.readPacketData(stream[start:], struct, False)) - # Mods if freemod (not used) - #if data[1]["freeMods"] == 1: - result = {} for i in data: result.update(i) diff --git a/constants/fokabotCommands.py b/constants/fokabotCommands.py index 1d30382..e47ad5d 100644 --- a/constants/fokabotCommands.py +++ b/constants/fokabotCommands.py @@ -25,8 +25,8 @@ message -- list containing arguments passed from the message . . . return the message or **False** if there's no response by the bot +TODO: Change False to None, because False doesn't make any sense """ - def instantRestart(fro, chan, message): glob.tokens.enqueueAll(serverPackets.notification("We are restarting Bancho. Be right back!")) systemHelper.scheduleShutdown(0, True, delay=1) diff --git a/constants/gameModes.py b/constants/gameModes.py index 0b78ffb..c5a118f 100644 --- a/constants/gameModes.py +++ b/constants/gameModes.py @@ -1,4 +1,3 @@ -"""Contains readable gamemodes with their codes""" std = 0 taiko = 1 ctb = 2 @@ -9,10 +8,8 @@ def getGameModeForDB(gameMode): Convert a gamemode number to string for database table/column gameMode -- gameMode int or variable (ex: gameMode.std) - return -- game mode readable string for db """ - if gameMode == std: return "std" elif gameMode == taiko: @@ -27,10 +24,8 @@ def getGameModeForPrinting(gameMode): Convert a gamemode number to string for showing to a user (e.g. !last) gameMode -- gameMode int or variable (ex: gameMode.std) - return -- game mode readable string for a human """ - if gameMode == std: return "osu!" elif gameMode == taiko: diff --git a/constants/serverPackets.py b/constants/serverPackets.py index 514a3d3..b6cdf08 100644 --- a/constants/serverPackets.py +++ b/constants/serverPackets.py @@ -5,9 +5,9 @@ from helpers import userHelper from objects import glob from constants import userRanks from constants import packetIDs +from constants import privileges -""" Login errors packets -(userID packets derivates) """ +""" Login errors packets """ def loginFailed(): return packetHelper.buildPacket(packetIDs.server_userID, [[-1, dataTypes.sInt32]]) @@ -18,7 +18,6 @@ def loginBanned(): packets = packetHelper.buildPacket(packetIDs.server_userID, [[-1, dataTypes.sInt32]]) packets += notification("You are banned. You can ask to get unbanned after 1 month since your ban by contacting support@ripple.moe") return packets - #return packetHelper.buildPacket(packetIDs.server_userID, [[-3, dataTypes.sInt32]]) def loginError(): return packetHelper.buildPacket(packetIDs.server_userID, [[-5, dataTypes.sInt32]]) @@ -29,6 +28,7 @@ def needSupporter(): def needVerification(): return packetHelper.buildPacket(packetIDs.server_userID, [[-8, dataTypes.sInt32]]) + """ Login packets """ def userID(uid): return packetHelper.buildPacket(packetIDs.server_userID, [[uid, dataTypes.sInt32]]) @@ -51,19 +51,8 @@ def userSupporterGMT(supporter, GMT): return packetHelper.buildPacket(packetIDs.server_supporterGMT, [[result, dataTypes.uInt32]]) def friendList(userID): - friendsData = [] - - # Get friend IDs from db friends = userHelper.getFriendList(userID) - - # Friends number - friendsData.append([len(friends), dataTypes.uInt16]) - - # Add all friend user IDs to friendsData - for i in friends: - friendsData.append([i, dataTypes.sInt32]) - - return packetHelper.buildPacket(packetIDs.server_friendsList, friendsData) + return packetHelper.buildPacket(packetIDs.server_friendsList, [[friends, dataTypes.intList]]) def onlineUsers(): userIDs = [] @@ -91,7 +80,7 @@ def userPanel(userID, force = False): # Get user data username = userToken.username - timezone = 24+userToken.timeOffset # TODO: Timezone + timezone = 24+userToken.timeOffset country = userToken.country gameRank = userToken.gameRank latitude = userToken.getLatitude() @@ -105,7 +94,7 @@ def userPanel(userID, force = False): userRank = userRanks.MOD elif userHelper.isInPrivilegeGroup(userID, "developer") == True: userRank = userRanks.ADMIN - elif userHelper.isInPrivilegeGroup(userID, "donor") == True: + elif (userToken.privileges & privileges.USER_DONOR) > 0: userRank = userRanks.SUPPORTER else: userRank = userRanks.NORMAL @@ -126,10 +115,12 @@ def userPanel(userID, force = False): def userStats(userID, force = False): # Get userID's token from tokens list userToken = glob.tokens.getTokenFromUserID(userID) + if userToken == None: return bytes() if (userToken.restricted == True or userToken.irc == True) and force == False: return bytes() + return packetHelper.buildPacket(packetIDs.server_userStats, [ [userID, dataTypes.uInt32], @@ -150,14 +141,23 @@ def userStats(userID, force = False): """ Chat packets """ def sendMessage(fro, to, message): - return packetHelper.buildPacket(packetIDs.server_sendMessage, [[fro, dataTypes.string], [message, dataTypes.string], [to, dataTypes.string], [userHelper.getID(fro), dataTypes.sInt32]]) + return packetHelper.buildPacket(packetIDs.server_sendMessage, [ + [fro, dataTypes.string], + [message, dataTypes.string], + [to, dataTypes.string], + [userHelper.getID(fro), dataTypes.sInt32] + ]) def channelJoinSuccess(userID, chan): return packetHelper.buildPacket(packetIDs.server_channelJoinSuccess, [[chan, dataTypes.string]]) def channelInfo(chan): channel = glob.channels.channels[chan] - return packetHelper.buildPacket(packetIDs.server_channelInfo, [[chan, dataTypes.string], [channel.description, dataTypes.string], [channel.getConnectedUsersCount(), dataTypes.uInt16]]) + return packetHelper.buildPacket(packetIDs.server_channelInfo, [ + [chan, dataTypes.string], + [channel.description, dataTypes.string], + [channel.getConnectedUsersCount(), dataTypes.uInt16] + ]) def channelInfoEnd(): return packetHelper.buildPacket(packetIDs.server_channelInfoEnd, [[0, dataTypes.uInt32]]) @@ -199,7 +199,6 @@ def createMatch(matchID): match = glob.matches.matches[matchID] return packetHelper.buildPacket(packetIDs.server_newMatch, match.getMatchData()) - def updateMatch(matchID): # Make sure the match exists if matchID not in glob.matches.matches: @@ -209,7 +208,6 @@ def updateMatch(matchID): match = glob.matches.matches[matchID] return packetHelper.buildPacket(packetIDs.server_updateMatch, match.getMatchData()) - def matchStart(matchID): # Make sure the match exists if matchID not in glob.matches.matches: @@ -219,9 +217,8 @@ def matchStart(matchID): match = glob.matches.matches[matchID] return packetHelper.buildPacket(packetIDs.server_matchStart, match.getMatchData()) - def disposeMatch(matchID): - return packetHelper.buildPacket(packetIDs.server_disposeMatch, [[matchID, dataTypes.uInt16]]) + return packetHelper.buildPacket(packetIDs.server_disposeMatch, [[matchID, dataTypes.uInt32]]) def matchJoinSuccess(matchID): # Make sure the match exists @@ -260,9 +257,10 @@ def playerFailed(slotID): def matchTransferHost(): return packetHelper.buildPacket(packetIDs.server_matchTransferHost) + """ Other packets """ def notification(message): return packetHelper.buildPacket(packetIDs.server_notification, [[message, dataTypes.string]]) def banchoRestart(msUntilReconnection): - return packetHelper.buildPacket(packetIDs.server_restart, [[msUntilReconnection, dataTypes.uInt32]]) + return packetHelper.buildPacket(packetIDs.server_restart, [[msUntilReconnection, dataTypes.uInt32]]) \ No newline at end of file diff --git a/events/changeActionEvent.py b/events/changeActionEvent.py index dbf5e47..6a88877 100644 --- a/events/changeActionEvent.py +++ b/events/changeActionEvent.py @@ -4,7 +4,6 @@ from constants import serverPackets from helpers import userHelper from helpers import logHelper as log from constants import actions -from helpers import chatHelper as chat def handle(userToken, packetData): # Get usertoken data @@ -24,9 +23,16 @@ def handle(userToken, packetData): # Change action packet packetData = clientPackets.userActionChange(packetData) + # If we are not in spectate status but we're spectating someone, stop spectating + #if userToken.spectating != 0 and userToken.actionID != actions.watching and userToken.actionID != actions.idle and userToken.actionID != actions.afk: + # userToken.stopSpectating() + + # If we are not in multiplayer but we are in a match, part match + #if userToken.matchID != -1 and userToken.actionID != actions.multiplaying and userToken.actionID != actions.multiplayer and userToken.actionID != actions.afk: + # userToken.partMatch() + # Update cached stats if our pp changedm if we've just submitted a score or we've changed gameMode if (userToken.actionID == actions.playing or userToken.actionID == actions.multiplaying) or (userToken.pp != userHelper.getPP(userID, userToken.gameMode)) or (userToken.gameMode != packetData["gameMode"]): - log.debug("!!!! UPDATING CACHED STATS !!!!") # Always update game mode, or we'll cache stats from the wrong game mode if we've changed it userToken.gameMode = packetData["gameMode"] userToken.updateCachedStats() @@ -55,12 +61,5 @@ def handle(userToken, packetData): token.enqueue(serverPackets.userPanel(userID, force)) token.enqueue(serverPackets.userStats(userID, force)) - # Send osu!direct alert if needed - # NOTE: Remove this when osu!direct will be fixed - if userToken.actionID == actions.osuDirect and userToken.osuDirectAlert == False: - userToken.osuDirectAlert = True - chat.sendMessage("FokaBot", userToken.username, "Sup! osu!direct works, but you'll need to update the switcher to have the Download button working. If you didn't update the switcher yet, please do!") - - # Console output log.info("{} changed action: {} [{}][{}]".format(username, str(userToken.actionID), userToken.actionText, userToken.actionMd5)) diff --git a/events/changeMatchModsEvent.py b/events/changeMatchModsEvent.py index 3f63d88..183f65d 100644 --- a/events/changeMatchModsEvent.py +++ b/events/changeMatchModsEvent.py @@ -16,6 +16,10 @@ def handle(userToken, packetData): return match = glob.matches.matches[matchID] + # Host check + if userID != match.hostUserID: + return + # Set slot or match mods according to modType if match.matchModMode == matchModModes.freeMod: # Freemod @@ -25,7 +29,7 @@ def handle(userToken, packetData): # If host has selected DT/HT and Freemod is enabled, set DT/HT as match mod if (packetData["mods"] & mods.DoubleTime) > 0: match.changeMatchMods(mods.DoubleTime) - # Nighcore + # Nightcore if (packetData["mods"] & mods.Nightcore) > 0: match.changeMatchMods(match.mods+mods.Nightcore) elif (packetData["mods"] & mods.HalfTime) > 0: diff --git a/events/changeMatchPasswordEvent.py b/events/changeMatchPasswordEvent.py index b7bac73..1c645b7 100644 --- a/events/changeMatchPasswordEvent.py +++ b/events/changeMatchPasswordEvent.py @@ -13,5 +13,9 @@ def handle(userToken, packetData): # Get our match match = glob.matches.matches[matchID] + # Host check + if userToken.userID != match.hostUserID: + return + # Update match password match.changePassword(packetData["matchPassword"]) diff --git a/events/changeMatchSettingsEvent.py b/events/changeMatchSettingsEvent.py index ce3b473..93451c8 100644 --- a/events/changeMatchSettingsEvent.py +++ b/events/changeMatchSettingsEvent.py @@ -6,6 +6,7 @@ from constants import matchTeamTypes from constants import matchTeams from constants import slotStatuses from helpers import logHelper as log +from helpers import generalFunctions def handle(userToken, packetData): # Read new settings @@ -13,7 +14,7 @@ def handle(userToken, packetData): # Get match ID matchID = userToken.matchID - + # Make sure the match exists if matchID not in glob.matches.matches: return @@ -21,6 +22,10 @@ def handle(userToken, packetData): # Get match object match = glob.matches.matches[matchID] + # Host check + if userToken.userID != match.hostUserID: + return + # Some dank memes easter egg memeTitles = [ "RWC 2020", @@ -53,7 +58,10 @@ def handle(userToken, packetData): # Update match settings match.inProgress = packetData["inProgress"] - match.matchPassword = packetData["matchPassword"] + if packetData["matchPassword"] != "": + match.matchPassword = generalFunctions.stringMd5(packetData["matchPassword"]) + else: + match.matchPassword = "" match.beatmapName = packetData["beatmapName"] match.beatmapID = packetData["beatmapID"] match.hostUserID = packetData["hostUserID"] @@ -71,14 +79,14 @@ def handle(userToken, packetData): # Reset ready if needed if oldMods != match.mods or oldBeatmapMD5 != match.beatmapMD5: for i in range(0,16): - if match.slots[i]["status"] == slotStatuses.ready: - match.slots[i]["status"] = slotStatuses.notReady + if match.slots[i].status == slotStatuses.ready: + match.slots[i].status = slotStatuses.notReady # Reset mods if needed if match.matchModMode == matchModModes.normal: # Reset slot mods if not freeMods for i in range(0,16): - match.slots[i]["mods"] = 0 + match.slots[i].mods = 0 else: # Reset match mods if freemod match.mods = 0 @@ -88,13 +96,13 @@ def handle(userToken, packetData): # Set teams c=0 for i in range(0,16): - if match.slots[i]["team"] == matchTeams.noTeam: - match.slots[i]["team"] = matchTeams.red if c % 2 == 0 else matchTeams.blue + if match.slots[i].team == matchTeams.noTeam: + match.slots[i].team = matchTeams.red if c % 2 == 0 else matchTeams.blue c+=1 else: # Reset teams for i in range(0,16): - match.slots[i]["team"] = matchTeams.noTeam + match.slots[i].team = matchTeams.noTeam # Force no freemods if tag coop if match.matchTeamType == matchTeamTypes.tagCoop or match.matchTeamType == matchTeamTypes.tagTeamVs: @@ -105,4 +113,3 @@ def handle(userToken, packetData): # Console output log.info("MPROOM{}: Updated room settings".format(match.matchID)) - #consoleHelper.printColored("> MPROOM{}: DEBUG: Host is {}".format(match.matchID, match.hostUserID), bcolors.PINK) diff --git a/events/joinMatchEvent.py b/events/joinMatchEvent.py index 6f75519..624a5ee 100644 --- a/events/joinMatchEvent.py +++ b/events/joinMatchEvent.py @@ -4,6 +4,7 @@ from objects import glob from constants import exceptions from helpers import logHelper as log from helpers import chatHelper as chat +from helpers import generalFunctions def handle(userToken, packetData): # read packet data @@ -12,12 +13,15 @@ def handle(userToken, packetData): # Get match from ID joinMatch(userToken, packetData["matchID"], packetData["password"]) -def joinMatch(userToken, matchID, password): +def joinMatch(userToken, matchID, password, isPasswordHashed = False): try: - # TODO: leave other matches - # TODO: Stop spectating + # Stop spectating + userToken.stopSpectating() - # get usertoken data + # Leave other matches + userToken.partMatch() + + # Get usertoken data userID = userToken.userID # Make sure the match exists @@ -27,6 +31,10 @@ def joinMatch(userToken, matchID, password): # Match exists, get object match = glob.matches.matches[matchID] + # Hash password if needed + if isPasswordHashed == False and password != "": + password = generalFunctions.stringMd5(password) + # Check password # TODO: Admins can enter every match if match.matchPassword != "": diff --git a/events/loginEvent.py b/events/loginEvent.py index 2373d24..b544e41 100644 --- a/events/loginEvent.py +++ b/events/loginEvent.py @@ -2,16 +2,10 @@ from helpers import userHelper from constants import serverPackets from constants import exceptions from objects import glob -from helpers import consoleHelper -from constants import bcolors from helpers import locationHelper from helpers import countryHelper -import time -from helpers import generalFunctions import sys import traceback -from helpers import requestHelper -from helpers import discordBotHelper from helpers import logHelper as log from helpers import chatHelper as chat from constants import privileges diff --git a/events/logoutEvent.py b/events/logoutEvent.py index 5472450..362c7be 100644 --- a/events/logoutEvent.py +++ b/events/logoutEvent.py @@ -15,21 +15,16 @@ def handle(userToken, _=None): # 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 == True: - # Stop spectating if needed - # TODO: Call stopSpectatingEvent!!!!!!!!! - if userToken.spectating != 0: - # The user was spectating someone - spectatorHostToken = glob.tokens.getTokenFromUserID(userToken.spectating) - if spectatorHostToken != None: - # The host is still online, send removeSpectator to him - spectatorHostToken.enqueue(serverPackets.removeSpectator(userID)) + # Stop spectating + userToken.stopSpectating() + # Part matches + userToken.partMatch() + # Part all joined channels for i in userToken.joinedChannels: chat.partChannel(token=userToken, channel=i) - # TODO: Lobby left if joined - # Enqueue our disconnection to everyone else glob.tokens.enqueueAll(serverPackets.userLogout(userID)) diff --git a/events/matchFramesEvent.py b/events/matchFramesEvent.py index 6a297c9..f47f8c1 100644 --- a/events/matchFramesEvent.py +++ b/events/matchFramesEvent.py @@ -25,7 +25,7 @@ def handle(userToken, packetData): # Enqueue frames to who's playing for i in range(0,16): - if match.slots[i]["userID"] > -1 and match.slots[i]["status"] == slotStatuses.playing: - token = glob.tokens.getTokenFromUserID(match.slots[i]["userID"]) + if match.slots[i].userID > -1 and match.slots[i].status == slotStatuses.playing: + token = glob.tokens.getTokenFromUserID(match.slots[i].userID) if token != None: token.enqueue(serverPackets.matchFrames(slotID, packetData)) diff --git a/events/matchHasBeatmapEvent.py b/events/matchHasBeatmapEvent.py index 7bf4490..e9b7228 100644 --- a/events/matchHasBeatmapEvent.py +++ b/events/matchHasBeatmapEvent.py @@ -1,3 +1,4 @@ from events import matchBeatmapEvent + def handle(userToken, packetData): matchBeatmapEvent.handle(userToken, packetData, True) diff --git a/events/matchLockEvent.py b/events/matchLockEvent.py index e25daca..5959e35 100644 --- a/events/matchLockEvent.py +++ b/events/matchLockEvent.py @@ -14,6 +14,10 @@ def handle(userToken, packetData): return match = glob.matches.matches[matchID] + # Host check + if userID != match.hostUserID: + return + # Make sure we aren't locking our slot ourSlot = match.getUserSlotID(userID) if packetData["slotID"] == ourSlot: diff --git a/events/matchNoBeatmapEvent.py b/events/matchNoBeatmapEvent.py index d0c3ff7..5410226 100644 --- a/events/matchNoBeatmapEvent.py +++ b/events/matchNoBeatmapEvent.py @@ -1,3 +1,4 @@ from events import matchBeatmapEvent + def handle(userToken, packetData): matchBeatmapEvent.handle(userToken, packetData, False) diff --git a/events/matchStartEvent.py b/events/matchStartEvent.py index 73ba781..f3cd9d6 100644 --- a/events/matchStartEvent.py +++ b/events/matchStartEvent.py @@ -3,7 +3,6 @@ from constants import slotStatuses from constants import serverPackets def handle(userToken, _): - # TODO: Host check # Get match ID and match object matchID = userToken.matchID @@ -19,10 +18,12 @@ def handle(userToken, _): # The match exists, get object match = glob.matches.matches[matchID] - force = False # TODO: Force thing + # Host check + if userToken.userID != match.hostUserID: + return # Make sure we have enough players - if (match.countUsers() < 2 or not match.checkTeams()) and not force: + if (match.countUsers() < 2 or match.checkTeams() == False): return # Change inProgress value @@ -30,16 +31,16 @@ def handle(userToken, _): # Set playing to ready players and set load, skip and complete to False for i in range(0,16): - if (match.slots[i]["status"] & slotStatuses.ready) > 0: - match.slots[i]["status"] = slotStatuses.playing - match.slots[i]["loaded"] = False - match.slots[i]["skip"] = False - match.slots[i]["complete"] = False + if (match.slots[i].status & slotStatuses.ready) > 0: + match.slots[i].status = slotStatuses.playing + match.slots[i].loaded = False + match.slots[i].skip = False + match.slots[i].complete = False # Send match start packet for i in range(0,16): - if (match.slots[i]["status"] & slotStatuses.playing) > 0 and match.slots[i]["userID"] != -1: - token = glob.tokens.getTokenFromUserID(match.slots[i]["userID"]) + if (match.slots[i].status & slotStatuses.playing) > 0 and match.slots[i].userID != -1: + token = glob.tokens.getTokenFromUserID(match.slots[i].userID) if token != None: token.enqueue(serverPackets.matchStart(matchID)) diff --git a/events/matchTransferHostEvent.py b/events/matchTransferHostEvent.py index b7bc300..b6a9432 100644 --- a/events/matchTransferHostEvent.py +++ b/events/matchTransferHostEvent.py @@ -19,5 +19,9 @@ def handle(userToken, packetData): # Match exists, get object match = glob.matches.matches[matchID] + # Host check + if userToken.userID != match.hostUserID: + return + # Transfer host match.transferHost(packetData["slotID"]) diff --git a/events/partMatchEvent.py b/events/partMatchEvent.py index 97aeca0..943a410 100644 --- a/events/partMatchEvent.py +++ b/events/partMatchEvent.py @@ -1,28 +1,2 @@ -from objects import glob - -def handle(userToken, _): - # get data from usertoken - userID = userToken.userID - - # Get match ID and match object - matchID = userToken.matchID - - # Make sure we are in a match - if matchID == -1: - return - - # Make sure the match exists - if matchID not in glob.matches.matches: - return - - # The match exists, get object - match = glob.matches.matches[matchID] - - # Set slot to free - match.userLeft(userID) - - # Part #multiplayer channel - #chat.partChannel(token=userToken, channel="#multi_{}".format(matchID), kick=True) - - # Set usertoken match to -1 - userToken.partMatch() +def handle(userToken, _=None): + userToken.partMatch() \ No newline at end of file diff --git a/events/requestStatusUpdateEvent.py b/events/requestStatusUpdateEvent.py index cd2021b..318ea9a 100644 --- a/events/requestStatusUpdateEvent.py +++ b/events/requestStatusUpdateEvent.py @@ -2,8 +2,6 @@ from constants import serverPackets from helpers import logHelper as log def handle(userToken, packetData): - log.debug("Requested status update") - # Update cache and send new stats userToken.updateCachedStats() userToken.enqueue(serverPackets.userStats(userToken.userID)) diff --git a/events/stopSpectatingEvent.py b/events/stopSpectatingEvent.py index 1332425..8cb355a 100644 --- a/events/stopSpectatingEvent.py +++ b/events/stopSpectatingEvent.py @@ -1,37 +1,2 @@ -from objects import glob -from constants import serverPackets -from constants import exceptions -from helpers import logHelper as log -from helpers import chatHelper as chat - -def handle(userToken, _): - try: - # get user token data - userID = userToken.userID - username = userToken.username - - # Remove our userID from host's spectators - target = userToken.spectating - targetToken = glob.tokens.getTokenFromUserID(target) - if targetToken == None: - raise exceptions.tokenNotFoundException - targetToken.removeSpectator(userID) - - # Part #spectator channel - chat.partChannel(token=userToken, channel="#spect_{}".format(target)) - - # Send the spectator left packet to host - targetToken.enqueue(serverPackets.removeSpectator(userID)) - for c in targetToken.spectators: - spec = glob.tokens.getTokenFromUserID(c) - spec.enqueue(serverPackets.fellowSpectatorLeft(userID)) - - #targetToken.enqueue(serverPackets.fellowSpectatorLeft(userID)) - - # Console output - log.info("{} are no longer spectating {}".format(username, target)) - except exceptions.tokenNotFoundException: - log.warning("Spectator stop: token not found") - finally: - # Set our spectating user to 0 - userToken.stopSpectating() +def handle(userToken, _=None): + userToken.stopSpectating() diff --git a/handlers/ciTriggerHandler.py b/handlers/ciTriggerHandler.py index 5ffe294..d2b15f6 100644 --- a/handlers/ciTriggerHandler.py +++ b/handlers/ciTriggerHandler.py @@ -33,7 +33,5 @@ class handler(requestHelper.asyncRequestHandler): data["status"] = statusCode # Send response - #self.clear() self.write(json.dumps(data)) self.set_status(statusCode) - #self.finish(json.dumps(data)) diff --git a/handlers/mainHandler.py b/handlers/mainHandler.py index 27bfedc..90d36bf 100644 --- a/handlers/mainHandler.py +++ b/handlers/mainHandler.py @@ -226,8 +226,8 @@ class handler(SentryMixin, requestHelper.asyncRequestHandler): self.set_status(200) self.add_header("cho-token", responseTokenString) self.add_header("cho-protocol", "19") - #self.add_header("Keep-Alive", "timeout=5, max=100") - #self.add_header("Connection", "keep-alive") + self.add_header("Connection", "keep-alive") + self.add_header("Keep-Alive", "timeout=5, max=100") self.add_header("Content-Type", "text/html; charset=UTF-8") except: log.error("Unknown error!\n```\n{}\n{}```".format(sys.exc_info(), traceback.format_exc())) @@ -259,6 +259,4 @@ class handler(SentryMixin, requestHelper.asyncRequestHandler): html += " \\ . .. .. . /
" html += "^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
" html += "
reverse engineering a protocol impossible to reverse engineer since always
we are actually reverse engineering bancho successfully. for the third time.

© Ripple team, 2016" - self.write(html) - #yield tornado.gen.Task(self.captureMessage, "test") - #self.finish() \ No newline at end of file + self.write(html) \ No newline at end of file diff --git a/handlers/routes.py b/handlers/routes.py deleted file mode 100644 index 753d427..0000000 --- a/handlers/routes.py +++ /dev/null @@ -1,52 +0,0 @@ -""" -WIP feature that will come in the future. -Don't import -""" -import flask -from objects import glob -from constants import exceptions - -@app.route("/api/online-users-count") -def APIonlineUsersCount(): - return flask.jsonify({"count" : len(glob.tokens.tokens)-1}) - -@app.route("/api/user-info") -def APIonlineUsers(): - resp = {} - - try: - u = flask.request.args.get('u') - - # Username/userID - if u.isdigit(): - u = int(u) - else: - u = userHelper.getID(u) - if u == None: - raise exceptions.userNotFoundException - - # Make sure this user is online - userToken = glob.tokens.getTokenFromUserID(u) - if userToken == None: - raise exceptions.tokenNotFoundException - - # Build response dictionary - resp["response"] = "1" - resp[userToken.username] = { - "userID" : userToken.userID, - "actionID" : userToken.actionID, - "actionText" : userToken.actionText, - "actionMd5" : userToken.actionMd5, - "actionMods": userToken.actionMods, - "gameMode": userToken.gameMode, - "country": countryHelper.getCountryLetters(userToken.country), - "position": userToken.location, - "spectating": userToken.spectating, - "spectators": userToken.spectators - } - except exceptions.userNotFoundException: - resp["response"] = "-1" - except exceptions.tokenNotFoundException: - resp["response"] = "-2" - finally: - return flask.jsonify(resp) diff --git a/helpers/chatHelper.py b/helpers/chatHelper.py index e434fad..e767f14 100644 --- a/helpers/chatHelper.py +++ b/helpers/chatHelper.py @@ -147,9 +147,6 @@ def partChannel(userID = 0, channel = "", token = None, toIRC = True, kick = Fal log.warning("User not connected to IRC/Bancho") return 442 # idk - - - def sendMessage(fro = "", to = "", message = "", token = None, toIRC = True): """ Send a message to osu!bancho and IRC server @@ -299,8 +296,13 @@ def sendMessage(fro = "", to = "", message = "", token = None, toIRC = True): return 401 - """ IRC-Bancho Connect/Disconnect/Join/Part interfaces""" +def fixUsernameForBancho(username): + return username.replace("_", " ") + +def fixUsernameForIRC(username): + return username.replace(" ", "_") + def IRCConnect(username): userID = userHelper.getID(username) if userID == False: diff --git a/helpers/configHelper.py b/helpers/configHelper.py index 75bf7c3..2bb0ca8 100644 --- a/helpers/configHelper.py +++ b/helpers/configHelper.py @@ -1,18 +1,7 @@ import os import configparser -class config: - """ - config.ini object - - config -- list with ini data - default -- if true, we have generated a default config.ini - """ - - config = configparser.ConfigParser() - fileName = "" # config filename - default = True - +class config(): # Check if config.ini exists and load/generate it def __init__(self, file): """ @@ -20,7 +9,8 @@ class config: file -- filename """ - + self.config = configparser.ConfigParser() + self.default = True self.fileName = file if os.path.isfile(self.fileName): # config.ini found, load it @@ -39,7 +29,6 @@ class config: return -- True if valid, False if not """ - try: # Try to get all the required keys self.config.get("db","host") @@ -75,11 +64,10 @@ class config: except: return False - - # Generate a default config.ini def generateDefaultConfig(self): - """Open and set default keys for that config file""" - + """ + Open and set default keys for that config file + """ # Open config.ini in write mode f = open(self.fileName, "w") diff --git a/helpers/consoleHelper.py b/helpers/consoleHelper.py index 6b781c7..80abcd5 100644 --- a/helpers/consoleHelper.py +++ b/helpers/consoleHelper.py @@ -1,13 +1,12 @@ -"""Some console related functions""" - from constants import bcolors from objects import glob def printServerStartHeader(asciiArt): - """Print server start header with optional ascii art - - asciiArt -- if True, will print ascii art too""" + """ + Print server start header with optional ascii art + asciiArt -- if True, will print ascii art too + """ if asciiArt == True: print("{} _ __".format(bcolors.GREEN)) print(" (_) / /") @@ -28,20 +27,17 @@ def printServerStartHeader(asciiArt): printColored("> Welcome to pep.py osu!bancho server v{}".format(glob.VERSION), bcolors.GREEN) printColored("> Made by the Ripple team", bcolors.GREEN) - printColored("> {}https://github.com/osuripple/ripple".format(bcolors.UNDERLINE), bcolors.GREEN) + printColored("> {}https://git.zxq.co/ripple/pep.py".format(bcolors.UNDERLINE), bcolors.GREEN) printColored("> Press CTRL+C to exit\n",bcolors.GREEN) - def printNoNl(string): """ Print string without new line at the end string -- string to print """ - print(string, end="") - def printColored(string, color): """ Print colored string @@ -49,23 +45,22 @@ def printColored(string, color): string -- string to print color -- see bcolors.py """ - print("{}{}{}".format(color, string, bcolors.ENDC)) - def printError(): - """Print error text FOR LOADING""" - + """ + Print error text FOR LOADING + """ printColored("Error", bcolors.RED) - def printDone(): - """Print error text FOR LOADING""" - + """ + Print error text FOR LOADING + """ printColored("Done", bcolors.GREEN) - def printWarning(): - """Print error text FOR LOADING""" - + """ + Print error text FOR LOADING + """ printColored("Warning", bcolors.YELLOW) diff --git a/helpers/countryHelper.py b/helpers/countryHelper.py index d5808d3..6932312 100644 --- a/helpers/countryHelper.py +++ b/helpers/countryHelper.py @@ -253,7 +253,6 @@ countryCodes = { "AI": 7 } - def getCountryID(code): """ Get country ID for osu client diff --git a/helpers/databaseHelperNew.py b/helpers/databaseHelperNew.py index 51dfa0c..1e3d811 100644 --- a/helpers/databaseHelperNew.py +++ b/helpers/databaseHelperNew.py @@ -2,13 +2,13 @@ import MySQLdb import threading from helpers import logHelper as log -class mysqlWorker: +class mysqlWorker(): """ - Instance of a pettirosso meme + Instance of a mysql worker """ def __init__(self, wid, host, username, password, database): """ - Create a pettirosso meme (mysql worker) + Create a mysql worker wid -- worker id host -- hostname @@ -22,11 +22,10 @@ class mysqlWorker: self.ready = True self.lock = threading.Lock() -class db: +class db(): """ A MySQL db connection with multiple workers """ - def __init__(self, host, username, password, database, workers): """ Create MySQL workers aka pettirossi meme @@ -37,9 +36,6 @@ class db: database -- MySQL database name workers -- Number of workers to spawn """ - #self.lock = threading.Lock() - #self.connection = MySQLdb.connect(host, username, password, database) - self.workers = [] self.lastWorker = 0 self.workersNumber = workers @@ -57,7 +53,6 @@ class db: self.lastWorker = 0 else: self.lastWorker += 1 - #print("Using worker {}".format(self.lastWorker)) return self.workers[self.lastWorker] def execute(self, query, params = ()): diff --git a/helpers/discordBotHelper.py b/helpers/discordBotHelper.py index 9a0a961..d9c5f31 100644 --- a/helpers/discordBotHelper.py +++ b/helpers/discordBotHelper.py @@ -1,9 +1,6 @@ import requests from objects import glob -from helpers import generalFunctions from urllib.parse import urlencode -from helpers import consoleHelper -from constants import bcolors def sendDiscordMessage(channel, message, alertDev = False, prefix = "**pep.py**"): """ @@ -24,7 +21,6 @@ def sendDiscordMessage(channel, message, alertDev = False, prefix = "**pep.py**" except: continue - def sendConfidential(message, alertDev = False): """ Send a message to #bunker @@ -33,7 +29,6 @@ def sendConfidential(message, alertDev = False): """ sendDiscordMessage("bunk", message, alertDev) - def sendStaff(message): """ Send a message to #staff @@ -42,7 +37,6 @@ def sendStaff(message): """ sendDiscordMessage("staff", message) - def sendGeneral(message): """ Send a message to #general @@ -51,7 +45,6 @@ def sendGeneral(message): """ sendDiscordMessage("general", message) - def sendChatlog(message): """ Send a message to #chatlog diff --git a/helpers/generalFunctions.py b/helpers/generalFunctions.py index 8866ee3..88f98aa 100644 --- a/helpers/generalFunctions.py +++ b/helpers/generalFunctions.py @@ -1,6 +1,17 @@ -"""Some functions that don't fit in any other file""" from constants import mods from time import gmtime, strftime +import hashlib + +def stringMd5(string): + """ + Return string's md5 + + string -- string to hash + return -- string's md5 hash + """ + d = hashlib.md5() + d.update(string.encode("utf-8")) + return d.hexdigest() def stringToBool(s): """ @@ -9,10 +20,8 @@ def stringToBool(s): s -- string/int value return -- True/False """ - return (s == "True" or s== "true" or s == "1" or s == 1) - def hexString(s): """ Output s' bytes in HEX @@ -20,7 +29,6 @@ def hexString(s): s -- string return -- string with hex value """ - return ":".join("{:02x}".format(ord(str(c))) for c in s) def readableMods(__mods): diff --git a/helpers/locationHelper.py b/helpers/locationHelper.py index 1220aa6..985676b 100644 --- a/helpers/locationHelper.py +++ b/helpers/locationHelper.py @@ -11,7 +11,6 @@ def getCountry(ip): ip -- IP Address return -- Country code (2 letters) """ - try: # Try to get country from Pikolo Aul's Go-Sanic ip API result = json.loads(urllib.request.urlopen("{}/{}".format(glob.conf.config["localize"]["ipapiurl"], ip), timeout=3).read().decode())["country"] @@ -20,7 +19,6 @@ def getCountry(ip): log.error("Error in get country") return "XX" - def getLocation(ip): """ Get latitude and longitude from IP address @@ -28,7 +26,6 @@ def getLocation(ip): ip -- IP address return -- [latitude, longitude] """ - try: # Try to get position from Pikolo Aul's Go-Sanic ip API result = json.loads(urllib.request.urlopen("{}/{}".format(glob.conf.config["localize"]["ipapiurl"], ip), timeout=3).read().decode())["loc"].split(",") diff --git a/helpers/packetHelper.py b/helpers/packetHelper.py index 8cb79ec..2a09094 100644 --- a/helpers/packetHelper.py +++ b/helpers/packetHelper.py @@ -8,7 +8,6 @@ def uleb128Encode(num): num -- int to encode return -- bytearray with encoded number """ - arr = bytearray() length = 0 @@ -24,7 +23,6 @@ def uleb128Encode(num): return arr - def uleb128Decode(num): """ Decode uleb128 -> int @@ -32,9 +30,7 @@ def uleb128Decode(num): num -- encoded uleb128 return -- list. [total, length] """ - shift = 0 - arr = [0,0] #total, length while True: @@ -47,42 +43,40 @@ def uleb128Decode(num): return arr - -def unpackData(__data, __dataType): +def unpackData(data, dataType): """ Unpacks data according to dataType - __data -- bytes array to unpack - __dataType -- data type. See dataTypes.py + data -- bytes array to unpack + dataType -- data type. See dataTypes.py return -- unpacked bytes """ # Get right pack Type - if __dataType == dataTypes.uInt16: + if dataType == dataTypes.uInt16: unpackType = "