.BANCHO. Switched from tornado to bottle + gevent, code cleaning

This commit is contained in:
Nyo 2016-08-17 16:41:05 +02:00
parent 0e74e5c1ce
commit 7910291b77
32 changed files with 463 additions and 787 deletions

View File

@ -1,8 +1,6 @@
from objects import glob from objects import glob
from constants import clientPackets from constants import clientPackets
from constants import matchModModes from constants import matchModModes
from helpers import consoleHelper
from constants import bcolors
import random import random
from constants import matchTeamTypes from constants import matchTeamTypes
from constants import matchTeams from constants import matchTeams

View File

@ -1,12 +1,9 @@
from constants import clientPackets from constants import clientPackets
from objects import glob from objects import glob
from helpers import consoleHelper
from constants import bcolors
def handle(userToken, packetData): def handle(userToken, packetData):
# Get usertoken data # Get usertoken data
userID = userToken.userID userID = userToken.userID
username = userToken.username
# Read packet data # Read packet data
packetData = clientPackets.changeSlot(packetData) packetData = clientPackets.changeSlot(packetData)

View File

@ -1,6 +1,3 @@
"""
Event called when someone parts a channel
"""
from constants import clientPackets from constants import clientPackets
from helpers import chatHelper as chat from helpers import chatHelper as chat

View File

@ -2,27 +2,22 @@ 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
from helpers import requestHelper
def handle(tornadoRequest): def handle(bottleRequest):
# Data to return # Data to return
responseTokenString = "ayy" responseTokenString = "ayy"
responseData = bytes() responseData = bytes()
# Get IP from tornado request # Get IP from tornado request
requestIP = tornadoRequest.getRequestIP() requestIP = requestHelper.getRequestIP(bottleRequest)
# Avoid exceptions # Avoid exceptions
clientData = ["unknown", "unknown", "unknown", "unknown", "unknown"] clientData = ["unknown", "unknown", "unknown", "unknown", "unknown"]
@ -30,7 +25,8 @@ def handle(tornadoRequest):
# Split POST body so we can get username/password/hardware data # Split POST body so we can get username/password/hardware data
# 2:-3 thing is because requestData has some escape stuff that we don't need # 2:-3 thing is because requestData has some escape stuff that we don't need
loginData = str(tornadoRequest.request.body)[2:-3].split("\\n") postBody = bottleRequest.body.read()
loginData = str(postBody)[2:-3].split("\\n")
try: try:
# If true, print error to console # If true, print error to console
err = False err = False

View File

@ -1,6 +1,4 @@
from objects import glob from objects import glob
from helpers import consoleHelper
from constants import bcolors
from constants import serverPackets from constants import serverPackets
import time import time
from helpers import logHelper as log from helpers import logHelper as log

View File

@ -1,7 +1,6 @@
from objects import glob from objects import glob
from constants import slotStatuses from constants import slotStatuses
from constants import serverPackets from constants import serverPackets
from helpers import logHelper as log
def handle(userToken, packetData): def handle(userToken, packetData):
# Get usertoken data # Get usertoken data

View File

@ -1,5 +1,4 @@
from objects import glob from objects import glob
from events import channelPartEvent
from helpers import logHelper as log from helpers import logHelper as log
from helpers import chatHelper as chat from helpers import chatHelper as chat

View File

@ -1,5 +1,4 @@
from objects import glob from objects import glob
from helpers import chatHelper as chat
def handle(userToken, _): def handle(userToken, _):
# get data from usertoken # get data from usertoken

View File

@ -1,6 +1,4 @@
from constants import clientPackets
from constants import serverPackets from constants import serverPackets
from helpers import userHelper
from helpers import logHelper as log from helpers import logHelper as log
def handle(userToken, packetData): def handle(userToken, packetData):

View File

@ -0,0 +1,37 @@
from constants import exceptions
import json
from objects import glob
from helpers import chatHelper
import bottle
@bottle.route("/api/v1/fokabotMessage")
def GETApiFokabotMessage():
statusCode = 400
data = {"message": "unknown error"}
try:
# Check arguments
if "k" not in bottle.request.query or "to" not in bottle.request.query or "msg" not in bottle.request.query:
raise exceptions.invalidArgumentsException()
# Check ci key
key = bottle.request.query["k"]
if key is None or key != glob.conf.config["server"]["cikey"]:
raise exceptions.invalidArgumentsException()
# Send chat message
chatHelper.sendMessage("FokaBot", bottle.request.query["to"], bottle.request.query["msg"])
# Status code and message
statusCode = 200
data["message"] = "ok"
except exceptions.invalidArgumentsException:
statusCode = 400
data["message"] = "invalid parameters"
finally:
# Add status code to data
data["status"] = statusCode
# Send response
bottle.response.status = statusCode
bottle.response.add_header("Content-Type", "application/json")
yield json.dumps(data)

View File

@ -1,36 +1,32 @@
from helpers import requestHelper
from constants import exceptions from constants import exceptions
import json import json
from objects import glob from objects import glob
import bottle
class handler(requestHelper.asyncRequestHandler): @bottle.route("/api/v1/isOnline")
def asyncGet(self): def GETApiIsOnline():
statusCode = 400
data = {"message": "unknown error"}
try:
# Check arguments
if "u" not in bottle.request.query:
raise exceptions.invalidArgumentsException()
# Get online staus
username = bottle.request.query["u"]
data["result"] = True if glob.tokens.getTokenFromUsername(username) != None else False
# Status code and message
statusCode = 200
data["message"] = "ok"
except exceptions.invalidArgumentsException:
statusCode = 400 statusCode = 400
data = {"message": "unknown error"} data["message"] = "missing required arguments"
try: finally:
# Check arguments # Add status code to data
if requestHelper.checkArguments(self.request.arguments, ["u"]) == False: data["status"] = statusCode
raise exceptions.invalidArgumentsException()
# Get online staus # Send response
username = self.get_argument("u") bottle.response.status = statusCode
if username == None: bottle.response.add_header("Content-Type", "application/json")
data["result"] = False yield json.dumps(data)
else:
data["result"] = True if glob.tokens.getTokenFromUsername(username) != None else False
# Status code and message
statusCode = 200
data["message"] = "ok"
except exceptions.invalidArgumentsException:
statusCode = 400
data["message"] = "missing required arguments"
finally:
# Add status code to data
data["status"] = statusCode
# Send response
#self.clear()
self.write(json.dumps(data))
self.set_status(statusCode)
#self.finish(json.dumps(data))

View File

