Compare commits
21 Commits
Author | SHA1 | Date | |
---|---|---|---|
|
e92cbe47bd | ||
|
6ca2016f7b | ||
|
2f54a56b7a | ||
|
cf9e506875 | ||
|
5c93d692ea | ||
|
a8a1dfb1bc | ||
|
9d562e7acd | ||
|
4f4253afce | ||
|
04898c24ae | ||
|
1b94936092 | ||
|
d4591b42a3 | ||
|
69508f9a0e | ||
|
5cf8c1bde8 | ||
|
20be60d9db | ||
|
61935f323c | ||
|
cecef18d13 | ||
|
5723c0e68f | ||
|
525235a27e | ||
|
3bc390e3e6 | ||
|
f6ae673401 | ||
|
aa32e8bea6 |
6
.gitignore
vendored
6
.gitignore
vendored
@@ -1,9 +1,9 @@
|
||||
**/__pycache__
|
||||
**/build
|
||||
config.ini
|
||||
filters.txt
|
||||
.data
|
||||
.idea
|
||||
common_funzia
|
||||
common_refractor
|
||||
common_memato
|
||||
redistest.py
|
||||
*.c
|
||||
*.so
|
13
README.md
13
README.md
@@ -1,4 +1,8 @@
|
||||
## pep.py
|
||||
|
||||
- Origin: https://git.zxq.co/ripple/pep.py
|
||||
- Mirror: https://github.com/osuripple/pep.py
|
||||
|
||||
This is Ripple's bancho server. It handles:
|
||||
- Client login
|
||||
- Online users listing and statuses
|
||||
@@ -9,6 +13,8 @@ This is Ripple's bancho server. It handles:
|
||||
|
||||
## Requirements
|
||||
- Python 3.5
|
||||
- Cython
|
||||
- C compiler
|
||||
- MySQLdb (`mysqlclient`)
|
||||
- Tornado
|
||||
- Bcrypt
|
||||
@@ -23,9 +29,14 @@ afterwards, install the required dependencies with pip
|
||||
```
|
||||
$ pip install -r requirements.txt
|
||||
```
|
||||
then, run pep.py once to create the default config file and edit it
|
||||
then, compile all `*.pyx` files to `*.so` or `*.dll` files using `setup.py` (distutils file)
|
||||
```
|
||||
$ python3 setup.py build_ext --inplace
|
||||
```
|
||||
finally, run pep.py once to create the default config file and edit it
|
||||
```
|
||||
$ python3 pep.py
|
||||
...
|
||||
$ nano config.ini
|
||||
```
|
||||
you can run pep.py by typing
|
||||
|
2
common
2
common
Submodule common updated: db36e8d589...3288420cd8
@@ -304,22 +304,7 @@ def systemShutdown(fro, chan, message):
|
||||
return restartShutdown(False)
|
||||
|
||||
def systemReload(fro, chan, message):
|
||||
# Reload settings from bancho_settings
|
||||
glob.banchoConf.loadSettings()
|
||||
|
||||
# Reload channels too
|
||||
glob.channels.loadChannels()
|
||||
|
||||
# And chat filters
|
||||
glob.chatFilters.loadFilters()
|
||||
|
||||
# Send new channels and new bottom icon to everyone
|
||||
glob.streams.broadcast("main", serverPackets.mainMenuIcon(glob.banchoConf.config["menuIcon"]))
|
||||
glob.streams.broadcast("main", serverPackets.channelInfoEnd())
|
||||
for key, value in glob.channels.channels.items():
|
||||
if value.publicRead == True and value.hidden == False:
|
||||
glob.streams.broadcast("main", serverPackets.channelInfo(key))
|
||||
|
||||
glob.banchoConf.reload()
|
||||
return "Bancho settings reloaded!"
|
||||
|
||||
def systemMaintenance(fro, chan, message):
|
||||
@@ -753,7 +738,7 @@ commands = [
|
||||
"callback": moderated
|
||||
}, {
|
||||
"trigger": "!kickall",
|
||||
"privileges": privileges.ADMIN_KICK_USERS,
|
||||
"privileges": privileges.ADMIN_MANAGE_SERVERS,
|
||||
"callback": kickAll
|
||||
}, {
|
||||
"trigger": "!kick",
|
||||
|
@@ -5,20 +5,19 @@ from constants import clientPackets
|
||||
from constants import serverPackets
|
||||
from objects import glob
|
||||
|
||||
|
||||
def handle(userToken, packetData):
|
||||
# Get usertoken data
|
||||
userID = userToken.userID
|
||||
username = userToken.username
|
||||
|
||||
# Make sure we are not banned
|
||||
if userUtils.isBanned(userID):
|
||||
userToken.enqueue(serverPackets.loginBanned())
|
||||
return
|
||||
#if userUtils.isBanned(userID):
|
||||
# userToken.enqueue(serverPackets.loginBanned())
|
||||
# return
|
||||
|
||||
# Send restricted message if needed
|
||||
if userToken.restricted:
|
||||
userToken.checkRestricted(True)
|
||||
#if userToken.restricted:
|
||||
# userToken.checkRestricted(True)
|
||||
|
||||
# Change action packet
|
||||
packetData = clientPackets.userActionChange(packetData)
|
||||
@@ -34,8 +33,10 @@ if userToken.matchID != -1 and userToken.actionID != actions.MULTIPLAYING and us
|
||||
'''
|
||||
|
||||
# Update cached stats if our pp changed if we've just submitted a score or we've changed gameMode
|
||||
if (userToken.actionID == actions.PLAYING or userToken.actionID == actions.MULTIPLAYING) or (userToken.pp != userUtils.getPP(userID, userToken.gameMode)) or (userToken.gameMode != packetData["gameMode"]):
|
||||
# Always update game mode, or we'll cache stats from the wrong game mode if we've changed it
|
||||
#if (userToken.actionID == actions.PLAYING or userToken.actionID == actions.MULTIPLAYING) or (userToken.pp != userUtils.getPP(userID, userToken.gameMode)) or (userToken.gameMode != packetData["gameMode"]):
|
||||
|
||||
# Update cached stats if we've changed gamemode
|
||||
if userToken.gameMode != packetData["gameMode"]:
|
||||
userToken.gameMode = packetData["gameMode"]
|
||||
userToken.updateCachedStats()
|
||||
|
||||
|
@@ -1,4 +1,5 @@
|
||||
import time
|
||||
import json
|
||||
|
||||
from common.log import logUtils as log
|
||||
from constants import serverPackets
|
||||
@@ -6,7 +7,7 @@ from helpers import chatHelper as chat
|
||||
from objects import glob
|
||||
|
||||
|
||||
def handle(userToken, _=None):
|
||||
def handle(userToken, _=None, deleteToken=True):
|
||||
# get usertoken data
|
||||
userID = userToken.userID
|
||||
username = userToken.username
|
||||
@@ -38,7 +39,19 @@ def handle(userToken, _=None):
|
||||
glob.ircServer.forceDisconnection(userToken.username)
|
||||
|
||||
# Delete token
|
||||
glob.tokens.deleteToken(requestToken)
|
||||
if deleteToken:
|
||||
glob.tokens.deleteToken(requestToken)
|
||||
else:
|
||||
userToken.kicked = True
|
||||
|
||||
# Change username if needed
|
||||
newUsername = glob.redis.get("ripple:change_username_pending:{}".format(userID))
|
||||
if newUsername is not None:
|
||||
log.debug("Sending username change request for user {}".format(userID))
|
||||
glob.redis.publish("peppy:change_username", json.dumps({
|
||||
"userID": userID,
|
||||
"newUsername": newUsername.decode("utf-8")
|
||||
}))
|
||||
|
||||
# Console output
|
||||
log.info("{} has been disconnected. (logout)".format(username))
|
||||
|
4
full_build.sh
Normal file
4
full_build.sh
Normal file
@@ -0,0 +1,4 @@
|
||||
find . -name "*.c" -type f -delete
|
||||
find . -name "*.o" -type f -delete
|
||||
find . -name "*.so" -type f -delete
|
||||
python3 setup.py build_ext --inplace
|
@@ -10,7 +10,7 @@ class handler(requestsManager.asyncRequestHandler):
|
||||
data = {"message": "unknown error"}
|
||||
try:
|
||||
# Get online users count
|
||||
data["result"] = len(glob.tokens.tokens)
|
||||
data["result"] = int(glob.redis.get("ripple:online_users").decode("utf-8"))
|
||||
|
||||
# Status code and message
|
||||
statusCode = 200
|
||||
|
@@ -122,7 +122,7 @@ class handler(SentryMixin, requestsManager.asyncRequestHandler):
|
||||
packetIDs.client_userStatsRequest: handleEvent(userStatsRequestEvent),
|
||||
packetIDs.client_requestStatusUpdate: handleEvent(requestStatusUpdateEvent),
|
||||
packetIDs.client_userPanelRequest: handleEvent(userPanelRequestEvent),
|
||||
|
||||
|
||||
packetIDs.client_channelJoin: handleEvent(channelJoinEvent),
|
||||
packetIDs.client_channelPart: handleEvent(channelPartEvent),
|
||||
packetIDs.client_sendPublicMessage: handleEvent(sendPublicMessageEvent),
|
||||
@@ -206,6 +206,9 @@ class handler(SentryMixin, requestsManager.asyncRequestHandler):
|
||||
userToken.updatePingTime()
|
||||
# Release token lock
|
||||
userToken.lock.release()
|
||||
# Delete token if kicked
|
||||
if userToken.kicked:
|
||||
glob.tokens.deleteToken(userToken)
|
||||
|
||||
if glob.outputRequestTime:
|
||||
# End time
|
@@ -127,9 +127,9 @@ class config:
|
||||
self.config.set("discord", "devgroup", "")
|
||||
|
||||
self.config.add_section("datadog")
|
||||
self.config.set("datadog", "enable")
|
||||
self.config.set("datadog", "apikey")
|
||||
self.config.set("datadog", "appkey")
|
||||
self.config.set("datadog", "enable", "0")
|
||||
self.config.set("datadog", "apikey", "")
|
||||
self.config.set("datadog", "appkey", "")
|
||||
|
||||
self.config.add_section("irc")
|
||||
self.config.set("irc", "enable", "1")
|
||||
|
@@ -1,15 +1,15 @@
|
||||
import struct
|
||||
from constants import dataTypes
|
||||
|
||||
def uleb128Encode(num):
|
||||
cpdef bytearray uleb128Encode(int num):
|
||||
"""
|
||||
Encode an int to uleb128
|
||||
|
||||
:param num: int to encode
|
||||
:return: bytearray with encoded number
|
||||
"""
|
||||
arr = bytearray()
|
||||
length = 0
|
||||
cdef bytearray arr = bytearray()
|
||||
cdef int length = 0
|
||||
|
||||
if num == 0:
|
||||
return bytearray(b"\x00")
|
||||
@@ -23,15 +23,16 @@ def uleb128Encode(num):
|
||||
|
||||
return arr
|
||||
|
||||
def uleb128Decode(num):
|
||||
cpdef list uleb128Decode(bytes num):
|
||||
"""
|
||||
Decode a uleb128 to int
|
||||
|
||||
:param num: encoded uleb128 int
|
||||
:return: (total, length)
|
||||
"""
|
||||
shift = 0
|
||||
arr = [0,0] #total, length
|
||||
cdef int shift = 0
|
||||
cdef list arr = [0,0] #total, length
|
||||
cdef int b
|
||||
|
||||
while True:
|
||||
b = num[arr[1]]
|
||||
@@ -43,7 +44,7 @@ def uleb128Decode(num):
|
||||
|
||||
return arr
|
||||
|
||||
def unpackData(data, dataType):
|
||||
cpdef unpackData(bytes data, int dataType):
|
||||
"""
|
||||
Unpacks a single section of a packet.
|
||||
|
||||
@@ -74,7 +75,7 @@ def unpackData(data, dataType):
|
||||
# Unpack
|
||||
return struct.unpack(unpackType, bytes(data))[0]
|
||||
|
||||
def packData(__data, dataType):
|
||||
cpdef bytes packData(__data, int dataType):
|
||||
"""
|
||||
Packs a single section of a packet.
|
||||
|
||||
@@ -82,8 +83,9 @@ def packData(__data, dataType):
|
||||
:param dataType: data type
|
||||
:return: packed bytes
|
||||
"""
|
||||
data = bytes() # data to return
|
||||
pack = True # if True, use pack. False only with strings
|
||||
cdef bytes data = bytes() # data to return
|
||||
cdef bint pack = True # if True, use pack. False only with strings
|
||||
cdef str packType
|
||||
|
||||
# Get right pack Type
|
||||
if dataType == dataTypes.BBYTES:
|
||||
@@ -134,7 +136,7 @@ def packData(__data, dataType):
|
||||
|
||||
return data
|
||||
|
||||
def buildPacket(__packet, __packetData=None):
|
||||
cpdef bytes buildPacket(int __packet, list __packetData = []):
|
||||
"""
|
||||
Builds a packet
|
||||
|
||||
@@ -143,13 +145,12 @@ def buildPacket(__packet, __packetData=None):
|
||||
:return: packet bytes
|
||||
"""
|
||||
# Set some variables
|
||||
if __packetData is None:
|
||||
__packetData = []
|
||||
packetData = bytes()
|
||||
packetLength = 0
|
||||
packetBytes = bytes()
|
||||
cdef bytes packetData = bytes()
|
||||
cdef int packetLength = 0
|
||||
cdef bytes packetBytes = bytes()
|
||||
|
||||
# Pack packet data
|
||||
cdef list i
|
||||
for i in __packetData:
|
||||
packetData += packData(i[0], i[1])
|
||||
|
||||
@@ -163,7 +164,7 @@ def buildPacket(__packet, __packetData=None):
|
||||
packetBytes += packetData # packet data
|
||||
return packetBytes
|
||||
|
||||
def readPacketID(stream):
|
||||
cpdef int readPacketID(bytes stream):
|
||||
"""
|
||||
Read packetID (first two bytes) from a packet
|
||||
|
||||
@@ -172,7 +173,7 @@ def readPacketID(stream):
|
||||
"""
|
||||
return unpackData(stream[0:2], dataTypes.UINT16)
|
||||
|
||||
def readPacketLength(stream):
|
||||
cpdef int readPacketLength(bytes stream):
|
||||
"""
|
||||
Read packet data length (3:7 bytes) from a packet
|
||||
|
||||
@@ -182,7 +183,7 @@ def readPacketLength(stream):
|
||||
return unpackData(stream[3:7], dataTypes.UINT32)
|
||||
|
||||
|
||||
def readPacketData(stream, structure=None, hasFirstBytes = True):
|
||||
cpdef readPacketData(bytes stream, list structure=[], bint hasFirstBytes = True):
|
||||
"""
|
||||
Read packet data from `stream` according to `structure`
|
||||
:param stream: packet bytes
|
||||
@@ -192,11 +193,10 @@ def readPacketData(stream, structure=None, hasFirstBytes = True):
|
||||
:return: {name: unpackedValue, ...}
|
||||
"""
|
||||
# Read packet ID (first 2 bytes)
|
||||
if structure is None:
|
||||
structure = []
|
||||
data = {}
|
||||
cdef dict data = {}
|
||||
|
||||
# Skip packet ID and packet length if needed
|
||||
cdef start, end
|
||||
if hasFirstBytes:
|
||||
end = 7
|
||||
start = 7
|
||||
@@ -205,6 +205,8 @@ def readPacketData(stream, structure=None, hasFirstBytes = True):
|
||||
start = 0
|
||||
|
||||
# Read packet
|
||||
cdef list i
|
||||
cdef bint unpack
|
||||
for i in structure:
|
||||
start = end
|
||||
unpack = True
|
||||
@@ -239,7 +241,10 @@ def readPacketData(stream, structure=None, hasFirstBytes = True):
|
||||
end = start+length[0]+length[1]+1
|
||||
|
||||
# Read bytes
|
||||
data[i[0]] = ''.join(chr(j) for j in stream[start+1+length[1]:end])
|
||||
#data[i[0]] = ''.join(chr(j) for j in stream[start+1+length[1]:end])
|
||||
data[i[0]] = ""
|
||||
for j in stream[start+1+length[1]:end]:
|
||||
data[i[0]] += chr(j)
|
||||
elif i[1] == dataTypes.BYTE:
|
||||
end = start+1
|
||||
elif i[1] == dataTypes.UINT16 or i[1] == dataTypes.SINT16:
|
@@ -1,5 +1,6 @@
|
||||
# TODO: Rewrite this shit
|
||||
from common import generalUtils
|
||||
from constants import serverPackets
|
||||
from objects import glob
|
||||
|
||||
|
||||
@@ -41,3 +42,20 @@ class banchoConfig:
|
||||
"""
|
||||
self.config["banchoMaintenance"] = maintenance
|
||||
glob.db.execute("UPDATE bancho_settings SET value_int = %s WHERE name = 'bancho_maintenance'", [int(maintenance)])
|
||||
|
||||
def reload(self):
|
||||
# Reload settings from bancho_settings
|
||||
glob.banchoConf.loadSettings()
|
||||
|
||||
# Reload channels too
|
||||
glob.channels.loadChannels()
|
||||
|
||||
# And chat filters
|
||||
glob.chatFilters.loadFilters()
|
||||
|
||||
# Send new channels and new bottom icon to everyone
|
||||
glob.streams.broadcast("main", serverPackets.mainMenuIcon(glob.banchoConf.config["menuIcon"]))
|
||||
glob.streams.broadcast("main", serverPackets.channelInfoEnd())
|
||||
for key, value in glob.channels.channels.items():
|
||||
if value.publicRead == True and value.hidden == False:
|
||||
glob.streams.broadcast("main", serverPackets.channelInfo(key))
|
@@ -31,6 +31,7 @@ class token:
|
||||
self.privileges = userUtils.getPrivileges(self.userID)
|
||||
self.admin = userUtils.isInPrivilegeGroup(self.userID, "developer") or userUtils.isInPrivilegeGroup(self.userID, "community manager")
|
||||
self.irc = irc
|
||||
self.kicked = False
|
||||
self.restricted = userUtils.isRestricted(self.userID)
|
||||
self.loginTime = int(time.time())
|
||||
self.pingTime = self.loginTime
|
||||
@@ -323,22 +324,28 @@ class token:
|
||||
self.enqueue(serverPackets.loginFailed())
|
||||
|
||||
# Logout event
|
||||
logoutEvent.handle(self, None)
|
||||
logoutEvent.handle(self, deleteToken=False)
|
||||
|
||||
def silence(self, seconds, reason, author = 999):
|
||||
def silence(self, seconds = None, reason = "", author = 999):
|
||||
"""
|
||||
Silences this user (db, packet and token)
|
||||
|
||||
:param seconds: silence length in seconds
|
||||
:param reason: silence reason
|
||||
:param seconds: silence length in seconds. If None, get it from db. Default: None
|
||||
:param reason: silence reason. Default: empty string
|
||||
:param author: userID of who has silenced the user. Default: 999 (FokaBot)
|
||||
:return:
|
||||
"""
|
||||
# Silence in db and token
|
||||
self.silenceEndTime = int(time.time())+seconds
|
||||
userUtils.silence(self.userID, seconds, reason, author)
|
||||
if seconds is None:
|
||||
# Get silence expire from db if needed
|
||||
seconds = max(0, userUtils.getSilenceEnd(self.userID) - int(time.time()))
|
||||
else:
|
||||
# Silence in db and token
|
||||
userUtils.silence(self.userID, seconds, reason, author)
|
||||
|
||||
# Send silence packet to target
|
||||
# Silence token
|
||||
self.silenceEndTime = int(time.time()) + seconds
|
||||
|
||||
# Send silence packet to user
|
||||
self.enqueue(serverPackets.silenceEndTime(seconds))
|
||||
|
||||
# Send silenced packet to everyone else
|
||||
@@ -394,18 +401,29 @@ class token:
|
||||
self.gameRank = stats["gameRank"]
|
||||
self.pp = stats["pp"]
|
||||
|
||||
def checkRestricted(self, force=False):
|
||||
def checkRestricted(self):
|
||||
"""
|
||||
Check if this token is restricted. If so, send fokabot message
|
||||
|
||||
:param force: If True, get restricted value from db.
|
||||
If False, get the cached one. Default: False
|
||||
:return:
|
||||
"""
|
||||
if force:
|
||||
self.restricted = userUtils.isRestricted(self.userID)
|
||||
oldRestricted = self.restricted
|
||||
self.restricted = userUtils.isRestricted(self.userID)
|
||||
if self.restricted:
|
||||
self.setRestricted()
|
||||
elif not self.restricted and oldRestricted != self.restricted:
|
||||
self.resetRestricted()
|
||||
|
||||
def checkBanned(self):
|
||||
"""
|
||||
Check if this user is banned. If so, disconnect it.
|
||||
|
||||
:return:
|
||||
"""
|
||||
if userUtils.isBanned(self.userID):
|
||||
self.enqueue(serverPackets.loginBanned())
|
||||
logoutEvent.handle(self, deleteToken=False)
|
||||
|
||||
|
||||
def setRestricted(self):
|
||||
"""
|
||||
@@ -415,7 +433,16 @@ class token:
|
||||
:return:
|
||||
"""
|
||||
self.restricted = True
|
||||
chat.sendMessage("FokaBot",self.username, "Your account is currently in restricted mode. Please visit ripple's website for more information.")
|
||||
chat.sendMessage("FokaBot", self.username, "Your account is currently in restricted mode. Please visit ripple's website for more information.")
|
||||
|
||||
def resetRestricted(self):
|
||||
"""
|
||||
Send FokaBot message to alert the user that he has been unrestricted
|
||||
and he has to log in again.
|
||||
|
||||
:return:
|
||||
"""
|
||||
chat.sendMessage("FokaBot", self.username, "Your account has been unrestricted! Please log in again.")
|
||||
|
||||
def joinStream(self, name):
|
||||
"""
|
||||
|
@@ -24,6 +24,7 @@ class tokenList:
|
||||
"""
|
||||
newToken = osuToken.token(userID, ip=ip, irc=irc, timeOffset=timeOffset, tournament=tournament)
|
||||
self.tokens[newToken.token] = newToken
|
||||
glob.redis.incr("ripple:online_users")
|
||||
return newToken
|
||||
|
||||
def deleteToken(self, token):
|
||||
@@ -34,12 +35,10 @@ class tokenList:
|
||||
:return:
|
||||
"""
|
||||
if token in self.tokens:
|
||||
# Delete session from DB
|
||||
if self.tokens[token].ip != "":
|
||||
userUtils.deleteBanchoSessions(self.tokens[token].userID, self.tokens[token].ip)
|
||||
|
||||
# Pop token from list
|
||||
self.tokens.pop(token)
|
||||
glob.redis.decr("ripple:online_users")
|
||||
|
||||
def getUserIDFromToken(self, token):
|
||||
"""
|
||||
@@ -104,10 +103,15 @@ class tokenList:
|
||||
:return:
|
||||
"""
|
||||
# Delete older tokens
|
||||
delete = []
|
||||
for key, value in list(self.tokens.items()):
|
||||
if value.userID == userID:
|
||||
# Delete this token from the dictionary
|
||||
self.tokens[key].kick("You have logged in from somewhere else. You can't connect to Bancho/IRC from more than one device at the same time.", "kicked, multiple clients")
|
||||
#self.tokens[key].kick("You have logged in from somewhere else. You can't connect to Bancho/IRC from more than one device at the same time.", "kicked, multiple clients")
|
||||
delete.append(self.tokens[key])
|
||||
|
||||
for i in delete:
|
||||
logoutEvent.handle(i)
|
||||
|
||||
def multipleEnqueue(self, packet, who, but = False):
|
||||
"""
|
||||
@@ -185,12 +189,16 @@ class tokenList:
|
||||
|
||||
def deleteBanchoSessions(self):
|
||||
"""
|
||||
Truncate bancho_sessions table.
|
||||
Remove all `peppy:sessions:*` redis keys.
|
||||
Call at bancho startup to delete old cached sessions
|
||||
|
||||
:return:
|
||||
"""
|
||||
glob.db.execute("TRUNCATE TABLE bancho_sessions")
|
||||
try:
|
||||
# TODO: Make function or some redis meme
|
||||
glob.redis.eval("return redis.call('del', unpack(redis.call('keys', ARGV[1])))", 0, "peppy:sessions:*")
|
||||
except:
|
||||
pass
|
||||
|
||||
|
||||
def tokenExists(self, username = "", userID = -1):
|
||||
|
42
pep.py
42
pep.py
@@ -16,7 +16,7 @@ from common.constants import bcolors
|
||||
from common.db import dbConnector
|
||||
from common.ddog import datadogClient
|
||||
from common.log import logUtils as log
|
||||
from common.ripple import userUtils
|
||||
from common.redis import pubSub
|
||||
from common.web import schiavo
|
||||
from handlers import apiFokabotMessageHandler
|
||||
from handlers import apiIsOnlineHandler
|
||||
@@ -34,6 +34,12 @@ from objects import banchoConfig
|
||||
from objects import chatFilters
|
||||
from objects import fokabot
|
||||
from objects import glob
|
||||
from pubSubHandlers import changeUsernameHandler
|
||||
|
||||
from pubSubHandlers import disconnectHandler
|
||||
from pubSubHandlers import banHandler
|
||||
from pubSubHandlers import updateSilenceHandler
|
||||
from pubSubHandlers import updateStatsHandler
|
||||
|
||||
|
||||
def make_app():
|
||||
@@ -108,6 +114,8 @@ if __name__ == "__main__":
|
||||
|
||||
# Empty redis cache
|
||||
try:
|
||||
# TODO: Make function or some redis meme
|
||||
glob.redis.set("ripple:online_users", 0)
|
||||
glob.redis.eval("return redis.call('del', unpack(redis.call('keys', ARGV[1])))", 0, "peppy:*")
|
||||
except redis.exceptions.ResponseError:
|
||||
# Script returns error if there are no keys starting with peppy:*
|
||||
@@ -222,18 +230,16 @@ if __name__ == "__main__":
|
||||
datadogClient.periodicCheck("online_users", lambda: len(glob.tokens.tokens)),
|
||||
datadogClient.periodicCheck("multiplayer_matches", lambda: len(glob.matches.matches)),
|
||||
|
||||
datadogClient.periodicCheck("ram_clients", lambda: generalUtils.getTotalSize(glob.tokens)),
|
||||
datadogClient.periodicCheck("ram_matches", lambda: generalUtils.getTotalSize(glob.matches)),
|
||||
datadogClient.periodicCheck("ram_channels", lambda: generalUtils.getTotalSize(glob.channels)),
|
||||
datadogClient.periodicCheck("ram_file_buffers", lambda: generalUtils.getTotalSize(glob.fileBuffers)),
|
||||
datadogClient.periodicCheck("ram_file_locks", lambda: generalUtils.getTotalSize(glob.fLocks)),
|
||||
datadogClient.periodicCheck("ram_datadog", lambda: generalUtils.getTotalSize(glob.datadogClient)),
|
||||
datadogClient.periodicCheck("ram_verified_cache", lambda: generalUtils.getTotalSize(glob.verifiedCache)),
|
||||
#datadogClient.periodicCheck("ram_userid_cache", lambda: generalUtils.getTotalSize(glob.userIDCache)),
|
||||
#datadogClient.periodicCheck("ram_pool", lambda: generalUtils.getTotalSize(glob.pool)),
|
||||
datadogClient.periodicCheck("ram_irc", lambda: generalUtils.getTotalSize(glob.ircServer)),
|
||||
datadogClient.periodicCheck("ram_tornado", lambda: generalUtils.getTotalSize(glob.application)),
|
||||
datadogClient.periodicCheck("ram_db", lambda: generalUtils.getTotalSize(glob.db)),
|
||||
#datadogClient.periodicCheck("ram_clients", lambda: generalUtils.getTotalSize(glob.tokens)),
|
||||
#datadogClient.periodicCheck("ram_matches", lambda: generalUtils.getTotalSize(glob.matches)),
|
||||
#datadogClient.periodicCheck("ram_channels", lambda: generalUtils.getTotalSize(glob.channels)),
|
||||
#datadogClient.periodicCheck("ram_file_buffers", lambda: generalUtils.getTotalSize(glob.fileBuffers)),
|
||||
#datadogClient.periodicCheck("ram_file_locks", lambda: generalUtils.getTotalSize(glob.fLocks)),
|
||||
#datadogClient.periodicCheck("ram_datadog", lambda: generalUtils.getTotalSize(glob.datadogClient)),
|
||||
#datadogClient.periodicCheck("ram_verified_cache", lambda: generalUtils.getTotalSize(glob.verifiedCache)),
|
||||
#datadogClient.periodicCheck("ram_irc", lambda: generalUtils.getTotalSize(glob.ircServer)),
|
||||
#datadogClient.periodicCheck("ram_tornado", lambda: generalUtils.getTotalSize(glob.application)),
|
||||
#datadogClient.periodicCheck("ram_db", lambda: generalUtils.getTotalSize(glob.db)),
|
||||
])
|
||||
else:
|
||||
consoleHelper.printColored("[!] Warning! Datadog stats tracking is disabled!", bcolors.YELLOW)
|
||||
@@ -264,6 +270,16 @@ if __name__ == "__main__":
|
||||
log.logMessage("**pep.py** Server started!", discord="bunker", of="info.txt", stdout=False)
|
||||
consoleHelper.printColored("> Tornado listening for HTTP(s) clients on 127.0.0.1:{}...".format(serverPort), bcolors.GREEN)
|
||||
|
||||
# Connect to pubsub channels
|
||||
pubSub.listener(glob.redis, {
|
||||
"peppy:disconnect": disconnectHandler.handler(),
|
||||
"peppy:change_username": changeUsernameHandler.handler(),
|
||||
"peppy:reload_settings": lambda x: x == b"reload" and glob.banchoConf.reload(),
|
||||
"peppy:update_cached_stats": updateStatsHandler.handler(),
|
||||
"peppy:silence": updateSilenceHandler.handler(),
|
||||
"peppy:ban": banHandler.handler(),
|
||||
}).start()
|
||||
|
||||
# Start tornado
|
||||
glob.application.listen(serverPort)
|
||||
tornado.ioloop.IOLoop.instance().start()
|
||||
|
0
pubSubHandlers/__init__.py
Normal file
0
pubSubHandlers/__init__.py
Normal file
18
pubSubHandlers/banHandler.py
Normal file
18
pubSubHandlers/banHandler.py
Normal file
@@ -0,0 +1,18 @@
|
||||
from common.redis import generalPubSubHandler
|
||||
from common.ripple import userUtils
|
||||
from objects import glob
|
||||
|
||||
class handler(generalPubSubHandler.generalPubSubHandler):
|
||||
def __init__(self):
|
||||
super().__init__()
|
||||
self.type = "int"
|
||||
|
||||
def handle(self, userID):
|
||||
userID = super().parseData(userID)
|
||||
if userID is None:
|
||||
return
|
||||
targetToken = glob.tokens.getTokenFromUserID(userID)
|
||||
if targetToken is not None:
|
||||
targetToken.privileges = userUtils.getPrivileges(userID)
|
||||
targetToken.checkBanned()
|
||||
targetToken.checkRestricted()
|
49
pubSubHandlers/changeUsernameHandler.py
Normal file
49
pubSubHandlers/changeUsernameHandler.py
Normal file
@@ -0,0 +1,49 @@
|
||||
from common.redis import generalPubSubHandler
|
||||
from common.ripple import userUtils
|
||||
from common.log import logUtils as log
|
||||
from common.constants import actions
|
||||
from objects import glob
|
||||
|
||||
def handleUsernameChange(userID, newUsername, targetToken=None):
|
||||
try:
|
||||
userUtils.changeUsername(userID, newUsername=newUsername)
|
||||
if targetToken is not None:
|
||||
targetToken.kick("Your username has been changed to {}. Please log in again.".format(newUsername), "username_change")
|
||||
except userUtils.usernameAlreadyInUseError:
|
||||
log.rap(999, "Username change: {} is already in use!", through="Bancho")
|
||||
if targetToken is not None:
|
||||
targetToken.kick("There was a critical error while trying to change your username. Please contact a developer.", "username_change_fail")
|
||||
except userUtils.invalidUsernameError:
|
||||
log.rap(999, "Username change: {} is not a valid username!", through="Bancho")
|
||||
if targetToken is not None:
|
||||
targetToken.kick("There was a critical error while trying to change your username. Please contact a developer.", "username_change_fail")
|
||||
|
||||
class handler(generalPubSubHandler.generalPubSubHandler):
|
||||
def __init__(self):
|
||||
super().__init__()
|
||||
self.structure = {
|
||||
"userID": 0,
|
||||
"newUsername": ""
|
||||
}
|
||||
|
||||
def handle(self, data):
|
||||
data = super().parseData(data)
|
||||
if data is None:
|
||||
return
|
||||
# Get the user's token
|
||||
targetToken = glob.tokens.getTokenFromUserID(data["userID"])
|
||||
if targetToken is None:
|
||||
# If the user is offline change username immediately
|
||||
handleUsernameChange(data["userID"], data["newUsername"])
|
||||
else:
|
||||
if targetToken.irc or (targetToken.actionID != actions.PLAYING and targetToken.actionID != actions.MULTIPLAYING):
|
||||
# If the user is online and he's connected through IRC or he's not playing,
|
||||
# change username and kick the user immediately
|
||||
handleUsernameChange(data["userID"], data["newUsername"], targetToken)
|
||||
else:
|
||||
# If the user is playing, delay the username change until he submits the score
|
||||
# On submit modular, lets will send the username change request again
|
||||
# through redis once the score has been submitted
|
||||
# The check is performed on bancho logout too, so if the user disconnects
|
||||
# without submitting a score, the username gets changed on bancho logout
|
||||
glob.redis.set("ripple:change_username_pending:{}".format(data["userID"]), data["newUsername"])
|
18
pubSubHandlers/disconnectHandler.py
Normal file
18
pubSubHandlers/disconnectHandler.py
Normal file
@@ -0,0 +1,18 @@
|
||||
from common.redis import generalPubSubHandler
|
||||
from objects import glob
|
||||
|
||||
class handler(generalPubSubHandler.generalPubSubHandler):
|
||||
def __init__(self):
|
||||
super().__init__()
|
||||
self.structure = {
|
||||
"userID": 0,
|
||||
"reason": ""
|
||||
}
|
||||
|
||||
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.kick(data["reason"], "pubsub_kick")
|
15
pubSubHandlers/updateSilenceHandler.py
Normal file
15
pubSubHandlers/updateSilenceHandler.py
Normal file
@@ -0,0 +1,15 @@
|
||||
from common.redis import generalPubSubHandler
|
||||
from objects import glob
|
||||
|
||||
class handler(generalPubSubHandler.generalPubSubHandler):
|
||||
def __init__(self):
|
||||
super().__init__()
|
||||
self.type = "int"
|
||||
|
||||
def handle(self, userID):
|
||||
userID = super().parseData(userID)
|
||||
if userID is None:
|
||||
return
|
||||
targetToken = glob.tokens.getTokenFromUserID(userID)
|
||||
if targetToken is not None:
|
||||
targetToken.silence()
|
15
pubSubHandlers/updateStatsHandler.py
Normal file
15
pubSubHandlers/updateStatsHandler.py
Normal file
@@ -0,0 +1,15 @@
|
||||
from common.redis import generalPubSubHandler
|
||||
from objects import glob
|
||||
|
||||
class handler(generalPubSubHandler.generalPubSubHandler):
|
||||
def __init__(self):
|
||||
super().__init__()
|
||||
self.type = "int"
|
||||
|
||||
def handle(self, userID):
|
||||
userID = super().parseData(userID)
|
||||
if userID is None:
|
||||
return
|
||||
targetToken = glob.tokens.getTokenFromUserID(userID)
|
||||
if targetToken is not None:
|
||||
targetToken.updateCachedStats()
|
@@ -5,4 +5,5 @@ psutil
|
||||
raven
|
||||
bcrypt>=3.1.1
|
||||
dill
|
||||
redis
|
||||
redis
|
||||
cython
|
17
setup.py
Normal file
17
setup.py
Normal file
@@ -0,0 +1,17 @@
|
||||
"""Cython build file"""
|
||||
from distutils.core import setup
|
||||
from distutils.extension import Extension
|
||||
from Cython.Build import cythonize
|
||||
import os
|
||||
|
||||
cythonExt = []
|
||||
for root, dirs, files in os.walk(os.getcwd()):
|
||||
for file in files:
|
||||
if file.endswith(".pyx"):
|
||||
filePath = os.path.relpath(os.path.join(root, file))
|
||||
cythonExt.append(Extension(filePath.replace("/", ".")[:-4], [filePath]))
|
||||
|
||||
setup(
|
||||
name = "pep.pyx modules",
|
||||
ext_modules = cythonize(cythonExt, nthreads = 4),
|
||||
)
|
Reference in New Issue
Block a user