Compare commits
26 Commits
Author | SHA1 | Date | |
---|---|---|---|
|
c6417c31ed | ||
|
9055fcaf5e | ||
|
f85640ae39 | ||
|
18a7c47db6 | ||
|
22ae4c332b | ||
|
8f156a0702 | ||
|
62b67da9fb | ||
|
501130721d | ||
|
e6cdef4580 | ||
|
00c544b7c7 | ||
|
ebf0e1d458 | ||
|
fd23cf2b2c | ||
|
8a8a4968a3 | ||
|
2ae3c5f701 | ||
|
f4c099c809 | ||
|
f8cc0c738c | ||
|
4557b08df8 | ||
|
49f8bd8cf1 | ||
|
7ba5db62b4 | ||
|
7f534f0984 | ||
|
daf457fc5c | ||
|
b4d498c26c | ||
|
44545c3bcb | ||
|
c4a6c84cec | ||
|
8532731f19 | ||
|
b836f77446 |
7
.landscape.yaml
Normal file
7
.landscape.yaml
Normal file
@@ -0,0 +1,7 @@
|
|||||||
|
python-targets:
|
||||||
|
- 3
|
||||||
|
pep8:
|
||||||
|
none: true
|
||||||
|
pylint:
|
||||||
|
disable:
|
||||||
|
- cyclic-import
|
@@ -1,4 +1,4 @@
|
|||||||
## pep.py
|
## pep.py [](https://landscape.io/github/osuripple/pep.py/master)
|
||||||
|
|
||||||
- Origin: https://git.zxq.co/ripple/pep.py
|
- Origin: https://git.zxq.co/ripple/pep.py
|
||||||
- Mirror: https://github.com/osuripple/pep.py
|
- Mirror: https://github.com/osuripple/pep.py
|
||||||
|
2
common
2
common
Submodule common updated: 3288420cd8...6329b9ac2d
@@ -89,4 +89,16 @@ class unknownStreamException(Exception):
|
|||||||
pass
|
pass
|
||||||
|
|
||||||
class userTournamentException(Exception):
|
class userTournamentException(Exception):
|
||||||
|
pass
|
||||||
|
|
||||||
|
class userAlreadyInChannelException(Exception):
|
||||||
|
pass
|
||||||
|
|
||||||
|
class userNotInChannelException(Exception):
|
||||||
|
pass
|
||||||
|
|
||||||
|
class missingReportInfoException(Exception):
|
||||||
|
pass
|
||||||
|
|
||||||
|
class invalidUserException(Exception):
|
||||||
pass
|
pass
|
@@ -1,7 +1,9 @@
|
|||||||
import json
|
import json
|
||||||
import random
|
import random
|
||||||
|
import re
|
||||||
|
|
||||||
import requests
|
import requests
|
||||||
|
import time
|
||||||
|
|
||||||
from common import generalUtils
|
from common import generalUtils
|
||||||
from common.constants import mods
|
from common.constants import mods
|
||||||
@@ -14,6 +16,7 @@ from constants import serverPackets
|
|||||||
from helpers import systemHelper
|
from helpers import systemHelper
|
||||||
from objects import fokabot
|
from objects import fokabot
|
||||||
from objects import glob
|
from objects import glob
|
||||||
|
from helpers import chatHelper as chat
|
||||||
|
|
||||||
"""
|
"""
|
||||||
Commands callbacks
|
Commands callbacks
|
||||||
@@ -119,15 +122,18 @@ def kickAll(fro, chan, message):
|
|||||||
|
|
||||||
def kick(fro, chan, message):
|
def kick(fro, chan, message):
|
||||||
# Get parameters
|
# Get parameters
|
||||||
target = message[0].replace("_", " ")
|
target = message[0].lower().replace("_", " ")
|
||||||
|
if target == "fokabot":
|
||||||
|
return "Nope."
|
||||||
|
|
||||||
# Get target token and make sure is connected
|
# Get target token and make sure is connected
|
||||||
targetToken = glob.tokens.getTokenFromUsername(target)
|
tokens = glob.tokens.getTokenFromUsername(target, _all=True)
|
||||||
if targetToken is None:
|
if len(tokens) == 0:
|
||||||
return "{} is not online".format(target)
|
return "{} is not online".format(target)
|
||||||
|
|
||||||
# Kick user
|
# Kick users
|
||||||
targetToken.kick()
|
for i in tokens:
|
||||||
|
i.kick()
|
||||||
|
|
||||||
# Bot response
|
# Bot response
|
||||||
return "{} has been kicked from the server.".format(target)
|
return "{} has been kicked from the server.".format(target)
|
||||||
@@ -380,7 +386,7 @@ def getPPMessage(userID, just_data = False):
|
|||||||
currentAcc = token.tillerino[2]
|
currentAcc = token.tillerino[2]
|
||||||
|
|
||||||
# Send request to LETS api
|
# Send request to LETS api
|
||||||
resp = requests.get("http://127.0.0.1:5002/api/v1/pp?b={}&m={}".format(currentMap, currentMods, currentAcc), timeout=10).text
|
resp = requests.get("http://127.0.0.1:5002/api/v1/pp?b={}&m={}".format(currentMap, currentMods), timeout=10).text
|
||||||
data = json.loads(resp)
|
data = json.loads(resp)
|
||||||
|
|
||||||
# Make sure status is in response data
|
# Make sure status is in response data
|
||||||
@@ -656,7 +662,7 @@ def pp(fro, chan, message):
|
|||||||
pp = userUtils.getPP(token.userID, gameMode)
|
pp = userUtils.getPP(token.userID, gameMode)
|
||||||
return "You have {:,} pp".format(pp)
|
return "You have {:,} pp".format(pp)
|
||||||
|
|
||||||
def updateBeatmap(fro, chan, to):
|
def updateBeatmap(fro, chan, message):
|
||||||
try:
|
try:
|
||||||
# Run the command in PM only
|
# Run the command in PM only
|
||||||
if chan.startswith("#"):
|
if chan.startswith("#"):
|
||||||
@@ -691,6 +697,69 @@ def updateBeatmap(fro, chan, to):
|
|||||||
except:
|
except:
|
||||||
return False
|
return False
|
||||||
|
|
||||||
|
def report(fro, chan, message):
|
||||||
|
msg = ""
|
||||||
|
try:
|
||||||
|
# TODO: Rate limit
|
||||||
|
# Regex on message
|
||||||
|
reportRegex = re.compile("^(.+) \((.+)\)\:(?: )?(.+)?$")
|
||||||
|
result = reportRegex.search(" ".join(message))
|
||||||
|
|
||||||
|
# Make sure the message matches the regex
|
||||||
|
if result is None:
|
||||||
|
raise exceptions.invalidArgumentsException()
|
||||||
|
|
||||||
|
# Get username, report reason and report info
|
||||||
|
target, reason, additionalInfo = result.groups()
|
||||||
|
target = chat.fixUsernameForBancho(target)
|
||||||
|
|
||||||
|
# Make sure the target is not foka
|
||||||
|
if target.lower() == "fokabot":
|
||||||
|
raise exceptions.invalidUserException()
|
||||||
|
|
||||||
|
# Make sure the user exists
|
||||||
|
targetID = userUtils.getID(target)
|
||||||
|
if targetID == 0:
|
||||||
|
raise exceptions.userNotFoundException()
|
||||||
|
|
||||||
|
# Make sure that the user has specified additional info if report reason is 'Other'
|
||||||
|
if reason.lower() == "other" and additionalInfo is None:
|
||||||
|
raise exceptions.missingReportInfoException()
|
||||||
|
|
||||||
|
# Get the token if possible
|
||||||
|
chatlog = ""
|
||||||
|
token = glob.tokens.getTokenFromUsername(target)
|
||||||
|
if token is not None:
|
||||||
|
chatlog = token.getMessagesBufferString()
|
||||||
|
|
||||||
|
# Everything is fine, submit report
|
||||||
|
glob.db.execute("INSERT INTO reports (id, from_uid, to_uid, reason, chatlog, time) VALUES (NULL, %s, %s, %s, %s, %s)", [userUtils.getID(fro), targetID, "{reason} - ingame {info}".format(reason=reason, info="({})".format(additionalInfo) if additionalInfo is not None else ""), chatlog, int(time.time())])
|
||||||
|
msg = "You've reported {target} for {reason}{info}. A Community Manager will check your report as soon as possible. Every !report message you may see in chat wasn't sent to anyone, so nobody in chat, but admins, know about your report. Thank you for reporting!".format(target=target, reason=reason, info="" if additionalInfo is None else " (" + additionalInfo + ")")
|
||||||
|
adminMsg = "{user} has reported {target} for {reason} ({info})".format(user=fro, target=target, reason=reason, info=additionalInfo)
|
||||||
|
|
||||||
|
# Log report in #admin and on discord
|
||||||
|
chat.sendMessage("FokaBot", "#admin", adminMsg)
|
||||||
|
log.warning(adminMsg, discord="cm")
|
||||||
|
except exceptions.invalidUserException:
|
||||||
|
msg = "Hello, FokaBot here! You can't report me. I won't forget what you've tried to do. Watch out."
|
||||||
|
except exceptions.invalidArgumentsException:
|
||||||
|
msg = "Invalid report command syntax. To report an user, click on it and select 'Report user'."
|
||||||
|
except exceptions.userNotFoundException:
|
||||||
|
msg = "The user you've tried to report doesn't exist."
|
||||||
|
except exceptions.missingReportInfoException:
|
||||||
|
msg = "Please specify the reason of your report."
|
||||||
|
except:
|
||||||
|
raise
|
||||||
|
finally:
|
||||||
|
if msg != "":
|
||||||
|
token = glob.tokens.getTokenFromUsername(fro)
|
||||||
|
if token is not None:
|
||||||
|
if token.irc:
|
||||||
|
chat.sendMessage("FokaBot", fro, msg)
|
||||||
|
else:
|
||||||
|
token.enqueue(serverPackets.notification(msg))
|
||||||
|
return False
|
||||||
|
|
||||||
"""
|
"""
|
||||||
Commands list
|
Commands list
|
||||||
|
|
||||||
@@ -710,7 +779,7 @@ commands = [
|
|||||||
"callback": faq
|
"callback": faq
|
||||||
}, {
|
}, {
|
||||||
"trigger": "!report",
|
"trigger": "!report",
|
||||||
"response": "Report command isn't here yet :c"
|
"callback": report
|
||||||
}, {
|
}, {
|
||||||
"trigger": "!help",
|
"trigger": "!help",
|
||||||
"response": "Click (here)[https://ripple.moe/index.php?p=16&id=4] for FokaBot's full command list"
|
"response": "Click (here)[https://ripple.moe/index.php?p=16&id=4] for FokaBot's full command list"
|
||||||
|
@@ -155,11 +155,13 @@ def channelJoinSuccess(userID, chan):
|
|||||||
return packetHelper.buildPacket(packetIDs.server_channelJoinSuccess, [[chan, dataTypes.STRING]])
|
return packetHelper.buildPacket(packetIDs.server_channelJoinSuccess, [[chan, dataTypes.STRING]])
|
||||||
|
|
||||||
def channelInfo(chan):
|
def channelInfo(chan):
|
||||||
|
if chan not in glob.channels.channels:
|
||||||
|
return bytes()
|
||||||
channel = glob.channels.channels[chan]
|
channel = glob.channels.channels[chan]
|
||||||
return packetHelper.buildPacket(packetIDs.server_channelInfo, [
|
return packetHelper.buildPacket(packetIDs.server_channelInfo, [
|
||||||
[chan, dataTypes.STRING],
|
[channel.name, dataTypes.STRING],
|
||||||
[channel.description, dataTypes.STRING],
|
[channel.description, dataTypes.STRING],
|
||||||
[len(channel.connectedUsers), dataTypes.UINT16]
|
[len(glob.streams.streams["chat/{}".format(chan)].clients), dataTypes.UINT16]
|
||||||
])
|
])
|
||||||
|
|
||||||
def channelInfoEnd():
|
def channelInfoEnd():
|
||||||
|
@@ -1,6 +1,4 @@
|
|||||||
from common.constants import actions
|
|
||||||
from common.log import logUtils as log
|
from common.log import logUtils as log
|
||||||
from common.ripple import userUtils
|
|
||||||
from constants import clientPackets
|
from constants import clientPackets
|
||||||
from constants import serverPackets
|
from constants import serverPackets
|
||||||
from objects import glob
|
from objects import glob
|
||||||
|
@@ -1,7 +1,6 @@
|
|||||||
from common.log import logUtils as log
|
from common.log import logUtils as log
|
||||||
from constants import clientPackets
|
from constants import clientPackets
|
||||||
from constants import exceptions
|
from constants import exceptions
|
||||||
from constants import serverPackets
|
|
||||||
from objects import glob
|
from objects import glob
|
||||||
|
|
||||||
|
|
||||||
|
@@ -1,4 +1,3 @@
|
|||||||
from common import generalUtils
|
|
||||||
from common.log import logUtils as log
|
from common.log import logUtils as log
|
||||||
from constants import clientPackets
|
from constants import clientPackets
|
||||||
from constants import exceptions
|
from constants import exceptions
|
||||||
|
@@ -15,6 +15,7 @@ from objects import glob
|
|||||||
|
|
||||||
def handle(tornadoRequest):
|
def handle(tornadoRequest):
|
||||||
# Data to return
|
# Data to return
|
||||||
|
responseToken = None
|
||||||
responseTokenString = "ayy"
|
responseTokenString = "ayy"
|
||||||
responseData = bytes()
|
responseData = bytes()
|
||||||
|
|
||||||
@@ -29,9 +30,6 @@ def handle(tornadoRequest):
|
|||||||
# 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")
|
loginData = str(tornadoRequest.request.body)[2:-3].split("\\n")
|
||||||
try:
|
try:
|
||||||
# If true, print error to console
|
|
||||||
err = False
|
|
||||||
|
|
||||||
# Make sure loginData is valid
|
# Make sure loginData is valid
|
||||||
if len(loginData) < 3:
|
if len(loginData) < 3:
|
||||||
raise exceptions.invalidArgumentsException()
|
raise exceptions.invalidArgumentsException()
|
||||||
@@ -220,25 +218,23 @@ def handle(tornadoRequest):
|
|||||||
except exceptions.loginFailedException:
|
except exceptions.loginFailedException:
|
||||||
# Login failed error packet
|
# Login failed error packet
|
||||||
# (we don't use enqueue because we don't have a token since login has failed)
|
# (we don't use enqueue because we don't have a token since login has failed)
|
||||||
err = True
|
|
||||||
responseData += serverPackets.loginFailed()
|
responseData += serverPackets.loginFailed()
|
||||||
except exceptions.invalidArgumentsException:
|
except exceptions.invalidArgumentsException:
|
||||||
# Invalid POST data
|
# Invalid POST data
|
||||||
# (we don't use enqueue because we don't have a token since login has failed)
|
# (we don't use enqueue because we don't have a token since login has failed)
|
||||||
err = True
|
|
||||||
responseData += serverPackets.loginFailed()
|
responseData += serverPackets.loginFailed()
|
||||||
responseData += serverPackets.notification("I see what you're doing...")
|
responseData += serverPackets.notification("I see what you're doing...")
|
||||||
except exceptions.loginBannedException:
|
except exceptions.loginBannedException:
|
||||||
# Login banned error packet
|
# Login banned error packet
|
||||||
err = True
|
|
||||||
responseData += serverPackets.loginBanned()
|
responseData += serverPackets.loginBanned()
|
||||||
except exceptions.loginLockedException:
|
except exceptions.loginLockedException:
|
||||||
# Login banned error packet
|
# Login banned error packet
|
||||||
err = True
|
|
||||||
responseData += serverPackets.loginLocked()
|
responseData += serverPackets.loginLocked()
|
||||||
except exceptions.banchoMaintenanceException:
|
except exceptions.banchoMaintenanceException:
|
||||||
# Bancho is in maintenance mode
|
# Bancho is in maintenance mode
|
||||||
responseData = responseToken.queue
|
responseData = bytes()
|
||||||
|
if responseToken is not None:
|
||||||
|
responseData = responseToken.queue
|
||||||
responseData += serverPackets.notification("Our bancho server is in maintenance mode. Please try to login again later.")
|
responseData += serverPackets.notification("Our bancho server is in maintenance mode. Please try to login again later.")
|
||||||
responseData += serverPackets.loginFailed()
|
responseData += serverPackets.loginFailed()
|
||||||
except exceptions.banchoRestartingException:
|
except exceptions.banchoRestartingException:
|
||||||
@@ -251,7 +247,6 @@ def handle(tornadoRequest):
|
|||||||
except exceptions.haxException:
|
except exceptions.haxException:
|
||||||
# Using oldoldold client, we don't have client data. Force update.
|
# Using oldoldold client, we don't have client data. Force update.
|
||||||
# (we don't use enqueue because we don't have a token since login has failed)
|
# (we don't use enqueue because we don't have a token since login has failed)
|
||||||
err = True
|
|
||||||
responseData += serverPackets.forceUpdate()
|
responseData += serverPackets.forceUpdate()
|
||||||
responseData += serverPackets.notification("Hory shitto, your client is TOO old! Nice prehistory! Please turn update it from the settings!")
|
responseData += serverPackets.notification("Hory shitto, your client is TOO old! Nice prehistory! Please turn update it from the settings!")
|
||||||
except:
|
except:
|
||||||
@@ -259,10 +254,7 @@ def handle(tornadoRequest):
|
|||||||
finally:
|
finally:
|
||||||
# Console and discord log
|
# Console and discord log
|
||||||
if len(loginData) < 3:
|
if len(loginData) < 3:
|
||||||
msg = "Invalid bancho login request from **{}** (insufficient POST data)".format(requestIP)
|
log.info("Invalid bancho login request from **{}** (insufficient POST data)".format(requestIP), "bunker")
|
||||||
else:
|
|
||||||
msg = "Bancho login request from **{}** for user **{}** ({})".format(requestIP, loginData[0], "failed" if err == True else "success")
|
|
||||||
log.info(msg, "bunker")
|
|
||||||
|
|
||||||
# Return token string and data
|
# Return token string and data
|
||||||
return responseTokenString, responseData
|
return responseTokenString, responseData
|
@@ -17,7 +17,7 @@ def handle(userToken, _=None, deleteToken=True):
|
|||||||
# the old logout packet will still be in the queue and will be sent to
|
# 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
|
# the server, so we accept logout packets sent at least 5 seconds after login
|
||||||
# if the user logs out before 5 seconds, he will be disconnected later with timeout check
|
# if the user logs out before 5 seconds, he will be disconnected later with timeout check
|
||||||
if (int(time.time()-userToken.loginTime) >= 5 or userToken.irc):
|
if int(time.time() - userToken.loginTime) >= 5 or userToken.irc:
|
||||||
# Stop spectating
|
# Stop spectating
|
||||||
userToken.stopSpectating()
|
userToken.stopSpectating()
|
||||||
|
|
||||||
@@ -35,7 +35,7 @@ def handle(userToken, _=None, deleteToken=True):
|
|||||||
glob.streams.broadcast("main", serverPackets.userLogout(userID))
|
glob.streams.broadcast("main", serverPackets.userLogout(userID))
|
||||||
|
|
||||||
# Disconnect from IRC if needed
|
# Disconnect from IRC if needed
|
||||||
if userToken.irc == True and glob.irc == True:
|
if userToken.irc and glob.irc:
|
||||||
glob.ircServer.forceDisconnection(userToken.username)
|
glob.ircServer.forceDisconnection(userToken.username)
|
||||||
|
|
||||||
# Delete token
|
# Delete token
|
||||||
|
@@ -1,6 +1,6 @@
|
|||||||
from objects import glob
|
from objects import glob
|
||||||
|
|
||||||
def handle(userToken, packetData, has):
|
def handle(userToken, _, has):
|
||||||
# Get usertoken data
|
# Get usertoken data
|
||||||
userID = userToken.userID
|
userID = userToken.userID
|
||||||
|
|
||||||
|
@@ -1,6 +1,6 @@
|
|||||||
from objects import glob
|
from objects import glob
|
||||||
|
|
||||||
def handle(userToken, packetData):
|
def handle(userToken, _):
|
||||||
# Get usertoken data
|
# Get usertoken data
|
||||||
userID = userToken.userID
|
userID = userToken.userID
|
||||||
|
|
||||||
|
@@ -1,5 +1,4 @@
|
|||||||
from objects import glob
|
from objects import glob
|
||||||
from constants import slotStatuses
|
|
||||||
from constants import serverPackets
|
from constants import serverPackets
|
||||||
|
|
||||||
def handle(userToken, packetData):
|
def handle(userToken, packetData):
|
||||||
|
@@ -1,6 +1,6 @@
|
|||||||
from objects import glob
|
from objects import glob
|
||||||
|
|
||||||
def handle(userToken, packetData):
|
def handle(userToken, _):
|
||||||
# Get userToken data
|
# Get userToken data
|
||||||
userID = userToken.userID
|
userID = userToken.userID
|
||||||
|
|
||||||
|
@@ -1,6 +1,6 @@
|
|||||||
from objects import glob
|
from objects import glob
|
||||||
|
|
||||||
def handle(userToken, packetData):
|
def handle(userToken, _):
|
||||||
# Get userToken data
|
# Get userToken data
|
||||||
userID = userToken.userID
|
userID = userToken.userID
|
||||||
|
|
||||||
|
@@ -1,6 +1,4 @@
|
|||||||
from objects import glob
|
from objects import glob
|
||||||
from constants import slotStatuses
|
|
||||||
from constants import serverPackets
|
|
||||||
|
|
||||||
def handle(userToken, _):
|
def handle(userToken, _):
|
||||||
|
|
||||||
|
@@ -1,17 +1,15 @@
|
|||||||
from common.log import logUtils as log
|
from common.log import logUtils as log
|
||||||
from helpers import chatHelper as chat
|
from helpers import chatHelper as chat
|
||||||
from objects import glob
|
|
||||||
|
|
||||||
|
|
||||||
def handle(userToken, _):
|
def handle(userToken, _):
|
||||||
# Get usertoken data
|
# Get usertoken data
|
||||||
userID = userToken.userID
|
|
||||||
username = userToken.username
|
username = userToken.username
|
||||||
|
|
||||||
# Remove user from users in lobby
|
# Remove user from users in lobby
|
||||||
userToken.leaveStream("lobby")
|
userToken.leaveStream("lobby")
|
||||||
|
|
||||||
# Part lobby channel
|
# Part lobby channel
|
||||||
|
# Done automatically by the client
|
||||||
chat.partChannel(channel="#lobby", token=userToken, kick=True)
|
chat.partChannel(channel="#lobby", token=userToken, kick=True)
|
||||||
|
|
||||||
# Console output
|
# Console output
|
||||||
|
@@ -1,6 +1,5 @@
|
|||||||
from objects import glob
|
from objects import glob
|
||||||
from constants import serverPackets
|
from constants import serverPackets
|
||||||
from constants import exceptions
|
|
||||||
|
|
||||||
def handle(userToken, packetData):
|
def handle(userToken, packetData):
|
||||||
# get token data
|
# get token data
|
||||||
|
@@ -1,5 +1,4 @@
|
|||||||
from constants import clientPackets
|
from constants import clientPackets
|
||||||
from constants import serverPackets
|
|
||||||
from objects import glob
|
from objects import glob
|
||||||
|
|
||||||
def handle(userToken, packetData):
|
def handle(userToken, packetData):
|
||||||
|
@@ -1,6 +1,9 @@
|
|||||||
import json
|
import json
|
||||||
|
|
||||||
from common.log import logUtils as log
|
import tornado.web
|
||||||
|
import tornado.gen
|
||||||
|
|
||||||
|
from common.sentry import sentry
|
||||||
from common.web import requestsManager
|
from common.web import requestsManager
|
||||||
from constants import exceptions
|
from constants import exceptions
|
||||||
from helpers import chatHelper
|
from helpers import chatHelper
|
||||||
@@ -8,6 +11,9 @@ from objects import glob
|
|||||||
|
|
||||||
|
|
||||||
class handler(requestsManager.asyncRequestHandler):
|
class handler(requestsManager.asyncRequestHandler):
|
||||||
|
@tornado.web.asynchronous
|
||||||
|
@tornado.gen.engine
|
||||||
|
@sentry.captureTornado
|
||||||
def asyncGet(self):
|
def asyncGet(self):
|
||||||
statusCode = 400
|
statusCode = 400
|
||||||
data = {"message": "unknown error"}
|
data = {"message": "unknown error"}
|
||||||
|
@@ -1,11 +1,19 @@
|
|||||||
import json
|
import json
|
||||||
|
|
||||||
|
import tornado.web
|
||||||
|
import tornado.gen
|
||||||
|
|
||||||
|
from common.sentry import sentry
|
||||||
|
from common.ripple import userUtils
|
||||||
from common.web import requestsManager
|
from common.web import requestsManager
|
||||||
from constants import exceptions
|
from constants import exceptions
|
||||||
from objects import glob
|
from objects import glob
|
||||||
|
|
||||||
|
|
||||||
class handler(requestsManager.asyncRequestHandler):
|
class handler(requestsManager.asyncRequestHandler):
|
||||||
|
@tornado.web.asynchronous
|
||||||
|
@tornado.gen.engine
|
||||||
|
@sentry.captureTornado
|
||||||
def asyncGet(self):
|
def asyncGet(self):
|
||||||
statusCode = 400
|
statusCode = 400
|
||||||
data = {"message": "unknown error"}
|
data = {"message": "unknown error"}
|
||||||
@@ -18,7 +26,8 @@ class handler(requestsManager.asyncRequestHandler):
|
|||||||
username = None
|
username = None
|
||||||
userID = None
|
userID = None
|
||||||
if "u" in self.request.arguments:
|
if "u" in self.request.arguments:
|
||||||
username = self.get_argument("u").lower().replace(" ", "_")
|
#username = self.get_argument("u").lower().replace(" ", "_")
|
||||||
|
username = userUtils.safeUsername(self.get_argument("u"))
|
||||||
else:
|
else:
|
||||||
try:
|
try:
|
||||||
userID = int(self.get_argument("id"))
|
userID = int(self.get_argument("id"))
|
||||||
|
@@ -1,10 +1,17 @@
|
|||||||
import json
|
import json
|
||||||
|
|
||||||
|
import tornado.web
|
||||||
|
import tornado.gen
|
||||||
|
|
||||||
|
from common.sentry import sentry
|
||||||
from common.web import requestsManager
|
from common.web import requestsManager
|
||||||
from objects import glob
|
from objects import glob
|
||||||
|
|
||||||
|
|
||||||
class handler(requestsManager.asyncRequestHandler):
|
class handler(requestsManager.asyncRequestHandler):
|
||||||
|
@tornado.web.asynchronous
|
||||||
|
@tornado.gen.engine
|
||||||
|
@sentry.captureTornado
|
||||||
def asyncGet(self):
|
def asyncGet(self):
|
||||||
statusCode = 400
|
statusCode = 400
|
||||||
data = {"message": "unknown error"}
|
data = {"message": "unknown error"}
|
||||||
|
@@ -1,10 +1,17 @@
|
|||||||
import json
|
import json
|
||||||
|
|
||||||
|
import tornado.web
|
||||||
|
import tornado.gen
|
||||||
|
|
||||||
|
from common.sentry import sentry
|
||||||
from common.web import requestsManager
|
from common.web import requestsManager
|
||||||
from objects import glob
|
from objects import glob
|
||||||
|
|
||||||
|
|
||||||
class handler(requestsManager.asyncRequestHandler):
|
class handler(requestsManager.asyncRequestHandler):
|
||||||
|
@tornado.web.asynchronous
|
||||||
|
@tornado.gen.engine
|
||||||
|
@sentry.captureTornado
|
||||||
def asyncGet(self):
|
def asyncGet(self):
|
||||||
statusCode = 400
|
statusCode = 400
|
||||||
data = {"message": "unknown error"}
|
data = {"message": "unknown error"}
|
||||||
|
@@ -1,11 +1,18 @@
|
|||||||
import json
|
import json
|
||||||
|
|
||||||
|
import tornado.web
|
||||||
|
import tornado.gen
|
||||||
|
|
||||||
|
from common.sentry import sentry
|
||||||
from common.web import requestsManager
|
from common.web import requestsManager
|
||||||
from constants import exceptions
|
from constants import exceptions
|
||||||
from objects import glob
|
from objects import glob
|
||||||
|
|
||||||
|
|
||||||
class handler(requestsManager.asyncRequestHandler):
|
class handler(requestsManager.asyncRequestHandler):
|
||||||
|
@tornado.web.asynchronous
|
||||||
|
@tornado.gen.engine
|
||||||
|
@sentry.captureTornado
|
||||||
def asyncGet(self):
|
def asyncGet(self):
|
||||||
statusCode = 400
|
statusCode = 400
|
||||||
data = {"message": "unknown error"}
|
data = {"message": "unknown error"}
|
||||||
|
@@ -1,5 +1,9 @@
|
|||||||
import json
|
import json
|
||||||
|
|
||||||
|
import tornado.web
|
||||||
|
import tornado.gen
|
||||||
|
|
||||||
|
from common.sentry import sentry
|
||||||
from common.log import logUtils as log
|
from common.log import logUtils as log
|
||||||
from common.web import requestsManager
|
from common.web import requestsManager
|
||||||
from constants import exceptions
|
from constants import exceptions
|
||||||
@@ -8,6 +12,9 @@ from objects import glob
|
|||||||
|
|
||||||
|
|
||||||
class handler(requestsManager.asyncRequestHandler):
|
class handler(requestsManager.asyncRequestHandler):
|
||||||
|
@tornado.web.asynchronous
|
||||||
|
@tornado.gen.engine
|
||||||
|
@sentry.captureTornado
|
||||||
def asyncGet(self):
|
def asyncGet(self):
|
||||||
statusCode = 400
|
statusCode = 400
|
||||||
data = {"message": "unknown error"}
|
data = {"message": "unknown error"}
|
||||||
|
@@ -56,194 +56,189 @@ from events import tournamentJoinMatchChannelEvent
|
|||||||
from events import tournamentLeaveMatchChannelEvent
|
from events import tournamentLeaveMatchChannelEvent
|
||||||
from helpers import packetHelper
|
from helpers import packetHelper
|
||||||
from objects import glob
|
from objects import glob
|
||||||
|
from common.sentry import sentry
|
||||||
|
|
||||||
|
|
||||||
class handler(SentryMixin, requestsManager.asyncRequestHandler):
|
class handler(requestsManager.asyncRequestHandler):
|
||||||
@tornado.web.asynchronous
|
@tornado.web.asynchronous
|
||||||
@tornado.gen.engine
|
@tornado.gen.engine
|
||||||
|
@sentry.captureTornado
|
||||||
def asyncPost(self):
|
def asyncPost(self):
|
||||||
try:
|
# Track time if needed
|
||||||
# Track time if needed
|
if glob.outputRequestTime:
|
||||||
if glob.outputRequestTime:
|
# Start time
|
||||||
# Start time
|
st = datetime.datetime.now()
|
||||||
st = datetime.datetime.now()
|
|
||||||
|
|
||||||
# Client's token string and request data
|
# Client's token string and request data
|
||||||
requestTokenString = self.request.headers.get("osu-token")
|
requestTokenString = self.request.headers.get("osu-token")
|
||||||
requestData = self.request.body
|
requestData = self.request.body
|
||||||
|
|
||||||
# Server's token string and request data
|
# Server's token string and request data
|
||||||
responseTokenString = "ayy"
|
responseTokenString = "ayy"
|
||||||
responseData = bytes()
|
responseData = bytes()
|
||||||
|
|
||||||
if requestTokenString is None:
|
if requestTokenString is None:
|
||||||
# No token, first request. Handle login.
|
# No token, first request. Handle login.
|
||||||
responseTokenString, responseData = loginEvent.handle(self)
|
responseTokenString, responseData = loginEvent.handle(self)
|
||||||
else:
|
else:
|
||||||
userToken = None # default value
|
userToken = None # default value
|
||||||
try:
|
try:
|
||||||
# This is not the first packet, send response based on client's request
|
# This is not the first packet, send response based on client's request
|
||||||
# Packet start position, used to read stacked packets
|
# Packet start position, used to read stacked packets
|
||||||
pos = 0
|
pos = 0
|
||||||
|
|
||||||
# Make sure the token exists
|
# Make sure the token exists
|
||||||
if requestTokenString not in glob.tokens.tokens:
|
if requestTokenString not in glob.tokens.tokens:
|
||||||
raise exceptions.tokenNotFoundException()
|
raise exceptions.tokenNotFoundException()
|
||||||
|
|
||||||
# Token exists, get its object and lock it
|
# Token exists, get its object and lock it
|
||||||
userToken = glob.tokens.tokens[requestTokenString]
|
userToken = glob.tokens.tokens[requestTokenString]
|
||||||
userToken.lock.acquire()
|
userToken.lock.acquire()
|
||||||
|
|
||||||
# Keep reading packets until everything has been read
|
# Keep reading packets until everything has been read
|
||||||
while pos < len(requestData):
|
while pos < len(requestData):
|
||||||
# Get packet from stack starting from new packet
|
# Get packet from stack starting from new packet
|
||||||
leftData = requestData[pos:]
|
leftData = requestData[pos:]
|
||||||
|
|
||||||
# Get packet ID, data length and data
|
# Get packet ID, data length and data
|
||||||
packetID = packetHelper.readPacketID(leftData)
|
packetID = packetHelper.readPacketID(leftData)
|
||||||
dataLength = packetHelper.readPacketLength(leftData)
|
dataLength = packetHelper.readPacketLength(leftData)
|
||||||
packetData = requestData[pos:(pos+dataLength+7)]
|
packetData = requestData[pos:(pos+dataLength+7)]
|
||||||
|
|
||||||
# Console output if needed
|
# Console output if needed
|
||||||
if glob.outputPackets == True and packetID != 4:
|
if glob.outputPackets == True and packetID != 4:
|
||||||
log.debug("Incoming packet ({})({}):\n\nPacket code: {}\nPacket length: {}\nSingle packet data: {}\n".format(requestTokenString, userToken.username, str(packetID), str(dataLength), str(packetData)))
|
log.debug("Incoming packet ({})({}):\n\nPacket code: {}\nPacket length: {}\nSingle packet data: {}\n".format(requestTokenString, userToken.username, str(packetID), str(dataLength), str(packetData)))
|
||||||
|
|
||||||
# Event handler
|
# Event handler
|
||||||
def handleEvent(ev):
|
def handleEvent(ev):
|
||||||
def wrapper():
|
def wrapper():
|
||||||
ev.handle(userToken, packetData)
|
ev.handle(userToken, packetData)
|
||||||
return wrapper
|
return wrapper
|
||||||
|
|
||||||
eventHandler = {
|
eventHandler = {
|
||||||
packetIDs.client_changeAction: handleEvent(changeActionEvent),
|
packetIDs.client_changeAction: handleEvent(changeActionEvent),
|
||||||
packetIDs.client_logout: handleEvent(logoutEvent),
|
packetIDs.client_logout: handleEvent(logoutEvent),
|
||||||
packetIDs.client_friendAdd: handleEvent(friendAddEvent),
|
packetIDs.client_friendAdd: handleEvent(friendAddEvent),
|
||||||
packetIDs.client_friendRemove: handleEvent(friendRemoveEvent),
|
packetIDs.client_friendRemove: handleEvent(friendRemoveEvent),
|
||||||
packetIDs.client_userStatsRequest: handleEvent(userStatsRequestEvent),
|
packetIDs.client_userStatsRequest: handleEvent(userStatsRequestEvent),
|
||||||
packetIDs.client_requestStatusUpdate: handleEvent(requestStatusUpdateEvent),
|
packetIDs.client_requestStatusUpdate: handleEvent(requestStatusUpdateEvent),
|
||||||
packetIDs.client_userPanelRequest: handleEvent(userPanelRequestEvent),
|
packetIDs.client_userPanelRequest: handleEvent(userPanelRequestEvent),
|
||||||
|
|
||||||
packetIDs.client_channelJoin: handleEvent(channelJoinEvent),
|
packetIDs.client_channelJoin: handleEvent(channelJoinEvent),
|
||||||
packetIDs.client_channelPart: handleEvent(channelPartEvent),
|
packetIDs.client_channelPart: handleEvent(channelPartEvent),
|
||||||
packetIDs.client_sendPublicMessage: handleEvent(sendPublicMessageEvent),
|
packetIDs.client_sendPublicMessage: handleEvent(sendPublicMessageEvent),
|
||||||
packetIDs.client_sendPrivateMessage: handleEvent(sendPrivateMessageEvent),
|
packetIDs.client_sendPrivateMessage: handleEvent(sendPrivateMessageEvent),
|
||||||
packetIDs.client_setAwayMessage: handleEvent(setAwayMessageEvent),
|
packetIDs.client_setAwayMessage: handleEvent(setAwayMessageEvent),
|
||||||
|
|
||||||
packetIDs.client_startSpectating: handleEvent(startSpectatingEvent),
|
packetIDs.client_startSpectating: handleEvent(startSpectatingEvent),
|
||||||
packetIDs.client_stopSpectating: handleEvent(stopSpectatingEvent),
|
packetIDs.client_stopSpectating: handleEvent(stopSpectatingEvent),
|
||||||
packetIDs.client_cantSpectate: handleEvent(cantSpectateEvent),
|
packetIDs.client_cantSpectate: handleEvent(cantSpectateEvent),
|
||||||
packetIDs.client_spectateFrames: handleEvent(spectateFramesEvent),
|
packetIDs.client_spectateFrames: handleEvent(spectateFramesEvent),
|
||||||
|
|
||||||
packetIDs.client_joinLobby: handleEvent(joinLobbyEvent),
|
packetIDs.client_joinLobby: handleEvent(joinLobbyEvent),
|
||||||
packetIDs.client_partLobby: handleEvent(partLobbyEvent),
|
packetIDs.client_partLobby: handleEvent(partLobbyEvent),
|
||||||
packetIDs.client_createMatch: handleEvent(createMatchEvent),
|
packetIDs.client_createMatch: handleEvent(createMatchEvent),
|
||||||
packetIDs.client_joinMatch: handleEvent(joinMatchEvent),
|
packetIDs.client_joinMatch: handleEvent(joinMatchEvent),
|
||||||
packetIDs.client_partMatch: handleEvent(partMatchEvent),
|
packetIDs.client_partMatch: handleEvent(partMatchEvent),
|
||||||
packetIDs.client_matchChangeSlot: handleEvent(changeSlotEvent),
|
packetIDs.client_matchChangeSlot: handleEvent(changeSlotEvent),
|
||||||
packetIDs.client_matchChangeSettings: handleEvent(changeMatchSettingsEvent),
|
packetIDs.client_matchChangeSettings: handleEvent(changeMatchSettingsEvent),
|
||||||
packetIDs.client_matchChangePassword: handleEvent(changeMatchPasswordEvent),
|
packetIDs.client_matchChangePassword: handleEvent(changeMatchPasswordEvent),
|
||||||
packetIDs.client_matchChangeMods: handleEvent(changeMatchModsEvent),
|
packetIDs.client_matchChangeMods: handleEvent(changeMatchModsEvent),
|
||||||
packetIDs.client_matchReady: handleEvent(matchReadyEvent),
|
packetIDs.client_matchReady: handleEvent(matchReadyEvent),
|
||||||
packetIDs.client_matchNotReady: handleEvent(matchReadyEvent),
|
packetIDs.client_matchNotReady: handleEvent(matchReadyEvent),
|
||||||
packetIDs.client_matchLock: handleEvent(matchLockEvent),
|
packetIDs.client_matchLock: handleEvent(matchLockEvent),
|
||||||
packetIDs.client_matchStart: handleEvent(matchStartEvent),
|
packetIDs.client_matchStart: handleEvent(matchStartEvent),
|
||||||
packetIDs.client_matchLoadComplete: handleEvent(matchPlayerLoadEvent),
|
packetIDs.client_matchLoadComplete: handleEvent(matchPlayerLoadEvent),
|
||||||
packetIDs.client_matchSkipRequest: handleEvent(matchSkipEvent),
|
packetIDs.client_matchSkipRequest: handleEvent(matchSkipEvent),
|
||||||
packetIDs.client_matchScoreUpdate: handleEvent(matchFramesEvent),
|
packetIDs.client_matchScoreUpdate: handleEvent(matchFramesEvent),
|
||||||
packetIDs.client_matchComplete: handleEvent(matchCompleteEvent),
|
packetIDs.client_matchComplete: handleEvent(matchCompleteEvent),
|
||||||
packetIDs.client_matchNoBeatmap: handleEvent(matchNoBeatmapEvent),
|
packetIDs.client_matchNoBeatmap: handleEvent(matchNoBeatmapEvent),
|
||||||
packetIDs.client_matchHasBeatmap: handleEvent(matchHasBeatmapEvent),
|
packetIDs.client_matchHasBeatmap: handleEvent(matchHasBeatmapEvent),
|
||||||
packetIDs.client_matchTransferHost: handleEvent(matchTransferHostEvent),
|
packetIDs.client_matchTransferHost: handleEvent(matchTransferHostEvent),
|
||||||
packetIDs.client_matchFailed: handleEvent(matchFailedEvent),
|
packetIDs.client_matchFailed: handleEvent(matchFailedEvent),
|
||||||
packetIDs.client_matchChangeTeam: handleEvent(matchChangeTeamEvent),
|
packetIDs.client_matchChangeTeam: handleEvent(matchChangeTeamEvent),
|
||||||
packetIDs.client_invite: handleEvent(matchInviteEvent),
|
packetIDs.client_invite: handleEvent(matchInviteEvent),
|
||||||
|
|
||||||
packetIDs.client_tournamentMatchInfoRequest: handleEvent(tournamentMatchInfoRequestEvent),
|
packetIDs.client_tournamentMatchInfoRequest: handleEvent(tournamentMatchInfoRequestEvent),
|
||||||
packetIDs.client_tournamentJoinMatchChannel: handleEvent(tournamentJoinMatchChannelEvent),
|
packetIDs.client_tournamentJoinMatchChannel: handleEvent(tournamentJoinMatchChannelEvent),
|
||||||
packetIDs.client_tournamentLeaveMatchChannel: handleEvent(tournamentLeaveMatchChannelEvent),
|
packetIDs.client_tournamentLeaveMatchChannel: handleEvent(tournamentLeaveMatchChannelEvent),
|
||||||
}
|
}
|
||||||
|
|
||||||
# Packets processed if in restricted mode.
|
# Packets processed if in restricted mode.
|
||||||
# All other packets will be ignored if the user is in restricted mode
|
# All other packets will be ignored if the user is in restricted mode
|
||||||
packetsRestricted = [
|
packetsRestricted = [
|
||||||
packetIDs.client_logout,
|
packetIDs.client_logout,
|
||||||
packetIDs.client_userStatsRequest,
|
packetIDs.client_userStatsRequest,
|
||||||
packetIDs.client_requestStatusUpdate,
|
packetIDs.client_requestStatusUpdate,
|
||||||
packetIDs.client_userPanelRequest,
|
packetIDs.client_userPanelRequest,
|
||||||
packetIDs.client_changeAction,
|
packetIDs.client_changeAction,
|
||||||
packetIDs.client_channelJoin,
|
packetIDs.client_channelJoin,
|
||||||
packetIDs.client_channelPart,
|
packetIDs.client_channelPart,
|
||||||
]
|
]
|
||||||
|
|
||||||
# Process/ignore packet
|
# Process/ignore packet
|
||||||
if packetID != 4:
|
if packetID != 4:
|
||||||
if packetID in eventHandler:
|
if packetID in eventHandler:
|
||||||
if userToken.restricted == False or (userToken.restricted == True and packetID in packetsRestricted):
|
if userToken.restricted == False or (userToken.restricted == True and packetID in packetsRestricted):
|
||||||
eventHandler[packetID]()
|
eventHandler[packetID]()
|
||||||
else:
|
|
||||||
log.warning("Ignored packet id from {} ({}) (user is restricted)".format(requestTokenString, packetID))
|
|
||||||
else:
|
else:
|
||||||
log.warning("Unknown packet id from {} ({})".format(requestTokenString, packetID))
|
log.warning("Ignored packet id from {} ({}) (user is restricted)".format(requestTokenString, packetID))
|
||||||
|
else:
|
||||||
|
log.warning("Unknown packet id from {} ({})".format(requestTokenString, packetID))
|
||||||
|
|
||||||
# Update pos so we can read the next stacked packet
|
# Update pos so we can read the next stacked packet
|
||||||
# +7 because we add packet ID bytes, unused byte and data length bytes
|
# +7 because we add packet ID bytes, unused byte and data length bytes
|
||||||
pos += dataLength+7
|
pos += dataLength+7
|
||||||
|
|
||||||
# Token queue built, send it
|
# Token queue built, send it
|
||||||
responseTokenString = userToken.token
|
responseTokenString = userToken.token
|
||||||
responseData = userToken.queue
|
responseData = userToken.queue
|
||||||
userToken.resetQueue()
|
userToken.resetQueue()
|
||||||
except exceptions.tokenNotFoundException:
|
except exceptions.tokenNotFoundException:
|
||||||
# Token not found. Disconnect that user
|
# Token not found. Disconnect that user
|
||||||
responseData = serverPackets.loginError()
|
responseData = serverPackets.loginError()
|
||||||
responseData += serverPackets.notification("Whoops! Something went wrong, please login again.")
|
responseData += serverPackets.notification("Whoops! Something went wrong, please login again.")
|
||||||
log.warning("Received packet from unknown token ({}).".format(requestTokenString))
|
log.warning("Received packet from unknown token ({}).".format(requestTokenString))
|
||||||
log.info("{} has been disconnected (invalid token)".format(requestTokenString))
|
log.info("{} has been disconnected (invalid token)".format(requestTokenString))
|
||||||
finally:
|
finally:
|
||||||
# Unlock token
|
# Unlock token
|
||||||
if userToken is not None:
|
if userToken is not None:
|
||||||
# Update ping time for timeout
|
# Update ping time for timeout
|
||||||
userToken.updatePingTime()
|
userToken.updatePingTime()
|
||||||
# Release token lock
|
# Release token lock
|
||||||
userToken.lock.release()
|
userToken.lock.release()
|
||||||
# Delete token if kicked
|
# Delete token if kicked
|
||||||
if userToken.kicked:
|
if userToken.kicked:
|
||||||
glob.tokens.deleteToken(userToken)
|
glob.tokens.deleteToken(userToken)
|
||||||
|
|
||||||
if glob.outputRequestTime:
|
if glob.outputRequestTime:
|
||||||
# End time
|
# End time
|
||||||
et = datetime.datetime.now()
|
et = datetime.datetime.now()
|
||||||
|
|
||||||
# Total time:
|
# Total time:
|
||||||
tt = float((et.microsecond-st.microsecond)/1000)
|
tt = float((et.microsecond-st.microsecond)/1000)
|
||||||
log.debug("Request time: {}ms".format(tt))
|
log.debug("Request time: {}ms".format(tt))
|
||||||
|
|
||||||
# Send server's response to client
|
# Send server's response to client
|
||||||
# We don't use token object because we might not have a token (failed login)
|
# We don't use token object because we might not have a token (failed login)
|
||||||
if glob.gzip:
|
if glob.gzip:
|
||||||
# First, write the gzipped response
|
# First, write the gzipped response
|
||||||
self.write(gzip.compress(responseData, int(glob.conf.config["server"]["gziplevel"])))
|
self.write(gzip.compress(responseData, int(glob.conf.config["server"]["gziplevel"])))
|
||||||
|
|
||||||
# Then, add gzip headers
|
# Then, add gzip headers
|
||||||
self.add_header("Vary", "Accept-Encoding")
|
self.add_header("Vary", "Accept-Encoding")
|
||||||
self.add_header("Content-Encoding", "gzip")
|
self.add_header("Content-Encoding", "gzip")
|
||||||
else:
|
else:
|
||||||
# First, write the response
|
# First, write the response
|
||||||
self.write(responseData)
|
self.write(responseData)
|
||||||
|
|
||||||
# Add all the headers AFTER the response has been written
|
# Add all the headers AFTER the response has been written
|
||||||
self.set_status(200)
|
self.set_status(200)
|
||||||
self.add_header("cho-token", responseTokenString)
|
self.add_header("cho-token", responseTokenString)
|
||||||
self.add_header("cho-protocol", "19")
|
self.add_header("cho-protocol", "19")
|
||||||
self.add_header("Connection", "keep-alive")
|
self.add_header("Connection", "keep-alive")
|
||||||
self.add_header("Keep-Alive", "timeout=5, max=100")
|
self.add_header("Keep-Alive", "timeout=5, max=100")
|
||||||
self.add_header("Content-Type", "text/html; charset=UTF-8")
|
self.add_header("Content-Type", "text/html; charset=UTF-8")
|
||||||
except:
|
|
||||||
log.error("Unknown error!\n```\n{}\n{}```".format(sys.exc_info(), traceback.format_exc()))
|
|
||||||
if glob.sentry:
|
|
||||||
yield tornado.gen.Task(self.captureException, exc_info=True)
|
|
||||||
#finally:
|
|
||||||
# self.finish()
|
|
||||||
|
|
||||||
@tornado.web.asynchronous
|
@tornado.web.asynchronous
|
||||||
@tornado.gen.engine
|
@tornado.gen.engine
|
||||||
|
@@ -27,44 +27,32 @@ def joinChannel(userID = 0, channel = "", token = None, toIRC = True):
|
|||||||
raise exceptions.userNotFoundException
|
raise exceptions.userNotFoundException
|
||||||
else:
|
else:
|
||||||
token = token
|
token = token
|
||||||
userID = token.userID
|
|
||||||
|
|
||||||
# Get usertoken data
|
|
||||||
username = token.username
|
|
||||||
|
|
||||||
# Normal channel, do check stuff
|
# Normal channel, do check stuff
|
||||||
# Make sure the channel exists
|
# Make sure the channel exists
|
||||||
if channel not in glob.channels.channels:
|
if channel not in glob.channels.channels:
|
||||||
raise exceptions.channelUnknownException
|
raise exceptions.channelUnknownException()
|
||||||
|
|
||||||
# Check channel permissions
|
|
||||||
channelObject = glob.channels.channels[channel]
|
|
||||||
if channelObject.publicRead == False and token.admin == False:
|
|
||||||
raise exceptions.channelNoPermissionsException
|
|
||||||
|
|
||||||
# Add our userID to users in that channel
|
|
||||||
channelObject.userJoin(userID)
|
|
||||||
|
|
||||||
# Add the channel to our joined channel
|
# Add the channel to our joined channel
|
||||||
token.joinChannel(channel)
|
token.joinChannel(glob.channels.channels[channel])
|
||||||
|
|
||||||
# Send channel joined (bancho). We use clientName here because of #multiplayer and #spectator channels
|
|
||||||
token.enqueue(serverPackets.channelJoinSuccess(userID, channelObject.clientName))
|
|
||||||
|
|
||||||
# Send channel joined (IRC)
|
# Send channel joined (IRC)
|
||||||
if glob.irc == True and toIRC == True:
|
if glob.irc == True and toIRC == True:
|
||||||
glob.ircServer.banchoJoinChannel(username, channel)
|
glob.ircServer.banchoJoinChannel(token.username, channel)
|
||||||
|
|
||||||
# Console output
|
# Console output
|
||||||
log.info("{} joined channel {}".format(username, channel))
|
log.info("{} joined channel {}".format(token.username, channel))
|
||||||
|
|
||||||
# IRC code return
|
# IRC code return
|
||||||
return 0
|
return 0
|
||||||
except exceptions.channelNoPermissionsException:
|
except exceptions.channelNoPermissionsException:
|
||||||
log.warning("{} attempted to join channel {}, but they have no read permissions".format(username, channel))
|
log.warning("{} attempted to join channel {}, but they have no read permissions".format(token.username, channel))
|
||||||
return 403
|
return 403
|
||||||
except exceptions.channelUnknownException:
|
except exceptions.channelUnknownException:
|
||||||
log.warning("{} attempted to join an unknown channel ({})".format(username, channel))
|
log.warning("{} attempted to join an unknown channel ({})".format(token.username, channel))
|
||||||
|
return 403
|
||||||
|
except exceptions.userAlreadyInChannelException:
|
||||||
|
log.warning("User {} already in channel {}".format(token.username, channel))
|
||||||
return 403
|
return 403
|
||||||
except exceptions.userNotFoundException:
|
except exceptions.userNotFoundException:
|
||||||
log.warning("User not connected to IRC/Bancho")
|
log.warning("User not connected to IRC/Bancho")
|
||||||
@@ -82,6 +70,10 @@ def partChannel(userID = 0, channel = "", token = None, toIRC = True, kick = Fal
|
|||||||
:return: 0 if joined or other IRC code in case of error. Needed only on IRC-side
|
:return: 0 if joined or other IRC code in case of error. Needed only on IRC-side
|
||||||
"""
|
"""
|
||||||
try:
|
try:
|
||||||
|
# Make sure the client is not drunk and sends partChannel when closing a PM tab
|
||||||
|
if not channel.startswith("#"):
|
||||||
|
return
|
||||||
|
|
||||||
# Get token if not defined
|
# Get token if not defined
|
||||||
if token is None:
|
if token is None:
|
||||||
token = glob.tokens.getTokenFromUserID(userID)
|
token = glob.tokens.getTokenFromUserID(userID)
|
||||||
@@ -90,10 +82,6 @@ def partChannel(userID = 0, channel = "", token = None, toIRC = True, kick = Fal
|
|||||||
raise exceptions.userNotFoundException
|
raise exceptions.userNotFoundException
|
||||||
else:
|
else:
|
||||||
token = token
|
token = token
|
||||||
userID = token.userID
|
|
||||||
|
|
||||||
# Get usertoken data
|
|
||||||
username = token.username
|
|
||||||
|
|
||||||
# Determine internal/client name if needed
|
# Determine internal/client name if needed
|
||||||
# (toclient is used clientwise for #multiplayer and #spectator channels)
|
# (toclient is used clientwise for #multiplayer and #spectator channels)
|
||||||
@@ -113,12 +101,20 @@ def partChannel(userID = 0, channel = "", token = None, toIRC = True, kick = Fal
|
|||||||
|
|
||||||
# Make sure the channel exists
|
# Make sure the channel exists
|
||||||
if channel not in glob.channels.channels:
|
if channel not in glob.channels.channels:
|
||||||
raise exceptions.channelUnknownException
|
raise exceptions.channelUnknownException()
|
||||||
|
|
||||||
|
# Make sure the user is in the channel
|
||||||
|
if channel not in token.joinedChannels:
|
||||||
|
raise exceptions.userNotInChannelException()
|
||||||
|
|
||||||
# Part channel (token-side and channel-side)
|
# Part channel (token-side and channel-side)
|
||||||
channelObject = glob.channels.channels[channel]
|
channelObject = glob.channels.channels[channel]
|
||||||
token.partChannel(channel)
|
token.partChannel(channelObject)
|
||||||
channelObject.userPart(userID)
|
|
||||||
|
# Delete temporary channel if everyone left
|
||||||
|
if "chat/{}".format(channelObject.name) in glob.streams.streams:
|
||||||
|
if channelObject.temp == True and len(glob.streams.streams["chat/{}".format(channelObject.name)].clients) - 1 == 0:
|
||||||
|
glob.channels.removeChannel(channelObject.name)
|
||||||
|
|
||||||
# Force close tab if needed
|
# Force close tab if needed
|
||||||
# NOTE: Maybe always needed, will check later
|
# NOTE: Maybe always needed, will check later
|
||||||
@@ -127,16 +123,19 @@ def partChannel(userID = 0, channel = "", token = None, toIRC = True, kick = Fal
|
|||||||
|
|
||||||
# IRC part
|
# IRC part
|
||||||
if glob.irc == True and toIRC == True:
|
if glob.irc == True and toIRC == True:
|
||||||
glob.ircServer.banchoPartChannel(username, channel)
|
glob.ircServer.banchoPartChannel(token.username, channel)
|
||||||
|
|
||||||
# Console output
|
# Console output
|
||||||
log.info("{} parted channel {} ({})".format(username, channel, channelClient))
|
log.info("{} parted channel {} ({})".format(token.username, channel, channelClient))
|
||||||
|
|
||||||
# Return IRC code
|
# Return IRC code
|
||||||
return 0
|
return 0
|
||||||
except exceptions.channelUnknownException:
|
except exceptions.channelUnknownException:
|
||||||
log.warning("{} attempted to part an unknown channel ({})".format(username, channel))
|
log.warning("{} attempted to part an unknown channel ({})".format(token.username, channel))
|
||||||
return 403
|
return 403
|
||||||
|
except exceptions.userNotInChannelException:
|
||||||
|
log.warning("{} attempted to part {}, but he's not in that channel".format(token.username, channel))
|
||||||
|
return 442
|
||||||
except exceptions.userNotFoundException:
|
except exceptions.userNotFoundException:
|
||||||
log.warning("User not connected to IRC/Bancho")
|
log.warning("User not connected to IRC/Bancho")
|
||||||
return 442 # idk
|
return 442 # idk
|
||||||
@@ -153,7 +152,7 @@ def sendMessage(fro = "", to = "", message = "", token = None, toIRC = True):
|
|||||||
:return: 0 if joined or other IRC code in case of error. Needed only on IRC-side
|
:return: 0 if joined or other IRC code in case of error. Needed only on IRC-side
|
||||||
"""
|
"""
|
||||||
try:
|
try:
|
||||||
tokenString = ""
|
#tokenString = ""
|
||||||
# Get token object if not passed
|
# Get token object if not passed
|
||||||
if token is None:
|
if token is None:
|
||||||
token = glob.tokens.getTokenFromUsername(fro)
|
token = glob.tokens.getTokenFromUsername(fro)
|
||||||
@@ -162,11 +161,7 @@ def sendMessage(fro = "", to = "", message = "", token = None, toIRC = True):
|
|||||||
else:
|
else:
|
||||||
# token object alredy passed, get its string and its username (fro)
|
# token object alredy passed, get its string and its username (fro)
|
||||||
fro = token.username
|
fro = token.username
|
||||||
tokenString = token.token
|
#tokenString = token.token
|
||||||
|
|
||||||
# Set some variables
|
|
||||||
userID = token.userID
|
|
||||||
username = token.username
|
|
||||||
|
|
||||||
# Make sure this is not a tournament client
|
# Make sure this is not a tournament client
|
||||||
if token.tournament:
|
if token.tournament:
|
||||||
@@ -180,12 +175,16 @@ def sendMessage(fro = "", to = "", message = "", token = None, toIRC = True):
|
|||||||
if token.isSilenced():
|
if token.isSilenced():
|
||||||
raise exceptions.userSilencedException()
|
raise exceptions.userSilencedException()
|
||||||
|
|
||||||
|
# Redirect !report to FokaBot
|
||||||
|
if message.startswith("!report"):
|
||||||
|
to = "FokaBot"
|
||||||
|
|
||||||
# Determine internal name if needed
|
# Determine internal name if needed
|
||||||
# (toclient is used clientwise for #multiplayer and #spectator channels)
|
# (toclient is used clientwise for #multiplayer and #spectator channels)
|
||||||
toClient = to
|
toClient = to
|
||||||
if to == "#spectator":
|
if to == "#spectator":
|
||||||
if token.spectating is None:
|
if token.spectating is None:
|
||||||
s = userID
|
s = token.userID
|
||||||
else:
|
else:
|
||||||
s = token.spectatingUserID
|
s = token.spectatingUserID
|
||||||
to = "#spect_{}".format(s)
|
to = "#spect_{}".format(s)
|
||||||
@@ -195,7 +194,6 @@ def sendMessage(fro = "", to = "", message = "", token = None, toIRC = True):
|
|||||||
toClient = "#spectator"
|
toClient = "#spectator"
|
||||||
elif to.startswith("#multi_"):
|
elif to.startswith("#multi_"):
|
||||||
toClient = "#multiplayer"
|
toClient = "#multiplayer"
|
||||||
|
|
||||||
# Truncate message if > 2048 characters
|
# Truncate message if > 2048 characters
|
||||||
message = message[:2048]+"..." if len(message) > 2048 else message
|
message = message[:2048]+"..." if len(message) > 2048 else message
|
||||||
|
|
||||||
@@ -203,7 +201,7 @@ def sendMessage(fro = "", to = "", message = "", token = None, toIRC = True):
|
|||||||
message = glob.chatFilters.filterMessage(message)
|
message = glob.chatFilters.filterMessage(message)
|
||||||
|
|
||||||
# Build packet bytes
|
# Build packet bytes
|
||||||
packet = serverPackets.sendMessage(username, toClient, message)
|
packet = serverPackets.sendMessage(token.username, toClient, message)
|
||||||
|
|
||||||
# Send the message
|
# Send the message
|
||||||
isChannel = to.startswith("#")
|
isChannel = to.startswith("#")
|
||||||
@@ -211,35 +209,31 @@ def sendMessage(fro = "", to = "", message = "", token = None, toIRC = True):
|
|||||||
# CHANNEL
|
# CHANNEL
|
||||||
# Make sure the channel exists
|
# Make sure the channel exists
|
||||||
if to not in glob.channels.channels:
|
if to not in glob.channels.channels:
|
||||||
raise exceptions.channelUnknownException
|
raise exceptions.channelUnknownException()
|
||||||
|
|
||||||
# Make sure the channel is not in moderated mode
|
# Make sure the channel is not in moderated mode
|
||||||
if glob.channels.channels[to].moderated == True and token.admin == False:
|
if glob.channels.channels[to].moderated == True and token.admin == False:
|
||||||
raise exceptions.channelModeratedException
|
raise exceptions.channelModeratedException()
|
||||||
|
|
||||||
# Make sure we have write permissions
|
# Make sure we have write permissions
|
||||||
if glob.channels.channels[to].publicWrite == False and token.admin == False:
|
if glob.channels.channels[to].publicWrite == False and token.admin == False:
|
||||||
raise exceptions.channelNoPermissionsException
|
raise exceptions.channelNoPermissionsException()
|
||||||
|
|
||||||
|
# Add message in buffer
|
||||||
|
token.addMessageInBuffer(to, message)
|
||||||
|
|
||||||
# Everything seems fine, build recipients list and send packet
|
# Everything seems fine, build recipients list and send packet
|
||||||
recipients = glob.channels.channels[to].connectedUsers[:]
|
glob.streams.broadcast("chat/{}".format(to), packet, but=[token.token])
|
||||||
for key, value in glob.tokens.tokens.items():
|
|
||||||
# Skip our client and irc clients
|
|
||||||
if key == tokenString or value.irc == True:
|
|
||||||
continue
|
|
||||||
# Send to this client if it's connected to the channel
|
|
||||||
if value.userID in recipients:
|
|
||||||
value.enqueue(packet)
|
|
||||||
else:
|
else:
|
||||||
# USER
|
# USER
|
||||||
# Make sure recipient user is connected
|
# Make sure recipient user is connected
|
||||||
recipientToken = glob.tokens.getTokenFromUsername(to)
|
recipientToken = glob.tokens.getTokenFromUsername(to)
|
||||||
if recipientToken is None:
|
if recipientToken is None:
|
||||||
raise exceptions.userNotFoundException
|
raise exceptions.userNotFoundException()
|
||||||
|
|
||||||
# Make sure the recipient is not a tournament client
|
# Make sure the recipient is not a tournament client
|
||||||
if recipientToken.tournament:
|
#if recipientToken.tournament:
|
||||||
raise exceptions.userTournamentException()
|
# raise exceptions.userTournamentException()
|
||||||
|
|
||||||
# Make sure the recipient is not restricted or we are FokaBot
|
# Make sure the recipient is not restricted or we are FokaBot
|
||||||
if recipientToken.restricted == True and fro.lower() != "fokabot":
|
if recipientToken.restricted == True and fro.lower() != "fokabot":
|
||||||
@@ -248,8 +242,8 @@ def sendMessage(fro = "", to = "", message = "", token = None, toIRC = True):
|
|||||||
# TODO: Make sure the recipient has not disabled PMs for non-friends or he's our friend
|
# TODO: Make sure the recipient has not disabled PMs for non-friends or he's our friend
|
||||||
|
|
||||||
# Away check
|
# Away check
|
||||||
if recipientToken.awayCheck(userID):
|
if recipientToken.awayCheck(token.userID):
|
||||||
sendMessage(to, fro, "\x01ACTION is away: {message}\x01".format(code=chr(int(1)), message=recipientToken.awayMessage))
|
sendMessage(to, fro, "\x01ACTION is away: {}\x01".format(recipientToken.awayMessage))
|
||||||
|
|
||||||
# Check message templates (mods/admins only)
|
# Check message templates (mods/admins only)
|
||||||
if message in messageTemplates.templates and token.admin == True:
|
if message in messageTemplates.templates and token.admin == True:
|
||||||
@@ -263,38 +257,38 @@ def sendMessage(fro = "", to = "", message = "", token = None, toIRC = True):
|
|||||||
glob.ircServer.banchoMessage(fro, to, message)
|
glob.ircServer.banchoMessage(fro, to, message)
|
||||||
|
|
||||||
# Spam protection (ignore FokaBot)
|
# Spam protection (ignore FokaBot)
|
||||||
if userID > 999:
|
if token.userID > 999:
|
||||||
token.spamProtection()
|
token.spamProtection()
|
||||||
|
|
||||||
# Fokabot message
|
# Fokabot message
|
||||||
if isChannel == True or to.lower() == "fokabot":
|
if isChannel == True or to.lower() == "fokabot":
|
||||||
fokaMessage = fokabot.fokabotResponse(username, to, message)
|
fokaMessage = fokabot.fokabotResponse(token.username, to, message)
|
||||||
if fokaMessage:
|
if fokaMessage:
|
||||||
sendMessage("FokaBot", to if isChannel else fro, fokaMessage)
|
sendMessage("FokaBot", to if isChannel else fro, fokaMessage)
|
||||||
|
|
||||||
# File and discord logs (public chat only)
|
# File and discord logs (public chat only)
|
||||||
if to.startswith("#") and not (message.startswith("\x01ACTION is playing") and to.startswith("#spect_")):
|
if to.startswith("#") and not (message.startswith("\x01ACTION is playing") and to.startswith("#spect_")):
|
||||||
log.chat("{fro} @ {to}: {message}".format(fro=username, to=to, message=str(message.encode("utf-8"))))
|
log.chat("{fro} @ {to}: {message}".format(fro=token.username, to=to, message=str(message.encode("utf-8"))))
|
||||||
glob.schiavo.sendChatlog("**{fro} @ {to}:** {message}".format(fro=username, to=to, message=str(message.encode("utf-8"))[2:-1]))
|
glob.schiavo.sendChatlog("**{fro} @ {to}:** {message}".format(fro=token.username, to=to, message=str(message.encode("utf-8"))[2:-1]))
|
||||||
return 0
|
return 0
|
||||||
except exceptions.userSilencedException:
|
except exceptions.userSilencedException:
|
||||||
token.enqueue(serverPackets.silenceEndTime(token.getSilenceSecondsLeft()))
|
token.enqueue(serverPackets.silenceEndTime(token.getSilenceSecondsLeft()))
|
||||||
log.warning("{} tried to send a message during silence".format(username))
|
log.warning("{} tried to send a message during silence".format(token.username))
|
||||||
return 404
|
return 404
|
||||||
except exceptions.channelModeratedException:
|
except exceptions.channelModeratedException:
|
||||||
log.warning("{} tried to send a message to a channel that is in moderated mode ({})".format(username, to))
|
log.warning("{} tried to send a message to a channel that is in moderated mode ({})".format(token.username, to))
|
||||||
return 404
|
return 404
|
||||||
except exceptions.channelUnknownException:
|
except exceptions.channelUnknownException:
|
||||||
log.warning("{} tried to send a message to an unknown channel ({})".format(username, to))
|
log.warning("{} tried to send a message to an unknown channel ({})".format(token.username, to))
|
||||||
return 403
|
return 403
|
||||||
except exceptions.channelNoPermissionsException:
|
except exceptions.channelNoPermissionsException:
|
||||||
log.warning("{} tried to send a message to channel {}, but they have no write permissions".format(username, to))
|
log.warning("{} tried to send a message to channel {}, but they have no write permissions".format(token.username, to))
|
||||||
return 404
|
return 404
|
||||||
except exceptions.userRestrictedException:
|
except exceptions.userRestrictedException:
|
||||||
log.warning("{} tried to send a message {}, but the recipient is in restricted mode".format(username, to))
|
log.warning("{} tried to send a message {}, but the recipient is in restricted mode".format(token.username, to))
|
||||||
return 404
|
return 404
|
||||||
except exceptions.userTournamentException:
|
except exceptions.userTournamentException:
|
||||||
log.warning("{} tried to send a message {}, but the recipient is a tournament client".format(username, to))
|
log.warning("{} tried to send a message {}, but the recipient is a tournament client".format(token.username, to))
|
||||||
return 404
|
return 404
|
||||||
except exceptions.userNotFoundException:
|
except exceptions.userNotFoundException:
|
||||||
log.warning("User not connected to IRC/Bancho")
|
log.warning("User not connected to IRC/Bancho")
|
||||||
|
@@ -74,7 +74,7 @@ class config:
|
|||||||
self.config.get("localize","enable")
|
self.config.get("localize","enable")
|
||||||
self.config.get("localize","ipapiurl")
|
self.config.get("localize","ipapiurl")
|
||||||
return True
|
return True
|
||||||
except:
|
except configparser.Error:
|
||||||
return False
|
return False
|
||||||
|
|
||||||
def generateDefaultConfig(self):
|
def generateDefaultConfig(self):
|
||||||
|
@@ -30,7 +30,7 @@ def getLocation(ip):
|
|||||||
try:
|
try:
|
||||||
# Try to get position from Pikolo Aul's Go-Sanic ip API
|
# Try to get position from Pikolo Aul's Go-Sanic ip API
|
||||||
result = json.loads(urllib.request.urlopen("{}/{}".format(glob.conf.config["localize"]["ipapiurl"], ip), timeout=3).read().decode())["loc"].split(",")
|
result = json.loads(urllib.request.urlopen("{}/{}".format(glob.conf.config["localize"]["ipapiurl"], ip), timeout=3).read().decode())["loc"].split(",")
|
||||||
return (float(result[0]), float(result[1]))
|
return float(result[0]), float(result[1])
|
||||||
except:
|
except:
|
||||||
log.error("Error in get position")
|
log.error("Error in get position")
|
||||||
return (0, 0)
|
return 0, 0
|
||||||
|
@@ -136,7 +136,7 @@ cpdef bytes packData(__data, int dataType):
|
|||||||
|
|
||||||
return data
|
return data
|
||||||
|
|
||||||
cpdef bytes buildPacket(int __packet, list __packetData = []):
|
cpdef bytes buildPacket(int __packet, list __packetData = None):
|
||||||
"""
|
"""
|
||||||
Builds a packet
|
Builds a packet
|
||||||
|
|
||||||
@@ -144,6 +144,9 @@ cpdef bytes buildPacket(int __packet, list __packetData = []):
|
|||||||
:param __packetData: packet structure [[data, dataType], [data, dataType], ...]
|
:param __packetData: packet structure [[data, dataType], [data, dataType], ...]
|
||||||
:return: packet bytes
|
:return: packet bytes
|
||||||
"""
|
"""
|
||||||
|
# Default argument
|
||||||
|
if __packetData is None:
|
||||||
|
__packetData = []
|
||||||
# Set some variables
|
# Set some variables
|
||||||
cdef bytes packetData = bytes()
|
cdef bytes packetData = bytes()
|
||||||
cdef int packetLength = 0
|
cdef int packetLength = 0
|
||||||
@@ -183,7 +186,7 @@ cpdef int readPacketLength(bytes stream):
|
|||||||
return unpackData(stream[3:7], dataTypes.UINT32)
|
return unpackData(stream[3:7], dataTypes.UINT32)
|
||||||
|
|
||||||
|
|
||||||
cpdef readPacketData(bytes stream, list structure=[], bint hasFirstBytes = True):
|
cpdef readPacketData(bytes stream, list structure=None, bint hasFirstBytes = True):
|
||||||
"""
|
"""
|
||||||
Read packet data from `stream` according to `structure`
|
Read packet data from `stream` according to `structure`
|
||||||
:param stream: packet bytes
|
:param stream: packet bytes
|
||||||
@@ -192,6 +195,10 @@ cpdef readPacketData(bytes stream, list structure=[], bint hasFirstBytes = True)
|
|||||||
if False, `stream` has only packet data. Default: True
|
if False, `stream` has only packet data. Default: True
|
||||||
:return: {name: unpackedValue, ...}
|
:return: {name: unpackedValue, ...}
|
||||||
"""
|
"""
|
||||||
|
# Default list argument
|
||||||
|
if structure is None:
|
||||||
|
structure = []
|
||||||
|
|
||||||
# Read packet ID (first 2 bytes)
|
# Read packet ID (first 2 bytes)
|
||||||
cdef dict data = {}
|
cdef dict data = {}
|
||||||
|
|
||||||
|
@@ -43,7 +43,7 @@ def scheduleShutdown(sendRestartTime, restart, message = "", delay=20):
|
|||||||
:return:
|
:return:
|
||||||
"""
|
"""
|
||||||
# Console output
|
# Console output
|
||||||
log.info("Pep.py will {} in {} seconds!".format("restart" if restart else "shutdown", sendRestartTime+delay))
|
log.info("Pep.py will {} in {} seconds!".format("restart" if restart else "shutdown", sendRestartTime+delay), "bunker")
|
||||||
log.info("Sending server restart packets in {} seconds...".format(sendRestartTime))
|
log.info("Sending server restart packets in {} seconds...".format(sendRestartTime))
|
||||||
|
|
||||||
# Send notification if set
|
# Send notification if set
|
||||||
|
@@ -136,7 +136,7 @@ class Client:
|
|||||||
self.server.removeClient(self, quitmsg)
|
self.server.removeClient(self, quitmsg)
|
||||||
|
|
||||||
# Bancho logout
|
# Bancho logout
|
||||||
if callLogout:
|
if callLogout and self.banchoUsername != "":
|
||||||
chat.IRCDisconnect(self.IRCUsername)
|
chat.IRCDisconnect(self.IRCUsername)
|
||||||
|
|
||||||
|
|
||||||
@@ -350,11 +350,11 @@ class Client:
|
|||||||
self.sendMotd()
|
self.sendMotd()
|
||||||
self.__handleCommand = self.mainHandler
|
self.__handleCommand = self.mainHandler
|
||||||
|
|
||||||
def quitHandler(self, command, arguments):
|
def quitHandler(self, _, arguments):
|
||||||
"""QUIT command handler"""
|
"""QUIT command handler"""
|
||||||
self.disconnect(self.IRCUsername if len(arguments) < 1 else arguments[0])
|
self.disconnect(self.IRCUsername if len(arguments) < 1 else arguments[0])
|
||||||
|
|
||||||
def joinHandler(self, command, arguments):
|
def joinHandler(self, _, arguments):
|
||||||
"""JOIN command handler"""
|
"""JOIN command handler"""
|
||||||
if len(arguments) < 1:
|
if len(arguments) < 1:
|
||||||
self.reply461("JOIN")
|
self.reply461("JOIN")
|
||||||
@@ -402,13 +402,15 @@ class Client:
|
|||||||
self.replyCode(332, description, channel=channel)
|
self.replyCode(332, description, channel=channel)
|
||||||
|
|
||||||
# Build connected users list
|
# Build connected users list
|
||||||
users = glob.channels.channels[channel].connectedUsers[:]
|
if "chat/{}".format(channel) not in glob.streams.streams:
|
||||||
|
self.reply403(channel)
|
||||||
|
continue
|
||||||
|
users = glob.streams.streams["chat/{}".format(channel)].clients
|
||||||
usernames = []
|
usernames = []
|
||||||
for user in users:
|
for user in users:
|
||||||
token = glob.tokens.getTokenFromUserID(user)
|
if user not in glob.tokens.tokens:
|
||||||
if token is None:
|
|
||||||
continue
|
continue
|
||||||
usernames.append(chat.fixUsernameForIRC(token.username))
|
usernames.append(chat.fixUsernameForIRC(glob.tokens.tokens[user].username))
|
||||||
usernames = " ".join(usernames)
|
usernames = " ".join(usernames)
|
||||||
|
|
||||||
# Send IRC users list
|
# Send IRC users list
|
||||||
@@ -419,7 +421,7 @@ class Client:
|
|||||||
self.reply403(channel)
|
self.reply403(channel)
|
||||||
continue
|
continue
|
||||||
|
|
||||||
def partHandler(self, command, arguments):
|
def partHandler(self, _, arguments):
|
||||||
"""PART command handler"""
|
"""PART command handler"""
|
||||||
if len(arguments) < 1:
|
if len(arguments) < 1:
|
||||||
self.reply461("PART")
|
self.reply461("PART")
|
||||||
@@ -503,7 +505,7 @@ class Client:
|
|||||||
"""LUSERS command handler"""
|
"""LUSERS command handler"""
|
||||||
self.sendLusers()
|
self.sendLusers()
|
||||||
|
|
||||||
def pingHandler(self, command, arguments):
|
def pingHandler(self, _, arguments):
|
||||||
"""PING command handler"""
|
"""PING command handler"""
|
||||||
if len(arguments) < 1:
|
if len(arguments) < 1:
|
||||||
self.replyCode(409, "No origin specified")
|
self.replyCode(409, "No origin specified")
|
||||||
@@ -514,7 +516,7 @@ class Client:
|
|||||||
"""(fake) PONG command handler"""
|
"""(fake) PONG command handler"""
|
||||||
pass
|
pass
|
||||||
|
|
||||||
def awayHandler(self, command, arguments):
|
def awayHandler(self, _, arguments):
|
||||||
"""AWAY command handler"""
|
"""AWAY command handler"""
|
||||||
response = chat.IRCAway(self.banchoUsername, " ".join(arguments))
|
response = chat.IRCAway(self.banchoUsername, " ".join(arguments))
|
||||||
self.replyCode(response, "You are no longer marked as being away" if response == 305 else "You have been marked as being away")
|
self.replyCode(response, "You are no longer marked as being away" if response == 305 else "You have been marked as being away")
|
||||||
@@ -619,12 +621,11 @@ class Server:
|
|||||||
value.message(":{} PRIVMSG {} :{}".format(fro, to, message))
|
value.message(":{} PRIVMSG {} :{}".format(fro, to, message))
|
||||||
|
|
||||||
|
|
||||||
def removeClient(self, client, quitmsg):
|
def removeClient(self, client, _):
|
||||||
"""
|
"""
|
||||||
Remove a client from connected clients
|
Remove a client from connected clients
|
||||||
|
|
||||||
:param client: client object
|
:param client: client object
|
||||||
:param quitmsg: QUIT argument, useless atm
|
|
||||||
:return:
|
:return:
|
||||||
"""
|
"""
|
||||||
if client.socket in self.clients:
|
if client.socket in self.clients:
|
||||||
@@ -637,6 +638,7 @@ class Server:
|
|||||||
:return:
|
:return:
|
||||||
"""
|
"""
|
||||||
# Sentry
|
# Sentry
|
||||||
|
sentryClient = None
|
||||||
if glob.sentry:
|
if glob.sentry:
|
||||||
sentryClient = raven.Client(glob.conf.config["sentry"]["ircdns"])
|
sentryClient = raven.Client(glob.conf.config["sentry"]["ircdns"])
|
||||||
|
|
||||||
@@ -669,7 +671,7 @@ class Server:
|
|||||||
try:
|
try:
|
||||||
self.clients[conn] = Client(self, conn)
|
self.clients[conn] = Client(self, conn)
|
||||||
log.info("[IRC] Accepted connection from {}:{}".format(addr[0], addr[1]))
|
log.info("[IRC] Accepted connection from {}:{}".format(addr[0], addr[1]))
|
||||||
except socket.error as e:
|
except socket.error:
|
||||||
try:
|
try:
|
||||||
conn.close()
|
conn.close()
|
||||||
except:
|
except:
|
||||||
@@ -688,7 +690,7 @@ class Server:
|
|||||||
lastAliveCheck = now
|
lastAliveCheck = now
|
||||||
except:
|
except:
|
||||||
log.error("[IRC] Unknown error!\n```\n{}\n{}```".format(sys.exc_info(), traceback.format_exc()))
|
log.error("[IRC] Unknown error!\n```\n{}\n{}```".format(sys.exc_info(), traceback.format_exc()))
|
||||||
if glob.sentry:
|
if glob.sentry and sentryClient is not None:
|
||||||
sentryClient.captureException()
|
sentryClient.captureException()
|
||||||
|
|
||||||
def main(port=6667):
|
def main(port=6667):
|
||||||
|
@@ -18,7 +18,6 @@ class channel:
|
|||||||
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.hidden = hidden
|
self.hidden = hidden
|
||||||
|
|
||||||
# Client name (#spectator/#multiplayer)
|
# Client name (#spectator/#multiplayer)
|
||||||
@@ -28,27 +27,7 @@ class channel:
|
|||||||
elif self.name.startswith("#multi_"):
|
elif self.name.startswith("#multi_"):
|
||||||
self.clientName = "#multiplayer"
|
self.clientName = "#multiplayer"
|
||||||
|
|
||||||
def userJoin(self, userID):
|
# Make Foka join the channel
|
||||||
"""
|
fokaToken = glob.tokens.getTokenFromUserID(999)
|
||||||
Add a user to connected users
|
if fokaToken is not None:
|
||||||
|
fokaToken.joinChannel(self)
|
||||||
:param userID:
|
|
||||||
:return:
|
|
||||||
"""
|
|
||||||
if userID not in self.connectedUsers:
|
|
||||||
self.connectedUsers.append(userID)
|
|
||||||
|
|
||||||
def userPart(self, userID):
|
|
||||||
"""
|
|
||||||
Remove a user from connected users
|
|
||||||
|
|
||||||
:param userID:
|
|
||||||
:return:
|
|
||||||
"""
|
|
||||||
if userID in self.connectedUsers:
|
|
||||||
self.connectedUsers.remove(userID)
|
|
||||||
|
|
||||||
# Remove temp channels if empty or there's only fokabot connected
|
|
||||||
l = len(self.connectedUsers)
|
|
||||||
if self.temp == True and ((l == 0) or (l == 1 and 999 in self.connectedUsers)):
|
|
||||||
glob.channels.removeChannel(self.name)
|
|
@@ -1,6 +1,7 @@
|
|||||||
from common.log import logUtils as log
|
from common.log import logUtils as log
|
||||||
from objects import channel
|
from objects import channel
|
||||||
from objects import glob
|
from objects import glob
|
||||||
|
from helpers import chatHelper as chat
|
||||||
|
|
||||||
|
|
||||||
class channelList:
|
class channelList:
|
||||||
@@ -34,6 +35,7 @@ class channelList:
|
|||||||
:param hidden: if True, thic channel won't be shown in channels list
|
:param hidden: if True, thic channel won't be shown in channels list
|
||||||
:return:
|
:return:
|
||||||
"""
|
"""
|
||||||
|
glob.streams.add("chat/{}".format(name))
|
||||||
self.channels[name] = channel.channel(name, description, publicRead, publicWrite, temp, hidden)
|
self.channels[name] = channel.channel(name, description, publicRead, publicWrite, temp, hidden)
|
||||||
log.info("Created channel {}".format(name))
|
log.info("Created channel {}".format(name))
|
||||||
|
|
||||||
@@ -47,6 +49,7 @@ class channelList:
|
|||||||
"""
|
"""
|
||||||
if name in self.channels:
|
if name in self.channels:
|
||||||
return False
|
return False
|
||||||
|
glob.streams.add("chat/{}".format(name))
|
||||||
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))
|
||||||
|
|
||||||
@@ -60,5 +63,13 @@ class channelList:
|
|||||||
if name not in self.channels:
|
if name not in self.channels:
|
||||||
log.debug("{} is not in channels list".format(name))
|
log.debug("{} is not in channels list".format(name))
|
||||||
return
|
return
|
||||||
|
#glob.streams.broadcast("chat/{}".format(name), serverPackets.channelKicked(name))
|
||||||
|
stream = glob.streams.getStream("chat/{}".format(name))
|
||||||
|
if stream is not None:
|
||||||
|
for token in stream.clients:
|
||||||
|
if token in glob.tokens.tokens:
|
||||||
|
chat.partChannel(channel=name, token=glob.tokens.tokens[token], kick=True)
|
||||||
|
glob.streams.dispose("chat/{}".format(name))
|
||||||
|
glob.streams.remove("chat/{}".format(name))
|
||||||
self.channels.pop(name)
|
self.channels.pop(name)
|
||||||
log.info("Removed channel {}".format(name))
|
log.info("Removed channel {}".format(name))
|
||||||
|
@@ -11,7 +11,7 @@ from common.web import schiavo
|
|||||||
|
|
||||||
try:
|
try:
|
||||||
with open("version") as f:
|
with open("version") as f:
|
||||||
VERSION = f.read()
|
VERSION = f.read().strip()
|
||||||
if VERSION == "":
|
if VERSION == "":
|
||||||
raise Exception
|
raise Exception
|
||||||
except:
|
except:
|
||||||
|
@@ -355,6 +355,7 @@ class match:
|
|||||||
glob.streams.broadcast(self.streamName, serverPackets.matchComplete())
|
glob.streams.broadcast(self.streamName, serverPackets.matchComplete())
|
||||||
|
|
||||||
# Destroy playing stream
|
# Destroy playing stream
|
||||||
|
glob.streams.dispose(self.playingStreamName)
|
||||||
glob.streams.remove(self.playingStreamName)
|
glob.streams.remove(self.playingStreamName)
|
||||||
|
|
||||||
# Console output
|
# Console output
|
||||||
@@ -375,7 +376,7 @@ class match:
|
|||||||
"""
|
"""
|
||||||
Add someone to users in match
|
Add someone to users in match
|
||||||
|
|
||||||
:param userID: user id of the user
|
:param user: user object of the user
|
||||||
:return: True if join success, False if fail (room is full)
|
:return: True if join success, False if fail (room is full)
|
||||||
"""
|
"""
|
||||||
# Make sure we're not in this match
|
# Make sure we're not in this match
|
||||||
@@ -403,7 +404,7 @@ class match:
|
|||||||
"""
|
"""
|
||||||
Remove someone from users in match
|
Remove someone from users in match
|
||||||
|
|
||||||
:param userID: user if of the user
|
:param user: user object of the user
|
||||||
:return:
|
:return:
|
||||||
"""
|
"""
|
||||||
# Make sure the user is in room
|
# Make sure the user is in room
|
||||||
|
@@ -1,7 +1,6 @@
|
|||||||
from objects import match
|
from objects import match
|
||||||
from objects import glob
|
from objects import glob
|
||||||
from constants import serverPackets
|
from constants import serverPackets
|
||||||
from common.log import logUtils as log
|
|
||||||
|
|
||||||
class matchList:
|
class matchList:
|
||||||
def __init__(self):
|
def __init__(self):
|
||||||
@@ -40,9 +39,11 @@ class matchList:
|
|||||||
return
|
return
|
||||||
|
|
||||||
# Remove match object and stream
|
# Remove match object and stream
|
||||||
match = self.matches.pop(matchID)
|
_match = self.matches.pop(matchID)
|
||||||
glob.streams.remove(match.streamName)
|
glob.streams.dispose(_match.streamName)
|
||||||
glob.streams.remove(match.playingStreamName)
|
glob.streams.dispose(_match.playingStreamName)
|
||||||
|
glob.streams.remove(_match.streamName)
|
||||||
|
glob.streams.remove(_match.playingStreamName)
|
||||||
|
|
||||||
# Send match dispose packet to everyone in lobby
|
# Send match dispose packet to everyone in lobby
|
||||||
glob.streams.broadcast("lobby", serverPackets.disposeMatch(matchID))
|
glob.streams.broadcast("lobby", serverPackets.disposeMatch(matchID))
|
@@ -5,6 +5,7 @@ import uuid
|
|||||||
from common.constants import gameModes, actions
|
from common.constants import gameModes, actions
|
||||||
from common.log import logUtils as log
|
from common.log import logUtils as log
|
||||||
from common.ripple import userUtils
|
from common.ripple import userUtils
|
||||||
|
from constants import exceptions
|
||||||
from constants import serverPackets
|
from constants import serverPackets
|
||||||
from events import logoutEvent
|
from events import logoutEvent
|
||||||
from helpers import chatHelper as chat
|
from helpers import chatHelper as chat
|
||||||
@@ -39,6 +40,7 @@ class token:
|
|||||||
self.lock = threading.Lock() # Sync primitive
|
self.lock = threading.Lock() # Sync primitive
|
||||||
self.streams = []
|
self.streams = []
|
||||||
self.tournament = tournament
|
self.tournament = tournament
|
||||||
|
self.messagesBuffer = []
|
||||||
|
|
||||||
# Default variables
|
# Default variables
|
||||||
self.spectators = []
|
self.spectators = []
|
||||||
@@ -96,9 +98,14 @@ class token:
|
|||||||
"""
|
"""
|
||||||
Add bytes (packets) to queue
|
Add bytes (packets) to queue
|
||||||
|
|
||||||
:param bytes: (packet) bytes to enqueue
|
:param bytes_: (packet) bytes to enqueue
|
||||||
"""
|
"""
|
||||||
# TODO: reduce max queue size
|
|
||||||
|
# Never enqueue for IRC clients or Foka
|
||||||
|
if self.irc or self.userID < 999:
|
||||||
|
return
|
||||||
|
|
||||||
|
# Avoid memory leaks
|
||||||
if len(bytes_) < 10 * 10 ** 6:
|
if len(bytes_) < 10 * 10 ** 6:
|
||||||
self.queue += bytes_
|
self.queue += bytes_
|
||||||
else:
|
else:
|
||||||
@@ -108,29 +115,37 @@ class token:
|
|||||||
"""Resets the queue. Call when enqueued packets have been sent"""
|
"""Resets the queue. Call when enqueued packets have been sent"""
|
||||||
self.queue = bytes()
|
self.queue = bytes()
|
||||||
|
|
||||||
def joinChannel(self, channel):
|
def joinChannel(self, channelObject):
|
||||||
"""
|
"""
|
||||||
Add channel to joined channels list
|
Join a channel
|
||||||
|
|
||||||
:param channel: channel name
|
:param channelObject: channel object
|
||||||
|
:raises: exceptions.userAlreadyInChannelException()
|
||||||
|
exceptions.channelNoPermissionsException()
|
||||||
"""
|
"""
|
||||||
if channel not in self.joinedChannels:
|
if channelObject.name in self.joinedChannels:
|
||||||
self.joinedChannels.append(channel)
|
raise exceptions.userAlreadyInChannelException()
|
||||||
|
if channelObject.publicRead == False and self.admin == False:
|
||||||
|
raise exceptions.channelNoPermissionsException()
|
||||||
|
self.joinedChannels.append(channelObject.name)
|
||||||
|
self.joinStream("chat/{}".format(channelObject.name))
|
||||||
|
self.enqueue(serverPackets.channelJoinSuccess(self.userID, channelObject.clientName))
|
||||||
|
|
||||||
def partChannel(self, channel):
|
def partChannel(self, channelObject):
|
||||||
"""
|
"""
|
||||||
Remove channel from joined channels list
|
Remove channel from joined channels list
|
||||||
|
|
||||||
:param channel: channel name
|
:param channelObject: channel object
|
||||||
"""
|
"""
|
||||||
if channel in self.joinedChannels:
|
self.joinedChannels.remove(channelObject.name)
|
||||||
self.joinedChannels.remove(channel)
|
self.leaveStream("chat/{}".format(channelObject.name))
|
||||||
|
|
||||||
def setLocation(self, latitude, longitude):
|
def setLocation(self, latitude, longitude):
|
||||||
"""
|
"""
|
||||||
Set client location
|
Set client location
|
||||||
|
|
||||||
:param location: [latitude, longitude]
|
:param latitude: latitude
|
||||||
|
:param longitude: longitude
|
||||||
"""
|
"""
|
||||||
self.location = (latitude, longitude)
|
self.location = (latitude, longitude)
|
||||||
|
|
||||||
@@ -229,12 +244,12 @@ class token:
|
|||||||
chat.partChannel(token=hostToken, channel="#spect_{}".format(hostToken.userID), kick=True)
|
chat.partChannel(token=hostToken, channel="#spect_{}".format(hostToken.userID), kick=True)
|
||||||
hostToken.leaveStream(streamName)
|
hostToken.leaveStream(streamName)
|
||||||
|
|
||||||
|
# Console output
|
||||||
|
log.info("{} is no longer spectating {}. Current spectators: {}".format(self.username, self.spectatingUserID, hostToken.spectators))
|
||||||
|
|
||||||
# Part #spectator channel
|
# Part #spectator channel
|
||||||
chat.partChannel(token=self, channel="#spect_{}".format(self.spectatingUserID), kick=True)
|
chat.partChannel(token=self, channel="#spect_{}".format(self.spectatingUserID), kick=True)
|
||||||
|
|
||||||
# Console output
|
|
||||||
log.info("{} is no longer spectating {}".format(self.username, self.spectatingUserID))
|
|
||||||
|
|
||||||
# Set our spectating user to 0
|
# Set our spectating user to 0
|
||||||
self.spectating = None
|
self.spectating = None
|
||||||
self.spectatingUserID = 0
|
self.spectatingUserID = 0
|
||||||
@@ -324,7 +339,7 @@ class token:
|
|||||||
self.enqueue(serverPackets.loginFailed())
|
self.enqueue(serverPackets.loginFailed())
|
||||||
|
|
||||||
# Logout event
|
# Logout event
|
||||||
logoutEvent.handle(self, deleteToken=False)
|
logoutEvent.handle(self, deleteToken=self.irc)
|
||||||
|
|
||||||
def silence(self, seconds = None, reason = "", author = 999):
|
def silence(self, seconds = None, reason = "", author = 999):
|
||||||
"""
|
"""
|
||||||
@@ -486,4 +501,25 @@ class token:
|
|||||||
if self.awayMessage == "" or userID in self.sentAway:
|
if self.awayMessage == "" or userID in self.sentAway:
|
||||||
return False
|
return False
|
||||||
self.sentAway.append(userID)
|
self.sentAway.append(userID)
|
||||||
return True
|
return True
|
||||||
|
|
||||||
|
def addMessageInBuffer(self, chan, message):
|
||||||
|
"""
|
||||||
|
Add a message in messages buffer (10 messages, truncated at 50 chars).
|
||||||
|
Used as proof when the user gets reported.
|
||||||
|
|
||||||
|
:param chan: channel
|
||||||
|
:param message: message content
|
||||||
|
:return:
|
||||||
|
"""
|
||||||
|
if len(self.messagesBuffer) > 9:
|
||||||
|
self.messagesBuffer = self.messagesBuffer[1:]
|
||||||
|
self.messagesBuffer.append("{time} - {user}@{channel}: {message}".format(time=time.strftime("%H:%M", time.localtime()), user=self.username, channel=chan, message=message[:50]))
|
||||||
|
|
||||||
|
def getMessagesBufferString(self):
|
||||||
|
"""
|
||||||
|
Get the content of the messages buffer as a string
|
||||||
|
|
||||||
|
:return: messages buffer content as a string
|
||||||
|
"""
|
||||||
|
return "\n".join(x for x in self.messagesBuffer)
|
@@ -43,15 +43,29 @@ class stream:
|
|||||||
log.info("{} has left stream {}".format(token, self.name))
|
log.info("{} has left stream {}".format(token, self.name))
|
||||||
self.clients.remove(token)
|
self.clients.remove(token)
|
||||||
|
|
||||||
def broadcast(self, data):
|
def broadcast(self, data, but=None):
|
||||||
"""
|
"""
|
||||||
Send some data to all clients connected to this stream
|
Send some data to all (or some) clients connected to this stream
|
||||||
|
|
||||||
:param data: data to send
|
:param data: data to send
|
||||||
|
:param but: array of tokens to ignore. Default: None (send to everyone)
|
||||||
|
:return:
|
||||||
|
"""
|
||||||
|
if but is None:
|
||||||
|
but = []
|
||||||
|
for i in self.clients:
|
||||||
|
if i in glob.tokens.tokens:
|
||||||
|
if i not in but:
|
||||||
|
glob.tokens.tokens[i].enqueue(data)
|
||||||
|
else:
|
||||||
|
self.removeClient(token=i)
|
||||||
|
|
||||||
|
def dispose(self):
|
||||||
|
"""
|
||||||
|
Tell every client in this stream to leave the stream
|
||||||
|
|
||||||
:return:
|
:return:
|
||||||
"""
|
"""
|
||||||
for i in self.clients:
|
for i in self.clients:
|
||||||
if i in glob.tokens.tokens:
|
if i in glob.tokens.tokens:
|
||||||
glob.tokens.tokens[i].enqueue(data)
|
glob.tokens.tokens[i].leaveStream(self.name)
|
||||||
else:
|
|
||||||
self.removeClient(token=i)
|
|
@@ -1,6 +1,7 @@
|
|||||||
from objects import stream
|
from objects import stream
|
||||||
from objects import glob
|
from objects import glob
|
||||||
|
|
||||||
|
# TODO: use *args and **kwargs
|
||||||
class streamList:
|
class streamList:
|
||||||
def __init__(self):
|
def __init__(self):
|
||||||
self.streams = {}
|
self.streams = {}
|
||||||
@@ -55,25 +56,39 @@ class streamList:
|
|||||||
return
|
return
|
||||||
self.streams[streamName].removeClient(client=client, token=token)
|
self.streams[streamName].removeClient(client=client, token=token)
|
||||||
|
|
||||||
def broadcast(self, streamName, data):
|
def broadcast(self, streamName, data, but=None):
|
||||||
"""
|
"""
|
||||||
Send some data to all clients in a stream
|
Send some data to all clients in a stream
|
||||||
|
|
||||||
:param streamName: stream name
|
:param streamName: stream name
|
||||||
:param data: data to send
|
:param data: data to send
|
||||||
|
:param but: array of tokens to ignore. Default: None (send to everyone)
|
||||||
:return:
|
:return:
|
||||||
"""
|
"""
|
||||||
if streamName not in self.streams:
|
if streamName not in self.streams:
|
||||||
return
|
return
|
||||||
self.streams[streamName].broadcast(data)
|
self.streams[streamName].broadcast(data, but)
|
||||||
|
|
||||||
'''def getClients(self, streamName):
|
def dispose(self, streamName, *args, **kwargs):
|
||||||
"""
|
"""
|
||||||
Get all clients in a stream
|
Call `dispose` on `streamName`
|
||||||
|
|
||||||
:param streamName: name of the stream
|
:param streamName: name of the stream
|
||||||
|
:param args:
|
||||||
|
:param kwargs:
|
||||||
:return:
|
:return:
|
||||||
"""
|
"""
|
||||||
if streamName not in self.streams:
|
if streamName not in self.streams:
|
||||||
return
|
return
|
||||||
return self.streams[streamName].clients'''
|
self.streams[streamName].dispose(*args, **kwargs)
|
||||||
|
|
||||||
|
def getStream(self, streamName):
|
||||||
|
"""
|
||||||
|
Returns streamName's stream object or None if it doesn't exist
|
||||||
|
|
||||||
|
:param streamName:
|
||||||
|
:return:
|
||||||
|
"""
|
||||||
|
if streamName in self.streams:
|
||||||
|
return self.streams[streamName]
|
||||||
|
return None
|
@@ -1,6 +1,8 @@
|
|||||||
import threading
|
import threading
|
||||||
import time
|
import time
|
||||||
|
|
||||||
|
import redis
|
||||||
|
|
||||||
from common.ripple import userUtils
|
from common.ripple import userUtils
|
||||||
from common.log import logUtils as log
|
from common.log import logUtils as log
|
||||||
from constants import serverPackets
|
from constants import serverPackets
|
||||||
@@ -17,6 +19,7 @@ class tokenList:
|
|||||||
Add a token object to tokens list
|
Add a token object to tokens list
|
||||||
|
|
||||||
:param userID: user id associated to that token
|
:param userID: user id associated to that token
|
||||||
|
:param ip: ip address of the client
|
||||||
:param irc: if True, set this token as IRC client
|
:param irc: if True, set this token as IRC client
|
||||||
:param timeOffset: the time offset from UTC for this user. Default: 0.
|
:param timeOffset: the time offset from UTC for this user. Default: 0.
|
||||||
:param tournament: if True, flag this client as a tournement client. Default: True.
|
:param tournament: if True, flag this client as a tournement client. Default: True.
|
||||||
@@ -54,25 +57,34 @@ class tokenList:
|
|||||||
# Get userID associated to that token
|
# Get userID associated to that token
|
||||||
return self.tokens[token].userID
|
return self.tokens[token].userID
|
||||||
|
|
||||||
def getTokenFromUserID(self, userID, ignoreIRC=False):
|
def getTokenFromUserID(self, userID, ignoreIRC=False, _all=False):
|
||||||
"""
|
"""
|
||||||
Get token from a user ID
|
Get token from a user ID
|
||||||
|
|
||||||
:param userID: user ID to find
|
:param userID: user ID to find
|
||||||
:param ignoreIRC: if True, consider bancho clients only and skip IRC clients
|
:param ignoreIRC: if True, consider bancho clients only and skip IRC clients
|
||||||
|
:param _all: if True, return a list with all clients that match given username, otherwise return
|
||||||
|
only the first occurrence.
|
||||||
:return: False if not found, token object if found
|
:return: False if not found, token object if found
|
||||||
"""
|
"""
|
||||||
# Make sure the token exists
|
# Make sure the token exists
|
||||||
|
ret = []
|
||||||
for _, value in self.tokens.items():
|
for _, value in self.tokens.items():
|
||||||
if value.userID == userID:
|
if value.userID == userID:
|
||||||
if ignoreIRC and value.irc:
|
if ignoreIRC and value.irc:
|
||||||
continue
|
continue
|
||||||
return value
|
if _all:
|
||||||
|
ret.append(value)
|
||||||
|
else:
|
||||||
|
return value
|
||||||
|
|
||||||
# Return none if not found
|
# Return full list or None if not found
|
||||||
return None
|
if _all:
|
||||||
|
return ret
|
||||||
|
else:
|
||||||
|
return None
|
||||||
|
|
||||||
def getTokenFromUsername(self, username, ignoreIRC=False, safe=False):
|
def getTokenFromUsername(self, username, ignoreIRC=False, safe=False, _all=False):
|
||||||
"""
|
"""
|
||||||
Get an osuToken object from an username
|
Get an osuToken object from an username
|
||||||
|
|
||||||
@@ -80,20 +92,29 @@ class tokenList:
|
|||||||
:param ignoreIRC: if True, consider bancho clients only and skip IRC clients
|
:param ignoreIRC: if True, consider bancho clients only and skip IRC clients
|
||||||
:param safe: if True, username is a safe username,
|
:param safe: if True, username is a safe username,
|
||||||
compare it with token's safe username rather than normal username
|
compare it with token's safe username rather than normal username
|
||||||
|
:param _all: if True, return a list with all clients that match given username, otherwise return
|
||||||
|
only the first occurrence.
|
||||||
:return: osuToken object or None
|
:return: osuToken object or None
|
||||||
"""
|
"""
|
||||||
# lowercase
|
# lowercase
|
||||||
who = username.lower() if not safe else username
|
who = username.lower() if not safe else username
|
||||||
|
|
||||||
# Make sure the token exists
|
# Make sure the token exists
|
||||||
|
ret = []
|
||||||
for _, value in self.tokens.items():
|
for _, value in self.tokens.items():
|
||||||
if (not safe and value.username.lower() == who) or (safe and value.safeUsername == who):
|
if (not safe and value.username.lower() == who) or (safe and value.safeUsername == who):
|
||||||
if ignoreIRC and value.irc:
|
if ignoreIRC and value.irc:
|
||||||
continue
|
continue
|
||||||
return value
|
if _all:
|
||||||
|
ret.append(value)
|
||||||
|
else:
|
||||||
|
return value
|
||||||
|
|
||||||
# Return none if not found
|
# Return full list or None if not found
|
||||||
return None
|
if _all:
|
||||||
|
return ret
|
||||||
|
else:
|
||||||
|
return None
|
||||||
|
|
||||||
def deleteOldTokens(self, userID):
|
def deleteOldTokens(self, userID):
|
||||||
"""
|
"""
|
||||||
@@ -197,7 +218,7 @@ class tokenList:
|
|||||||
try:
|
try:
|
||||||
# TODO: Make function or some redis meme
|
# TODO: Make function or some redis meme
|
||||||
glob.redis.eval("return redis.call('del', unpack(redis.call('keys', ARGV[1])))", 0, "peppy:sessions:*")
|
glob.redis.eval("return redis.call('del', unpack(redis.call('keys', ARGV[1])))", 0, "peppy:sessions:*")
|
||||||
except:
|
except redis.RedisError:
|
||||||
pass
|
pass
|
||||||
|
|
||||||
|
|
||||||
|
25
pep.py
25
pep.py
@@ -1,9 +1,7 @@
|
|||||||
"""Hello, pep.py here, ex-owner of ripple and prime minister of Ripwot."""
|
|
||||||
import os
|
import os
|
||||||
import sys
|
import sys
|
||||||
import threading
|
import threading
|
||||||
from multiprocessing.pool import ThreadPool
|
from multiprocessing.pool import ThreadPool
|
||||||
|
|
||||||
import tornado.gen
|
import tornado.gen
|
||||||
import tornado.httpserver
|
import tornado.httpserver
|
||||||
import tornado.ioloop
|
import tornado.ioloop
|
||||||
@@ -38,10 +36,10 @@ from pubSubHandlers import changeUsernameHandler
|
|||||||
|
|
||||||
from pubSubHandlers import disconnectHandler
|
from pubSubHandlers import disconnectHandler
|
||||||
from pubSubHandlers import banHandler
|
from pubSubHandlers import banHandler
|
||||||
|
from pubSubHandlers import notificationHandler
|
||||||
from pubSubHandlers import updateSilenceHandler
|
from pubSubHandlers import updateSilenceHandler
|
||||||
from pubSubHandlers import updateStatsHandler
|
from pubSubHandlers import updateStatsHandler
|
||||||
|
|
||||||
|
|
||||||
def make_app():
|
def make_app():
|
||||||
return tornado.web.Application([
|
return tornado.web.Application([
|
||||||
(r"/", mainHandler.handler),
|
(r"/", mainHandler.handler),
|
||||||
@@ -144,7 +142,7 @@ if __name__ == "__main__":
|
|||||||
consoleHelper.printNoNl("> Creating threads pool... ")
|
consoleHelper.printNoNl("> Creating threads pool... ")
|
||||||
glob.pool = ThreadPool(int(glob.conf.config["server"]["threads"]))
|
glob.pool = ThreadPool(int(glob.conf.config["server"]["threads"]))
|
||||||
consoleHelper.printDone()
|
consoleHelper.printDone()
|
||||||
except:
|
except ValueError:
|
||||||
consoleHelper.printError()
|
consoleHelper.printError()
|
||||||
consoleHelper.printColored("[!] Error while creating threads pool. Please check your config.ini and run the server again", bcolors.RED)
|
consoleHelper.printColored("[!] Error while creating threads pool. Please check your config.ini and run the server again", bcolors.RED)
|
||||||
|
|
||||||
@@ -157,6 +155,11 @@ if __name__ == "__main__":
|
|||||||
consoleHelper.printColored("[!] Error while loading chat filters. Make sure there is a filters.txt file present", bcolors.RED)
|
consoleHelper.printColored("[!] Error while loading chat filters. Make sure there is a filters.txt file present", bcolors.RED)
|
||||||
raise
|
raise
|
||||||
|
|
||||||
|
# Start fokabot
|
||||||
|
consoleHelper.printNoNl("> Connecting FokaBot... ")
|
||||||
|
fokabot.connect()
|
||||||
|
consoleHelper.printDone()
|
||||||
|
|
||||||
# Initialize chat channels
|
# Initialize chat channels
|
||||||
print("> Initializing chat channels... ")
|
print("> Initializing chat channels... ")
|
||||||
glob.channels.loadChannels()
|
glob.channels.loadChannels()
|
||||||
@@ -168,11 +171,6 @@ if __name__ == "__main__":
|
|||||||
glob.streams.add("lobby")
|
glob.streams.add("lobby")
|
||||||
consoleHelper.printDone()
|
consoleHelper.printDone()
|
||||||
|
|
||||||
# Start fokabot
|
|
||||||
consoleHelper.printNoNl("> Connecting FokaBot... ")
|
|
||||||
fokabot.connect()
|
|
||||||
consoleHelper.printDone()
|
|
||||||
|
|
||||||
# Initialize user timeout check loop
|
# Initialize user timeout check loop
|
||||||
consoleHelper.printNoNl("> Initializing user timeout check loop... ")
|
consoleHelper.printNoNl("> Initializing user timeout check loop... ")
|
||||||
glob.tokens.usersTimeoutCheckLoop()
|
glob.tokens.usersTimeoutCheckLoop()
|
||||||
@@ -190,7 +188,7 @@ if __name__ == "__main__":
|
|||||||
|
|
||||||
# Discord
|
# Discord
|
||||||
if generalUtils.stringToBool(glob.conf.config["discord"]["enable"]):
|
if generalUtils.stringToBool(glob.conf.config["discord"]["enable"]):
|
||||||
glob.schiavo = schiavo.schiavo(glob.conf.config["discord"]["boturl"])
|
glob.schiavo = schiavo.schiavo(glob.conf.config["discord"]["boturl"], "**pep.py**")
|
||||||
else:
|
else:
|
||||||
consoleHelper.printColored("[!] Warning! Discord logging is disabled!", bcolors.YELLOW)
|
consoleHelper.printColored("[!] Warning! Discord logging is disabled!", bcolors.YELLOW)
|
||||||
|
|
||||||
@@ -250,9 +248,10 @@ if __name__ == "__main__":
|
|||||||
glob.irc = generalUtils.stringToBool(glob.conf.config["irc"]["enable"])
|
glob.irc = generalUtils.stringToBool(glob.conf.config["irc"]["enable"])
|
||||||
if glob.irc:
|
if glob.irc:
|
||||||
# IRC port
|
# IRC port
|
||||||
|
ircPort = 0
|
||||||
try:
|
try:
|
||||||
ircPort = int(glob.conf.config["irc"]["port"])
|
ircPort = int(glob.conf.config["irc"]["port"])
|
||||||
except:
|
except ValueError:
|
||||||
consoleHelper.printColored("[!] Invalid IRC port! Please check your config.ini and run the server again", bcolors.RED)
|
consoleHelper.printColored("[!] Invalid IRC port! Please check your config.ini and run the server again", bcolors.RED)
|
||||||
log.logMessage("**pep.py** IRC server started!", discord="bunker", of="info.txt", stdout=False)
|
log.logMessage("**pep.py** IRC server started!", discord="bunker", of="info.txt", stdout=False)
|
||||||
consoleHelper.printColored("> IRC server listening on 127.0.0.1:{}...".format(ircPort), bcolors.GREEN)
|
consoleHelper.printColored("> IRC server listening on 127.0.0.1:{}...".format(ircPort), bcolors.GREEN)
|
||||||
@@ -261,9 +260,10 @@ if __name__ == "__main__":
|
|||||||
consoleHelper.printColored("[!] Warning! IRC server is disabled!", bcolors.YELLOW)
|
consoleHelper.printColored("[!] Warning! IRC server is disabled!", bcolors.YELLOW)
|
||||||
|
|
||||||
# Server port
|
# Server port
|
||||||
|
serverPort = 0
|
||||||
try:
|
try:
|
||||||
serverPort = int(glob.conf.config["server"]["port"])
|
serverPort = int(glob.conf.config["server"]["port"])
|
||||||
except:
|
except ValueError:
|
||||||
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
|
||||||
@@ -278,6 +278,7 @@ if __name__ == "__main__":
|
|||||||
"peppy:update_cached_stats": updateStatsHandler.handler(),
|
"peppy:update_cached_stats": updateStatsHandler.handler(),
|
||||||
"peppy:silence": updateSilenceHandler.handler(),
|
"peppy:silence": updateSilenceHandler.handler(),
|
||||||
"peppy:ban": banHandler.handler(),
|
"peppy:ban": banHandler.handler(),
|
||||||
|
"peppy:notification": notificationHandler.handler(),
|
||||||
}).start()
|
}).start()
|
||||||
|
|
||||||
# Start tornado
|
# Start tornado
|
||||||
|
@@ -6,6 +6,7 @@ from objects import glob
|
|||||||
|
|
||||||
def handleUsernameChange(userID, newUsername, targetToken=None):
|
def handleUsernameChange(userID, newUsername, targetToken=None):
|
||||||
try:
|
try:
|
||||||
|
userUtils.appendNotes(userID, "-- Username change: '{}' -> '{}'".format(userUtils.getUsername(userID), newUsername))
|
||||||
userUtils.changeUsername(userID, newUsername=newUsername)
|
userUtils.changeUsername(userID, newUsername=newUsername)
|
||||||
if targetToken is not None:
|
if targetToken is not None:
|
||||||
targetToken.kick("Your username has been changed to {}. Please log in again.".format(newUsername), "username_change")
|
targetToken.kick("Your username has been changed to {}. Please log in again.".format(newUsername), "username_change")
|
||||||
|
19
pubSubHandlers/notificationHandler.py
Normal file
19
pubSubHandlers/notificationHandler.py
Normal file
@@ -0,0 +1,19 @@
|
|||||||
|
from common.redis import generalPubSubHandler
|
||||||
|
from objects import glob
|
||||||
|
from constants import serverPackets
|
||||||
|
|
||||||
|
class handler(generalPubSubHandler.generalPubSubHandler):
|
||||||
|
def __init__(self):
|
||||||
|
super().__init__()
|
||||||
|
self.structure = {
|
||||||
|
"userID": 0,
|
||||||
|
"message": ""
|
||||||
|
}
|
||||||
|
|
||||||
|
def handle(self, data):
|
||||||
|
data = super().parseData(data)
|
||||||
|
if data is None:
|
||||||
|
return
|
||||||
|
targetToken = glob.tokens.getTokenFromUserID(data["userID"])
|
||||||
|
if targetToken is not None:
|
||||||
|
targetToken.enqueue(serverPackets.notification(data["message"]))
|
@@ -6,4 +6,5 @@ raven
|
|||||||
bcrypt>=3.1.1
|
bcrypt>=3.1.1
|
||||||
dill
|
dill
|
||||||
redis
|
redis
|
||||||
cython
|
cython
|
||||||
|
datadog
|
Reference in New Issue
Block a user