def connect(): """Add FokaBot to connected users and send userpanel/stats packet to everyone""" token = glob.tokens.addToken(999) token.actionID = actions.idle glob.tokens.enqueueAll(serverPackets.userPanel(999)) glob.tokens.enqueueAll(serverPackets.userStats(999))
def connect(): """Add Rohwabot to connected users and send userpanel/stats packet to everyone""" token = glob.tokens.addToken(999) token.actionID = actions.idle glob.tokens.enqueueAll(serverPackets.userPanel(999)) glob.tokens.enqueueAll(serverPackets.userStats(999))
def handle(userToken, packetData): # Get usertoken data userID = userToken.userID username = userToken.username # Change action packet packetData = clientPackets.userActionChange(packetData) # Update our action id, text and md5 userToken.actionID = packetData["actionID"] userToken.actionText = packetData["actionText"] userToken.actionMd5 = packetData["actionMd5"] userToken.actionMods = packetData["actionMods"] userToken.gameMode = packetData["gameMode"] # Enqueue our new user panel and stats to everyone glob.tokens.enqueueAll(serverPackets.userPanel(userID)) glob.tokens.enqueueAll(serverPackets.userStats(userID)) # Console output print("> {} changed action: {} [{}][{}]".format(username, str(userToken.actionID), userToken.actionText, userToken.actionMd5))
def handle(flaskRequest): # Data to return responseTokenString = "ayy" responseData = bytes() # Get IP from flask request requestIP = flaskRequest.headers.get('X-Real-IP') if requestIP == None: requestIP = flaskRequest.remote_addr # Console output print("> Accepting connection from {}...".format(requestIP)) # Split POST body so we can get username/password/hardware data # 2:-3 thing is because requestData has some escape stuff that we don't need loginData = str(flaskRequest.data)[2:-3].split("\\n") # Process login print("> Processing login request for {}...".format(loginData[0])) try: # If true, print error to console err = False # Try to get the ID from username userID = userHelper.getID(str(loginData[0])) if userID == False: # Invalid username raise exceptions.loginFailedException() if userHelper.checkLogin(userID, loginData[1]) == False: # Invalid password raise exceptions.loginFailedException() # Make sure we are not banned userAllowed = userHelper.getAllowed(userID) if userAllowed == 0: # Banned raise exceptions.loginBannedException() # No login errors! # Delete old tokens for that user and generate a new one glob.tokens.deleteOldTokens(userID) responseToken = glob.tokens.addToken(userID) responseTokenString = responseToken.token # Get silence end userSilenceEnd = max( 0, userHelper.getSilenceEnd(userID) - int(time.time())) # Get supporter/GMT userRank = userHelper.getRankPrivileges(userID) userGMT = False userSupporter = True if userRank >= 3: userGMT = True # Server restarting check if glob.restarting == True: raise exceptions.banchoRestartingException() # Maintenance check if glob.banchoConf.config["banchoMaintenance"] == True: if userGMT == False: # We are not mod/admin, delete token, send notification and logout glob.tokens.deleteToken(responseTokenString) raise exceptions.banchoMaintenanceException() else: # We are mod/admin, send warning notification and continue responseToken.enqueue( serverPackets.notification( "Bancho is in maintenance mode. Only mods/admins have full access to the server.\nType !system maintenance off in chat to turn off maintenance mode." )) # Send all needed login packets responseToken.enqueue(serverPackets.silenceEndTime(userSilenceEnd)) responseToken.enqueue(serverPackets.userID(userID)) responseToken.enqueue(serverPackets.protocolVersion()) responseToken.enqueue( serverPackets.userSupporterGMT(userSupporter, userGMT)) responseToken.enqueue(serverPackets.userPanel(userID)) responseToken.enqueue(serverPackets.userStats(userID)) # Channel info end (before starting!?! wtf bancho?) responseToken.enqueue(serverPackets.channelInfoEnd()) # Default opened channels # TODO: Configurable default channels channelJoinEvent.joinChannel(responseToken, "#osu") channelJoinEvent.joinChannel(responseToken, "#announce") if userRank >= 3: # Join admin chanenl if we are mod/admin # TODO: Separate channels for mods and admins channelJoinEvent.joinChannel(responseToken, "#admin") # Output channels info for key, value in glob.channels.channels.items(): if value.publicRead == True: responseToken.enqueue(serverPackets.channelInfo(key)) responseToken.enqueue(serverPackets.friendList(userID)) # Send main menu icon and login notification if needed if glob.banchoConf.config["menuIcon"] != "": responseToken.enqueue( serverPackets.mainMenuIcon(glob.banchoConf.config["menuIcon"])) if glob.banchoConf.config["loginNotification"] != "": responseToken.enqueue( serverPackets.notification( glob.banchoConf.config["loginNotification"])) # Get everyone else userpanel # TODO: Better online users handling for key, value in glob.tokens.tokens.items(): responseToken.enqueue(serverPackets.userPanel(value.userID)) responseToken.enqueue(serverPackets.userStats(value.userID)) # Send online users IDs array responseToken.enqueue(serverPackets.onlineUsers()) # Get location and country from ip.zxq.co or database if generalFunctions.stringToBool( glob.conf.config["server"]["localizeusers"]): # Get location and country from IP location = locationHelper.getLocation(requestIP) country = countryHelper.getCountryID( locationHelper.getCountry(requestIP)) else: # Set location to 0,0 and get country from db print("[!] Location skipped") location = [0, 0] country = countryHelper.getCountryID(userHelper.getCountry(userID)) # Set location and country responseToken.setLocation(location) responseToken.setCountry(country) # Send to everyone our userpanel and userStats (so they now we have logged in) glob.tokens.enqueueAll(serverPackets.userPanel(userID)) glob.tokens.enqueueAll(serverPackets.userStats(userID)) # Set reponse data to right value and reset our queue responseData = responseToken.queue responseToken.resetQueue() # Print logged in message consoleHelper.printColored( "> {} logged in ({})".format(loginData[0], responseToken.token), bcolors.GREEN) except exceptions.loginFailedException: # Login failed error packet # (we don't use enqueue because we don't have a token since login has failed) err = True responseData += serverPackets.loginFailed() except exceptions.loginBannedException: # Login banned error packet err = True responseData += serverPackets.loginBanned() except exceptions.banchoMaintenanceException: # Bancho is in maintenance mode responseData += serverPackets.notification( "Our bancho server is in maintenance mode. Please try to login again later." ) responseData += serverPackets.loginError() except exceptions.banchoRestartingException: # Bancho is restarting responseData += serverPackets.notification( "Bancho is restarting. Try again in a few minutes.") responseData += serverPackets.loginError() finally: # Print login failed message to console if needed if err == True: consoleHelper.printColored( "> {}'s login failed".format(loginData[0]), bcolors.YELLOW) return (responseTokenString, responseData)
def handle(flaskRequest): # Data to return responseTokenString = "ayy" responseData = bytes() # Get IP from flask request requestIP = flaskRequest.headers.get('X-Real-IP') if (requestIP == None): requestIP = flaskRequest.remote_addr # Console output print("> Accepting connection from {}...".format(requestIP)) # Split POST body so we can get username/password/hardware data # 2:-3 thing is because requestData has some escape stuff that we don't need loginData = str(flaskRequest.data)[2:-3].split("\\n") # Process login print("> Processing login request for {}...".format(loginData[0])) try: # If true, print error to console err = False # Try to get the ID from username userID = userHelper.getUserID(str(loginData[0])) if (userID == False): # Invalid username raise exceptions.loginFailedException() if (userHelper.checkLogin(userID, loginData[1]) == False): # Invalid password raise exceptions.loginFailedException() # Make sure we are not banned userAllowed = userHelper.getUserAllowed(userID) if (userAllowed == 0): # Banned raise exceptions.loginBannedException() # No login errors! # Delete old tokens for that user and generate a new one glob.tokens.deleteOldTokens(userID) responseToken = glob.tokens.addToken(userID) responseTokenString = responseToken.token # Get silence end userSilenceEnd = max(0, userHelper.getUserSilenceEnd(userID)-int(time.time())) # Get supporter/GMT userRank = userHelper.getUserRank(userID) userGMT = False userSupporter = True if (userRank >= 3): userGMT = True # Maintenance check if (glob.banchoConf.config["banchoMaintenance"] == True): if (userGMT == False): # We are not mod/admin, delete token, send notification and logout glob.tokens.deleteToken(responseTokenString) raise exceptions.banchoMaintenanceException() else: # We are mod/admin, send warning notification and continue responseToken.enqueue(serverPackets.notification("Bancho is in maintenance mode. Only mods/admins have full access to the server.\nType !system maintenance off in chat to turn off maintenance mode.")) # Send all needed login packets responseToken.enqueue(serverPackets.silenceEndTime(userSilenceEnd)) responseToken.enqueue(serverPackets.userID(userID)) responseToken.enqueue(serverPackets.protocolVersion()) responseToken.enqueue(serverPackets.userSupporterGMT(userSupporter, userGMT)) responseToken.enqueue(serverPackets.userPanel(userID)) responseToken.enqueue(serverPackets.userStats(userID)) # Channel info end (before starting!?! wtf bancho?) responseToken.enqueue(serverPackets.channelInfoEnd()) # Default opened channels # TODO: Configurable default channels channelJoinEvent.joinChannel(responseToken, "#osu") channelJoinEvent.joinChannel(responseToken, "#announce") if (userRank >= 3): # Join admin chanenl if we are mod/admin # TODO: Separate channels for mods and admins channelJoinEvent.joinChannel(responseToken, "#admin") # Output channels info for key, value in glob.channels.channels.items(): responseToken.enqueue(serverPackets.channelInfo(key)) responseToken.enqueue(serverPackets.friendList(userID)) # Send main menu icon and login notification if needed if (glob.banchoConf.config["menuIcon"] != ""): responseToken.enqueue(serverPackets.mainMenuIcon(glob.banchoConf.config["menuIcon"])) if (glob.banchoConf.config["loginNotification"] != ""): responseToken.enqueue(serverPackets.notification(glob.banchoConf.config["loginNotification"])) # Get everyone else userpanel # TODO: Better online users handling for key, value in glob.tokens.tokens.items(): responseToken.enqueue(serverPackets.userPanel(value.userID)) responseToken.enqueue(serverPackets.userStats(value.userID)) # Send online users IDs array responseToken.enqueue(serverPackets.onlineUsers()) # Get location and country from ip.zxq.co or database if (generalFunctions.stringToBool(glob.conf.config["server"]["localizeusers"])): # Get location and country from IP location = locationHelper.getLocation(requestIP) country = countryHelper.getCountryID(locationHelper.getCountry(requestIP)) else: # Set location to 0,0 and get country from db print("[!] Location skipped") location = [0,0] country = countryHelper.getCountryID(userHelper.getCountry(userID)) # Set location and country responseToken.setLocation(location) responseToken.setCountry(country) # Send to everyone our userpanel and userStats (so they now we have logged in) glob.tokens.enqueueAll(serverPackets.userPanel(userID)) glob.tokens.enqueueAll(serverPackets.userStats(userID)) # Set reponse data to right value and reset our queue responseData = responseToken.queue responseToken.resetQueue() # Print logged in message consoleHelper.printColored("> {} logged in ({})".format(loginData[0], responseToken.token), bcolors.GREEN) except exceptions.loginFailedException: # Login failed error packet # (we don't use enqueue because we don't have a token since login has failed) err = True responseData += serverPackets.loginFailed() except exceptions.loginBannedException: # Login banned error packet err = True responseData += serverPackets.loginBanned() except exceptions.banchoMaintenanceException: # Bancho is in maintenance mode responseData += serverPackets.notification("Our bancho server is in maintenance mode. Please try to login again later.") responseData += serverPackets.loginError() finally: # Print login failed message to console if needed if (err == True): consoleHelper.printColored("> {}'s login failed".format(loginData[0]), bcolors.YELLOW) return (responseTokenString, responseData)
def banchoServer(): if (flask.request.method == 'POST'): # Client's token requestToken = flask.request.headers.get('osu-token') # Client's request data # We remove the first two and last three characters because they are # some escape stuff that we don't need requestData = flask.request.data # Client's IP requestIP = flask.request.headers.get('X-Real-IP') if (requestIP == None): requestIP = flask.request.remote_addr # Server's response data responseData = bytes() # Server's response token string responseTokenString = "ayy"; if (requestToken == None): # We don't have a token, this is the first packet aka login print("> Accepting connection from "+requestIP+"...") # Split POST body so we can get username/password/hardware data loginData = str(requestData)[2:-3].split("\\n") # Process login print("> Processing login request for "+loginData[0]+"...") try: # If true, print error to console err = False # Try to get the ID from username userID = userHelper.getUserID(str(loginData[0])) if (userID == False): # Invalid username raise exceptions.loginFailedException() if (userHelper.checkLogin(userID, loginData[1]) == False): # Invalid password raise exceptions.loginFailedException() # Make sure we are not banned userAllowed = userHelper.getUserAllowed(userID) if (userAllowed == 0): # Banned raise exceptions.loginBannedException() # No login errors! # Delete old tokens for that user and generate a new one glob.tokens.deleteOldTokens(userID) responseToken = glob.tokens.addToken(userID) responseTokenString = responseToken.token # Print logged in message consoleHelper.printColored("> "+loginData[0]+" logged in ("+responseToken.token+")", bcolors.GREEN) # Get silence end userSilenceEnd = max(0, userHelper.getUserSilenceEnd(userID)-int(time.time())) # Get supporter/GMT userRank = userHelper.getUserRank(userID) userGMT = False userSupporter = True if (userRank >= 3): userGMT = True # Maintenance check if (glob.banchoConf.config["banchoMaintenance"] == True): if (userGMT == False): # We are not mod/admin, delete token, send notification and logout glob.tokens.deleteToken(responseTokenString) raise exceptions.banchoMaintenanceException() else: # We are mod/admin, send warning notification and continue responseToken.enqueue(serverPackets.notification("Bancho is in maintenance mode. Only mods/admins have full access to the server.\nType !system maintenance off in chat to turn off maintenance mode.")) # Send all needed login packets responseToken.enqueue(serverPackets.silenceEndTime(userSilenceEnd)) responseToken.enqueue(serverPackets.userID(userID)) responseToken.enqueue(serverPackets.protocolVersion()) responseToken.enqueue(serverPackets.userSupporterGMT(userSupporter, userGMT)) responseToken.enqueue(serverPackets.userPanel(userID)) responseToken.enqueue(serverPackets.userStats(userID)) # Channel info end (before starting!?! wtf bancho?) responseToken.enqueue(serverPackets.channelInfoEnd()) # TODO: Configurable default channels # Default opened channels glob.channels.channels["#osu"].userJoin(userID) responseToken.joinChannel("#osu") glob.channels.channels["#announce"].userJoin(userID) responseToken.joinChannel("#announce") responseToken.enqueue(serverPackets.channelJoinSuccess(userID, "#osu")) responseToken.enqueue(serverPackets.channelJoinSuccess(userID, "#announce")) # Output channels info for key, value in glob.channels.channels.items(): responseToken.enqueue(serverPackets.channelInfo(key)) responseToken.enqueue(serverPackets.friendList(userID)) # Send main menu icon and login notification if needed if (glob.banchoConf.config["menuIcon"] != ""): responseToken.enqueue(serverPackets.mainMenuIcon(glob.banchoConf.config["menuIcon"])) if (glob.banchoConf.config["loginNotification"] != ""): responseToken.enqueue(serverPackets.notification(glob.banchoConf.config["loginNotification"])) # Get everyone else userpanel # TODO: Better online users handling for key, value in glob.tokens.tokens.items(): responseToken.enqueue(serverPackets.userPanel(value.userID)) responseToken.enqueue(serverPackets.userStats(value.userID)) # Send online users IDs array responseToken.enqueue(serverPackets.onlineUsers()) # Send to everyone our userpanel and userStats (so they now we have logged in) glob.tokens.enqueueAll(serverPackets.userPanel(userID)) glob.tokens.enqueueAll(serverPackets.userStats(userID)) # Set position and country responseToken.setLocation(locationHelper.getLocation(requestIP)) responseToken.setCountry(countryHelper.getCountryID(locationHelper.getCountry(requestIP))) # Set reponse data to right value and reset our queue responseData = responseToken.queue responseToken.resetQueue() except exceptions.loginFailedException: # Login failed error packet # (we don't use enqueue because we don't have a token since login has failed) err = True responseData += serverPackets.loginFailed() except exceptions.loginBannedException: # Login banned error packet err = True responseData += serverPackets.loginBanned() except exceptions.banchoMaintenanceException: # Bancho is in maintenance mode responseData += serverPackets.notification("Our bancho server is in maintenance mode. Please try to login again later.") responseData += serverPackets.loginError() finally: # Print login failed message to console if needed if (err == True): consoleHelper.printColored("> "+loginData[0]+"'s login failed", bcolors.YELLOW) else: try: # This is not the first packet, send response based on client's request # Packet start position, used to read stacked packets pos = 0 # Make sure the token exists if (requestToken not in glob.tokens.tokens): raise exceptions.tokenNotFoundException() # Token exists, get its object userToken = glob.tokens.tokens[requestToken] # Get userID and username from token userID = userToken.userID username = userToken.username userRank = userToken.rank # Keep reading packets until everything has been read while pos < len(requestData): # Get packet from stack starting from new packet leftData = requestData[pos:] # Get packet ID, data length and data packetID = packetHelper.readPacketID(leftData) dataLength = packetHelper.readPacketLength(leftData) packetData = requestData[pos:(pos+dataLength+7)] # Console output if needed if (serverOutputPackets == True and packetID != 4): consoleHelper.printColored("Incoming packet ("+requestToken+")("+username+"):", bcolors.GREEN) consoleHelper.printColored("Packet code: "+str(packetID)+"\nPacket length: "+str(dataLength)+"\nSingle packet data: "+str(packetData)+"\n", bcolors.YELLOW) # Packet switch if (packetID == packetIDs.client_pong): # Ping packet, nothing to do # New packets are automatically taken from the queue pass elif (packetID == packetIDs.client_sendPublicMessage): try: # Public chat packet packetData = clientPackets.sendPublicMessage(packetData) # Receivers who = [] # Check #spectator if (packetData["to"] != "#spectator"): # Standard channel # Make sure the channel exists if (packetData["to"] not in glob.channels.channels): raise exceptions.channelUnknownException # Make sure the channel is not in moderated mode if (glob.channels.channels[packetData["to"]].moderated == True and userRank < 2): raise exceptions.channelModeratedException # Make sure we have write permissions if (glob.channels.channels[packetData["to"]].publicWrite == False and userRank < 2): raise exceptions.channelNoPermissionsException # Send this packet to everyone in that channel except us who = glob.channels.channels[packetData["to"]].getConnectedUsers()[:] if userID in who: who.remove(userID) else: # Spectator channel # Send this packet to every spectator and host if (userToken.spectating == 0): # We have sent to send a message to our #spectator channel targetToken = userToken who = targetToken.spectators[:] # No need to remove us because we are the host so we are not in spectators list else: # We have sent a message to someone else's #spectator targetToken = glob.tokens.getTokenFromUserID(userToken.spectating) who = targetToken.spectators[:] # Remove us if (userID in who): who.remove(userID) # Add host who.append(targetToken.userID) # Send packet to required users glob.tokens.multipleEnqueue(serverPackets.sendMessage(username, packetData["to"], packetData["message"]), who, False) # Fokabot command check fokaMessage = fokabot.fokabotResponse(username, packetData["to"], packetData["message"]) if (fokaMessage != False): who.append(userID) glob.tokens.multipleEnqueue(serverPackets.sendMessage("FokaBot", packetData["to"], fokaMessage), who, False) consoleHelper.printColored("> FokaBot@"+packetData["to"]+": "+str(fokaMessage.encode("UTF-8")), bcolors.PINK) # Console output consoleHelper.printColored("> "+username+"@"+packetData["to"]+": "+str(packetData["message"].encode("UTF-8")), bcolors.PINK) except exceptions.channelModeratedException: consoleHelper.printColored("[!] "+username+" has attempted to send a message to a channel that is in moderated mode ("+packetData["to"]+")", bcolors.RED) except exceptions.channelUnknownException: consoleHelper.printColored("[!] "+username+" has attempted to send a message to an unknown channel ("+packetData["to"]+")", bcolors.RED) except exceptions.channelNoPermissionsException: consoleHelper.printColored("[!] "+username+" has attempted to send a message to channel "+packetData["to"]+", but he has no write permissions", bcolors.RED) elif (packetID == packetIDs.client_sendPrivateMessage): try: # Private message packet packetData = clientPackets.sendPrivateMessage(packetData) if (packetData["to"] == "FokaBot"): # FokaBot command check fokaMessage = fokabot.fokabotResponse(username, packetData["to"], packetData["message"]) if (fokaMessage != False): userToken.enqueue(serverPackets.sendMessage("FokaBot", username, fokaMessage)) consoleHelper.printColored("> FokaBot>"+packetData["to"]+": "+str(fokaMessage.encode("UTF-8")), bcolors.PINK) else: # Send packet message to target if it exists token = glob.tokens.getTokenFromUsername(packetData["to"]) if (token == None): raise exceptions.tokenNotFoundException() token.enqueue(serverPackets.sendMessage(username, packetData["to"], packetData["message"])) # Console output consoleHelper.printColored("> "+username+">"+packetData["to"]+": "+packetData["message"], bcolors.PINK) except exceptions.tokenNotFoundException: # Token not found, user disconnected consoleHelper.printColored("[!] "+username+" has tried to send a message to "+packetData["to"]+", but its token couldn't be found", bcolors.RED) elif (packetID == packetIDs.client_channelJoin): try: # Channel join packet packetData = clientPackets.channelJoin(packetData) # Check spectator channel # If it's spectator channel, skip checks and list stuff if (packetData["channel"] != "#spectator"): # Normal channel, do check stuff # Make sure the channel exists if (packetData["channel"] not in glob.channels.channels): raise exceptions.channelUnknownException # Check channel permissions if ((glob.channels.channels[packetData["channel"]].publicWrite == False or glob.channels.channels[packetData["channel"]].moderated == True) and userRank < 2): raise exceptions.channelNoPermissionsException # Add our userID to users in that channel glob.channels.channels[packetData["channel"]].userJoin(userID) # Add the channel to our joined channel userToken.joinChannel(packetData["channel"]) # Send channel joined userToken.enqueue(serverPackets.channelJoinSuccess(userID, packetData["channel"])) # Console output consoleHelper.printColored("> "+username+" has joined channel "+packetData["channel"], bcolors.GREEN) except exceptions.channelNoPermissionsException: consoleHelper.printColored("[!] "+username+" has attempted to join channel "+packetData["channel"]+", but he has no read permissions", bcolors.RED) except exceptions.channelUnknownException: consoleHelper.printColored("[!] "+username+" has attempted to join an unknown channel ("+packetData["channel"]+")", bcolors.RED) elif (packetID == packetIDs.client_channelPart): # Channel part packet packetData = clientPackets.channelPart(packetData) # Remove us from joined users and joined channels if packetData["channel"] in glob.channels.channels: userToken.partChannel(packetData["channel"]) glob.channels.channels[packetData["channel"]].userPart(userID) # Console output consoleHelper.printColored("> "+username+" has parted channel "+packetData["channel"], bcolors.YELLOW) elif (packetID == packetIDs.client_changeAction): # Change action packet packetData = clientPackets.userActionChange(packetData) # Update our action id, text and md5 userToken.actionID = packetData["actionID"] userToken.actionText = packetData["actionText"] userToken.actionMd5 = packetData["actionMd5"] userToken.actionMods = packetData["actionMods"] userToken.gameMode = packetData["gameMode"] # Enqueue our new user panel and stats to everyone glob.tokens.enqueueAll(serverPackets.userPanel(userID)) glob.tokens.enqueueAll(serverPackets.userStats(userID)) # Console output print("> "+username+" has changed action: "+str(userToken.actionID)+" ["+userToken.actionText+"]["+userToken.actionMd5+"]") elif (packetID == packetIDs.client_startSpectating): try: # Start spectating packet packetData = clientPackets.startSpectating(packetData) # Stop spectating old user if needed if (userToken.spectating != 0): oldTargetToken = glob.tokens.getTokenFromUserID(userToken.spectating) oldTargetToken.enqueue(serverPackets.removeSpectator(userID)) userToken.stopSpectating() # Start spectating new user userToken.startSpectating(packetData["userID"]) # Get host token targetToken = glob.tokens.getTokenFromUserID(packetData["userID"]) if (targetToken == None): raise exceptions.tokenNotFoundException # Add us to host's spectators targetToken.addSpectator(userID) # Send spectator join packet to host targetToken.enqueue(serverPackets.addSpectator(userID)) # Join #spectator channel userToken.enqueue(serverPackets.channelJoinSuccess(userID, "#spectator")) if (len(targetToken.spectators) == 1): # First spectator, send #spectator join to host too targetToken.enqueue(serverPackets.channelJoinSuccess(userID, "#spectator")) # Console output consoleHelper.printColored("> "+username+" is spectating "+userHelper.getUserUsername(packetData["userID"]), bcolors.PINK) consoleHelper.printColored("> {}'s spectators: {}".format(str(packetData["userID"]), str(targetToken.spectators)), bcolors.BLUE) except exceptions.tokenNotFoundException: # Stop spectating if token not found consoleHelper.printColored("[!] Spectator start: token not found", bcolors.RED) userToken.stopSpectating() elif (packetID == packetIDs.client_stopSpectating): try: # Stop spectating packet, has no parameters # Remove our userID from host's spectators target = userToken.spectating targetToken = glob.tokens.getTokenFromUserID(target) if (targetToken == None): raise exceptions.tokenNotFoundException targetToken.removeSpectator(userID) # Send the spectator left packet to host targetToken.enqueue(serverPackets.removeSpectator(userID)) # Console output # TODO: Move messages in stop spectating consoleHelper.printColored("> "+username+" is no longer spectating whoever he was spectating", bcolors.PINK) consoleHelper.printColored("> {}'s spectators: {}".format(str(target), str(targetToken.spectators)), bcolors.BLUE) except exceptions.tokenNotFoundException: consoleHelper.printColored("[!] Spectator stop: token not found", bcolors.RED) finally: # Set our spectating user to 0 userToken.stopSpectating() elif (packetID == packetIDs.client_cantSpectate): try: # We don't have the beatmap, we can't spectate target = userToken.spectating targetToken = glob.tokens.getTokenFromUserID(target) # Send the packet to host targetToken.enqueue(serverPackets.noSongSpectator(userID)) except exceptions.tokenNotFoundException: # Stop spectating if token not found consoleHelper.printColored("[!] Spectator can't spectate: token not found", bcolors.RED) userToken.stopSpectating() elif (packetID == packetIDs.client_spectateFrames): # Client spectate frames # Send spectator frames to every spectator consoleHelper.printColored("> {}'s spectators: {}".format(str(userID), str(userToken.spectators)), bcolors.BLUE) for i in userToken.spectators: if (i != userID): # TODO: Check that spectators are spectating us # Send to every spectator but us (host) spectatorToken = glob.tokens.getTokenFromUserID(i) if (spectatorToken != None): # Token found, send frames spectatorToken.enqueue(serverPackets.spectatorFrames(packetData[7:])) else: # Token not found, remove it userToken.removeSpectator(i) userToken.enqueue(serverPackets.removeSpectator(i)) elif (packetID == packetIDs.client_friendAdd): # Friend add packet packetData = clientPackets.addRemoveFriend(packetData) userHelper.addFriend(userID, packetData["friendID"]) # Console output print("> "+username+" has added "+str(packetData["friendID"])+" to his friends") elif (packetID == packetIDs.client_friendRemove): # Friend remove packet packetData = clientPackets.addRemoveFriend(packetData) userHelper.removeFriend(userID, packetData["friendID"]) # Console output print("> "+username+" has removed "+str(packetData["friendID"])+" from his friends") elif (packetID == packetIDs.client_logout): # Logout packet, no parameters to read # 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 (int(time.time()-userToken.loginTime) >= 5): # TODO: Channel part at logout # TODO: Stop spectating at logout # TODO: Stop spectating at timeout # Enqueue our disconnection to everyone else glob.tokens.enqueueAll(serverPackets.userLogout(userID)) # Delete token glob.tokens.deleteToken(requestToken) consoleHelper.printColored("> "+username+" has been disconnected (logout)", bcolors.YELLOW) # Set reponse data and tokenstring to right value and reset our queue # Update pos so we can read the next stacked packet pos += dataLength+7 # add packet ID bytes, unused byte and data length bytes # WHILE END # Token queue built, send it # TODO: Move somewhere else responseTokenString = userToken.token responseData = userToken.queue userToken.resetQueue() # Update ping time for timeout userToken.updatePingTime() except exceptions.tokenNotFoundException: # Token not found. Disconnect that user responseData = serverPackets.loginError() responseData += serverPackets.notification("Whoops! Something went wrong, please login again.") consoleHelper.printColored("[!] Received packet from unknown token ("+requestToken+").", bcolors.RED) consoleHelper.printColored("> "+requestToken+" has been disconnected (invalid token)", bcolors.YELLOW) # Send server's response to client # We don't use token object because we might not have a token (failed login) return responseHelper.generateResponse(responseTokenString, responseData) else: # Not a POST request, send html page # TODO: Fix this crap return responseHelper.HTMLResponse()