@ -1,24 +1,23 @@
from helpers import requestHelper
import json import json
from objects import glob from objects import glob
import bottle
class handler(requestHelper.asyncRequestHandler): @bottle.route("/api/v1/onlineUsers")
def asyncGet(self): def GETApiOnlineUsers():
statusCode = 400 statusCode = 400
data = {"message": "unknown error"} data = {"message": "unknown error"}
try: try:
# Get online users count # Get online users count
data["result"] = len(glob.tokens.tokens) data["result"] = len(glob.tokens.tokens)
# Status code and message # Status code and message
statusCode = 200 statusCode = 200
data["message"] = "ok" data["message"] = "ok"
finally: finally:
# Add status code to data # Add status code to data
data["status"] = statusCode data["status"] = statusCode
# Send response # Send response
#self.clear() bottle.response.status = statusCode
self.write(json.dumps(data)) bottle.response.add_header("Content-Type", "application/json")
self.set_status(statusCode) yield json.dumps(data)
#self.finish(json.dumps(data))

View File

@ -1,24 +1,23 @@
from helpers import requestHelper
import json import json
from objects import glob from objects import glob
import bottle
class handler(requestHelper.asyncRequestHandler): @bottle.route("/api/v1/serverStatus")
def asyncGet(self): def GETApiServerStatus():
statusCode = 400 statusCode = 400
data = {"message": "unknown error"} data = {"message": "unknown error"}
try: try:
# Get online users count # Get online users count
data["result"] = -1 if glob.restarting == True else 1 data["result"] = -1 if glob.restarting == True else 1
# Status code and message # Status code and message
statusCode = 200 statusCode = 200
data["message"] = "ok" data["message"] = "ok"
finally: finally:
# Add status code to data # Add status code to data
data["status"] = statusCode data["status"] = statusCode
# Send response # Send response
#self.clear() bottle.response.status = statusCode
self.write(json.dumps(data)) bottle.response.add_header("Content-Type", "application/json")
self.set_status(statusCode) yield json.dumps(data)
#self.finish(json.dumps(data))

View File

@ -1,46 +1,48 @@
from helpers import requestHelper
from helpers import logHelper as log
import json import json
from objects import glob from objects import glob
from constants import exceptions from constants import exceptions
import bottle
class handler(requestHelper.asyncRequestHandler): @bottle.route("/api/v1/verifiedStatus")
def asyncGet(self): def GETApiVerifiedStatus():
statusCode = 400
data = {"message": "unknown error"}
try:
# Check arguments
if "u" not in bottle.request.query:
raise exceptions.invalidArgumentsException()
# Get userID and its verified cache thing
# -1: Not in cache
# 0: Not verified (multiacc)
# 1: Verified
userID = bottle.request.query["u"]
callback = None
if "callback" in bottle.request.query:
callback = bottle.request.query["callback"]
data["result"] = -1 if userID not in glob.verifiedCache else glob.verifiedCache[userID]
# Status code and message
statusCode = 200
data["message"] = "ok"
except exceptions.invalidArgumentsException:
statusCode = 400 statusCode = 400
data = {"message": "unknown error"} data["message"] = "missing required arguments"
try: finally:
# Check arguments # Add status code to data
if requestHelper.checkArguments(self.request.arguments, ["u"]) == False: data["status"] = statusCode
raise exceptions.invalidArgumentsException()
# Get userID and its verified cache thing # Send response
# -1: Not in cache bottle.response.add_header("Access-Control-Allow-Origin", "*")
# 0: Not verified (multiacc) bottle.response.add_header("Content-Type", "application/json")
# 1: Verified
userID = self.get_argument("u")
data["result"] = -1 if userID not in glob.verifiedCache else glob.verifiedCache[userID]
# Status code and message # jquery meme
statusCode = 200 output = ""
data["message"] = "ok" if callback != None:
except exceptions.invalidArgumentsException: output += callback+"("
statusCode = 400 output += json.dumps(data)
data["message"] = "missing required arguments" if callback != None:
finally: output += ")"
# Add status code to data
data["status"] = statusCode
# Send response bottle.response.status = statusCode
self.add_header("Access-Control-Allow-Origin", "*") yield output
self.add_header("Content-Type", "application/json")
# jquery meme
output = ""
if "callback" in self.request.arguments:
output += self.get_argument("callback")+"("
output += json.dumps(data)
if "callback" in self.request.arguments:
output += ")"
self.write(output)
self.set_status(statusCode)

View File

@ -1,39 +1,38 @@
from helpers import requestHelper
from constants import exceptions from constants import exceptions
import json import json
from objects import glob from objects import glob
from helpers import systemHelper from helpers import systemHelper
from helpers import logHelper as log from helpers import logHelper as log
import bottle
class handler(requestHelper.asyncRequestHandler): @bottle.route("/api/v1/ciTrigger")
def asyncGet(self): def GETCiTrigger():
statusCode = 400 statusCode = 400
data = {"message": "unknown error"} data = {"message": "unknown error"}
try: try:
# Check arguments # Check arguments
if requestHelper.checkArguments(self.request.arguments, ["k"]) == False: if "k" not in bottle.request.query:
raise exceptions.invalidArgumentsException() raise exceptions.invalidArgumentsException()
# Check ci key # Check ci key
key = self.get_argument("k") key = bottle.request.query["k"]
if key is None or key != glob.conf.config["server"]["cikey"]: if key != glob.conf.config["server"]["cikey"]:
raise exceptions.invalidArgumentsException() raise exceptions.invalidArgumentsException()
log.info("Ci event triggered!!") log.info("Ci event triggered!!")
systemHelper.scheduleShutdown(5, False, "A new Bancho update is available and the server will be restarted in 5 seconds. Thank you for your patience.") systemHelper.scheduleShutdown(5, False, "A new Bancho update is available and the server will be restarted in 5 seconds. Thank you for your patience.")
# Status code and message # Status code and message
statusCode = 200 statusCode = 200
data["message"] = "ok" data["message"] = "ok"
except exceptions.invalidArgumentsException: except exceptions.invalidArgumentsException:
statusCode = 400 statusCode = 403
data["message"] = "invalid ci key" data["message"] = "invalid ci key"
finally: finally:
# Add status code to data # Add status code to data
data["status"] = statusCode data["status"] = statusCode
# Send response # Send response
#self.clear() bottle.response.status = statusCode
self.write(json.dumps(data)) bottle.response.add_header("Content-Type", "application/json")
self.set_status(statusCode) yield json.dumps(data)
#self.finish(json.dumps(data))

View File

@ -1,39 +0,0 @@
from helpers import requestHelper
from constants import exceptions
import json
from objects import glob
from helpers import chatHelper
from helpers import logHelper as log
class handler(requestHelper.asyncRequestHandler):
def asyncGet(self):
statusCode = 400
data = {"message": "unknown error"}
try:
# Check arguments
if requestHelper.checkArguments(self.request.arguments, ["k", "to", "msg"]) == False:
raise exceptions.invalidArgumentsException()
# Check ci key
key = self.get_argument("k")
if key is None or key != glob.conf.config["server"]["cikey"]:
raise exceptions.invalidArgumentsException()
log.info("API REQUEST FOR FOKABOT MESSAGE AAAAAAA")
chatHelper.sendMessage("FokaBot", self.get_argument("to"), self.get_argument("msg"))
# Status code and message
statusCode = 200
data["message"] = "ok"
except exceptions.invalidArgumentsException:
statusCode = 400
data["message"] = "invalid parameters"
finally:
# Add status code to data
data["status"] = statusCode
# Send response
#self.clear()
self.write(json.dumps(data))
self.set_status(statusCode)
#self.finish(json.dumps(data))

