IRC Support for username with spaces

BATs with Donor have bright yellow username in chat
General performance improvements
Code cleaning
Multiplayer improvements and fixes
Fixed some spectator bugs
This commit is contained in:
Nyo 2016-09-02 12:41:19 +02:00
parent e16e4d7493
commit 653303831b
47 changed files with 450 additions and 622 deletions

1
.gitignore vendored
View File

@ -2,3 +2,4 @@
config.ini config.ini
filters.txt filters.txt
.data .data
.idea

View File

@ -57,13 +57,12 @@ def addRemoveFriend(stream):
return packetHelper.readPacketData(stream, [["friendID", dataTypes.sInt32]]) return packetHelper.readPacketData(stream, [["friendID", dataTypes.sInt32]])
""" Spectator packets """
""" SPECTATOR PACKETS """
def startSpectating(stream): def startSpectating(stream):
return packetHelper.readPacketData(stream,[["userID", dataTypes.sInt32]]) return packetHelper.readPacketData(stream,[["userID", dataTypes.sInt32]])
""" MULTIPLAYER PACKETS """ """ Multiplayer packets """
def matchSettings(stream): def matchSettings(stream):
# Data to return, will be merged later # Data to return, will be merged later
data = [] data = []
@ -115,9 +114,6 @@ def matchSettings(stream):
# Read last part # Read last part
data.append(packetHelper.readPacketData(stream[start:], struct, False)) data.append(packetHelper.readPacketData(stream[start:], struct, False))
# Mods if freemod (not used)
#if data[1]["freeMods"] == 1:
result = {} result = {}
for i in data: for i in data:
result.update(i) result.update(i)

View File

@ -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 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): def instantRestart(fro, chan, message):
glob.tokens.enqueueAll(serverPackets.notification("We are restarting Bancho. Be right back!")) glob.tokens.enqueueAll(serverPackets.notification("We are restarting Bancho. Be right back!"))
systemHelper.scheduleShutdown(0, True, delay=1) systemHelper.scheduleShutdown(0, True, delay=1)

View File

@ -1,4 +1,3 @@
"""Contains readable gamemodes with their codes"""
std = 0 std = 0
taiko = 1 taiko = 1
ctb = 2 ctb = 2
@ -9,10 +8,8 @@ def getGameModeForDB(gameMode):
Convert a gamemode number to string for database table/column Convert a gamemode number to string for database table/column
gameMode -- gameMode int or variable (ex: gameMode.std) gameMode -- gameMode int or variable (ex: gameMode.std)
return -- game mode readable string for db return -- game mode readable string for db
""" """
if gameMode == std: if gameMode == std:
return "std" return "std"
elif gameMode == taiko: elif gameMode == taiko:
@ -27,10 +24,8 @@ def getGameModeForPrinting(gameMode):
Convert a gamemode number to string for showing to a user (e.g. !last) Convert a gamemode number to string for showing to a user (e.g. !last)
gameMode -- gameMode int or variable (ex: gameMode.std) gameMode -- gameMode int or variable (ex: gameMode.std)
return -- game mode readable string for a human return -- game mode readable string for a human
""" """
if gameMode == std: if gameMode == std:
return "osu!" return "osu!"
elif gameMode == taiko: elif gameMode == taiko:

View File

