Compare commits
2 Commits
Author | SHA1 | Date | |
---|---|---|---|
|
4cbaaafba5 | ||
|
fe283ff293 |
7
.gitignore
vendored
7
.gitignore
vendored
@@ -1,9 +1,8 @@
|
|||||||
**/__pycache__
|
**/__pycache__
|
||||||
**/build
|
|
||||||
config.ini
|
config.ini
|
||||||
filters.txt
|
filters.txt
|
||||||
.data
|
.data
|
||||||
.idea
|
.idea
|
||||||
redistest.py
|
common_funzia
|
||||||
*.c
|
common_refractor
|
||||||
*.so
|
common_memato
|
||||||
|
13
README.md
13
README.md
@@ -1,8 +1,4 @@
|
|||||||
## pep.py
|
## 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:
|
This is Ripple's bancho server. It handles:
|
||||||
- Client login
|
- Client login
|
||||||
- Online users listing and statuses
|
- Online users listing and statuses
|
||||||
@@ -13,8 +9,6 @@ This is Ripple's bancho server. It handles:
|
|||||||
|
|
||||||
## Requirements
|
## Requirements
|
||||||
- Python 3.5
|
- Python 3.5
|
||||||
- Cython
|
|
||||||
- C compiler
|
|
||||||
- MySQLdb (`mysqlclient`)
|
- MySQLdb (`mysqlclient`)
|
||||||
- Tornado
|
- Tornado
|
||||||
- Bcrypt
|
- Bcrypt
|
||||||
@@ -29,14 +23,9 @@ afterwards, install the required dependencies with pip
|
|||||||
```
|
```
|
||||||
$ pip install -r requirements.txt
|
$ pip install -r requirements.txt
|
||||||
```
|
```
|
||||||
then, compile all `*.pyx` files to `*.so` or `*.dll` files using `setup.py` (distutils file)
|
then, run pep.py once to create the default config file and edit it
|
||||||
```
|
|
||||||
$ python3 setup.py build_ext --inplace
|
|
||||||
```
|
|
||||||
finally, run pep.py once to create the default config file and edit it
|
|
||||||
```
|
```
|
||||||
$ python3 pep.py
|
$ python3 pep.py
|
||||||
...
|
|
||||||
$ nano config.ini
|
$ nano config.ini
|
||||||
```
|
```
|
||||||
you can run pep.py by typing
|
you can run pep.py by typing
|
||||||
|
2
common
2
common
Submodule common updated: 3288420cd8...d68736652c
@@ -1,3 +1,4 @@
|
|||||||
|
""" Contains functions used to read specific client packets from byte stream """
|
||||||
from constants import dataTypes
|
from constants import dataTypes
|
||||||
from helpers import packetHelper
|
from helpers import packetHelper
|
||||||
from constants import slotStatuses
|
from constants import slotStatuses
|
||||||
@@ -99,7 +100,7 @@ def matchSettings(stream):
|
|||||||
start += 2
|
start += 2
|
||||||
for i in range(0,16):
|
for i in range(0,16):
|
||||||
s = data[0]["slot{}Status".format(str(i))]
|
s = data[0]["slot{}Status".format(str(i))]
|
||||||
if s != slotStatuses.FREE and s != slotStatuses.LOCKED:
|
if s != slotStatuses.free and s != slotStatuses.locked:
|
||||||
start += 4
|
start += 4
|
||||||
|
|
||||||
# Other settings
|
# Other settings
|
||||||
|
@@ -1,3 +1,5 @@
|
|||||||
|
"""Bancho exceptions"""
|
||||||
|
# TODO: Prints in exceptions
|
||||||
class loginFailedException(Exception):
|
class loginFailedException(Exception):
|
||||||
pass
|
pass
|
||||||
|
|
||||||
|
@@ -4,6 +4,7 @@ import random
|
|||||||
import requests
|
import requests
|
||||||
|
|
||||||
from common import generalUtils
|
from common import generalUtils
|
||||||
|
from common.constants import actions
|
||||||
from common.constants import mods
|
from common.constants import mods
|
||||||
from common.log import logUtils as log
|
from common.log import logUtils as log
|
||||||
from common.ripple import userUtils
|
from common.ripple import userUtils
|
||||||
@@ -19,12 +20,12 @@ from objects import glob
|
|||||||
Commands callbacks
|
Commands callbacks
|
||||||
|
|
||||||
Must have fro, chan and messages as arguments
|
Must have fro, chan and messages as arguments
|
||||||
:param fro: username of who triggered the command
|
fro -- name of who triggered the command
|
||||||
:param chan: channel"(or username, if PM) where the message was sent
|
chan -- channel where the message was sent
|
||||||
:param message: list containing arguments passed from the message
|
message -- list containing arguments passed from the message
|
||||||
[0] = first argument
|
[0] = first argument
|
||||||
[1] = second argument
|
[1] = second argument
|
||||||
. . .
|
. . .
|
||||||
|
|
||||||
return the message or **False** if there's no response by the bot
|
return the message or **False** if there's no response by the bot
|
||||||
TODO: Change False to None, because False doesn't make any sense
|
TODO: Change False to None, because False doesn't make any sense
|
||||||
@@ -35,7 +36,6 @@ def instantRestart(fro, chan, message):
|
|||||||
return False
|
return False
|
||||||
|
|
||||||
def faq(fro, chan, message):
|
def faq(fro, chan, message):
|
||||||
# TODO: Unhardcode this
|
|
||||||
if message[0] == "rules":
|
if message[0] == "rules":
|
||||||
return "Please make sure to check (Ripple's rules)[http://ripple.moe/?p=23]."
|
return "Please make sure to check (Ripple's rules)[http://ripple.moe/?p=23]."
|
||||||
elif message[0] == "swearing":
|
elif message[0] == "swearing":
|
||||||
@@ -161,11 +161,11 @@ def silence(fro, chan, message):
|
|||||||
if unit == 's':
|
if unit == 's':
|
||||||
silenceTime = int(amount)
|
silenceTime = int(amount)
|
||||||
elif unit == 'm':
|
elif unit == 'm':
|
||||||
silenceTime = int(amount) * 60
|
silenceTime = int(amount)*60
|
||||||
elif unit == 'h':
|
elif unit == 'h':
|
||||||
silenceTime = int(amount) * 3600
|
silenceTime = int(amount)*3600
|
||||||
elif unit == 'd':
|
elif unit == 'd':
|
||||||
silenceTime = int(amount) * 86400
|
silenceTime = int(amount)*86400
|
||||||
else:
|
else:
|
||||||
return "Invalid time unit (s/m/h/d)."
|
return "Invalid time unit (s/m/h/d)."
|
||||||
|
|
||||||
@@ -304,7 +304,22 @@ def systemShutdown(fro, chan, message):
|
|||||||
return restartShutdown(False)
|
return restartShutdown(False)
|
||||||
|
|
||||||
def systemReload(fro, chan, message):
|
def systemReload(fro, chan, message):
|
||||||
glob.banchoConf.reload()
|
# 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))
|
||||||
|
|
||||||
return "Bancho settings reloaded!"
|
return "Bancho settings reloaded!"
|
||||||
|
|
||||||
def systemMaintenance(fro, chan, message):
|
def systemMaintenance(fro, chan, message):
|
||||||
@@ -345,13 +360,7 @@ def systemStatus(fro, chan, message):
|
|||||||
data = systemHelper.getSystemInfo()
|
data = systemHelper.getSystemInfo()
|
||||||
|
|
||||||
# Final message
|
# Final message
|
||||||
letsVersion = glob.redis.get("lets:version")
|
|
||||||
if letsVersion is None:
|
|
||||||
letsVersion = "\_(xd)_/"
|
|
||||||
else:
|
|
||||||
letsVersion = letsVersion.decode("utf-8")
|
|
||||||
msg = "pep.py bancho server v{}\n".format(glob.VERSION)
|
msg = "pep.py bancho server v{}\n".format(glob.VERSION)
|
||||||
msg += "LETS scores server v{}\n".format(letsVersion)
|
|
||||||
msg += "made by the Ripple team\n"
|
msg += "made by the Ripple team\n"
|
||||||
msg += "\n"
|
msg += "\n"
|
||||||
msg += "=== BANCHO STATS ===\n"
|
msg += "=== BANCHO STATS ===\n"
|
||||||
@@ -656,7 +665,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 +700,42 @@ def updateBeatmap(fro, chan, to):
|
|||||||
except:
|
except:
|
||||||
return False
|
return False
|
||||||
|
|
||||||
|
def trick(fro, chan, message):
|
||||||
|
if chan.startswith("#"):
|
||||||
|
return False
|
||||||
|
token = glob.tokens.getTokenFromUsername(fro)
|
||||||
|
if token is None or token.zingheri != 0:
|
||||||
|
return False
|
||||||
|
token.zingheri = 1
|
||||||
|
return "As you want..."
|
||||||
|
|
||||||
|
def treat(fro, chan, message):
|
||||||
|
if chan.startswith("#"):
|
||||||
|
return False
|
||||||
|
token = glob.tokens.getTokenFromUsername(fro)
|
||||||
|
if token is None or token.zingheri != 0:
|
||||||
|
return False
|
||||||
|
if token.actionID != actions.IDLE and token.actionID != actions.AFK:
|
||||||
|
log.warning(str(token.actionID))
|
||||||
|
return "You must be in the main menu to give me a treat :3"
|
||||||
|
token.zingheri = -2
|
||||||
|
token.leaveStream("zingheri")
|
||||||
|
usePP = token.gameMode == gameModes.STD or token.gameMode == gameModes.MANIA
|
||||||
|
if usePP:
|
||||||
|
currentPP = userUtils.getPP(token.userID, token.gameMode)
|
||||||
|
gift = currentPP/3
|
||||||
|
userUtils.setPP(token.userID, token.gameMode, currentPP - gift)
|
||||||
|
userUtils.setPP(999, token.gameMode, userUtils.getPP(999, token.gameMode) + gift)
|
||||||
|
else:
|
||||||
|
currentScore = userUtils.getRankedScore(token.userID, token.gameMode)
|
||||||
|
gift = currentScore/3
|
||||||
|
userUtils.setRankedScore(token.userID, token.gameMode, currentScore - gift)
|
||||||
|
userUtils.setRankedScore(999, token.gameMode, userUtils.getRankedScore(999, token.gameMode) + gift)
|
||||||
|
token.updateCachedStats()
|
||||||
|
token.enqueue(serverPackets.userStats(token.userID))
|
||||||
|
token.enqueue(serverPackets.userStats(999, True))
|
||||||
|
return "You just gave me {num:.2f} {type} as a treat, thanks! ^.^".format(num=gift, type="pp" if usePP else "score")
|
||||||
|
|
||||||
"""
|
"""
|
||||||
Commands list
|
Commands list
|
||||||
|
|
||||||
@@ -699,6 +744,11 @@ callback: function to call when the command is triggered. Optional.
|
|||||||
response: text to return when the command is triggered. Optional.
|
response: text to return when the command is triggered. Optional.
|
||||||
syntax: command syntax. Arguments must be separated by spaces (eg: <arg1> <arg2>)
|
syntax: command syntax. Arguments must be separated by spaces (eg: <arg1> <arg2>)
|
||||||
privileges: privileges needed to execute the command. Optional.
|
privileges: privileges needed to execute the command. Optional.
|
||||||
|
|
||||||
|
NOTES:
|
||||||
|
- You CAN'T use both rank and minRank at the same time.
|
||||||
|
- If both rank and minrank are **not** present, everyone will be able to run that command.
|
||||||
|
- You MUST set trigger and callback/response, or the command won't work.
|
||||||
"""
|
"""
|
||||||
commands = [
|
commands = [
|
||||||
{
|
{
|
||||||
@@ -738,7 +788,7 @@ commands = [
|
|||||||
"callback": moderated
|
"callback": moderated
|
||||||
}, {
|
}, {
|
||||||
"trigger": "!kickall",
|
"trigger": "!kickall",
|
||||||
"privileges": privileges.ADMIN_MANAGE_SERVERS,
|
"privileges": privileges.ADMIN_KICK_USERS,
|
||||||
"callback": kickAll
|
"callback": kickAll
|
||||||
}, {
|
}, {
|
||||||
"trigger": "!kick",
|
"trigger": "!kick",
|
||||||
@@ -825,6 +875,12 @@ commands = [
|
|||||||
}, {
|
}, {
|
||||||
"trigger": "!update",
|
"trigger": "!update",
|
||||||
"callback": updateBeatmap
|
"callback": updateBeatmap
|
||||||
|
}, {
|
||||||
|
"trigger": "trick",
|
||||||
|
"callback": trick
|
||||||
|
}, {
|
||||||
|
"trigger": "treat",
|
||||||
|
"callback": treat
|
||||||
}
|
}
|
||||||
#
|
#
|
||||||
# "trigger": "!acc",
|
# "trigger": "!acc",
|
||||||
|
@@ -1,2 +1,2 @@
|
|||||||
NORMAL = 0
|
normal = 0
|
||||||
FREE_MOD = 1
|
freeMod = 1
|
||||||
|
@@ -1,3 +1,3 @@
|
|||||||
SCORE = 0
|
score = 0
|
||||||
ACCURACY = 1
|
accuracy = 1
|
||||||
COMBO = 2
|
combo = 2
|
||||||
|
@@ -1,4 +1,4 @@
|
|||||||
HEAD_TO_HEAD = 0
|
headToHead = 0
|
||||||
TAG_COOP = 1
|
tagCoop = 1
|
||||||
TEAM_VS = 2
|
teamVs = 2
|
||||||
TAG_TEAM_VS = 3
|
tagTeamVs = 3
|
||||||
|
@@ -1,3 +1,3 @@
|
|||||||
NO_TEAM = 0
|
noTeam = 0
|
||||||
BLUE = 1
|
blue = 1
|
||||||
RED = 2
|
red = 2
|
||||||
|
@@ -79,4 +79,6 @@ server_userPresenceBundle = 96
|
|||||||
client_userPanelRequest = 97
|
client_userPanelRequest = 97
|
||||||
client_tournamentMatchInfoRequest = 93
|
client_tournamentMatchInfoRequest = 93
|
||||||
client_tournamentJoinMatchChannel = 108
|
client_tournamentJoinMatchChannel = 108
|
||||||
client_tournamentLeaveMatchChannel = 109
|
client_tournamentLeaveMatchChannel = 109
|
||||||
|
|
||||||
|
server_zingheri = 105
|
@@ -159,7 +159,7 @@ def channelInfo(chan):
|
|||||||
return packetHelper.buildPacket(packetIDs.server_channelInfo, [
|
return packetHelper.buildPacket(packetIDs.server_channelInfo, [
|
||||||
[chan, dataTypes.STRING],
|
[chan, dataTypes.STRING],
|
||||||
[channel.description, dataTypes.STRING],
|
[channel.description, dataTypes.STRING],
|
||||||
[len(channel.connectedUsers), dataTypes.UINT16]
|
[channel.getConnectedUsersCount(), dataTypes.UINT16]
|
||||||
])
|
])
|
||||||
|
|
||||||
def channelInfoEnd():
|
def channelInfoEnd():
|
||||||
@@ -267,4 +267,7 @@ def notification(message):
|
|||||||
return packetHelper.buildPacket(packetIDs.server_notification, [[message, dataTypes.STRING]])
|
return packetHelper.buildPacket(packetIDs.server_notification, [[message, dataTypes.STRING]])
|
||||||
|
|
||||||
def banchoRestart(msUntilReconnection):
|
def banchoRestart(msUntilReconnection):
|
||||||
return packetHelper.buildPacket(packetIDs.server_restart, [[msUntilReconnection, dataTypes.UINT32]])
|
return packetHelper.buildPacket(packetIDs.server_restart, [[msUntilReconnection, dataTypes.UINT32]])
|
||||||
|
|
||||||
|
def zingheri(message):
|
||||||
|
return packetHelper.buildPacket(packetIDs.server_zingheri, [[message, dataTypes.STRING]])
|
@@ -1,8 +1,8 @@
|
|||||||
FREE = 1
|
free = 1
|
||||||
LOCKED = 2
|
locked = 2
|
||||||
NOT_READY = 4
|
notReady = 4
|
||||||
READY = 8
|
ready = 8
|
||||||
NO_MAP = 16
|
noMap = 16
|
||||||
PLAYING = 32
|
playing = 32
|
||||||
OCCUPIED = 124
|
occupied = 124
|
||||||
PLAYING_QUIT = 128
|
playingQuit = 128
|
||||||
|
@@ -1,3 +1,4 @@
|
|||||||
|
"""Bancho user ranks"""
|
||||||
NORMAL = 0
|
NORMAL = 0
|
||||||
PLAYER = 1
|
PLAYER = 1
|
||||||
BAT = 2
|
BAT = 2
|
||||||
|
@@ -4,6 +4,7 @@ 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
|
||||||
|
import time
|
||||||
|
|
||||||
def handle(userToken, packetData):
|
def handle(userToken, packetData):
|
||||||
# Get usertoken data
|
# Get usertoken data
|
||||||
@@ -11,13 +12,14 @@ def handle(userToken, packetData):
|
|||||||
username = userToken.username
|
username = userToken.username
|
||||||
|
|
||||||
# Make sure we are not banned
|
# Make sure we are not banned
|
||||||
#if userUtils.isBanned(userID):
|
if userUtils.isBanned(userID):
|
||||||
# userToken.enqueue(serverPackets.loginBanned())
|
userToken.enqueue(serverPackets.loginBanned())
|
||||||
# return
|
return
|
||||||
|
|
||||||
# Send restricted message if needed
|
# Send restricted message if needed
|
||||||
#if userToken.restricted:
|
if not userToken.restricted:
|
||||||
# userToken.checkRestricted(True)
|
if userUtils.isRestricted(userID):
|
||||||
|
userToken.setRestricted()
|
||||||
|
|
||||||
# Change action packet
|
# Change action packet
|
||||||
packetData = clientPackets.userActionChange(packetData)
|
packetData = clientPackets.userActionChange(packetData)
|
||||||
@@ -33,10 +35,8 @@ 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
|
# 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"]):
|
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
|
||||||
# Update cached stats if we've changed gamemode
|
|
||||||
if userToken.gameMode != packetData["gameMode"]:
|
|
||||||
userToken.gameMode = packetData["gameMode"]
|
userToken.gameMode = packetData["gameMode"]
|
||||||
userToken.updateCachedStats()
|
userToken.updateCachedStats()
|
||||||
|
|
||||||
@@ -46,6 +46,7 @@ if userToken.matchID != -1 and userToken.actionID != actions.MULTIPLAYING and us
|
|||||||
userToken.actionMd5 = packetData["actionMd5"]
|
userToken.actionMd5 = packetData["actionMd5"]
|
||||||
userToken.actionMods = packetData["actionMods"]
|
userToken.actionMods = packetData["actionMods"]
|
||||||
userToken.beatmapID = packetData["beatmapID"]
|
userToken.beatmapID = packetData["beatmapID"]
|
||||||
|
userToken.actionLatestUpdate = int(time.time())
|
||||||
|
|
||||||
# Enqueue our new user panel and stats to us and our spectators
|
# Enqueue our new user panel and stats to us and our spectators
|
||||||
recipients = [userToken]
|
recipients = [userToken]
|
||||||
|
@@ -18,7 +18,7 @@ def handle(userToken, packetData):
|
|||||||
match = glob.matches.matches[matchID]
|
match = glob.matches.matches[matchID]
|
||||||
|
|
||||||
# Set slot or match mods according to modType
|
# Set slot or match mods according to modType
|
||||||
if match.matchModMode == matchModModes.FREE_MOD:
|
if match.matchModMode == matchModModes.freeMod:
|
||||||
# Freemod
|
# Freemod
|
||||||
# Host can set global DT/HT
|
# Host can set global DT/HT
|
||||||
if userID == match.hostUserID:
|
if userID == match.hostUserID:
|
||||||
|
@@ -81,11 +81,11 @@ def handle(userToken, packetData):
|
|||||||
# Reset ready if needed
|
# Reset ready if needed
|
||||||
if oldMods != match.mods or oldBeatmapMD5 != match.beatmapMD5:
|
if oldMods != match.mods or oldBeatmapMD5 != match.beatmapMD5:
|
||||||
for i in range(0,16):
|
for i in range(0,16):
|
||||||
if match.slots[i].status == slotStatuses.READY:
|
if match.slots[i].status == slotStatuses.ready:
|
||||||
match.slots[i].status = slotStatuses.NOT_READY
|
match.slots[i].status = slotStatuses.notReady
|
||||||
|
|
||||||
# Reset mods if needed
|
# Reset mods if needed
|
||||||
if match.matchModMode == matchModModes.NORMAL:
|
if match.matchModMode == matchModModes.normal:
|
||||||
# Reset slot mods if not freeMods
|
# Reset slot mods if not freeMods
|
||||||
for i in range(0,16):
|
for i in range(0,16):
|
||||||
match.slots[i].mods = 0
|
match.slots[i].mods = 0
|
||||||
@@ -94,21 +94,21 @@ def handle(userToken, packetData):
|
|||||||
match.mods = 0
|
match.mods = 0
|
||||||
|
|
||||||
# Set/reset teams
|
# Set/reset teams
|
||||||
if match.matchTeamType == matchTeamTypes.TEAM_VS or match.matchTeamType == matchTeamTypes.TAG_TEAM_VS:
|
if match.matchTeamType == matchTeamTypes.teamVs or match.matchTeamType == matchTeamTypes.tagTeamVs:
|
||||||
# Set teams
|
# Set teams
|
||||||
c=0
|
c=0
|
||||||
for i in range(0,16):
|
for i in range(0,16):
|
||||||
if match.slots[i].team == matchTeams.NO_TEAM:
|
if match.slots[i].team == matchTeams.noTeam:
|
||||||
match.slots[i].team = matchTeams.RED if c % 2 == 0 else matchTeams.BLUE
|
match.slots[i].team = matchTeams.red if c % 2 == 0 else matchTeams.blue
|
||||||
c+=1
|
c+=1
|
||||||
else:
|
else:
|
||||||
# Reset teams
|
# Reset teams
|
||||||
for i in range(0,16):
|
for i in range(0,16):
|
||||||
match.slots[i].team = matchTeams.NO_TEAM
|
match.slots[i].team = matchTeams.noTeam
|
||||||
|
|
||||||
# Force no freemods if tag coop
|
# Force no freemods if tag coop
|
||||||
if match.matchTeamType == matchTeamTypes.TAG_COOP or match.matchTeamType == matchTeamTypes.TAG_TEAM_VS:
|
if match.matchTeamType == matchTeamTypes.tagCoop or match.matchTeamType == matchTeamTypes.tagTeamVs:
|
||||||
match.matchModMode = matchModModes.NORMAL
|
match.matchModMode = matchModModes.normal
|
||||||
|
|
||||||
# Send updated settings
|
# Send updated settings
|
||||||
match.sendUpdates()
|
match.sendUpdates()
|
||||||
|
@@ -46,6 +46,7 @@ def handle(tornadoRequest):
|
|||||||
splitData = loginData[2].split("|")
|
splitData = loginData[2].split("|")
|
||||||
osuVersion = splitData[0]
|
osuVersion = splitData[0]
|
||||||
timeOffset = int(splitData[1])
|
timeOffset = int(splitData[1])
|
||||||
|
print(str(timeOffset))
|
||||||
clientData = splitData[3].split(":")[:5]
|
clientData = splitData[3].split(":")[:5]
|
||||||
if len(clientData) < 4:
|
if len(clientData) < 4:
|
||||||
raise exceptions.forceUpdateException()
|
raise exceptions.forceUpdateException()
|
||||||
@@ -191,20 +192,19 @@ def handle(tornadoRequest):
|
|||||||
# Get location and country from ip.zxq.co or database
|
# Get location and country from ip.zxq.co or database
|
||||||
if glob.localize:
|
if glob.localize:
|
||||||
# Get location and country from IP
|
# Get location and country from IP
|
||||||
latitude, longitude = locationHelper.getLocation(requestIP)
|
location = locationHelper.getLocation(requestIP)
|
||||||
countryLetters = locationHelper.getCountry(requestIP)
|
countryLetters = locationHelper.getCountry(requestIP)
|
||||||
country = countryHelper.getCountryID(countryLetters)
|
country = countryHelper.getCountryID(countryLetters)
|
||||||
else:
|
else:
|
||||||
# Set location to 0,0 and get country from db
|
# Set location to 0,0 and get country from db
|
||||||
log.warning("Location skipped")
|
log.warning("Location skipped")
|
||||||
latitude = 0
|
location = [0,0]
|
||||||
longitude = 0
|
|
||||||
countryLetters = "XX"
|
countryLetters = "XX"
|
||||||
country = countryHelper.getCountryID(userUtils.getCountry(userID))
|
country = countryHelper.getCountryID(userUtils.getCountry(userID))
|
||||||
|
|
||||||
# Set location and country
|
# Set location and country
|
||||||
responseToken.setLocation(latitude, longitude)
|
responseToken.setLocation(location)
|
||||||
responseToken.country = country
|
responseToken.setCountry(country)
|
||||||
|
|
||||||
# Set country in db if user has no country (first bancho login)
|
# Set country in db if user has no country (first bancho login)
|
||||||
if userUtils.getCountry(userID) == "XX":
|
if userUtils.getCountry(userID) == "XX":
|
||||||
|
@@ -1,5 +1,4 @@
|
|||||||
import time
|
import time
|
||||||
import json
|
|
||||||
|
|
||||||
from common.log import logUtils as log
|
from common.log import logUtils as log
|
||||||
from constants import serverPackets
|
from constants import serverPackets
|
||||||
@@ -7,7 +6,7 @@ from helpers import chatHelper as chat
|
|||||||
from objects import glob
|
from objects import glob
|
||||||
|
|
||||||
|
|
||||||
def handle(userToken, _=None, deleteToken=True):
|
def handle(userToken, _=None):
|
||||||
# get usertoken data
|
# get usertoken data
|
||||||
userID = userToken.userID
|
userID = userToken.userID
|
||||||
username = userToken.username
|
username = userToken.username
|
||||||
@@ -39,19 +38,7 @@ def handle(userToken, _=None, deleteToken=True):
|
|||||||
glob.ircServer.forceDisconnection(userToken.username)
|
glob.ircServer.forceDisconnection(userToken.username)
|
||||||
|
|
||||||
# Delete token
|
# Delete token
|
||||||
if deleteToken:
|
glob.tokens.deleteToken(requestToken)
|
||||||
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
|
# Console output
|
||||||
log.info("{} has been disconnected. (logout)".format(username))
|
log.info("{} has been disconnected. (logout)".format(username))
|
||||||
|
@@ -11,7 +11,7 @@ def handle(userToken, packetData):
|
|||||||
packetData = clientPackets.setAwayMessage(packetData)
|
packetData = clientPackets.setAwayMessage(packetData)
|
||||||
|
|
||||||
# Set token away message
|
# Set token away message
|
||||||
userToken.awayMessage = packetData["awayMessage"]
|
userToken.setAwayMessage(packetData["awayMessage"])
|
||||||
|
|
||||||
# Send private message from fokabot
|
# Send private message from fokabot
|
||||||
if packetData["awayMessage"] == "":
|
if packetData["awayMessage"] == "":
|
||||||
|
@@ -1,4 +0,0 @@
|
|||||||
find . -name "*.c" -type f -delete
|
|
||||||
find . -name "*.o" -type f -delete
|
|
||||||
find . -name "*.so" -type f -delete
|
|
||||||
python3 setup.py build_ext --inplace
|
|
@@ -21,6 +21,7 @@ class handler(requestsManager.asyncRequestHandler):
|
|||||||
if key is None or key != glob.conf.config["server"]["cikey"]:
|
if key is None or key != glob.conf.config["server"]["cikey"]:
|
||||||
raise exceptions.invalidArgumentsException()
|
raise exceptions.invalidArgumentsException()
|
||||||
|
|
||||||
|
log.info("API REQUEST FOR FOKABOT MESSAGE AAAAAAA")
|
||||||
chatHelper.sendMessage("FokaBot", self.get_argument("to"), self.get_argument("msg"))
|
chatHelper.sendMessage("FokaBot", self.get_argument("to"), self.get_argument("msg"))
|
||||||
|
|
||||||
# Status code and message
|
# Status code and message
|
||||||
@@ -34,5 +35,7 @@ class handler(requestsManager.asyncRequestHandler):
|
|||||||
data["status"] = statusCode
|
data["status"] = statusCode
|
||||||
|
|
||||||
# Send response
|
# Send response
|
||||||
|
#self.clear()
|
||||||
self.write(json.dumps(data))
|
self.write(json.dumps(data))
|
||||||
self.set_status(statusCode)
|
self.set_status(statusCode)
|
||||||
|
#self.finish(json.dumps(data))
|
||||||
|
@@ -18,7 +18,7 @@ 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")
|
||||||
else:
|
else:
|
||||||
try:
|
try:
|
||||||
userID = int(self.get_argument("id"))
|
userID = int(self.get_argument("id"))
|
||||||
@@ -29,7 +29,7 @@ class handler(requestsManager.asyncRequestHandler):
|
|||||||
data["result"] = False
|
data["result"] = False
|
||||||
else:
|
else:
|
||||||
if username is not None:
|
if username is not None:
|
||||||
data["result"] = True if glob.tokens.getTokenFromUsername(username, safe=True) is not None else False
|
data["result"] = True if glob.tokens.getTokenFromUsername(username) is not None else False
|
||||||
else:
|
else:
|
||||||
data["result"] = True if glob.tokens.getTokenFromUserID(userID) is not None else False
|
data["result"] = True if glob.tokens.getTokenFromUserID(userID) is not None else False
|
||||||
|
|
||||||
@@ -44,5 +44,7 @@ class handler(requestsManager.asyncRequestHandler):
|
|||||||
data["status"] = statusCode
|
data["status"] = statusCode
|
||||||
|
|
||||||
# Send response
|
# Send response
|
||||||
|
#self.clear()
|
||||||
self.write(json.dumps(data))
|
self.write(json.dumps(data))
|
||||||
self.set_status(statusCode)
|
self.set_status(statusCode)
|
||||||
|
#self.finish(json.dumps(data))
|
||||||
|
@@ -10,7 +10,7 @@ class handler(requestsManager.asyncRequestHandler):
|
|||||||
data = {"message": "unknown error"}
|
data = {"message": "unknown error"}
|
||||||
try:
|
try:
|
||||||
# Get online users count
|
# Get online users count
|
||||||
data["result"] = int(glob.redis.get("ripple:online_users").decode("utf-8"))
|
data["result"] = len(glob.tokens.tokens)
|
||||||
|
|
||||||
# Status code and message
|
# Status code and message
|
||||||
statusCode = 200
|
statusCode = 200
|
||||||
@@ -20,5 +20,7 @@ class handler(requestsManager.asyncRequestHandler):
|
|||||||
data["status"] = statusCode
|
data["status"] = statusCode
|
||||||
|
|
||||||
# Send response
|
# Send response
|
||||||
|
#self.clear()
|
||||||
self.write(json.dumps(data))
|
self.write(json.dumps(data))
|
||||||
self.set_status(statusCode)
|
self.set_status(statusCode)
|
||||||
|
#self.finish(json.dumps(data))
|
||||||
|
@@ -20,5 +20,7 @@ class handler(requestsManager.asyncRequestHandler):
|
|||||||
data["status"] = statusCode
|
data["status"] = statusCode
|
||||||
|
|
||||||
# Send response
|
# Send response
|
||||||
|
#self.clear()
|
||||||
self.write(json.dumps(data))
|
self.write(json.dumps(data))
|
||||||
self.set_status(statusCode)
|
self.set_status(statusCode)
|
||||||
|
#self.finish(json.dumps(data))
|
||||||
|
@@ -115,6 +115,8 @@ class handler(SentryMixin, requestsManager.asyncRequestHandler):
|
|||||||
return wrapper
|
return wrapper
|
||||||
|
|
||||||
eventHandler = {
|
eventHandler = {
|
||||||
|
# TODO: Rename packets and events
|
||||||
|
# TODO: Host check for multi
|
||||||
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),
|
||||||
@@ -122,7 +124,7 @@ class handler(SentryMixin, requestsManager.asyncRequestHandler):
|
|||||||
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),
|
||||||
@@ -206,9 +208,6 @@ class handler(SentryMixin, requestsManager.asyncRequestHandler):
|
|||||||
userToken.updatePingTime()
|
userToken.updatePingTime()
|
||||||
# Release token lock
|
# Release token lock
|
||||||
userToken.lock.release()
|
userToken.lock.release()
|
||||||
# Delete token if kicked
|
|
||||||
if userToken.kicked:
|
|
||||||
glob.tokens.deleteToken(userToken)
|
|
||||||
|
|
||||||
if glob.outputRequestTime:
|
if glob.outputRequestTime:
|
||||||
# End time
|
# End time
|
@@ -12,11 +12,14 @@ def joinChannel(userID = 0, channel = "", token = None, toIRC = True):
|
|||||||
"""
|
"""
|
||||||
Join a channel
|
Join a channel
|
||||||
|
|
||||||
:param userID: user ID of the user that joins the channel. Optional. token can be used instead.
|
userID -- user ID of the user that joins the channel. Optional.
|
||||||
:param token: user token object of user that joins the channel. Optional. userID can be used instead.
|
token can be used instead.
|
||||||
:param channel: channel name
|
token -- user token object of user that joins the channel. Optional.
|
||||||
:param toIRC: if True, send this channel join event to IRC. Must be true if joining from bancho. Default: True
|
userID can be used instead.
|
||||||
:return: 0 if joined or other IRC code in case of error. Needed only on IRC-side
|
channel -- name of channe
|
||||||
|
toIRC -- if True, send this channel join event to IRC. Must be true if joining from bancho.
|
||||||
|
Optional. Defaukt: True
|
||||||
|
return -- returns 0 if joined or other IRC code in case of error. Needed only on IRC-side
|
||||||
"""
|
"""
|
||||||
try:
|
try:
|
||||||
# Get token if not defined
|
# Get token if not defined
|
||||||
@@ -74,12 +77,15 @@ def partChannel(userID = 0, channel = "", token = None, toIRC = True, kick = Fal
|
|||||||
"""
|
"""
|
||||||
Part a channel
|
Part a channel
|
||||||
|
|
||||||
:param userID: user ID of the user that parts the channel. Optional. token can be used instead.
|
userID -- user ID of the user that parts the channel. Optional.
|
||||||
:param token: user token object of user that parts the channel. Optional. userID can be used instead.
|
token can be used instead.
|
||||||
:param channel: channel name
|
token -- user token object of user that parts the channel. Optional.
|
||||||
:param toIRC: if True, send this channel join event to IRC. Must be true if joining from bancho. Optional. Default: True
|
userID can be used instead.
|
||||||
:param kick: if True, channel tab will be closed on client. Used when leaving lobby. Optional. Default: False
|
channel -- name of channel
|
||||||
:return: 0 if joined or other IRC code in case of error. Needed only on IRC-side
|
toIRC -- if True, send this channel join event to IRC. Must be true if joining from bancho.
|
||||||
|
Optional. Defaukt: True
|
||||||
|
kick -- if True, channel tab will be closed on client. Used when leaving lobby. Optional. Default: False
|
||||||
|
return -- returns 0 if joined or other IRC code in case of error. Needed only on IRC-side
|
||||||
"""
|
"""
|
||||||
try:
|
try:
|
||||||
# Get token if not defined
|
# Get token if not defined
|
||||||
@@ -145,12 +151,15 @@ def sendMessage(fro = "", to = "", message = "", token = None, toIRC = True):
|
|||||||
"""
|
"""
|
||||||
Send a message to osu!bancho and IRC server
|
Send a message to osu!bancho and IRC server
|
||||||
|
|
||||||
:param fro: sender username. Optional. token can be used instead
|
fro -- sender username. Optional.
|
||||||
:param to: receiver channel (if starts with #) or username
|
You can use token instead of this if you wish.
|
||||||
:param message: text of the message
|
to -- receiver channel (if starts with #) or username
|
||||||
:param token: sender token object. Optional. fro can be used instead
|
message -- text of the message
|
||||||
:param toIRC: if True, send the message to IRC. If False, send it to Bancho only. Default: True
|
token -- sender token object.
|
||||||
:return: 0 if joined or other IRC code in case of error. Needed only on IRC-side
|
You can use this instead of fro if you are sending messages from bancho.
|
||||||
|
Optional.
|
||||||
|
toIRC -- if True, send the message to IRC. If False, send it to Bancho only.
|
||||||
|
Optional. Default: True
|
||||||
"""
|
"""
|
||||||
try:
|
try:
|
||||||
tokenString = ""
|
tokenString = ""
|
||||||
@@ -222,7 +231,7 @@ def sendMessage(fro = "", to = "", message = "", token = None, toIRC = True):
|
|||||||
raise exceptions.channelNoPermissionsException
|
raise exceptions.channelNoPermissionsException
|
||||||
|
|
||||||
# Everything seems fine, build recipients list and send packet
|
# Everything seems fine, build recipients list and send packet
|
||||||
recipients = glob.channels.channels[to].connectedUsers[:]
|
recipients = glob.channels.channels[to].getConnectedUsers()[:]
|
||||||
for key, value in glob.tokens.tokens.items():
|
for key, value in glob.tokens.tokens.items():
|
||||||
# Skip our client and irc clients
|
# Skip our client and irc clients
|
||||||
if key == tokenString or value.irc == True:
|
if key == tokenString or value.irc == True:
|
||||||
@@ -247,10 +256,6 @@ 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
|
|
||||||
if recipientToken.awayCheck(userID):
|
|
||||||
sendMessage(to, fro, "\x01ACTION is away: {message}\x01".format(code=chr(int(1)), message=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:
|
||||||
sendMessage(fro, to, messageTemplates.templates[message])
|
sendMessage(fro, to, messageTemplates.templates[message])
|
||||||
@@ -273,7 +278,7 @@ def sendMessage(fro = "", to = "", message = "", token = None, toIRC = True):
|
|||||||
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("#"):
|
||||||
log.chat("{fro} @ {to}: {message}".format(fro=username, to=to, message=str(message.encode("utf-8"))))
|
log.chat("{fro} @ {to}: {message}".format(fro=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=username, to=to, message=str(message.encode("utf-8"))[2:-1]))
|
||||||
return 0
|
return 0
|
||||||
@@ -303,12 +308,6 @@ def sendMessage(fro = "", to = "", message = "", token = None, toIRC = True):
|
|||||||
|
|
||||||
""" IRC-Bancho Connect/Disconnect/Join/Part interfaces"""
|
""" IRC-Bancho Connect/Disconnect/Join/Part interfaces"""
|
||||||
def fixUsernameForBancho(username):
|
def fixUsernameForBancho(username):
|
||||||
"""
|
|
||||||
Convert username from IRC format (without spaces) to Bancho format (with spaces)
|
|
||||||
|
|
||||||
:param username: username to convert
|
|
||||||
:return: converted username
|
|
||||||
"""
|
|
||||||
# If there are no spaces or underscores in the name
|
# If there are no spaces or underscores in the name
|
||||||
# return it
|
# return it
|
||||||
if " " not in username and "_" not in username:
|
if " " not in username and "_" not in username:
|
||||||
@@ -323,22 +322,9 @@ def fixUsernameForBancho(username):
|
|||||||
return username.replace("_", " ")
|
return username.replace("_", " ")
|
||||||
|
|
||||||
def fixUsernameForIRC(username):
|
def fixUsernameForIRC(username):
|
||||||
"""
|
|
||||||
Convert an username from Bancho format to IRC format (underscores instead of spaces)
|
|
||||||
|
|
||||||
:param username: username to convert
|
|
||||||
:return: converted username
|
|
||||||
"""
|
|
||||||
return username.replace(" ", "_")
|
return username.replace(" ", "_")
|
||||||
|
|
||||||
def IRCConnect(username):
|
def IRCConnect(username):
|
||||||
"""
|
|
||||||
Handle IRC login bancho-side.
|
|
||||||
Add token and broadcast login packet.
|
|
||||||
|
|
||||||
:param username: username
|
|
||||||
:return:
|
|
||||||
"""
|
|
||||||
userID = userUtils.getID(username)
|
userID = userUtils.getID(username)
|
||||||
if not userID:
|
if not userID:
|
||||||
log.warning("{} doesn't exist".format(username))
|
log.warning("{} doesn't exist".format(username))
|
||||||
@@ -349,13 +335,6 @@ def IRCConnect(username):
|
|||||||
log.info("{} logged in from IRC".format(username))
|
log.info("{} logged in from IRC".format(username))
|
||||||
|
|
||||||
def IRCDisconnect(username):
|
def IRCDisconnect(username):
|
||||||
"""
|
|
||||||
Handle IRC logout bancho-side.
|
|
||||||
Remove token and broadcast logout packet.
|
|
||||||
|
|
||||||
:param username: username
|
|
||||||
:return:
|
|
||||||
"""
|
|
||||||
token = glob.tokens.getTokenFromUsername(username)
|
token = glob.tokens.getTokenFromUsername(username)
|
||||||
if token is None:
|
if token is None:
|
||||||
log.warning("{} doesn't exist".format(username))
|
log.warning("{} doesn't exist".format(username))
|
||||||
@@ -364,13 +343,6 @@ def IRCDisconnect(username):
|
|||||||
log.info("{} disconnected from IRC".format(username))
|
log.info("{} disconnected from IRC".format(username))
|
||||||
|
|
||||||
def IRCJoinChannel(username, channel):
|
def IRCJoinChannel(username, channel):
|
||||||
"""
|
|
||||||
Handle IRC channel join bancho-side.
|
|
||||||
|
|
||||||
:param username: username
|
|
||||||
:param channel: channel name
|
|
||||||
:return: IRC return code
|
|
||||||
"""
|
|
||||||
userID = userUtils.getID(username)
|
userID = userUtils.getID(username)
|
||||||
if not userID:
|
if not userID:
|
||||||
log.warning("{} doesn't exist".format(username))
|
log.warning("{} doesn't exist".format(username))
|
||||||
@@ -381,30 +353,8 @@ def IRCJoinChannel(username, channel):
|
|||||||
return joinChannel(userID, channel)
|
return joinChannel(userID, channel)
|
||||||
|
|
||||||
def IRCPartChannel(username, channel):
|
def IRCPartChannel(username, channel):
|
||||||
"""
|
|
||||||
Handle IRC channel part bancho-side.
|
|
||||||
|
|
||||||
:param username: username
|
|
||||||
:param channel: channel name
|
|
||||||
:return: IRC return code
|
|
||||||
"""
|
|
||||||
userID = userUtils.getID(username)
|
userID = userUtils.getID(username)
|
||||||
if not userID:
|
if not userID:
|
||||||
log.warning("{} doesn't exist".format(username))
|
log.warning("{} doesn't exist".format(username))
|
||||||
return
|
return
|
||||||
return partChannel(userID, channel)
|
return partChannel(userID, channel)
|
||||||
|
|
||||||
def IRCAway(username, message):
|
|
||||||
"""
|
|
||||||
Handle IRC away command bancho-side.
|
|
||||||
|
|
||||||
:param username:
|
|
||||||
:param message: away message
|
|
||||||
:return: IRC return code
|
|
||||||
"""
|
|
||||||
userID = userUtils.getID(username)
|
|
||||||
if not userID:
|
|
||||||
log.warning("{} doesn't exist".format(username))
|
|
||||||
return
|
|
||||||
glob.tokens.getTokenFromUserID(userID).awayMessage = message
|
|
||||||
return 305 if message == "" else 306
|
|
@@ -5,9 +5,9 @@ class config:
|
|||||||
# Check if config.ini exists and load/generate it
|
# Check if config.ini exists and load/generate it
|
||||||
def __init__(self, file):
|
def __init__(self, file):
|
||||||
"""
|
"""
|
||||||
Initialize a config file object
|
Initialize a config object
|
||||||
|
|
||||||
:param file: file name
|
file -- filename
|
||||||
"""
|
"""
|
||||||
self.config = configparser.ConfigParser()
|
self.config = configparser.ConfigParser()
|
||||||
self.default = True
|
self.default = True
|
||||||
@@ -25,9 +25,9 @@ class config:
|
|||||||
# Check if config.ini has all needed the keys
|
# Check if config.ini has all needed the keys
|
||||||
def checkConfig(self):
|
def checkConfig(self):
|
||||||
"""
|
"""
|
||||||
Check is the config file has all required keys
|
Check if this config has the required keys
|
||||||
|
|
||||||
:return: True if valid, False if not valid
|
return -- True if valid, False if not
|
||||||
"""
|
"""
|
||||||
try:
|
try:
|
||||||
# Try to get all the required keys
|
# Try to get all the required keys
|
||||||
@@ -37,11 +37,6 @@ class config:
|
|||||||
self.config.get("db","database")
|
self.config.get("db","database")
|
||||||
self.config.get("db","workers")
|
self.config.get("db","workers")
|
||||||
|
|
||||||
self.config.get("redis","host")
|
|
||||||
self.config.get("redis","port")
|
|
||||||
self.config.get("redis","database")
|
|
||||||
self.config.get("redis","password")
|
|
||||||
|
|
||||||
self.config.get("server","port")
|
self.config.get("server","port")
|
||||||
self.config.get("server","threads")
|
self.config.get("server","threads")
|
||||||
self.config.get("server","gzip")
|
self.config.get("server","gzip")
|
||||||
@@ -79,9 +74,7 @@ class config:
|
|||||||
|
|
||||||
def generateDefaultConfig(self):
|
def generateDefaultConfig(self):
|
||||||
"""
|
"""
|
||||||
Write a default config file to disk
|
Open and set default keys for that config file
|
||||||
|
|
||||||
:return:
|
|
||||||
"""
|
"""
|
||||||
# Open config.ini in write mode
|
# Open config.ini in write mode
|
||||||
f = open(self.fileName, "w")
|
f = open(self.fileName, "w")
|
||||||
@@ -94,12 +87,6 @@ class config:
|
|||||||
self.config.set("db", "database", "ripple")
|
self.config.set("db", "database", "ripple")
|
||||||
self.config.set("db", "workers", "4")
|
self.config.set("db", "workers", "4")
|
||||||
|
|
||||||
self.config.add_section("redis")
|
|
||||||
self.config.set("redis", "host", "localhost")
|
|
||||||
self.config.set("redis", "port", "6379")
|
|
||||||
self.config.set("redis", "database", "0")
|
|
||||||
self.config.set("redis", "password", "")
|
|
||||||
|
|
||||||
self.config.add_section("server")
|
self.config.add_section("server")
|
||||||
self.config.set("server", "port", "5001")
|
self.config.set("server", "port", "5001")
|
||||||
self.config.set("server", "threads", "16")
|
self.config.set("server", "threads", "16")
|
||||||
@@ -127,9 +114,9 @@ class config:
|
|||||||
self.config.set("discord", "devgroup", "")
|
self.config.set("discord", "devgroup", "")
|
||||||
|
|
||||||
self.config.add_section("datadog")
|
self.config.add_section("datadog")
|
||||||
self.config.set("datadog", "enable", "0")
|
self.config.set("datadog", "enable")
|
||||||
self.config.set("datadog", "apikey", "")
|
self.config.set("datadog", "apikey")
|
||||||
self.config.set("datadog", "appkey", "")
|
self.config.set("datadog", "appkey")
|
||||||
|
|
||||||
self.config.add_section("irc")
|
self.config.add_section("irc")
|
||||||
self.config.set("irc", "enable", "1")
|
self.config.set("irc", "enable", "1")
|
||||||
|
@@ -1,12 +1,11 @@
|
|||||||
from common.constants import bcolors
|
from common.constants import bcolors
|
||||||
from objects import glob
|
from objects import glob
|
||||||
|
|
||||||
def printServerStartHeader(asciiArt=True):
|
def printServerStartHeader(asciiArt):
|
||||||
"""
|
"""
|
||||||
Print server start message
|
Print server start header with optional ascii art
|
||||||
|
|
||||||
:param asciiArt: print BanchoBoat ascii art. Default: True
|
asciiArt -- if True, will print ascii art too
|
||||||
:return:
|
|
||||||
"""
|
"""
|
||||||
if asciiArt:
|
if asciiArt:
|
||||||
print("{} _ __".format(bcolors.GREEN))
|
print("{} _ __".format(bcolors.GREEN))
|
||||||
@@ -33,43 +32,35 @@ def printServerStartHeader(asciiArt=True):
|
|||||||
|
|
||||||
def printNoNl(string):
|
def printNoNl(string):
|
||||||
"""
|
"""
|
||||||
Print a string without \n at the end
|
Print string without new line at the end
|
||||||
|
|
||||||
:param string: string to print
|
string -- string to print
|
||||||
:return:
|
|
||||||
"""
|
"""
|
||||||
print(string, end="")
|
print(string, end="")
|
||||||
|
|
||||||
def printColored(string, color):
|
def printColored(string, color):
|
||||||
"""
|
"""
|
||||||
Print a colored string
|
Print colored string
|
||||||
|
|
||||||
:param string: string to print
|
string -- string to print
|
||||||
:param color: ANSI color code
|
color -- see bcolors.py
|
||||||
:return:
|
|
||||||
"""
|
"""
|
||||||
print("{}{}{}".format(color, string, bcolors.ENDC))
|
print("{}{}{}".format(color, string, bcolors.ENDC))
|
||||||
|
|
||||||
def printError():
|
def printError():
|
||||||
"""
|
"""
|
||||||
Print a red "Error"
|
Print error text FOR LOADING
|
||||||
|
|
||||||
:return:
|
|
||||||
"""
|
"""
|
||||||
printColored("Error", bcolors.RED)
|
printColored("Error", bcolors.RED)
|
||||||
|
|
||||||
def printDone():
|
def printDone():
|
||||||
"""
|
"""
|
||||||
Print a green "Done"
|
Print error text FOR LOADING
|
||||||
|
|
||||||
:return:
|
|
||||||
"""
|
"""
|
||||||
printColored("Done", bcolors.GREEN)
|
printColored("Done", bcolors.GREEN)
|
||||||
|
|
||||||
def printWarning():
|
def printWarning():
|
||||||
"""
|
"""
|
||||||
Print a yellow "Warning"
|
Print error text FOR LOADING
|
||||||
|
|
||||||
:return:
|
|
||||||
"""
|
"""
|
||||||
printColored("Warning", bcolors.YELLOW)
|
printColored("Warning", bcolors.YELLOW)
|
||||||
|
@@ -1,4 +1,5 @@
|
|||||||
# TODO: Update countries list
|
"""Contains all country codes with their osu numeric code"""
|
||||||
|
|
||||||
countryCodes = {
|
countryCodes = {
|
||||||
"LV": 132,
|
"LV": 132,
|
||||||
"AD": 3,
|
"AD": 3,
|
||||||
@@ -254,11 +255,12 @@ countryCodes = {
|
|||||||
|
|
||||||
def getCountryID(code):
|
def getCountryID(code):
|
||||||
"""
|
"""
|
||||||
Get osu country ID from country letters
|
Get country ID for osu client
|
||||||
|
|
||||||
:param code: country letters (eg: US)
|
code -- country name abbreviation (eg: US)
|
||||||
:return: country osu code
|
return -- country code int
|
||||||
"""
|
"""
|
||||||
|
|
||||||
if code in countryCodes:
|
if code in countryCodes:
|
||||||
return countryCodes[code]
|
return countryCodes[code]
|
||||||
else:
|
else:
|
||||||
@@ -268,9 +270,10 @@ def getCountryLetters(code):
|
|||||||
"""
|
"""
|
||||||
Get country letters from osu country ID
|
Get country letters from osu country ID
|
||||||
|
|
||||||
:param code: osu country ID
|
code -- country code int
|
||||||
:return: country letters (XX if not found)
|
return -- country name (2 letters) (XX if code not found)
|
||||||
"""
|
"""
|
||||||
|
|
||||||
for key, value in countryCodes.items():
|
for key, value in countryCodes.items():
|
||||||
if value == code:
|
if value == code:
|
||||||
return key
|
return key
|
||||||
|
@@ -7,10 +7,10 @@ from objects import glob
|
|||||||
|
|
||||||
def getCountry(ip):
|
def getCountry(ip):
|
||||||
"""
|
"""
|
||||||
Get country from IP address using geoip api
|
Get country from IP address
|
||||||
|
|
||||||
:param ip: IP address
|
ip -- IP Address
|
||||||
:return: country code. XX if invalid.
|
return -- Country code (2 letters)
|
||||||
"""
|
"""
|
||||||
try:
|
try:
|
||||||
# Try to get country from Pikolo Aul's Go-Sanic ip API
|
# Try to get country from Pikolo Aul's Go-Sanic ip API
|
||||||
@@ -22,15 +22,15 @@ def getCountry(ip):
|
|||||||
|
|
||||||
def getLocation(ip):
|
def getLocation(ip):
|
||||||
"""
|
"""
|
||||||
Get latitude and longitude from IP address using geoip api
|
Get latitude and longitude from IP address
|
||||||
|
|
||||||
:param ip: IP address
|
ip -- IP address
|
||||||
:return: (latitude, longitude)
|
return -- [latitude, longitude]
|
||||||
"""
|
"""
|
||||||
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]
|
||||||
|
@@ -1,15 +1,15 @@
|
|||||||
import struct
|
import struct
|
||||||
from constants import dataTypes
|
from constants import dataTypes
|
||||||
|
|
||||||
cpdef bytearray uleb128Encode(int num):
|
def uleb128Encode(num):
|
||||||
"""
|
"""
|
||||||
Encode an int to uleb128
|
Encode int -> uleb128
|
||||||
|
|
||||||
:param num: int to encode
|
num -- int to encode
|
||||||
:return: bytearray with encoded number
|
return -- bytearray with encoded number
|
||||||
"""
|
"""
|
||||||
cdef bytearray arr = bytearray()
|
arr = bytearray()
|
||||||
cdef int length = 0
|
length = 0
|
||||||
|
|
||||||
if num == 0:
|
if num == 0:
|
||||||
return bytearray(b"\x00")
|
return bytearray(b"\x00")
|
||||||
@@ -23,16 +23,15 @@ cpdef bytearray uleb128Encode(int num):
|
|||||||
|
|
||||||
return arr
|
return arr
|
||||||
|
|
||||||
cpdef list uleb128Decode(bytes num):
|
def uleb128Decode(num):
|
||||||
"""
|
"""
|
||||||
Decode a uleb128 to int
|
Decode uleb128 -> int
|
||||||
|
|
||||||
:param num: encoded uleb128 int
|
num -- encoded uleb128
|
||||||
:return: (total, length)
|
return -- list. [total, length]
|
||||||
"""
|
"""
|
||||||
cdef int shift = 0
|
shift = 0
|
||||||
cdef list arr = [0,0] #total, length
|
arr = [0,0] #total, length
|
||||||
cdef int b
|
|
||||||
|
|
||||||
while True:
|
while True:
|
||||||
b = num[arr[1]]
|
b = num[arr[1]]
|
||||||
@@ -44,14 +43,16 @@ cpdef list uleb128Decode(bytes num):
|
|||||||
|
|
||||||
return arr
|
return arr
|
||||||
|
|
||||||
cpdef unpackData(bytes data, int dataType):
|
def unpackData(data, dataType):
|
||||||
"""
|
"""
|
||||||
Unpacks a single section of a packet.
|
Unpacks data according to dataType
|
||||||
|
|
||||||
:param data: bytes to unpack
|
data -- bytes array to unpack
|
||||||
:param dataType: data type
|
dataType -- data type. See dataTypes.py
|
||||||
:return: unpacked bytes
|
|
||||||
|
return -- unpacked bytes
|
||||||
"""
|
"""
|
||||||
|
|
||||||
# Get right pack Type
|
# Get right pack Type
|
||||||
if dataType == dataTypes.UINT16:
|
if dataType == dataTypes.UINT16:
|
||||||
unpackType = "<H"
|
unpackType = "<H"
|
||||||
@@ -75,17 +76,18 @@ cpdef unpackData(bytes data, int dataType):
|
|||||||
# Unpack
|
# Unpack
|
||||||
return struct.unpack(unpackType, bytes(data))[0]
|
return struct.unpack(unpackType, bytes(data))[0]
|
||||||
|
|
||||||
cpdef bytes packData(__data, int dataType):
|
def packData(__data, dataType):
|
||||||
"""
|
"""
|
||||||
Packs a single section of a packet.
|
Packs data according to dataType
|
||||||
|
|
||||||
:param __data: data to pack
|
data -- bytes to pack
|
||||||
:param dataType: data type
|
dataType -- data type. See dataTypes.py
|
||||||
:return: packed bytes
|
|
||||||
|
return -- packed bytes
|
||||||
"""
|
"""
|
||||||
cdef bytes data = bytes() # data to return
|
|
||||||
cdef bint pack = True # if True, use pack. False only with strings
|
data = bytes() # data to return
|
||||||
cdef str packType
|
pack = True # if True, use pack. False only with strings
|
||||||
|
|
||||||
# Get right pack Type
|
# Get right pack Type
|
||||||
if dataType == dataTypes.BBYTES:
|
if dataType == dataTypes.BBYTES:
|
||||||
@@ -136,21 +138,23 @@ cpdef bytes packData(__data, int dataType):
|
|||||||
|
|
||||||
return data
|
return data
|
||||||
|
|
||||||
cpdef bytes buildPacket(int __packet, list __packetData = []):
|
def buildPacket(__packet, __packetData=None):
|
||||||
"""
|
"""
|
||||||
Builds a packet
|
Build a packet
|
||||||
|
|
||||||
:param __packet: packet ID
|
packet -- packet id (int)
|
||||||
:param __packetData: packet structure [[data, dataType], [data, dataType], ...]
|
packetData -- list [[data, dataType], [data, dataType], ...]
|
||||||
:return: packet bytes
|
|
||||||
|
return -- packet bytes
|
||||||
"""
|
"""
|
||||||
# Set some variables
|
# Set some variables
|
||||||
cdef bytes packetData = bytes()
|
if __packetData is None:
|
||||||
cdef int packetLength = 0
|
__packetData = []
|
||||||
cdef bytes packetBytes = bytes()
|
packetData = bytes()
|
||||||
|
packetLength = 0
|
||||||
|
packetBytes = bytes()
|
||||||
|
|
||||||
# Pack packet data
|
# Pack packet data
|
||||||
cdef list i
|
|
||||||
for i in __packetData:
|
for i in __packetData:
|
||||||
packetData += packData(i[0], i[1])
|
packetData += packData(i[0], i[1])
|
||||||
|
|
||||||
@@ -164,39 +168,42 @@ cpdef bytes buildPacket(int __packet, list __packetData = []):
|
|||||||
packetBytes += packetData # packet data
|
packetBytes += packetData # packet data
|
||||||
return packetBytes
|
return packetBytes
|
||||||
|
|
||||||
cpdef int readPacketID(bytes stream):
|
def readPacketID(stream):
|
||||||
"""
|
"""
|
||||||
Read packetID (first two bytes) from a packet
|
Read packetID from stream (0-1 bytes)
|
||||||
|
|
||||||
:param stream: packet bytes
|
stream -- data stream
|
||||||
:return: packet ID
|
return -- packet ID (int)
|
||||||
"""
|
"""
|
||||||
return unpackData(stream[0:2], dataTypes.UINT16)
|
return unpackData(stream[0:2], dataTypes.UINT16)
|
||||||
|
|
||||||
cpdef int readPacketLength(bytes stream):
|
def readPacketLength(stream):
|
||||||
"""
|
"""
|
||||||
Read packet data length (3:7 bytes) from a packet
|
Read packet length from stream (3-4-5-6 bytes)
|
||||||
|
|
||||||
:param stream: packet bytes
|
stream -- data stream
|
||||||
:return: packet data length
|
return -- packet length (int)
|
||||||
"""
|
"""
|
||||||
return unpackData(stream[3:7], dataTypes.UINT32)
|
return unpackData(stream[3:7], dataTypes.UINT32)
|
||||||
|
|
||||||
|
|
||||||
cpdef readPacketData(bytes stream, list structure=[], bint hasFirstBytes = True):
|
def readPacketData(stream, structure=None, hasFirstBytes = True):
|
||||||
"""
|
"""
|
||||||
Read packet data from `stream` according to `structure`
|
Read packet data from stream according to structure
|
||||||
:param stream: packet bytes
|
|
||||||
:param structure: packet structure: [[name, dataType], [name, dataType], ...]
|
stream -- data stream
|
||||||
:param hasFirstBytes: if True, `stream` has packetID and length bytes.
|
structure -- [[name, dataType], [name, dataType], ...]
|
||||||
if False, `stream` has only packet data. Default: True
|
hasFirstBytes -- if True, stream has packetID and length bytes.
|
||||||
:return: {name: unpackedValue, ...}
|
if False, stream has only packetData.
|
||||||
|
Optional. Default: True
|
||||||
|
return -- dictionary. key: name, value: read data
|
||||||
"""
|
"""
|
||||||
# Read packet ID (first 2 bytes)
|
# Read packet ID (first 2 bytes)
|
||||||
cdef dict data = {}
|
if structure is None:
|
||||||
|
structure = []
|
||||||
|
data = {}
|
||||||
|
|
||||||
# Skip packet ID and packet length if needed
|
# Skip packet ID and packet length if needed
|
||||||
cdef start, end
|
|
||||||
if hasFirstBytes:
|
if hasFirstBytes:
|
||||||
end = 7
|
end = 7
|
||||||
start = 7
|
start = 7
|
||||||
@@ -205,8 +212,6 @@ cpdef readPacketData(bytes stream, list structure=[], bint hasFirstBytes = True)
|
|||||||
start = 0
|
start = 0
|
||||||
|
|
||||||
# Read packet
|
# Read packet
|
||||||
cdef list i
|
|
||||||
cdef bint unpack
|
|
||||||
for i in structure:
|
for i in structure:
|
||||||
start = end
|
start = end
|
||||||
unpack = True
|
unpack = True
|
||||||
@@ -241,10 +246,7 @@ cpdef readPacketData(bytes stream, list structure=[], bint hasFirstBytes = True)
|
|||||||
end = start+length[0]+length[1]+1
|
end = start+length[0]+length[1]+1
|
||||||
|
|
||||||
# Read bytes
|
# 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:
|
elif i[1] == dataTypes.BYTE:
|
||||||
end = start+1
|
end = start+1
|
||||||
elif i[1] == dataTypes.UINT16 or i[1] == dataTypes.SINT16:
|
elif i[1] == dataTypes.UINT16 or i[1] == dataTypes.SINT16:
|
@@ -17,7 +17,6 @@ from objects import glob
|
|||||||
def dispose():
|
def dispose():
|
||||||
"""
|
"""
|
||||||
Perform some clean up. Called on shutdown.
|
Perform some clean up. Called on shutdown.
|
||||||
|
|
||||||
:return:
|
:return:
|
||||||
"""
|
"""
|
||||||
print("> Disposing server... ")
|
print("> Disposing server... ")
|
||||||
@@ -28,7 +27,7 @@ def runningUnderUnix():
|
|||||||
"""
|
"""
|
||||||
Get if the server is running under UNIX or NT
|
Get if the server is running under UNIX or NT
|
||||||
|
|
||||||
:return: True if running under UNIX, otherwise False
|
return --- True if running under UNIX, otherwise False
|
||||||
"""
|
"""
|
||||||
return True if os.name == "posix" else False
|
return True if os.name == "posix" else False
|
||||||
|
|
||||||
@@ -36,11 +35,9 @@ def scheduleShutdown(sendRestartTime, restart, message = "", delay=20):
|
|||||||
"""
|
"""
|
||||||
Schedule a server shutdown/restart
|
Schedule a server shutdown/restart
|
||||||
|
|
||||||
:param sendRestartTime: time (seconds) to wait before sending server restart packets to every client
|
sendRestartTime -- time (seconds) to wait before sending server restart packets to every client
|
||||||
:param restart: if True, server will restart. if False, server will shudown
|
restart -- if True, server will restart. if False, server will shudown
|
||||||
:param message: if set, send that message to every client to warn about the shutdown/restart
|
message -- if set, send that message to every client to warn about the shutdown/restart
|
||||||
:param delay: additional restart delay in seconds. Default: 20
|
|
||||||
: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))
|
||||||
@@ -64,21 +61,13 @@ def scheduleShutdown(sendRestartTime, restart, message = "", delay=20):
|
|||||||
threading.Timer(sendRestartTime+delay, action).start()
|
threading.Timer(sendRestartTime+delay, action).start()
|
||||||
|
|
||||||
def restartServer():
|
def restartServer():
|
||||||
"""
|
"""Restart pep.py script"""
|
||||||
Restart pep.py
|
|
||||||
|
|
||||||
:return:
|
|
||||||
"""
|
|
||||||
log.info("Restarting pep.py...")
|
log.info("Restarting pep.py...")
|
||||||
dispose()
|
dispose()
|
||||||
os.execv(sys.executable, [sys.executable] + sys.argv)
|
os.execv(sys.executable, [sys.executable] + sys.argv)
|
||||||
|
|
||||||
def shutdownServer():
|
def shutdownServer():
|
||||||
"""
|
"""Shutdown pep.py"""
|
||||||
Shutdown pep.py
|
|
||||||
|
|
||||||
:return:
|
|
||||||
"""
|
|
||||||
log.info("Shutting down pep.py...")
|
log.info("Shutting down pep.py...")
|
||||||
dispose()
|
dispose()
|
||||||
sig = signal.SIGKILL if runningUnderUnix() else signal.CTRL_C_EVENT
|
sig = signal.SIGKILL if runningUnderUnix() else signal.CTRL_C_EVENT
|
||||||
@@ -88,7 +77,7 @@ def getSystemInfo():
|
|||||||
"""
|
"""
|
||||||
Get a dictionary with some system/server info
|
Get a dictionary with some system/server info
|
||||||
|
|
||||||
:return: ["unix", "connectedUsers", "webServer", "cpuUsage", "totalMemory", "usedMemory", "loadAverage"]
|
return -- ["unix", "connectedUsers", "webServer", "cpuUsage", "totalMemory", "usedMemory", "loadAverage"]
|
||||||
"""
|
"""
|
||||||
data = {"unix": runningUnderUnix(), "connectedUsers": len(glob.tokens.tokens), "matches": len(glob.matches.matches)}
|
data = {"unix": runningUnderUnix(), "connectedUsers": len(glob.tokens.tokens), "matches": len(glob.matches.matches)}
|
||||||
|
|
||||||
|
140
irc/ircserver.py
140
irc/ircserver.py
@@ -22,15 +22,18 @@ from objects import glob
|
|||||||
|
|
||||||
|
|
||||||
class Client:
|
class Client:
|
||||||
|
"""
|
||||||
|
IRC Client object
|
||||||
|
"""
|
||||||
__linesep_regexp = re.compile(r"\r?\n")
|
__linesep_regexp = re.compile(r"\r?\n")
|
||||||
|
|
||||||
|
|
||||||
def __init__(self, server, sock):
|
def __init__(self, server, sock):
|
||||||
"""
|
"""
|
||||||
Initialize a Client object
|
Initialize a Client object
|
||||||
|
|
||||||
:param server: server object
|
server -- server object
|
||||||
:param sock: socket connection object
|
sock -- socket connection object
|
||||||
:return:
|
|
||||||
"""
|
"""
|
||||||
self.__timestamp = time.time()
|
self.__timestamp = time.time()
|
||||||
self.__readbuffer = ""
|
self.__readbuffer = ""
|
||||||
@@ -57,8 +60,7 @@ class Client:
|
|||||||
Add a message (basic string) to client buffer.
|
Add a message (basic string) to client buffer.
|
||||||
This is the lowest possible level.
|
This is the lowest possible level.
|
||||||
|
|
||||||
:param msg: message to add
|
msg -- message to add
|
||||||
:return:
|
|
||||||
"""
|
"""
|
||||||
self.__writebuffer += msg + "\r\n"
|
self.__writebuffer += msg + "\r\n"
|
||||||
|
|
||||||
@@ -67,7 +69,7 @@ class Client:
|
|||||||
"""
|
"""
|
||||||
Return this client's write buffer size
|
Return this client's write buffer size
|
||||||
|
|
||||||
:return: write buffer size
|
return -- write buffer size
|
||||||
"""
|
"""
|
||||||
return len(self.__writebuffer)
|
return len(self.__writebuffer)
|
||||||
|
|
||||||
@@ -76,8 +78,7 @@ class Client:
|
|||||||
"""
|
"""
|
||||||
Add an IRC-like message to client buffer.
|
Add an IRC-like message to client buffer.
|
||||||
|
|
||||||
:param msg: message (without IRC stuff)
|
msg -- message (without IRC stuff)
|
||||||
:return:
|
|
||||||
"""
|
"""
|
||||||
self.message(":{} {}".format(self.server.host, msg))
|
self.message(":{} {}".format(self.server.host, msg))
|
||||||
|
|
||||||
@@ -86,11 +87,10 @@ class Client:
|
|||||||
"""
|
"""
|
||||||
Add an IRC-like message to client buffer with code
|
Add an IRC-like message to client buffer with code
|
||||||
|
|
||||||
:param code: response code
|
code -- response code
|
||||||
:param message: response message
|
message -- response message
|
||||||
:param nickname: receiver nickname
|
nickname -- receiver nickname
|
||||||
:param channel: optional
|
channel -- optional
|
||||||
:return:
|
|
||||||
"""
|
"""
|
||||||
if nickname == "":
|
if nickname == "":
|
||||||
nickname = self.IRCUsername
|
nickname = self.IRCUsername
|
||||||
@@ -103,8 +103,7 @@ class Client:
|
|||||||
"""
|
"""
|
||||||
Add a 403 reply (no such channel) to client buffer.
|
Add a 403 reply (no such channel) to client buffer.
|
||||||
|
|
||||||
:param channel:
|
channel -- meh
|
||||||
:return:
|
|
||||||
"""
|
"""
|
||||||
self.replyCode(403, "{} :No such channel".format(channel))
|
self.replyCode(403, "{} :No such channel".format(channel))
|
||||||
|
|
||||||
@@ -113,8 +112,7 @@ class Client:
|
|||||||
"""
|
"""
|
||||||
Add a 461 reply (not enough parameters) to client buffer
|
Add a 461 reply (not enough parameters) to client buffer
|
||||||
|
|
||||||
:param command: name of the command that had not enough parameters
|
command -- command that had not enough parameters
|
||||||
:return:
|
|
||||||
"""
|
"""
|
||||||
self.replyCode(403, "{} :Not enough parameters".format(command))
|
self.replyCode(403, "{} :Not enough parameters".format(command))
|
||||||
|
|
||||||
@@ -123,9 +121,8 @@ class Client:
|
|||||||
"""
|
"""
|
||||||
Disconnects this client from the IRC server
|
Disconnects this client from the IRC server
|
||||||
|
|
||||||
:param quitmsg: IRC quit message. Default: 'Client quit'
|
quitmsg -- IRC quit message. Default: 'Client quit'
|
||||||
:param callLogout: if True, call logoutEvent on bancho
|
callLogout -- if True, call logoutEvent on bancho
|
||||||
:return:
|
|
||||||
"""
|
"""
|
||||||
# Send error to client and close socket
|
# Send error to client and close socket
|
||||||
self.message("ERROR :{}".format(quitmsg))
|
self.message("ERROR :{}".format(quitmsg))
|
||||||
@@ -141,11 +138,7 @@ class Client:
|
|||||||
|
|
||||||
|
|
||||||
def readSocket(self):
|
def readSocket(self):
|
||||||
"""
|
"""Read data coming from this client socket"""
|
||||||
Read data coming from this client socket
|
|
||||||
|
|
||||||
:return:
|
|
||||||
"""
|
|
||||||
try:
|
try:
|
||||||
# Try to read incoming data from socket
|
# Try to read incoming data from socket
|
||||||
data = self.socket.recv(2 ** 10)
|
data = self.socket.recv(2 ** 10)
|
||||||
@@ -168,11 +161,7 @@ class Client:
|
|||||||
|
|
||||||
|
|
||||||
def parseBuffer(self):
|
def parseBuffer(self):
|
||||||
"""
|
"""Parse self.__readbuffer, get command, arguments and call its handler"""
|
||||||
Parse self.__readbuffer, get command, arguments and call its handler
|
|
||||||
|
|
||||||
:return:
|
|
||||||
"""
|
|
||||||
# Get lines from buffer
|
# Get lines from buffer
|
||||||
lines = self.__linesep_regexp.split(self.__readbuffer)
|
lines = self.__linesep_regexp.split(self.__readbuffer)
|
||||||
self.__readbuffer = lines[-1]
|
self.__readbuffer = lines[-1]
|
||||||
@@ -209,11 +198,7 @@ class Client:
|
|||||||
|
|
||||||
|
|
||||||
def writeSocket(self):
|
def writeSocket(self):
|
||||||
"""
|
"""Write buffer to socket"""
|
||||||
Write buffer to socket
|
|
||||||
|
|
||||||
:return:
|
|
||||||
"""
|
|
||||||
try:
|
try:
|
||||||
sent = self.socket.send(self.__writebuffer.encode())
|
sent = self.socket.send(self.__writebuffer.encode())
|
||||||
log.debug("[IRC] [{}:{}] <- {}".format(self.ip, self.port, self.__writebuffer[:sent]))
|
log.debug("[IRC] [{}:{}] <- {}".format(self.ip, self.port, self.__writebuffer[:sent]))
|
||||||
@@ -221,13 +206,9 @@ class Client:
|
|||||||
except socket.error as x:
|
except socket.error as x:
|
||||||
self.disconnect(str(x))
|
self.disconnect(str(x))
|
||||||
|
|
||||||
def checkAlive(self):
|
|
||||||
"""
|
|
||||||
Check if this client is still connected.
|
|
||||||
If the client is dead, disconnect it.
|
|
||||||
|
|
||||||
:return:
|
def checkAlive(self):
|
||||||
"""
|
"""Check if this client is still connected"""
|
||||||
now = time.time()
|
now = time.time()
|
||||||
if self.__timestamp + 180 < now:
|
if self.__timestamp + 180 < now:
|
||||||
self.disconnect("ping timeout")
|
self.disconnect("ping timeout")
|
||||||
@@ -243,19 +224,11 @@ class Client:
|
|||||||
|
|
||||||
|
|
||||||
def sendLusers(self):
|
def sendLusers(self):
|
||||||
"""
|
"""Send lusers response to this client"""
|
||||||
Send lusers response to this client
|
|
||||||
|
|
||||||
:return:
|
|
||||||
"""
|
|
||||||
self.replyCode(251, "There are {} users and 0 services on 1 server".format(len(glob.tokens.tokens)))
|
self.replyCode(251, "There are {} users and 0 services on 1 server".format(len(glob.tokens.tokens)))
|
||||||
|
|
||||||
def sendMotd(self):
|
def sendMotd(self):
|
||||||
"""
|
"""Send MOTD to this client"""
|
||||||
Send MOTD to this client
|
|
||||||
|
|
||||||
:return:
|
|
||||||
"""
|
|
||||||
self.replyCode(375, "- {} Message of the day - ".format(self.server.host))
|
self.replyCode(375, "- {} Message of the day - ".format(self.server.host))
|
||||||
if len(self.server.motd) == 0:
|
if len(self.server.motd) == 0:
|
||||||
self.replyCode(422, "MOTD File is missing")
|
self.replyCode(422, "MOTD File is missing")
|
||||||
@@ -323,6 +296,7 @@ class Client:
|
|||||||
# Disconnect other IRC clients from the same user
|
# Disconnect other IRC clients from the same user
|
||||||
for _, value in self.server.clients.items():
|
for _, value in self.server.clients.items():
|
||||||
if value.IRCUsername.lower() == self.IRCUsername.lower() and value != self:
|
if value.IRCUsername.lower() == self.IRCUsername.lower() and value != self:
|
||||||
|
print("DISCONNECTERINOOOOOOOOOOOOOOOOOOOOO")
|
||||||
value.disconnect(quitmsg="Connected from another client")
|
value.disconnect(quitmsg="Connected from another client")
|
||||||
return
|
return
|
||||||
elif command == "USER":
|
elif command == "USER":
|
||||||
@@ -367,13 +341,13 @@ class Client:
|
|||||||
|
|
||||||
# TODO: Part all channels
|
# TODO: Part all channels
|
||||||
if arguments[0] == "0":
|
if arguments[0] == "0":
|
||||||
|
return
|
||||||
'''for (channelname, channel) in self.channels.items():
|
'''for (channelname, channel) in self.channels.items():
|
||||||
self.message_channel(channel, "PART", channelname, True)
|
self.message_channel(channel, "PART", channelname, True)
|
||||||
self.channel_log(channel, "left", meta=True)
|
self.channel_log(channel, "left", meta=True)
|
||||||
server.remove_member_from_channel(self, channelname)
|
server.remove_member_from_channel(self, channelname)
|
||||||
self.channels = {}
|
self.channels = {}
|
||||||
return'''
|
return'''
|
||||||
return
|
|
||||||
|
|
||||||
# Get channels to join list
|
# Get channels to join list
|
||||||
channels = arguments[0].split(",")
|
channels = arguments[0].split(",")
|
||||||
@@ -402,7 +376,7 @@ 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[:]
|
users = glob.channels.channels[channel].getConnectedUsers()[:]
|
||||||
usernames = []
|
usernames = []
|
||||||
for user in users:
|
for user in users:
|
||||||
token = glob.tokens.getTokenFromUserID(user)
|
token = glob.tokens.getTokenFromUserID(user)
|
||||||
@@ -466,6 +440,7 @@ class Client:
|
|||||||
|
|
||||||
# Send the message to bancho and reply
|
# Send the message to bancho and reply
|
||||||
if not recipientIRC.startswith("#"):
|
if not recipientIRC.startswith("#"):
|
||||||
|
print("PMPMPM!!!!!!!!!!")
|
||||||
recipientBancho = chat.fixUsernameForBancho(recipientIRC)
|
recipientBancho = chat.fixUsernameForBancho(recipientIRC)
|
||||||
else:
|
else:
|
||||||
recipientBancho = recipientIRC
|
recipientBancho = recipientIRC
|
||||||
@@ -514,17 +489,10 @@ class Client:
|
|||||||
"""(fake) PONG command handler"""
|
"""(fake) PONG command handler"""
|
||||||
pass
|
pass
|
||||||
|
|
||||||
def awayHandler(self, command, arguments):
|
|
||||||
"""AWAY command handler"""
|
|
||||||
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")
|
|
||||||
|
|
||||||
def mainHandler(self, command, arguments):
|
def mainHandler(self, command, arguments):
|
||||||
"""
|
"""Handler for post-login commands"""
|
||||||
Handler for post-login commands
|
|
||||||
"""
|
|
||||||
handlers = {
|
handlers = {
|
||||||
"AWAY": self.awayHandler,
|
#"AWAY": away_handler,
|
||||||
#"ISON": ison_handler,
|
#"ISON": ison_handler,
|
||||||
"JOIN": self.joinHandler,
|
"JOIN": self.joinHandler,
|
||||||
#"LIST": list_handler,
|
#"LIST": list_handler,
|
||||||
@@ -550,20 +518,24 @@ class Client:
|
|||||||
self.replyCode(421, "Unknown command ({})".format(command))
|
self.replyCode(421, "Unknown command ({})".format(command))
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
class Server:
|
class Server:
|
||||||
def __init__(self, port):
|
def __init__(self, port):
|
||||||
|
#self.host = socket.getfqdn("127.0.0.1")[:63]
|
||||||
self.host = glob.conf.config["irc"]["hostname"]
|
self.host = glob.conf.config["irc"]["hostname"]
|
||||||
self.port = port
|
self.port = port
|
||||||
self.clients = {} # Socket - - > Client instance.
|
self.clients = {} # Socket --> Client instance.
|
||||||
self.motd = ["Welcome to pep.py's embedded IRC server!", "This is a VERY simple IRC server and it's still in beta.", "Expect things to crash and not work as expected :("]
|
self.motd = ["Welcome to pep.py's embedded IRC server!", "This is a VERY simple IRC server and it's still in beta.", "Expect things to crash and not work as expected :("]
|
||||||
|
|
||||||
def forceDisconnection(self, username, isBanchoUsername=True):
|
def forceDisconnection(self, username, isBanchoUsername=True):
|
||||||
"""
|
"""
|
||||||
Disconnect someone from IRC if connected
|
Disconnect someone from IRC if connected
|
||||||
|
|
||||||
:param username: victim
|
username -- victim
|
||||||
:param isBanchoUsername: if True, username is a bancho username, else convert it to a bancho username
|
|
||||||
:return:
|
|
||||||
"""
|
"""
|
||||||
for _, value in self.clients.items():
|
for _, value in self.clients.items():
|
||||||
if (value.IRCUsername == username and not isBanchoUsername) or (value.banchoUsername == username and isBanchoUsername):
|
if (value.IRCUsername == username and not isBanchoUsername) or (value.banchoUsername == username and isBanchoUsername):
|
||||||
@@ -574,9 +546,8 @@ class Server:
|
|||||||
"""
|
"""
|
||||||
Let every IRC client connected to a specific client know that 'username' joined the channel from bancho
|
Let every IRC client connected to a specific client know that 'username' joined the channel from bancho
|
||||||
|
|
||||||
:param username: username of bancho user
|
username -- username of bancho user
|
||||||
:param channel: joined channel name
|
channel -- joined channel name
|
||||||
:return:
|
|
||||||
"""
|
"""
|
||||||
username = chat.fixUsernameForIRC(username)
|
username = chat.fixUsernameForIRC(username)
|
||||||
for _, value in self.clients.items():
|
for _, value in self.clients.items():
|
||||||
@@ -587,9 +558,8 @@ class Server:
|
|||||||
"""
|
"""
|
||||||
Let every IRC client connected to a specific client know that 'username' parted the channel from bancho
|
Let every IRC client connected to a specific client know that 'username' parted the channel from bancho
|
||||||
|
|
||||||
:param username: username of bancho user
|
username -- username of bancho user
|
||||||
:param channel: joined channel name
|
channel -- joined channel name
|
||||||
:return:
|
|
||||||
"""
|
"""
|
||||||
username = chat.fixUsernameForIRC(username)
|
username = chat.fixUsernameForIRC(username)
|
||||||
for _, value in self.clients.items():
|
for _, value in self.clients.items():
|
||||||
@@ -600,10 +570,9 @@ class Server:
|
|||||||
"""
|
"""
|
||||||
Send a message to IRC when someone sends it from bancho
|
Send a message to IRC when someone sends it from bancho
|
||||||
|
|
||||||
:param fro: sender username
|
fro -- sender username
|
||||||
:param to: receiver username
|
to -- receiver username
|
||||||
:param message: text of the message
|
message -- text of the message
|
||||||
:return:
|
|
||||||
"""
|
"""
|
||||||
fro = chat.fixUsernameForIRC(fro)
|
fro = chat.fixUsernameForIRC(fro)
|
||||||
to = chat.fixUsernameForIRC(to)
|
to = chat.fixUsernameForIRC(to)
|
||||||
@@ -623,19 +592,14 @@ class Server:
|
|||||||
"""
|
"""
|
||||||
Remove a client from connected clients
|
Remove a client from connected clients
|
||||||
|
|
||||||
:param client: client object
|
client -- client object
|
||||||
:param quitmsg: QUIT argument, useless atm
|
quitmsg -- QUIT argument, useless atm
|
||||||
:return:
|
|
||||||
"""
|
"""
|
||||||
if client.socket in self.clients:
|
if client.socket in self.clients:
|
||||||
del self.clients[client.socket]
|
del self.clients[client.socket]
|
||||||
|
|
||||||
def start(self):
|
def start(self):
|
||||||
"""
|
"""Start IRC server main loop"""
|
||||||
Start IRC server main loop
|
|
||||||
|
|
||||||
:return:
|
|
||||||
"""
|
|
||||||
# Sentry
|
# Sentry
|
||||||
if glob.sentry:
|
if glob.sentry:
|
||||||
sentryClient = raven.Client(glob.conf.config["sentry"]["ircdns"])
|
sentryClient = raven.Client(glob.conf.config["sentry"]["ircdns"])
|
||||||
@@ -658,7 +622,7 @@ class Server:
|
|||||||
[x.socket for x in self.clients.values()
|
[x.socket for x in self.clients.values()
|
||||||
if x.writeBufferSize() > 0],
|
if x.writeBufferSize() > 0],
|
||||||
[],
|
[],
|
||||||
1)
|
2)
|
||||||
|
|
||||||
# Handle incoming connections
|
# Handle incoming connections
|
||||||
for x in iwtd:
|
for x in iwtd:
|
||||||
@@ -692,11 +656,5 @@ class Server:
|
|||||||
sentryClient.captureException()
|
sentryClient.captureException()
|
||||||
|
|
||||||
def main(port=6667):
|
def main(port=6667):
|
||||||
"""
|
|
||||||
Create and start an IRC server
|
|
||||||
|
|
||||||
:param port: IRC port. Default: 6667
|
|
||||||
:return:
|
|
||||||
"""
|
|
||||||
glob.ircServer = Server(port)
|
glob.ircServer = Server(port)
|
||||||
glob.ircServer.start()
|
glob.ircServer.start()
|
||||||
|
@@ -1,6 +1,5 @@
|
|||||||
# TODO: Rewrite this shit
|
# TODO: Rewrite this shit
|
||||||
from common import generalUtils
|
from common import generalUtils
|
||||||
from constants import serverPackets
|
|
||||||
from objects import glob
|
from objects import glob
|
||||||
|
|
||||||
|
|
||||||
@@ -42,20 +41,3 @@ class banchoConfig:
|
|||||||
"""
|
"""
|
||||||
self.config["banchoMaintenance"] = maintenance
|
self.config["banchoMaintenance"] = maintenance
|
||||||
glob.db.execute("UPDATE bancho_settings SET value_int = %s WHERE name = 'bancho_maintenance'", [int(maintenance)])
|
glob.db.execute("UPDATE bancho_settings SET value_int = %s WHERE name = 'bancho_maintenance'", [int(maintenance)])
|
||||||
|
|
||||||
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))
|
|
@@ -1,16 +1,20 @@
|
|||||||
from objects import glob
|
from objects import glob
|
||||||
|
|
||||||
class channel:
|
class channel:
|
||||||
|
"""
|
||||||
|
A chat channel
|
||||||
|
"""
|
||||||
|
|
||||||
def __init__(self, name, description, publicRead, publicWrite, temp, hidden):
|
def __init__(self, name, description, publicRead, publicWrite, temp, hidden):
|
||||||
"""
|
"""
|
||||||
Create a new chat channel object
|
Create a new chat channel object
|
||||||
|
|
||||||
:param name: channel name
|
name -- channel name
|
||||||
:param description: channel description
|
description -- channel description
|
||||||
:param publicRead: if True, this channel can be read by everyone. If False, it can be read only by mods/admins
|
publicRead -- bool, if true channel can be read by everyone, if false it can be read only by mods/admins
|
||||||
:param publicWrite: same as public read, but regards writing permissions
|
publicWrite -- bool, same as public read but relative to write permissions
|
||||||
:param temp: if True, this channel will be deleted when there's no one in this channel
|
temp -- if True, channel will be deleted when there's no one in the channel
|
||||||
:param hidden: if True, thic channel won't be shown in channels list
|
hidden -- if True, channel won't be shown in channels list
|
||||||
"""
|
"""
|
||||||
self.name = name
|
self.name = name
|
||||||
self.description = description
|
self.description = description
|
||||||
@@ -32,8 +36,7 @@ class channel:
|
|||||||
"""
|
"""
|
||||||
Add a user to connected users
|
Add a user to connected users
|
||||||
|
|
||||||
:param userID:
|
userID -- user ID that joined the channel
|
||||||
:return:
|
|
||||||
"""
|
"""
|
||||||
if userID not in self.connectedUsers:
|
if userID not in self.connectedUsers:
|
||||||
self.connectedUsers.append(userID)
|
self.connectedUsers.append(userID)
|
||||||
@@ -42,8 +45,7 @@ class channel:
|
|||||||
"""
|
"""
|
||||||
Remove a user from connected users
|
Remove a user from connected users
|
||||||
|
|
||||||
:param userID:
|
userID -- user ID that left the channel
|
||||||
:return:
|
|
||||||
"""
|
"""
|
||||||
if userID in self.connectedUsers:
|
if userID in self.connectedUsers:
|
||||||
self.connectedUsers.remove(userID)
|
self.connectedUsers.remove(userID)
|
||||||
@@ -51,4 +53,20 @@ class channel:
|
|||||||
# Remove temp channels if empty or there's only fokabot connected
|
# Remove temp channels if empty or there's only fokabot connected
|
||||||
l = len(self.connectedUsers)
|
l = len(self.connectedUsers)
|
||||||
if self.temp == True and ((l == 0) or (l == 1 and 999 in self.connectedUsers)):
|
if self.temp == True and ((l == 0) or (l == 1 and 999 in self.connectedUsers)):
|
||||||
glob.channels.removeChannel(self.name)
|
glob.channels.removeChannel(self.name)
|
||||||
|
|
||||||
|
def getConnectedUsers(self):
|
||||||
|
"""
|
||||||
|
Get connected user IDs list
|
||||||
|
|
||||||
|
return -- connectedUsers list
|
||||||
|
"""
|
||||||
|
return self.connectedUsers
|
||||||
|
|
||||||
|
def getConnectedUsersCount(self):
|
||||||
|
"""
|
||||||
|
Count connected users
|
||||||
|
|
||||||
|
return -- connected users number
|
||||||
|
"""
|
||||||
|
return len(self.connectedUsers)
|
||||||
|
@@ -4,14 +4,18 @@ from objects import glob
|
|||||||
|
|
||||||
|
|
||||||
class channelList:
|
class channelList:
|
||||||
def __init__(self):
|
"""
|
||||||
self.channels = {}
|
Channel list
|
||||||
|
|
||||||
|
channels -- dictionary. key: channel name, value: channel object
|
||||||
|
"""
|
||||||
|
channels = {}
|
||||||
|
|
||||||
def loadChannels(self):
|
def loadChannels(self):
|
||||||
"""
|
"""
|
||||||
Load chat channels from db and add them to channels list
|
Load chat channels from db and add them to channels dictionary
|
||||||
:return:
|
|
||||||
"""
|
"""
|
||||||
|
|
||||||
# Get channels from DB
|
# Get channels from DB
|
||||||
channels = glob.db.fetchAll("SELECT * FROM bancho_channels")
|
channels = glob.db.fetchAll("SELECT * FROM bancho_channels")
|
||||||
|
|
||||||
@@ -24,15 +28,14 @@ class channelList:
|
|||||||
|
|
||||||
def addChannel(self, name, description, publicRead, publicWrite, temp = False, hidden = False):
|
def addChannel(self, name, description, publicRead, publicWrite, temp = False, hidden = False):
|
||||||
"""
|
"""
|
||||||
Add a channel to channels list
|
Add a channel object to channels dictionary
|
||||||
|
|
||||||
:param name: channel name
|
name -- channel name
|
||||||
:param description: channel description
|
description -- channel description
|
||||||
:param publicRead: if True, this channel can be read by everyone. If False, it can be read only by mods/admins
|
publicRead -- bool, if true channel can be read by everyone, if false it can be read only by mods/admins
|
||||||
:param publicWrite: same as public read, but regards writing permissions
|
publicWrite -- bool, same as public read but relative to write permissions
|
||||||
:param temp: if True, this channel will be deleted when there's no one in this channel
|
temp -- if True, channel will be deleted when there's no one in the channel. Optional. Default = False.
|
||||||
:param hidden: if True, thic channel won't be shown in channels list
|
hidden -- if True, channel will be hidden in channels list. Optional. Default = False.
|
||||||
:return:
|
|
||||||
"""
|
"""
|
||||||
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))
|
||||||
@@ -42,8 +45,8 @@ class channelList:
|
|||||||
Add a temporary channel (like #spectator or #multiplayer), gets deleted when there's no one in the channel
|
Add a temporary channel (like #spectator or #multiplayer), gets deleted when there's no one in the channel
|
||||||
and it's hidden in channels list
|
and it's hidden in channels list
|
||||||
|
|
||||||
:param name: channel name
|
name -- channel name
|
||||||
:return: True if the channel was created, otherwise False
|
return -- True if channel was created, False if failed
|
||||||
"""
|
"""
|
||||||
if name in self.channels:
|
if name in self.channels:
|
||||||
return False
|
return False
|
||||||
@@ -54,8 +57,7 @@ class channelList:
|
|||||||
"""
|
"""
|
||||||
Removes a channel from channels list
|
Removes a channel from channels list
|
||||||
|
|
||||||
:param name: channel name
|
name -- channel name
|
||||||
:return:
|
|
||||||
"""
|
"""
|
||||||
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))
|
||||||
|
@@ -1,20 +1,9 @@
|
|||||||
class chatFilters:
|
class chatFilters:
|
||||||
def __init__(self, fileName="filters.txt"):
|
def __init__(self, fileName="filters.txt"):
|
||||||
"""
|
|
||||||
Initialize chat filters
|
|
||||||
|
|
||||||
:param fileName: name of the file containing filters. Default: filters.txt
|
|
||||||
"""
|
|
||||||
self.filters = {}
|
self.filters = {}
|
||||||
self.loadFilters(fileName)
|
self.loadFilters(fileName)
|
||||||
|
|
||||||
def loadFilters(self, fileName="filters.txt"):
|
def loadFilters(self, fileName="filters.txt"):
|
||||||
"""
|
|
||||||
Load filters from a file
|
|
||||||
|
|
||||||
:param fileName: name of the file containing filters. Default: filters.txt
|
|
||||||
:return:
|
|
||||||
"""
|
|
||||||
# Reset chat filters
|
# Reset chat filters
|
||||||
self.filters = {}
|
self.filters = {}
|
||||||
|
|
||||||
@@ -30,12 +19,6 @@ class chatFilters:
|
|||||||
self.filters[lineSplit[0].lower()] = lineSplit[1].replace("\n", "")
|
self.filters[lineSplit[0].lower()] = lineSplit[1].replace("\n", "")
|
||||||
|
|
||||||
def filterMessage(self, message):
|
def filterMessage(self, message):
|
||||||
"""
|
|
||||||
Replace forbidden words with filtered ones
|
|
||||||
|
|
||||||
:param message: normal message
|
|
||||||
:return: filtered message
|
|
||||||
"""
|
|
||||||
# Split words by spaces
|
# Split words by spaces
|
||||||
messageTemp = message.split(" ")
|
messageTemp = message.split(" ")
|
||||||
|
|
||||||
|
@@ -1,47 +1,48 @@
|
|||||||
"""FokaBot related functions"""
|
"""FokaBot related functions"""
|
||||||
|
import random
|
||||||
import re
|
import re
|
||||||
|
|
||||||
|
import time
|
||||||
|
|
||||||
from common import generalUtils
|
from common import generalUtils
|
||||||
from common.constants import actions
|
from common.constants import actions
|
||||||
from common.ripple import userUtils
|
from common.ripple import userUtils
|
||||||
from constants import fokabotCommands
|
from constants import fokabotCommands
|
||||||
from constants import serverPackets
|
|
||||||
from objects import glob
|
from objects import glob
|
||||||
|
from common.log import logUtils as log
|
||||||
|
|
||||||
|
import threading
|
||||||
|
from helpers import chatHelper as chat
|
||||||
|
from constants import serverPackets
|
||||||
|
|
||||||
# Tillerino np regex, compiled only once to increase performance
|
# Tillerino np regex, compiled only once to increase performance
|
||||||
npRegex = re.compile("^https?:\\/\\/osu\\.ppy\\.sh\\/b\\/(\\d*)")
|
npRegex = re.compile("^https?:\\/\\/osu\\.ppy\\.sh\\/b\\/(\\d*)")
|
||||||
|
|
||||||
def connect():
|
def connect():
|
||||||
"""
|
"""Add FokaBot to connected users and send userpanel/stats packet to everyone"""
|
||||||
Connect FokaBot to Bancho
|
|
||||||
|
|
||||||
:return:
|
|
||||||
"""
|
|
||||||
token = glob.tokens.addToken(999)
|
token = glob.tokens.addToken(999)
|
||||||
token.actionID = actions.IDLE
|
token.actionID = actions.IDLE
|
||||||
glob.streams.broadcast("main", serverPackets.userPanel(999))
|
glob.streams.broadcast("main", serverPackets.userPanel(999))
|
||||||
glob.streams.broadcast("main", serverPackets.userStats(999))
|
glob.streams.broadcast("main", serverPackets.userStats(999))
|
||||||
|
|
||||||
def disconnect():
|
def disconnect():
|
||||||
"""
|
"""Remove FokaBot from connected users"""
|
||||||
Disconnect FokaBot from Bancho
|
|
||||||
|
|
||||||
:return:
|
|
||||||
"""
|
|
||||||
glob.tokens.deleteToken(glob.tokens.getTokenFromUserID(999))
|
glob.tokens.deleteToken(glob.tokens.getTokenFromUserID(999))
|
||||||
|
|
||||||
def fokabotResponse(fro, chan, message):
|
def fokabotResponse(fro, chan, message):
|
||||||
"""
|
"""
|
||||||
Check if a message has triggered FokaBot
|
Check if a message has triggered fokabot (and return its response)
|
||||||
|
|
||||||
:param fro: sender username
|
fro -- sender username (for permissions stuff with admin commands)
|
||||||
:param chan: channel name (or receiver username)
|
chan -- channel name
|
||||||
:param message: chat mesage
|
message -- message
|
||||||
:return: FokaBot's response or False if no response
|
|
||||||
|
return -- fokabot's response string or False
|
||||||
"""
|
"""
|
||||||
for i in fokabotCommands.commands:
|
for i in fokabotCommands.commands:
|
||||||
# Loop though all commands
|
# Loop though all commands
|
||||||
if generalUtils.strContains(message, i["trigger"]):
|
#if i["trigger"] in message:
|
||||||
|
if generalUtils.strContains(message.lower(), i["trigger"].lower()):
|
||||||
# message has triggered a command
|
# message has triggered a command
|
||||||
|
|
||||||
# Make sure the user has right permissions
|
# Make sure the user has right permissions
|
||||||
@@ -62,4 +63,23 @@ def fokabotResponse(fro, chan, message):
|
|||||||
return i["callback"](fro, chan, message[1:])
|
return i["callback"](fro, chan, message[1:])
|
||||||
|
|
||||||
# No commands triggered
|
# No commands triggered
|
||||||
return False
|
return False
|
||||||
|
|
||||||
|
def zingheriLoop():
|
||||||
|
log.debug("SONO STATI I ZINGHERI, I ZINGHERI!")
|
||||||
|
clients = glob.streams.getClients("zingheri")
|
||||||
|
for i in clients:
|
||||||
|
log.debug(str(i))
|
||||||
|
if i not in glob.tokens.tokens:
|
||||||
|
continue
|
||||||
|
token = glob.tokens.tokens[i]
|
||||||
|
if token.userID == 999:
|
||||||
|
continue
|
||||||
|
if token.zingheri == -1:
|
||||||
|
chat.sendMessage("FokaBot", token.username, "Knock knock, trick or treat?\nWho are you?\nI'm a {meme}. I'm a little {meme}.\n(reply with 'trick' or 'treat')".format(meme=random.choice(["shavit", "loctaf", "peppy", "foka", "elfo", "nano", "cupola autoportante"])))
|
||||||
|
token.zingheri = 0
|
||||||
|
elif token.zingheri == 1:
|
||||||
|
if token.actionID == actions.PLAYING and (int(time.time()) - token.actionLatestUpdate >= 25):
|
||||||
|
token.enqueue(serverPackets.zingheri("You'd better give me a treat next time ;)"))
|
||||||
|
token.leaveStream("zingheri")
|
||||||
|
threading.Timer(30, zingheriLoop).start()
|
@@ -1,6 +1,7 @@
|
|||||||
"""Global objects and variables"""
|
"""Global objects and variables"""
|
||||||
|
|
||||||
import time
|
import time
|
||||||
|
|
||||||
from common.ddog import datadogClient
|
from common.ddog import datadogClient
|
||||||
from common.files import fileBuffer, fileLocks
|
from common.files import fileBuffer, fileLocks
|
||||||
from objects import channelList
|
from objects import channelList
|
||||||
@@ -13,25 +14,26 @@ try:
|
|||||||
with open("version") as f:
|
with open("version") as f:
|
||||||
VERSION = f.read()
|
VERSION = f.read()
|
||||||
if VERSION == "":
|
if VERSION == "":
|
||||||
raise Exception
|
raise
|
||||||
except:
|
except:
|
||||||
VERSION = "Unknown"
|
VERSION = "¯\_(xd)_/¯"
|
||||||
|
|
||||||
DATADOG_PREFIX = "peppy"
|
DATADOG_PREFIX = "peppy"
|
||||||
application = None
|
application = None
|
||||||
db = None
|
db = None
|
||||||
redis = None
|
|
||||||
conf = None
|
conf = None
|
||||||
banchoConf = None
|
banchoConf = None
|
||||||
tokens = tokenList.tokenList()
|
tokens = tokenList.tokenList()
|
||||||
channels = channelList.channelList()
|
channels = channelList.channelList()
|
||||||
matches = matchList.matchList()
|
matches = matchList.matchList()
|
||||||
|
restarting = False
|
||||||
fLocks = fileLocks.fileLocks()
|
fLocks = fileLocks.fileLocks()
|
||||||
fileBuffers = fileBuffer.buffersList()
|
fileBuffers = fileBuffer.buffersList()
|
||||||
schiavo = schiavo.schiavo()
|
schiavo = schiavo.schiavo()
|
||||||
dog = datadogClient.datadogClient()
|
dog = datadogClient.datadogClient()
|
||||||
verifiedCache = {}
|
verifiedCache = {}
|
||||||
chatFilters = None
|
chatFilters = None
|
||||||
|
userIDCache = {}
|
||||||
pool = None
|
pool = None
|
||||||
ircServer = None
|
ircServer = None
|
||||||
busyThreads = 0
|
busyThreads = 0
|
||||||
@@ -43,8 +45,8 @@ gzip = False
|
|||||||
localize = False
|
localize = False
|
||||||
sentry = False
|
sentry = False
|
||||||
irc = False
|
irc = False
|
||||||
restarting = False
|
|
||||||
|
|
||||||
startTime = int(time.time())
|
startTime = int(time.time())
|
||||||
|
|
||||||
|
|
||||||
streams = streamList.streamList()
|
streams = streamList.streamList()
|
||||||
|
192
objects/match.py
192
objects/match.py
@@ -13,7 +13,7 @@ from objects import glob
|
|||||||
|
|
||||||
class slot:
|
class slot:
|
||||||
def __init__(self):
|
def __init__(self):
|
||||||
self.status = slotStatuses.FREE
|
self.status = slotStatuses.free
|
||||||
self.team = 0
|
self.team = 0
|
||||||
self.userID = -1
|
self.userID = -1
|
||||||
self.user = None
|
self.user = None
|
||||||
@@ -23,18 +23,19 @@ class slot:
|
|||||||
self.complete = False
|
self.complete = False
|
||||||
|
|
||||||
class match:
|
class match:
|
||||||
|
"""Multiplayer match object"""
|
||||||
def __init__(self, matchID, matchName, matchPassword, beatmapID, beatmapName, beatmapMD5, gameMode, hostUserID):
|
def __init__(self, matchID, matchName, matchPassword, beatmapID, beatmapName, beatmapMD5, gameMode, hostUserID):
|
||||||
"""
|
"""
|
||||||
Create a new match object
|
Create a new match object
|
||||||
|
|
||||||
:param matchID: match progressive identifier
|
matchID -- match progressive identifier
|
||||||
:param matchName: match name, string
|
matchName -- match name, string
|
||||||
:param matchPassword: match md5 password. Leave empty for no password
|
matchPassword -- match md5 password. Leave empty for no password
|
||||||
:param beatmapID: beatmap ID
|
beatmapID -- beatmap ID
|
||||||
:param beatmapName: beatmap name, string
|
beatmapName -- beatmap name, string
|
||||||
:param beatmapMD5: beatmap md5 hash, string
|
beatmapMD5 -- beatmap md5 hash, string
|
||||||
:param gameMode: game mode ID. See gameModes.py
|
gameMode -- game mode ID. See gameModes.py
|
||||||
:param hostUserID: user id of the host
|
hostUserID -- user id of the host
|
||||||
"""
|
"""
|
||||||
self.matchID = matchID
|
self.matchID = matchID
|
||||||
self.streamName = "multi/{}".format(self.matchID)
|
self.streamName = "multi/{}".format(self.matchID)
|
||||||
@@ -48,9 +49,9 @@ class match:
|
|||||||
self.beatmapMD5 = beatmapMD5
|
self.beatmapMD5 = beatmapMD5
|
||||||
self.hostUserID = hostUserID
|
self.hostUserID = hostUserID
|
||||||
self.gameMode = gameMode
|
self.gameMode = gameMode
|
||||||
self.matchScoringType = matchScoringTypes.SCORE # default values
|
self.matchScoringType = matchScoringTypes.score # default values
|
||||||
self.matchTeamType = matchTeamTypes.HEAD_TO_HEAD # default value
|
self.matchTeamType = matchTeamTypes.headToHead # default value
|
||||||
self.matchModMode = matchModModes.NORMAL # default value
|
self.matchModMode = matchModModes.normal # default value
|
||||||
self.seed = 0
|
self.seed = 0
|
||||||
self.matchDataCache = bytes()
|
self.matchDataCache = bytes()
|
||||||
|
|
||||||
@@ -69,8 +70,6 @@ class match:
|
|||||||
def getMatchData(self):
|
def getMatchData(self):
|
||||||
"""
|
"""
|
||||||
Return binary match data structure for packetHelper
|
Return binary match data structure for packetHelper
|
||||||
|
|
||||||
:return:
|
|
||||||
"""
|
"""
|
||||||
# General match info
|
# General match info
|
||||||
# TODO: Test without safe copy, the error might have been caused by outdated python bytecode cache
|
# TODO: Test without safe copy, the error might have been caused by outdated python bytecode cache
|
||||||
@@ -110,7 +109,7 @@ class match:
|
|||||||
])
|
])
|
||||||
|
|
||||||
# Slot mods if free mod is enabled
|
# Slot mods if free mod is enabled
|
||||||
if safeMatch.matchModMode == matchModModes.FREE_MOD:
|
if safeMatch.matchModMode == matchModModes.freeMod:
|
||||||
for i in range(0,16):
|
for i in range(0,16):
|
||||||
struct.append([safeMatch.slots[i].mods, dataTypes.UINT32])
|
struct.append([safeMatch.slots[i].mods, dataTypes.UINT32])
|
||||||
|
|
||||||
@@ -124,8 +123,7 @@ class match:
|
|||||||
"""
|
"""
|
||||||
Set room host to newHost and send him host packet
|
Set room host to newHost and send him host packet
|
||||||
|
|
||||||
:param newHost: new host userID
|
newHost -- new host userID
|
||||||
:return:
|
|
||||||
"""
|
"""
|
||||||
slotID = self.getUserSlotID(newHost)
|
slotID = self.getUserSlotID(newHost)
|
||||||
if slotID is None or self.slots[slotID].user not in glob.tokens.tokens:
|
if slotID is None or self.slots[slotID].user not in glob.tokens.tokens:
|
||||||
@@ -137,21 +135,7 @@ class match:
|
|||||||
log.info("MPROOM{}: {} is now the host".format(self.matchID, token.username))
|
log.info("MPROOM{}: {} is now the host".format(self.matchID, token.username))
|
||||||
|
|
||||||
def setSlot(self, slotID, status = None, team = None, user = "", mods = None, loaded = None, skip = None, complete = None):
|
def setSlot(self, slotID, status = None, team = None, user = "", mods = None, loaded = None, skip = None, complete = None):
|
||||||
"""
|
#self.setSlot(i, slotStatuses.notReady, 0, user, 0)
|
||||||
Set data for a specific slot.
|
|
||||||
All fields but slotID are optional.
|
|
||||||
Skipped fields won't be edited.
|
|
||||||
|
|
||||||
:param slotID: slot ID
|
|
||||||
:param status: new status
|
|
||||||
:param team: new team
|
|
||||||
:param user: new user id
|
|
||||||
:param mods: new mods
|
|
||||||
:param loaded: new loaded status
|
|
||||||
:param skip: new skip value
|
|
||||||
:param complete: new completed value
|
|
||||||
:return:
|
|
||||||
"""
|
|
||||||
if status is not None:
|
if status is not None:
|
||||||
self.slots[slotID].status = status
|
self.slots[slotID].status = status
|
||||||
|
|
||||||
@@ -177,9 +161,8 @@ class match:
|
|||||||
"""
|
"""
|
||||||
Set slotID mods. Same as calling setSlot and then sendUpdate
|
Set slotID mods. Same as calling setSlot and then sendUpdate
|
||||||
|
|
||||||
:param slotID: slot number
|
slotID -- slot number
|
||||||
:param mods: new mods
|
mods -- new mods
|
||||||
:return:
|
|
||||||
"""
|
"""
|
||||||
# Set new slot data and send update
|
# Set new slot data and send update
|
||||||
self.setSlot(slotID, mods=mods)
|
self.setSlot(slotID, mods=mods)
|
||||||
@@ -191,15 +174,14 @@ class match:
|
|||||||
Switch slotID ready/not ready status
|
Switch slotID ready/not ready status
|
||||||
Same as calling setSlot and then sendUpdate
|
Same as calling setSlot and then sendUpdate
|
||||||
|
|
||||||
:param slotID: slot number
|
slotID -- slot number
|
||||||
:return:
|
|
||||||
"""
|
"""
|
||||||
# Update ready status and setnd update
|
# Update ready status and setnd update
|
||||||
oldStatus = self.slots[slotID].status
|
oldStatus = self.slots[slotID].status
|
||||||
if oldStatus == slotStatuses.READY:
|
if oldStatus == slotStatuses.ready:
|
||||||
newStatus = slotStatuses.NOT_READY
|
newStatus = slotStatuses.notReady
|
||||||
else:
|
else:
|
||||||
newStatus = slotStatuses.READY
|
newStatus = slotStatuses.ready
|
||||||
self.setSlot(slotID, newStatus)
|
self.setSlot(slotID, newStatus)
|
||||||
self.sendUpdates()
|
self.sendUpdates()
|
||||||
log.info("MPROOM{}: Slot{} changed ready status to {}".format(self.matchID, slotID, self.slots[slotID].status))
|
log.info("MPROOM{}: Slot{} changed ready status to {}".format(self.matchID, slotID, self.slots[slotID].status))
|
||||||
@@ -209,14 +191,13 @@ class match:
|
|||||||
Lock a slot
|
Lock a slot
|
||||||
Same as calling setSlot and then sendUpdate
|
Same as calling setSlot and then sendUpdate
|
||||||
|
|
||||||
:param slotID: slot number
|
slotID -- slot number
|
||||||
:return:
|
|
||||||
"""
|
"""
|
||||||
# Check if slot is already locked
|
# Check if slot is already locked
|
||||||
if self.slots[slotID].status == slotStatuses.LOCKED:
|
if self.slots[slotID].status == slotStatuses.locked:
|
||||||
newStatus = slotStatuses.FREE
|
newStatus = slotStatuses.free
|
||||||
else:
|
else:
|
||||||
newStatus = slotStatuses.LOCKED
|
newStatus = slotStatuses.locked
|
||||||
|
|
||||||
# Send updated settings to kicked user, so he returns to lobby
|
# Send updated settings to kicked user, so he returns to lobby
|
||||||
if self.slots[slotID].user is not None and self.slots[slotID].user in glob.tokens.tokens:
|
if self.slots[slotID].user is not None and self.slots[slotID].user in glob.tokens.tokens:
|
||||||
@@ -227,14 +208,13 @@ class match:
|
|||||||
|
|
||||||
# Send updates to everyone else
|
# Send updates to everyone else
|
||||||
self.sendUpdates()
|
self.sendUpdates()
|
||||||
log.info("MPROOM{}: Slot{} {}".format(self.matchID, slotID, "locked" if newStatus == slotStatuses.LOCKED else "unlocked"))
|
log.info("MPROOM{}: Slot{} {}".format(self.matchID, slotID, "locked" if newStatus == slotStatuses.locked else "unlocked"))
|
||||||
|
|
||||||
def playerLoaded(self, userID):
|
def playerLoaded(self, userID):
|
||||||
"""
|
"""
|
||||||
Set a player loaded status to True
|
Set a player loaded status to True
|
||||||
|
|
||||||
:param userID: ID of user
|
userID -- ID of user
|
||||||
:return:
|
|
||||||
"""
|
"""
|
||||||
slotID = self.getUserSlotID(userID)
|
slotID = self.getUserSlotID(userID)
|
||||||
if slotID is None:
|
if slotID is None:
|
||||||
@@ -248,7 +228,7 @@ class match:
|
|||||||
total = 0
|
total = 0
|
||||||
loaded = 0
|
loaded = 0
|
||||||
for i in range(0,16):
|
for i in range(0,16):
|
||||||
if self.slots[i].status == slotStatuses.PLAYING:
|
if self.slots[i].status == slotStatuses.playing:
|
||||||
total+=1
|
total+=1
|
||||||
if self.slots[i].loaded:
|
if self.slots[i].loaded:
|
||||||
loaded+=1
|
loaded+=1
|
||||||
@@ -257,11 +237,7 @@ class match:
|
|||||||
self.allPlayersLoaded()
|
self.allPlayersLoaded()
|
||||||
|
|
||||||
def allPlayersLoaded(self):
|
def allPlayersLoaded(self):
|
||||||
"""
|
"""Send allPlayersLoaded packet to every playing usr in match"""
|
||||||
Send allPlayersLoaded packet to every playing usr in match
|
|
||||||
|
|
||||||
:return:
|
|
||||||
"""
|
|
||||||
glob.streams.broadcast(self.playingStreamName, serverPackets.allPlayersLoaded())
|
glob.streams.broadcast(self.playingStreamName, serverPackets.allPlayersLoaded())
|
||||||
log.info("MPROOM{}: All players loaded! Match starting...".format(self.matchID))
|
log.info("MPROOM{}: All players loaded! Match starting...".format(self.matchID))
|
||||||
|
|
||||||
@@ -269,8 +245,7 @@ class match:
|
|||||||
"""
|
"""
|
||||||
Set a player skip status to True
|
Set a player skip status to True
|
||||||
|
|
||||||
:param userID: ID of user
|
userID -- ID of user
|
||||||
:return:
|
|
||||||
"""
|
"""
|
||||||
slotID = self.getUserSlotID(userID)
|
slotID = self.getUserSlotID(userID)
|
||||||
if slotID is None:
|
if slotID is None:
|
||||||
@@ -288,7 +263,7 @@ class match:
|
|||||||
total = 0
|
total = 0
|
||||||
skipped = 0
|
skipped = 0
|
||||||
for i in range(0,16):
|
for i in range(0,16):
|
||||||
if self.slots[i].status == slotStatuses.PLAYING:
|
if self.slots[i].status == slotStatuses.playing:
|
||||||
total+=1
|
total+=1
|
||||||
if self.slots[i].skip:
|
if self.slots[i].skip:
|
||||||
skipped+=1
|
skipped+=1
|
||||||
@@ -297,11 +272,7 @@ class match:
|
|||||||
self.allPlayersSkipped()
|
self.allPlayersSkipped()
|
||||||
|
|
||||||
def allPlayersSkipped(self):
|
def allPlayersSkipped(self):
|
||||||
"""
|
"""Send allPlayersSkipped packet to every playing usr in match"""
|
||||||
Send allPlayersSkipped packet to every playing usr in match
|
|
||||||
|
|
||||||
:return:
|
|
||||||
"""
|
|
||||||
glob.streams.broadcast(self.playingStreamName, serverPackets.allPlayersSkipped())
|
glob.streams.broadcast(self.playingStreamName, serverPackets.allPlayersSkipped())
|
||||||
log.info("MPROOM{}: All players have skipped!".format(self.matchID))
|
log.info("MPROOM{}: All players have skipped!".format(self.matchID))
|
||||||
|
|
||||||
@@ -309,7 +280,7 @@ class match:
|
|||||||
"""
|
"""
|
||||||
Set userID's slot completed to True
|
Set userID's slot completed to True
|
||||||
|
|
||||||
:param userID: ID of user
|
userID -- ID of user
|
||||||
"""
|
"""
|
||||||
slotID = self.getUserSlotID(userID)
|
slotID = self.getUserSlotID(userID)
|
||||||
if slotID is None:
|
if slotID is None:
|
||||||
@@ -323,7 +294,7 @@ class match:
|
|||||||
total = 0
|
total = 0
|
||||||
completed = 0
|
completed = 0
|
||||||
for i in range(0,16):
|
for i in range(0,16):
|
||||||
if self.slots[i].status == slotStatuses.PLAYING:
|
if self.slots[i].status == slotStatuses.playing:
|
||||||
total+=1
|
total+=1
|
||||||
if self.slots[i].complete:
|
if self.slots[i].complete:
|
||||||
completed+=1
|
completed+=1
|
||||||
@@ -332,18 +303,15 @@ class match:
|
|||||||
self.allPlayersCompleted()
|
self.allPlayersCompleted()
|
||||||
|
|
||||||
def allPlayersCompleted(self):
|
def allPlayersCompleted(self):
|
||||||
"""
|
"""Cleanup match stuff and send match end packet to everyone"""
|
||||||
Cleanup match stuff and send match end packet to everyone
|
|
||||||
|
|
||||||
:return:
|
|
||||||
"""
|
|
||||||
# Reset inProgress
|
# Reset inProgress
|
||||||
self.inProgress = False
|
self.inProgress = False
|
||||||
|
|
||||||
# Reset slots
|
# Reset slots
|
||||||
for i in range(0,16):
|
for i in range(0,16):
|
||||||
if self.slots[i].user is not None and self.slots[i].status == slotStatuses.PLAYING:
|
if self.slots[i].user is not None and self.slots[i].status == slotStatuses.playing:
|
||||||
self.slots[i].status = slotStatuses.NOT_READY
|
self.slots[i].status = slotStatuses.notReady
|
||||||
self.slots[i].loaded = False
|
self.slots[i].loaded = False
|
||||||
self.slots[i].skip = False
|
self.slots[i].skip = False
|
||||||
self.slots[i].complete = False
|
self.slots[i].complete = False
|
||||||
@@ -364,7 +332,7 @@ class match:
|
|||||||
"""
|
"""
|
||||||
Get slot ID occupied by userID
|
Get slot ID occupied by userID
|
||||||
|
|
||||||
:return: slot id if found, None if user is not in room
|
return -- slot id if found, None if user is not in room
|
||||||
"""
|
"""
|
||||||
for i in range(0,16):
|
for i in range(0,16):
|
||||||
if self.slots[i].user is not None and self.slots[i].user in glob.tokens.tokens and glob.tokens.tokens[self.slots[i].user].userID == userID:
|
if self.slots[i].user is not None and self.slots[i].user in glob.tokens.tokens and glob.tokens.tokens[self.slots[i].user].userID == userID:
|
||||||
@@ -375,20 +343,21 @@ class match:
|
|||||||
"""
|
"""
|
||||||
Add someone to users in match
|
Add someone to users in match
|
||||||
|
|
||||||
:param userID: user id of the user
|
userID -- user id 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
|
||||||
for i in range(0,16):
|
for i in range(0,16):
|
||||||
if self.slots[i].user == user.token:
|
if self.slots[i].user == user.token:
|
||||||
# Set bugged slot to free
|
# Set bugged slot to free
|
||||||
self.setSlot(i, slotStatuses.FREE, 0, None, 0)
|
self.setSlot(i, slotStatuses.free, 0, None, 0)
|
||||||
|
|
||||||
# Find first free slot
|
# Find first free slot
|
||||||
for i in range(0,16):
|
for i in range(0,16):
|
||||||
if self.slots[i].status == slotStatuses.FREE:
|
if self.slots[i].status == slotStatuses.free:
|
||||||
# Occupy slot
|
# Occupy slot
|
||||||
self.setSlot(i, slotStatuses.NOT_READY, 0, user.token, 0)
|
self.setSlot(i, slotStatuses.notReady, 0, user.token, 0)
|
||||||
|
|
||||||
# Send updated match data
|
# Send updated match data
|
||||||
self.sendUpdates()
|
self.sendUpdates()
|
||||||
@@ -403,8 +372,7 @@ class match:
|
|||||||
"""
|
"""
|
||||||
Remove someone from users in match
|
Remove someone from users in match
|
||||||
|
|
||||||
:param userID: user if of the user
|
userID -- user if of the user
|
||||||
:return:
|
|
||||||
"""
|
"""
|
||||||
# Make sure the user is in room
|
# Make sure the user is in room
|
||||||
slotID = self.getUserSlotID(user.userID)
|
slotID = self.getUserSlotID(user.userID)
|
||||||
@@ -412,7 +380,7 @@ class match:
|
|||||||
return
|
return
|
||||||
|
|
||||||
# Set that slot to free
|
# Set that slot to free
|
||||||
self.setSlot(slotID, slotStatuses.FREE, 0, None, 0)
|
self.setSlot(slotID, slotStatuses.free, 0, None, 0)
|
||||||
|
|
||||||
# Check if everyone left
|
# Check if everyone left
|
||||||
if self.countUsers() == 0:
|
if self.countUsers() == 0:
|
||||||
@@ -439,9 +407,8 @@ class match:
|
|||||||
"""
|
"""
|
||||||
Change userID slot to newSlotID
|
Change userID slot to newSlotID
|
||||||
|
|
||||||
:param userID: user that changed slot
|
userID -- user that changed slot
|
||||||
:param newSlotID: slot id of new slot
|
newSlotID -- slot id of new slot
|
||||||
:return:
|
|
||||||
"""
|
"""
|
||||||
# Make sure the user is in room
|
# Make sure the user is in room
|
||||||
oldSlotID = self.getUserSlotID(userID)
|
oldSlotID = self.getUserSlotID(userID)
|
||||||
@@ -449,7 +416,7 @@ class match:
|
|||||||
return
|
return
|
||||||
|
|
||||||
# Make sure there is no one inside new slot
|
# Make sure there is no one inside new slot
|
||||||
if self.slots[newSlotID].user is not None and self.slots[newSlotID].status != slotStatuses.FREE:
|
if self.slots[newSlotID].user is not None and self.slots[newSlotID].status != slotStatuses.free:
|
||||||
return
|
return
|
||||||
|
|
||||||
# Get old slot data
|
# Get old slot data
|
||||||
@@ -457,7 +424,7 @@ class match:
|
|||||||
oldData = copy.deepcopy(self.slots[oldSlotID])
|
oldData = copy.deepcopy(self.slots[oldSlotID])
|
||||||
|
|
||||||
# Free old slot
|
# Free old slot
|
||||||
self.setSlot(oldSlotID, slotStatuses.FREE, 0, None, 0, False, False, False)
|
self.setSlot(oldSlotID, slotStatuses.free, 0, None, 0, False, False, False)
|
||||||
|
|
||||||
# Occupy new slot
|
# Occupy new slot
|
||||||
self.setSlot(newSlotID, oldData.status, oldData.team, oldData.user, oldData.mods)
|
self.setSlot(newSlotID, oldData.status, oldData.team, oldData.user, oldData.mods)
|
||||||
@@ -472,10 +439,13 @@ class match:
|
|||||||
"""
|
"""
|
||||||
Change match password to newPassword
|
Change match password to newPassword
|
||||||
|
|
||||||
:param newPassword: new password string
|
newPassword -- new password string
|
||||||
:return:
|
|
||||||
"""
|
"""
|
||||||
self.matchPassword = newPassword
|
self.matchPassword = newPassword
|
||||||
|
#if newPassword != "":
|
||||||
|
# self.matchPassword = generalUtils.stringMd5(newPassword)
|
||||||
|
#else:
|
||||||
|
# self.matchPassword = ""
|
||||||
|
|
||||||
# Send password change to every user in match
|
# Send password change to every user in match
|
||||||
glob.streams.broadcast(self.streamName, serverPackets.changeMatchPassword(self.matchPassword))
|
glob.streams.broadcast(self.streamName, serverPackets.changeMatchPassword(self.matchPassword))
|
||||||
@@ -490,8 +460,7 @@ class match:
|
|||||||
"""
|
"""
|
||||||
Set match global mods
|
Set match global mods
|
||||||
|
|
||||||
:param mods: mods bitwise int thing
|
mods -- mods bitwise int thing
|
||||||
:return:
|
|
||||||
"""
|
"""
|
||||||
# Set new mods and send update
|
# Set new mods and send update
|
||||||
self.mods = mods
|
self.mods = mods
|
||||||
@@ -502,9 +471,8 @@ class match:
|
|||||||
"""
|
"""
|
||||||
Set no beatmap status for userID
|
Set no beatmap status for userID
|
||||||
|
|
||||||
:param userID: ID of user
|
userID -- ID of user
|
||||||
:param has: True if has beatmap, false if not
|
has -- True if has beatmap, false if not
|
||||||
:return:
|
|
||||||
"""
|
"""
|
||||||
# Make sure the user is in room
|
# Make sure the user is in room
|
||||||
slotID = self.getUserSlotID(userID)
|
slotID = self.getUserSlotID(userID)
|
||||||
@@ -512,7 +480,7 @@ class match:
|
|||||||
return
|
return
|
||||||
|
|
||||||
# Set slot
|
# Set slot
|
||||||
self.setSlot(slotID, slotStatuses.NO_MAP if not has else slotStatuses.NOT_READY)
|
self.setSlot(slotID, slotStatuses.noMap if not has else slotStatuses.notReady)
|
||||||
|
|
||||||
# Send updates
|
# Send updates
|
||||||
self.sendUpdates()
|
self.sendUpdates()
|
||||||
@@ -521,8 +489,7 @@ class match:
|
|||||||
"""
|
"""
|
||||||
Transfer host to slotID
|
Transfer host to slotID
|
||||||
|
|
||||||
:param slotID: ID of slot
|
slotID -- ID of slot
|
||||||
:return:
|
|
||||||
"""
|
"""
|
||||||
# Make sure there is someone in that slot
|
# Make sure there is someone in that slot
|
||||||
if self.slots[slotID].user is None or self.slots[slotID].user not in glob.tokens.tokens:
|
if self.slots[slotID].user is None or self.slots[slotID].user not in glob.tokens.tokens:
|
||||||
@@ -538,8 +505,7 @@ class match:
|
|||||||
"""
|
"""
|
||||||
Send userID's failed packet to everyone in match
|
Send userID's failed packet to everyone in match
|
||||||
|
|
||||||
:param userID: ID of user
|
userID -- ID of user
|
||||||
:return:
|
|
||||||
"""
|
"""
|
||||||
# Make sure the user is in room
|
# Make sure the user is in room
|
||||||
slotID = self.getUserSlotID(userID)
|
slotID = self.getUserSlotID(userID)
|
||||||
@@ -556,10 +522,10 @@ class match:
|
|||||||
"""
|
"""
|
||||||
Fro invites to in this match.
|
Fro invites to in this match.
|
||||||
|
|
||||||
:param fro: sender userID
|
fro -- sender userID
|
||||||
:param to: receiver userID
|
to -- receiver userID
|
||||||
:return:
|
|
||||||
"""
|
"""
|
||||||
|
|
||||||
# Get tokens
|
# Get tokens
|
||||||
froToken = glob.tokens.getTokenFromUserID(fro)
|
froToken = glob.tokens.getTokenFromUserID(fro)
|
||||||
toToken = glob.tokens.getTokenFromUserID(to)
|
toToken = glob.tokens.getTokenFromUserID(to)
|
||||||
@@ -578,7 +544,7 @@ class match:
|
|||||||
"""
|
"""
|
||||||
Return how many players are in that match
|
Return how many players are in that match
|
||||||
|
|
||||||
:return: number of users
|
return -- number of users
|
||||||
"""
|
"""
|
||||||
c = 0
|
c = 0
|
||||||
for i in range(0,16):
|
for i in range(0,16):
|
||||||
@@ -590,8 +556,7 @@ class match:
|
|||||||
"""
|
"""
|
||||||
Change userID's team
|
Change userID's team
|
||||||
|
|
||||||
:param userID: id of user
|
userID -- id of user
|
||||||
:return:
|
|
||||||
"""
|
"""
|
||||||
# Make sure the user is in room
|
# Make sure the user is in room
|
||||||
slotID = self.getUserSlotID(userID)
|
slotID = self.getUserSlotID(userID)
|
||||||
@@ -599,16 +564,11 @@ class match:
|
|||||||
return
|
return
|
||||||
|
|
||||||
# Update slot and send update
|
# Update slot and send update
|
||||||
newTeam = matchTeams.BLUE if self.slots[slotID].team == matchTeams.RED else matchTeams.RED
|
newTeam = matchTeams.blue if self.slots[slotID].team == matchTeams.red else matchTeams.red
|
||||||
self.setSlot(slotID, None, newTeam)
|
self.setSlot(slotID, None, newTeam)
|
||||||
self.sendUpdates()
|
self.sendUpdates()
|
||||||
|
|
||||||
def sendUpdates(self):
|
def sendUpdates(self):
|
||||||
"""
|
|
||||||
Send match updates packet to everyone in lobby and room streams
|
|
||||||
|
|
||||||
:return:
|
|
||||||
"""
|
|
||||||
self.matchDataCache = serverPackets.updateMatch(self.matchID)
|
self.matchDataCache = serverPackets.updateMatch(self.matchID)
|
||||||
if self.matchDataCache is not None:
|
if self.matchDataCache is not None:
|
||||||
glob.streams.broadcast(self.streamName, self.matchDataCache)
|
glob.streams.broadcast(self.streamName, self.matchDataCache)
|
||||||
@@ -620,17 +580,16 @@ class match:
|
|||||||
"""
|
"""
|
||||||
Check if match teams are valid
|
Check if match teams are valid
|
||||||
|
|
||||||
:return: True if valid, False if invalid
|
return -- True if valid, False if invalid
|
||||||
:return:
|
|
||||||
"""
|
"""
|
||||||
if self.matchTeamType != matchTeamTypes.TEAM_VS or self.matchTeamType != matchTeamTypes.TAG_TEAM_VS:
|
if self.matchTeamType != matchTeamTypes.teamVs or self.matchTeamType != matchTeamTypes.tagTeamVs:
|
||||||
# Teams are always valid if we have no teams
|
# Teams are always valid if we have no teams
|
||||||
return True
|
return True
|
||||||
|
|
||||||
# We have teams, check if they are valid
|
# We have teams, check if they are valid
|
||||||
firstTeam = -1
|
firstTeam = -1
|
||||||
for i in range(0,16):
|
for i in range(0,16):
|
||||||
if self.slots[i].user is not None and (self.slots[i].status & slotStatuses.NO_MAP) == 0:
|
if self.slots[i].user is not None and (self.slots[i].status & slotStatuses.noMap) == 0:
|
||||||
if firstTeam == -1:
|
if firstTeam == -1:
|
||||||
firstTeam = self.slots[i].team
|
firstTeam = self.slots[i].team
|
||||||
elif firstTeam != self.slots[i].team:
|
elif firstTeam != self.slots[i].team:
|
||||||
@@ -641,11 +600,6 @@ class match:
|
|||||||
return False
|
return False
|
||||||
|
|
||||||
def start(self):
|
def start(self):
|
||||||
"""
|
|
||||||
Start the match
|
|
||||||
|
|
||||||
:return:
|
|
||||||
"""
|
|
||||||
# Make sure we have enough players
|
# Make sure we have enough players
|
||||||
if self.countUsers() < 2 or not self.checkTeams():
|
if self.countUsers() < 2 or not self.checkTeams():
|
||||||
return
|
return
|
||||||
@@ -659,8 +613,8 @@ class match:
|
|||||||
# Set playing to ready players and set load, skip and complete to False
|
# Set playing to ready players and set load, skip and complete to False
|
||||||
# Make clients join playing stream
|
# Make clients join playing stream
|
||||||
for i in range(0, 16):
|
for i in range(0, 16):
|
||||||
if (self.slots[i].status & slotStatuses.READY) > 0 and self.slots[i].user in glob.tokens.tokens:
|
if (self.slots[i].status & slotStatuses.ready) > 0 and self.slots[i].user in glob.tokens.tokens:
|
||||||
self.slots[i].status = slotStatuses.PLAYING
|
self.slots[i].status = slotStatuses.playing
|
||||||
self.slots[i].loaded = False
|
self.slots[i].loaded = False
|
||||||
self.slots[i].skip = False
|
self.slots[i].skip = False
|
||||||
self.slots[i].complete = False
|
self.slots[i].complete = False
|
||||||
|
@@ -13,14 +13,14 @@ class matchList:
|
|||||||
"""
|
"""
|
||||||
Add a new match to matches list
|
Add a new match to matches list
|
||||||
|
|
||||||
:param matchName: match name, string
|
matchName -- match name, string
|
||||||
:param matchPassword: match md5 password. Leave empty for no password
|
matchPassword -- match md5 password. Leave empty for no password
|
||||||
:param beatmapID: beatmap ID
|
beatmapID -- beatmap ID
|
||||||
:param beatmapName: beatmap name, string
|
beatmapName -- beatmap name, string
|
||||||
:param beatmapMD5: beatmap md5 hash, string
|
beatmapMD5 -- beatmap md5 hash, string
|
||||||
:param gameMode: game mode ID. See gameModes.py
|
gameMode -- game mode ID. See gameModes.py
|
||||||
:param hostUserID: user id of who created the match
|
hostUserID -- user id of who created the match
|
||||||
:return: match ID
|
return -- match ID
|
||||||
"""
|
"""
|
||||||
# Add a new match to matches list and create its stream
|
# Add a new match to matches list and create its stream
|
||||||
matchID = self.lastID
|
matchID = self.lastID
|
||||||
@@ -32,8 +32,7 @@ class matchList:
|
|||||||
"""
|
"""
|
||||||
Destroy match object with id = matchID
|
Destroy match object with id = matchID
|
||||||
|
|
||||||
:param matchID: ID of match to dispose
|
matchID -- ID of match to dispose
|
||||||
:return:
|
|
||||||
"""
|
"""
|
||||||
# Make sure the match exists
|
# Make sure the match exists
|
||||||
if matchID not in self.matches:
|
if matchID not in self.matches:
|
||||||
|
@@ -12,26 +12,24 @@ from objects import glob
|
|||||||
|
|
||||||
|
|
||||||
class token:
|
class token:
|
||||||
|
|
||||||
def __init__(self, userID, token_ = None, ip ="", irc = False, timeOffset = 0, tournament = False):
|
def __init__(self, userID, token_ = None, ip ="", irc = False, timeOffset = 0, tournament = False):
|
||||||
"""
|
"""
|
||||||
Create a token object and set userID and token
|
Create a token object and set userID and token
|
||||||
|
|
||||||
:param userID: user associated to this token
|
userID -- user associated to this token
|
||||||
:param token_: if passed, set token to that value
|
token -- if passed, set token to that value
|
||||||
if not passed, token will be generated
|
if not passed, token will be generated
|
||||||
:param ip: client ip. optional.
|
ip -- client ip. optional.
|
||||||
:param irc: if True, set this token as IRC client. Default: False.
|
irc -- if True, set this token as IRC client. optional.
|
||||||
:param timeOffset: the time offset from UTC for this user. Default: 0.
|
timeOffset -- the time offset from UTC for this user. optional.
|
||||||
:param tournament: if True, flag this client as a tournement client. Default: True.
|
|
||||||
"""
|
"""
|
||||||
# Set stuff
|
# Set stuff
|
||||||
self.userID = userID
|
self.userID = userID
|
||||||
self.username = userUtils.getUsername(self.userID)
|
self.username = userUtils.getUsername(self.userID)
|
||||||
self.safeUsername = userUtils.getSafeUsername(self.userID)
|
|
||||||
self.privileges = userUtils.getPrivileges(self.userID)
|
self.privileges = userUtils.getPrivileges(self.userID)
|
||||||
self.admin = userUtils.isInPrivilegeGroup(self.userID, "developer") or userUtils.isInPrivilegeGroup(self.userID, "community manager")
|
self.admin = userUtils.isInPrivilegeGroup(self.userID, "developer") or userUtils.isInPrivilegeGroup(self.userID, "community manager")
|
||||||
self.irc = irc
|
self.irc = irc
|
||||||
self.kicked = False
|
|
||||||
self.restricted = userUtils.isRestricted(self.userID)
|
self.restricted = userUtils.isRestricted(self.userID)
|
||||||
self.loginTime = int(time.time())
|
self.loginTime = int(time.time())
|
||||||
self.pingTime = self.loginTime
|
self.pingTime = self.loginTime
|
||||||
@@ -53,7 +51,6 @@ class token:
|
|||||||
self.country = 0
|
self.country = 0
|
||||||
self.location = [0,0]
|
self.location = [0,0]
|
||||||
self.awayMessage = ""
|
self.awayMessage = ""
|
||||||
self.sentAway = []
|
|
||||||
self.matchID = -1
|
self.matchID = -1
|
||||||
self.tillerino = [0,0,-1.0] # beatmap, mods, acc
|
self.tillerino = [0,0,-1.0] # beatmap, mods, acc
|
||||||
self.silenceEndTime = 0
|
self.silenceEndTime = 0
|
||||||
@@ -67,6 +64,7 @@ class token:
|
|||||||
self.actionText = ""
|
self.actionText = ""
|
||||||
self.actionMd5 = ""
|
self.actionMd5 = ""
|
||||||
self.actionMods = 0
|
self.actionMods = 0
|
||||||
|
self.actionLatestUpdate = self.pingTime
|
||||||
self.gameMode = gameModes.STD
|
self.gameMode = gameModes.STD
|
||||||
self.beatmapID = 0
|
self.beatmapID = 0
|
||||||
self.rankedScore = 0
|
self.rankedScore = 0
|
||||||
@@ -76,6 +74,11 @@ class token:
|
|||||||
self.gameRank = 0
|
self.gameRank = 0
|
||||||
self.pp = 0
|
self.pp = 0
|
||||||
|
|
||||||
|
# -1: Non sa dell'esistenza dei zingheri
|
||||||
|
# 0: In attesa di risposta al messaggiomem
|
||||||
|
# 1: zingheri soonTM
|
||||||
|
self.zingheri = -1
|
||||||
|
|
||||||
# Generate/set token
|
# Generate/set token
|
||||||
if token_ is not None:
|
if token_ is not None:
|
||||||
self.token = token_
|
self.token = token_
|
||||||
@@ -91,28 +94,31 @@ class token:
|
|||||||
|
|
||||||
# Join main stream
|
# Join main stream
|
||||||
self.joinStream("main")
|
self.joinStream("main")
|
||||||
|
self.joinStream("zingheri")
|
||||||
|
|
||||||
def enqueue(self, bytes_):
|
def enqueue(self, bytes_):
|
||||||
"""
|
"""
|
||||||
Add bytes (packets) to queue
|
Add bytes (packets) to queue
|
||||||
|
|
||||||
:param bytes: (packet) bytes to enqueue
|
bytes -- (packet) bytes to enqueue
|
||||||
"""
|
"""
|
||||||
# TODO: reduce max queue size
|
if not self.irc:
|
||||||
if len(bytes_) < 10 * 10 ** 6:
|
if len(bytes_) < 10 * 10 ** 6:
|
||||||
self.queue += bytes_
|
self.queue += bytes_
|
||||||
else:
|
else:
|
||||||
log.warning("{}'s packets buffer is above 10M!! Lost some data!".format(self.username))
|
log.warning("{}'s packets buffer is above 10M!! Lost some data!".format(self.username))
|
||||||
|
|
||||||
|
|
||||||
def resetQueue(self):
|
def resetQueue(self):
|
||||||
"""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, channel):
|
||||||
"""
|
"""
|
||||||
Add channel to joined channels list
|
Add channel to joined channels list
|
||||||
|
|
||||||
:param channel: channel name
|
channel -- channel name
|
||||||
"""
|
"""
|
||||||
if channel not in self.joinedChannels:
|
if channel not in self.joinedChannels:
|
||||||
self.joinedChannels.append(channel)
|
self.joinedChannels.append(channel)
|
||||||
@@ -121,24 +127,24 @@ class token:
|
|||||||
"""
|
"""
|
||||||
Remove channel from joined channels list
|
Remove channel from joined channels list
|
||||||
|
|
||||||
:param channel: channel name
|
channel -- channel name
|
||||||
"""
|
"""
|
||||||
if channel in self.joinedChannels:
|
if channel in self.joinedChannels:
|
||||||
self.joinedChannels.remove(channel)
|
self.joinedChannels.remove(channel)
|
||||||
|
|
||||||
def setLocation(self, latitude, longitude):
|
def setLocation(self, location):
|
||||||
"""
|
"""
|
||||||
Set client location
|
Set location (latitude and longitude)
|
||||||
|
|
||||||
:param location: [latitude, longitude]
|
location -- [latitude, longitude]
|
||||||
"""
|
"""
|
||||||
self.location = (latitude, longitude)
|
self.location = location
|
||||||
|
|
||||||
def getLatitude(self):
|
def getLatitude(self):
|
||||||
"""
|
"""
|
||||||
Get latitude
|
Get latitude
|
||||||
|
|
||||||
:return: latitude
|
return -- latitude
|
||||||
"""
|
"""
|
||||||
return self.location[0]
|
return self.location[0]
|
||||||
|
|
||||||
@@ -146,16 +152,15 @@ class token:
|
|||||||
"""
|
"""
|
||||||
Get longitude
|
Get longitude
|
||||||
|
|
||||||
:return: longitude
|
return -- longitude
|
||||||
"""
|
"""
|
||||||
return self.location[1]
|
return self.location[1]
|
||||||
|
|
||||||
def startSpectating(self, host):
|
def startSpectating(self, host):
|
||||||
"""
|
"""
|
||||||
Set the spectating user to userID, join spectator stream and chat channel
|
Set the spectating user to userID
|
||||||
and send required packets to host
|
|
||||||
|
|
||||||
:param host: host osuToken object
|
user -- user object
|
||||||
"""
|
"""
|
||||||
# Stop spectating old client
|
# Stop spectating old client
|
||||||
self.stopSpectating()
|
self.stopSpectating()
|
||||||
@@ -195,12 +200,6 @@ class token:
|
|||||||
log.info("{} is spectating {}".format(self.username, host.username))
|
log.info("{} is spectating {}".format(self.username, host.username))
|
||||||
|
|
||||||
def stopSpectating(self):
|
def stopSpectating(self):
|
||||||
"""
|
|
||||||
Stop spectating, leave spectator stream and channel
|
|
||||||
and send required packets to host
|
|
||||||
|
|
||||||
:return:
|
|
||||||
"""
|
|
||||||
# Remove our userID from host's spectators
|
# Remove our userID from host's spectators
|
||||||
if self.spectating is None:
|
if self.spectating is None:
|
||||||
return
|
return
|
||||||
@@ -239,20 +238,36 @@ class token:
|
|||||||
self.spectating = None
|
self.spectating = None
|
||||||
self.spectatingUserID = 0
|
self.spectatingUserID = 0
|
||||||
|
|
||||||
def updatePingTime(self):
|
def setCountry(self, countryID):
|
||||||
"""
|
"""
|
||||||
Update latest ping time to current time
|
Set country to countryID
|
||||||
|
|
||||||
:return:
|
countryID -- numeric country ID. See countryHelper.py
|
||||||
"""
|
"""
|
||||||
|
self.country = countryID
|
||||||
|
|
||||||
|
def getCountry(self):
|
||||||
|
"""
|
||||||
|
Get numeric country ID
|
||||||
|
|
||||||
|
return -- numeric country ID. See countryHelper.py
|
||||||
|
"""
|
||||||
|
return self.country
|
||||||
|
|
||||||
|
def updatePingTime(self):
|
||||||
|
"""Update latest ping time"""
|
||||||
self.pingTime = int(time.time())
|
self.pingTime = int(time.time())
|
||||||
|
|
||||||
|
def setAwayMessage(self, __awayMessage):
|
||||||
|
"""Set a new away message"""
|
||||||
|
self.awayMessage = __awayMessage
|
||||||
|
|
||||||
|
|
||||||
def joinMatch(self, matchID):
|
def joinMatch(self, matchID):
|
||||||
"""
|
"""
|
||||||
Set match to matchID, join match stream and channel
|
Set match to matchID, join match stream and channel
|
||||||
|
|
||||||
:param matchID: new match ID
|
matchID -- new match ID
|
||||||
:return:
|
|
||||||
"""
|
"""
|
||||||
# Make sure the match exists
|
# Make sure the match exists
|
||||||
if matchID not in glob.matches.matches:
|
if matchID not in glob.matches.matches:
|
||||||
@@ -312,10 +327,7 @@ class token:
|
|||||||
"""
|
"""
|
||||||
Kick this user from the server
|
Kick this user from the server
|
||||||
|
|
||||||
:param message: Notification message to send to this user.
|
message -- Notification message to send to this user. Optional.
|
||||||
Default: "You have been kicked from the server. Please login again."
|
|
||||||
:param reason: Kick reason, used in logs. Default: "kick"
|
|
||||||
:return:
|
|
||||||
"""
|
"""
|
||||||
# Send packet to target
|
# Send packet to target
|
||||||
log.info("{} has been disconnected. ({})".format(self.username, reason))
|
log.info("{} has been disconnected. ({})".format(self.username, reason))
|
||||||
@@ -324,28 +336,21 @@ class token:
|
|||||||
self.enqueue(serverPackets.loginFailed())
|
self.enqueue(serverPackets.loginFailed())
|
||||||
|
|
||||||
# Logout event
|
# Logout event
|
||||||
logoutEvent.handle(self, deleteToken=False)
|
logoutEvent.handle(self, None)
|
||||||
|
|
||||||
def silence(self, seconds = None, reason = "", author = 999):
|
def silence(self, seconds, reason, author = 999):
|
||||||
"""
|
"""
|
||||||
Silences this user (db, packet and token)
|
Silences this user (db, packet and token)
|
||||||
|
|
||||||
:param seconds: silence length in seconds. If None, get it from db. Default: None
|
seconds -- silence length in seconds
|
||||||
:param reason: silence reason. Default: empty string
|
reason -- silence reason
|
||||||
:param author: userID of who has silenced the user. Default: 999 (FokaBot)
|
author -- userID of who has silenced the target. Optional. Default: 999 (fokabot)
|
||||||
:return:
|
|
||||||
"""
|
"""
|
||||||
if seconds is None:
|
# Silence in db and token
|
||||||
# Get silence expire from db if needed
|
self.silenceEndTime = int(time.time())+seconds
|
||||||
seconds = max(0, userUtils.getSilenceEnd(self.userID) - int(time.time()))
|
userUtils.silence(self.userID, seconds, reason, author)
|
||||||
else:
|
|
||||||
# Silence in db and token
|
|
||||||
userUtils.silence(self.userID, seconds, reason, author)
|
|
||||||
|
|
||||||
# Silence token
|
# Send silence packet to target
|
||||||
self.silenceEndTime = int(time.time()) + seconds
|
|
||||||
|
|
||||||
# Send silence packet to user
|
|
||||||
self.enqueue(serverPackets.silenceEndTime(seconds))
|
self.enqueue(serverPackets.silenceEndTime(seconds))
|
||||||
|
|
||||||
# Send silenced packet to everyone else
|
# Send silenced packet to everyone else
|
||||||
@@ -355,8 +360,7 @@ class token:
|
|||||||
"""
|
"""
|
||||||
Silences the user if is spamming.
|
Silences the user if is spamming.
|
||||||
|
|
||||||
:param increaseSpamRate: set to True if the user has sent a new message. Default: True
|
increaseSpamRate -- pass True if the user has sent a new message. Optional. Default: True
|
||||||
:return:
|
|
||||||
"""
|
"""
|
||||||
# Increase the spam rate if needed
|
# Increase the spam rate if needed
|
||||||
if increaseSpamRate:
|
if increaseSpamRate:
|
||||||
@@ -370,7 +374,7 @@ class token:
|
|||||||
"""
|
"""
|
||||||
Returns True if this user is silenced, otherwise False
|
Returns True if this user is silenced, otherwise False
|
||||||
|
|
||||||
:return: True if this user is silenced, otherwise False
|
return -- True/False
|
||||||
"""
|
"""
|
||||||
return self.silenceEndTime-int(time.time()) > 0
|
return self.silenceEndTime-int(time.time()) > 0
|
||||||
|
|
||||||
@@ -379,16 +383,12 @@ class token:
|
|||||||
Returns the seconds left for this user's silence
|
Returns the seconds left for this user's silence
|
||||||
(0 if user is not silenced)
|
(0 if user is not silenced)
|
||||||
|
|
||||||
:return: silence seconds left (or 0)
|
return -- silence seconds left
|
||||||
"""
|
"""
|
||||||
return max(0, self.silenceEndTime-int(time.time()))
|
return max(0, self.silenceEndTime-int(time.time()))
|
||||||
|
|
||||||
def updateCachedStats(self):
|
def updateCachedStats(self):
|
||||||
"""
|
"""Update all cached stats for this token"""
|
||||||
Update all cached stats for this token
|
|
||||||
|
|
||||||
:return:
|
|
||||||
"""
|
|
||||||
stats = userUtils.getUserStats(self.userID, self.gameMode)
|
stats = userUtils.getUserStats(self.userID, self.gameMode)
|
||||||
log.debug(str(stats))
|
log.debug(str(stats))
|
||||||
if stats is None:
|
if stats is None:
|
||||||
@@ -401,89 +401,36 @@ class token:
|
|||||||
self.gameRank = stats["gameRank"]
|
self.gameRank = stats["gameRank"]
|
||||||
self.pp = stats["pp"]
|
self.pp = stats["pp"]
|
||||||
|
|
||||||
def checkRestricted(self):
|
def checkRestricted(self, force=False):
|
||||||
"""
|
"""
|
||||||
Check if this token is restricted. If so, send fokabot message
|
Check if this token is restricted. If so, send fokabot message
|
||||||
|
|
||||||
:return:
|
force -- If True, get restricted value from db.
|
||||||
|
If false, get the cached one. Optional. Default: False
|
||||||
"""
|
"""
|
||||||
oldRestricted = self.restricted
|
if force:
|
||||||
self.restricted = userUtils.isRestricted(self.userID)
|
self.restricted = userUtils.isRestricted(self.userID)
|
||||||
if self.restricted:
|
if self.restricted:
|
||||||
self.setRestricted()
|
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):
|
def setRestricted(self):
|
||||||
"""
|
"""
|
||||||
Set this token as restricted, send FokaBot message to user
|
Set this token as restricted, send FokaBot message to user
|
||||||
and send offline packet to everyone
|
and send offline packet to everyone
|
||||||
|
|
||||||
:return:
|
|
||||||
"""
|
"""
|
||||||
self.restricted = True
|
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):
|
def joinStream(self, name):
|
||||||
"""
|
|
||||||
Join a packet stream, or create it if the stream doesn't exist.
|
|
||||||
|
|
||||||
:param name: stream name
|
|
||||||
:return:
|
|
||||||
"""
|
|
||||||
glob.streams.join(name, token=self.token)
|
glob.streams.join(name, token=self.token)
|
||||||
if name not in self.streams:
|
if name not in self.streams:
|
||||||
self.streams.append(name)
|
self.streams.append(name)
|
||||||
|
|
||||||
def leaveStream(self, name):
|
def leaveStream(self, name):
|
||||||
"""
|
|
||||||
Leave a packets stream
|
|
||||||
|
|
||||||
:param name: stream name
|
|
||||||
:return:
|
|
||||||
"""
|
|
||||||
glob.streams.leave(name, token=self.token)
|
glob.streams.leave(name, token=self.token)
|
||||||
if name in self.streams:
|
if name in self.streams:
|
||||||
self.streams.remove(name)
|
self.streams.remove(name)
|
||||||
|
|
||||||
def leaveAllStreams(self):
|
def leaveAllStreams(self):
|
||||||
"""
|
|
||||||
Leave all joined packet streams
|
|
||||||
|
|
||||||
:return:
|
|
||||||
"""
|
|
||||||
for i in self.streams:
|
for i in self.streams:
|
||||||
self.leaveStream(i)
|
self.leaveStream(i)
|
||||||
|
|
||||||
def awayCheck(self, userID):
|
|
||||||
"""
|
|
||||||
Returns True if userID doesn't know that we are away
|
|
||||||
Returns False if we are not away or if userID already knows we are away
|
|
||||||
|
|
||||||
:param userID: original sender userID
|
|
||||||
:return:
|
|
||||||
"""
|
|
||||||
if self.awayMessage == "" or userID in self.sentAway:
|
|
||||||
return False
|
|
||||||
self.sentAway.append(userID)
|
|
||||||
return True
|
|
@@ -67,7 +67,7 @@ class streamList:
|
|||||||
return
|
return
|
||||||
self.streams[streamName].broadcast(data)
|
self.streams[streamName].broadcast(data)
|
||||||
|
|
||||||
'''def getClients(self, streamName):
|
def getClients(self, streamName):
|
||||||
"""
|
"""
|
||||||
Get all clients in a stream
|
Get all clients in a stream
|
||||||
|
|
||||||
@@ -76,4 +76,4 @@ class streamList:
|
|||||||
"""
|
"""
|
||||||
if streamName not in self.streams:
|
if streamName not in self.streams:
|
||||||
return
|
return
|
||||||
return self.streams[streamName].clients'''
|
return self.streams[streamName].clients
|
@@ -8,44 +8,52 @@ from events import logoutEvent
|
|||||||
from objects import glob
|
from objects import glob
|
||||||
from objects import osuToken
|
from objects import osuToken
|
||||||
|
|
||||||
|
|
||||||
class tokenList:
|
class tokenList:
|
||||||
|
"""
|
||||||
|
List of connected osu tokens
|
||||||
|
|
||||||
|
tokens -- dictionary. key: token string, value: token object
|
||||||
|
"""
|
||||||
|
|
||||||
def __init__(self):
|
def __init__(self):
|
||||||
|
"""
|
||||||
|
Initialize a tokens list
|
||||||
|
"""
|
||||||
self.tokens = {}
|
self.tokens = {}
|
||||||
|
|
||||||
def addToken(self, userID, ip = "", irc = False, timeOffset=0, tournament=False):
|
def addToken(self, userID, ip = "", irc = False, timeOffset=0, tournament=False):
|
||||||
"""
|
"""
|
||||||
Add a token object to tokens list
|
Add a token object to tokens list
|
||||||
|
|
||||||
:param userID: user id associated to that token
|
userID -- user id associated to that token
|
||||||
:param irc: if True, set this token as IRC client
|
irc -- if True, set this token as IRC client
|
||||||
:param timeOffset: the time offset from UTC for this user. Default: 0.
|
return -- token object
|
||||||
:param tournament: if True, flag this client as a tournement client. Default: True.
|
|
||||||
:return: token object
|
|
||||||
"""
|
"""
|
||||||
newToken = osuToken.token(userID, ip=ip, irc=irc, timeOffset=timeOffset, tournament=tournament)
|
newToken = osuToken.token(userID, ip=ip, irc=irc, timeOffset=timeOffset, tournament=tournament)
|
||||||
self.tokens[newToken.token] = newToken
|
self.tokens[newToken.token] = newToken
|
||||||
glob.redis.incr("ripple:online_users")
|
|
||||||
return newToken
|
return newToken
|
||||||
|
|
||||||
def deleteToken(self, token):
|
def deleteToken(self, token):
|
||||||
"""
|
"""
|
||||||
Delete a token from token list if it exists
|
Delete a token from token list if it exists
|
||||||
|
|
||||||
:param token: token string
|
token -- token string
|
||||||
:return:
|
|
||||||
"""
|
"""
|
||||||
if token in self.tokens:
|
if token in self.tokens:
|
||||||
|
# Delete session from DB
|
||||||
if self.tokens[token].ip != "":
|
if self.tokens[token].ip != "":
|
||||||
userUtils.deleteBanchoSessions(self.tokens[token].userID, self.tokens[token].ip)
|
userUtils.deleteBanchoSessions(self.tokens[token].userID, self.tokens[token].ip)
|
||||||
|
|
||||||
|
# Pop token from list
|
||||||
self.tokens.pop(token)
|
self.tokens.pop(token)
|
||||||
glob.redis.decr("ripple:online_users")
|
|
||||||
|
|
||||||
def getUserIDFromToken(self, token):
|
def getUserIDFromToken(self, token):
|
||||||
"""
|
"""
|
||||||
Get user ID from a token
|
Get user ID from a token
|
||||||
|
|
||||||
:param token: token to find
|
token -- token to find
|
||||||
:return: False if not found, userID if found
|
return -- false if not found, userID if found
|
||||||
"""
|
"""
|
||||||
# Make sure the token exists
|
# Make sure the token exists
|
||||||
if token not in self.tokens:
|
if token not in self.tokens:
|
||||||
@@ -58,9 +66,8 @@ class tokenList:
|
|||||||
"""
|
"""
|
||||||
Get token from a user ID
|
Get token from a user ID
|
||||||
|
|
||||||
:param userID: user ID to find
|
userID -- user ID to find
|
||||||
:param ignoreIRC: if True, consider bancho clients only and skip IRC clients
|
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
|
||||||
for _, value in self.tokens.items():
|
for _, value in self.tokens.items():
|
||||||
@@ -72,22 +79,19 @@ class tokenList:
|
|||||||
# Return none if not found
|
# Return none if not found
|
||||||
return None
|
return None
|
||||||
|
|
||||||
def getTokenFromUsername(self, username, ignoreIRC=False, safe=False):
|
def getTokenFromUsername(self, username, ignoreIRC=False):
|
||||||
"""
|
"""
|
||||||
Get an osuToken object from an username
|
Get token from a username
|
||||||
|
|
||||||
:param username: normal username or safe username
|
username -- username to find
|
||||||
:param ignoreIRC: if True, consider bancho clients only and skip IRC clients
|
return -- False if not found, token object if found
|
||||||
:param safe: if True, username is a safe username,
|
|
||||||
compare it with token's safe username rather than normal username
|
|
||||||
:return: osuToken object or None
|
|
||||||
"""
|
"""
|
||||||
# lowercase
|
# lowercase
|
||||||
who = username.lower() if not safe else username
|
who = username.lower()
|
||||||
|
|
||||||
# Make sure the token exists
|
# Make sure the token exists
|
||||||
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 value.username.lower() == who:
|
||||||
if ignoreIRC and value.irc:
|
if ignoreIRC and value.irc:
|
||||||
continue
|
continue
|
||||||
return value
|
return value
|
||||||
@@ -99,28 +103,22 @@ class tokenList:
|
|||||||
"""
|
"""
|
||||||
Delete old userID's tokens if found
|
Delete old userID's tokens if found
|
||||||
|
|
||||||
:param userID: tokens associated to this user will be deleted
|
userID -- tokens associated to this user will be deleted
|
||||||
:return:
|
|
||||||
"""
|
"""
|
||||||
|
|
||||||
# Delete older tokens
|
# Delete older tokens
|
||||||
delete = []
|
|
||||||
for key, value in list(self.tokens.items()):
|
for key, value in list(self.tokens.items()):
|
||||||
if value.userID == userID:
|
if value.userID == userID:
|
||||||
# Delete this token from the dictionary
|
# 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):
|
def multipleEnqueue(self, packet, who, but = False):
|
||||||
"""
|
"""
|
||||||
Enqueue a packet to multiple users
|
Enqueue a packet to multiple users
|
||||||
|
|
||||||
:param packet: packet bytes to enqueue
|
packet -- packet bytes to enqueue
|
||||||
:param who: userIDs array
|
who -- userIDs array
|
||||||
:param but: if True, enqueue to everyone but users in `who` array
|
but -- if True, enqueue to everyone but users in who array
|
||||||
:return:
|
|
||||||
"""
|
"""
|
||||||
for _, value in self.tokens.items():
|
for _, value in self.tokens.items():
|
||||||
shouldEnqueue = False
|
shouldEnqueue = False
|
||||||
@@ -136,21 +134,19 @@ class tokenList:
|
|||||||
"""
|
"""
|
||||||
Enqueue packet(s) to every connected user
|
Enqueue packet(s) to every connected user
|
||||||
|
|
||||||
:param packet: packet bytes to enqueue
|
packet -- packet bytes to enqueue
|
||||||
:return:
|
|
||||||
"""
|
"""
|
||||||
for _, value in self.tokens.items():
|
for _, value in self.tokens.items():
|
||||||
value.enqueue(packet)
|
value.enqueue(packet)
|
||||||
|
|
||||||
def usersTimeoutCheckLoop(self, timeoutTime = 100, checkTime = 100):
|
def usersTimeoutCheckLoop(self, timeoutTime = 100, checkTime = 100):
|
||||||
"""
|
"""
|
||||||
Start timed out users disconnect loop.
|
Deletes all timed out users.
|
||||||
This function will be called every `checkTime` seconds and so on, forever.
|
If called once, will recall after checkTime seconds and so on, forever
|
||||||
CALL THIS FUNCTION ONLY ONCE!
|
CALL THIS FUNCTION ONLY ONCE!
|
||||||
|
|
||||||
:param timeoutTime: seconds of inactivity required to disconnect someone. Default: 100
|
timeoutTime - seconds of inactivity required to disconnect someone (Default: 100)
|
||||||
:param checkTime: seconds between loops. Default: 100
|
checkTime - seconds between loops (Default: 100)
|
||||||
:return:
|
|
||||||
"""
|
"""
|
||||||
log.debug("Checking timed out clients")
|
log.debug("Checking timed out clients")
|
||||||
timedOutTokens = [] # timed out users
|
timedOutTokens = [] # timed out users
|
||||||
@@ -174,11 +170,8 @@ class tokenList:
|
|||||||
|
|
||||||
def spamProtectionResetLoop(self):
|
def spamProtectionResetLoop(self):
|
||||||
"""
|
"""
|
||||||
Start spam protection reset loop.
|
Reset spam rate every 10 seconds.
|
||||||
Called every 10 seconds.
|
|
||||||
CALL THIS FUNCTION ONLY ONCE!
|
CALL THIS FUNCTION ONLY ONCE!
|
||||||
|
|
||||||
:return:
|
|
||||||
"""
|
"""
|
||||||
# Reset spamRate for every token
|
# Reset spamRate for every token
|
||||||
for _, value in self.tokens.items():
|
for _, value in self.tokens.items():
|
||||||
@@ -189,28 +182,22 @@ class tokenList:
|
|||||||
|
|
||||||
def deleteBanchoSessions(self):
|
def deleteBanchoSessions(self):
|
||||||
"""
|
"""
|
||||||
Remove all `peppy:sessions:*` redis keys.
|
Truncate bancho_sessions table.
|
||||||
Call at bancho startup to delete old cached sessions
|
Call at bancho startup to delete old cached sessions
|
||||||
|
|
||||||
:return:
|
|
||||||
"""
|
"""
|
||||||
try:
|
glob.db.execute("TRUNCATE TABLE bancho_sessions")
|
||||||
# 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):
|
def tokenExists(self, username = "", userID = -1):
|
||||||
"""
|
"""
|
||||||
Check if a token exists
|
Check if a token exists (aka check if someone is connected)
|
||||||
Use username or userid, not both at the same time.
|
|
||||||
|
|
||||||
:param username: Optional.
|
username -- Optional.
|
||||||
:param userID: Optional.
|
userID -- Optional.
|
||||||
:return: True if it exists, otherwise False
|
return -- True if it exists, otherwise False
|
||||||
|
|
||||||
|
Use username or userid, not both at the same time.
|
||||||
"""
|
"""
|
||||||
if userID > -1:
|
if userID > -1:
|
||||||
return True if self.getTokenFromUserID(userID) is not None else False
|
return True if self.getTokenFromUserID(userID) is not None else False
|
||||||
else:
|
else:
|
||||||
return True if self.getTokenFromUsername(username) is not None else False
|
return True if self.getTokenFromUsername(username) is not None else False
|
||||||
|
68
pep.py
68
pep.py
@@ -9,14 +9,13 @@ import tornado.httpserver
|
|||||||
import tornado.ioloop
|
import tornado.ioloop
|
||||||
import tornado.web
|
import tornado.web
|
||||||
from raven.contrib.tornado import AsyncSentryClient
|
from raven.contrib.tornado import AsyncSentryClient
|
||||||
import redis
|
|
||||||
|
|
||||||
from common import generalUtils
|
from common import generalUtils
|
||||||
from common.constants import bcolors
|
from common.constants import bcolors
|
||||||
from common.db import dbConnector
|
from common.db import dbConnector
|
||||||
from common.ddog import datadogClient
|
from common.ddog import datadogClient
|
||||||
from common.log import logUtils as log
|
from common.log import logUtils as log
|
||||||
from common.redis import pubSub
|
from common.ripple import userUtils
|
||||||
from common.web import schiavo
|
from common.web import schiavo
|
||||||
from handlers import apiFokabotMessageHandler
|
from handlers import apiFokabotMessageHandler
|
||||||
from handlers import apiIsOnlineHandler
|
from handlers import apiIsOnlineHandler
|
||||||
@@ -34,12 +33,6 @@ from objects import banchoConfig
|
|||||||
from objects import chatFilters
|
from objects import chatFilters
|
||||||
from objects import fokabot
|
from objects import fokabot
|
||||||
from objects import glob
|
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():
|
def make_app():
|
||||||
@@ -89,7 +82,7 @@ if __name__ == "__main__":
|
|||||||
|
|
||||||
# Connect to db
|
# Connect to db
|
||||||
try:
|
try:
|
||||||
consoleHelper.printNoNl("> Connecting to MySQL database... ")
|
consoleHelper.printNoNl("> Connecting to MySQL database...")
|
||||||
glob.db = dbConnector.db(glob.conf.config["db"]["host"], glob.conf.config["db"]["username"], glob.conf.config["db"]["password"], glob.conf.config["db"]["database"], int(glob.conf.config["db"]["workers"]))
|
glob.db = dbConnector.db(glob.conf.config["db"]["host"], glob.conf.config["db"]["username"], glob.conf.config["db"]["password"], glob.conf.config["db"]["database"], int(glob.conf.config["db"]["workers"]))
|
||||||
consoleHelper.printNoNl(" ")
|
consoleHelper.printNoNl(" ")
|
||||||
consoleHelper.printDone()
|
consoleHelper.printDone()
|
||||||
@@ -99,31 +92,6 @@ if __name__ == "__main__":
|
|||||||
consoleHelper.printColored("[!] Error while connection to database. Please check your config.ini and run the server again", bcolors.RED)
|
consoleHelper.printColored("[!] Error while connection to database. Please check your config.ini and run the server again", bcolors.RED)
|
||||||
raise
|
raise
|
||||||
|
|
||||||
# Connect to redis
|
|
||||||
try:
|
|
||||||
consoleHelper.printNoNl("> Connecting to redis... ")
|
|
||||||
glob.redis = redis.Redis(glob.conf.config["redis"]["host"], glob.conf.config["redis"]["port"], glob.conf.config["redis"]["database"], glob.conf.config["redis"]["password"])
|
|
||||||
glob.redis.ping()
|
|
||||||
consoleHelper.printNoNl(" ")
|
|
||||||
consoleHelper.printDone()
|
|
||||||
except:
|
|
||||||
# Exception while connecting to db
|
|
||||||
consoleHelper.printError()
|
|
||||||
consoleHelper.printColored("[!] Error while connection to redis. Please check your config.ini and run the server again", bcolors.RED)
|
|
||||||
raise
|
|
||||||
|
|
||||||
# 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:*
|
|
||||||
pass
|
|
||||||
|
|
||||||
# Save peppy version in redis
|
|
||||||
glob.redis.set("peppy:version", glob.VERSION)
|
|
||||||
|
|
||||||
# Load bancho_settings
|
# Load bancho_settings
|
||||||
try:
|
try:
|
||||||
consoleHelper.printNoNl("> Loading bancho settings from DB... ")
|
consoleHelper.printNoNl("> Loading bancho settings from DB... ")
|
||||||
@@ -166,6 +134,7 @@ if __name__ == "__main__":
|
|||||||
consoleHelper.printNoNl("> Creating packets streams... ")
|
consoleHelper.printNoNl("> Creating packets streams... ")
|
||||||
glob.streams.add("main")
|
glob.streams.add("main")
|
||||||
glob.streams.add("lobby")
|
glob.streams.add("lobby")
|
||||||
|
glob.streams.add("zingheri")
|
||||||
consoleHelper.printDone()
|
consoleHelper.printDone()
|
||||||
|
|
||||||
# Start fokabot
|
# Start fokabot
|
||||||
@@ -183,6 +152,16 @@ if __name__ == "__main__":
|
|||||||
glob.tokens.spamProtectionResetLoop()
|
glob.tokens.spamProtectionResetLoop()
|
||||||
consoleHelper.printDone()
|
consoleHelper.printDone()
|
||||||
|
|
||||||
|
# Initialize zingheri loop
|
||||||
|
consoleHelper.printNoNl("> WOO WOO... ")
|
||||||
|
fokabot.zingheriLoop()
|
||||||
|
consoleHelper.printDone()
|
||||||
|
|
||||||
|
# Cache user ids
|
||||||
|
consoleHelper.printNoNl("> Caching user IDs... ")
|
||||||
|
userUtils.cacheUserIDs()
|
||||||
|
consoleHelper.printDone()
|
||||||
|
|
||||||
# Localize warning
|
# Localize warning
|
||||||
glob.localize = generalUtils.stringToBool(glob.conf.config["localize"]["enable"])
|
glob.localize = generalUtils.stringToBool(glob.conf.config["localize"]["enable"])
|
||||||
if not glob.localize:
|
if not glob.localize:
|
||||||
@@ -229,17 +208,6 @@ if __name__ == "__main__":
|
|||||||
[
|
[
|
||||||
datadogClient.periodicCheck("online_users", lambda: len(glob.tokens.tokens)),
|
datadogClient.periodicCheck("online_users", lambda: len(glob.tokens.tokens)),
|
||||||
datadogClient.periodicCheck("multiplayer_matches", lambda: len(glob.matches.matches)),
|
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_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:
|
else:
|
||||||
consoleHelper.printColored("[!] Warning! Datadog stats tracking is disabled!", bcolors.YELLOW)
|
consoleHelper.printColored("[!] Warning! Datadog stats tracking is disabled!", bcolors.YELLOW)
|
||||||
@@ -270,16 +238,6 @@ if __name__ == "__main__":
|
|||||||
log.logMessage("**pep.py** Server started!", discord="bunker", of="info.txt", stdout=False)
|
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)
|
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
|
# Start tornado
|
||||||
glob.application.listen(serverPort)
|
glob.application.listen(serverPort)
|
||||||
tornado.ioloop.IOLoop.instance().start()
|
tornado.ioloop.IOLoop.instance().start()
|
||||||
|
@@ -1,18 +0,0 @@
|
|||||||
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()
|
|
@@ -1,49 +0,0 @@
|
|||||||
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"])
|
|
@@ -1,18 +0,0 @@
|
|||||||
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")
|
|
@@ -1,15 +0,0 @@
|
|||||||
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()
|
|
@@ -1,15 +0,0 @@
|
|||||||
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()
|
|
@@ -3,7 +3,4 @@ tornado
|
|||||||
mysqlclient
|
mysqlclient
|
||||||
psutil
|
psutil
|
||||||
raven
|
raven
|
||||||
bcrypt>=3.1.1
|
bcrypt
|
||||||
dill
|
|
||||||
redis
|
|
||||||
cython
|
|
17
setup.py
17
setup.py
@@ -1,17 +0,0 @@
|
|||||||
"""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