View File

@ -1,10 +1,11 @@
import bottle
import datetime import datetime
import gzip import gzip
from helpers import requestHelper
from objects import glob from objects import glob
from helpers import packetHelper
from helpers import logHelper as log
from constants import exceptions from constants import exceptions
from constants import packetIDs from constants import packetIDs
from helpers import packetHelper
from constants import serverPackets from constants import serverPackets
from events import sendPublicMessageEvent from events import sendPublicMessageEvent
from events import sendPrivateMessageEvent from events import sendPrivateMessageEvent
@ -46,219 +47,198 @@ from events import userStatsRequestEvent
from events import requestStatusUpdateEvent from events import requestStatusUpdateEvent
from events import userPanelRequestEvent from events import userPanelRequestEvent
# Exception tracking @bottle.route("/", method="POST")
import tornado.web def POSTMain():
import tornado.gen # Track time if needed
import sys if glob.outputRequestTime == True:
import traceback # Start time
from raven.contrib.tornado import SentryMixin st = datetime.datetime.now()
from helpers import logHelper as log
class handler(SentryMixin, requestHelper.asyncRequestHandler): # Client's token string and request data
@tornado.web.asynchronous requestTokenString = bottle.request.headers.get("osu-token")
@tornado.gen.engine requestData = bottle.request.body.read()
def asyncPost(self):
# Server's token string and request data
responseTokenString = "ayy"
responseData = bytes()
if requestTokenString == None:
# No token, first request. Handle login.
responseTokenString, responseData = loginEvent.handle(bottle.request)
else:
userToken = None # default value
try: try:
# Track time if needed # This is not the first packet, send response based on client's request
if glob.outputRequestTime == True: # Packet start position, used to read stacked packets
# Start time pos = 0
st = datetime.datetime.now()
# Client's token string and request data # Make sure the token exists
requestTokenString = self.request.headers.get("osu-token") if requestTokenString not in glob.tokens.tokens:
requestData = self.request.body raise exceptions.tokenNotFoundException()
# Server's token string and request data # Token exists, get its object and lock it
responseTokenString = "ayy" userToken = glob.tokens.tokens[requestTokenString]
responseData = bytes() userToken.lock.acquire()
if requestTokenString == None: # Keep reading packets until everything has been read
# No token, first request. Handle login. while pos < len(requestData):
responseTokenString, responseData = loginEvent.handle(self) # Get packet from stack starting from new packet
else: leftData = requestData[pos:]
userToken = None # default value
try:
# This is not the first packet, send response based on client's request
# Packet start position, used to read stacked packets
pos = 0
# Make sure the token exists # Get packet ID, data length and data
if requestTokenString not in glob.tokens.tokens: packetID = packetHelper.readPacketID(leftData)
raise exceptions.tokenNotFoundException() dataLength = packetHelper.readPacketLength(leftData)
packetData = requestData[pos:(pos+dataLength+7)]
# Token exists, get its object and lock it # Console output if needed
userToken = glob.tokens.tokens[requestTokenString] if glob.outputPackets == True and packetID != 4:
userToken.lock.acquire() log.debug("Incoming packet ({})({}):\n\nPacket code: {}\nPacket length: {}\nSingle packet data: {}\n".format(requestTokenString, userToken.username, str(packetID), str(dataLength), str(packetData)))
# Keep reading packets until everything has been read # Event handler
while pos < len(requestData): def handleEvent(ev):
# Get packet from stack starting from new packet def wrapper():
leftData = requestData[pos:] ev.handle(userToken, packetData)
return wrapper
# Get packet ID, data length and data eventHandler = {
packetID = packetHelper.readPacketID(leftData) # TODO: Rename packets and events
dataLength = packetHelper.readPacketLength(leftData) # TODO: Host check for multi
packetData = requestData[pos:(pos+dataLength+7)] packetIDs.client_changeAction: handleEvent(changeActionEvent),
packetIDs.client_logout: handleEvent(logoutEvent),
packetIDs.client_friendAdd: handleEvent(friendAddEvent),
packetIDs.client_friendRemove: handleEvent(friendRemoveEvent),
packetIDs.client_userStatsRequest: handleEvent(userStatsRequestEvent),
packetIDs.client_requestStatusUpdate: handleEvent(requestStatusUpdateEvent),
packetIDs.client_userPanelRequest: handleEvent(userPanelRequestEvent),
packetIDs.client_channelJoin: handleEvent(channelJoinEvent),
packetIDs.client_channelPart: handleEvent(channelPartEvent),
packetIDs.client_sendPublicMessage: handleEvent(sendPublicMessageEvent),
packetIDs.client_sendPrivateMessage: handleEvent(sendPrivateMessageEvent),
packetIDs.client_setAwayMessage: handleEvent(setAwayMessageEvent),
# Console output if needed packetIDs.client_startSpectating: handleEvent(startSpectatingEvent),
if glob.outputPackets == True and packetID != 4: packetIDs.client_stopSpectating: handleEvent(stopSpectatingEvent),
log.debug("Incoming packet ({})({}):\n\nPacket code: {}\nPacket length: {}\nSingle packet data: {}\n".format(requestTokenString, userToken.username, str(packetID), str(dataLength), str(packetData))) packetIDs.client_cantSpectate: handleEvent(cantSpectateEvent),
packetIDs.client_spectateFrames: handleEvent(spectateFramesEvent),
# Event handler packetIDs.client_joinLobby: handleEvent(joinLobbyEvent),
def handleEvent(ev): packetIDs.client_partLobby: handleEvent(partLobbyEvent),
def wrapper(): packetIDs.client_createMatch: handleEvent(createMatchEvent),
ev.handle(userToken, packetData) packetIDs.client_joinMatch: handleEvent(joinMatchEvent),
return wrapper packetIDs.client_partMatch: handleEvent(partMatchEvent),
packetIDs.client_matchChangeSlot: handleEvent(changeSlotEvent),
packetIDs.client_matchChangeSettings: handleEvent(changeMatchSettingsEvent),
packetIDs.client_matchChangePassword: handleEvent(changeMatchPasswordEvent),
packetIDs.client_matchChangeMods: handleEvent(changeMatchModsEvent),
packetIDs.client_matchReady: handleEvent(matchReadyEvent),
packetIDs.client_matchNotReady: handleEvent(matchReadyEvent),
packetIDs.client_matchLock: handleEvent(matchLockEvent),
packetIDs.client_matchStart: handleEvent(matchStartEvent),
packetIDs.client_matchLoadComplete: handleEvent(matchPlayerLoadEvent),
packetIDs.client_matchSkipRequest: handleEvent(matchSkipEvent),
packetIDs.client_matchScoreUpdate: handleEvent(matchFramesEvent),
packetIDs.client_matchComplete: handleEvent(matchCompleteEvent),
packetIDs.client_matchNoBeatmap: handleEvent(matchNoBeatmapEvent),
packetIDs.client_matchHasBeatmap: handleEvent(matchHasBeatmapEvent),
packetIDs.client_matchTransferHost: handleEvent(matchTransferHostEvent),
packetIDs.client_matchFailed: handleEvent(matchFailedEvent),
packetIDs.client_matchChangeTeam: handleEvent(matchChangeTeamEvent),
packetIDs.client_invite: handleEvent(matchInviteEvent),
}
eventHandler = { # Packets processed if in restricted mode.
# TODO: Rename packets and events # All other packets will be ignored if the user is in restricted mode
# TODO: Host check for multi packetsRestricted = [
packetIDs.client_changeAction: handleEvent(changeActionEvent), packetIDs.client_logout,
packetIDs.client_logout: handleEvent(logoutEvent), packetIDs.client_userStatsRequest,
packetIDs.client_friendAdd: handleEvent(friendAddEvent), packetIDs.client_requestStatusUpdate,
packetIDs.client_friendRemove: handleEvent(friendRemoveEvent), packetIDs.client_userPanelRequest,
packetIDs.client_userStatsRequest: handleEvent(userStatsRequestEvent), packetIDs.client_changeAction,
packetIDs.client_requestStatusUpdate: handleEvent(requestStatusUpdateEvent), packetIDs.client_channelJoin,
packetIDs.client_userPanelRequest: handleEvent(userPanelRequestEvent), packetIDs.client_channelPart,
]
packetIDs.client_channelJoin: handleEvent(channelJoinEvent),
packetIDs.client_channelPart: handleEvent(channelPartEvent),
packetIDs.client_sendPublicMessage: handleEvent(sendPublicMessageEvent),
packetIDs.client_sendPrivateMessage: handleEvent(sendPrivateMessageEvent),
packetIDs.client_setAwayMessage: handleEvent(setAwayMessageEvent),
packetIDs.client_startSpectating: handleEvent(startSpectatingEvent), # Process/ignore packet
packetIDs.client_stopSpectating: handleEvent(stopSpectatingEvent), if packetID != 4:
packetIDs.client_cantSpectate: handleEvent(cantSpectateEvent), if packetID in eventHandler:
packetIDs.client_spectateFrames: handleEvent(spectateFramesEvent), if userToken.restricted == False or (userToken.restricted == True and packetID in packetsRestricted):
eventHandler[packetID]()
else:
log.warning("Ignored packet id from {} ({}) (user is restricted)".format(requestTokenString, packetID))
else:
log.warning("Unknown packet id from {} ({})".format(requestTokenString, packetID))
packetIDs.client_joinLobby: handleEvent(joinLobbyEvent), # Update pos so we can read the next stacked packet
packetIDs.client_partLobby: handleEvent(partLobbyEvent), # +7 because we add packet ID bytes, unused byte and data length bytes
packetIDs.client_createMatch: handleEvent(createMatchEvent), pos += dataLength+7
packetIDs.client_joinMatch: handleEvent(joinMatchEvent),
packetIDs.client_partMatch: handleEvent(partMatchEvent),
packetIDs.client_matchChangeSlot: handleEvent(changeSlotEvent),
packetIDs.client_matchChangeSettings: handleEvent(changeMatchSettingsEvent),
packetIDs.client_matchChangePassword: handleEvent(changeMatchPasswordEvent),
packetIDs.client_matchChangeMods: handleEvent(changeMatchModsEvent),
packetIDs.client_matchReady: handleEvent(matchReadyEvent),
packetIDs.client_matchNotReady: handleEvent(matchReadyEvent),
packetIDs.client_matchLock: handleEvent(matchLockEvent),
packetIDs.client_matchStart: handleEvent(matchStartEvent),
packetIDs.client_matchLoadComplete: handleEvent(matchPlayerLoadEvent),
packetIDs.client_matchSkipRequest: handleEvent(matchSkipEvent),
packetIDs.client_matchScoreUpdate: handleEvent(matchFramesEvent),
packetIDs.client_matchComplete: handleEvent(matchCompleteEvent),
packetIDs.client_matchNoBeatmap: handleEvent(matchNoBeatmapEvent),
packetIDs.client_matchHasBeatmap: handleEvent(matchHasBeatmapEvent),
packetIDs.client_matchTransferHost: handleEvent(matchTransferHostEvent),
packetIDs.client_matchFailed: handleEvent(matchFailedEvent),
packetIDs.client_matchChangeTeam: handleEvent(matchChangeTeamEvent),
packetIDs.client_invite: handleEvent(matchInviteEvent),
}
# Packets processed if in restricted mode. # Token queue built, send it
# All other packets will be ignored if the user is in restricted mode responseTokenString = userToken.token
packetsRestricted = [ responseData = userToken.queue
packetIDs.client_logout, userToken.resetQueue()
packetIDs.client_userStatsRequest,
packetIDs.client_requestStatusUpdate,
packetIDs.client_userPanelRequest,
packetIDs.client_changeAction,
packetIDs.client_channelJoin,
packetIDs.client_channelPart,
]
# Process/ignore packet # Update ping time for timeout
if packetID != 4: userToken.updatePingTime()
if packetID in eventHandler: except exceptions.tokenNotFoundException:
if userToken.restricted == False or (userToken.restricted == True and packetID in packetsRestricted): # Token not found. Disconnect that user
eventHandler[packetID]() responseData = serverPackets.loginError()
else: responseData += serverPackets.notification("Whoops! Something went wrong, please login again.")
log.warning("Ignored packet id from {} ({}) (user is restricted)".format(requestTokenString, packetID)) log.warning("Received packet from unknown token ({}).".format(requestTokenString))
else: log.info("{} has been disconnected (invalid token)".format(requestTokenString))
log.warning("Unknown packet id from {} ({})".format(requestTokenString, packetID)) finally:
# Unlock token
if userToken != None:
userToken.lock.release()
# Update pos so we can read the next stacked packet if glob.outputRequestTime == True:
# +7 because we add packet ID bytes, unused byte and data length bytes # End time
pos += dataLength+7 et = datetime.datetime.now()
# Token queue built, send it # Total time:
responseTokenString = userToken.token tt = float((et.microsecond-st.microsecond)/1000)
responseData = userToken.queue log.debug("Request time: {}ms".format(tt))
userToken.resetQueue()
# Update ping time for timeout # Send server's response to client
userToken.updatePingTime() # We don't use token object because we might not have a token (failed login)
except exceptions.tokenNotFoundException: if glob.gzip == True:
# Token not found. Disconnect that user # First, write the gzipped response
responseData = serverPackets.loginError() responseData = gzip.compress(responseData, int(glob.conf.config["server"]["gziplevel"]))
responseData += serverPackets.notification("Whoops! Something went wrong, please login again.")
log.warning("Received packet from unknown token ({}).".format(requestTokenString))
log.info("{} has been disconnected (invalid token)".format(requestTokenString))
finally:
# Unlock token
if userToken != None:
userToken.lock.release()
if glob.outputRequestTime == True: # Then, add gzip headers
# End time bottle.response.add_header("Vary", "Accept-Encoding")
et = datetime.datetime.now() bottle.response.add_header("Content-Encoding", "gzip")
else:
# First, write the response
responseData = responseData
# Total time: # Add all the headers AFTER the response has been written
tt = float((et.microsecond-st.microsecond)/1000) bottle.response.status = 200
log.debug("Request time: {}ms".format(tt)) bottle.response.add_header("cho-token", responseTokenString)
bottle.response.add_header("cho-protocol", "19")
bottle.response.add_header("Content-Type", "text/html; charset=UTF-8")
yield responseData
# Send server's response to client @bottle.route("/", method="GET")
# We don't use token object because we might not have a token (failed login) def GETMain():
if glob.gzip == True: html = "<html><head><title>MA MAURO ESISTE?</title><style type='text/css'>body{width:30%}</style></head><body><pre>"
# First, write the gzipped response html += " _ __<br>"
self.write(gzip.compress(responseData, int(glob.conf.config["server"]["gziplevel"]))) html += " (_) / /<br>"
html += " ______ __ ____ ____ / /____<br>"
# Then, add gzip headers html += " / ___/ / _ \\/ _ \\/ / _ \\<br>"
self.add_header("Vary", "Accept-Encoding") html += " / / / / /_) / /_) / / ____/<br>"
self.add_header("Content-Encoding", "gzip") html += "/__/ /__/ .___/ .___/__/ \\_____/<br>"
else: html += " / / / /<br>"
# First, write the response html += " /__/ /__/<br>"
self.write(responseData) html += "<b>PYTHON > ALL VERSION</b><br><br>"
html += "<marquee style='white-space:pre;'><br>"
# Add all the headers AFTER the response has been written html += " .. o .<br>"
self.set_status(200) html += " o.o o . o<br>"
self.add_header("cho-token", responseTokenString) html += " oo...<br>"
self.add_header("cho-protocol", "19") html += " __[]__<br>"
#self.add_header("Keep-Alive", "timeout=5, max=100") html += " phwr--> _\\:D/_/o_o_o_|__ <span style=\"font-family: 'Comic Sans MS'; font-size: 8pt;\">u wot m8</span><br>"
#self.add_header("Connection", "keep-alive") html += " \\\"\"\"\"\"\"\"\"\"\"\"\"\"\"/<br>"
self.add_header("Content-Type", "text/html; charset=UTF-8") html += " \\ . .. .. . /<br>"
except: html += "^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^<br>"
log.error("Unknown error!\n```\n{}\n{}```".format(sys.exc_info(), traceback.format_exc())) 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>"
if glob.sentry: yield html
yield tornado.gen.Task(self.captureException, exc_info=True)
#finally:
# self.finish()
@tornado.web.asynchronous
@tornado.gen.engine
def asyncGet(self):
html = "<html><head><title>MA MAURO ESISTE?</title><style type='text/css'>body{width:30%}</style></head><body><pre>"
html += " _ __<br>"
html += " (_) / /<br>"
html += " ______ __ ____ ____ / /____<br>"
html += " / ___/ / _ \\/ _ \\/ / _ \\<br>"
html += " / / / / /_) / /_) / / ____/<br>"
html += "/__/ /__/ .___/ .___/__/ \\_____/<br>"
html += " / / / /<br>"
html += " /__/ /__/<br>"
html += "<b>PYTHON > ALL VERSION</b><br><br>"
html += "<marquee style='white-space:pre;'><br>"
html += " .. o .<br>"
html += " o.o o . o<br>"
html += " oo...<br>"
html += " __[]__<br>"
html += " phwr--> _\\:D/_/o_o_o_|__ <span style=\"font-family: 'Comic Sans MS'; font-size: 8pt;\">u wot m8</span><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>"
self.write(html)
#yield tornado.gen.Task(self.captureMessage, "test")
#self.finish()

