.BANCHO. Add IRC support, internal changes

This commit is contained in:
Nyo
2016-07-14 12:37:07 +02:00
parent 34be190aa3
commit 95df629e1c
32 changed files with 1191 additions and 351 deletions

View File

@@ -4,6 +4,7 @@ from constants import serverPackets
from helpers import userHelper
from helpers import logHelper as log
from constants import actions
from helpers import chatHelper as chat
def handle(userToken, packetData):
# Get usertoken data
@@ -58,7 +59,7 @@ def handle(userToken, packetData):
# NOTE: Remove this when osu!direct will be fixed
if userToken.actionID == actions.osuDirect and userToken.osuDirectAlert == False:
userToken.osuDirectAlert = True
userToken.enqueue(serverPackets.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!"))
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

View File

@@ -1,56 +1,7 @@
"""
Event called when someone joins a channel
"""
from constants import clientPackets
from helpers import consoleHelper
from constants import bcolors
from constants import serverPackets
from objects import glob
from constants import exceptions
from helpers import logHelper as log
from helpers import chatHelper as chat
def handle(userToken, packetData):
# Channel join packet
packetData = clientPackets.channelJoin(packetData)
joinChannel(userToken, packetData["channel"])
def joinChannel(userToken, channelName):
'''
Join a channel
userToken -- user token object of user that joins the chanlle
channelName -- name of channel
'''
try:
# Get usertoken data
username = userToken.username
userID = userToken.userID
# Check spectator channel
# If it's spectator channel, skip checks and list stuff
if channelName != "#spectator" and channelName != "#multiplayer":
# Normal channel, do check stuff
# Make sure the channel exists
if channelName not in glob.channels.channels:
raise exceptions.channelUnknownException
# Check channel permissions
if glob.channels.channels[channelName].publicRead == False and userToken.admin == False:
raise exceptions.channelNoPermissionsException
# Add our userID to users in that channel
glob.channels.channels[channelName].userJoin(userID)
# Add the channel to our joined channel
userToken.joinChannel(channelName)
# Send channel joined
userToken.enqueue(serverPackets.channelJoinSuccess(userID, channelName))
# Console output
log.info("{} joined channel {}".format(username, channelName))
except exceptions.channelNoPermissionsException:
log.warning("{} attempted to join channel {}, but they have no read permissions".format(username, channelName))
except exceptions.channelUnknownException:
log.warning("{} attempted to join an unknown channel ({})".format(username, channelName))
chat.joinChannel(token=userToken, channel=packetData["channel"])

View File

@@ -8,13 +8,14 @@ from objects import glob
from constants import clientPackets
from constants import serverPackets
from helpers import logHelper as log
from helpers import chatHelper as chat
def handle(userToken, packetData):
# Channel part packet
# Channel join packet
packetData = clientPackets.channelPart(packetData)
partChannel(userToken, packetData["channel"])
chat.partChannel(token=userToken, channel=packetData["channel"])
def partChannel(userToken, channelName, kick = False):
"""def partChannel(userToken, channelName, kick = False):
# Get usertoken data
username = userToken.username
userID = userToken.userID
@@ -34,4 +35,4 @@ def partChannel(userToken, channelName, kick = False):
userToken.enqueue(serverPackets.channelKicked(channelName))
# Console output
log.info("{} parted channel {}".format(username, channelName))
log.info("{} parted channel {}".format(username, channelName))"""

View File

@@ -3,6 +3,7 @@ from constants import serverPackets
from objects import glob
from constants import exceptions
from helpers import logHelper as log
from helpers import chatHelper as chat
def handle(userToken, packetData):
# read packet data
@@ -44,8 +45,7 @@ def joinMatch(userToken, matchID, password):
# Send packets
userToken.enqueue(serverPackets.matchJoinSuccess(matchID))
userToken.enqueue(serverPackets.channelJoinSuccess(userID, "#multiplayer"))
#userToken.enqueue(serverPackets.sendMessage("FokaBot", "#multiplayer", "Hi {}, and welcome to Ripple's multiplayer mode! This feature is still WIP and might have some issues. If you find any bugs, please report them (by clicking here)[https://ripple.moe/index.php?p=22].".format(username)))
chat.joinChannel(token=userToken, channel="#multi_{}".format(matchID))
except exceptions.matchNotFoundException:
userToken.enqueue(serverPackets.matchJoinFail())
log.warning("{} has tried to join a mp room, but it doesn't exist".format(userToken.username))

View File

@@ -8,12 +8,12 @@ from helpers import locationHelper
from helpers import countryHelper
import time
from helpers import generalFunctions
from events import channelJoinEvent
import sys
import traceback
from helpers import requestHelper
from helpers import discordBotHelper
from helpers import logHelper as log
from helpers import chatHelper as chat
def handle(tornadoRequest):
# Data to return
@@ -30,6 +30,10 @@ def handle(tornadoRequest):
# If true, print error to console
err = False
# Make sure loginData is valid
if len(loginData) < 3:
raise exceptions.haxException()
# Try to get the ID from username
username = str(loginData[0])
userID = userHelper.getID(username)
@@ -59,6 +63,9 @@ def handle(tornadoRequest):
responseToken = glob.tokens.addToken(userID, requestIP)
responseTokenString = responseToken.token
# Check restricted mode (and eventually send message)
responseToken.checkRestricted()
# Set silence end UNIX time in token
responseToken.silenceEndTime = userHelper.getSilenceEnd(userID)
@@ -101,12 +108,12 @@ def handle(tornadoRequest):
responseToken.enqueue(serverPackets.channelInfoEnd())
# Default opened channels
# TODO: Configurable default channels
channelJoinEvent.joinChannel(responseToken, "#osu")
channelJoinEvent.joinChannel(responseToken, "#announce")
chat.joinChannel(token=responseToken, channel="#osu")
chat.joinChannel(token=responseToken, channel="#announce")
# Join admin channel if we are an admin
if responseToken.admin == True:
channelJoinEvent.joinChannel(responseToken, "#admin")
chat.joinChannel(token=responseToken, channel="#admin")
# Output channels info
for key, value in glob.channels.channels.items():
@@ -156,6 +163,12 @@ def handle(tornadoRequest):
# (we don't use enqueue because we don't have a token since login has failed)
err = True
responseData += serverPackets.loginFailed()
except exceptions.haxException:
# Invalid POST data
# (we don't use enqueue because we don't have a token since login has failed)
err = True
responseData += serverPackets.loginFailed()
responseData += serverPackets.notification("I see what you're doing...")
except exceptions.loginBannedException:
# Login banned error packet
err = True
@@ -172,9 +185,14 @@ def handle(tornadoRequest):
except exceptions.need2FAException:
# User tried to log in from unknown IP
responseData += serverPackets.needVerification()
except:
log.error("Unknown error!\n```\n{}\n{}```".format(sys.exc_info(), traceback.format_exc()))
finally:
# Console and discord log
msg = "Bancho login request from {} for user {} ({})".format(requestIP, loginData[0], "failed" if err == True else "success")
if len(loginData) < 3:
msg = "Invalid bancho login request from **{}** (insufficient POST data)".format(requestIP)
else:
msg = "Bancho login request from **{}** for user **{}** ({}) **({})**".format(requestIP, loginData[0], loginData[2], "failed" if err == True else "success")
log.info(msg, True)
# Return token string and data

View File

@@ -4,8 +4,9 @@ from constants import bcolors
from constants import serverPackets
import time
from helpers import logHelper as log
from helpers import chatHelper as chat
def handle(userToken, _):
def handle(userToken, _=None):
# get usertoken data
userID = userToken.userID
username = userToken.username
@@ -15,8 +16,9 @@ def handle(userToken, _):
# the old logout packet will still be in the queue and will be sent to
# the server, so we accept logout packets sent at least 5 seconds after login
# if the user logs out before 5 seconds, he will be disconnected later with timeout check
if int(time.time()-userToken.loginTime) >= 5:
if int(time.time()-userToken.loginTime) >= 5 or userToken.irc == True:
# Stop spectating if needed
# TODO: Call stopSpectatingEvent!!!!!!!!!
if userToken.spectating != 0:
# The user was spectating someone
spectatorHostToken = glob.tokens.getTokenFromUserID(userToken.spectating)
@@ -26,13 +28,17 @@ def handle(userToken, _):
# Part all joined channels
for i in userToken.joinedChannels:
glob.channels.channels[i].userPart(userID)
chat.partChannel(token=userToken, channel=i)
# TODO: Lobby left if joined
# Enqueue our disconnection to everyone else
glob.tokens.enqueueAll(serverPackets.userLogout(userID))
# Disconnect from IRC if needed
if userToken.irc == True and glob.irc == True:
glob.ircServer.forceDisconnection(userToken.username)
# Delete token
glob.tokens.deleteToken(requestToken)

View File

@@ -1,6 +1,7 @@
from objects import glob
from events import channelPartEvent
from helpers import logHelper as log
from helpers import chatHelper as chat
def handle(userToken, _):
# Get usertoken data
@@ -11,7 +12,7 @@ def handle(userToken, _):
glob.matches.lobbyUserPart(userID)
# Part lobby channel
channelPartEvent.partChannel(userToken, "#lobby", True)
chat.partChannel(channel="#lobby", token=userToken, kick=True)
# Console output
log.info("{} has left multiplayer lobby".format(username))

View File

@@ -1,4 +1,5 @@
from objects import glob
from helpers import chatHelper as chat
from constants import serverPackets
def handle(userToken, _):
@@ -22,6 +23,8 @@ def handle(userToken, _):
# Set slot to free
match.userLeft(userID)
# Part #multiplayer channel
chat.partChannel(token=userToken, channel="#multi_{}".format(matchID))
# Set usertoken match to -1
userToken.partMatch()
userToken.enqueue(serverPackets.channelKicked("#multiplayer"))

View File

@@ -1,79 +1,7 @@
from helpers import consoleHelper
from constants import bcolors
from constants import clientPackets
from constants import serverPackets
from objects import glob
from objects import fokabot
from constants import exceptions
from constants import messageTemplates
from helpers import generalFunctions
from helpers import userHelper
from helpers import logHelper as log
import time
from helpers import chatHelper as chat
def handle(userToken, packetData):
"""
Event called when someone sends a private message
userToken -- request user token
packetData -- request data bytes
"""
try:
# Get usertoken username
username = userToken.username
userID = userToken.userID
# Make sure the user is not in restricted mode
if userToken.restricted == True:
raise exceptions.userRestrictedException
# Private message packet
packetData = clientPackets.sendPrivateMessage(packetData)
# Make sure the user is not silenced
if userToken.isSilenced() == True:
raise exceptions.userSilencedException
# Check message length
packetData["message"] = packetData["message"][:2048]+"..." if len(packetData["message"]) > 2048 else packetData["message"]
if packetData["to"] == "FokaBot":
# FokaBot command check
fokaMessage = fokabot.fokabotResponse(username, packetData["to"], packetData["message"])
if fokaMessage != False:
userToken.enqueue(serverPackets.sendMessage("FokaBot", username, fokaMessage))
log.pm("FokaBot -> {}: {}".format(packetData["to"], str(fokaMessage.encode("UTF-8"))))
else:
# Send packet message to target if it exists
token = glob.tokens.getTokenFromUsername(packetData["to"])
if token == None:
raise exceptions.tokenNotFoundException()
# Check message templates (mods/admins only)
if packetData["message"] in messageTemplates.templates and userToken.admin == True:
packetData["message"] = messageTemplates.templates[packetData["message"]]
# Send message to target
token.enqueue(serverPackets.sendMessage(username, packetData["to"], packetData["message"]))
# Send away message to sender if needed
if token.awayMessage != "":
userToken.enqueue(serverPackets.sendMessage(packetData["to"], username, "This user is away: {}".format(token.awayMessage)))
# Spam protection
userToken.spamProtection()
# Console and file output
log.pm("{} -> {}: {}".format(username, packetData["to"], packetData["message"]))
except exceptions.userSilencedException:
userToken.enqueue(serverPackets.silenceEndTime(userToken.getSilenceSecondsLeft()))
log.warning("{} tried to send a message during silence".format(username))
except exceptions.tokenNotFoundException:
# Token not found, user disconnected
log.warning("{} tried to send a message to {}, but their token couldn't be found".format(username, packetData["to"]))
except exceptions.messageTooLongException:
# Message > 256 silence
userToken.silence(2*3600, "Sending messages longer than 256 characters")
except exceptions.userRestrictedException:
pass
# Send private message packet
packetData = clientPackets.sendPrivateMessage(packetData)
chat.sendMessage(token=userToken, to=packetData["to"], message=packetData["message"])

View File

@@ -1,135 +1,7 @@
from constants import exceptions
from constants import clientPackets
from objects import glob
from objects import fokabot
from constants import serverPackets
from helpers import discordBotHelper
from helpers import logHelper as log
from helpers import userHelper
import time
from helpers import chatHelper as chat
def handle(userToken, packetData):
"""
Event called when someone sends a public message
userToken -- request user token
packetData -- request data bytes
"""
try:
# Get userToken data
userID = userToken.userID
username = userToken.username
# Make sure the user is not in restricted mode
if userToken.restricted == True:
raise exceptions.userRestrictedException
# Public chat packet
packetData = clientPackets.sendPublicMessage(packetData)
# Receivers
who = []
# Make sure the user is not silenced
if userToken.isSilenced() == True:
raise exceptions.userSilencedException
# Check message length
packetData["message"] = packetData["message"][:2048]+"..." if len(packetData["message"]) > 2048 else packetData["message"]
# Get receivers list
# Check #spectator
if packetData["to"] == "#spectator":
# Spectator channel
# Send this packet to every spectator and host
if userToken.spectating == 0:
# We have sent to send a message to our #spectator channel
targetToken = userToken
who = targetToken.spectators[:]
# No need to remove us because we are the host so we are not in spectators list
else:
# We have sent a message to someone else's #spectator
targetToken = glob.tokens.getTokenFromUserID(userToken.spectating)
who = targetToken.spectators[:]
# Remove us
if userID in who:
who.remove(userID)
# Add host
who.append(targetToken.userID)
elif packetData["to"] == "#multiplayer":
# Multiplayer Channel
# 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]
# Create targets list
who = []
for i in range(0,16):
uid = match.slots[i]["userID"]
if uid > -1 and uid != userID:
who.append(uid)
else:
# Standard channel
# Make sure the channel exists
if packetData["to"] not in glob.channels.channels:
raise exceptions.channelUnknownException
# Make sure the channel is not in moderated mode
if glob.channels.channels[packetData["to"]].moderated == True and userToken.admin == False:
raise exceptions.channelModeratedException
# Make sure we have write permissions
if glob.channels.channels[packetData["to"]].publicWrite == False and userToken.admin == False:
raise exceptions.channelNoPermissionsException
# Send this packet to everyone in that channel except us
who = glob.channels.channels[packetData["to"]].getConnectedUsers()[:]
if userID in who:
who.remove(userID)
# We have receivers
# Send packet to required users
glob.tokens.multipleEnqueue(serverPackets.sendMessage(username, packetData["to"], packetData["message"]), who, False)
# Fokabot command check
fokaMessage = fokabot.fokabotResponse(username, packetData["to"], packetData["message"])
if fokaMessage != False:
who.append(userID)
glob.tokens.multipleEnqueue(serverPackets.sendMessage("FokaBot", packetData["to"], fokaMessage), who, False)
log.chat("FokaBot @ {}: {}".format(packetData["to"], str(fokaMessage.encode("UTF-8"))))
# Spam protection
userToken.spamProtection()
# Console and file log
log.chat("{fro} @ {to}: {message}".format(fro=username, to=packetData["to"], message=str(packetData["message"].encode("utf-8"))))
# Discord log
discordBotHelper.sendChatlog("**{fro} @ {to}:** {message}".format(fro=username, to=packetData["to"], message=str(packetData["message"].encode("utf-8"))[2:-1]))
except exceptions.userSilencedException:
userToken.enqueue(serverPackets.silenceEndTime(userToken.getSilenceSecondsLeft()))
log.warning("{} tried to send a message during silence".format(username))
except exceptions.channelModeratedException:
log.warning("{} tried to send a message to a channel that is in moderated mode ({})".format(username, packetData["to"]))
except exceptions.channelUnknownException:
log.warning("{} tried to send a message to an unknown channel ({})".format(username, packetData["to"]))
except exceptions.channelNoPermissionsException:
log.warning("{} tried to send a message to channel {}, but they have no write permissions".format(username, packetData["to"]))
except exceptions.messageTooLongException:
# Message > 256 silence
userToken.silence(2*3600, "Sending messages longer than 256 characters")
except exceptions.userRestrictedException:
pass
# Send public message packet
packetData = clientPackets.sendPublicMessage(packetData)
chat.sendMessage(token=userToken, to=packetData["to"], message=packetData["message"])

View File

@@ -4,6 +4,7 @@ from constants import exceptions
from objects import glob
from helpers import userHelper
from helpers import logHelper as log
from helpers import chatHelper as chat
def handle(userToken, packetData):
try:
@@ -34,12 +35,12 @@ def handle(userToken, packetData):
# Send spectator join packet to host
targetToken.enqueue(serverPackets.addSpectator(userID))
# Join #spectator channel
userToken.enqueue(serverPackets.channelJoinSuccess(userID, "#spectator"))
# Create and join #spectator (#spect_userid) channel
glob.channels.addTempChannel("#spect_{}".format(targetToken.userID))
chat.joinChannel(token=userToken, channel="#spect_{}".format(targetToken.userID))
if len(targetToken.spectators) == 1:
# First spectator, send #spectator join to host too
targetToken.enqueue(serverPackets.channelJoinSuccess(userID, "#spectator"))
chat.joinChannel(token=targetToken, channel="#spect_{}".format(targetToken.userID))
# send fellowSpectatorJoined to all spectators
for spec in targetToken.spectators:

View File

@@ -2,6 +2,7 @@ from objects import glob
from constants import serverPackets
from constants import exceptions
from helpers import logHelper as log
from helpers import chatHelper as chat
def handle(userToken, _):
try:
@@ -16,6 +17,9 @@ def handle(userToken, _):
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:
@@ -25,8 +29,7 @@ def handle(userToken, _):
#targetToken.enqueue(serverPackets.fellowSpectatorLeft(userID))
# Console output
# TODO: Move messages in stop spectating
log.info("{} are no longer spectating whoever they were spectating".format(username))
log.info("{} are no longer spectating {}".format(username, target))
except exceptions.tokenNotFoundException:
log.warning("Spectator stop: token not found")
finally: