pep.py/objects/osuToken.py

345 lines
8.6 KiB
Python
Raw Normal View History

from constants import actions
2016-05-18 17:12:46 +00:00
from constants import gameModes
from helpers import userHelper
from constants import serverPackets
from events import logoutEvent
from helpers import logHelper as log
from objects import glob
import uuid
import time
2016-06-02 17:07:33 +00:00
import threading
from helpers import chatHelper as chat
2016-04-19 17:40:59 +00:00
2016-09-02 15:45:10 +00:00
class token:
2016-09-04 08:56:10 +00:00
2016-09-02 15:45:10 +00:00
def __init__(self, userID, token_ = None, ip ="", irc = False, timeOffset = 0):
2016-04-19 17:40:59 +00:00
"""
Create a token object and set userID and token
userID -- user associated to this token
2016-06-10 11:15:42 +00:00
token -- if passed, set token to that value
2016-04-19 17:40:59 +00:00
if not passed, token will be generated
2016-06-10 11:15:42 +00:00
ip -- client ip. optional.
irc -- if True, set this token as IRC client. optional.
timeOffset -- the time offset from UTC for this user. optional.
2016-04-19 17:40:59 +00:00
"""
# Set stuff
self.userID = userID
2016-04-19 17:40:59 +00:00
self.username = userHelper.getUsername(self.userID)
self.privileges = userHelper.getPrivileges(self.userID)
self.admin = userHelper.isInPrivilegeGroup(self.userID, "developer") or userHelper.isInPrivilegeGroup(self.userID, "community manager")
self.irc = irc
self.restricted = userHelper.isRestricted(self.userID)
2016-04-19 17:40:59 +00:00
self.loginTime = int(time.time())
self.pingTime = self.loginTime
2016-08-01 18:38:26 +00:00
self.timeOffset = timeOffset
2016-06-10 11:15:42 +00:00
self.lock = threading.Lock() # Sync primitive
2016-04-19 17:40:59 +00:00
# Default variables
self.spectators = []
self.spectating = 0
self.location = [0,0]
self.joinedChannels = []
2016-06-10 11:15:42 +00:00
self.ip = ip
self.country = 0
self.location = [0,0]
2016-04-19 17:40:59 +00:00
self.awayMessage = ""
self.matchID = -1
self.tillerino = [0,0,-1.0] # beatmap, mods, acc
self.silenceEndTime = 0
self.queue = bytes()
2016-04-19 17:40:59 +00:00
# Spam protection
self.spamRate = 0
# Stats cache
2016-09-02 15:16:22 +00:00
self.actionID = actions.IDLE
self.actionText = ""
self.actionMd5 = ""
self.actionMods = 0
self.gameMode = gameModes.std
self.rankedScore = 0
self.accuracy = 0.0
self.playcount = 0
self.totalScore = 0
self.gameRank = 0
self.pp = 0
2016-04-19 17:40:59 +00:00
# Generate/set token
2016-09-02 15:45:10 +00:00
if token_ is not None:
self.token = token_
2016-04-19 17:40:59 +00:00
else:
self.token = str(uuid.uuid4())
# Set stats
self.updateCachedStats()
2016-06-10 11:15:42 +00:00
# If we have a valid ip, save bancho session in DB so we can cache LETS logins
if ip != "":
userHelper.saveBanchoSession(self.userID, self.ip)
2016-09-02 15:45:10 +00:00
def enqueue(self, bytes_):
2016-04-19 17:40:59 +00:00
"""
Add bytes (packets) to queue
bytes -- (packet) bytes to enqueue
2016-04-19 17:40:59 +00:00
"""
2016-09-02 15:45:10 +00:00
if not self.irc:
self.queue += bytes_
2016-04-19 17:40:59 +00:00
def resetQueue(self):
"""Resets the queue. Call when enqueued packets have been sent"""
self.queue = bytes()
def joinChannel(self, channel):
"""
Add channel to joined channels list
2016-04-19 17:40:59 +00:00
channel -- channel name
"""
if channel not in self.joinedChannels:
self.joinedChannels.append(channel)
2016-04-19 17:40:59 +00:00
def partChannel(self, channel):
"""
Remove channel from joined channels list
2016-04-19 17:40:59 +00:00
channel -- channel name
"""
if channel in self.joinedChannels:
self.joinedChannels.remove(channel)
2016-04-19 17:40:59 +00:00
def setLocation(self, location):
"""
Set location (latitude and longitude)
2016-04-19 17:40:59 +00:00
location -- [latitude, longitude]
"""
self.location = location
2016-04-19 17:40:59 +00:00
def getLatitude(self):
"""
Get latitude
2016-04-19 17:40:59 +00:00
return -- latitude
"""
2016-04-19 17:40:59 +00:00
return self.location[0]
def getLongitude(self):
"""
Get longitude
2016-04-19 17:40:59 +00:00
return -- longitude
"""
2016-04-19 17:40:59 +00:00
return self.location[1]
def startSpectating(self, userID):
"""
Set the spectating user to userID
2016-04-19 17:40:59 +00:00
userID -- target userID
"""
self.spectating = userID
2016-04-19 17:40:59 +00:00
def stopSpectating(self):
# Remove our userID from host's spectators
target = self.spectating
if self.spectating == 0:
return
targetToken = glob.tokens.getTokenFromUserID(target)
2016-09-02 15:45:10 +00:00
if targetToken is not 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
2016-04-19 17:40:59 +00:00
self.spectating = 0
# Console output
log.info("{} are no longer spectating {}".format(self.username, target))
2016-04-19 17:40:59 +00:00
def partMatch(self):
# Make sure we are in a match
if self.matchID == -1:
return
2016-04-19 17:40:59 +00:00
# Part #multiplayer channel
chat.partChannel(token=self, channel="#multi_{}".format(self.matchID), kick=True)
2016-04-19 17:40:59 +00:00
# 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):
"""
Add userID to our spectators
userID -- new spectator userID
"""
2016-04-19 17:40:59 +00:00
# Add userID to spectators if not already in
if userID not in self.spectators:
self.spectators.append(userID)
2016-04-19 17:40:59 +00:00
def removeSpectator(self, userID):
"""
Remove userID from our spectators
2016-04-19 17:40:59 +00:00
userID -- old spectator userID
"""
2016-04-19 17:40:59 +00:00
# Remove spectator
if userID in self.spectators:
self.spectators.remove(userID)
2016-04-19 17:40:59 +00:00
def setCountry(self, countryID):
"""
Set country to countryID
2016-04-19 17:40:59 +00:00
countryID -- numeric country ID. See countryHelper.py
"""
self.country = countryID
2016-04-19 17:40:59 +00:00
def getCountry(self):
"""
Get numeric country ID
2016-04-19 17:40:59 +00:00
return -- numeric country ID. See countryHelper.py
"""
2016-04-19 17:40:59 +00:00
return self.country
def updatePingTime(self):
"""Update latest ping time"""
self.pingTime = int(time.time())
def setAwayMessage(self, __awayMessage):
"""Set a new away message"""
self.awayMessage = __awayMessage
def joinMatch(self, matchID):
2016-04-19 17:40:59 +00:00
"""
Set match to matchID
matchID -- new match ID
2016-04-19 17:40:59 +00:00
"""
self.matchID = matchID
2016-04-19 17:40:59 +00:00
def kick(self, message="You have been kicked from the server. Please login again."):
"""
Kick this user from the server
message -- Notification message to send to this user. Optional.
"""
2016-04-19 17:40:59 +00:00
# Send packet to target
log.info("{} has been disconnected. (kick)".format(self.username))
if message != "":
self.enqueue(serverPackets.notification(message))
2016-04-19 17:40:59 +00:00
self.enqueue(serverPackets.loginFailed())
# Logout event
logoutEvent.handle(self, None)
def silence(self, seconds, reason, author = 999):
"""
Silences this user (db, packet and token)
seconds -- silence length in seconds
reason -- silence reason
author -- userID of who has silenced the target. Optional. Default: 999 (fokabot)
"""
# Silence in db and token
self.silenceEndTime = int(time.time())+seconds
2016-06-08 09:33:27 +00:00
userHelper.silence(self.userID, seconds, reason, author)
# Send silence packet to target
self.enqueue(serverPackets.silenceEndTime(seconds))
# Send silenced packet to everyone else
glob.tokens.enqueueAll(serverPackets.userSilenced(self.userID))
def spamProtection(self, increaseSpamRate = True):
"""
Silences the user if is spamming.
increaseSpamRate -- pass True if the user has sent a new message. Optional. Default: True
"""
2016-06-10 14:22:14 +00:00
# Increase the spam rate if needed
2016-09-02 15:45:10 +00:00
if increaseSpamRate:
2016-06-10 14:22:14 +00:00
self.spamRate += 1
# Silence the user if needed
if self.spamRate > 10:
self.silence(1800, "Spamming (auto spam protection)")
def isSilenced(self):
"""
Returns True if this user is silenced, otherwise False
return -- True/False
"""
return self.silenceEndTime-int(time.time()) > 0
def getSilenceSecondsLeft(self):
"""
Returns the seconds left for this user's silence
(0 if user is not silenced)
return -- silence seconds left
"""
return max(0, self.silenceEndTime-int(time.time()))
def updateCachedStats(self):
"""Update all cached stats for this token"""
stats = userHelper.getUserStats(self.userID, self.gameMode)
log.debug(str(stats))
2016-09-02 15:45:10 +00:00
if stats is None:
log.warning("Stats query returned None")
return
self.rankedScore = stats["rankedScore"]
self.accuracy = stats["accuracy"]/100
self.playcount = stats["playcount"]
self.totalScore = stats["totalScore"]
self.gameRank = stats["gameRank"]
self.pp = stats["pp"]
def checkRestricted(self, force=False):
"""
Check if this token is restricted. If so, send fokabot message
force -- If True, get restricted value from db.
If false, get the cached one. Optional. Default: False
"""
2016-09-02 15:45:10 +00:00
if force:
self.restricted = userHelper.isRestricted(self.userID)
2016-09-02 15:45:10 +00:00
if self.restricted:
self.setRestricted()
def setRestricted(self):
"""
Set this token as restricted, send FokaBot message to user
and send offline packet to everyone
"""
self.restricted = True
chat.sendMessage("FokaBot",self.username, "Your account is currently in restricted mode. Please visit ripple's website for more information.")