View File

@ -14,14 +14,14 @@ class config:
default = True 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):
""" """
Initialize a config object Initialize a config object
__file -- filename file -- filename
""" """
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
self.config.read(self.fileName) self.config.read(self.fileName)
@ -49,7 +49,6 @@ class config:
self.config.get("db","workers") self.config.get("db","workers")
self.config.get("server","port") self.config.get("server","port")
self.config.get("server","threads")
self.config.get("server","gzip") self.config.get("server","gzip")
self.config.get("server","gziplevel") self.config.get("server","gziplevel")
self.config.get("server","cikey") self.config.get("server","cikey")
@ -94,7 +93,6 @@ class config:
self.config.add_section("server") self.config.add_section("server")
self.config.set("server", "port", "5001") self.config.set("server", "port", "5001")
self.config.set("server", "threads", "16")
self.config.set("server", "gzip", "1") self.config.set("server", "gzip", "1")
self.config.set("server", "gziplevel", "6") self.config.set("server", "gziplevel", "6")
self.config.set("server", "cikey", "changeme") self.config.set("server", "cikey", "changeme")

View File

@ -1,138 +0,0 @@
import pymysql
from constants import bcolors
from helpers import consoleHelper
import threading
from objects import glob
class db:
"""A MySQL database connection"""
connection = None
disconnected = False
pingTime = 600
def __init__(self, __host, __username, __password, __database, __pingTime = 600):
"""
Connect to MySQL database
__host -- MySQL host name
__username -- MySQL username
__password -- MySQL password
__database -- MySQL database name
__pingTime -- MySQL database ping time (default: 600)
"""
self.connection = pymysql.connect(host=__host, user=__username, password=__password, db=__database, cursorclass=pymysql.cursors.DictCursor, autocommit=True)
self.pingTime = __pingTime
self.pingLoop()
def bindParams(self, __query, __params):
"""
Replace every ? with the respective **escaped** parameter in array
__query -- query with ?s
__params -- array with params
return -- new query
"""
for i in __params:
escaped = self.connection.escape(i)
__query = __query.replace("?", str(escaped), 1)
return __query
def execute(self, __query, __params = None):
"""
Execute a SQL query
__query -- query, can contain ?s
__params -- array with params. Optional
"""
log.debug(query)
with self.connection.cursor() as cursor:
try:
# Bind params if needed
if __params != None:
__query = self.bindParams(__query, __params)
# Execute the query
cursor.execute(__query)
finally:
# Close this connection
cursor.close()
def fetch(self, __query, __params = None, __all = False):
"""
Fetch the first (or all) element(s) of SQL query result
__query -- query, can contain ?s
__params -- array with params. Optional
__all -- if true, will fetch all values. Same as fetchAll
return -- dictionary with result data or False if failed
"""
log.debug(query)
with self.connection.cursor() as cursor:
try:
# Bind params if needed
if __params != None:
__query = self.bindParams(__query, __params)
# Execute the query with binded params
cursor.execute(__query)
# Get first result and return it
if __all == False:
return cursor.fetchone()
else:
return cursor.fetchall()
finally:
# Close this connection
cursor.close()
def fetchAll(self, __query, __params = None):
"""
Fetch the all elements of SQL query result
__query -- query, can contain ?s
__params -- array with params. Optional
return -- dictionary with result data
"""
return self.fetch(__query, __params, True)
def pingLoop(self):
"""
Pings MySQL server. We need to ping/execute a query at least once every 8 hours
or the connection will die.
If called once, will recall after 30 minutes and so on, forever
CALL THIS FUNCTION ONLY ONCE!
"""
# Default loop time
time = self.pingTime
# Make sure the connection is alive
try:
# Try to ping and reconnect if not connected
self.connection.ping()
if self.disconnected == True:
# If we were disconnected, set disconnected to false and print message
self.disconnected = False
log.error("> Reconnected to MySQL server!", bcolors.GREEN)
except:
# Can't ping MySQL server. Show error and call loop in 5 seconds
log.error("[!] CRITICAL!! MySQL connection died! Make sure your MySQL server is running! Checking again in 5 seconds...", bcolors.RED)
self.disconnected = True
time = 5
# Schedule a new check (endless loop)
threading.Timer(time, self.pingLoop).start()

View File

@ -72,42 +72,42 @@ def logMessage(message, alertType = "INFO", messageColor = bcolors.ENDC, discord
def warning(message, discord = None, alertDev = False): def warning(message, discord = None, alertDev = False):
""" """
Log a warning to stdout, warnings.log (always) and discord (optional) Log a warning to stdout (always) and discord (optional)
message -- warning message message -- warning message
discord -- if not None, send message to that discord channel through schiavo. Optional. Default = None discord -- if not None, send message to that discord channel through schiavo. Optional. Default = None
alertDev -- if True, send al hl to devs on discord. Optional. Default = False. alertDev -- if True, send al hl to devs on discord. Optional. Default = False.
""" """
logMessage(message, "WARNING", bcolors.YELLOW, discord, alertDev, "warnings.txt") logMessage(message, "WARNING", bcolors.YELLOW, discord, alertDev)
def error(message, discord = None, alertDev = True): def error(message, discord = None, alertDev = True):
""" """
Log an error to stdout, errors.log (always) and discord (optional) Log an error to stdout (always) and discord (optional)
message -- error message message -- error message
discord -- if not None, send message to that discord channel through schiavo. Optional. Default = None discord -- if not None, send message to that discord channel through schiavo. Optional. Default = None
alertDev -- if True, send al hl to devs on discord. Optional. Default = False. alertDev -- if True, send al hl to devs on discord. Optional. Default = False.
""" """
logMessage(message, "ERROR", bcolors.RED, discord, alertDev, "errors.txt") logMessage(message, "ERROR", bcolors.RED, discord, alertDev)
def info(message, discord = None, alertDev = False): def info(message, discord = None, alertDev = False):
""" """
Log an error to stdout (and info.log) Log an info message to stdout
message -- info message message -- info message
discord -- if not None, send message to that discord channel through schiavo. Optional. Default = None discord -- if not None, send message to that discord channel through schiavo. Optional. Default = None
alertDev -- if True, send al hl to devs on discord. Optional. Default = False. alertDev -- if True, send al hl to devs on discord. Optional. Default = False.
""" """
logMessage(message, "INFO", bcolors.ENDC, discord, alertDev, "info.txt") logMessage(message, "INFO", bcolors.ENDC, discord, alertDev)
def debug(message): def debug(message):
""" """
Log a debug message to stdout and debug.log if server is running in debug mode Log a debug message to stdout if server is running in debug mode
message -- debug message message -- debug message
""" """
if glob.debug == True: if glob.debug == True:
logMessage(message, "DEBUG", bcolors.PINK, of="debug.txt") logMessage(message, "DEBUG", bcolors.PINK)
def chat(message): def chat(message):
""" """

View File

@ -1,86 +1,7 @@
import tornado
import tornado.web
import tornado.gen
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
class asyncRequestHandler(tornado.web.RequestHandler): def getRequestIP(bottleRequest):
""" realIP = bottleRequest.headers.get("X-Forwarded-For") if glob.cloudflare == True else bottleRequest.headers.get("X-Real-IP")
Tornado asynchronous request handler if realIP != None:
create a class that extends this one (requestHelper.asyncRequestHandler) return realIP
use asyncGet() and asyncPost() instad of get() and post(). return bottleRequest.environ.get("REMOTE_ADDR")
Done. I'm not kidding.
"""
@tornado.web.asynchronous
@tornado.gen.engine
def get(self, *args, **kwargs):
try:
yield tornado.gen.Task(runBackground, (self.asyncGet, tuple(args), dict(kwargs)))
except Exception as e:
yield tornado.gen.Task(self.captureException, exc_info=True)
finally:
if not self._finished:
self.finish()
@tornado.web.asynchronous
@tornado.gen.engine
def post(self, *args, **kwargs):
try:
yield tornado.gen.Task(runBackground, (self.asyncPost, tuple(args), dict(kwargs)))
except Exception as e:
yield tornado.gen.Task(self.captureException, exc_info=True)
finally:
if not self._finished:
self.finish()
def asyncGet(self, *args, **kwargs):
self.send_error(405)
self.finish()
def asyncPost(self, *args, **kwargs):
self.send_error(405)
self.finish()
def getRequestIP(self):
realIP = self.request.headers.get("X-Forwarded-For") if glob.cloudflare == True else self.request.headers.get("X-Real-IP")
if realIP != None:
return realIP
return self.request.remote_ip
def runBackground(data, callback):
"""
Run a function in the background.
Used to handle multiple requests at the same time
"""
func, args, kwargs = data
def _callback(result):
IOLoop.instance().add_callback(lambda: callback(result))
glob.pool.apply_async(func, args, kwargs, _callback)
def checkArguments(arguments, requiredArguments):
"""
Check that every requiredArguments elements are in arguments
arguments -- full argument list, from tornado
requiredArguments -- required arguments list es: ["u", "ha"]
handler -- handler string name to print in exception. Optional
return -- True if all arguments are passed, none if not
"""
for i in requiredArguments:
if i not in arguments:
return False
return True
def printArguments(t):
"""
Print passed arguments, for debug purposes
t -- tornado object (self)
"""
print("ARGS::")
for i in t.request.arguments:
print ("{}={}".format(i, t.get_argument(i)))

View File

@ -8,14 +8,14 @@ class banchoConfig:
config = {"banchoMaintenance": False, "freeDirect": True, "menuIcon": "", "loginNotification": ""} config = {"banchoMaintenance": False, "freeDirect": True, "menuIcon": "", "loginNotification": ""}
def __init__(self, __loadFromDB = True): def __init__(self, loadFromDB = True):
""" """
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. Default: True]
""" """
if __loadFromDB: if loadFromDB:
try: try:
self.loadSettings() self.loadSettings()
except: except:
@ -31,12 +31,12 @@ class banchoConfig:
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