@ -5,9 +5,9 @@ from helpers import userHelper
from objects import glob from objects import glob
from constants import userRanks from constants import userRanks
from constants import packetIDs from constants import packetIDs
from constants import privileges
""" Login errors packets """ Login errors packets """
(userID packets derivates) """
def loginFailed(): def loginFailed():
return packetHelper.buildPacket(packetIDs.server_userID, [[-1, dataTypes.sInt32]]) 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 = 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") 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 packets
#return packetHelper.buildPacket(packetIDs.server_userID, [[-3, dataTypes.sInt32]])
def loginError(): def loginError():
return packetHelper.buildPacket(packetIDs.server_userID, [[-5, dataTypes.sInt32]]) return packetHelper.buildPacket(packetIDs.server_userID, [[-5, dataTypes.sInt32]])
@ -29,6 +28,7 @@ def needSupporter():
def needVerification(): def needVerification():
return packetHelper.buildPacket(packetIDs.server_userID, [[-8, dataTypes.sInt32]]) return packetHelper.buildPacket(packetIDs.server_userID, [[-8, dataTypes.sInt32]])
""" Login packets """ """ Login packets """
def userID(uid): def userID(uid):
return packetHelper.buildPacket(packetIDs.server_userID, [[uid, dataTypes.sInt32]]) 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]]) return packetHelper.buildPacket(packetIDs.server_supporterGMT, [[result, dataTypes.uInt32]])
def friendList(userID): def friendList(userID):
friendsData = []
# Get friend IDs from db
friends = userHelper.getFriendList(userID) friends = userHelper.getFriendList(userID)
return packetHelper.buildPacket(packetIDs.server_friendsList, [[friends, dataTypes.intList]])
# 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)
def onlineUsers(): def onlineUsers():
userIDs = [] userIDs = []
@ -91,7 +80,7 @@ def userPanel(userID, force = False):
# Get user data # Get user data
username = userToken.username username = userToken.username
timezone = 24+userToken.timeOffset # TODO: Timezone timezone = 24+userToken.timeOffset
country = userToken.country country = userToken.country
gameRank = userToken.gameRank gameRank = userToken.gameRank
latitude = userToken.getLatitude() latitude = userToken.getLatitude()
@ -105,7 +94,7 @@ def userPanel(userID, force = False):
userRank = userRanks.MOD userRank = userRanks.MOD
elif userHelper.isInPrivilegeGroup(userID, "developer") == True: elif userHelper.isInPrivilegeGroup(userID, "developer") == True:
userRank = userRanks.ADMIN userRank = userRanks.ADMIN
elif userHelper.isInPrivilegeGroup(userID, "donor") == True: elif (userToken.privileges & privileges.USER_DONOR) > 0:
userRank = userRanks.SUPPORTER userRank = userRanks.SUPPORTER
else: else:
userRank = userRanks.NORMAL userRank = userRanks.NORMAL
@ -126,10 +115,12 @@ def userPanel(userID, force = False):
def userStats(userID, force = False): def userStats(userID, force = False):
# Get userID's token from tokens list # Get userID's token from tokens list
userToken = glob.tokens.getTokenFromUserID(userID) userToken = glob.tokens.getTokenFromUserID(userID)
if userToken == None: if userToken == None:
return bytes() return bytes()
if (userToken.restricted == True or userToken.irc == True) and force == False: if (userToken.restricted == True or userToken.irc == True) and force == False:
return bytes() return bytes()
return packetHelper.buildPacket(packetIDs.server_userStats, return packetHelper.buildPacket(packetIDs.server_userStats,
[ [
[userID, dataTypes.uInt32], [userID, dataTypes.uInt32],
@ -150,14 +141,23 @@ def userStats(userID, force = False):
""" Chat packets """ """ Chat packets """
def sendMessage(fro, to, message): 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): def channelJoinSuccess(userID, chan):
return packetHelper.buildPacket(packetIDs.server_channelJoinSuccess, [[chan, dataTypes.string]]) return packetHelper.buildPacket(packetIDs.server_channelJoinSuccess, [[chan, dataTypes.string]])
def channelInfo(chan): def channelInfo(chan):
channel = glob.channels.channels[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(): def channelInfoEnd():
return packetHelper.buildPacket(packetIDs.server_channelInfoEnd, [[0, dataTypes.uInt32]]) return packetHelper.buildPacket(packetIDs.server_channelInfoEnd, [[0, dataTypes.uInt32]])
@ -199,7 +199,6 @@ def createMatch(matchID):
match = glob.matches.matches[matchID] match = glob.matches.matches[matchID]
return packetHelper.buildPacket(packetIDs.server_newMatch, match.getMatchData()) return packetHelper.buildPacket(packetIDs.server_newMatch, match.getMatchData())
def updateMatch(matchID): def updateMatch(matchID):
# Make sure the match exists # Make sure the match exists
if matchID not in glob.matches.matches: if matchID not in glob.matches.matches:
@ -209,7 +208,6 @@ def updateMatch(matchID):
match = glob.matches.matches[matchID] match = glob.matches.matches[matchID]
return packetHelper.buildPacket(packetIDs.server_updateMatch, match.getMatchData()) return packetHelper.buildPacket(packetIDs.server_updateMatch, match.getMatchData())
def matchStart(matchID): def matchStart(matchID):
# Make sure the match exists # Make sure the match exists
if matchID not in glob.matches.matches: if matchID not in glob.matches.matches:
@ -219,9 +217,8 @@ def matchStart(matchID):
match = glob.matches.matches[matchID] match = glob.matches.matches[matchID]
return packetHelper.buildPacket(packetIDs.server_matchStart, match.getMatchData()) return packetHelper.buildPacket(packetIDs.server_matchStart, match.getMatchData())
def disposeMatch(matchID): def disposeMatch(matchID):
return packetHelper.buildPacket(packetIDs.server_disposeMatch, [[matchID, dataTypes.uInt16]]) return packetHelper.buildPacket(packetIDs.server_disposeMatch, [[matchID, dataTypes.uInt32]])
def matchJoinSuccess(matchID): def matchJoinSuccess(matchID):
# Make sure the match exists # Make sure the match exists
@ -260,9 +257,10 @@ def playerFailed(slotID):
def matchTransferHost(): def matchTransferHost():
return packetHelper.buildPacket(packetIDs.server_matchTransferHost) return packetHelper.buildPacket(packetIDs.server_matchTransferHost)
""" Other packets """ """ Other packets """
def notification(message): def notification(message):
return packetHelper.buildPacket(packetIDs.server_notification, [[message, dataTypes.string]]) return packetHelper.buildPacket(packetIDs.server_notification, [[message, dataTypes.string]])
def banchoRestart(msUntilReconnection): def banchoRestart(msUntilReconnection):
return packetHelper.buildPacket(packetIDs.server_restart, [[msUntilReconnection, dataTypes.uInt32]]) return packetHelper.buildPacket(packetIDs.server_restart, [[msUntilReconnection, dataTypes.uInt32]])

View File

@ -4,7 +4,6 @@ from constants import serverPackets
from helpers import userHelper from helpers import userHelper
from helpers import logHelper as log from helpers import logHelper as log
from constants import actions from constants import actions
from helpers import chatHelper as chat
def handle(userToken, packetData): def handle(userToken, packetData):
# Get usertoken data # Get usertoken data
@ -24,9 +23,16 @@ def handle(userToken, packetData):
# Change action packet # Change action packet
packetData = clientPackets.userActionChange(packetData) 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 # 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"]): 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 # Always update game mode, or we'll cache stats from the wrong game mode if we've changed it
userToken.gameMode = packetData["gameMode"] userToken.gameMode = packetData["gameMode"]
userToken.updateCachedStats() userToken.updateCachedStats()
@ -55,12 +61,5 @@ def handle(userToken, packetData):
token.enqueue(serverPackets.userPanel(userID, force)) token.enqueue(serverPackets.userPanel(userID, force))
token.enqueue(serverPackets.userStats(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 # Console output
log.info("{} changed action: {} [{}][{}]".format(username, str(userToken.actionID), userToken.actionText, userToken.actionMd5)) log.info("{} changed action: {} [{}][{}]".format(username, str(userToken.actionID), userToken.actionText, userToken.actionMd5))

View File

@ -16,6 +16,10 @@ def handle(userToken, packetData):
return return
match = glob.matches.matches[matchID] match = glob.matches.matches[matchID]
# Host check
if userID != match.hostUserID:
return
# Set slot or match mods according to modType # Set slot or match mods according to modType
if match.matchModMode == matchModModes.freeMod: if match.matchModMode == matchModModes.freeMod:
# 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 host has selected DT/HT and Freemod is enabled, set DT/HT as match mod
if (packetData["mods"] & mods.DoubleTime) > 0: if (packetData["mods"] & mods.DoubleTime) > 0:
match.changeMatchMods(mods.DoubleTime) match.changeMatchMods(mods.DoubleTime)
# Nighcore # Nightcore
if (packetData["mods"] & mods.Nightcore) > 0: if (packetData["mods"] & mods.Nightcore) > 0:
match.changeMatchMods(match.mods+mods.Nightcore) match.changeMatchMods(match.mods+mods.Nightcore)
elif (packetData["mods"] & mods.HalfTime) > 0: elif (packetData["mods"] & mods.HalfTime) > 0:

View File

@ -13,5 +13,9 @@ def handle(userToken, packetData):
# Get our match # Get our match
match = glob.matches.matches[matchID] match = glob.matches.matches[matchID]
# Host check
if userToken.userID != match.hostUserID:
return
# Update match password # Update match password
match.changePassword(packetData["matchPassword"]) match.changePassword(packetData["matchPassword"])

View File

@ -6,6 +6,7 @@ from constants import matchTeamTypes
from constants import matchTeams from constants import matchTeams
from constants import slotStatuses from constants import slotStatuses
from helpers import logHelper as log from helpers import logHelper as log
from helpers import generalFunctions
def handle(userToken, packetData): def handle(userToken, packetData):
# Read new settings # Read new settings
@ -13,7 +14,7 @@ def handle(userToken, packetData):
# Get match ID # Get match ID
matchID = userToken.matchID matchID = userToken.matchID
# Make sure the match exists # Make sure the match exists
if matchID not in glob.matches.matches: if matchID not in glob.matches.matches:
return return
@ -21,6 +22,10 @@ def handle(userToken, packetData):
# Get match object # Get match object
match = glob.matches.matches[matchID] match = glob.matches.matches[matchID]
# Host check
if userToken.userID != match.hostUserID:
return
# Some dank memes easter egg # Some dank memes easter egg
memeTitles = [ memeTitles = [
"RWC 2020", "RWC 2020",
@ -53,7 +58,10 @@ def handle(userToken, packetData):
# Update match settings # Update match settings
match.inProgress = packetData["inProgress"] 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.beatmapName = packetData["beatmapName"]
match.beatmapID = packetData["beatmapID"] match.beatmapID = packetData["beatmapID"]
match.hostUserID = packetData["hostUserID"] match.hostUserID = packetData["hostUserID"]
@ -71,14 +79,14 @@ def handle(userToken, packetData):
# Reset ready if needed # Reset ready if needed
if oldMods != match.mods or oldBeatmapMD5 != match.beatmapMD5: if oldMods != match.mods or oldBeatmapMD5 != match.beatmapMD5:
for i in range(0,16): for i in range(0,16):
if match.slots[i]["status"] == slotStatuses.ready: if match.slots[i].status == slotStatuses.ready:
match.slots[i]["status"] = slotStatuses.notReady match.slots[i].status = slotStatuses.notReady
# Reset mods if needed # Reset mods if needed
if match.matchModMode == matchModModes.normal: if match.matchModMode == matchModModes.normal:
# Reset slot mods if not freeMods # Reset slot mods if not freeMods
for i in range(0,16): for i in range(0,16):
match.slots[i]["mods"] = 0 match.slots[i].mods = 0
else: else:
# Reset match mods if freemod # Reset match mods if freemod
match.mods = 0 match.mods = 0
@ -88,13 +96,13 @@ def handle(userToken, packetData):
# Set teams # Set teams
c=0 c=0
for i in range(0,16): for i in range(0,16):
if match.slots[i]["team"] == matchTeams.noTeam: if match.slots[i].team == matchTeams.noTeam:
match.slots[i]["team"] = matchTeams.red if c % 2 == 0 else matchTeams.blue match.slots[i].team = matchTeams.red if c % 2 == 0 else matchTeams.blue
c+=1 c+=1
else: else:
# Reset teams # Reset teams
for i in range(0,16): for i in range(0,16):
match.slots[i]["team"] = matchTeams.noTeam match.slots[i].team = matchTeams.noTeam
# Force no freemods if tag coop # Force no freemods if tag coop
if match.matchTeamType == matchTeamTypes.tagCoop or match.matchTeamType == matchTeamTypes.tagTeamVs: if match.matchTeamType == matchTeamTypes.tagCoop or match.matchTeamType == matchTeamTypes.tagTeamVs:
@ -105,4 +113,3 @@ def handle(userToken, packetData):
# Console output # Console output
log.info("MPROOM{}: Updated room settings".format(match.matchID)) log.info("MPROOM{}: Updated room settings".format(match.matchID))
#consoleHelper.printColored("> MPROOM{}: DEBUG: Host is {}".format(match.matchID, match.hostUserID), bcolors.PINK)

View File

@ -4,6 +4,7 @@ from objects import glob
from constants import exceptions from constants import exceptions
from helpers import logHelper as log from helpers import logHelper as log
from helpers import chatHelper as chat from helpers import chatHelper as chat
from helpers import generalFunctions
def handle(userToken, packetData): def handle(userToken, packetData):
# read packet data # read packet data
@ -12,12 +13,15 @@ def handle(userToken, packetData):
# Get match from ID # Get match from ID
joinMatch(userToken, packetData["matchID"], packetData["password"]) joinMatch(userToken, packetData["matchID"], packetData["password"])
def joinMatch(userToken, matchID, password): def joinMatch(userToken, matchID, password, isPasswordHashed = False):
try: try:
# TODO: leave other matches # Stop spectating
# TODO: Stop spectating userToken.stopSpectating()
# get usertoken data # Leave other matches
userToken.partMatch()
# Get usertoken data
userID = userToken.userID userID = userToken.userID
# Make sure the match exists # Make sure the match exists
@ -27,6 +31,10 @@ def joinMatch(userToken, matchID, password):
# Match exists, get object # Match exists, get object
match = glob.matches.matches[matchID] match = glob.matches.matches[matchID]
# Hash password if needed
if isPasswordHashed == False and password != "":
password = generalFunctions.stringMd5(password)
# Check password # Check password
# TODO: Admins can enter every match # TODO: Admins can enter every match
if match.matchPassword != "": if match.matchPassword != "":

View File

@ -2,16 +2,10 @@ from helpers import userHelper
from constants import serverPackets from constants import serverPackets
from constants import exceptions from constants import exceptions
from objects import glob from objects import glob
from helpers import consoleHelper
from constants import bcolors
from helpers import locationHelper from helpers import locationHelper
from helpers import countryHelper from helpers import countryHelper
import time
from helpers import generalFunctions
import sys import sys
import traceback import traceback
from helpers import requestHelper
from helpers import discordBotHelper
from helpers import logHelper as log from helpers import logHelper as log
from helpers import chatHelper as chat from helpers import chatHelper as chat
from constants import privileges from constants import privileges

View File

@ -15,21 +15,16 @@ def handle(userToken, _=None):
# the server, so we accept logout packets sent at least 5 seconds after login # 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 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: if int(time.time()-userToken.loginTime) >= 5 or userToken.irc == True:
# Stop spectating if needed # Stop spectating
# TODO: Call stopSpectatingEvent!!!!!!!!! userToken.stopSpectating()
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))
# Part matches
userToken.partMatch()
# Part all joined channels # Part all joined channels
for i in userToken.joinedChannels: for i in userToken.joinedChannels:
chat.partChannel(token=userToken, channel=i) chat.partChannel(token=userToken, channel=i)
# TODO: Lobby left if joined
# Enqueue our disconnection to everyone else # Enqueue our disconnection to everyone else
glob.tokens.enqueueAll(serverPackets.userLogout(userID)) glob.tokens.enqueueAll(serverPackets.userLogout(userID))

View File

@ -25,7 +25,7 @@ def handle(userToken, packetData):
# Enqueue frames to who's playing # Enqueue frames to who's playing
for i in range(0,16): for i in range(0,16):
if match.slots[i]["userID"] > -1 and match.slots[i]["status"] == slotStatuses.playing: if match.slots[i].userID > -1 and match.slots[i].status == slotStatuses.playing:
token = glob.tokens.getTokenFromUserID(match.slots[i]["userID"]) token = glob.tokens.getTokenFromUserID(match.slots[i].userID)
if token != None: if token != None:
token.enqueue(serverPackets.matchFrames(slotID, packetData)) token.enqueue(serverPackets.matchFrames(slotID, packetData))

View File

@ -1,3 +1,4 @@
from events import matchBeatmapEvent from events import matchBeatmapEvent
def handle(userToken, packetData): def handle(userToken, packetData):
matchBeatmapEvent.handle(userToken, packetData, True) matchBeatmapEvent.handle(userToken, packetData, True)

View File

@ -14,6 +14,10 @@ def handle(userToken, packetData):
return return
match = glob.matches.matches[matchID] match = glob.matches.matches[matchID]
# Host check
if userID != match.hostUserID:
return
# Make sure we aren't locking our slot # Make sure we aren't locking our slot
ourSlot = match.getUserSlotID(userID) ourSlot = match.getUserSlotID(userID)
if packetData["slotID"] == ourSlot: if packetData["slotID"] == ourSlot:

View File

@ -1,3 +1,4 @@
from events import matchBeatmapEvent from events import matchBeatmapEvent
def handle(userToken, packetData): def handle(userToken, packetData):
matchBeatmapEvent.handle(userToken, packetData, False) matchBeatmapEvent.handle(userToken, packetData, False)

View File

@ -3,7 +3,6 @@ from constants import slotStatuses
from constants import serverPackets from constants import serverPackets
def handle(userToken, _): def handle(userToken, _):
# TODO: Host check
# Get match ID and match object # Get match ID and match object
matchID = userToken.matchID matchID = userToken.matchID
@ -19,10 +18,12 @@ def handle(userToken, _):
# The match exists, get object # The match exists, get object
match = glob.matches.matches[matchID] match = glob.matches.matches[matchID]
force = False # TODO: Force thing # Host check
if userToken.userID != match.hostUserID:
return
# Make sure we have enough players # 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 return
# Change inProgress value # Change inProgress value
@ -30,16 +31,16 @@ def handle(userToken, _):
# Set playing to ready players and set load, skip and complete to False # Set playing to ready players and set load, skip and complete to False
for i in range(0,16): for i in range(0,16):
if (match.slots[i]["status"] & slotStatuses.ready) > 0: if (match.slots[i].status & slotStatuses.ready) > 0:
match.slots[i]["status"] = slotStatuses.playing match.slots[i].status = slotStatuses.playing
match.slots[i]["loaded"] = False match.slots[i].loaded = False
match.slots[i]["skip"] = False match.slots[i].skip = False
match.slots[i]["complete"] = False match.slots[i].complete = False
# Send match start packet # Send match start packet
for i in range(0,16): for i in range(0,16):
if (match.slots[i]["status"] & slotStatuses.playing) > 0 and match.slots[i]["userID"] != -1: if (match.slots[i].status & slotStatuses.playing) > 0 and match.slots[i].userID != -1:
token = glob.tokens.getTokenFromUserID(match.slots[i]["userID"]) token = glob.tokens.getTokenFromUserID(match.slots[i].userID)
if token != None: if token != None:
token.enqueue(serverPackets.matchStart(matchID)) token.enqueue(serverPackets.matchStart(matchID))

View File

@ -19,5 +19,9 @@ def handle(userToken, packetData):
# Match exists, get object # Match exists, get object
match = glob.matches.matches[matchID] match = glob.matches.matches[matchID]
# Host check
if userToken.userID != match.hostUserID:
return
# Transfer host # Transfer host
match.transferHost(packetData["slotID"]) match.transferHost(packetData["slotID"])

View File

@ -1,28 +1,2 @@
from objects import glob def handle(userToken, _=None):
userToken.partMatch()
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()

View File

@ -2,8 +2,6 @@ from constants import serverPackets
from helpers import logHelper as log from helpers import logHelper as log
def handle(userToken, packetData): def handle(userToken, packetData):
log.debug("Requested status update")
# Update cache and send new stats # Update cache and send new stats
userToken.updateCachedStats() userToken.updateCachedStats()
userToken.enqueue(serverPackets.userStats(userToken.userID)) userToken.enqueue(serverPackets.userStats(userToken.userID))

View File

@ -1,37 +1,2 @@
from objects import glob def handle(userToken, _=None):
from constants import serverPackets userToken.stopSpectating()
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()

View File

@ -33,7 +33,5 @@ class handler(requestHelper.asyncRequestHandler):
data["status"] = statusCode data["status"] = statusCode
# Send response # Send response
#self.clear()
self.write(json.dumps(data)) self.write(json.dumps(data))
self.set_status(statusCode) self.set_status(statusCode)
#self.finish(json.dumps(data))

View File

@ -226,8 +226,8 @@ class handler(SentryMixin, requestHelper.asyncRequestHandler):
self.set_status(200) self.set_status(200)
self.add_header("cho-token", responseTokenString) self.add_header("cho-token", responseTokenString)
self.add_header("cho-protocol", "19") 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") self.add_header("Content-Type", "text/html; charset=UTF-8")
except: except:
log.error("Unknown error!\n```\n{}\n{}```".format(sys.exc_info(), traceback.format_exc())) log.error("Unknown error!\n```\n{}\n{}```".format(sys.exc_info(), traceback.format_exc()))
@ -259,6 +259,4 @@ class handler(SentryMixin, requestHelper.asyncRequestHandler):
html += " \\ . .. .. . /<br>" html += " \\ . .. .. . /<br>"
html += "^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^<br>" html += "^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^<br>"
html += "</marquee><br><strike>reverse engineering a protocol impossible to reverse engineer since always</strike><br>we are actually reverse engineering bancho successfully. for the third time.<br><br><i>&copy; Ripple team, 2016</i></pre></body></html>" html += "</marquee><br><strike>reverse engineering a protocol impossible to reverse engineer since always</strike><br>we are actually reverse engineering bancho successfully. for the third time.<br><br><i>&copy; Ripple team, 2016</i></pre></body></html>"
self.write(html) self.write(html)
#yield tornado.gen.Task(self.captureMessage, "test")
#self.finish()

View File

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

View File

@ -147,9 +147,6 @@ def partChannel(userID = 0, channel = "", token = None, toIRC = True, kick = Fal
log.warning("User not connected to IRC/Bancho") log.warning("User not connected to IRC/Bancho")
return 442 # idk return 442 # idk
def sendMessage(fro = "", to = "", message = "", token = None, toIRC = True): def sendMessage(fro = "", to = "", message = "", token = None, toIRC = True):
""" """
Send a message to osu!bancho and IRC server Send a message to osu!bancho and IRC server
@ -299,8 +296,13 @@ def sendMessage(fro = "", to = "", message = "", token = None, toIRC = True):
return 401 return 401
""" IRC-Bancho Connect/Disconnect/Join/Part interfaces""" """ IRC-Bancho Connect/Disconnect/Join/Part interfaces"""
def fixUsernameForBancho(username):
return username.replace("_", " ")
def fixUsernameForIRC(username):
return username.replace(" ", "_")
def IRCConnect(username): def IRCConnect(username):
userID = userHelper.getID(username) userID = userHelper.getID(username)
if userID == False: if userID == False:

View File

@ -1,18 +1,7 @@
import os import os
import configparser import configparser
class config: 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
# Check if config.ini exists and load/generate it # Check if config.ini exists and load/generate it
def __init__(self, file): def __init__(self, file):
""" """
@ -20,7 +9,8 @@ class config:
file -- filename file -- filename
""" """
self.config = configparser.ConfigParser()
self.default = True
self.fileName = file self.fileName = file
if os.path.isfile(self.fileName): if os.path.isfile(self.fileName):
# config.ini found, load it # config.ini found, load it
@ -39,7 +29,6 @@ class config:
return -- True if valid, False if not return -- True if valid, False if not
""" """
try: try:
# Try to get all the required keys # Try to get all the required keys
self.config.get("db","host") self.config.get("db","host")
@ -75,11 +64,10 @@ class config:
except: except:
return False return False
# Generate a default config.ini
def generateDefaultConfig(self): 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 # Open config.ini in write mode
f = open(self.fileName, "w") f = open(self.fileName, "w")

View File

@ -1,13 +1,12 @@
"""Some console related functions"""
from constants import bcolors from constants import bcolors
from objects import glob from objects import glob
def printServerStartHeader(asciiArt): def printServerStartHeader(asciiArt):
"""Print server start header with optional ascii art """
Print server start header with optional ascii art
asciiArt -- if True, will print ascii art too"""
asciiArt -- if True, will print ascii art too
"""
if asciiArt == True: if asciiArt == True:
print("{} _ __".format(bcolors.GREEN)) print("{} _ __".format(bcolors.GREEN))
print(" (_) / /") print(" (_) / /")
@ -28,20 +27,17 @@ def printServerStartHeader(asciiArt):
printColored("> Welcome to pep.py osu!bancho server v{}".format(glob.VERSION), bcolors.GREEN) printColored("> Welcome to pep.py osu!bancho server v{}".format(glob.VERSION), bcolors.GREEN)
printColored("> Made by the Ripple team", 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) printColored("> Press CTRL+C to exit\n",bcolors.GREEN)
def printNoNl(string): def printNoNl(string):
""" """
Print string without new line at the end Print string without new line at the end
string -- string to print string -- string to print
""" """
print(string, end="") print(string, end="")
def printColored(string, color): def printColored(string, color):
""" """
Print colored string Print colored string
@ -49,23 +45,22 @@ def printColored(string, color):
string -- string to print string -- string to print
color -- see bcolors.py color -- see bcolors.py
""" """
print("{}{}{}".format(color, string, bcolors.ENDC)) print("{}{}{}".format(color, string, bcolors.ENDC))
def printError(): def printError():
"""Print error text FOR LOADING""" """
Print error text FOR LOADING
"""
printColored("Error", bcolors.RED) printColored("Error", bcolors.RED)
def printDone(): def printDone():
"""Print error text FOR LOADING""" """
Print error text FOR LOADING
"""
printColored("Done", bcolors.GREEN) printColored("Done", bcolors.GREEN)
def printWarning(): def printWarning():
"""Print error text FOR LOADING""" """
Print error text FOR LOADING
"""
printColored("Warning", bcolors.YELLOW) printColored("Warning", bcolors.YELLOW)

View File

@ -253,7 +253,6 @@ countryCodes = {
"AI": 7 "AI": 7
} }
def getCountryID(code): def getCountryID(code):
""" """
Get country ID for osu client Get country ID for osu client

View File

@ -2,13 +2,13 @@ import MySQLdb
import threading import threading
from helpers import logHelper as log 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): def __init__(self, wid, host, username, password, database):
""" """
Create a pettirosso meme (mysql worker) Create a mysql worker
wid -- worker id wid -- worker id
host -- hostname host -- hostname
@ -22,11 +22,10 @@ class mysqlWorker:
self.ready = True self.ready = True
self.lock = threading.Lock() self.lock = threading.Lock()
class db: class db():
""" """
A MySQL db connection with multiple workers A MySQL db connection with multiple workers
""" """
def __init__(self, host, username, password, database, workers): def __init__(self, host, username, password, database, workers):
""" """
Create MySQL workers aka pettirossi meme Create MySQL workers aka pettirossi meme
@ -37,9 +36,6 @@ class db:
database -- MySQL database name database -- MySQL database name
workers -- Number of workers to spawn workers -- Number of workers to spawn
""" """
#self.lock = threading.Lock()
#self.connection = MySQLdb.connect(host, username, password, database)
self.workers = [] self.workers = []
self.lastWorker = 0 self.lastWorker = 0
self.workersNumber = workers self.workersNumber = workers
@ -57,7 +53,6 @@ class db:
self.lastWorker = 0 self.lastWorker = 0
else: else:
self.lastWorker += 1 self.lastWorker += 1
#print("Using worker {}".format(self.lastWorker))
return self.workers[self.lastWorker] return self.workers[self.lastWorker]
def execute(self, query, params = ()): def execute(self, query, params = ()):

View File

@ -1,9 +1,6 @@
import requests import requests
from objects import glob from objects import glob
from helpers import generalFunctions
from urllib.parse import urlencode from urllib.parse import urlencode
from helpers import consoleHelper
from constants import bcolors
def sendDiscordMessage(channel, message, alertDev = False, prefix = "**pep.py**"): def sendDiscordMessage(channel, message, alertDev = False, prefix = "**pep.py**"):
""" """
@ -24,7 +21,6 @@ def sendDiscordMessage(channel, message, alertDev = False, prefix = "**pep.py**"
except: except:
continue continue
def sendConfidential(message, alertDev = False): def sendConfidential(message, alertDev = False):
""" """
Send a message to #bunker Send a message to #bunker
@ -33,7 +29,6 @@ def sendConfidential(message, alertDev = False):
""" """
sendDiscordMessage("bunk", message, alertDev) sendDiscordMessage("bunk", message, alertDev)
def sendStaff(message): def sendStaff(message):
""" """
Send a message to #staff Send a message to #staff
@ -42,7 +37,6 @@ def sendStaff(message):
""" """
sendDiscordMessage("staff", message) sendDiscordMessage("staff", message)
def sendGeneral(message): def sendGeneral(message):
""" """
Send a message to #general Send a message to #general
@ -51,7 +45,6 @@ def sendGeneral(message):
""" """
sendDiscordMessage("general", message) sendDiscordMessage("general", message)
def sendChatlog(message): def sendChatlog(message):
""" """
Send a message to #chatlog Send a message to #chatlog

View File

@ -1,6 +1,17 @@
"""Some functions that don't fit in any other file"""
from constants import mods from constants import mods
from time import gmtime, strftime 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): def stringToBool(s):
""" """
@ -9,10 +20,8 @@ def stringToBool(s):
s -- string/int value s -- string/int value
return -- True/False return -- True/False
""" """
return (s == "True" or s== "true" or s == "1" or s == 1) return (s == "True" or s== "true" or s == "1" or s == 1)
def hexString(s): def hexString(s):
""" """
Output s' bytes in HEX Output s' bytes in HEX
@ -20,7 +29,6 @@ def hexString(s):
s -- string s -- string
return -- string with hex value return -- string with hex value
""" """
return ":".join("{:02x}".format(ord(str(c))) for c in s) return ":".join("{:02x}".format(ord(str(c))) for c in s)
def readableMods(__mods): def readableMods(__mods):

View File

@ -11,7 +11,6 @@ def getCountry(ip):
ip -- IP Address ip -- IP Address
return -- Country code (2 letters) return -- Country code (2 letters)
""" """
try: try:
# Try to get country from Pikolo Aul's Go-Sanic ip API # 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"] 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") log.error("Error in get country")
return "XX" return "XX"
def getLocation(ip): def getLocation(ip):
""" """
Get latitude and longitude from IP address Get latitude and longitude from IP address
@ -28,7 +26,6 @@ def getLocation(ip):
ip -- IP address ip -- IP address
return -- [latitude, longitude] return -- [latitude, longitude]
""" """
try: try:
# Try to get position from Pikolo Aul's Go-Sanic ip API # 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(",") result = json.loads(urllib.request.urlopen("{}/{}".format(glob.conf.config["localize"]["ipapiurl"], ip), timeout=3).read().decode())["loc"].split(",")

View File

@ -8,7 +8,6 @@ def uleb128Encode(num):
num -- int to encode num -- int to encode
return -- bytearray with encoded number return -- bytearray with encoded number
""" """
arr = bytearray() arr = bytearray()
length = 0 length = 0
@ -24,7 +23,6 @@ def uleb128Encode(num):
return arr return arr
def uleb128Decode(num): def uleb128Decode(num):
""" """
Decode uleb128 -> int Decode uleb128 -> int
@ -32,9 +30,7 @@ def uleb128Decode(num):
num -- encoded uleb128 num -- encoded uleb128
return -- list. [total, length] return -- list. [total, length]
""" """
shift = 0 shift = 0
arr = [0,0] #total, length arr = [0,0] #total, length
while True: while True:
@ -47,42 +43,40 @@ def uleb128Decode(num):
return arr return arr
def unpackData(data, dataType):
def unpackData(__data, __dataType):
""" """
Unpacks data according to dataType Unpacks data according to dataType
__data -- bytes array to unpack data -- bytes array to unpack
__dataType -- data type. See dataTypes.py dataType -- data type. See dataTypes.py
return -- unpacked bytes return -- unpacked bytes
""" """
# Get right pack Type # Get right pack Type
if __dataType == dataTypes.uInt16: if dataType == dataTypes.uInt16:
unpackType = "<H" unpackType = "<H"
elif __dataType == dataTypes.sInt16: elif dataType == dataTypes.sInt16:
unpackType = "<h" unpackType = "<h"
elif __dataType == dataTypes.uInt32: elif dataType == dataTypes.uInt32:
unpackType = "<L" unpackType = "<L"
elif __dataType == dataTypes.sInt32: elif dataType == dataTypes.sInt32:
unpackType = "<l" unpackType = "<l"
elif __dataType == dataTypes.uInt64: elif dataType == dataTypes.uInt64:
unpackType = "<Q" unpackType = "<Q"
elif __dataType == dataTypes.sInt64: elif dataType == dataTypes.sInt64:
unpackType = "<q" unpackType = "<q"
elif __dataType == dataTypes.string: elif dataType == dataTypes.string:
unpackType = "<s" unpackType = "<s"
elif __dataType == dataTypes.ffloat: elif dataType == dataTypes.ffloat:
unpackType = "<f" unpackType = "<f"
else: else:
unpackType = "<B" unpackType = "<B"
# Unpack # Unpack
return struct.unpack(unpackType, bytes(__data))[0] return struct.unpack(unpackType, bytes(data))[0]
def packData(__data, dataType):
def packData(__data, __dataType):
""" """
Packs data according to dataType Packs data according to dataType
@ -96,11 +90,11 @@ def packData(__data, __dataType):
pack = True # if True, use pack. False only with strings pack = True # if True, use pack. False only with strings
# Get right pack Type # Get right pack Type
if __dataType == dataTypes.bbytes: if dataType == dataTypes.bbytes:
# Bytes, do not use pack, do manually # Bytes, do not use pack, do manually
pack = False pack = False
data = __data data = __data
elif __dataType == dataTypes.intList: elif dataType == dataTypes.intList:
# Pack manually # Pack manually
pack = False pack = False
# Add length # Add length
@ -108,7 +102,7 @@ def packData(__data, __dataType):
# Add all elements # Add all elements
for i in __data: for i in __data:
data += packData(i, dataTypes.sInt32) data += packData(i, dataTypes.sInt32)
elif __dataType == dataTypes.string: elif dataType == dataTypes.string:
# String, do not use pack, do manually # String, do not use pack, do manually
pack = False pack = False
if len(__data) == 0: if len(__data) == 0:
@ -119,21 +113,21 @@ def packData(__data, __dataType):
data += b"\x0B" data += b"\x0B"
data += uleb128Encode(len(__data)) data += uleb128Encode(len(__data))
data += str.encode(__data, "latin_1", "ignore") data += str.encode(__data, "latin_1", "ignore")
elif __dataType == dataTypes.uInt16: elif dataType == dataTypes.uInt16:
packType = "<H" packType = "<H"
elif __dataType == dataTypes.sInt16: elif dataType == dataTypes.sInt16:
packType = "<h" packType = "<h"
elif __dataType == dataTypes.uInt32: elif dataType == dataTypes.uInt32:
packType = "<L" packType = "<L"
elif __dataType == dataTypes.sInt32: elif dataType == dataTypes.sInt32:
packType = "<l" packType = "<l"
elif __dataType == dataTypes.uInt64: elif dataType == dataTypes.uInt64:
packType = "<Q" packType = "<Q"
elif __dataType == dataTypes.sInt64: elif dataType == dataTypes.sInt64:
packType = "<q" packType = "<q"
elif __dataType == dataTypes.string: elif dataType == dataTypes.string:
packType = "<s" packType = "<s"
elif __dataType == dataTypes.ffloat: elif dataType == dataTypes.ffloat:
packType = "<f" packType = "<f"
else: else:
packType = "<B" packType = "<B"
@ -144,7 +138,6 @@ def packData(__data, __dataType):
return data return data
# TODO: Wat dangerous
def buildPacket(__packet, __packetData = []): def buildPacket(__packet, __packetData = []):
""" """
Build a packet Build a packet
@ -154,7 +147,6 @@ def buildPacket(__packet, __packetData = []):
return -- packet bytes return -- packet bytes
""" """
# Set some variables # Set some variables
packetData = bytes() packetData = bytes()
packetLength = 0 packetLength = 0
@ -174,7 +166,6 @@ def buildPacket(__packet, __packetData = []):
packetBytes += packetData # packet data packetBytes += packetData # packet data
return packetBytes return packetBytes
def readPacketID(stream): def readPacketID(stream):
""" """
Read packetID from stream (0-1 bytes) Read packetID from stream (0-1 bytes)
@ -182,10 +173,8 @@ def readPacketID(stream):
stream -- data stream stream -- data stream
return -- packet ID (int) return -- packet ID (int)
""" """
return unpackData(stream[0:2], dataTypes.uInt16) return unpackData(stream[0:2], dataTypes.uInt16)
def readPacketLength(stream): def readPacketLength(stream):
""" """
Read packet length from stream (3-4-5-6 bytes) Read packet length from stream (3-4-5-6 bytes)
@ -193,7 +182,6 @@ def readPacketLength(stream):
stream -- data stream stream -- data stream
return -- packet length (int) return -- packet length (int)
""" """
return unpackData(stream[3:7], dataTypes.uInt32) return unpackData(stream[3:7], dataTypes.uInt32)
@ -208,7 +196,6 @@ def readPacketData(stream, structure = [], hasFirstBytes = True):
Optional. Default: True Optional. Default: True
return -- dictionary. key: name, value: read data return -- dictionary. key: name, value: read data
""" """
# Read packet ID (first 2 bytes) # Read packet ID (first 2 bytes)
data = {} data = {}

View File

@ -11,7 +11,6 @@ def checkOldPassword(password, salt, rightPassword):
rightPassword -- right password rightPassword -- right password
return -- bool return -- bool
""" """
return (rightPassword == cryptHelper.crypt(password, "$2y$"+str(base64.b64decode(salt)))) return (rightPassword == cryptHelper.crypt(password, "$2y$"+str(base64.b64decode(salt))))
def checkNewPassword(password, dbPassword): def checkNewPassword(password, dbPassword):

View File

@ -3,8 +3,6 @@ import tornado.web
import tornado.gen import tornado.gen
from tornado.ioloop import IOLoop from tornado.ioloop import IOLoop
from objects import glob from objects import glob
from raven.contrib.tornado import SentryMixin
from raven.contrib.tornado import AsyncSentryClient
import gevent import gevent
class asyncRequestHandler(tornado.web.RequestHandler): class asyncRequestHandler(tornado.web.RequestHandler):
@ -50,7 +48,6 @@ class asyncRequestHandler(tornado.web.RequestHandler):
return realIP return realIP
return self.request.remote_ip return self.request.remote_ip
def runBackground(data, callback): def runBackground(data, callback):
""" """
Run a function in the background. Run a function in the background.
@ -59,7 +56,6 @@ def runBackground(data, callback):
func, args, kwargs = data func, args, kwargs = data
def _callback(result): def _callback(result):
IOLoop.instance().add_callback(lambda: callback(result)) IOLoop.instance().add_callback(lambda: callback(result))
#glob.pool.apply_async(func, args, kwargs, _callback)
g = gevent.Greenlet(func, *args, **kwargs) g = gevent.Greenlet(func, *args, **kwargs)
g.link(_callback) g.link(_callback)
g.start() g.start()

View File

@ -15,10 +15,8 @@ def runningUnderUnix():
return --- True if running under UNIX, otherwise False return --- True if running under UNIX, otherwise False
""" """
return True if os.name == "posix" else False return True if os.name == "posix" else False
def scheduleShutdown(sendRestartTime, restart, message = "", delay=20): def scheduleShutdown(sendRestartTime, restart, message = "", delay=20):
""" """
Schedule a server shutdown/restart Schedule a server shutdown/restart
@ -27,7 +25,6 @@ def scheduleShutdown(sendRestartTime, restart, message = "", delay=20):
restart -- if True, server will restart. if False, server will shudown restart -- if True, server will restart. if False, server will shudown
message -- if set, send that message to every client to warn about the shutdown/restart message -- if set, send that message to every client to warn about the shutdown/restart
""" """
# Console output # Console output
log.info("Pep.py will {} in {} seconds!".format("restart" if restart else "shutdown", sendRestartTime+delay)) log.info("Pep.py will {} in {} seconds!".format("restart" if restart else "shutdown", sendRestartTime+delay))
log.info("Sending server restart packets in {} seconds...".format(sendRestartTime)) log.info("Sending server restart packets in {} seconds...".format(sendRestartTime))
@ -49,27 +46,23 @@ def scheduleShutdown(sendRestartTime, restart, message = "", delay=20):
# Schedule actual server shutdown/restart some seconds after server restart packet, so everyone gets it # Schedule actual server shutdown/restart some seconds after server restart packet, so everyone gets it
threading.Timer(sendRestartTime+delay, action).start() threading.Timer(sendRestartTime+delay, action).start()
def restartServer(): def restartServer():
"""Restart pep.py script""" """Restart pep.py script"""
log.info("Restarting pep.py...") log.info("Restarting pep.py...")
os.execv(sys.executable, [sys.executable] + sys.argv) os.execv(sys.executable, [sys.executable] + sys.argv)
def shutdownServer(): def shutdownServer():
"""Shutdown pep.py""" """Shutdown pep.py"""
log.info("Shutting down pep.py...") log.info("Shutting down pep.py...")
sig = signal.SIGKILL if runningUnderUnix() else signal.CTRL_C_EVENT sig = signal.SIGKILL if runningUnderUnix() else signal.CTRL_C_EVENT
os.kill(os.getpid(), sig) os.kill(os.getpid(), sig)
def getSystemInfo(): def getSystemInfo():
""" """
Get a dictionary with some system/server info Get a dictionary with some system/server info
return -- ["unix", "connectedUsers", "webServer", "cpuUsage", "totalMemory", "usedMemory", "loadAverage"] return -- ["unix", "connectedUsers", "webServer", "cpuUsage", "totalMemory", "usedMemory", "loadAverage"]
""" """
data = {} data = {}
# Get if server is running under unix/nt # Get if server is running under unix/nt

View File

@ -14,9 +14,8 @@ def getID(username):
username -- user username -- user
return -- user id or False return -- user id or False
""" """
# Get user ID from db # Get user ID from db
userID = glob.db.fetch("SELECT id FROM users WHERE username = %s", [username]) userID = glob.db.fetch("SELECT id FROM users WHERE username = %s LIMIT 1", [username])
# Make sure the query returned something # Make sure the query returned something
if userID == None: if userID == None:
@ -25,7 +24,6 @@ def getID(username):
# Return user ID # Return user ID
return userID["id"] return userID["id"]
def checkLogin(userID, password): def checkLogin(userID, password):
""" """
Check userID's login with specified password Check userID's login with specified password
@ -35,9 +33,8 @@ def checkLogin(userID, password):
password -- plain md5 password password -- plain md5 password
return -- True or False return -- True or False
""" """
# Get password data # Get password data
passwordData = glob.db.fetch("SELECT password_md5, salt, password_version FROM users WHERE id = %s", [userID]) passwordData = glob.db.fetch("SELECT password_md5, salt, password_version FROM users WHERE id = %s LIMIT 1", [userID])
# Make sure the query returned something # Make sure the query returned something
if passwordData == None: if passwordData == None:
@ -51,8 +48,7 @@ def checkLogin(userID, password):
ok = passwordHelper.checkOldPassword(password, passwordData["salt"], passwordData["password_md5"]) ok = passwordHelper.checkOldPassword(password, passwordData["salt"], passwordData["password_md5"])
if not ok: return False if not ok: return False
newpass = passwordHelper.genBcrypt(password) newpass = passwordHelper.genBcrypt(password)
glob.db.execute("UPDATE users SET password_md5=%s, salt='', password_version='2' WHERE id = %s", [newpass, userID]) glob.db.execute("UPDATE users SET password_md5=%s, salt='', password_version='2' WHERE id = %s LIMIT 1", [newpass, userID])
def exists(userID): def exists(userID):
""" """
@ -61,8 +57,7 @@ def exists(userID):
userID -- user ID to check userID -- user ID to check
return -- bool return -- bool
""" """
result = glob.db.fetch("SELECT id FROM users WHERE id = %s LIMIT 1", [userID])
result = glob.db.fetch("SELECT id FROM users WHERE id = %s", [userID])
if result == None: if result == None:
return False return False
else: else:
@ -76,8 +71,7 @@ def getSilenceEnd(userID):
userID -- userID userID -- userID
return -- UNIX time return -- UNIX time
""" """
return glob.db.fetch("SELECT silence_end FROM users WHERE id = %s LIMIT 1", [userID])["silence_end"]
return glob.db.fetch("SELECT silence_end FROM users WHERE id = %s", [userID])["silence_end"]
def silence(userID, seconds, silenceReason, author = 999): def silence(userID, seconds, silenceReason, author = 999):
@ -91,7 +85,7 @@ def silence(userID, seconds, silenceReason, author = 999):
""" """
# db qurey # db qurey
silenceEndTime = int(time.time())+seconds silenceEndTime = int(time.time())+seconds
glob.db.execute("UPDATE users SET silence_end = %s, silence_reason = %s WHERE id = %s", [silenceEndTime, silenceReason, userID]) glob.db.execute("UPDATE users SET silence_end = %s, silence_reason = %s WHERE id = %s LIMIT 1", [silenceEndTime, silenceReason, userID])
# Loh # Loh
targetUsername = getUsername(userID) targetUsername = getUsername(userID)
@ -109,9 +103,8 @@ def getRankedScore(userID, gameMode):
gameMode -- int value, see gameModes gameMode -- int value, see gameModes
return -- ranked score return -- ranked score
""" """
modeForDB = gameModes.getGameModeForDB(gameMode) modeForDB = gameModes.getGameModeForDB(gameMode)
return glob.db.fetch("SELECT ranked_score_"+modeForDB+" FROM users_stats WHERE id = %s", [userID])["ranked_score_"+modeForDB] return glob.db.fetch("SELECT ranked_score_"+modeForDB+" FROM users_stats WHERE id = %s LIMIT 1", [userID])["ranked_score_"+modeForDB]
def getTotalScore(userID, gameMode): def getTotalScore(userID, gameMode):
@ -122,10 +115,8 @@ def getTotalScore(userID, gameMode):
gameMode -- int value, see gameModes gameMode -- int value, see gameModes
return -- total score return -- total score
""" """
modeForDB = gameModes.getGameModeForDB(gameMode) modeForDB = gameModes.getGameModeForDB(gameMode)
return glob.db.fetch("SELECT total_score_"+modeForDB+" FROM users_stats WHERE id = %s", [userID])["total_score_"+modeForDB] return glob.db.fetch("SELECT total_score_"+modeForDB+" FROM users_stats WHERE id = %s LIMIT 1", [userID])["total_score_"+modeForDB]
def getAccuracy(userID, gameMode): def getAccuracy(userID, gameMode):
""" """
@ -135,10 +126,8 @@ def getAccuracy(userID, gameMode):
gameMode -- int value, see gameModes gameMode -- int value, see gameModes
return -- accuracy return -- accuracy
""" """
modeForDB = gameModes.getGameModeForDB(gameMode) modeForDB = gameModes.getGameModeForDB(gameMode)
return glob.db.fetch("SELECT avg_accuracy_"+modeForDB+" FROM users_stats WHERE id = %s", [userID])["avg_accuracy_"+modeForDB] return glob.db.fetch("SELECT avg_accuracy_"+modeForDB+" FROM users_stats WHERE id = %s LIMIT 1", [userID])["avg_accuracy_"+modeForDB]
def getGameRank(userID, gameMode): def getGameRank(userID, gameMode):
""" """
@ -150,13 +139,12 @@ def getGameRank(userID, gameMode):
""" """
modeForDB = gameModes.getGameModeForDB(gameMode) modeForDB = gameModes.getGameModeForDB(gameMode)
result = glob.db.fetch("SELECT position FROM leaderboard_"+modeForDB+" WHERE user = %s", [userID]) result = glob.db.fetch("SELECT position FROM leaderboard_"+modeForDB+" WHERE user = %s LIMIT 1", [userID])
if result == None: if result == None:
return 0 return 0
else: else:
return result["position"] return result["position"]
def getPlaycount(userID, gameMode): def getPlaycount(userID, gameMode):
""" """
Get userID's playcount relative to gameMode Get userID's playcount relative to gameMode
@ -167,8 +155,7 @@ def getPlaycount(userID, gameMode):
""" """
modeForDB = gameModes.getGameModeForDB(gameMode) modeForDB = gameModes.getGameModeForDB(gameMode)
return glob.db.fetch("SELECT playcount_"+modeForDB+" FROM users_stats WHERE id = %s", [userID])["playcount_"+modeForDB] return glob.db.fetch("SELECT playcount_"+modeForDB+" FROM users_stats WHERE id = %s LIMIT 1", [userID])["playcount_"+modeForDB]
def getUsername(userID): def getUsername(userID):
""" """
@ -178,8 +165,7 @@ def getUsername(userID):
return -- username return -- username
""" """
return glob.db.fetch("SELECT username FROM users WHERE id = %s", [userID])["username"] return glob.db.fetch("SELECT username FROM users WHERE id = %s LIMIT 1", [userID])["username"]
def getFriendList(userID): def getFriendList(userID):
""" """
@ -202,7 +188,6 @@ def getFriendList(userID):
# Return friend IDs # Return friend IDs
return friends return friends
def addFriend(userID, friendID): def addFriend(userID, friendID):
""" """
Add friendID to userID's friend list Add friendID to userID's friend list
@ -216,7 +201,7 @@ def addFriend(userID, friendID):
return return
# check user isn't already a friend of ours # check user isn't already a friend of ours
if glob.db.fetch("SELECT id FROM users_relationships WHERE user1 = %s AND user2 = %s", [userID, friendID]) != None: if glob.db.fetch("SELECT id FROM users_relationships WHERE user1 = %s AND user2 = %s LIMIT 1", [userID, friendID]) != None:
return return
# Set new value # Set new value
@ -230,7 +215,6 @@ def removeFriend(userID, friendID):
userID -- user userID -- user
friendID -- old friend friendID -- old friend
""" """
# Delete user relationship. We don't need to check if the relationship was there, because who gives a shit, # Delete user relationship. We don't need to check if the relationship was there, because who gives a shit,
# if they were not friends and they don't want to be anymore, be it. ¯\_(ツ)_/¯ # if they were not friends and they don't want to be anymore, be it. ¯\_(ツ)_/¯
glob.db.execute("DELETE FROM users_relationships WHERE user1 = %s AND user2 = %s", [userID, friendID]) glob.db.execute("DELETE FROM users_relationships WHERE user1 = %s AND user2 = %s", [userID, friendID])
@ -245,8 +229,7 @@ def getCountry(userID):
userID -- user userID -- user
return -- country code (two letters) return -- country code (two letters)
""" """
return glob.db.fetch("SELECT country FROM users_stats WHERE id = %s LIMIT 1", [userID])["country"]
return glob.db.fetch("SELECT country FROM users_stats WHERE id = %s", [userID])["country"]
def getPP(userID, gameMode): def getPP(userID, gameMode):
""" """
@ -257,7 +240,7 @@ def getPP(userID, gameMode):
""" """
modeForDB = gameModes.getGameModeForDB(gameMode) modeForDB = gameModes.getGameModeForDB(gameMode)
return glob.db.fetch("SELECT pp_{} FROM users_stats WHERE id = %s".format(modeForDB), [userID])["pp_{}".format(modeForDB)] return glob.db.fetch("SELECT pp_{} FROM users_stats WHERE id = %s LIMIT 1".format(modeForDB), [userID])["pp_{}".format(modeForDB)]
def setCountry(userID, country): def setCountry(userID, country):
""" """
@ -266,7 +249,7 @@ def setCountry(userID, country):
userID -- userID userID -- userID
country -- country letters country -- country letters
""" """
glob.db.execute("UPDATE users_stats SET country = %s WHERE id = %s", [country, userID]) glob.db.execute("UPDATE users_stats SET country = %s WHERE id = %s LIMIT 1", [country, userID])
def getShowCountry(userID): def getShowCountry(userID):
""" """
@ -275,7 +258,7 @@ def getShowCountry(userID):
userID -- userID userID -- userID
return -- True if country is shown, False if it's hidden return -- True if country is shown, False if it's hidden
""" """
country = glob.db.fetch("SELECT show_country FROM users_stats WHERE id = %s", [userID]) country = glob.db.fetch("SELECT show_country FROM users_stats WHERE id = %s LIMIT 1", [userID])
if country == None: if country == None:
return False return False
return generalFunctions.stringToBool(country) return generalFunctions.stringToBool(country)
@ -292,25 +275,42 @@ def saveBanchoSession(userID, ip):
""" """
Save userid and ip of this token in bancho_sessions table. Save userid and ip of this token in bancho_sessions table.
Used to cache logins on LETS requests Used to cache logins on LETS requests
userID --
ip -- user's ip address
""" """
log.debug("Saving bancho session ({}::{}) in db".format(userID, ip))
glob.db.execute("INSERT INTO bancho_sessions (id, userid, ip) VALUES (NULL, %s, %s)", [userID, ip]) glob.db.execute("INSERT INTO bancho_sessions (id, userid, ip) VALUES (NULL, %s, %s)", [userID, ip])
def deleteBanchoSessions(userID, ip): def deleteBanchoSessions(userID, ip):
"""Delete this bancho session from DB""" """
log.debug("Deleting bancho session ({}::{}) from db".format(userID, ip)) Delete this bancho session from DB
userID --
ip -- user's IP address
"""
try: try:
glob.db.execute("DELETE FROM bancho_sessions WHERE userid = %s AND ip = %s", [userID, ip]) glob.db.execute("DELETE FROM bancho_sessions WHERE userid = %s AND ip = %s", [userID, ip])
except: except:
log.warning("Token for user: {} ip: {} doesn't exist".format(userID, ip)) log.warning("Token for user: {} ip: {} doesn't exist".format(userID, ip))
def is2FAEnabled(userID): def is2FAEnabled(userID):
"""Returns True if 2FA is enable for this account""" """
Check if 2FA is enabled on an account
userID --
return -- True if 2FA is enabled, False if 2FA is disabled
"""
result = glob.db.fetch("SELECT id FROM 2fa_telegram WHERE userid = %s LIMIT 1", [userID]) result = glob.db.fetch("SELECT id FROM 2fa_telegram WHERE userid = %s LIMIT 1", [userID])
return True if result is not None else False return True if result is not None else False
def check2FA(userID, ip): def check2FA(userID, ip):
"""Returns True if this IP is untrusted""" """
Check if an ip is trusted
userID --
ip -- user's IP address
return -- True if the IP is untrusted, False if it's trusted
"""
if is2FAEnabled(userID) == False: if is2FAEnabled(userID) == False:
return False return False
@ -353,7 +353,7 @@ def isAllowed(userID):
userID -- id of the user userID -- id of the user
return -- True if not banned or restricted, otherwise false. return -- True if not banned or restricted, otherwise false.
""" """
result = glob.db.fetch("SELECT privileges FROM users WHERE id = %s", [userID]) result = glob.db.fetch("SELECT privileges FROM users WHERE id = %s LIMIT 1", [userID])
if result != None: if result != None:
return (result["privileges"] & privileges.USER_NORMAL) and (result["privileges"] & privileges.USER_PUBLIC) return (result["privileges"] & privileges.USER_NORMAL) and (result["privileges"] & privileges.USER_PUBLIC)
else: else:
@ -366,7 +366,7 @@ def isRestricted(userID):
userID -- id of the user userID -- id of the user
return -- True if not restricted, otherwise false. return -- True if not restricted, otherwise false.
""" """
result = glob.db.fetch("SELECT privileges FROM users WHERE id = %s", [userID]) result = glob.db.fetch("SELECT privileges FROM users WHERE id = %s LIMIT 1", [userID])
if result != None: if result != None:
return (result["privileges"] & privileges.USER_NORMAL) and not (result["privileges"] & privileges.USER_PUBLIC) return (result["privileges"] & privileges.USER_NORMAL) and not (result["privileges"] & privileges.USER_PUBLIC)
else: else:
@ -379,7 +379,7 @@ def isBanned(userID):
userID -- id of the user userID -- id of the user
return -- True if not banned, otherwise false. return -- True if not banned, otherwise false.
""" """
result = glob.db.fetch("SELECT privileges FROM users WHERE id = %s", [userID]) result = glob.db.fetch("SELECT privileges FROM users WHERE id = %s LIMIT 1", [userID])
if result != None: if result != None:
return not (result["privileges"] & 3 > 0) return not (result["privileges"] & 3 > 0)
else: else:
@ -392,7 +392,7 @@ def ban(userID):
userID -- id of user userID -- id of user
""" """
banDateTime = int(time.time()) banDateTime = int(time.time())
glob.db.execute("UPDATE users SET privileges = privileges & %s, ban_datetime = %s WHERE id = %s", [ ~(privileges.USER_NORMAL | privileges.USER_PUBLIC | privileges.USER_PENDING_VERIFICATION) , banDateTime, userID]) glob.db.execute("UPDATE users SET privileges = privileges & %s, ban_datetime = %s WHERE id = %s LIMIT 1", [ ~(privileges.USER_NORMAL | privileges.USER_PUBLIC | privileges.USER_PENDING_VERIFICATION) , banDateTime, userID])
def unban(userID): def unban(userID):
""" """
@ -400,7 +400,7 @@ def unban(userID):
userID -- id of user userID -- id of user
""" """
glob.db.execute("UPDATE users SET privileges = privileges | %s, ban_datetime = 0 WHERE id = %s", [ (privileges.USER_NORMAL | privileges.USER_PUBLIC) , userID]) glob.db.execute("UPDATE users SET privileges = privileges | %s, ban_datetime = 0 WHERE id = %s LIMIT 1", [ (privileges.USER_NORMAL | privileges.USER_PUBLIC) , userID])
def restrict(userID): def restrict(userID):
""" """
@ -409,7 +409,7 @@ def restrict(userID):
userID -- id of user userID -- id of user
""" """
banDateTime = int(time.time()) banDateTime = int(time.time())
glob.db.execute("UPDATE users SET privileges = privileges & %s, ban_datetime = %s WHERE id = %s", [~privileges.USER_PUBLIC, banDateTime, userID]) glob.db.execute("UPDATE users SET privileges = privileges & %s, ban_datetime = %s WHERE id = %s LIMIT 1", [~privileges.USER_PUBLIC, banDateTime, userID])
def unrestrict(userID): def unrestrict(userID):
""" """
@ -427,7 +427,7 @@ def getPrivileges(userID):
userID -- id of user userID -- id of user
return -- privileges number return -- privileges number
""" """
result = glob.db.fetch("SELECT privileges FROM users WHERE id = %s", [userID]) result = glob.db.fetch("SELECT privileges FROM users WHERE id = %s LIMIT 1", [userID])
if result != None: if result != None:
return result["privileges"] return result["privileges"]
else: else:
@ -440,10 +440,10 @@ def setPrivileges(userID, priv):
userID -- id of user userID -- id of user
priv -- privileges number priv -- privileges number
""" """
glob.db.execute("UPDATE users SET privileges = %s WHERE id = %s", [priv, userID]) glob.db.execute("UPDATE users SET privileges = %s WHERE id = %s LIMIT 1", [priv, userID])
def isInPrivilegeGroup(userID, groupName): def isInPrivilegeGroup(userID, groupName):
groupPrivileges = glob.db.fetch("SELECT privileges FROM privileges_groups WHERE name = %s", [groupName]) groupPrivileges = glob.db.fetch("SELECT privileges FROM privileges_groups WHERE name = %s LIMIT 1", [groupName])
if groupPrivileges == None: if groupPrivileges == None:
return False return False
groupPrivileges = groupPrivileges["privileges"] groupPrivileges = groupPrivileges["privileges"]
@ -465,7 +465,7 @@ def appendNotes(userID, notes, addNl = True):
""" """
if addNl == True: if addNl == True:
notes = "\n"+notes notes = "\n"+notes
glob.db.execute("UPDATE users SET notes=CONCAT(COALESCE(notes, ''),%s) WHERE id = %s", [notes, userID]) glob.db.execute("UPDATE users SET notes=CONCAT(COALESCE(notes, ''),%s) WHERE id = %s LIMIT 1", [notes, userID])
def logHardware(userID, hashes, activation = False): def logHardware(userID, hashes, activation = False):

View File

@ -19,7 +19,7 @@ from objects import glob
from helpers import chatHelper as chat from helpers import chatHelper as chat
import raven import raven
class Client: class Client():
""" """
IRC Client object IRC Client object
""" """
@ -43,6 +43,7 @@ class Client:
self.socket = sock self.socket = sock
(self.ip, self.port) = sock.getpeername() (self.ip, self.port) = sock.getpeername()
self.username = "" self.username = ""
self.banchoUsername = ""
self.supposedUsername = "" self.supposedUsername = ""
self.joinedChannels = [] self.joinedChannels = []
@ -275,12 +276,12 @@ class Client:
return return
# Make sure the IRC token was correct: # Make sure the IRC token was correct:
if nick.lower() != self.supposedUsername.lower(): if nick.lower() != chat.fixUsernameForIRC(self.supposedUsername.lower()):
self.reply("464 :Password incorrect") self.reply("464 :Password incorrect")
return return
# Make sure we are not connected to Bancho # Make sure we are not connected to Bancho
token = glob.tokens.getTokenFromUsername(nick) token = glob.tokens.getTokenFromUsername(chat.fixUsernameForBancho(nick))
if token != None: if token != None:
self.reply("433 * {} :Nickname is already in use".format(nick)) self.reply("433 * {} :Nickname is already in use".format(nick))
return return
@ -293,6 +294,7 @@ class Client:
# Everything seems fine, set username (nickname) # Everything seems fine, set username (nickname)
self.username = nick self.username = nick
self.banchoUsername = chat.fixUsernameForBancho(self.username)
elif command == "USER": elif command == "USER":
# Ignore USER command, we use nickname only # Ignore USER command, we use nickname only
return return
@ -307,7 +309,7 @@ class Client:
# If we now have a valid username, connect to bancho and send IRC welcome stuff # If we now have a valid username, connect to bancho and send IRC welcome stuff
if self.username != "": if self.username != "":
# Bancho connection # Bancho connection
chat.IRCConnect(self.username) chat.IRCConnect(self.banchoUsername)
# IRC reply # IRC reply
self.replyCode(1, "Welcome to the Internet Relay Network") self.replyCode(1, "Welcome to the Internet Relay Network")
@ -329,7 +331,7 @@ class Client:
return return
# Get bancho token object # Get bancho token object
token = glob.tokens.getTokenFromUsername(self.username) token = glob.tokens.getTokenFromUsername(self.banchoUsername)
if token == None: if token == None:
return return
@ -354,7 +356,7 @@ class Client:
continue continue
# Attempt to join the channel # Attempt to join the channel
response = chat.IRCJoinChannel(self.username, channel) response = chat.IRCJoinChannel(self.banchoUsername, channel)
if response == 0: if response == 0:
# Joined successfully # Joined successfully
self.joinedChannels.append(channel) self.joinedChannels.append(channel)
@ -376,7 +378,7 @@ class Client:
token = glob.tokens.getTokenFromUserID(user) token = glob.tokens.getTokenFromUserID(user)
if token == None: if token == None:
continue continue
usernames.append(token.username) usernames.append(chat.fixUsernameForIRC(token.username))
usernames = " ".join(usernames) usernames = " ".join(usernames)
# Send IRC users lis # Send IRC users lis
@ -394,7 +396,7 @@ class Client:
return return
# Get bancho token object # Get bancho token object
token = glob.tokens.getTokenFromUsername(self.username) token = glob.tokens.getTokenFromUsername(self.banchoUsername)
if token == None: if token == None:
return return
@ -409,7 +411,7 @@ class Client:
continue continue
# Attempt to part the channel # Attempt to part the channel
response = chat.IRCPartChannel(self.username, channel) response = chat.IRCPartChannel(self.banchoUsername, channel)
if response == 0: if response == 0:
# No errors, remove channel from joinedChannels # No errors, remove channel from joinedChannels
self.joinedChannels.remove(channel) self.joinedChannels.remove(channel)
@ -433,7 +435,7 @@ class Client:
message = arguments[1] message = arguments[1]
# Send the message to bancho and reply # Send the message to bancho and reply
response = chat.sendMessage(self.username, recipient, message, toIRC=False) response = chat.sendMessage(self.banchoUsername, recipient, message, toIRC=False)
if response == 404: if response == 404:
self.replyCode(404, "Cannot send to channel", channel=recipient) self.replyCode(404, "Cannot send to channel", channel=recipient)
return return
@ -453,7 +455,6 @@ class Client:
for _, value in self.server.clients.items(): for _, value in self.server.clients.items():
if recipient in value.joinedChannels and value != self: if recipient in value.joinedChannels and value != self:
value.message(":{} PRIVMSG {} :{}".format(self.username, recipient, message)) value.message(":{} PRIVMSG {} :{}".format(self.username, recipient, message))
#self.messageChannel(recipient, command, "{} :{}".format(recipient, message))
else: else:
# Private message (IRC) # Private message (IRC)
for _, value in self.server.clients.items(): for _, value in self.server.clients.items():
@ -513,7 +514,7 @@ class Client:
class Server: class Server():
def __init__(self, port): def __init__(self, port):
self.host = socket.getfqdn("127.0.0.1")[:63] self.host = socket.getfqdn("127.0.0.1")[:63]
self.port = port self.port = port
@ -529,7 +530,7 @@ class Server:
for _, value in self.clients.items(): for _, value in self.clients.items():
if value.username == username: if value.username == username:
value.disconnect(callLogout=False) value.disconnect(callLogout=False)
break# or dictionary changes size during iteration break # or dictionary changes size during iteration
def banchoJoinChannel(self, username, channel): def banchoJoinChannel(self, username, channel):
""" """
@ -538,6 +539,7 @@ class Server:
username -- username of bancho user username -- username of bancho user
channel -- joined channel name channel -- joined channel name
""" """
username = chat.fixUsernameForIRC(username)
for _, value in self.clients.items(): for _, value in self.clients.items():
if channel in value.joinedChannels: if channel in value.joinedChannels:
value.message(":{} JOIN {}".format(username, channel)) value.message(":{} JOIN {}".format(username, channel))
@ -549,6 +551,7 @@ class Server:
username -- username of bancho user username -- username of bancho user
channel -- joined channel name channel -- joined channel name
""" """
username = chat.fixUsernameForIRC(username)
for _, value in self.clients.items(): for _, value in self.clients.items():
if channel in value.joinedChannels: if channel in value.joinedChannels:
value.message(":{} PART {}".format(username, channel)) value.message(":{} PART {}".format(username, channel))
@ -561,6 +564,8 @@ class Server:
to -- receiver username to -- receiver username
message -- text of the message message -- text of the message
""" """
fro = chat.fixUsernameForIRC(fro)
to = chat.fixUsernameForIRC(to)
if to.startswith("#"): if to.startswith("#"):
# Public message # Public message
for _, value in self.clients.items(): for _, value in self.clients.items():

View File

@ -1,7 +1,8 @@
# TODO: Rewrite this shit
from objects import glob from objects import glob
from helpers import generalFunctions from helpers import generalFunctions
class banchoConfig: class banchoConfig():
""" """
Class that loads settings from bancho_settings db table Class that loads settings from bancho_settings db table
""" """
@ -12,31 +13,30 @@ class banchoConfig:
""" """
Initialize a banchoConfig object (and load bancho_settings from db) Initialize a banchoConfig object (and load bancho_settings from db)
[loadFromDB -- if True, load values from db. If False, don't load values. Default: True] loadFromDB -- if True, load values from db. If False, don't load values. Optional.
""" """
if loadFromDB: if loadFromDB:
try: try:
self.loadSettings() self.loadSettings()
except: except:
raise raise
def loadSettings(self): def loadSettings(self):
""" """
(re)load bancho_settings from DB and set values in config array (re)load bancho_settings from DB and set values in config array
""" """
self.config["banchoMaintenance"] = generalFunctions.stringToBool(glob.db.fetch("SELECT value_int FROM bancho_settings WHERE name = 'bancho_maintenance'")["value_int"]) self.config["banchoMaintenance"] = generalFunctions.stringToBool(glob.db.fetch("SELECT value_int FROM bancho_settings WHERE name = 'bancho_maintenance'")["value_int"])
self.config["freeDirect"] = generalFunctions.stringToBool(glob.db.fetch("SELECT value_int FROM bancho_settings WHERE name = 'free_direct'")["value_int"]) self.config["freeDirect"] = generalFunctions.stringToBool(glob.db.fetch("SELECT value_int FROM bancho_settings WHERE name = 'free_direct'")["value_int"])
self.config["menuIcon"] = glob.db.fetch("SELECT value_string FROM bancho_settings WHERE name = 'menu_icon'")["value_string"] self.config["menuIcon"] = glob.db.fetch("SELECT value_string FROM bancho_settings WHERE name = 'menu_icon'")["value_string"]
self.config["loginNotification"] = glob.db.fetch("SELECT value_string FROM bancho_settings WHERE name = 'login_notification'")["value_string"] self.config["loginNotification"] = glob.db.fetch("SELECT value_string FROM bancho_settings WHERE name = 'login_notification'")["value_string"]
def setMaintenance(self, maintenance): def setMaintenance(self, maintenance):
""" """
Turn on/off bancho maintenance mode. Write new value to db too Turn on/off bancho maintenance mode. Write new value to db too
maintenance -- if True, turn on maintenance mode. If false, turn it off maintenance -- if True, turn on maintenance mode. If false, turn it off
""" """
self.config["banchoMaintenance"] = maintenance self.config["banchoMaintenance"] = maintenance
glob.db.execute("UPDATE bancho_settings SET value_int = %s WHERE name = 'bancho_maintenance'", [int(maintenance)]) glob.db.execute("UPDATE bancho_settings SET value_int = %s WHERE name = 'bancho_maintenance'", [int(maintenance)])

View File

@ -1,6 +1,6 @@
from objects import glob from objects import glob
class channel: class channel():
""" """
A chat channel A chat channel
""" """
@ -16,7 +16,6 @@ class channel:
temp -- if True, channel will be deleted when there's no one in the channel temp -- if True, channel will be deleted when there's no one in the channel
hidden -- if True, channel won't be shown in channels list hidden -- if True, channel won't be shown in channels list
""" """
self.name = name self.name = name
self.description = description self.description = description
self.publicRead = publicRead self.publicRead = publicRead
@ -33,25 +32,21 @@ class channel:
elif self.name.startswith("#multi_"): elif self.name.startswith("#multi_"):
self.clientName = "#multiplayer" self.clientName = "#multiplayer"
def userJoin(self, userID): def userJoin(self, userID):
""" """
Add a user to connected users Add a user to connected users
userID -- user ID that joined the channel userID -- user ID that joined the channel
""" """
if userID not in self.connectedUsers: if userID not in self.connectedUsers:
self.connectedUsers.append(userID) self.connectedUsers.append(userID)
def userPart(self, userID): def userPart(self, userID):
""" """
Remove a user from connected users Remove a user from connected users
userID -- user ID that left the channel userID -- user ID that left the channel
""" """
if userID in self.connectedUsers: if userID in self.connectedUsers:
self.connectedUsers.remove(userID) self.connectedUsers.remove(userID)
@ -60,7 +55,6 @@ class channel:
if self.temp == True and ((l == 0) or (l == 1 and 999 in self.connectedUsers)): if self.temp == True and ((l == 0) or (l == 1 and 999 in self.connectedUsers)):
glob.channels.removeChannel(self.name) glob.channels.removeChannel(self.name)
def getConnectedUsers(self): def getConnectedUsers(self):
""" """
Get connected user IDs list Get connected user IDs list
@ -69,7 +63,6 @@ class channel:
""" """
return self.connectedUsers return self.connectedUsers
def getConnectedUsersCount(self): def getConnectedUsersCount(self):
""" """
Count connected users Count connected users

View File

@ -2,16 +2,14 @@ from objects import glob
from objects import channel from objects import channel
from helpers import logHelper as log from helpers import logHelper as log
class channelList: class channelList():
""" """
Channel list Channel list
channels -- dictionary. key: channel name, value: channel object channels -- dictionary. key: channel name, value: channel object
""" """
channels = {} channels = {}
def loadChannels(self): def loadChannels(self):
""" """
Load chat channels from db and add them to channels dictionary Load chat channels from db and add them to channels dictionary
@ -27,7 +25,6 @@ class channelList:
publicWrite = True if i["public_write"] == 1 else False publicWrite = True if i["public_write"] == 1 else False
self.addChannel(i["name"], i["description"], publicRead, publicWrite) self.addChannel(i["name"], i["description"], publicRead, publicWrite)
def addChannel(self, name, description, publicRead, publicWrite, temp = False, hidden = False): def addChannel(self, name, description, publicRead, publicWrite, temp = False, hidden = False):
""" """
Add a channel object to channels dictionary Add a channel object to channels dictionary
@ -42,7 +39,6 @@ class channelList:
self.channels[name] = channel.channel(name, description, publicRead, publicWrite, temp, hidden) self.channels[name] = channel.channel(name, description, publicRead, publicWrite, temp, hidden)
log.info("Created channel {}".format(name)) log.info("Created channel {}".format(name))
def addTempChannel(self, name): def addTempChannel(self, name):
""" """
Add a temporary channel (like #spectator or #multiplayer), gets deleted when there's no one in the channel Add a temporary channel (like #spectator or #multiplayer), gets deleted when there's no one in the channel
@ -56,7 +52,6 @@ class channelList:
self.channels[name] = channel.channel(name, "Chat", True, True, True, True) self.channels[name] = channel.channel(name, "Chat", True, True, True, True)
log.info("Created temp channel {}".format(name)) log.info("Created temp channel {}".format(name))
def removeChannel(self, name): def removeChannel(self, name):
""" """
Removes a channel from channels list Removes a channel from channels list

View File

@ -1,4 +1,4 @@
class chatFilters: class chatFilters():
def __init__(self, fileName="filters.txt"): def __init__(self, fileName="filters.txt"):
self.filters = {} self.filters = {}
self.loadFilters(fileName) self.loadFilters(fileName)

View File

@ -17,12 +17,10 @@ def connect():
glob.tokens.enqueueAll(serverPackets.userPanel(999)) glob.tokens.enqueueAll(serverPackets.userPanel(999))
glob.tokens.enqueueAll(serverPackets.userStats(999)) glob.tokens.enqueueAll(serverPackets.userStats(999))
def disconnect(): def disconnect():
"""Remove FokaBot from connected users""" """Remove FokaBot from connected users"""
glob.tokens.deleteToken(glob.tokens.getTokenFromUserID(999)) glob.tokens.deleteToken(glob.tokens.getTokenFromUserID(999))
def fokabotResponse(fro, chan, message): def fokabotResponse(fro, chan, message):
""" """
Check if a message has triggered fokabot (and return its response) Check if a message has triggered fokabot (and return its response)
@ -57,4 +55,4 @@ def fokabotResponse(fro, chan, message):
return i["callback"](fro, chan, message[1:]) return i["callback"](fro, chan, message[1:])
# No commands triggered # No commands triggered
return False return False

View File

@ -10,8 +10,20 @@ from constants import dataTypes
from constants import matchTeams from constants import matchTeams
from helpers import logHelper as log from helpers import logHelper as log
from helpers import chatHelper as chat from helpers import chatHelper as chat
from helpers import generalFunctions
import copy
class match: class slot():
def __init__(self):
self.status = slotStatuses.free
self.team = 0
self.userID = -1
self.mods = 0
self.loaded = False
self.skip = False
self.complete = False
class match():
"""Multiplayer match object""" """Multiplayer match object"""
matchID = 0 matchID = 0
inProgress = False inProgress = False
@ -21,7 +33,7 @@ class match:
beatmapName = "" beatmapName = ""
beatmapID = 0 beatmapID = 0
beatmapMD5 = "" beatmapMD5 = ""
slots = [] # list of dictionaries {"status": 0, "team": 0, "userID": -1, "mods": 0, "loaded": False, "skip": False, "complete": False} slots = []
hostUserID = 0 hostUserID = 0
gameMode = gameModes.std gameMode = gameModes.std
matchScoringType = matchScoringTypes.score matchScoringType = matchScoringTypes.score
@ -46,7 +58,10 @@ class match:
self.inProgress = False self.inProgress = False
self.mods = 0 self.mods = 0
self.matchName = matchName self.matchName = matchName
self.matchPassword = matchPassword if matchPassword != "":
self.matchPassword = generalFunctions.stringMd5(matchPassword)
else:
self.matchPassword = ""
self.beatmapID = beatmapID self.beatmapID = beatmapID
self.beatmapName = beatmapName self.beatmapName = beatmapName
self.beatmapMD5 = beatmapMD5 self.beatmapMD5 = beatmapMD5
@ -60,12 +75,11 @@ class match:
# Create all slots and reset them # Create all slots and reset them
self.slots = [] self.slots = []
for _ in range(0,16): for _ in range(0,16):
self.slots.append({"status": slotStatuses.free, "team": 0, "userID": -1, "mods": 0, "loaded": False, "skip": False, "complete": False}) self.slots.append(slot())
# Create #multiplayer channel # Create #multiplayer channel
glob.channels.addTempChannel("#multi_{}".format(self.matchID)) glob.channels.addTempChannel("#multi_{}".format(self.matchID))
def getMatchData(self): def getMatchData(self):
""" """
Return binary match data structure for packetHelper Return binary match data structure for packetHelper
@ -85,15 +99,15 @@ class match:
# Slots status IDs, always 16 elements # Slots status IDs, always 16 elements
for i in range(0,16): for i in range(0,16):
struct.append([self.slots[i]["status"], dataTypes.byte]) struct.append([self.slots[i].status, dataTypes.byte])
# Slot teams, always 16 elements # Slot teams, always 16 elements
for i in range(0,16): for i in range(0,16):
struct.append([self.slots[i]["team"], dataTypes.byte]) struct.append([self.slots[i].team, dataTypes.byte])
# Slot user ID. Write only if slot is occupied # Slot user ID. Write only if slot is occupied
for i in range(0,16): for i in range(0,16):
uid = self.slots[i]["userID"] uid = self.slots[i].userID
if uid > -1: if uid > -1:
struct.append([uid, dataTypes.uInt32]) struct.append([uid, dataTypes.uInt32])
@ -109,15 +123,13 @@ class match:
# Slot mods if free mod is enabled # Slot mods if free mod is enabled
if self.matchModMode == matchModModes.freeMod: if self.matchModMode == matchModModes.freeMod:
for i in range(0,16): for i in range(0,16):
struct.append([self.slots[i]["mods"], dataTypes.uInt32]) struct.append([self.slots[i].mods, dataTypes.uInt32])
# Seed idk # Seed idk
struct.append([self.seed, dataTypes.uInt32]) struct.append([self.seed, dataTypes.uInt32])
return struct return struct
def setHost(self, newHost): def setHost(self, newHost):
""" """
Set room host to newHost and send him host packet Set room host to newHost and send him host packet
@ -149,26 +161,25 @@ class match:
If Null is passed, that value won't be edited If Null is passed, that value won't be edited
""" """
if slotStatus != None: if slotStatus != None:
self.slots[slotID]["status"] = slotStatus self.slots[slotID].status = slotStatus
if slotTeam != None: if slotTeam != None:
self.slots[slotID]["team"] = slotTeam self.slots[slotID].team = slotTeam
if slotUserID != None: if slotUserID != None:
self.slots[slotID]["userID"] = slotUserID self.slots[slotID].userID = slotUserID
if slotMods != None: if slotMods != None:
self.slots[slotID]["mods"] = slotMods self.slots[slotID].mods = slotMods
if slotLoaded != None: if slotLoaded != None:
self.slots[slotID]["loaded"] = slotLoaded self.slots[slotID].loaded = slotLoaded
if slotSkip != None: if slotSkip != None:
self.slots[slotID]["skip"] = slotSkip self.slots[slotID].skip = slotSkip
if slotComplete != None: if slotComplete != None:
self.slots[slotID]["complete"] = slotComplete self.slots[slotID].complete = slotComplete
def setSlotMods(self, slotID, mods): def setSlotMods(self, slotID, mods):
""" """
@ -182,7 +193,6 @@ class match:
self.sendUpdate() self.sendUpdate()
log.info("MPROOM{}: Slot{} mods changed to {}".format(self.matchID, slotID, mods)) log.info("MPROOM{}: Slot{} mods changed to {}".format(self.matchID, slotID, mods))
def toggleSlotReady(self, slotID): def toggleSlotReady(self, slotID):
""" """
Switch slotID ready/not ready status Switch slotID ready/not ready status
@ -191,14 +201,14 @@ class match:
slotID -- slot number slotID -- slot number
""" """
# Update ready status and setnd update # Update ready status and setnd update
oldStatus = self.slots[slotID]["status"] oldStatus = self.slots[slotID].status
if oldStatus == slotStatuses.ready: if oldStatus == slotStatuses.ready:
newStatus = slotStatuses.notReady newStatus = slotStatuses.notReady
else: else:
newStatus = slotStatuses.ready newStatus = slotStatuses.ready
self.setSlot(slotID, newStatus, None, None, None) self.setSlot(slotID, newStatus, None, None, None)
self.sendUpdate() self.sendUpdate()
log.info("MPROOM{}: Slot{} changed ready status to {}".format(self.matchID, slotID, self.slots[slotID]["status"])) log.info("MPROOM{}: Slot{} changed ready status to {}".format(self.matchID, slotID, self.slots[slotID].status))
def toggleSlotLock(self, slotID): def toggleSlotLock(self, slotID):
""" """
@ -208,13 +218,13 @@ class match:
slotID -- slot number slotID -- slot number
""" """
# Get token of user in that slot (if there's someone) # Get token of user in that slot (if there's someone)
if self.slots[slotID]["userID"] > -1: if self.slots[slotID].userID > -1:
token = glob.tokens.getTokenFromUserID(self.slots[slotID]["userID"]) token = glob.tokens.getTokenFromUserID(self.slots[slotID].userID)
else: else:
token = None token = None
# Check if slot is already locked # Check if slot is already locked
if self.slots[slotID]["status"] == slotStatuses.locked: if self.slots[slotID].status == slotStatuses.locked:
newStatus = slotStatuses.free newStatus = slotStatuses.free
else: else:
newStatus = slotStatuses.locked newStatus = slotStatuses.locked
@ -240,33 +250,31 @@ class match:
return return
# Set loaded to True # Set loaded to True
self.slots[slotID]["loaded"] = True self.slots[slotID].loaded = True
log.info("MPROOM{}: User {} loaded".format(self.matchID, userID)) log.info("MPROOM{}: User {} loaded".format(self.matchID, userID))
# Check all loaded # Check all loaded
total = 0 total = 0
loaded = 0 loaded = 0
for i in range(0,16): for i in range(0,16):
if self.slots[i]["status"] == slotStatuses.playing: if self.slots[i].status == slotStatuses.playing:
total+=1 total+=1
if self.slots[i]["loaded"] == True: if self.slots[i].loaded == True:
loaded+=1 loaded+=1
if total == loaded: if total == loaded:
self.allPlayersLoaded() self.allPlayersLoaded()
def allPlayersLoaded(self): def allPlayersLoaded(self):
"""Send allPlayersLoaded packet to every playing usr in match""" """Send allPlayersLoaded packet to every playing usr in match"""
for i in range(0,16): for i in range(0,16):
if self.slots[i]["userID"] > -1 and self.slots[i]["status"] == slotStatuses.playing: if self.slots[i].userID > -1 and self.slots[i].status == slotStatuses.playing:
token = glob.tokens.getTokenFromUserID(self.slots[i]["userID"]) token = glob.tokens.getTokenFromUserID(self.slots[i].userID)
if token != None: if token != None:
token.enqueue(serverPackets.allPlayersLoaded()) token.enqueue(serverPackets.allPlayersLoaded())
log.info("MPROOM{}: All players loaded! Match starting...".format(self.matchID)) log.info("MPROOM{}: All players loaded! Match starting...".format(self.matchID))
def playerSkip(self, userID): def playerSkip(self, userID):
""" """
Set a player skip status to True Set a player skip status to True
@ -278,13 +286,13 @@ class match:
return return
# Set skip to True # Set skip to True
self.slots[slotID]["skip"] = True self.slots[slotID].skip = True
log.info("MPROOM{}: User {} skipped".format(self.matchID, userID)) log.info("MPROOM{}: User {} skipped".format(self.matchID, userID))
# Send skip packet to every playing useR # Send skip packet to every playing user
for i in range(0,16): for i in range(0,16):
uid = self.slots[i]["userID"] uid = self.slots[i].userID
if self.slots[i]["status"] == slotStatuses.playing and uid > -1: if (self.slots[i].status & slotStatuses.playing > 0) and uid > -1:
token = glob.tokens.getTokenFromUserID(uid) token = glob.tokens.getTokenFromUserID(uid)
if token != None: if token != None:
token.enqueue(serverPackets.playerSkipped(uid)) token.enqueue(serverPackets.playerSkipped(uid))
@ -293,9 +301,9 @@ class match:
total = 0 total = 0
skipped = 0 skipped = 0
for i in range(0,16): for i in range(0,16):
if self.slots[i]["status"] == slotStatuses.playing: if self.slots[i].status == slotStatuses.playing:
total+=1 total+=1
if self.slots[i]["skip"] == True: if self.slots[i].skip == True:
skipped+=1 skipped+=1
if total == skipped: if total == skipped:
@ -304,8 +312,8 @@ class match:
def allPlayersSkipped(self): def allPlayersSkipped(self):
"""Send allPlayersSkipped packet to every playing usr in match""" """Send allPlayersSkipped packet to every playing usr in match"""
for i in range(0,16): for i in range(0,16):
if self.slots[i]["userID"] > -1 and self.slots[i]["status"] == slotStatuses.playing: if self.slots[i].userID > -1 and self.slots[i].status == slotStatuses.playing:
token = glob.tokens.getTokenFromUserID(self.slots[i]["userID"]) token = glob.tokens.getTokenFromUserID(self.slots[i].userID)
if token != None: if token != None:
token.enqueue(serverPackets.allPlayersSkipped()) token.enqueue(serverPackets.allPlayersSkipped())
@ -329,9 +337,9 @@ class match:
total = 0 total = 0
completed = 0 completed = 0
for i in range(0,16): for i in range(0,16):
if self.slots[i]["status"] == slotStatuses.playing: if self.slots[i].status == slotStatuses.playing:
total+=1 total+=1
if self.slots[i]["complete"] == True: if self.slots[i].complete == True:
completed+=1 completed+=1
if total == completed: if total == completed:
@ -345,38 +353,34 @@ class match:
# Reset slots # Reset slots
for i in range(0,16): for i in range(0,16):
if self.slots[i]["userID"] > -1 and self.slots[i]["status"] == slotStatuses.playing: if self.slots[i].userID > -1 and self.slots[i].status == slotStatuses.playing:
self.slots[i]["status"] = slotStatuses.notReady self.slots[i].status = slotStatuses.notReady
self.slots[i]["loaded"] = False self.slots[i].loaded = False
self.slots[i]["skip"] = False self.slots[i].skip = False
self.slots[i]["complete"] = False self.slots[i].complete = False
# Send match update # Send match update
self.sendUpdate() self.sendUpdate()
# Send match complete # Send match complete
for i in range(0,16): for i in range(0,16):
if self.slots[i]["userID"] > -1: if self.slots[i].userID > -1:
token = glob.tokens.getTokenFromUserID(self.slots[i]["userID"]) token = glob.tokens.getTokenFromUserID(self.slots[i].userID)
if token != None: if token != None:
token.enqueue(serverPackets.matchComplete()) token.enqueue(serverPackets.matchComplete())
# Console output # Console output
log.info("MPROOM{}: Match completed".format(self.matchID)) log.info("MPROOM{}: Match completed".format(self.matchID))
def getUserSlotID(self, userID): def getUserSlotID(self, userID):
""" """
Get slot ID occupied by userID Get slot ID occupied by userID
return -- slot id if found, None if user is not in room return -- slot id if found, None if user is not in room
""" """
for i in range(0,16): for i in range(0,16):
if self.slots[i]["userID"] == userID: if self.slots[i].userID == userID:
return i return i
return None return None
def userJoin(self, userID): def userJoin(self, userID):
@ -389,7 +393,7 @@ class match:
# Find first free slot # Find first free slot
for i in range(0,16): for i in range(0,16):
if self.slots[i]["status"] == slotStatuses.free: if self.slots[i].status == slotStatuses.free:
# Occupy slot # Occupy slot
self.setSlot(i, slotStatuses.notReady, 0, userID, 0) self.setSlot(i, slotStatuses.notReady, 0, userID, 0)
@ -409,7 +413,6 @@ class match:
userID -- user if of the user userID -- user if of the user
""" """
# Make sure the user is in room # Make sure the user is in room
slotID = self.getUserSlotID(userID) slotID = self.getUserSlotID(userID)
if slotID == None: if slotID == None:
@ -429,7 +432,7 @@ class match:
if userID == self.hostUserID: if userID == self.hostUserID:
# Give host to someone else # Give host to someone else
for i in range(0,16): for i in range(0,16):
uid = self.slots[i]["userID"] uid = self.slots[i].userID
if uid > -1: if uid > -1:
self.setHost(uid) self.setHost(uid)
break break
@ -440,7 +443,6 @@ class match:
# Console output # Console output
log.info("MPROOM{}: {} left the room".format(self.matchID, userID)) log.info("MPROOM{}: {} left the room".format(self.matchID, userID))
def userChangeSlot(self, userID, newSlotID): def userChangeSlot(self, userID, newSlotID):
""" """
Change userID slot to newSlotID Change userID slot to newSlotID
@ -448,24 +450,23 @@ class match:
userID -- user that changed slot userID -- user that changed slot
newSlotID -- slot id of new slot newSlotID -- slot id of new slot
""" """
# Make sure the user is in room # Make sure the user is in room
oldSlotID = self.getUserSlotID(userID) oldSlotID = self.getUserSlotID(userID)
if oldSlotID == None: if oldSlotID == None:
return return
# Make sure there is no one inside new slot # Make sure there is no one inside new slot
if self.slots[newSlotID]["userID"] > -1: if self.slots[newSlotID].userID > -1 and self.slots[newSlotID].status != slotStatuses.free:
return return
# Get old slot data # Get old slot data
oldData = self.slots[oldSlotID].copy() oldData = copy.deepcopy(self.slots[oldSlotID])
# Free old slot # Free old slot
self.setSlot(oldSlotID, slotStatuses.free, 0, -1, 0) self.setSlot(oldSlotID, slotStatuses.free, 0, -1, 0)
# Occupy new slot # Occupy new slot
self.setSlot(newSlotID, oldData["status"], oldData["team"], userID, oldData["mods"]) self.setSlot(newSlotID, oldData.status, oldData.team, oldData.userID, oldData.mods)
# Send updated match data # Send updated match data
self.sendUpdate() self.sendUpdate()
@ -479,12 +480,15 @@ class match:
newPassword -- new password string newPassword -- new password string
""" """
self.matchPassword = newPassword if newPassword != "":
self.matchPassword = generalFunctions.stringMd5(newPassword)
else:
self.matchPassword = ""
# Send password change to every user in match # Send password change to every user in match
for i in range(0,16): for i in range(0,16):
if self.slots[i]["userID"] > -1: if self.slots[i].userID > -1:
token = glob.tokens.getTokenFromUserID(self.slots[i]["userID"]) token = glob.tokens.getTokenFromUserID(self.slots[i].userID)
if token != None: if token != None:
token.enqueue(serverPackets.changeMatchPassword(self.matchPassword)) token.enqueue(serverPackets.changeMatchPassword(self.matchPassword))
@ -494,7 +498,6 @@ class match:
# Console output # Console output
log.info("MPROOM{}: Password changed to {}".format(self.matchID, self.matchPassword)) log.info("MPROOM{}: Password changed to {}".format(self.matchID, self.matchPassword))
def changeMatchMods(self, mods): def changeMatchMods(self, mods):
""" """
Set match global mods Set match global mods
@ -531,7 +534,7 @@ class match:
slotID -- ID of slot slotID -- ID of slot
""" """
# Make sure there is someone in that slot # Make sure there is someone in that slot
uid = self.slots[slotID]["userID"] uid = self.slots[slotID].userID
if uid == -1: if uid == -1:
return return
@ -541,7 +544,6 @@ class match:
# Send updates # Send updates
self.sendUpdate() self.sendUpdate()
def playerFailed(self, userID): def playerFailed(self, userID):
""" """
Send userID's failed packet to everyone in match Send userID's failed packet to everyone in match
@ -555,7 +557,7 @@ class match:
# Send packet to everyone # Send packet to everyone
for i in range(0,16): for i in range(0,16):
uid = self.slots[i]["userID"] uid = self.slots[i].userID
if uid > -1: if uid > -1:
token = glob.tokens.getTokenFromUserID(uid) token = glob.tokens.getTokenFromUserID(uid)
if token != None: if token != None:
@ -564,7 +566,6 @@ class match:
# Console output # Console output
log.info("MPROOM{}: {} has failed!".format(self.matchID, userID)) log.info("MPROOM{}: {} has failed!".format(self.matchID, userID))
def invite(self, fro, to): def invite(self, fro, to):
""" """
Fro invites to in this match. Fro invites to in this match.
@ -587,19 +588,16 @@ class match:
message = "Come join my multiplayer match: \"[osump://{}/{} {}]\"".format(self.matchID, self.matchPassword.replace(" ", "_"), self.matchName) message = "Come join my multiplayer match: \"[osump://{}/{} {}]\"".format(self.matchID, self.matchPassword.replace(" ", "_"), self.matchName)
chat.sendMessage(token=froToken, to=toToken.username, message=message) chat.sendMessage(token=froToken, to=toToken.username, message=message)
def countUsers(self): def countUsers(self):
""" """
Return how many players are in that match Return how many players are in that match
return -- number of users return -- number of users
""" """
c = 0 c = 0
for i in range(0,16): for i in range(0,16):
if self.slots[i]["userID"] > -1: if self.slots[i].userID > -1:
c+=1 c+=1
return c return c
def changeTeam(self, userID): def changeTeam(self, userID):
@ -614,15 +612,15 @@ class match:
return return
# Update slot and send update # Update slot and send update
newTeam = matchTeams.blue if self.slots[slotID]["team"] == matchTeams.red else matchTeams.red newTeam = matchTeams.blue if self.slots[slotID].team == matchTeams.red else matchTeams.red
self.setSlot(slotID, None, newTeam) self.setSlot(slotID, None, newTeam)
self.sendUpdate() self.sendUpdate()
def sendUpdate(self): def sendUpdate(self):
# Send to users in room # Send to users in room
for i in range(0,16): for i in range(0,16):
if self.slots[i]["userID"] > -1: if self.slots[i].userID > -1:
token = glob.tokens.getTokenFromUserID(self.slots[i]["userID"]) token = glob.tokens.getTokenFromUserID(self.slots[i].userID)
if token != None: if token != None:
token.enqueue(serverPackets.updateMatch(self.matchID)) token.enqueue(serverPackets.updateMatch(self.matchID))
@ -645,10 +643,10 @@ class match:
# We have teams, check if they are valid # We have teams, check if they are valid
firstTeam = -1 firstTeam = -1
for i in range(0,16): for i in range(0,16):
if self.slots[i]["userID"] > -1 and (self.slots[i]["status"]&slotStatuses.noMap) == 0: if self.slots[i].userID > -1 and (self.slots[i].status&slotStatuses.noMap) == 0:
if firstTeam == -1: if firstTeam == -1:
firstTeam = self.slots[i]["team"] firstTeam = self.slots[i].team
elif firstTeam != self.slots[i]["teams"]: elif firstTeam != self.slots[i].team:
log.info("MPROOM{}: Teams are valid".format(self.matchID)) log.info("MPROOM{}: Teams are valid".format(self.matchID))
return True return True

View File

@ -2,7 +2,7 @@ from objects import match
from objects import glob from objects import glob
from constants import serverPackets from constants import serverPackets
class matchList: class matchList():
matches = {} matches = {}
usersInLobby = [] usersInLobby = []
lastID = 1 lastID = 1
@ -32,49 +32,43 @@ class matchList:
self.matches[matchID] = match.match(matchID, matchName, matchPassword, beatmapID, beatmapName, beatmapMD5, gameMode, hostUserID) self.matches[matchID] = match.match(matchID, matchName, matchPassword, beatmapID, beatmapName, beatmapMD5, gameMode, hostUserID)
return matchID return matchID
def lobbyUserJoin(self, userID): def lobbyUserJoin(self, userID):
""" """
Add userID to users in lobby Add userID to users in lobby
userID -- user who joined mp lobby userID -- user who joined mp lobby
""" """
# Make sure the user is not already in mp lobby # Make sure the user is not already in mp lobby
if userID not in self.usersInLobby: if userID not in self.usersInLobby:
# We don't need to join #lobby, client will automatically send a packet for it # We don't need to join #lobby, client will automatically send a packet for it
self.usersInLobby.append(userID) self.usersInLobby.append(userID)
def lobbyUserPart(self, userID): def lobbyUserPart(self, userID):
""" """
Remove userID from users in lobby Remove userID from users in lobby
userID -- user who left mp lobby userID -- user who left mp lobby
""" """
# Make sure the user is in mp lobby # Make sure the user is in mp lobby
if userID in self.usersInLobby: if userID in self.usersInLobby:
# Part lobby and #lobby channel # Part lobby and #lobby channel
self.usersInLobby.remove(userID) self.usersInLobby.remove(userID)
def disposeMatch(self, matchID):
def disposeMatch(self, __matchID):
""" """
Destroy match object with id = __matchID Destroy match object with id = matchID
__matchID -- ID of match to dispose matchID -- ID of match to dispose
""" """
# Make sure the match exists # Make sure the match exists
if __matchID not in self.matches: if matchID not in self.matches:
return return
# Remove match object # Remove match object
self.matches.pop(__matchID) self.matches.pop(matchID)
# Send match dispose packet to everyone in lobby # Send match dispose packet to everyone in lobby
for i in self.usersInLobby: for i in self.usersInLobby:
token = glob.tokens.getTokenFromUserID(i) token = glob.tokens.getTokenFromUserID(i)
if token != None: if token != None:
token.enqueue(serverPackets.disposeMatch(__matchID)) token.enqueue(serverPackets.disposeMatch(matchID))

View File

@ -8,33 +8,9 @@ from objects import glob
import uuid import uuid
import time import time
import threading import threading
from helpers import logHelper as log
from helpers import chatHelper as chat from helpers import chatHelper as chat
class token: class token():
"""
Osu Token object
token -- token string
userID -- userID associated to that token
username -- username relative to userID (cache)
actionID -- current user action (see actions.py)
actionText -- current user action text
actionMd5 -- md5 relative to user action
actionMods -- current acton mods
gameMode -- current user game mode
location -- [latitude,longitude]
queue -- packets queue
joinedChannels -- list. Contains joined channel names
spectating -- userID of spectating user. 0 if not spectating.
spectators -- list. Contains userIDs of spectators
country -- osu country code. Use countryHelper to convert from letter country code to osu country code
pingTime -- latest packet received UNIX time
loginTime -- login UNIX time
latestTillerino -- beatmap ID of latest song from tillerino bot
"""
def __init__(self, userID, token = None, ip = "", irc = False, timeOffset = 0): def __init__(self, userID, token = None, ip = "", irc = False, timeOffset = 0):
""" """
Create a token object and set userID and token Create a token object and set userID and token
@ -44,8 +20,8 @@ class token:
if not passed, token will be generated if not passed, token will be generated
ip -- client ip. optional. ip -- client ip. optional.
irc -- if True, set this token as IRC client. optional. irc -- if True, set this token as IRC client. optional.
timeOffset -- the time offset from UTC for this user. optional.
""" """
# Set stuff # Set stuff
self.userID = userID self.userID = userID
self.username = userHelper.getUsername(self.userID) self.username = userHelper.getUsername(self.userID)
@ -71,7 +47,6 @@ class token:
self.tillerino = [0,0,-1.0] # beatmap, mods, acc self.tillerino = [0,0,-1.0] # beatmap, mods, acc
self.silenceEndTime = 0 self.silenceEndTime = 0
self.queue = bytes() self.queue = bytes()
self.osuDirectAlert = False # NOTE: Remove this when osu!direct will be fixed
# Spam protection # Spam protection
self.spamRate = 0 self.spamRate = 0
@ -102,14 +77,14 @@ class token:
if ip != "": if ip != "":
userHelper.saveBanchoSession(self.userID, self.ip) userHelper.saveBanchoSession(self.userID, self.ip)
def enqueue(self, __bytes): def enqueue(self, bytes):
""" """
Add bytes (packets) to queue Add bytes (packets) to queue
__bytes -- (packet) bytes to enqueue bytes -- (packet) bytes to enqueue
""" """
if self.irc == False: if self.irc == False:
self.queue += __bytes self.queue += bytes
def resetQueue(self): def resetQueue(self):
@ -117,95 +92,140 @@ class token:
self.queue = bytes() self.queue = bytes()
def joinChannel(self, __channel): def joinChannel(self, channel):
"""Add __channel to joined channels list """
Add channel to joined channels list
__channel -- channel name""" channel -- channel name
"""
if channel not in self.joinedChannels:
self.joinedChannels.append(channel)
if __channel not in self.joinedChannels: def partChannel(self, channel):
self.joinedChannels.append(__channel) """
Remove channel from joined channels list
channel -- channel name
"""
if channel in self.joinedChannels:
self.joinedChannels.remove(channel)
def partChannel(self, __channel): def setLocation(self, location):
"""Remove __channel from joined channels list """
Set location (latitude and longitude)
__channel -- channel name"""
if __channel in self.joinedChannels:
self.joinedChannels.remove(__channel)
def setLocation(self, __location):
"""Set location (latitude and longitude)
__location -- [latitude, longitude]"""
self.location = __location
location -- [latitude, longitude]
"""
self.location = location
def getLatitude(self): def getLatitude(self):
"""Get latitude """
Get latitude
return -- latitude"""
return -- latitude
"""
return self.location[0] return self.location[0]
def getLongitude(self): def getLongitude(self):
"""Get longitude """
Get longitude
return -- longitude""" return -- longitude
"""
return self.location[1] return self.location[1]
def startSpectating(self, userID): def startSpectating(self, userID):
"""Set the spectating user to userID """
Set the spectating user to userID
userID -- target userID""" userID -- target userID
"""
self.spectating = userID self.spectating = userID
def stopSpectating(self): def stopSpectating(self):
"""Set the spectating user to 0, aka no user""" # Remove our userID from host's spectators
target = self.spectating
targetToken = glob.tokens.getTokenFromUserID(target)
if targetToken != None:
# Remove us from host's spectators list
targetToken.removeSpectator(self.userID)
# Send the spectator left packet to host
targetToken.enqueue(serverPackets.removeSpectator(self.userID))
for c in targetToken.spectators:
spec = glob.tokens.getTokenFromUserID(c)
spec.enqueue(serverPackets.fellowSpectatorLeft(self.userID))
# If nobody is spectating the host anymore, close #spectator channel
if len(targetToken.spectators) == 0:
chat.partChannel(token=targetToken, channel="#spect_{}".format(target), kick=True)
# Part #spectator channel
chat.partChannel(token=self, channel="#spect_{}".format(target), kick=True)
# Set our spectating user to 0
self.spectating = 0 self.spectating = 0
# Console output
log.info("{} are no longer spectating {}".format(self.username, target))
def partMatch(self):
# Make sure we are in a match
if self.matchID == -1:
return
# Part #multiplayer channel
chat.partChannel(token=self, channel="#multi_{}".format(self.matchID), kick=True)
# Make sure the match exists
if self.matchID not in glob.matches.matches:
return
# The match exists, get object
match = glob.matches.matches[self.matchID]
# Set slot to free
match.userLeft(self.userID)
# Set usertoken match to -1
self.matchID = -1
def addSpectator(self, userID): def addSpectator(self, userID):
"""Add userID to our spectators """
Add userID to our spectators
userID -- new spectator userID"""
userID -- new spectator userID
"""
# Add userID to spectators if not already in # Add userID to spectators if not already in
if userID not in self.spectators: if userID not in self.spectators:
self.spectators.append(userID) self.spectators.append(userID)
def removeSpectator(self, userID): def removeSpectator(self, userID):
"""Remove userID from our spectators """
Remove userID from our spectators
userID -- old spectator userID"""
userID -- old spectator userID
"""
# Remove spectator # Remove spectator
if userID in self.spectators: if userID in self.spectators:
self.spectators.remove(userID) self.spectators.remove(userID)
def setCountry(self, countryID):
"""
Set country to countryID
def setCountry(self, __countryID): countryID -- numeric country ID. See countryHelper.py
"""Set country to __countryID """
self.country = countryID
__countryID -- numeric country ID. See countryHelper.py"""
self.country = __countryID
def getCountry(self): def getCountry(self):
"""Get numeric country ID """
Get numeric country ID
return -- numeric country ID. See countryHelper.py"""
return -- numeric country ID. See countryHelper.py
"""
return self.country return self.country
def updatePingTime(self): def updatePingTime(self):
"""Update latest ping time""" """Update latest ping time"""
self.pingTime = int(time.time()) self.pingTime = int(time.time())
@ -214,23 +234,24 @@ class token:
"""Set a new away message""" """Set a new away message"""
self.awayMessage = __awayMessage self.awayMessage = __awayMessage
def joinMatch(self, __matchID): def joinMatch(self, matchID):
""" """
Set match to matchID Set match to matchID
__matchID -- new match ID matchID -- new match ID
""" """
self.matchID = __matchID self.matchID = matchID
def partMatch(self):
"""Set match to -1"""
self.matchID = -1
def kick(self, message="You have been kicked from the server. Please login again."): def kick(self, message="You have been kicked from the server. Please login again."):
"""Kick this user from the server""" """
Kick this user from the server
message -- Notification message to send to this user. Optional.
"""
# Send packet to target # Send packet to target
log.info("{} has been disconnected. (kick)".format(self.username)) log.info("{} has been disconnected. (kick)".format(self.username))
self.enqueue(serverPackets.notification(message)) if message != "":
self.enqueue(serverPackets.notification(message))
self.enqueue(serverPackets.loginFailed()) self.enqueue(serverPackets.loginFailed())
# Logout event # Logout event

View File

@ -3,10 +3,9 @@ from objects import glob
import time import time
import threading import threading
from events import logoutEvent from events import logoutEvent
from helpers import logHelper as log
from helpers import userHelper from helpers import userHelper
class tokenList: class tokenList():
""" """
List of connected osu tokens List of connected osu tokens
@ -27,7 +26,6 @@ class tokenList:
irc -- if True, set this token as IRC client irc -- if True, set this token as IRC client
return -- token object return -- token object
""" """
newToken = osuToken.token(userID, ip=ip, irc=irc, timeOffset=timeOffset) newToken = osuToken.token(userID, ip=ip, irc=irc, timeOffset=timeOffset)
self.tokens[newToken.token] = newToken self.tokens[newToken.token] = newToken
return newToken return newToken
@ -38,7 +36,6 @@ class tokenList:
token -- token string token -- token string
""" """
if token in self.tokens: if token in self.tokens:
# Delete session from DB # Delete session from DB
if self.tokens[token].ip != "": if self.tokens[token].ip != "":
@ -47,16 +44,13 @@ class tokenList:
# Pop token from list # Pop token from list
self.tokens.pop(token) self.tokens.pop(token)
def getUserIDFromToken(self, token): def getUserIDFromToken(self, token):
""" """
Get user ID from a token Get user ID from a token
token -- token to find token -- token to find
return -- false if not found, userID if found
return: false if not found, userID if found
""" """
# Make sure the token exists # Make sure the token exists
if token not in self.tokens: if token not in self.tokens:
return False return False
@ -64,7 +58,6 @@ class tokenList:
# Get userID associated to that token # Get userID associated to that token
return self.tokens[token].userID return self.tokens[token].userID
def getTokenFromUserID(self, userID): def getTokenFromUserID(self, userID):
""" """
Get token from a user ID Get token from a user ID
@ -72,7 +65,6 @@ class tokenList:
userID -- user ID to find userID -- user ID to find
return -- False if not found, token object if found return -- False if not found, token object if found
""" """
# Make sure the token exists # Make sure the token exists
for _, value in self.tokens.items(): for _, value in self.tokens.items():
if value.userID == userID: if value.userID == userID:
@ -81,7 +73,6 @@ class tokenList:
# Return none if not found # Return none if not found
return None return None
def getTokenFromUsername(self, username): def getTokenFromUsername(self, username):
""" """
Get token from a username Get token from a username
@ -89,7 +80,6 @@ class tokenList:
username -- username to find username -- username to find
return -- False if not found, token object if found return -- False if not found, token object if found
""" """
# lowercase # lowercase
who = username.lower() who = username.lower()
@ -101,7 +91,6 @@ class tokenList:
# Return none if not found # Return none if not found
return None return None
def deleteOldTokens(self, userID): def deleteOldTokens(self, userID):
""" """
Delete old userID's tokens if found Delete old userID's tokens if found
@ -114,11 +103,6 @@ class tokenList:
if value.userID == userID: if value.userID == userID:
# Delete this token from the dictionary # Delete this token from the dictionary
self.tokens[key].kick("You have logged in from somewhere else. You can't connect to Bancho/IRC from more than one device at the same time.") self.tokens[key].kick("You have logged in from somewhere else. You can't connect to Bancho/IRC from more than one device at the same time.")
#self.tokens.pop(key)
# break or items() function throws errors
#break
def multipleEnqueue(self, packet, who, but = False): def multipleEnqueue(self, packet, who, but = False):
""" """
@ -128,7 +112,6 @@ class tokenList:
who -- userIDs array who -- userIDs array
but -- if True, enqueue to everyone but users in who array but -- if True, enqueue to everyone but users in who array
""" """
for _, value in self.tokens.items(): for _, value in self.tokens.items():
shouldEnqueue = False shouldEnqueue = False
if value.userID in who and not but: if value.userID in who and not but:
@ -145,22 +128,20 @@ class tokenList:
packet -- packet bytes to enqueue packet -- packet bytes to enqueue
""" """
for _, value in self.tokens.items(): for _, value in self.tokens.items():
value.enqueue(packet) value.enqueue(packet)
def usersTimeoutCheckLoop(self, __timeoutTime = 100, __checkTime = 100): def usersTimeoutCheckLoop(self, timeoutTime = 100, checkTime = 100):
""" """
Deletes all timed out users. Deletes all timed out users.
If called once, will recall after __checkTime seconds and so on, forever If called once, will recall after checkTime seconds and so on, forever
CALL THIS FUNCTION ONLY ONCE! CALL THIS FUNCTION ONLY ONCE!
__timeoutTime - seconds of inactivity required to disconnect someone (Default: 100) timeoutTime - seconds of inactivity required to disconnect someone (Default: 100)
__checkTime - seconds between loops (Default: 100) checkTime - seconds between loops (Default: 100)
""" """
timedOutTokens = [] # timed out users timedOutTokens = [] # timed out users
timeoutLimit = time.time()-__timeoutTime timeoutLimit = time.time()-timeoutTime
for key, value in self.tokens.items(): for key, value in self.tokens.items():
# Check timeout (fokabot is ignored) # Check timeout (fokabot is ignored)
if value.pingTime < timeoutLimit and value.userID != 999 and value.irc == False: if value.pingTime < timeoutLimit and value.userID != 999 and value.irc == False:
@ -174,15 +155,13 @@ class tokenList:
logoutEvent.handle(self.tokens[i], None) logoutEvent.handle(self.tokens[i], None)
# Schedule a new check (endless loop) # Schedule a new check (endless loop)
threading.Timer(__checkTime, self.usersTimeoutCheckLoop, [__timeoutTime, __checkTime]).start() threading.Timer(checkTime, self.usersTimeoutCheckLoop, [timeoutTime, checkTime]).start()
def spamProtectionResetLoop(self): def spamProtectionResetLoop(self):
""" """
Reset spam rate every 10 seconds. Reset spam rate every 10 seconds.
CALL THIS FUNCTION ONLY ONCE! CALL THIS FUNCTION ONLY ONCE!
""" """
#log.debug("Resetting spam protection...")
# Reset spamRate for every token # Reset spamRate for every token
for _, value in self.tokens.items(): for _, value in self.tokens.items():
value.spamRate = 0 value.spamRate = 0