2016-04-19 17:40:59 +00:00
import threading
2016-10-02 20:48:14 +00:00
import time
from common . ripple import userUtils
2016-10-09 17:12:18 +00:00
from common . log import logUtils as log
from constants import serverPackets
2016-05-18 17:12:46 +00:00
from events import logoutEvent
2016-10-02 20:48:14 +00:00
from objects import glob
from objects import osuToken
2016-04-19 17:40:59 +00:00
2016-09-02 15:45:10 +00:00
class tokenList :
2016-04-19 17:40:59 +00:00
"""
List of connected osu tokens
tokens - - dictionary . key : token string , value : token object
"""
2016-06-10 14:22:14 +00:00
def __init__ ( self ) :
"""
Initialize a tokens list
"""
self . tokens = { }
2016-04-19 17:40:59 +00:00
2016-10-05 21:28:26 +00:00
def addToken ( self , userID , ip = " " , irc = False , timeOffset = 0 , tournament = False ) :
2016-04-19 17:40:59 +00:00
"""
Add a token object to tokens list
2016-06-10 11:15:42 +00:00
userID - - user id associated to that token
2016-07-14 10:37:07 +00:00
irc - - if True , set this token as IRC client
2016-04-19 17:40:59 +00:00
return - - token object
"""
2016-10-05 21:28:26 +00:00
newToken = osuToken . token ( userID , ip = ip , irc = irc , timeOffset = timeOffset , tournament = tournament )
2016-04-19 17:40:59 +00:00
self . tokens [ newToken . token ] = newToken
return newToken
2016-06-10 11:15:42 +00:00
def deleteToken ( self , token ) :
2016-04-19 17:40:59 +00:00
"""
Delete a token from token list if it exists
2016-06-10 11:15:42 +00:00
token - - token string
2016-04-19 17:40:59 +00:00
"""
2016-06-10 11:15:42 +00:00
if token in self . tokens :
# Delete session from DB
2016-07-14 10:37:07 +00:00
if self . tokens [ token ] . ip != " " :
2016-10-02 20:48:14 +00:00
userUtils . deleteBanchoSessions ( self . tokens [ token ] . userID , self . tokens [ token ] . ip )
2016-04-19 17:40:59 +00:00
2016-06-10 11:15:42 +00:00
# Pop token from list
self . tokens . pop ( token )
2016-04-19 17:40:59 +00:00
2016-06-10 11:15:42 +00:00
def getUserIDFromToken ( self , token ) :
2016-04-19 17:40:59 +00:00
"""
Get user ID from a token
2016-06-10 11:15:42 +00:00
token - - token to find
2016-09-02 10:41:19 +00:00
return - - false if not found , userID if found
2016-04-19 17:40:59 +00:00
"""
# Make sure the token exists
2016-06-10 11:15:42 +00:00
if token not in self . tokens :
2016-04-19 17:40:59 +00:00
return False
# Get userID associated to that token
2016-06-10 11:15:42 +00:00
return self . tokens [ token ] . userID
2016-04-19 17:40:59 +00:00
2016-10-01 19:19:03 +00:00
def getTokenFromUserID ( self , userID , ignoreIRC = False ) :
2016-04-19 17:40:59 +00:00
"""
Get token from a user ID
2016-06-10 11:15:42 +00:00
userID - - user ID to find
2016-04-19 17:40:59 +00:00
return - - False if not found , token object if found
"""
# Make sure the token exists
for _ , value in self . tokens . items ( ) :
2016-06-10 11:15:42 +00:00
if value . userID == userID :
2016-10-01 19:19:03 +00:00
if ignoreIRC and value . irc :
continue
2016-04-19 17:40:59 +00:00
return value
# Return none if not found
return None
2016-11-17 14:27:27 +00:00
def getTokenFromUsername ( self , username , ignoreIRC = False , safe = False ) :
2016-04-19 17:40:59 +00:00
"""
2016-11-17 14:27:27 +00:00
Get an osuToken object from an username
2016-04-19 17:40:59 +00:00
2016-11-17 14:27:27 +00:00
: param username : normal username or safe username
: param ignoreIRC : if True , consider bancho clients only and skip IRC clients
: param safe : if True , username is a safe username ,
compare it with token ' s safe username rather than normal username
: return : osuToken object or None
2016-04-19 17:40:59 +00:00
"""
# lowercase
2016-11-17 14:27:27 +00:00
who = username . lower ( ) if not safe else username
2016-04-19 17:40:59 +00:00
# Make sure the token exists
for _ , value in self . tokens . items ( ) :
2016-11-17 14:27:27 +00:00
if ( not safe and value . username . lower ( ) == who ) or ( safe and value . safeUsername == who ) :
2016-10-01 19:19:03 +00:00
if ignoreIRC and value . irc :
continue
2016-04-19 17:40:59 +00:00
return value
# Return none if not found
return None
2016-06-10 11:15:42 +00:00
def deleteOldTokens ( self , userID ) :
2016-04-19 17:40:59 +00:00
"""
Delete old userID ' s tokens if found
2016-06-10 11:15:42 +00:00
userID - - tokens associated to this user will be deleted
2016-04-19 17:40:59 +00:00
"""
# Delete older tokens
2016-07-14 10:37:07 +00:00
for key , value in list ( self . tokens . items ( ) ) :
2016-06-10 11:15:42 +00:00
if value . userID == userID :
2016-04-19 17:40:59 +00:00
# Delete this token from the dictionary
2016-10-09 17:12:18 +00:00
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. " , " kicked, multiple clients " )
2016-04-19 17:40:59 +00:00
2016-06-10 11:15:42 +00:00
def multipleEnqueue ( self , packet , who , but = False ) :
2016-04-19 17:40:59 +00:00
"""
Enqueue a packet to multiple users
2016-06-10 11:15:42 +00:00
packet - - packet bytes to enqueue
who - - userIDs array
but - - if True , enqueue to everyone but users in who array
2016-04-19 17:40:59 +00:00
"""
for _ , value in self . tokens . items ( ) :
shouldEnqueue = False
2016-06-10 11:15:42 +00:00
if value . userID in who and not but :
2016-04-19 17:40:59 +00:00
shouldEnqueue = True
2016-06-10 11:15:42 +00:00
elif value . userID not in who and but :
2016-04-19 17:40:59 +00:00
shouldEnqueue = True
if shouldEnqueue :
2016-06-10 11:15:42 +00:00
value . enqueue ( packet )
2016-04-19 17:40:59 +00:00
2016-06-10 11:15:42 +00:00
def enqueueAll ( self , packet ) :
2016-04-19 17:40:59 +00:00
"""
Enqueue packet ( s ) to every connected user
2016-06-10 11:15:42 +00:00
packet - - packet bytes to enqueue
2016-04-19 17:40:59 +00:00
"""
for _ , value in self . tokens . items ( ) :
2016-06-10 11:15:42 +00:00
value . enqueue ( packet )
2016-04-19 17:40:59 +00:00
2016-09-02 10:41:19 +00:00
def usersTimeoutCheckLoop ( self , timeoutTime = 100 , checkTime = 100 ) :
2016-04-19 17:40:59 +00:00
"""
Deletes all timed out users .
2016-09-02 10:41:19 +00:00
If called once , will recall after checkTime seconds and so on , forever
2016-04-19 17:40:59 +00:00
CALL THIS FUNCTION ONLY ONCE !
2016-09-02 10:41:19 +00:00
timeoutTime - seconds of inactivity required to disconnect someone ( Default : 100 )
checkTime - seconds between loops ( Default : 100 )
2016-04-19 17:40:59 +00:00
"""
2016-10-09 17:12:18 +00:00
log . debug ( " Checking timed out clients " )
2016-04-19 17:40:59 +00:00
timedOutTokens = [ ] # timed out users
2016-10-09 17:12:18 +00:00
timeoutLimit = int ( time . time ( ) ) - timeoutTime
2016-04-19 17:40:59 +00:00
for key , value in self . tokens . items ( ) :
# Check timeout (fokabot is ignored)
2016-10-09 17:12:18 +00:00
if value . pingTime < timeoutLimit and value . userID != 999 and value . irc == False and value . tournament == False :
2016-04-19 17:40:59 +00:00
# That user has timed out, add to disconnected tokens
# We can't delete it while iterating or items() throws an error
timedOutTokens . append ( key )
# Delete timed out users from self.tokens
# i is token string (dictionary key)
for i in timedOutTokens :
2016-10-09 17:12:18 +00:00
log . debug ( " {} timed out!! " . format ( self . tokens [ i ] . username ) )
self . tokens [ i ] . enqueue ( serverPackets . notification ( " Your connection to the server timed out. " ) )
2016-04-19 17:40:59 +00:00
logoutEvent . handle ( self . tokens [ i ] , None )
# Schedule a new check (endless loop)
2016-09-02 10:41:19 +00:00
threading . Timer ( checkTime , self . usersTimeoutCheckLoop , [ timeoutTime , checkTime ] ) . start ( )
2016-06-10 14:22:14 +00:00
def spamProtectionResetLoop ( self ) :
"""
Reset spam rate every 10 seconds .
CALL THIS FUNCTION ONLY ONCE !
"""
# Reset spamRate for every token
for _ , value in self . tokens . items ( ) :
value . spamRate = 0
# Schedule a new check (endless loop)
threading . Timer ( 10 , self . spamProtectionResetLoop ) . start ( )
2016-06-10 11:15:42 +00:00
def deleteBanchoSessions ( self ) :
"""
Truncate bancho_sessions table .
Call at bancho startup to delete old cached sessions
"""
glob . db . execute ( " TRUNCATE TABLE bancho_sessions " )
2016-07-14 10:37:07 +00:00
def tokenExists ( self , username = " " , userID = - 1 ) :
"""
Check if a token exists ( aka check if someone is connected )
username - - Optional .
userID - - Optional .
return - - True if it exists , otherwise False
Use username or userid , not both at the same time .
"""
if userID > - 1 :
return True if self . getTokenFromUserID ( userID ) is not None else False
else :
return True if self . getTokenFromUsername ( username ) is not None else False