@ -5,22 +5,22 @@ class channel:
A chat channel A chat channel
""" """
def __init__(self, __name, __description, __publicRead, __publicWrite, temp, hidden): def __init__(self, name, description, publicRead, publicWrite, temp, hidden):
""" """
Create a new chat channel object Create a new chat channel object
__name -- channel name name -- channel name
__description -- channel description description -- channel description
__publicRead -- bool, if true channel can be read by everyone, if false it can be read only by mods/admins publicRead -- bool, if true channel can be read by everyone, if false it can be read only by mods/admins
__publicWrite -- bool, same as public read but relative to write permissions publicWrite -- bool, same as public read but relative to write permissions
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
self.publicWrite = __publicWrite self.publicWrite = publicWrite
self.moderated = False self.moderated = False
self.temp = temp self.temp = temp
self.connectedUsers = [999] # Fokabot is always connected to every channels (otherwise it doesn't show up in IRC users list) self.connectedUsers = [999] # Fokabot is always connected to every channels (otherwise it doesn't show up in IRC users list)
@ -34,26 +34,26 @@ class channel:
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)
# Remove temp channels if empty or there's only fokabot connected # Remove temp channels if empty or there's only fokabot connected
l = len(self.connectedUsers) l = len(self.connectedUsers)

View File

@ -56,6 +56,7 @@ 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

@ -12,23 +12,17 @@ npRegex = re.compile("^https?:\\/\\/osu\\.ppy\\.sh\\/b\\/(\\d*)")
def connect(): def connect():
"""Add FokaBot to connected users and send userpanel/stats packet to everyone""" """Add FokaBot to connected users and send userpanel/stats packet to everyone"""
token = glob.tokens.addToken(999) token = glob.tokens.addToken(999)
token.actionID = actions.idle token.actionID = actions.idle
glob.tokens.enqueueAll(serverPackets.userPanel(999)) glob.tokens.enqueueAll(serverPackets.userPanel(999))
####glob.tokens.enqueueAll(serverPackets.userStats(999)) glob.tokens.enqueueAll(serverPackets.userStats(999))
# NOTE: Debug thing to set all users as connected
#users = glob.db.fetchAll("SELECT id FROM users")
#for i in users:
# t = glob.tokens.addToken(i["id"])
# t.actionID = actions.idle
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)
@ -39,7 +33,6 @@ def fokabotResponse(fro, chan, message):
return -- fokabot's response string or False return -- fokabot's response string or False
""" """
for i in fokabotCommands.commands: for i in fokabotCommands.commands:
# Loop though all commands # Loop though all commands
#if i["trigger"] in message: #if i["trigger"] in message:

View File

@ -20,7 +20,6 @@ tokens = tokenList.tokenList()
channels = channelList.channelList() channels = channelList.channelList()
matches = matchList.matchList() matches = matchList.matchList()
restarting = False restarting = False
pool = None
fLocks = fileLocks.fileLocks() fLocks = fileLocks.fileLocks()
verifiedCache = {} verifiedCache = {}
cloudflare = False cloudflare = False

View File

@ -1,24 +0,0 @@
'''
import threading
class task:
def __init__(self, function, args = (), kwargs = {}):
self.function = function
self.args = args
self.kwargs = kwargs
class logThread:
def __init__(self):
self.thread = threading.Thread()
self.queue = []
def enqueue(self, function, args = (), kwargs = {}):
self.queue.append(task(function, args, kwargs))
def run(self):
for i in self.queue:
self.thread = threading.Thread(i.function, i.args, i.kwargs)
self.thread.run()
self.thread.join()
self.queue = []
'''

View File

@ -29,29 +29,29 @@ class match:
matchModMode = matchModModes.normal matchModMode = matchModModes.normal
seed = 0 seed = 0
def __init__(self, __matchID, __matchName, __matchPassword, __beatmapID, __beatmapName, __beatmapMD5, __gameMode, __hostUserID): def __init__(self, matchID, matchName, matchPassword, beatmapID, beatmapName, beatmapMD5, gameMode, hostUserID):
""" """
Create a new match object Create a new match object
__matchID -- match progressive identifier matchID -- match progressive identifier
__matchName -- match name, string matchName -- match name, string
__matchPassword -- match md5 password. Leave empty for no password matchPassword -- match md5 password. Leave empty for no password
__beatmapID -- beatmap ID beatmapID -- beatmap ID
__beatmapName -- beatmap name, string beatmapName -- beatmap name, string
__beatmapMD5 -- beatmap md5 hash, string beatmapMD5 -- beatmap md5 hash, string
__gameMode -- game mode ID. See gameModes.py gameMode -- game mode ID. See gameModes.py
__hostUserID -- user id of the host hostUserID -- user id of the host
""" """
self.matchID = __matchID self.matchID = matchID
self.inProgress = False self.inProgress = False
self.mods = 0 self.mods = 0
self.matchName = __matchName self.matchName = matchName
self.matchPassword = __matchPassword self.matchPassword = matchPassword
self.beatmapID = __beatmapID self.beatmapID = beatmapID
self.beatmapName = __beatmapName self.beatmapName = beatmapName
self.beatmapMD5 = __beatmapMD5 self.beatmapMD5 = beatmapMD5
self.hostUserID = __hostUserID self.hostUserID = hostUserID
self.gameMode = __gameMode self.gameMode = gameMode
self.matchScoringTypes = matchScoringTypes.score # default values self.matchScoringTypes = matchScoringTypes.score # default values
self.matchTeamType = matchTeamTypes.headToHead # default value self.matchTeamType = matchTeamTypes.headToHead # default value
self.matchModMode = matchModModes.normal # default value self.matchModMode = matchModModes.normal # default value
@ -618,8 +618,6 @@ class match:
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):

View File

@ -13,50 +13,50 @@ class matchList:
self.usersInLobby = [] self.usersInLobby = []
self.lastID = 1 self.lastID = 1
def createMatch(self, __matchName, __matchPassword, __beatmapID, __beatmapName, __beatmapMD5, __gameMode, __hostUserID): def createMatch(self, matchName, matchPassword, beatmapID, beatmapName, beatmapMD5, gameMode, hostUserID):
""" """
Add a new match to matches list Add a new match to matches list
__matchName -- match name, string matchName -- match name, string
__matchPassword -- match md5 password. Leave empty for no password matchPassword -- match md5 password. Leave empty for no password
__beatmapID -- beatmap ID beatmapID -- beatmap ID
__beatmapName -- beatmap name, string beatmapName -- beatmap name, string
__beatmapMD5 -- beatmap md5 hash, string beatmapMD5 -- beatmap md5 hash, string
__gameMode -- game mode ID. See gameModes.py gameMode -- game mode ID. See gameModes.py
__hostUserID -- user id of who created the match hostUserID -- user id of who created the match
return -- match ID return -- match ID
""" """
# Add a new match to matches list # Add a new match to matches list
matchID = self.lastID matchID = self.lastID
self.lastID+=1 self.lastID+=1
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):

View File

@ -35,11 +35,11 @@ class token:
""" """
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
__userID -- user associated to this token userID -- user associated to this token
token -- if passed, set token to that value token -- if passed, set token to that value
if not passed, token will be generated if not passed, token will be generated
ip -- client ip. optional. ip -- client ip. optional.
@ -47,7 +47,7 @@ class token:
""" """
# Set stuff # Set stuff
self.userID = __userID self.userID = userID
self.username = userHelper.getUsername(self.userID) self.username = userHelper.getUsername(self.userID)
self.privileges = userHelper.getPrivileges(self.userID) self.privileges = userHelper.getPrivileges(self.userID)
self.admin = userHelper.isInPrivilegeGroup(self.userID, "developer") or userHelper.isInPrivilegeGroup(self.userID, "community manager") self.admin = userHelper.isInPrivilegeGroup(self.userID, "developer") or userHelper.isInPrivilegeGroup(self.userID, "community manager")
@ -102,12 +102,6 @@ class token:
if ip != "": if ip != "":
userHelper.saveBanchoSession(self.userID, self.ip) userHelper.saveBanchoSession(self.userID, self.ip)
# If we are restricted, send message from FokaBot to user
# NOTE: Sent later
#if self.restricted == True:
# self.setRestricted()
def enqueue(self, __bytes): def enqueue(self, __bytes):
""" """
Add bytes (packets) to queue Add bytes (packets) to queue
@ -164,11 +158,11 @@ class token:
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):
@ -176,24 +170,24 @@ class token:
self.spectating = 0 self.spectating = 0
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): def setCountry(self, __countryID):

65
pep.py
View File

@ -1,17 +1,12 @@
"""Hello, pep.py here, ex-owner of ripple and prime minister of Ripwot.""" """Hello, pep.py here, ex-owner of ripple and prime minister of Ripwot."""
import sys import sys
import os import os
from multiprocessing.pool import ThreadPool
import threading import threading
# Tornado # Bottle
import tornado.ioloop import bottle
import tornado.web from gevent import monkey as brit_monkey
import tornado.httpserver brit_monkey.patch_all()
import tornado.gen
# Raven
from raven.contrib.tornado import AsyncSentryClient
# pep.py files # pep.py files
from constants import bcolors from constants import bcolors
@ -25,27 +20,13 @@ from helpers import databaseHelperNew
from helpers import generalFunctions from helpers import generalFunctions
from helpers import logHelper as log from helpers import logHelper as log
from handlers import mainHandler # Raven
from handlers import apiIsOnlineHandler from raven import Client
from handlers import apiOnlineUsersHandler from raven.contrib.bottle import Sentry
from handlers import apiServerStatusHandler
from handlers import ciTriggerHandler
from handlers import apiVerifiedStatusHandler
from handlers import fokabotMessageHandler
# IRC
from irc import ircserver from irc import ircserver
def make_app():
return tornado.web.Application([
(r"/", mainHandler.handler),
(r"/api/v1/isOnline", apiIsOnlineHandler.handler),
(r"/api/v1/onlineUsers", apiOnlineUsersHandler.handler),
(r"/api/v1/serverStatus", apiServerStatusHandler.handler),
(r"/api/v1/ciTrigger", ciTriggerHandler.handler),
(r"/api/v1/verifiedStatus", apiVerifiedStatusHandler.handler),
(r"/api/v1/fokabotMessage", fokabotMessageHandler.handler)
])
if __name__ == "__main__": if __name__ == "__main__":
# Server start # Server start
consoleHelper.printServerStartHeader(True) consoleHelper.printServerStartHeader(True)
@ -98,15 +79,6 @@ if __name__ == "__main__":
glob.tokens.deleteBanchoSessions() glob.tokens.deleteBanchoSessions()
consoleHelper.printDone() consoleHelper.printDone()
# Create threads pool
try:
consoleHelper.printNoNl("> Creating threads pool... ")
glob.pool = ThreadPool(int(glob.conf.config["server"]["threads"]))
consoleHelper.printDone()
except:
consoleHelper.printError()
consoleHelper.printColored("[!] Error while creating threads pool. Please check your config.ini and run the server again", bcolors.RED)
try: try:
consoleHelper.printNoNl("> Loading chat filters... ") consoleHelper.printNoNl("> Loading chat filters... ")
glob.chatFilters = chatFilters.chatFilters() glob.chatFilters = chatFilters.chatFilters()
@ -168,13 +140,21 @@ if __name__ == "__main__":
consoleHelper.printColored("[!] Warning! Server running in debug mode!", bcolors.YELLOW) consoleHelper.printColored("[!] Warning! Server running in debug mode!", bcolors.YELLOW)
# Make app # Make app
application = make_app() app = bottle.app()
app.catchall = False
from handlers import mainHandler
from handlers import apiIsOnlineHandler
from handlers import apiServerStatusHandler
from handlers import ciTriggerHandler
from handlers import apiVerifiedStatusHandler
from handlers import apiFokabotMessageHandler
# Set up sentry # Set up sentry
try: try:
glob.sentry = generalFunctions.stringToBool(glob.conf.config["sentry"]["enable"]) glob.sentry = generalFunctions.stringToBool(glob.conf.config["sentry"]["enable"])
if glob.sentry == True: if glob.sentry == True:
application.sentry_client = AsyncSentryClient(glob.conf.config["sentry"]["banchodns"], release=glob.VERSION) client = Client(glob.conf.config["sentry"]["banchodns"], release=glob.VERSION)
app = Sentry(app, client)
else: else:
consoleHelper.printColored("[!] Warning! Sentry logging is disabled!", bcolors.YELLOW) consoleHelper.printColored("[!] Warning! Sentry logging is disabled!", bcolors.YELLOW)
except: except:
@ -204,9 +184,8 @@ if __name__ == "__main__":
consoleHelper.printColored("[!] Invalid server port! Please check your config.ini and run the server again", bcolors.RED) consoleHelper.printColored("[!] Invalid server port! Please check your config.ini and run the server again", bcolors.RED)
# Server start message and console output # Server start message and console output
log.logMessage("Server started!", discord=True, of="info.txt", stdout=False) log.logMessage("Server started!", discord=True, stdout=False)
consoleHelper.printColored("> Tornado listening for HTTP(s) clients on 127.0.0.1:{}...".format(serverPort), bcolors.GREEN) consoleHelper.printColored("> Bottle listening for HTTP(s) clients on 127.0.0.1:{}...".format(serverPort), bcolors.GREEN)
# Start tornado # Start bottle
application.listen(serverPort) bottle.run(app=app, host="0.0.0.0", port=serverPort, server="gevent", quiet=True)
tornado.ioloop.IOLoop.instance().start()

View File

@ -0,0 +1 @@
1.7.0