Compare commits
82 Commits
tornado-ge
...
tourney-fi
Author | SHA1 | Date | |
---|---|---|---|
|
a48aa73a0b | ||
|
90dfb2c705 | ||
|
e7b7dc932a | ||
|
4ed5e0d14a | ||
|
0750ead5db | ||
|
74f3ec0f4c | ||
|
fdec8620fb | ||
|
8ff493f706 | ||
|
2d26d36fbf | ||
|
7c54df6586 | ||
|
2eb7fb609c | ||
|
b1399aaf6e | ||
|
26dbdd72c1 | ||
|
99d14b46e8 | ||
|
927621cfcd | ||
|
847a955e2f | ||
|
99f76e3227 | ||
|
ea83d3c86d | ||
|
10e182ce55 | ||
|
ca34583e7b | ||
|
7a7d64c209 | ||
|
569230c16a | ||
|
f155b0567c | ||
|
05f09ad35b | ||
|
ead44270af | ||
|
820df034f4 | ||
|
7347b1d455 | ||
|
4babcd2643 | ||
|
142c3d35cb | ||
|
996287f871 | ||
|
795b6f09be | ||
|
afbd8e7e8c | ||
|
cd3054c83c | ||
|
7fcc9bca5e | ||
|
8173ff3bb6 | ||
|
60e629a4fe | ||
|
88c80a4080 | ||
|
40264ceffe | ||
|
2213a99147 | ||
|
121d19aaa7 | ||
|
4b6e621a70 | ||
|
712aecb602 | ||
|
5bde0164fb | ||
|
f912f6ea82 | ||
|
6020f7cc47 | ||
|
47ce794bfc | ||
|
89af599e1a | ||
|
784973b298 | ||
|
8e4c44b857 | ||
|
ba774bf567 | ||
|
ea7cd9ff30 | ||
|
14348a68bb | ||
|
fd9cde1ec6 | ||
|
48925c58c0 | ||
|
17a8636de7 | ||
|
f5a34d9048 | ||
|
6aa7eb6b69 | ||
|
19c4c32c7b | ||
|
7fc6d4c540 | ||
|
255a0958ff | ||
|
31a78432bb | ||
|
d5c87ba51c | ||
|
2d91231320 | ||
|
9ee2e5d7ff | ||
|
cf60c167b6 | ||
|
3703618112 | ||
|
653303831b | ||
|
e16e4d7493 | ||
|
a1d45a4419 | ||
|
1ac48c51b5 | ||
|
27ac94a736 | ||
|
771b6e294b | ||
|
bd395ef30b | ||
|
78dbd7e1f5 | ||
|
649c400883 | ||
|
65b55fdcf1 | ||
|
de47c46d25 | ||
|
1a31042619 | ||
|
7c906e48c5 | ||
|
2f8f8e1beb | ||
|
8f79e58185 | ||
|
7910291b77 |
4
.gitignore
vendored
4
.gitignore
vendored
@@ -2,3 +2,7 @@
|
|||||||
config.ini
|
config.ini
|
||||||
filters.txt
|
filters.txt
|
||||||
.data
|
.data
|
||||||
|
.idea
|
||||||
|
common_funzia
|
||||||
|
common_refractor
|
||||||
|
common_memato
|
||||||
|
3
.gitmodules
vendored
Normal file
3
.gitmodules
vendored
Normal file
@@ -0,0 +1,3 @@
|
|||||||
|
[submodule "common"]
|
||||||
|
path = common
|
||||||
|
url = git@git.zxq.co:ripple/ripple-python-common.git
|
12
README.md
12
README.md
@@ -9,15 +9,19 @@ This is Ripple's bancho server. It handles:
|
|||||||
|
|
||||||
## Requirements
|
## Requirements
|
||||||
- Python 3.5
|
- Python 3.5
|
||||||
- MySQLdb (`mysqlclient` or `mysql-python`)
|
- MySQLdb (`mysqlclient`)
|
||||||
- Tornado
|
- Tornado
|
||||||
- Gevent
|
|
||||||
- Bcrypt
|
- Bcrypt
|
||||||
|
- Raven
|
||||||
|
|
||||||
## How to set up pep.py
|
## How to set up pep.py
|
||||||
First of all, install all the dependencies
|
First of all, initialize and update the submodules
|
||||||
```
|
```
|
||||||
$ pip install mysqlclient tornado gevent bcrypt
|
$ git submodule init && git submodule update
|
||||||
|
```
|
||||||
|
afterwards, install the required dependencies with pip
|
||||||
|
```
|
||||||
|
$ pip install -r requirements.txt
|
||||||
```
|
```
|
||||||
then, run pep.py once to create the default config file and edit it
|
then, run pep.py once to create the default config file and edit it
|
||||||
```
|
```
|
||||||
|
1
common
Submodule
1
common
Submodule
Submodule common added at a899c0be89
@@ -1,17 +0,0 @@
|
|||||||
"""Contains user actions"""
|
|
||||||
#TODO: Uppercase
|
|
||||||
idle = 0
|
|
||||||
afk = 1
|
|
||||||
playing = 2
|
|
||||||
editing = 3
|
|
||||||
modding = 4
|
|
||||||
multiplayer = 5
|
|
||||||
watching = 6
|
|
||||||
unknown = 7
|
|
||||||
testing = 8
|
|
||||||
submitting = 9
|
|
||||||
paused = 10
|
|
||||||
lobby = 11
|
|
||||||
multiplaying= 12
|
|
||||||
osuDirect = 13
|
|
||||||
none = 14
|
|
@@ -1,9 +0,0 @@
|
|||||||
"""Console colors"""
|
|
||||||
PINK = '\033[95m'
|
|
||||||
BLUE = '\033[94m'
|
|
||||||
GREEN = '\033[92m'
|
|
||||||
YELLOW = '\033[93m'
|
|
||||||
RED = '\033[91m'
|
|
||||||
ENDC = '\033[0m'
|
|
||||||
BOLD = '\033[1m'
|
|
||||||
UNDERLINE = '\033[4m'
|
|
@@ -8,86 +8,86 @@ from constants import slotStatuses
|
|||||||
def userActionChange(stream):
|
def userActionChange(stream):
|
||||||
return packetHelper.readPacketData(stream,
|
return packetHelper.readPacketData(stream,
|
||||||
[
|
[
|
||||||
["actionID", dataTypes.byte],
|
["actionID", dataTypes.BYTE],
|
||||||
["actionText", dataTypes.string],
|
["actionText", dataTypes.STRING],
|
||||||
["actionMd5", dataTypes.string],
|
["actionMd5", dataTypes.STRING],
|
||||||
["actionMods", dataTypes.uInt32],
|
["actionMods", dataTypes.UINT32],
|
||||||
["gameMode", dataTypes.byte]
|
["gameMode", dataTypes.BYTE],
|
||||||
|
["beatmapID", dataTypes.SINT32]
|
||||||
])
|
])
|
||||||
|
|
||||||
def userStatsRequest(stream):
|
def userStatsRequest(stream):
|
||||||
return packetHelper.readPacketData(stream, [["users", dataTypes.intList]])
|
return packetHelper.readPacketData(stream, [["users", dataTypes.INT_LIST]])
|
||||||
|
|
||||||
def userPanelRequest(stream):
|
def userPanelRequest(stream):
|
||||||
return packetHelper.readPacketData(stream, [["users", dataTypes.intList]])
|
return packetHelper.readPacketData(stream, [["users", dataTypes.INT_LIST]])
|
||||||
|
|
||||||
|
|
||||||
""" Client chat packets """
|
""" Client chat packets """
|
||||||
def sendPublicMessage(stream):
|
def sendPublicMessage(stream):
|
||||||
return packetHelper.readPacketData(stream,
|
return packetHelper.readPacketData(stream,
|
||||||
[
|
[
|
||||||
["unknown", dataTypes.string],
|
["unknown", dataTypes.STRING],
|
||||||
["message", dataTypes.string],
|
["message", dataTypes.STRING],
|
||||||
["to", dataTypes.string]
|
["to", dataTypes.STRING]
|
||||||
])
|
])
|
||||||
|
|
||||||
def sendPrivateMessage(stream):
|
def sendPrivateMessage(stream):
|
||||||
return packetHelper.readPacketData(stream,
|
return packetHelper.readPacketData(stream,
|
||||||
[
|
[
|
||||||
["unknown", dataTypes.string],
|
["unknown", dataTypes.STRING],
|
||||||
["message", dataTypes.string],
|
["message", dataTypes.STRING],
|
||||||
["to", dataTypes.string],
|
["to", dataTypes.STRING],
|
||||||
["unknown2", dataTypes.uInt32]
|
["unknown2", dataTypes.UINT32]
|
||||||
])
|
])
|
||||||
|
|
||||||
def setAwayMessage(stream):
|
def setAwayMessage(stream):
|
||||||
return packetHelper.readPacketData(stream,
|
return packetHelper.readPacketData(stream,
|
||||||
[
|
[
|
||||||
["unknown", dataTypes.string],
|
["unknown", dataTypes.STRING],
|
||||||
["awayMessage", dataTypes.string]
|
["awayMessage", dataTypes.STRING]
|
||||||
])
|
])
|
||||||
|
|
||||||
def channelJoin(stream):
|
def channelJoin(stream):
|
||||||
return packetHelper.readPacketData(stream,[["channel", dataTypes.string]])
|
return packetHelper.readPacketData(stream, [["channel", dataTypes.STRING]])
|
||||||
|
|
||||||
def channelPart(stream):
|
def channelPart(stream):
|
||||||
return packetHelper.readPacketData(stream,[["channel", dataTypes.string]])
|
return packetHelper.readPacketData(stream, [["channel", dataTypes.STRING]])
|
||||||
|
|
||||||
def addRemoveFriend(stream):
|
def addRemoveFriend(stream):
|
||||||
return packetHelper.readPacketData(stream, [["friendID", dataTypes.sInt32]])
|
return packetHelper.readPacketData(stream, [["friendID", dataTypes.SINT32]])
|
||||||
|
|
||||||
|
|
||||||
|
""" Spectator packets """
|
||||||
""" SPECTATOR PACKETS """
|
|
||||||
def startSpectating(stream):
|
def startSpectating(stream):
|
||||||
return packetHelper.readPacketData(stream,[["userID", dataTypes.sInt32]])
|
return packetHelper.readPacketData(stream, [["userID", dataTypes.SINT32]])
|
||||||
|
|
||||||
|
|
||||||
""" MULTIPLAYER PACKETS """
|
""" Multiplayer packets """
|
||||||
def matchSettings(stream):
|
def matchSettings(stream):
|
||||||
# Data to return, will be merged later
|
# Data to return, will be merged later
|
||||||
data = []
|
data = []
|
||||||
|
|
||||||
# Some settings
|
# Some settings
|
||||||
struct = [
|
struct = [
|
||||||
["matchID", dataTypes.uInt16],
|
["matchID", dataTypes.UINT16],
|
||||||
["inProgress", dataTypes.byte],
|
["inProgress", dataTypes.BYTE],
|
||||||
["unknown", dataTypes.byte],
|
["unknown", dataTypes.BYTE],
|
||||||
["mods", dataTypes.uInt32],
|
["mods", dataTypes.UINT32],
|
||||||
["matchName", dataTypes.string],
|
["matchName", dataTypes.STRING],
|
||||||
["matchPassword", dataTypes.string],
|
["matchPassword", dataTypes.STRING],
|
||||||
["beatmapName", dataTypes.string],
|
["beatmapName", dataTypes.STRING],
|
||||||
["beatmapID", dataTypes.uInt32],
|
["beatmapID", dataTypes.UINT32],
|
||||||
["beatmapMD5", dataTypes.string]
|
["beatmapMD5", dataTypes.STRING]
|
||||||
]
|
]
|
||||||
|
|
||||||
# Slot statuses (not used)
|
# Slot statuses (not used)
|
||||||
for i in range(0,16):
|
for i in range(0,16):
|
||||||
struct.append(["slot{}Status".format(str(i)), dataTypes.byte])
|
struct.append(["slot{}Status".format(str(i)), dataTypes.BYTE])
|
||||||
|
|
||||||
# Slot statuses (not used)
|
# Slot statuses (not used)
|
||||||
for i in range(0,16):
|
for i in range(0,16):
|
||||||
struct.append(["slot{}Team".format(str(i)), dataTypes.byte])
|
struct.append(["slot{}Team".format(str(i)), dataTypes.BYTE])
|
||||||
|
|
||||||
# Read first part
|
# Read first part
|
||||||
data.append(packetHelper.readPacketData(stream, struct))
|
data.append(packetHelper.readPacketData(stream, struct))
|
||||||
@@ -105,19 +105,16 @@ def matchSettings(stream):
|
|||||||
|
|
||||||
# Other settings
|
# Other settings
|
||||||
struct = [
|
struct = [
|
||||||
["hostUserID", dataTypes.sInt32],
|
["hostUserID", dataTypes.SINT32],
|
||||||
["gameMode", dataTypes.byte],
|
["gameMode", dataTypes.BYTE],
|
||||||
["scoringType", dataTypes.byte],
|
["scoringType", dataTypes.BYTE],
|
||||||
["teamType", dataTypes.byte],
|
["teamType", dataTypes.BYTE],
|
||||||
["freeMods", dataTypes.byte],
|
["freeMods", dataTypes.BYTE],
|
||||||
]
|
]
|
||||||
|
|
||||||
# Read last part
|
# Read last part
|
||||||
data.append(packetHelper.readPacketData(stream[start:], struct, False))
|
data.append(packetHelper.readPacketData(stream[start:], struct, False))
|
||||||
|
|
||||||
# Mods if freemod (not used)
|
|
||||||
#if data[1]["freeMods"] == 1:
|
|
||||||
|
|
||||||
result = {}
|
result = {}
|
||||||
for i in data:
|
for i in data:
|
||||||
result.update(i)
|
result.update(i)
|
||||||
@@ -130,19 +127,28 @@ def changeMatchSettings(stream):
|
|||||||
return matchSettings(stream)
|
return matchSettings(stream)
|
||||||
|
|
||||||
def changeSlot(stream):
|
def changeSlot(stream):
|
||||||
return packetHelper.readPacketData(stream, [["slotID", dataTypes.uInt32]])
|
return packetHelper.readPacketData(stream, [["slotID", dataTypes.UINT32]])
|
||||||
|
|
||||||
def joinMatch(stream):
|
def joinMatch(stream):
|
||||||
return packetHelper.readPacketData(stream, [["matchID", dataTypes.uInt32], ["password", dataTypes.string]])
|
return packetHelper.readPacketData(stream, [["matchID", dataTypes.UINT32], ["password", dataTypes.STRING]])
|
||||||
|
|
||||||
def changeMods(stream):
|
def changeMods(stream):
|
||||||
return packetHelper.readPacketData(stream, [["mods", dataTypes.uInt32]])
|
return packetHelper.readPacketData(stream, [["mods", dataTypes.UINT32]])
|
||||||
|
|
||||||
def lockSlot(stream):
|
def lockSlot(stream):
|
||||||
return packetHelper.readPacketData(stream, [["slotID", dataTypes.uInt32]])
|
return packetHelper.readPacketData(stream, [["slotID", dataTypes.UINT32]])
|
||||||
|
|
||||||
def transferHost(stream):
|
def transferHost(stream):
|
||||||
return packetHelper.readPacketData(stream, [["slotID", dataTypes.uInt32]])
|
return packetHelper.readPacketData(stream, [["slotID", dataTypes.UINT32]])
|
||||||
|
|
||||||
def matchInvite(stream):
|
def matchInvite(stream):
|
||||||
return packetHelper.readPacketData(stream, [["userID", dataTypes.uInt32]])
|
return packetHelper.readPacketData(stream, [["userID", dataTypes.UINT32]])
|
||||||
|
|
||||||
|
def tournamentMatchInfoRequest(stream):
|
||||||
|
return packetHelper.readPacketData(stream, [["matchID", dataTypes.UINT32]])
|
||||||
|
|
||||||
|
def tournamentJoinMatchChannel(stream):
|
||||||
|
return packetHelper.readPacketData(stream, [["matchID", dataTypes.UINT32]])
|
||||||
|
|
||||||
|
def tournamentLeaveMatchChannel(stream):
|
||||||
|
return packetHelper.readPacketData(stream, [["matchID", dataTypes.UINT32]])
|
@@ -1,13 +1,12 @@
|
|||||||
"""Bancho packets data types"""
|
"""Bancho packets data types"""
|
||||||
#TODO: Uppercase, maybe?
|
BYTE = 0
|
||||||
byte = 0
|
UINT16 = 1
|
||||||
uInt16 = 1
|
SINT16 = 2
|
||||||
sInt16 = 2
|
UINT32 = 3
|
||||||
uInt32 = 3
|
SINT32 = 4
|
||||||
sInt32 = 4
|
UINT64 = 5
|
||||||
uInt64 = 5
|
SINT64 = 6
|
||||||
sInt64 = 6
|
STRING = 7
|
||||||
string = 7
|
FFLOAT = 8 # because float is a keyword
|
||||||
ffloat = 8 # because float is a keyword
|
BBYTES = 9
|
||||||
bbytes = 9
|
INT_LIST = 10 # TODO: Maybe there are some packets that still use uInt16 + uInt32 thing somewhere.
|
||||||
intList = 10 # TODO: Maybe there are some packets that still use uInt16 + uInt32 thing somewhere.
|
|
||||||
|
@@ -83,3 +83,12 @@ class haxException(Exception):
|
|||||||
|
|
||||||
class forceUpdateException(Exception):
|
class forceUpdateException(Exception):
|
||||||
pass
|
pass
|
||||||
|
|
||||||
|
class loginLockedException(Exception):
|
||||||
|
pass
|
||||||
|
|
||||||
|
class unknownStreamException(Exception):
|
||||||
|
pass
|
||||||
|
|
||||||
|
class userTournamentException(Exception):
|
||||||
|
pass
|
@@ -1,17 +1,19 @@
|
|||||||
from objects import fokabot
|
|
||||||
import random
|
|
||||||
from objects import glob
|
|
||||||
from constants import serverPackets
|
|
||||||
from constants import exceptions
|
|
||||||
from helpers import userHelper
|
|
||||||
from helpers import systemHelper
|
|
||||||
import requests
|
|
||||||
import json
|
import json
|
||||||
from constants import mods
|
import random
|
||||||
from helpers import generalFunctions
|
|
||||||
from helpers import logHelper as log
|
import requests
|
||||||
from constants import gameModes
|
|
||||||
from constants import privileges
|
from common import generalUtils
|
||||||
|
from common.constants import mods
|
||||||
|
from common.log import logUtils as log
|
||||||
|
from common.ripple import userUtils
|
||||||
|
from constants import exceptions
|
||||||
|
from common.constants import gameModes
|
||||||
|
from common.constants import privileges
|
||||||
|
from constants import serverPackets
|
||||||
|
from helpers import systemHelper
|
||||||
|
from objects import fokabot
|
||||||
|
from objects import glob
|
||||||
|
|
||||||
"""
|
"""
|
||||||
Commands callbacks
|
Commands callbacks
|
||||||
@@ -25,7 +27,12 @@ message -- list containing arguments passed from the message
|
|||||||
. . .
|
. . .
|
||||||
|
|
||||||
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
|
||||||
"""
|
"""
|
||||||
|
def instantRestart(fro, chan, message):
|
||||||
|
glob.streams.broadcast("main", serverPackets.notification("We are restarting Bancho. Be right back!"))
|
||||||
|
systemHelper.scheduleShutdown(0, True, delay=1)
|
||||||
|
return False
|
||||||
|
|
||||||
def faq(fro, chan, message):
|
def faq(fro, chan, message):
|
||||||
if message[0] == "rules":
|
if message[0] == "rules":
|
||||||
@@ -64,14 +71,14 @@ def roll(fro, chan, message):
|
|||||||
# return random.choice(["yes", "no", "maybe"])
|
# return random.choice(["yes", "no", "maybe"])
|
||||||
|
|
||||||
def alert(fro, chan, message):
|
def alert(fro, chan, message):
|
||||||
glob.tokens.enqueueAll(serverPackets.notification(' '.join(message[:])))
|
glob.streams.broadcast("main", serverPackets.notification(' '.join(message[:])))
|
||||||
return False
|
return False
|
||||||
|
|
||||||
def alertUser(fro, chan, message):
|
def alertUser(fro, chan, message):
|
||||||
target = message[0].replace("_", " ")
|
target = message[0].replace("_", " ")
|
||||||
|
|
||||||
targetToken = glob.tokens.getTokenFromUsername(target)
|
targetToken = glob.tokens.getTokenFromUsername(target)
|
||||||
if targetToken != None:
|
if targetToken is not None:
|
||||||
targetToken.enqueue(serverPackets.notification(' '.join(message[1:])))
|
targetToken.enqueue(serverPackets.notification(' '.join(message[1:])))
|
||||||
return False
|
return False
|
||||||
else:
|
else:
|
||||||
@@ -80,7 +87,7 @@ def alertUser(fro, chan, message):
|
|||||||
def moderated(fro, chan, message):
|
def moderated(fro, chan, message):
|
||||||
try:
|
try:
|
||||||
# Make sure we are in a channel and not PM
|
# Make sure we are in a channel and not PM
|
||||||
if chan.startswith("#") == False:
|
if not chan.startswith("#"):
|
||||||
raise exceptions.moderatedPMException
|
raise exceptions.moderatedPMException
|
||||||
|
|
||||||
# Get on/off
|
# Get on/off
|
||||||
@@ -99,7 +106,7 @@ def kickAll(fro, chan, message):
|
|||||||
# Kick everyone but mods/admins
|
# Kick everyone but mods/admins
|
||||||
toKick = []
|
toKick = []
|
||||||
for key, value in glob.tokens.tokens.items():
|
for key, value in glob.tokens.tokens.items():
|
||||||
if value.admin == False:
|
if not value.admin:
|
||||||
toKick.append(key)
|
toKick.append(key)
|
||||||
|
|
||||||
# Loop though users to kick (we can't change dictionary size while iterating)
|
# Loop though users to kick (we can't change dictionary size while iterating)
|
||||||
@@ -115,7 +122,7 @@ def kick(fro, chan, message):
|
|||||||
|
|
||||||
# Get target token and make sure is connected
|
# Get target token and make sure is connected
|
||||||
targetToken = glob.tokens.getTokenFromUsername(target)
|
targetToken = glob.tokens.getTokenFromUsername(target)
|
||||||
if targetToken == None:
|
if targetToken is None:
|
||||||
return "{} is not online".format(target)
|
return "{} is not online".format(target)
|
||||||
|
|
||||||
# Kick user
|
# Kick user
|
||||||
@@ -126,7 +133,7 @@ def kick(fro, chan, message):
|
|||||||
|
|
||||||
def fokabotReconnect(fro, chan, message):
|
def fokabotReconnect(fro, chan, message):
|
||||||
# Check if fokabot is already connected
|
# Check if fokabot is already connected
|
||||||
if glob.tokens.getTokenFromUserID(999) != None:
|
if glob.tokens.getTokenFromUserID(999) is not None:
|
||||||
return "Fokabot is already connected to Bancho"
|
return "Fokabot is already connected to Bancho"
|
||||||
|
|
||||||
# Fokabot is not connected, connect it
|
# Fokabot is not connected, connect it
|
||||||
@@ -142,11 +149,11 @@ def silence(fro, chan, message):
|
|||||||
reason = ' '.join(message[3:])
|
reason = ' '.join(message[3:])
|
||||||
|
|
||||||
# Get target user ID
|
# Get target user ID
|
||||||
targetUserID = userHelper.getID(target)
|
targetUserID = userUtils.getID(target)
|
||||||
userID = userHelper.getID(fro)
|
userID = userUtils.getID(fro)
|
||||||
|
|
||||||
# Make sure the user exists
|
# Make sure the user exists
|
||||||
if targetUserID == False:
|
if not targetUserID:
|
||||||
return "{}: user not found".format(target)
|
return "{}: user not found".format(target)
|
||||||
|
|
||||||
# Calculate silence seconds
|
# Calculate silence seconds
|
||||||
@@ -167,12 +174,12 @@ def silence(fro, chan, message):
|
|||||||
|
|
||||||
# Send silence packet to target if he's connected
|
# Send silence packet to target if he's connected
|
||||||
targetToken = glob.tokens.getTokenFromUsername(target)
|
targetToken = glob.tokens.getTokenFromUsername(target)
|
||||||
if targetToken != None:
|
if targetToken is not None:
|
||||||
# user online, silence both in db and with packet
|
# user online, silence both in db and with packet
|
||||||
targetToken.silence(silenceTime, reason, userID)
|
targetToken.silence(silenceTime, reason, userID)
|
||||||
else:
|
else:
|
||||||
# User offline, silence user only in db
|
# User offline, silence user only in db
|
||||||
userHelper.silence(targetUserID, silenceTime, reason, userID)
|
userUtils.silence(targetUserID, silenceTime, reason, userID)
|
||||||
|
|
||||||
# Log message
|
# Log message
|
||||||
msg = "{} has been silenced for the following reason: {}".format(target, reason)
|
msg = "{} has been silenced for the following reason: {}".format(target, reason)
|
||||||
@@ -185,19 +192,19 @@ def removeSilence(fro, chan, message):
|
|||||||
target = message[0].replace("_", " ")
|
target = message[0].replace("_", " ")
|
||||||
|
|
||||||
# Make sure the user exists
|
# Make sure the user exists
|
||||||
targetUserID = userHelper.getID(target)
|
targetUserID = userUtils.getID(target)
|
||||||
userID = userHelper.getID(fro)
|
userID = userUtils.getID(fro)
|
||||||
if targetUserID == False:
|
if not targetUserID:
|
||||||
return "{}: user not found".format(target)
|
return "{}: user not found".format(target)
|
||||||
|
|
||||||
# Send new silence end packet to user if he's online
|
# Send new silence end packet to user if he's online
|
||||||
targetToken = glob.tokens.getTokenFromUsername(target)
|
targetToken = glob.tokens.getTokenFromUsername(target)
|
||||||
if targetToken != None:
|
if targetToken is not None:
|
||||||
# User online, remove silence both in db and with packet
|
# User online, remove silence both in db and with packet
|
||||||
targetToken.silence(0, "", userID)
|
targetToken.silence(0, "", userID)
|
||||||
else:
|
else:
|
||||||
# user offline, remove islene ofnlt from db
|
# user offline, remove islene ofnlt from db
|
||||||
userHelper.silence(targetUserID, 0, "", userID)
|
userUtils.silence(targetUserID, 0, "", userID)
|
||||||
|
|
||||||
return "{}'s silence reset".format(target)
|
return "{}'s silence reset".format(target)
|
||||||
|
|
||||||
@@ -208,17 +215,17 @@ def ban(fro, chan, message):
|
|||||||
target = message[0].replace("_", " ")
|
target = message[0].replace("_", " ")
|
||||||
|
|
||||||
# Make sure the user exists
|
# Make sure the user exists
|
||||||
targetUserID = userHelper.getID(target)
|
targetUserID = userUtils.getID(target)
|
||||||
userID = userHelper.getID(fro)
|
userID = userUtils.getID(fro)
|
||||||
if targetUserID == False:
|
if not targetUserID:
|
||||||
return "{}: user not found".format(target)
|
return "{}: user not found".format(target)
|
||||||
|
|
||||||
# Set allowed to 0
|
# Set allowed to 0
|
||||||
userHelper.ban(targetUserID)
|
userUtils.ban(targetUserID)
|
||||||
|
|
||||||
# Send ban packet to the user if he's online
|
# Send ban packet to the user if he's online
|
||||||
targetToken = glob.tokens.getTokenFromUsername(target)
|
targetToken = glob.tokens.getTokenFromUsername(target)
|
||||||
if targetToken != None:
|
if targetToken is not None:
|
||||||
targetToken.enqueue(serverPackets.loginBanned())
|
targetToken.enqueue(serverPackets.loginBanned())
|
||||||
|
|
||||||
log.rap(userID, "has banned {}".format(target), True)
|
log.rap(userID, "has banned {}".format(target), True)
|
||||||
@@ -231,13 +238,13 @@ def unban(fro, chan, message):
|
|||||||
target = message[0].replace("_", " ")
|
target = message[0].replace("_", " ")
|
||||||
|
|
||||||
# Make sure the user exists
|
# Make sure the user exists
|
||||||
targetUserID = userHelper.getID(target)
|
targetUserID = userUtils.getID(target)
|
||||||
userID = userHelper.getID(fro)
|
userID = userUtils.getID(fro)
|
||||||
if targetUserID == False:
|
if not targetUserID:
|
||||||
return "{}: user not found".format(target)
|
return "{}: user not found".format(target)
|
||||||
|
|
||||||
# Set allowed to 1
|
# Set allowed to 1
|
||||||
userHelper.unban(targetUserID)
|
userUtils.unban(targetUserID)
|
||||||
|
|
||||||
log.rap(userID, "has unbanned {}".format(target), True)
|
log.rap(userID, "has unbanned {}".format(target), True)
|
||||||
return "Welcome back {}!".format(target)
|
return "Welcome back {}!".format(target)
|
||||||
@@ -249,17 +256,17 @@ def restrict(fro, chan, message):
|
|||||||
target = message[0].replace("_", " ")
|
target = message[0].replace("_", " ")
|
||||||
|
|
||||||
# Make sure the user exists
|
# Make sure the user exists
|
||||||
targetUserID = userHelper.getID(target)
|
targetUserID = userUtils.getID(target)
|
||||||
userID = userHelper.getID(fro)
|
userID = userUtils.getID(fro)
|
||||||
if targetUserID == False:
|
if not targetUserID:
|
||||||
return "{}: user not found".format(target)
|
return "{}: user not found".format(target)
|
||||||
|
|
||||||
# Put this user in restricted mode
|
# Put this user in restricted mode
|
||||||
userHelper.restrict(targetUserID)
|
userUtils.restrict(targetUserID)
|
||||||
|
|
||||||
# Send restricted mode packet to this user if he's online
|
# Send restricted mode packet to this user if he's online
|
||||||
targetToken = glob.tokens.getTokenFromUsername(target)
|
targetToken = glob.tokens.getTokenFromUsername(target)
|
||||||
if targetToken != None:
|
if targetToken is not None:
|
||||||
targetToken.setRestricted()
|
targetToken.setRestricted()
|
||||||
|
|
||||||
log.rap(userID, "has put {} in restricted mode".format(target), True)
|
log.rap(userID, "has put {} in restricted mode".format(target), True)
|
||||||
@@ -272,13 +279,13 @@ def unrestrict(fro, chan, message):
|
|||||||
target = message[0].replace("_", " ")
|
target = message[0].replace("_", " ")
|
||||||
|
|
||||||
# Make sure the user exists
|
# Make sure the user exists
|
||||||
targetUserID = userHelper.getID(target)
|
targetUserID = userUtils.getID(target)
|
||||||
userID = userHelper.getID(fro)
|
userID = userUtils.getID(fro)
|
||||||
if targetUserID == False:
|
if not targetUserID:
|
||||||
return "{}: user not found".format(target)
|
return "{}: user not found".format(target)
|
||||||
|
|
||||||
# Set allowed to 1
|
# Set allowed to 1
|
||||||
userHelper.unrestrict(targetUserID)
|
userUtils.unrestrict(targetUserID)
|
||||||
|
|
||||||
log.rap(userID, "has removed restricted mode from {}".format(target), True)
|
log.rap(userID, "has removed restricted mode from {}".format(target), True)
|
||||||
return "Welcome back {}!".format(target)
|
return "Welcome back {}!".format(target)
|
||||||
@@ -306,11 +313,11 @@ def systemReload(fro, chan, message):
|
|||||||
glob.chatFilters.loadFilters()
|
glob.chatFilters.loadFilters()
|
||||||
|
|
||||||
# Send new channels and new bottom icon to everyone
|
# Send new channels and new bottom icon to everyone
|
||||||
glob.tokens.enqueueAll(serverPackets.mainMenuIcon(glob.banchoConf.config["menuIcon"]))
|
glob.streams.broadcast("main", serverPackets.mainMenuIcon(glob.banchoConf.config["menuIcon"]))
|
||||||
glob.tokens.enqueueAll(serverPackets.channelInfoEnd())
|
glob.streams.broadcast("main", serverPackets.channelInfoEnd())
|
||||||
for key, value in glob.channels.channels.items():
|
for key, value in glob.channels.channels.items():
|
||||||
if value.publicRead == True and value.hidden == False:
|
if value.publicRead == True and value.hidden == False:
|
||||||
glob.tokens.enqueueAll(serverPackets.channelInfo(key))
|
glob.streams.broadcast("main", serverPackets.channelInfo(key))
|
||||||
|
|
||||||
return "Bancho settings reloaded!"
|
return "Bancho settings reloaded!"
|
||||||
|
|
||||||
@@ -326,17 +333,17 @@ def systemMaintenance(fro, chan, message):
|
|||||||
# Set new maintenance value in bancho_settings table
|
# Set new maintenance value in bancho_settings table
|
||||||
glob.banchoConf.setMaintenance(maintenance)
|
glob.banchoConf.setMaintenance(maintenance)
|
||||||
|
|
||||||
if maintenance == True:
|
if maintenance:
|
||||||
# We have turned on maintenance mode
|
# We have turned on maintenance mode
|
||||||
# Users that will be disconnected
|
# Users that will be disconnected
|
||||||
who = []
|
who = []
|
||||||
|
|
||||||
# Disconnect everyone but mod/admins
|
# Disconnect everyone but mod/admins
|
||||||
for _, value in glob.tokens.tokens.items():
|
for _, value in glob.tokens.tokens.items():
|
||||||
if value.admin == False:
|
if not value.admin:
|
||||||
who.append(value.userID)
|
who.append(value.userID)
|
||||||
|
|
||||||
glob.tokens.enqueueAll(serverPackets.notification("Our bancho server is in maintenance mode. Please try to login again later."))
|
glob.streams.broadcast("main", serverPackets.notification("Our bancho server is in maintenance mode. Please try to login again later."))
|
||||||
glob.tokens.multipleEnqueue(serverPackets.loginError(), who)
|
glob.tokens.multipleEnqueue(serverPackets.loginError(), who)
|
||||||
msg = "The server is now in maintenance mode!"
|
msg = "The server is now in maintenance mode!"
|
||||||
else:
|
else:
|
||||||
@@ -352,17 +359,18 @@ def systemStatus(fro, chan, message):
|
|||||||
data = systemHelper.getSystemInfo()
|
data = systemHelper.getSystemInfo()
|
||||||
|
|
||||||
# Final message
|
# Final message
|
||||||
msg = "pep.py bancho server v{}".format(glob.VERSION)
|
msg = "pep.py bancho server v{}\n".format(glob.VERSION)
|
||||||
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"
|
||||||
msg += "Connected users: {}\n".format(data["connectedUsers"])
|
msg += "Connected users: {}\n".format(data["connectedUsers"])
|
||||||
msg += "Multiplayer matches: {}\n".format(data["matches"])
|
msg += "Multiplayer matches: {}\n".format(data["matches"])
|
||||||
|
msg += "Uptime: {}\n".format(data["uptime"])
|
||||||
msg += "\n"
|
msg += "\n"
|
||||||
msg += "=== SYSTEM STATS ===\n"
|
msg += "=== SYSTEM STATS ===\n"
|
||||||
msg += "CPU: {}%\n".format(data["cpuUsage"])
|
msg += "CPU: {}%\n".format(data["cpuUsage"])
|
||||||
msg += "RAM: {}GB/{}GB\n".format(data["usedMemory"], data["totalMemory"])
|
msg += "RAM: {}GB/{}GB\n".format(data["usedMemory"], data["totalMemory"])
|
||||||
if data["unix"] == True:
|
if data["unix"]:
|
||||||
msg += "Load average: {}/{}/{}\n".format(data["loadAverage"][0], data["loadAverage"][1], data["loadAverage"][2])
|
msg += "Load average: {}/{}/{}\n".format(data["loadAverage"][0], data["loadAverage"][1], data["loadAverage"][2])
|
||||||
|
|
||||||
return msg
|
return msg
|
||||||
@@ -372,11 +380,15 @@ def getPPMessage(userID, just_data = False):
|
|||||||
try:
|
try:
|
||||||
# Get user token
|
# Get user token
|
||||||
token = glob.tokens.getTokenFromUserID(userID)
|
token = glob.tokens.getTokenFromUserID(userID)
|
||||||
if token == None:
|
if token is None:
|
||||||
return False
|
return False
|
||||||
|
|
||||||
|
currentMap = token.tillerino[0]
|
||||||
|
currentMods = token.tillerino[1]
|
||||||
|
currentAcc = token.tillerino[2]
|
||||||
|
|
||||||
# Send request to LETS api
|
# Send request to LETS api
|
||||||
resp = requests.get("http://127.0.0.1:5002/api/v1/pp?b={}&m={}&a={}".format(token.tillerino[0], token.tillerino[1], token.tillerino[2]), timeout=10).text
|
resp = requests.get("http://127.0.0.1:5002/api/v1/pp?b={}&m={}".format(currentMap, currentMods, currentAcc), timeout=10).text
|
||||||
data = json.loads(resp)
|
data = json.loads(resp)
|
||||||
|
|
||||||
# Make sure status is in response data
|
# Make sure status is in response data
|
||||||
@@ -395,16 +407,25 @@ def getPPMessage(userID, just_data = False):
|
|||||||
|
|
||||||
# Return response in chat
|
# Return response in chat
|
||||||
# Song name and mods
|
# Song name and mods
|
||||||
msg = "{song}{plus}{mods} ".format(song=data["song_name"], plus="+" if token.tillerino[1] > 0 else "", mods=generalFunctions.readableMods(token.tillerino[1]))
|
msg = "{song}{plus}{mods} ".format(song=data["song_name"], plus="+" if currentMods > 0 else "", mods=generalUtils.readableMods(currentMods))
|
||||||
|
|
||||||
# PP values
|
# PP values
|
||||||
if token.tillerino[2] == -1:
|
if currentAcc == -1:
|
||||||
msg += "95%: {pp95}pp | 98%: {pp98}pp | 99% {pp99}pp | 100%: {pp100}pp".format(pp100=data["pp"][0], pp99=data["pp"][1], pp98=data["pp"][2], pp95=data["pp"][3])
|
msg += "95%: {pp95}pp | 98%: {pp98}pp | 99% {pp99}pp | 100%: {pp100}pp".format(pp100=data["pp"][0], pp99=data["pp"][1], pp98=data["pp"][2], pp95=data["pp"][3])
|
||||||
else:
|
else:
|
||||||
msg += "{acc:.2f}%: {pp}pp".format(acc=token.tillerino[2], pp=data["pp"][0])
|
msg += "{acc:.2f}%: {pp}pp".format(acc=token.tillerino[2], pp=data["pp"][0])
|
||||||
|
|
||||||
|
originalAR = data["ar"]
|
||||||
|
# calc new AR if HR/EZ is on
|
||||||
|
if (currentMods & mods.EASY) > 0:
|
||||||
|
data["ar"] = max(0, data["ar"] / 2)
|
||||||
|
if (currentMods & mods.HARDROCK) > 0:
|
||||||
|
data["ar"] = min(10, data["ar"] * 1.4)
|
||||||
|
|
||||||
|
arstr = " ({})".format(originalAR) if originalAR != data["ar"] else ""
|
||||||
|
|
||||||
# Beatmap info
|
# Beatmap info
|
||||||
msg += " | {bpm} BPM | AR {ar} | {stars:.2f} stars".format(bpm=data["bpm"], stars=data["stars"], ar=data["ar"])
|
msg += " | {bpm} BPM | AR {ar}{arstr} | {stars:.2f} stars".format(bpm=data["bpm"], stars=data["stars"], ar=data["ar"], arstr=arstr)
|
||||||
|
|
||||||
# Return final message
|
# Return final message
|
||||||
return msg
|
return msg
|
||||||
@@ -414,10 +435,10 @@ def getPPMessage(userID, just_data = False):
|
|||||||
except exceptions.apiException:
|
except exceptions.apiException:
|
||||||
# API error
|
# API error
|
||||||
return "Unknown error in LETS API call. Please tell this to a dev."
|
return "Unknown error in LETS API call. Please tell this to a dev."
|
||||||
except:
|
#except:
|
||||||
# Unknown exception
|
# Unknown exception
|
||||||
# TODO: print exception
|
# TODO: print exception
|
||||||
return False
|
# return False
|
||||||
|
|
||||||
def tillerinoNp(fro, chan, message):
|
def tillerinoNp(fro, chan, message):
|
||||||
try:
|
try:
|
||||||
@@ -425,21 +446,41 @@ def tillerinoNp(fro, chan, message):
|
|||||||
if chan.startswith("#"):
|
if chan.startswith("#"):
|
||||||
return False
|
return False
|
||||||
|
|
||||||
|
playWatch = message[1] == "playing" or message[1] == "watching"
|
||||||
# Get URL from message
|
# Get URL from message
|
||||||
if message[1] == "listening":
|
if message[1] == "listening":
|
||||||
beatmapURL = str(message[3][1:])
|
beatmapURL = str(message[3][1:])
|
||||||
elif message[1] == "playing" or message[1] == "watching":
|
elif playWatch:
|
||||||
beatmapURL = str(message[2][1:])
|
beatmapURL = str(message[2][1:])
|
||||||
else:
|
else:
|
||||||
return False
|
return False
|
||||||
|
|
||||||
|
modsEnum = 0
|
||||||
|
mapping = {
|
||||||
|
"-Easy": mods.EASY,
|
||||||
|
"-NoFail": mods.NOFAIL,
|
||||||
|
"+Hidden": mods.HIDDEN,
|
||||||
|
"+HardRock": mods.HARDROCK,
|
||||||
|
"+Nightcore": mods.NIGHTCORE,
|
||||||
|
"+DoubleTime": mods.DOUBLETIME,
|
||||||
|
"-HalfTime": mods.HALFTIME,
|
||||||
|
"+Flashlight": mods.FLASHLIGHT,
|
||||||
|
"-SpunOut": mods.SPUNOUT
|
||||||
|
}
|
||||||
|
|
||||||
|
if playWatch:
|
||||||
|
for part in message:
|
||||||
|
part = part.replace("\x01", "")
|
||||||
|
if part in mapping.keys():
|
||||||
|
modsEnum += mapping[part]
|
||||||
|
|
||||||
# Get beatmap id from URL
|
# Get beatmap id from URL
|
||||||
beatmapID = fokabot.npRegex.search(beatmapURL).groups(0)[0]
|
beatmapID = fokabot.npRegex.search(beatmapURL).groups(0)[0]
|
||||||
|
|
||||||
# Update latest tillerino song for current token
|
# Update latest tillerino song for current token
|
||||||
token = glob.tokens.getTokenFromUsername(fro)
|
token = glob.tokens.getTokenFromUsername(fro)
|
||||||
if token != None:
|
if token is not None:
|
||||||
token.tillerino = [int(beatmapID), 0, -1.0]
|
token.tillerino = [int(beatmapID), modsEnum, -1.0]
|
||||||
userID = token.userID
|
userID = token.userID
|
||||||
|
|
||||||
# Return tillerino message
|
# Return tillerino message
|
||||||
@@ -456,7 +497,7 @@ def tillerinoMods(fro, chan, message):
|
|||||||
|
|
||||||
# Get token and user ID
|
# Get token and user ID
|
||||||
token = glob.tokens.getTokenFromUsername(fro)
|
token = glob.tokens.getTokenFromUsername(fro)
|
||||||
if token == None:
|
if token is None:
|
||||||
return False
|
return False
|
||||||
userID = token.userID
|
userID = token.userID
|
||||||
|
|
||||||
@@ -474,23 +515,23 @@ def tillerinoMods(fro, chan, message):
|
|||||||
modsEnum = 0
|
modsEnum = 0
|
||||||
break
|
break
|
||||||
elif i == "NF":
|
elif i == "NF":
|
||||||
modsEnum += mods.NoFail
|
modsEnum += mods.NOFAIL
|
||||||
elif i == "EZ":
|
elif i == "EZ":
|
||||||
modsEnum += mods.Easy
|
modsEnum += mods.EASY
|
||||||
elif i == "HD":
|
elif i == "HD":
|
||||||
modsEnum += mods.Hidden
|
modsEnum += mods.HIDDEN
|
||||||
elif i == "HR":
|
elif i == "HR":
|
||||||
modsEnum += mods.HardRock
|
modsEnum += mods.HARDROCK
|
||||||
elif i == "DT":
|
elif i == "DT":
|
||||||
modsEnum += mods.DoubleTime
|
modsEnum += mods.DOUBLETIME
|
||||||
elif i == "HT":
|
elif i == "HT":
|
||||||
modsEnum += mods.HalfTime
|
modsEnum += mods.HALFTIME
|
||||||
elif i == "NC":
|
elif i == "NC":
|
||||||
modsEnum += mods.Nightcore
|
modsEnum += mods.NIGHTCORE
|
||||||
elif i == "FL":
|
elif i == "FL":
|
||||||
modsEnum += mods.Flashlight
|
modsEnum += mods.FLASHLIGHT
|
||||||
elif i == "SO":
|
elif i == "SO":
|
||||||
modsEnum += mods.SpunOut
|
modsEnum += mods.SPUNOUT
|
||||||
|
|
||||||
# Set mods
|
# Set mods
|
||||||
token.tillerino[1] = modsEnum
|
token.tillerino[1] = modsEnum
|
||||||
@@ -508,7 +549,7 @@ def tillerinoAcc(fro, chan, message):
|
|||||||
|
|
||||||
# Get token and user ID
|
# Get token and user ID
|
||||||
token = glob.tokens.getTokenFromUsername(fro)
|
token = glob.tokens.getTokenFromUsername(fro)
|
||||||
if token == None:
|
if token is None:
|
||||||
return False
|
return False
|
||||||
userID = token.userID
|
userID = token.userID
|
||||||
|
|
||||||
@@ -539,26 +580,26 @@ def tillerinoLast(fro, chan, message):
|
|||||||
WHERE users.username = %s
|
WHERE users.username = %s
|
||||||
ORDER BY scores.time DESC
|
ORDER BY scores.time DESC
|
||||||
LIMIT 1""", [fro])
|
LIMIT 1""", [fro])
|
||||||
if data == None:
|
if data is None:
|
||||||
return False
|
return False
|
||||||
|
|
||||||
diffString = "difficulty_{}".format(gameModes.getGameModeForDB(data["play_mode"]))
|
diffString = "difficulty_{}".format(gameModes.getGameModeForDB(data["play_mode"]))
|
||||||
rank = generalFunctions.getRank(data["play_mode"], data["mods"], data["accuracy"],\
|
rank = generalUtils.getRank(data["play_mode"], data["mods"], data["accuracy"],
|
||||||
data["300_count"], data["100_count"], data["50_count"], data["misses_count"])
|
data["300_count"], data["100_count"], data["50_count"], data["misses_count"])
|
||||||
|
|
||||||
ifPlayer = "{0} | ".format(fro) if chan != "FokaBot" else ""
|
ifPlayer = "{0} | ".format(fro) if chan != "FokaBot" else ""
|
||||||
ifFc = " (FC)" if data["max_combo"] == data["fc"] else " {0}x/{1}x".format(data["max_combo"], data["fc"])
|
ifFc = " (FC)" if data["max_combo"] == data["fc"] else " {0}x/{1}x".format(data["max_combo"], data["fc"])
|
||||||
beatmapLink = "[http://osu.ppy.sh/b/{1} {0}]".format(data["sn"], data["bid"])
|
beatmapLink = "[http://osu.ppy.sh/b/{1} {0}]".format(data["sn"], data["bid"])
|
||||||
|
|
||||||
hasPP = data["play_mode"] == gameModes.std or data["play_mode"] == gameModes.mania
|
hasPP = data["play_mode"] == gameModes.STD or data["play_mode"] == gameModes.MANIA
|
||||||
|
|
||||||
msg = ifPlayer
|
msg = ifPlayer
|
||||||
msg += beatmapLink
|
msg += beatmapLink
|
||||||
if data["play_mode"] != gameModes.std:
|
if data["play_mode"] != gameModes.STD:
|
||||||
msg += " <{0}>".format(gameModes.getGameModeForPrinting(data["play_mode"]))
|
msg += " <{0}>".format(gameModes.getGameModeForPrinting(data["play_mode"]))
|
||||||
|
|
||||||
if data["mods"]:
|
if data["mods"]:
|
||||||
msg += ' +' + generalFunctions.readableMods(data["mods"])
|
msg += ' +' + generalUtils.readableMods(data["mods"])
|
||||||
|
|
||||||
if not hasPP:
|
if not hasPP:
|
||||||
msg += " | {0:,}".format(data["score"])
|
msg += " | {0:,}".format(data["score"])
|
||||||
@@ -575,7 +616,7 @@ def tillerinoLast(fro, chan, message):
|
|||||||
stars = data[diffString]
|
stars = data[diffString]
|
||||||
if data["mods"]:
|
if data["mods"]:
|
||||||
token = glob.tokens.getTokenFromUsername(fro)
|
token = glob.tokens.getTokenFromUsername(fro)
|
||||||
if token == None:
|
if token is None:
|
||||||
return False
|
return False
|
||||||
userID = token.userID
|
userID = token.userID
|
||||||
token.tillerino[0] = data["bid"]
|
token.tillerino[0] = data["bid"]
|
||||||
@@ -595,6 +636,69 @@ def mm00(fro, chan, message):
|
|||||||
random.seed()
|
random.seed()
|
||||||
return random.choice(["meme", "MA MAURO ESISTE?"])
|
return random.choice(["meme", "MA MAURO ESISTE?"])
|
||||||
|
|
||||||
|
def pp(fro, chan, message):
|
||||||
|
if chan.startswith("#"):
|
||||||
|
return False
|
||||||
|
|
||||||
|
gameMode = None
|
||||||
|
if len(message) >= 1:
|
||||||
|
gm = {
|
||||||
|
"standard": 0,
|
||||||
|
"std": 0,
|
||||||
|
"taiko": 1,
|
||||||
|
"ctb": 2,
|
||||||
|
"mania": 3
|
||||||
|
}
|
||||||
|
if message[0].lower() not in gm:
|
||||||
|
return "What's that game mode? I've never heard of it :/"
|
||||||
|
else:
|
||||||
|
gameMode = gm[message[0].lower()]
|
||||||
|
|
||||||
|
token = glob.tokens.getTokenFromUsername(fro)
|
||||||
|
if token is None:
|
||||||
|
return False
|
||||||
|
if gameMode is None:
|
||||||
|
gameMode = token.gameMode
|
||||||
|
if gameMode == gameModes.TAIKO or gameMode == gameModes.CTB:
|
||||||
|
return "PP for your current game mode is not supported yet."
|
||||||
|
pp = userUtils.getPP(token.userID, gameMode)
|
||||||
|
return "You have {:,} pp".format(pp)
|
||||||
|
|
||||||
|
def updateBeatmap(fro, chan, to):
|
||||||
|
try:
|
||||||
|
# Run the command in PM only
|
||||||
|
if chan.startswith("#"):
|
||||||
|
return False
|
||||||
|
|
||||||
|
# Get token and user ID
|
||||||
|
token = glob.tokens.getTokenFromUsername(fro)
|
||||||
|
if token is None:
|
||||||
|
return False
|
||||||
|
|
||||||
|
# Make sure the user has triggered the bot with /np command
|
||||||
|
if token.tillerino[0] == 0:
|
||||||
|
return "Please give me a beatmap first with /np command."
|
||||||
|
|
||||||
|
# Send request
|
||||||
|
beatmapData = glob.db.fetch("SELECT beatmapset_id, song_name FROM beatmaps WHERE beatmap_id = %s LIMIT 1", [token.tillerino[0]])
|
||||||
|
if beatmapData is None:
|
||||||
|
return "Couldn't find beatmap data in database. Please load the beatmap's leaderboard and try again."
|
||||||
|
|
||||||
|
response = requests.post("{}/api/v1/update_beatmap".format(glob.conf.config["mirror"]["apiurl"]), {
|
||||||
|
"beatmap_set_id": beatmapData["beatmapset_id"],
|
||||||
|
"beatmap_name": beatmapData["song_name"],
|
||||||
|
"username": token.username,
|
||||||
|
"key": glob.conf.config["mirror"]["apikey"]
|
||||||
|
})
|
||||||
|
if response.status_code == 200:
|
||||||
|
return "An update request for that beatmap has been queued. You'll receive a message once the beatmap has been updated on our mirror!"
|
||||||
|
elif response.status_code == 429:
|
||||||
|
return "You are sending too many beatmaps update requests. Wait a bit and retry later."
|
||||||
|
else:
|
||||||
|
return "Error in beatmap mirror API request. Tell this to a dev: {}".format(response.text)
|
||||||
|
except:
|
||||||
|
return False
|
||||||
|
|
||||||
"""
|
"""
|
||||||
Commands list
|
Commands list
|
||||||
|
|
||||||
@@ -724,6 +828,17 @@ commands = [
|
|||||||
}, {
|
}, {
|
||||||
"trigger": "!last",
|
"trigger": "!last",
|
||||||
"callback": tillerinoLast
|
"callback": tillerinoLast
|
||||||
|
}, {
|
||||||
|
"trigger": "!ir",
|
||||||
|
"privileges": privileges.ADMIN_MANAGE_SERVERS,
|
||||||
|
"callback": instantRestart
|
||||||
|
}, {
|
||||||
|
"trigger": "!pp",
|
||||||
|
"callback": pp
|
||||||
|
}, {
|
||||||
|
"trigger": "!update",
|
||||||
|
"callback": updateBeatmap,
|
||||||
|
"privileges": privileges.ADMIN_MANAGE_SERVERS, # TODO: Remove privileges for !update
|
||||||
}
|
}
|
||||||
#
|
#
|
||||||
# "trigger": "!acc",
|
# "trigger": "!acc",
|
||||||
|
@@ -1,41 +0,0 @@
|
|||||||
"""Contains readable gamemodes with their codes"""
|
|
||||||
std = 0
|
|
||||||
taiko = 1
|
|
||||||
ctb = 2
|
|
||||||
mania = 3
|
|
||||||
|
|
||||||
def getGameModeForDB(gameMode):
|
|
||||||
"""
|
|
||||||
Convert a gamemode number to string for database table/column
|
|
||||||
|
|
||||||
gameMode -- gameMode int or variable (ex: gameMode.std)
|
|
||||||
|
|
||||||
return -- game mode readable string for db
|
|
||||||
"""
|
|
||||||
|
|
||||||
if gameMode == std:
|
|
||||||
return "std"
|
|
||||||
elif gameMode == taiko:
|
|
||||||
return "taiko"
|
|
||||||
elif gameMode == ctb:
|
|
||||||
return "ctb"
|
|
||||||
else:
|
|
||||||
return "mania"
|
|
||||||
|
|
||||||
def getGameModeForPrinting(gameMode):
|
|
||||||
"""
|
|
||||||
Convert a gamemode number to string for showing to a user (e.g. !last)
|
|
||||||
|
|
||||||
gameMode -- gameMode int or variable (ex: gameMode.std)
|
|
||||||
|
|
||||||
return -- game mode readable string for a human
|
|
||||||
"""
|
|
||||||
|
|
||||||
if gameMode == std:
|
|
||||||
return "osu!"
|
|
||||||
elif gameMode == taiko:
|
|
||||||
return "Taiko"
|
|
||||||
elif gameMode == ctb:
|
|
||||||
return "CatchTheBeat"
|
|
||||||
else:
|
|
||||||
return "osu!mania"
|
|
@@ -1,30 +0,0 @@
|
|||||||
Nomod = 0
|
|
||||||
NoFail = 1
|
|
||||||
Easy = 2
|
|
||||||
NoVideo = 4
|
|
||||||
Hidden = 8
|
|
||||||
HardRock = 16
|
|
||||||
SuddenDeath = 32
|
|
||||||
DoubleTime = 64
|
|
||||||
Relax = 128
|
|
||||||
HalfTime = 256
|
|
||||||
Nightcore = 512
|
|
||||||
Flashlight = 1024
|
|
||||||
Autoplay = 2048
|
|
||||||
SpunOut = 4096
|
|
||||||
Relax2 = 8192
|
|
||||||
Perfect = 16384
|
|
||||||
Key4 = 32768
|
|
||||||
Key5 = 65536
|
|
||||||
Key6 = 131072
|
|
||||||
Key7 = 262144
|
|
||||||
Key8 = 524288
|
|
||||||
keyMod = 1015808
|
|
||||||
FadeIn = 1048576
|
|
||||||
Random = 2097152
|
|
||||||
LastMod = 4194304
|
|
||||||
Key9 = 16777216
|
|
||||||
Key10 = 33554432
|
|
||||||
Key1 = 67108864
|
|
||||||
Key3 = 134217728
|
|
||||||
Key2 = 268435456
|
|
@@ -74,7 +74,9 @@ server_channelInfoEnd = 89
|
|||||||
client_matchChangePassword = 90
|
client_matchChangePassword = 90
|
||||||
server_matchChangePassword = 91
|
server_matchChangePassword = 91
|
||||||
server_silenceEnd = 92
|
server_silenceEnd = 92
|
||||||
client_specialMatchInfoRequest = 93
|
|
||||||
server_userSilenced = 94
|
server_userSilenced = 94
|
||||||
server_userPresenceBundle = 96
|
server_userPresenceBundle = 96
|
||||||
client_userPanelRequest = 97
|
client_userPanelRequest = 97
|
||||||
|
client_tournamentMatchInfoRequest = 93
|
||||||
|
client_tournamentJoinMatchChannel = 108
|
||||||
|
client_tournamentLeaveMatchChannel = 109
|
@@ -1,21 +0,0 @@
|
|||||||
USER_PUBLIC = 1
|
|
||||||
USER_NORMAL = 2 << 0
|
|
||||||
USER_DONOR = 2 << 1
|
|
||||||
ADMIN_ACCESS_RAP = 2 << 2
|
|
||||||
ADMIN_MANAGE_USERS = 2 << 3
|
|
||||||
ADMIN_BAN_USERS = 2 << 4
|
|
||||||
ADMIN_SILENCE_USERS = 2 << 5
|
|
||||||
ADMIN_WIPE_USERS = 2 << 6
|
|
||||||
ADMIN_MANAGE_BEATMAPS = 2 << 7
|
|
||||||
ADMIN_MANAGE_SERVERS = 2 << 8
|
|
||||||
ADMIN_MANAGE_SETTINGS = 2 << 9
|
|
||||||
ADMIN_MANAGE_BETAKEYS = 2 << 10
|
|
||||||
ADMIN_MANAGE_REPORTS = 2 << 11
|
|
||||||
ADMIN_MANAGE_DOCS = 2 << 12
|
|
||||||
ADMIN_MANAGE_BADGES = 2 << 13
|
|
||||||
ADMIN_VIEW_RAP_LOGS = 2 << 14
|
|
||||||
ADMIN_MANAGE_PRIVILEGES = 2 << 15
|
|
||||||
ADMIN_SEND_ALERTS = 2 << 16
|
|
||||||
ADMIN_CHAT_MOD = 2 << 17
|
|
||||||
ADMIN_KICK_USERS = 2 << 18
|
|
||||||
USER_PENDING_VERIFICATION = 2 << 19
|
|
@@ -1,69 +1,65 @@
|
|||||||
""" Contains functions used to write specific server packets to byte streams """
|
""" Contains functions used to write specific server packets to byte streams """
|
||||||
from helpers import packetHelper
|
from common.constants import privileges
|
||||||
|
from common.ripple import userUtils
|
||||||
from constants import dataTypes
|
from constants import dataTypes
|
||||||
from helpers import userHelper
|
|
||||||
from objects import glob
|
|
||||||
from constants import userRanks
|
|
||||||
from constants import packetIDs
|
from constants import packetIDs
|
||||||
|
from constants import userRanks
|
||||||
|
from helpers import packetHelper
|
||||||
|
from objects import glob
|
||||||
|
|
||||||
""" Login errors packets
|
""" Login errors packets """
|
||||||
(userID packets derivates) """
|
|
||||||
def loginFailed():
|
def loginFailed():
|
||||||
return packetHelper.buildPacket(packetIDs.server_userID, [[-1, dataTypes.sInt32]])
|
return packetHelper.buildPacket(packetIDs.server_userID, [[-1, dataTypes.SINT32]])
|
||||||
|
|
||||||
def forceUpdate():
|
def forceUpdate():
|
||||||
return packetHelper.buildPacket(packetIDs.server_userID, [[-2, dataTypes.sInt32]])
|
return packetHelper.buildPacket(packetIDs.server_userID, [[-2, dataTypes.SINT32]])
|
||||||
|
|
||||||
def loginBanned():
|
def loginBanned():
|
||||||
packets = packetHelper.buildPacket(packetIDs.server_userID, [[-1, dataTypes.sInt32]])
|
packets = packetHelper.buildPacket(packetIDs.server_userID, [[-1, dataTypes.SINT32]])
|
||||||
packets += notification("You are banned. You can ask to get unbanned after 1 month since your ban by contacting support@ripple.moe")
|
packets += notification("You are banned. You can appeal after one month since your ban by sending an email to support@ripple.moe from the email address you've used to sign up.")
|
||||||
|
return packets
|
||||||
|
|
||||||
|
def loginLocked():
|
||||||
|
packets = packetHelper.buildPacket(packetIDs.server_userID, [[-1, dataTypes.SINT32]])
|
||||||
|
packets += notification("Your account is locked. You can't log in, but your profile and scores are still visible from the website. If you want to unlock your account, send an email to support@ripple.moe from the email address you've used to sign up.")
|
||||||
return packets
|
return packets
|
||||||
#return packetHelper.buildPacket(packetIDs.server_userID, [[-3, dataTypes.sInt32]])
|
|
||||||
|
|
||||||
def loginError():
|
def loginError():
|
||||||
return packetHelper.buildPacket(packetIDs.server_userID, [[-5, dataTypes.sInt32]])
|
return packetHelper.buildPacket(packetIDs.server_userID, [[-5, dataTypes.SINT32]])
|
||||||
|
|
||||||
def needSupporter():
|
def needSupporter():
|
||||||
return packetHelper.buildPacket(packetIDs.server_userID, [[-6, dataTypes.sInt32]])
|
return packetHelper.buildPacket(packetIDs.server_userID, [[-6, dataTypes.SINT32]])
|
||||||
|
|
||||||
def needVerification():
|
def needVerification():
|
||||||
return packetHelper.buildPacket(packetIDs.server_userID, [[-8, dataTypes.sInt32]])
|
return packetHelper.buildPacket(packetIDs.server_userID, [[-8, dataTypes.SINT32]])
|
||||||
|
|
||||||
|
|
||||||
""" Login packets """
|
""" Login packets """
|
||||||
def userID(uid):
|
def userID(uid):
|
||||||
return packetHelper.buildPacket(packetIDs.server_userID, [[uid, dataTypes.sInt32]])
|
return packetHelper.buildPacket(packetIDs.server_userID, [[uid, dataTypes.SINT32]])
|
||||||
|
|
||||||
def silenceEndTime(seconds):
|
def silenceEndTime(seconds):
|
||||||
return packetHelper.buildPacket(packetIDs.server_silenceEnd, [[seconds, dataTypes.uInt32]])
|
return packetHelper.buildPacket(packetIDs.server_silenceEnd, [[seconds, dataTypes.UINT32]])
|
||||||
|
|
||||||
def protocolVersion(version = 19):
|
def protocolVersion(version = 19):
|
||||||
return packetHelper.buildPacket(packetIDs.server_protocolVersion, [[version, dataTypes.uInt32]])
|
return packetHelper.buildPacket(packetIDs.server_protocolVersion, [[version, dataTypes.UINT32]])
|
||||||
|
|
||||||
def mainMenuIcon(icon):
|
def mainMenuIcon(icon):
|
||||||
return packetHelper.buildPacket(packetIDs.server_mainMenuIcon, [[icon, dataTypes.string]])
|
return packetHelper.buildPacket(packetIDs.server_mainMenuIcon, [[icon, dataTypes.STRING]])
|
||||||
|
|
||||||
def userSupporterGMT(supporter, GMT):
|
def userSupporterGMT(supporter, GMT, tournamentStaff):
|
||||||
result = 1
|
result = 1
|
||||||
if supporter == True:
|
if supporter:
|
||||||
result += 4
|
result |= userRanks.SUPPORTER
|
||||||
if GMT == True:
|
if GMT:
|
||||||
result += 2
|
result |= userRanks.BAT
|
||||||
return packetHelper.buildPacket(packetIDs.server_supporterGMT, [[result, dataTypes.uInt32]])
|
if tournamentStaff:
|
||||||
|
result |= userRanks.TOURNAMENT_STAFF
|
||||||
|
return packetHelper.buildPacket(packetIDs.server_supporterGMT, [[result, dataTypes.UINT32]])
|
||||||
|
|
||||||
def friendList(userID):
|
def friendList(userID):
|
||||||
friendsData = []
|
friends = userUtils.getFriendList(userID)
|
||||||
|
return packetHelper.buildPacket(packetIDs.server_friendsList, [[friends, dataTypes.INT_LIST]])
|
||||||
# Get friend IDs from db
|
|
||||||
friends = userHelper.getFriendList(userID)
|
|
||||||
|
|
||||||
# Friends number
|
|
||||||
friendsData.append([len(friends), dataTypes.uInt16])
|
|
||||||
|
|
||||||
# Add all friend user IDs to friendsData
|
|
||||||
for i in friends:
|
|
||||||
friendsData.append([i, dataTypes.sInt32])
|
|
||||||
|
|
||||||
return packetHelper.buildPacket(packetIDs.server_friendsList, friendsData)
|
|
||||||
|
|
||||||
def onlineUsers():
|
def onlineUsers():
|
||||||
userIDs = []
|
userIDs = []
|
||||||
@@ -71,27 +67,25 @@ def onlineUsers():
|
|||||||
|
|
||||||
# Create list with all connected (and not restricted) users
|
# Create list with all connected (and not restricted) users
|
||||||
for _, value in users.items():
|
for _, value in users.items():
|
||||||
if value.restricted == False:
|
if not value.restricted:
|
||||||
userIDs.append(value.userID)
|
userIDs.append(value.userID)
|
||||||
|
|
||||||
return packetHelper.buildPacket(packetIDs.server_userPresenceBundle, [[userIDs, dataTypes.intList]])
|
return packetHelper.buildPacket(packetIDs.server_userPresenceBundle, [[userIDs, dataTypes.INT_LIST]])
|
||||||
|
|
||||||
|
|
||||||
""" Users packets """
|
""" Users packets """
|
||||||
def userLogout(userID):
|
def userLogout(userID):
|
||||||
return packetHelper.buildPacket(packetIDs.server_userLogout, [[userID, dataTypes.sInt32], [0, dataTypes.byte]])
|
return packetHelper.buildPacket(packetIDs.server_userLogout, [[userID, dataTypes.SINT32], [0, dataTypes.BYTE]])
|
||||||
|
|
||||||
def userPanel(userID, force = False):
|
def userPanel(userID, force = False):
|
||||||
# Connected and restricted check
|
# Connected and restricted check
|
||||||
userToken = glob.tokens.getTokenFromUserID(userID)
|
userToken = glob.tokens.getTokenFromUserID(userID)
|
||||||
if userToken == None:
|
if userToken is None or ((userToken.restricted) and not force):
|
||||||
return bytes()
|
|
||||||
if userToken.restricted == True and force == False:
|
|
||||||
return bytes()
|
return bytes()
|
||||||
|
|
||||||
# Get user data
|
# Get user data
|
||||||
username = userToken.username
|
username = userToken.username
|
||||||
timezone = 24+userToken.timeOffset # TODO: Timezone
|
timezone = 24+userToken.timeOffset
|
||||||
country = userToken.country
|
country = userToken.country
|
||||||
gameRank = userToken.gameRank
|
gameRank = userToken.gameRank
|
||||||
latitude = userToken.getLatitude()
|
latitude = userToken.getLatitude()
|
||||||
@@ -99,134 +93,141 @@ def userPanel(userID, force = False):
|
|||||||
|
|
||||||
# Get username color according to rank
|
# Get username color according to rank
|
||||||
# Only admins and normal users are currently supported
|
# Only admins and normal users are currently supported
|
||||||
|
userRank = 0
|
||||||
if username == "FokaBot":
|
if username == "FokaBot":
|
||||||
userRank = userRanks.MOD
|
userRank |= userRanks.MOD
|
||||||
elif userHelper.isInPrivilegeGroup(userID, "community manager") == True:
|
elif userUtils.isInPrivilegeGroup(userID, "community manager"):
|
||||||
userRank = userRanks.MOD
|
userRank |= userRanks.MOD
|
||||||
elif userHelper.isInPrivilegeGroup(userID, "developer") == True:
|
elif userUtils.isInPrivilegeGroup(userID, "developer"):
|
||||||
userRank = userRanks.ADMIN
|
userRank |= userRanks.ADMIN
|
||||||
elif userHelper.isInPrivilegeGroup(userID, "donor") == True:
|
elif (userToken.privileges & privileges.USER_DONOR) > 0:
|
||||||
userRank = userRanks.SUPPORTER
|
userRank |= userRanks.SUPPORTER
|
||||||
else:
|
else:
|
||||||
userRank = userRanks.NORMAL
|
userRank |= userRanks.NORMAL
|
||||||
|
|
||||||
return packetHelper.buildPacket(packetIDs.server_userPanel,
|
return packetHelper.buildPacket(packetIDs.server_userPanel,
|
||||||
[
|
[
|
||||||
[userID, dataTypes.sInt32],
|
[userID, dataTypes.SINT32],
|
||||||
[username, dataTypes.string],
|
[username, dataTypes.STRING],
|
||||||
[timezone, dataTypes.byte],
|
[timezone, dataTypes.BYTE],
|
||||||
[country, dataTypes.byte],
|
[country, dataTypes.BYTE],
|
||||||
[userRank, dataTypes.byte],
|
[userRank, dataTypes.BYTE],
|
||||||
[longitude, dataTypes.ffloat],
|
[longitude, dataTypes.FFLOAT],
|
||||||
[latitude, dataTypes.ffloat],
|
[latitude, dataTypes.FFLOAT],
|
||||||
[gameRank, dataTypes.uInt32]
|
[gameRank, dataTypes.UINT32]
|
||||||
])
|
])
|
||||||
|
|
||||||
|
|
||||||
def userStats(userID, force = False):
|
def userStats(userID, force = False):
|
||||||
# Get userID's token from tokens list
|
# Get userID's token from tokens list
|
||||||
userToken = glob.tokens.getTokenFromUserID(userID)
|
userToken = glob.tokens.getTokenFromUserID(userID)
|
||||||
if userToken == None:
|
if userToken is None or ((userToken.restricted or userToken.irc or userToken.tournament) and not force):
|
||||||
return bytes()
|
|
||||||
if (userToken.restricted == True or userToken.irc == True) and force == False:
|
|
||||||
return bytes()
|
return bytes()
|
||||||
|
|
||||||
return packetHelper.buildPacket(packetIDs.server_userStats,
|
return packetHelper.buildPacket(packetIDs.server_userStats,
|
||||||
[
|
[
|
||||||
[userID, dataTypes.uInt32],
|
[userID, dataTypes.UINT32],
|
||||||
[userToken.actionID, dataTypes.byte],
|
[userToken.actionID, dataTypes.BYTE],
|
||||||
[userToken.actionText, dataTypes.string],
|
[userToken.actionText, dataTypes.STRING],
|
||||||
[userToken.actionMd5, dataTypes.string],
|
[userToken.actionMd5, dataTypes.STRING],
|
||||||
[userToken.actionMods, dataTypes.sInt32],
|
[userToken.actionMods, dataTypes.SINT32],
|
||||||
[userToken.gameMode, dataTypes.byte],
|
[userToken.gameMode, dataTypes.BYTE],
|
||||||
[0, dataTypes.sInt32],
|
[userToken.beatmapID, dataTypes.SINT32],
|
||||||
[userToken.rankedScore, dataTypes.uInt64],
|
[userToken.rankedScore, dataTypes.UINT64],
|
||||||
[userToken.accuracy, dataTypes.ffloat],
|
[userToken.accuracy, dataTypes.FFLOAT],
|
||||||
[userToken.playcount, dataTypes.uInt32],
|
[userToken.playcount, dataTypes.UINT32],
|
||||||
[userToken.totalScore, dataTypes.uInt64],
|
[userToken.totalScore, dataTypes.UINT64],
|
||||||
[userToken.gameRank, dataTypes.uInt32],
|
[userToken.gameRank, dataTypes.UINT32],
|
||||||
[userToken.pp, dataTypes.uInt16]
|
[userToken.pp if 65535 >= userToken.pp > 0 else 0, dataTypes.UINT16]
|
||||||
])
|
])
|
||||||
|
|
||||||
|
|
||||||
""" Chat packets """
|
""" Chat packets """
|
||||||
def sendMessage(fro, to, message):
|
def sendMessage(fro, to, message):
|
||||||
return packetHelper.buildPacket(packetIDs.server_sendMessage, [[fro, dataTypes.string], [message, dataTypes.string], [to, dataTypes.string], [userHelper.getID(fro), dataTypes.sInt32]])
|
return packetHelper.buildPacket(packetIDs.server_sendMessage, [
|
||||||
|
[fro, dataTypes.STRING],
|
||||||
|
[message, dataTypes.STRING],
|
||||||
|
[to, dataTypes.STRING],
|
||||||
|
[userUtils.getID(fro), dataTypes.SINT32]
|
||||||
|
])
|
||||||
|
|
||||||
def channelJoinSuccess(userID, chan):
|
def channelJoinSuccess(userID, chan):
|
||||||
return packetHelper.buildPacket(packetIDs.server_channelJoinSuccess, [[chan, dataTypes.string]])
|
return packetHelper.buildPacket(packetIDs.server_channelJoinSuccess, [[chan, dataTypes.STRING]])
|
||||||
|
|
||||||
def channelInfo(chan):
|
def channelInfo(chan):
|
||||||
channel = glob.channels.channels[chan]
|
channel = glob.channels.channels[chan]
|
||||||
return packetHelper.buildPacket(packetIDs.server_channelInfo, [[chan, dataTypes.string], [channel.description, dataTypes.string], [channel.getConnectedUsersCount(), dataTypes.uInt16]])
|
return packetHelper.buildPacket(packetIDs.server_channelInfo, [
|
||||||
|
[chan, dataTypes.STRING],
|
||||||
|
[channel.description, dataTypes.STRING],
|
||||||
|
[channel.getConnectedUsersCount(), dataTypes.UINT16]
|
||||||
|
])
|
||||||
|
|
||||||
def channelInfoEnd():
|
def channelInfoEnd():
|
||||||
return packetHelper.buildPacket(packetIDs.server_channelInfoEnd, [[0, dataTypes.uInt32]])
|
return packetHelper.buildPacket(packetIDs.server_channelInfoEnd, [[0, dataTypes.UINT32]])
|
||||||
|
|
||||||
def channelKicked(chan):
|
def channelKicked(chan):
|
||||||
return packetHelper.buildPacket(packetIDs.server_channelKicked, [[chan, dataTypes.string]])
|
return packetHelper.buildPacket(packetIDs.server_channelKicked, [[chan, dataTypes.STRING]])
|
||||||
|
|
||||||
def userSilenced(userID):
|
def userSilenced(userID):
|
||||||
return packetHelper.buildPacket(packetIDs.server_userSilenced, [[userID, dataTypes.uInt32]])
|
return packetHelper.buildPacket(packetIDs.server_userSilenced, [[userID, dataTypes.UINT32]])
|
||||||
|
|
||||||
|
|
||||||
""" Spectator packets """
|
""" Spectator packets """
|
||||||
def addSpectator(userID):
|
def addSpectator(userID):
|
||||||
return packetHelper.buildPacket(packetIDs.server_spectatorJoined, [[userID, dataTypes.sInt32]])
|
return packetHelper.buildPacket(packetIDs.server_spectatorJoined, [[userID, dataTypes.SINT32]])
|
||||||
|
|
||||||
def removeSpectator(userID):
|
def removeSpectator(userID):
|
||||||
return packetHelper.buildPacket(packetIDs.server_spectatorLeft, [[userID, dataTypes.sInt32]])
|
return packetHelper.buildPacket(packetIDs.server_spectatorLeft, [[userID, dataTypes.SINT32]])
|
||||||
|
|
||||||
def spectatorFrames(data):
|
def spectatorFrames(data):
|
||||||
return packetHelper.buildPacket(packetIDs.server_spectateFrames, [[data, dataTypes.bbytes]])
|
return packetHelper.buildPacket(packetIDs.server_spectateFrames, [[data, dataTypes.BBYTES]])
|
||||||
|
|
||||||
def noSongSpectator(userID):
|
def noSongSpectator(userID):
|
||||||
return packetHelper.buildPacket(packetIDs.server_spectatorCantSpectate, [[userID, dataTypes.sInt32]])
|
return packetHelper.buildPacket(packetIDs.server_spectatorCantSpectate, [[userID, dataTypes.SINT32]])
|
||||||
|
|
||||||
def fellowSpectatorJoined(userID):
|
def fellowSpectatorJoined(userID):
|
||||||
return packetHelper.buildPacket(packetIDs.server_fellowSpectatorJoined, [[userID, dataTypes.sInt32]])
|
return packetHelper.buildPacket(packetIDs.server_fellowSpectatorJoined, [[userID, dataTypes.SINT32]])
|
||||||
|
|
||||||
def fellowSpectatorLeft(userID):
|
def fellowSpectatorLeft(userID):
|
||||||
return packetHelper.buildPacket(packetIDs.server_fellowSpectatorLeft, [[userID, dataTypes.sInt32]])
|
return packetHelper.buildPacket(packetIDs.server_fellowSpectatorLeft, [[userID, dataTypes.SINT32]])
|
||||||
|
|
||||||
|
|
||||||
""" Multiplayer Packets """
|
""" Multiplayer Packets """
|
||||||
def createMatch(matchID):
|
def createMatch(matchID):
|
||||||
# Make sure the match exists
|
# Make sure the match exists
|
||||||
if matchID not in glob.matches.matches:
|
if matchID not in glob.matches.matches:
|
||||||
return None
|
return bytes()
|
||||||
|
|
||||||
# Get match binary data and build packet
|
# Get match binary data and build packet
|
||||||
match = glob.matches.matches[matchID]
|
match = glob.matches.matches[matchID]
|
||||||
return packetHelper.buildPacket(packetIDs.server_newMatch, match.getMatchData())
|
return packetHelper.buildPacket(packetIDs.server_newMatch, match.getMatchData())
|
||||||
|
|
||||||
|
# TODO: Add match object argument to save some CPU
|
||||||
def updateMatch(matchID):
|
def updateMatch(matchID):
|
||||||
# Make sure the match exists
|
# Make sure the match exists
|
||||||
if matchID not in glob.matches.matches:
|
if matchID not in glob.matches.matches:
|
||||||
return None
|
return bytes()
|
||||||
|
|
||||||
# Get match binary data and build packet
|
# Get match binary data and build packet
|
||||||
match = glob.matches.matches[matchID]
|
match = glob.matches.matches[matchID]
|
||||||
return packetHelper.buildPacket(packetIDs.server_updateMatch, match.getMatchData())
|
return packetHelper.buildPacket(packetIDs.server_updateMatch, match.getMatchData())
|
||||||
|
|
||||||
|
|
||||||
def matchStart(matchID):
|
def matchStart(matchID):
|
||||||
# Make sure the match exists
|
# Make sure the match exists
|
||||||
if matchID not in glob.matches.matches:
|
if matchID not in glob.matches.matches:
|
||||||
return None
|
return bytes()
|
||||||
|
|
||||||
# Get match binary data and build packet
|
# Get match binary data and build packet
|
||||||
match = glob.matches.matches[matchID]
|
match = glob.matches.matches[matchID]
|
||||||
return packetHelper.buildPacket(packetIDs.server_matchStart, match.getMatchData())
|
return packetHelper.buildPacket(packetIDs.server_matchStart, match.getMatchData())
|
||||||
|
|
||||||
|
|
||||||
def disposeMatch(matchID):
|
def disposeMatch(matchID):
|
||||||
return packetHelper.buildPacket(packetIDs.server_disposeMatch, [[matchID, dataTypes.uInt16]])
|
return packetHelper.buildPacket(packetIDs.server_disposeMatch, [[matchID, dataTypes.UINT32]])
|
||||||
|
|
||||||
def matchJoinSuccess(matchID):
|
def matchJoinSuccess(matchID):
|
||||||
# Make sure the match exists
|
# Make sure the match exists
|
||||||
if matchID not in glob.matches.matches:
|
if matchID not in glob.matches.matches:
|
||||||
return None
|
return bytes()
|
||||||
|
|
||||||
# Get match binary data and build packet
|
# Get match binary data and build packet
|
||||||
match = glob.matches.matches[matchID]
|
match = glob.matches.matches[matchID]
|
||||||
@@ -237,32 +238,33 @@ def matchJoinFail():
|
|||||||
return packetHelper.buildPacket(packetIDs.server_matchJoinFail)
|
return packetHelper.buildPacket(packetIDs.server_matchJoinFail)
|
||||||
|
|
||||||
def changeMatchPassword(newPassword):
|
def changeMatchPassword(newPassword):
|
||||||
return packetHelper.buildPacket(packetIDs.server_matchChangePassword, [[newPassword, dataTypes.string]])
|
return packetHelper.buildPacket(packetIDs.server_matchChangePassword, [[newPassword, dataTypes.STRING]])
|
||||||
|
|
||||||
def allPlayersLoaded():
|
def allPlayersLoaded():
|
||||||
return packetHelper.buildPacket(packetIDs.server_matchAllPlayersLoaded)
|
return packetHelper.buildPacket(packetIDs.server_matchAllPlayersLoaded)
|
||||||
|
|
||||||
def playerSkipped(userID):
|
def playerSkipped(userID):
|
||||||
return packetHelper.buildPacket(packetIDs.server_matchPlayerSkipped, [[userID, dataTypes.sInt32]])
|
return packetHelper.buildPacket(packetIDs.server_matchPlayerSkipped, [[userID, dataTypes.SINT32]])
|
||||||
|
|
||||||
def allPlayersSkipped():
|
def allPlayersSkipped():
|
||||||
return packetHelper.buildPacket(packetIDs.server_matchSkip)
|
return packetHelper.buildPacket(packetIDs.server_matchSkip)
|
||||||
|
|
||||||
def matchFrames(slotID, data):
|
def matchFrames(slotID, data):
|
||||||
return packetHelper.buildPacket(packetIDs.server_matchScoreUpdate, [[data[7:11], dataTypes.bbytes], [slotID, dataTypes.byte], [data[12:], dataTypes.bbytes]])
|
return packetHelper.buildPacket(packetIDs.server_matchScoreUpdate, [[data[7:11], dataTypes.BBYTES], [slotID, dataTypes.BYTE], [data[12:], dataTypes.BBYTES]])
|
||||||
|
|
||||||
def matchComplete():
|
def matchComplete():
|
||||||
return packetHelper.buildPacket(packetIDs.server_matchComplete)
|
return packetHelper.buildPacket(packetIDs.server_matchComplete)
|
||||||
|
|
||||||
def playerFailed(slotID):
|
def playerFailed(slotID):
|
||||||
return packetHelper.buildPacket(packetIDs.server_matchPlayerFailed, [[slotID, dataTypes.uInt32]])
|
return packetHelper.buildPacket(packetIDs.server_matchPlayerFailed, [[slotID, dataTypes.UINT32]])
|
||||||
|
|
||||||
def matchTransferHost():
|
def matchTransferHost():
|
||||||
return packetHelper.buildPacket(packetIDs.server_matchTransferHost)
|
return packetHelper.buildPacket(packetIDs.server_matchTransferHost)
|
||||||
|
|
||||||
|
|
||||||
""" Other packets """
|
""" Other packets """
|
||||||
def notification(message):
|
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]])
|
@@ -1,8 +1,9 @@
|
|||||||
"""Bancho user ranks"""
|
"""Bancho user ranks"""
|
||||||
NORMAL = 0
|
NORMAL = 0
|
||||||
PLAYER = 1
|
PLAYER = 1
|
||||||
|
BAT = 2
|
||||||
SUPPORTER = 4
|
SUPPORTER = 4
|
||||||
MOD = 6
|
MOD = 6
|
||||||
PEPPY = 8
|
PEPPY = 8
|
||||||
ADMIN = 16
|
ADMIN = 16
|
||||||
TOURNAMENTSTAFF = 32
|
TOURNAMENT_STAFF = 32
|
||||||
|
@@ -1,19 +1,17 @@
|
|||||||
from objects import glob
|
from common.log import logUtils as log
|
||||||
from constants import serverPackets
|
|
||||||
from constants import exceptions
|
from constants import exceptions
|
||||||
from helpers import logHelper as log
|
from constants import serverPackets
|
||||||
|
from objects import glob
|
||||||
|
|
||||||
def handle(userToken, packetData):
|
|
||||||
# get usertoken data
|
|
||||||
userID = userToken.userID
|
|
||||||
|
|
||||||
|
def handle(userToken, _):
|
||||||
try:
|
try:
|
||||||
# We don't have the beatmap, we can't spectate
|
# We don't have the beatmap, we can't spectate
|
||||||
target = userToken.spectating
|
if userToken.spectating not in glob.tokens.tokens:
|
||||||
targetToken = glob.tokens.getTokenFromUserID(target)
|
raise exceptions.tokenNotFoundException()
|
||||||
|
|
||||||
# Send the packet to host
|
# Send the packet to host
|
||||||
targetToken.enqueue(serverPackets.noSongSpectator(userID))
|
glob.tokens.tokens[userToken.spectating].enqueue(serverPackets.noSongSpectator(userToken.userID))
|
||||||
except exceptions.tokenNotFoundException:
|
except exceptions.tokenNotFoundException:
|
||||||
# Stop spectating if token not found
|
# Stop spectating if token not found
|
||||||
log.warning("Spectator can't spectate: token not found")
|
log.warning("Spectator can't spectate: token not found")
|
||||||
|
@@ -1,10 +1,10 @@
|
|||||||
from objects import glob
|
from common.constants import actions
|
||||||
|
from common.log import logUtils as log
|
||||||
|
from common.ripple import userUtils
|
||||||
from constants import clientPackets
|
from constants import clientPackets
|
||||||
from constants import serverPackets
|
from constants import serverPackets
|
||||||
from helpers import userHelper
|
from objects import glob
|
||||||
from helpers import logHelper as log
|
|
||||||
from constants import actions
|
|
||||||
from helpers import chatHelper as chat
|
|
||||||
|
|
||||||
def handle(userToken, packetData):
|
def handle(userToken, packetData):
|
||||||
# Get usertoken data
|
# Get usertoken data
|
||||||
@@ -12,55 +12,54 @@ def handle(userToken, packetData):
|
|||||||
username = userToken.username
|
username = userToken.username
|
||||||
|
|
||||||
# Make sure we are not banned
|
# Make sure we are not banned
|
||||||
if userHelper.isBanned(userID) == True:
|
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 == False:
|
if not userToken.restricted:
|
||||||
if userHelper.isRestricted(userID) == True:
|
if userUtils.isRestricted(userID):
|
||||||
userToken.setRestricted()
|
userToken.setRestricted()
|
||||||
|
|
||||||
# Change action packet
|
# Change action packet
|
||||||
packetData = clientPackets.userActionChange(packetData)
|
packetData = clientPackets.userActionChange(packetData)
|
||||||
|
|
||||||
# Update cached stats if our pp changedm if we've just submitted a score or we've changed gameMode
|
# If we are not in spectate status but we're spectating someone, stop spectating
|
||||||
if (userToken.actionID == actions.playing or userToken.actionID == actions.multiplaying) or (userToken.pp != userHelper.getPP(userID, userToken.gameMode)) or (userToken.gameMode != packetData["gameMode"]):
|
'''
|
||||||
log.debug("!!!! UPDATING CACHED STATS !!!!")
|
if userToken.spectating != 0 and userToken.actionID != actions.WATCHING and userToken.actionID != actions.IDLE and userToken.actionID != actions.AFK:
|
||||||
|
userToken.stopSpectating()
|
||||||
|
|
||||||
|
# If we are not in multiplayer but we are in a match, part match
|
||||||
|
if userToken.matchID != -1 and userToken.actionID != actions.MULTIPLAYING and userToken.actionID != actions.MULTIPLAYER and userToken.actionID != actions.AFK:
|
||||||
|
userToken.partMatch()
|
||||||
|
'''
|
||||||
|
|
||||||
|
# Update cached stats if our pp changed if we've just submitted a score or we've changed gameMode
|
||||||
|
if (userToken.actionID == actions.PLAYING or userToken.actionID == actions.MULTIPLAYING) or (userToken.pp != userUtils.getPP(userID, userToken.gameMode)) or (userToken.gameMode != packetData["gameMode"]):
|
||||||
# Always update game mode, or we'll cache stats from the wrong game mode if we've changed it
|
# Always update game mode, or we'll cache stats from the wrong game mode if we've changed it
|
||||||
userToken.gameMode = packetData["gameMode"]
|
userToken.gameMode = packetData["gameMode"]
|
||||||
userToken.updateCachedStats()
|
userToken.updateCachedStats()
|
||||||
|
|
||||||
# Always update action id, text and md5
|
# Always update action id, text, md5 and beatmapID
|
||||||
userToken.actionID = packetData["actionID"]
|
userToken.actionID = packetData["actionID"]
|
||||||
userToken.actionText = packetData["actionText"]
|
userToken.actionText = packetData["actionText"]
|
||||||
userToken.actionMd5 = packetData["actionMd5"]
|
userToken.actionMd5 = packetData["actionMd5"]
|
||||||
userToken.actionMods = packetData["actionMods"]
|
userToken.actionMods = packetData["actionMods"]
|
||||||
|
userToken.beatmapID = packetData["beatmapID"]
|
||||||
|
|
||||||
# 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 = [userID]
|
recipients = [userToken]
|
||||||
if len(userToken.spectators) > 0:
|
if len(userToken.spectators) > 0:
|
||||||
recipients += userToken.spectators
|
for i in userToken.spectators:
|
||||||
|
if i in glob.tokens.tokens:
|
||||||
|
recipients.append(glob.tokens.tokens[i])
|
||||||
|
|
||||||
for i in recipients:
|
for i in recipients:
|
||||||
if i == userID:
|
if i is not None:
|
||||||
# Save some loops
|
|
||||||
token = userToken
|
|
||||||
else:
|
|
||||||
token = glob.tokens.getTokenFromUserID(i)
|
|
||||||
|
|
||||||
if token != None:
|
|
||||||
# Force our own packet
|
# Force our own packet
|
||||||
force = True if token.userID == userID else False
|
force = True if i == userToken else False
|
||||||
token.enqueue(serverPackets.userPanel(userID, force))
|
i.enqueue(serverPackets.userPanel(userID, force))
|
||||||
token.enqueue(serverPackets.userStats(userID, force))
|
i.enqueue(serverPackets.userStats(userID, force))
|
||||||
|
|
||||||
# Send osu!direct alert if needed
|
|
||||||
# NOTE: Remove this when osu!direct will be fixed
|
|
||||||
if userToken.actionID == actions.osuDirect and userToken.osuDirectAlert == False:
|
|
||||||
userToken.osuDirectAlert = True
|
|
||||||
chat.sendMessage("FokaBot", userToken.username, "Sup! osu!direct works, but you'll need to update the switcher to have the Download button working. If you didn't update the switcher yet, please do!")
|
|
||||||
|
|
||||||
|
|
||||||
# Console output
|
# Console output
|
||||||
log.info("{} changed action: {} [{}][{}]".format(username, str(userToken.actionID), userToken.actionText, userToken.actionMd5))
|
log.info("{} changed action: {} [{}][{}][{}]".format(username, str(userToken.actionID), userToken.actionText, userToken.actionMd5, userToken.beatmapID))
|
||||||
|
@@ -1,7 +1,8 @@
|
|||||||
from objects import glob
|
from common.constants import mods
|
||||||
from constants import clientPackets
|
from constants import clientPackets
|
||||||
from constants import matchModModes
|
from constants import matchModModes
|
||||||
from constants import mods
|
from objects import glob
|
||||||
|
|
||||||
|
|
||||||
def handle(userToken, packetData):
|
def handle(userToken, packetData):
|
||||||
# Get token data
|
# Get token data
|
||||||
@@ -19,25 +20,24 @@ def handle(userToken, packetData):
|
|||||||
# Set slot or match mods according to modType
|
# Set slot or match mods according to modType
|
||||||
if match.matchModMode == matchModModes.freeMod:
|
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:
|
||||||
# If host has selected DT/HT and Freemod is enabled, set DT/HT as match mod
|
# If host has selected DT/HT and Freemod is enabled, set DT/HT as match mod
|
||||||
if (packetData["mods"] & mods.DoubleTime) > 0:
|
if (packetData["mods"] & mods.DOUBLETIME) > 0:
|
||||||
match.changeMatchMods(mods.DoubleTime)
|
match.changeMods(mods.DOUBLETIME)
|
||||||
# Nighcore
|
# Nightcore
|
||||||
if (packetData["mods"] & mods.Nightcore) > 0:
|
if (packetData["mods"] & mods.NIGHTCORE) > 0:
|
||||||
match.changeMatchMods(match.mods+mods.Nightcore)
|
match.changeMods(match.mods + mods.NIGHTCORE)
|
||||||
elif (packetData["mods"] & mods.HalfTime) > 0:
|
elif (packetData["mods"] & mods.HALFTIME) > 0:
|
||||||
match.changeMatchMods(mods.HalfTime)
|
match.changeMods(mods.HALFTIME)
|
||||||
else:
|
else:
|
||||||
# No DT/HT, set global mods to 0 (we are in freemod mode)
|
# No DT/HT, set global mods to 0 (we are in freemod mode)
|
||||||
match.changeMatchMods(0)
|
match.changeMods(0)
|
||||||
|
|
||||||
# Set slot mods
|
# Set slot mods
|
||||||
slotID = match.getUserSlotID(userID)
|
slotID = match.getUserSlotID(userID)
|
||||||
if slotID != None:
|
if slotID is not None:
|
||||||
match.setSlotMods(slotID, packetData["mods"])
|
match.setSlotMods(slotID, packetData["mods"])
|
||||||
else:
|
else:
|
||||||
# Not freemod, set match mods
|
# Not freemod, set match mods
|
||||||
match.changeMatchMods(packetData["mods"])
|
match.changeMods(packetData["mods"])
|
||||||
|
@@ -13,5 +13,9 @@ def handle(userToken, packetData):
|
|||||||
# Get our match
|
# Get our match
|
||||||
match = glob.matches.matches[matchID]
|
match = glob.matches.matches[matchID]
|
||||||
|
|
||||||
|
# Host check
|
||||||
|
if userToken.userID != match.hostUserID:
|
||||||
|
return
|
||||||
|
|
||||||
# Update match password
|
# Update match password
|
||||||
match.changePassword(packetData["matchPassword"])
|
match.changePassword(packetData["matchPassword"])
|
||||||
|
@@ -1,13 +1,14 @@
|
|||||||
from objects import glob
|
import random
|
||||||
|
|
||||||
|
from common import generalUtils
|
||||||
|
from common.log import logUtils as log
|
||||||
from constants import clientPackets
|
from constants import clientPackets
|
||||||
from constants import matchModModes
|
from constants import matchModModes
|
||||||
from helpers import consoleHelper
|
|
||||||
from constants import bcolors
|
|
||||||
import random
|
|
||||||
from constants import matchTeamTypes
|
from constants import matchTeamTypes
|
||||||
from constants import matchTeams
|
from constants import matchTeams
|
||||||
from constants import slotStatuses
|
from constants import slotStatuses
|
||||||
from helpers import logHelper as log
|
from objects import glob
|
||||||
|
|
||||||
|
|
||||||
def handle(userToken, packetData):
|
def handle(userToken, packetData):
|
||||||
# Read new settings
|
# Read new settings
|
||||||
@@ -23,6 +24,10 @@ def handle(userToken, packetData):
|
|||||||
# Get match object
|
# Get match object
|
||||||
match = glob.matches.matches[matchID]
|
match = glob.matches.matches[matchID]
|
||||||
|
|
||||||
|
# Host check
|
||||||
|
if userToken.userID != match.hostUserID:
|
||||||
|
return
|
||||||
|
|
||||||
# Some dank memes easter egg
|
# Some dank memes easter egg
|
||||||
memeTitles = [
|
memeTitles = [
|
||||||
"RWC 2020",
|
"RWC 2020",
|
||||||
@@ -55,7 +60,10 @@ def handle(userToken, packetData):
|
|||||||
|
|
||||||
# Update match settings
|
# Update match settings
|
||||||
match.inProgress = packetData["inProgress"]
|
match.inProgress = packetData["inProgress"]
|
||||||
match.matchPassword = packetData["matchPassword"]
|
if packetData["matchPassword"] != "":
|
||||||
|
match.matchPassword = generalUtils.stringMd5(packetData["matchPassword"])
|
||||||
|
else:
|
||||||
|
match.matchPassword = ""
|
||||||
match.beatmapName = packetData["beatmapName"]
|
match.beatmapName = packetData["beatmapName"]
|
||||||
match.beatmapID = packetData["beatmapID"]
|
match.beatmapID = packetData["beatmapID"]
|
||||||
match.hostUserID = packetData["hostUserID"]
|
match.hostUserID = packetData["hostUserID"]
|
||||||
@@ -73,14 +81,14 @@ 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.notReady
|
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
|
||||||
else:
|
else:
|
||||||
# Reset match mods if freemod
|
# Reset match mods if freemod
|
||||||
match.mods = 0
|
match.mods = 0
|
||||||
@@ -90,21 +98,20 @@ def handle(userToken, packetData):
|
|||||||
# 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.noTeam:
|
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.noTeam
|
match.slots[i].team = matchTeams.noTeam
|
||||||
|
|
||||||
# Force no freemods if tag coop
|
# Force no freemods if tag coop
|
||||||
if match.matchTeamType == matchTeamTypes.tagCoop or match.matchTeamType == matchTeamTypes.tagTeamVs:
|
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.sendUpdate()
|
match.sendUpdates()
|
||||||
|
|
||||||
# Console output
|
# Console output
|
||||||
log.info("MPROOM{}: Updated room settings".format(match.matchID))
|
log.info("MPROOM{}: Updated room settings".format(match.matchID))
|
||||||
#consoleHelper.printColored("> MPROOM{}: DEBUG: Host is {}".format(match.matchID, match.hostUserID), bcolors.PINK)
|
|
||||||
|
@@ -1,12 +1,9 @@
|
|||||||
from constants import clientPackets
|
from constants import clientPackets
|
||||||
from objects import glob
|
from objects import glob
|
||||||
from helpers import consoleHelper
|
|
||||||
from constants import bcolors
|
|
||||||
|
|
||||||
def handle(userToken, packetData):
|
def handle(userToken, packetData):
|
||||||
# Get usertoken data
|
# Get usertoken data
|
||||||
userID = userToken.userID
|
userID = userToken.userID
|
||||||
username = userToken.username
|
|
||||||
|
|
||||||
# Read packet data
|
# Read packet data
|
||||||
packetData = clientPackets.changeSlot(packetData)
|
packetData = clientPackets.changeSlot(packetData)
|
||||||
|
@@ -1,6 +1,3 @@
|
|||||||
"""
|
|
||||||
Event called when someone parts a channel
|
|
||||||
"""
|
|
||||||
from constants import clientPackets
|
from constants import clientPackets
|
||||||
from helpers import chatHelper as chat
|
from helpers import chatHelper as chat
|
||||||
|
|
||||||
|
@@ -1,9 +1,9 @@
|
|||||||
from constants import serverPackets
|
from common.log import logUtils as log
|
||||||
from constants import clientPackets
|
from constants import clientPackets
|
||||||
from objects import glob
|
|
||||||
from events import joinMatchEvent
|
|
||||||
from constants import exceptions
|
from constants import exceptions
|
||||||
from helpers import logHelper as log
|
from constants import serverPackets
|
||||||
|
from objects import glob
|
||||||
|
|
||||||
|
|
||||||
def handle(userToken, packetData):
|
def handle(userToken, packetData):
|
||||||
try:
|
try:
|
||||||
@@ -25,17 +25,12 @@ def handle(userToken, packetData):
|
|||||||
match = glob.matches.matches[matchID]
|
match = glob.matches.matches[matchID]
|
||||||
|
|
||||||
# Join that match
|
# Join that match
|
||||||
joinMatchEvent.joinMatch(userToken, matchID, packetData["matchPassword"])
|
userToken.joinMatch(matchID)
|
||||||
|
|
||||||
# Give host to match creator
|
# Give host to match creator
|
||||||
match.setHost(userID)
|
match.setHost(userID)
|
||||||
|
match.sendUpdates()
|
||||||
# Send match create packet to everyone in lobby
|
match.changePassword(packetData["matchPassword"])
|
||||||
for i in glob.matches.usersInLobby:
|
|
||||||
# Make sure this user is still connected
|
|
||||||
token = glob.tokens.getTokenFromUserID(i)
|
|
||||||
if token != None:
|
|
||||||
token.enqueue(serverPackets.createMatch(matchID))
|
|
||||||
|
|
||||||
# Console output
|
# Console output
|
||||||
log.info("MPROOM{}: Room created!".format(matchID))
|
log.info("MPROOM{}: Room created!".format(matchID))
|
||||||
|
@@ -1,11 +1,12 @@
|
|||||||
from helpers import userHelper
|
from common.log import logUtils as log
|
||||||
|
from common.ripple import userUtils
|
||||||
from constants import clientPackets
|
from constants import clientPackets
|
||||||
from helpers import logHelper as log
|
|
||||||
|
|
||||||
def handle(userToken, packetData):
|
def handle(userToken, packetData):
|
||||||
# Friend add packet
|
# Friend add packet
|
||||||
packetData = clientPackets.addRemoveFriend(packetData)
|
packetData = clientPackets.addRemoveFriend(packetData)
|
||||||
userHelper.addFriend(userToken.userID, packetData["friendID"])
|
userUtils.addFriend(userToken.userID, packetData["friendID"])
|
||||||
|
|
||||||
# Console output
|
# Console output
|
||||||
log.info("{} have added {} to their friends".format(userToken.username, str(packetData["friendID"])))
|
log.info("{} have added {} to their friends".format(userToken.username, str(packetData["friendID"])))
|
||||||
|
@@ -1,11 +1,12 @@
|
|||||||
from helpers import userHelper
|
from common.log import logUtils as log
|
||||||
|
from common.ripple import userUtils
|
||||||
from constants import clientPackets
|
from constants import clientPackets
|
||||||
from helpers import logHelper as log
|
|
||||||
|
|
||||||
def handle(userToken, packetData):
|
def handle(userToken, packetData):
|
||||||
# Friend remove packet
|
# Friend remove packet
|
||||||
packetData = clientPackets.addRemoveFriend(packetData)
|
packetData = clientPackets.addRemoveFriend(packetData)
|
||||||
userHelper.removeFriend(userToken.userID, packetData["friendID"])
|
userUtils.removeFriend(userToken.userID, packetData["friendID"])
|
||||||
|
|
||||||
# Console output
|
# Console output
|
||||||
log.info("{} have removed {} from their friends".format(userToken.username, str(packetData["friendID"])))
|
log.info("{} have removed {} from their friends".format(userToken.username, str(packetData["friendID"])))
|
||||||
|
@@ -1,14 +1,14 @@
|
|||||||
|
from common.log import logUtils as log
|
||||||
from constants import serverPackets
|
from constants import serverPackets
|
||||||
from objects import glob
|
from objects import glob
|
||||||
from helpers import logHelper as log
|
|
||||||
|
|
||||||
def handle(userToken, _):
|
def handle(userToken, _):
|
||||||
# Get userToken data
|
# Get userToken data
|
||||||
username = userToken.username
|
username = userToken.username
|
||||||
userID = userToken.userID
|
|
||||||
|
|
||||||
# Add user to users in lobby
|
# Add user to users in lobby
|
||||||
glob.matches.lobbyUserJoin(userID)
|
userToken.joinStream("lobby")
|
||||||
|
|
||||||
# Send matches data
|
# Send matches data
|
||||||
for key, _ in glob.matches.matches.items():
|
for key, _ in glob.matches.matches.items():
|
||||||
|
@@ -1,32 +1,30 @@
|
|||||||
|
from common import generalUtils
|
||||||
|
from common.log import logUtils as log
|
||||||
from constants import clientPackets
|
from constants import clientPackets
|
||||||
|
from constants import exceptions
|
||||||
from constants import serverPackets
|
from constants import serverPackets
|
||||||
from objects import glob
|
from objects import glob
|
||||||
from constants import exceptions
|
|
||||||
from helpers import logHelper as log
|
|
||||||
from helpers import chatHelper as chat
|
|
||||||
|
|
||||||
def handle(userToken, packetData):
|
def handle(userToken, packetData):
|
||||||
# read packet data
|
# read packet data
|
||||||
packetData = clientPackets.joinMatch(packetData)
|
packetData = clientPackets.joinMatch(packetData)
|
||||||
|
matchID = packetData["matchID"]
|
||||||
|
password = packetData["password"]
|
||||||
|
|
||||||
# Get match from ID
|
# Get match from ID
|
||||||
joinMatch(userToken, packetData["matchID"], packetData["password"])
|
|
||||||
|
|
||||||
def joinMatch(userToken, matchID, password):
|
|
||||||
try:
|
try:
|
||||||
# TODO: leave other matches
|
|
||||||
# TODO: Stop spectating
|
|
||||||
|
|
||||||
# get usertoken data
|
|
||||||
userID = userToken.userID
|
|
||||||
|
|
||||||
# Make sure the match exists
|
# Make sure the match exists
|
||||||
if matchID not in glob.matches.matches:
|
if matchID not in glob.matches.matches:
|
||||||
raise exceptions.matchNotFoundException
|
return
|
||||||
|
|
||||||
# Match exists, get object
|
# Match exists, get object
|
||||||
match = glob.matches.matches[matchID]
|
match = glob.matches.matches[matchID]
|
||||||
|
|
||||||
|
# Hash password if needed
|
||||||
|
#if password != "":
|
||||||
|
# password = generalUtils.stringMd5(password)
|
||||||
|
|
||||||
# Check password
|
# Check password
|
||||||
# TODO: Admins can enter every match
|
# TODO: Admins can enter every match
|
||||||
if match.matchPassword != "":
|
if match.matchPassword != "":
|
||||||
@@ -34,24 +32,7 @@ def joinMatch(userToken, matchID, password):
|
|||||||
raise exceptions.matchWrongPasswordException
|
raise exceptions.matchWrongPasswordException
|
||||||
|
|
||||||
# Password is correct, join match
|
# Password is correct, join match
|
||||||
result = match.userJoin(userID)
|
|
||||||
|
|
||||||
# Check if we've joined the match successfully
|
|
||||||
if result == False:
|
|
||||||
raise exceptions.matchJoinErrorException
|
|
||||||
|
|
||||||
# Match joined, set matchID for usertoken
|
|
||||||
userToken.joinMatch(matchID)
|
userToken.joinMatch(matchID)
|
||||||
|
|
||||||
# Send packets
|
|
||||||
userToken.enqueue(serverPackets.matchJoinSuccess(matchID))
|
|
||||||
chat.joinChannel(token=userToken, channel="#multi_{}".format(matchID))
|
|
||||||
except exceptions.matchNotFoundException:
|
|
||||||
userToken.enqueue(serverPackets.matchJoinFail())
|
|
||||||
log.warning("{} has tried to join a mp room, but it doesn't exist".format(userToken.username))
|
|
||||||
except exceptions.matchWrongPasswordException:
|
except exceptions.matchWrongPasswordException:
|
||||||
userToken.enqueue(serverPackets.matchJoinFail())
|
userToken.enqueue(serverPackets.matchJoinFail())
|
||||||
log.warning("{} has tried to join a mp room, but he typed the wrong password".format(userToken.username))
|
log.warning("{} has tried to join a mp room, but he typed the wrong password".format(userToken.username))
|
||||||
except exceptions.matchJoinErrorException:
|
|
||||||
userToken.enqueue(serverPackets.matchJoinFail())
|
|
||||||
log.warning("{} has tried to join a mp room, but an error has occured".format(userToken.username))
|
|
||||||
|
@@ -1,20 +1,17 @@
|
|||||||
from helpers import userHelper
|
|
||||||
from constants import serverPackets
|
|
||||||
from constants import exceptions
|
|
||||||
from objects import glob
|
|
||||||
from helpers import consoleHelper
|
|
||||||
from constants import bcolors
|
|
||||||
from helpers import locationHelper
|
|
||||||
from helpers import countryHelper
|
|
||||||
import time
|
|
||||||
from helpers import generalFunctions
|
|
||||||
import sys
|
import sys
|
||||||
|
import time
|
||||||
import traceback
|
import traceback
|
||||||
from helpers import requestHelper
|
|
||||||
from helpers import discordBotHelper
|
from common.constants import privileges
|
||||||
from helpers import logHelper as log
|
from common.log import logUtils as log
|
||||||
|
from common.ripple import userUtils
|
||||||
|
from constants import exceptions
|
||||||
|
from constants import serverPackets
|
||||||
from helpers import chatHelper as chat
|
from helpers import chatHelper as chat
|
||||||
from constants import privileges
|
from helpers import countryHelper
|
||||||
|
from helpers import locationHelper
|
||||||
|
from objects import glob
|
||||||
|
|
||||||
|
|
||||||
def handle(tornadoRequest):
|
def handle(tornadoRequest):
|
||||||
# Data to return
|
# Data to return
|
||||||
@@ -37,7 +34,7 @@ def handle(tornadoRequest):
|
|||||||
|
|
||||||
# Make sure loginData is valid
|
# Make sure loginData is valid
|
||||||
if len(loginData) < 3:
|
if len(loginData) < 3:
|
||||||
raise exceptions.haxException()
|
raise exceptions.invalidArgumentsException()
|
||||||
|
|
||||||
# Get HWID, MAC address and more
|
# Get HWID, MAC address and more
|
||||||
# Structure (new line = "|", already split)
|
# Structure (new line = "|", already split)
|
||||||
@@ -56,22 +53,24 @@ def handle(tornadoRequest):
|
|||||||
|
|
||||||
# Try to get the ID from username
|
# Try to get the ID from username
|
||||||
username = str(loginData[0])
|
username = str(loginData[0])
|
||||||
userID = userHelper.getID(username)
|
userID = userUtils.getID(username)
|
||||||
|
|
||||||
if userID == False:
|
if not userID:
|
||||||
# Invalid username
|
# Invalid username
|
||||||
raise exceptions.loginFailedException()
|
raise exceptions.loginFailedException()
|
||||||
if userHelper.checkLogin(userID, loginData[1]) == False:
|
if not userUtils.checkLogin(userID, loginData[1]):
|
||||||
# Invalid password
|
# Invalid password
|
||||||
raise exceptions.loginFailedException()
|
raise exceptions.loginFailedException()
|
||||||
|
|
||||||
# Make sure we are not banned
|
# Make sure we are not banned or locked
|
||||||
priv = userHelper.getPrivileges(userID)
|
priv = userUtils.getPrivileges(userID)
|
||||||
if userHelper.isBanned(userID) == True and priv & privileges.USER_PENDING_VERIFICATION == 0:
|
if userUtils.isBanned(userID) == True and priv & privileges.USER_PENDING_VERIFICATION == 0:
|
||||||
raise exceptions.loginBannedException()
|
raise exceptions.loginBannedException()
|
||||||
|
if userUtils.isLocked(userID) == True and priv & privileges.USER_PENDING_VERIFICATION == 0:
|
||||||
|
raise exceptions.loginLockedException()
|
||||||
|
|
||||||
# 2FA check
|
# 2FA check
|
||||||
if userHelper.check2FA(userID, requestIP) == True:
|
if userUtils.check2FA(userID, requestIP):
|
||||||
log.warning("Need 2FA check for user {}".format(loginData[0]))
|
log.warning("Need 2FA check for user {}".format(loginData[0]))
|
||||||
raise exceptions.need2FAException()
|
raise exceptions.need2FAException()
|
||||||
|
|
||||||
@@ -79,8 +78,8 @@ def handle(tornadoRequest):
|
|||||||
|
|
||||||
# Verify this user (if pending activation)
|
# Verify this user (if pending activation)
|
||||||
firstLogin = False
|
firstLogin = False
|
||||||
if priv & privileges.USER_PENDING_VERIFICATION > 0 or userHelper.hasVerifiedHardware(userID) == False:
|
if priv & privileges.USER_PENDING_VERIFICATION > 0 or userUtils.hasVerifiedHardware(userID) == False:
|
||||||
if userHelper.verifyUser(userID, clientData) == True:
|
if userUtils.verifyUser(userID, clientData):
|
||||||
# Valid account
|
# Valid account
|
||||||
log.info("Account {} verified successfully!".format(userID))
|
log.info("Account {} verified successfully!".format(userID))
|
||||||
glob.verifiedCache[str(userID)] = 1
|
glob.verifiedCache[str(userID)] = 1
|
||||||
@@ -93,27 +92,38 @@ def handle(tornadoRequest):
|
|||||||
|
|
||||||
|
|
||||||
# Save HWID in db for multiaccount detection
|
# Save HWID in db for multiaccount detection
|
||||||
hwAllowed = userHelper.logHardware(userID, clientData, firstLogin)
|
hwAllowed = userUtils.logHardware(userID, clientData, firstLogin)
|
||||||
|
|
||||||
# This is false only if HWID is empty
|
# This is false only if HWID is empty
|
||||||
# if HWID is banned, we get restricted so there's no
|
# if HWID is banned, we get restricted so there's no
|
||||||
# need to deny bancho access
|
# need to deny bancho access
|
||||||
if hwAllowed == False:
|
if not hwAllowed:
|
||||||
raise exceptions.haxException()
|
raise exceptions.haxException()
|
||||||
|
|
||||||
# Log user IP
|
# Log user IP
|
||||||
userHelper.logIP(userID, requestIP)
|
userUtils.logIP(userID, requestIP)
|
||||||
|
|
||||||
# Delete old tokens for that user and generate a new one
|
# Delete old tokens for that user and generate a new one
|
||||||
|
isTournament = "tourney" in osuVersion
|
||||||
|
if not isTournament:
|
||||||
glob.tokens.deleteOldTokens(userID)
|
glob.tokens.deleteOldTokens(userID)
|
||||||
responseToken = glob.tokens.addToken(userID, requestIP, timeOffset=timeOffset)
|
responseToken = glob.tokens.addToken(userID, requestIP, timeOffset=timeOffset, tournament=isTournament)
|
||||||
responseTokenString = responseToken.token
|
responseTokenString = responseToken.token
|
||||||
|
|
||||||
# Check restricted mode (and eventually send message)
|
# Check restricted mode (and eventually send message)
|
||||||
responseToken.checkRestricted()
|
responseToken.checkRestricted()
|
||||||
|
|
||||||
|
# Send message if donor expires soon
|
||||||
|
if responseToken.privileges & privileges.USER_DONOR > 0:
|
||||||
|
expireDate = userUtils.getDonorExpire(responseToken.userID)
|
||||||
|
if expireDate-int(time.time()) <= 86400*3:
|
||||||
|
expireDays = round((expireDate-int(time.time()))/86400)
|
||||||
|
expireIn = "{} days".format(expireDays) if expireDays > 1 else "less than 24 hours"
|
||||||
|
responseToken.enqueue(serverPackets.notification("Your donor tag expires in {}! When your donor tag expires, you won't have any of the donor privileges, like yellow username, custom badge and discord custom role and username color! If you wish to keep supporting Ripple and you don't want to lose your donor privileges, you can donate again by clicking on 'Support us' on Ripple's website.".format(expireIn)))
|
||||||
|
|
||||||
|
|
||||||
# Set silence end UNIX time in token
|
# Set silence end UNIX time in token
|
||||||
responseToken.silenceEndTime = userHelper.getSilenceEnd(userID)
|
responseToken.silenceEndTime = userUtils.getSilenceEnd(userID)
|
||||||
|
|
||||||
# Get only silence remaining seconds
|
# Get only silence remaining seconds
|
||||||
silenceSeconds = responseToken.getSilenceSecondsLeft()
|
silenceSeconds = responseToken.getSilenceSecondsLeft()
|
||||||
@@ -121,11 +131,14 @@ def handle(tornadoRequest):
|
|||||||
# Get supporter/GMT
|
# Get supporter/GMT
|
||||||
userGMT = False
|
userGMT = False
|
||||||
userSupporter = True
|
userSupporter = True
|
||||||
if responseToken.admin == True:
|
userTournament = False
|
||||||
|
if responseToken.admin:
|
||||||
userGMT = True
|
userGMT = True
|
||||||
|
if responseToken.privileges & privileges.USER_TOURNAMENT_STAFF > 0:
|
||||||
|
userTournament = True
|
||||||
|
|
||||||
# Server restarting check
|
# Server restarting check
|
||||||
if glob.restarting == True:
|
if glob.restarting:
|
||||||
raise exceptions.banchoRestartingException()
|
raise exceptions.banchoRestartingException()
|
||||||
|
|
||||||
# Send login notification before maintenance message
|
# Send login notification before maintenance message
|
||||||
@@ -133,8 +146,8 @@ def handle(tornadoRequest):
|
|||||||
responseToken.enqueue(serverPackets.notification(glob.banchoConf.config["loginNotification"]))
|
responseToken.enqueue(serverPackets.notification(glob.banchoConf.config["loginNotification"]))
|
||||||
|
|
||||||
# Maintenance check
|
# Maintenance check
|
||||||
if glob.banchoConf.config["banchoMaintenance"] == True:
|
if glob.banchoConf.config["banchoMaintenance"]:
|
||||||
if userGMT == False:
|
if not userGMT:
|
||||||
# We are not mod/admin, delete token, send notification and logout
|
# We are not mod/admin, delete token, send notification and logout
|
||||||
glob.tokens.deleteToken(responseTokenString)
|
glob.tokens.deleteToken(responseTokenString)
|
||||||
raise exceptions.banchoMaintenanceException()
|
raise exceptions.banchoMaintenanceException()
|
||||||
@@ -146,7 +159,7 @@ def handle(tornadoRequest):
|
|||||||
responseToken.enqueue(serverPackets.silenceEndTime(silenceSeconds))
|
responseToken.enqueue(serverPackets.silenceEndTime(silenceSeconds))
|
||||||
responseToken.enqueue(serverPackets.userID(userID))
|
responseToken.enqueue(serverPackets.userID(userID))
|
||||||
responseToken.enqueue(serverPackets.protocolVersion())
|
responseToken.enqueue(serverPackets.protocolVersion())
|
||||||
responseToken.enqueue(serverPackets.userSupporterGMT(userSupporter, userGMT))
|
responseToken.enqueue(serverPackets.userSupporterGMT(userSupporter, userGMT, userTournament))
|
||||||
responseToken.enqueue(serverPackets.userPanel(userID, True))
|
responseToken.enqueue(serverPackets.userPanel(userID, True))
|
||||||
responseToken.enqueue(serverPackets.userStats(userID, True))
|
responseToken.enqueue(serverPackets.userStats(userID, True))
|
||||||
|
|
||||||
@@ -158,7 +171,7 @@ def handle(tornadoRequest):
|
|||||||
chat.joinChannel(token=responseToken, channel="#announce")
|
chat.joinChannel(token=responseToken, channel="#announce")
|
||||||
|
|
||||||
# Join admin channel if we are an admin
|
# Join admin channel if we are an admin
|
||||||
if responseToken.admin == True:
|
if responseToken.admin:
|
||||||
chat.joinChannel(token=responseToken, channel="#admin")
|
chat.joinChannel(token=responseToken, channel="#admin")
|
||||||
|
|
||||||
# Output channels info
|
# Output channels info
|
||||||
@@ -177,7 +190,7 @@ def handle(tornadoRequest):
|
|||||||
responseToken.enqueue(serverPackets.onlineUsers())
|
responseToken.enqueue(serverPackets.onlineUsers())
|
||||||
|
|
||||||
# Get location and country from ip.zxq.co or database
|
# Get location and country from ip.zxq.co or database
|
||||||
if glob.localize == True:
|
if glob.localize:
|
||||||
# Get location and country from IP
|
# Get location and country from IP
|
||||||
location = locationHelper.getLocation(requestIP)
|
location = locationHelper.getLocation(requestIP)
|
||||||
countryLetters = locationHelper.getCountry(requestIP)
|
countryLetters = locationHelper.getCountry(requestIP)
|
||||||
@@ -187,19 +200,19 @@ def handle(tornadoRequest):
|
|||||||
log.warning("Location skipped")
|
log.warning("Location skipped")
|
||||||
location = [0,0]
|
location = [0,0]
|
||||||
countryLetters = "XX"
|
countryLetters = "XX"
|
||||||
country = countryHelper.getCountryID(userHelper.getCountry(userID))
|
country = countryHelper.getCountryID(userUtils.getCountry(userID))
|
||||||
|
|
||||||
# Set location and country
|
# Set location and country
|
||||||
responseToken.setLocation(location)
|
responseToken.setLocation(location)
|
||||||
responseToken.setCountry(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 userHelper.getCountry(userID) == "XX":
|
if userUtils.getCountry(userID) == "XX":
|
||||||
userHelper.setCountry(userID, countryLetters)
|
userUtils.setCountry(userID, countryLetters)
|
||||||
|
|
||||||
# Send to everyone our userpanel if we are not restricted
|
# Send to everyone our userpanel if we are not restricted or tournament
|
||||||
if responseToken.restricted == False:
|
if not responseToken.restricted:
|
||||||
glob.tokens.enqueueAll(serverPackets.userPanel(userID))
|
glob.streams.broadcast("main", serverPackets.userPanel(userID))
|
||||||
|
|
||||||
# Set reponse data to right value and reset our queue
|
# Set reponse data to right value and reset our queue
|
||||||
responseData = responseToken.queue
|
responseData = responseToken.queue
|
||||||
@@ -209,7 +222,7 @@ def handle(tornadoRequest):
|
|||||||
# (we don't use enqueue because we don't have a token since login has failed)
|
# (we don't use enqueue because we don't have a token since login has failed)
|
||||||
err = True
|
err = True
|
||||||
responseData += serverPackets.loginFailed()
|
responseData += serverPackets.loginFailed()
|
||||||
except exceptions.haxException:
|
except exceptions.invalidArgumentsException:
|
||||||
# Invalid POST data
|
# Invalid POST data
|
||||||
# (we don't use enqueue because we don't have a token since login has failed)
|
# (we don't use enqueue because we don't have a token since login has failed)
|
||||||
err = True
|
err = True
|
||||||
@@ -219,6 +232,10 @@ def handle(tornadoRequest):
|
|||||||
# Login banned error packet
|
# Login banned error packet
|
||||||
err = True
|
err = True
|
||||||
responseData += serverPackets.loginBanned()
|
responseData += serverPackets.loginBanned()
|
||||||
|
except exceptions.loginLockedException:
|
||||||
|
# Login banned error packet
|
||||||
|
err = True
|
||||||
|
responseData += serverPackets.loginLocked()
|
||||||
except exceptions.banchoMaintenanceException:
|
except exceptions.banchoMaintenanceException:
|
||||||
# Bancho is in maintenance mode
|
# Bancho is in maintenance mode
|
||||||
responseData = responseToken.queue
|
responseData = responseToken.queue
|
||||||
@@ -236,7 +253,7 @@ def handle(tornadoRequest):
|
|||||||
# (we don't use enqueue because we don't have a token since login has failed)
|
# (we don't use enqueue because we don't have a token since login has failed)
|
||||||
err = True
|
err = True
|
||||||
responseData += serverPackets.forceUpdate()
|
responseData += serverPackets.forceUpdate()
|
||||||
responseData += serverPackets.notification("Hory shitto, your client is TOO old! Nice preistoria! Please turn off the switcher and update it.")
|
responseData += serverPackets.notification("Hory shitto, your client is TOO old! Nice prehistory! Please turn update it from the settings!")
|
||||||
except:
|
except:
|
||||||
log.error("Unknown error!\n```\n{}\n{}```".format(sys.exc_info(), traceback.format_exc()))
|
log.error("Unknown error!\n```\n{}\n{}```".format(sys.exc_info(), traceback.format_exc()))
|
||||||
finally:
|
finally:
|
||||||
@@ -248,4 +265,4 @@ def handle(tornadoRequest):
|
|||||||
log.info(msg, "bunker")
|
log.info(msg, "bunker")
|
||||||
|
|
||||||
# Return token string and data
|
# Return token string and data
|
||||||
return (responseTokenString, responseData)
|
return responseTokenString, responseData
|
@@ -1,10 +1,10 @@
|
|||||||
from objects import glob
|
|
||||||
from helpers import consoleHelper
|
|
||||||
from constants import bcolors
|
|
||||||
from constants import serverPackets
|
|
||||||
import time
|
import time
|
||||||
from helpers import logHelper as log
|
|
||||||
|
from common.log import logUtils as log
|
||||||
|
from constants import serverPackets
|
||||||
from helpers import chatHelper as chat
|
from helpers import chatHelper as chat
|
||||||
|
from objects import glob
|
||||||
|
|
||||||
|
|
||||||
def handle(userToken, _=None):
|
def handle(userToken, _=None):
|
||||||
# get usertoken data
|
# get usertoken data
|
||||||
@@ -16,24 +16,22 @@ def handle(userToken, _=None):
|
|||||||
# the old logout packet will still be in the queue and will be sent to
|
# the old logout packet will still be in the queue and will be sent to
|
||||||
# the server, so we accept logout packets sent at least 5 seconds after login
|
# the server, so we accept logout packets sent at least 5 seconds after login
|
||||||
# if the user logs out before 5 seconds, he will be disconnected later with timeout check
|
# if the user logs out before 5 seconds, he will be disconnected later with timeout check
|
||||||
if int(time.time()-userToken.loginTime) >= 5 or userToken.irc == True:
|
if (int(time.time()-userToken.loginTime) >= 5 or userToken.irc):
|
||||||
# Stop spectating if needed
|
# Stop spectating
|
||||||
# TODO: Call stopSpectatingEvent!!!!!!!!!
|
userToken.stopSpectating()
|
||||||
if userToken.spectating != 0:
|
|
||||||
# The user was spectating someone
|
# Part matches
|
||||||
spectatorHostToken = glob.tokens.getTokenFromUserID(userToken.spectating)
|
userToken.leaveMatch()
|
||||||
if spectatorHostToken != None:
|
|
||||||
# The host is still online, send removeSpectator to him
|
|
||||||
spectatorHostToken.enqueue(serverPackets.removeSpectator(userID))
|
|
||||||
|
|
||||||
# Part all joined channels
|
# Part all joined channels
|
||||||
for i in userToken.joinedChannels:
|
for i in userToken.joinedChannels:
|
||||||
chat.partChannel(token=userToken, channel=i)
|
chat.partChannel(token=userToken, channel=i)
|
||||||
|
|
||||||
# TODO: Lobby left if joined
|
# Leave all joined streams
|
||||||
|
userToken.leaveAllStreams()
|
||||||
|
|
||||||
# Enqueue our disconnection to everyone else
|
# Enqueue our disconnection to everyone else
|
||||||
glob.tokens.enqueueAll(serverPackets.userLogout(userID))
|
glob.streams.broadcast("main", serverPackets.userLogout(userID))
|
||||||
|
|
||||||
# Disconnect from IRC if needed
|
# Disconnect from IRC if needed
|
||||||
if userToken.irc == True and glob.irc == True:
|
if userToken.irc == True and glob.irc == True:
|
||||||
@@ -43,4 +41,4 @@ def handle(userToken, _=None):
|
|||||||
glob.tokens.deleteToken(requestToken)
|
glob.tokens.deleteToken(requestToken)
|
||||||
|
|
||||||
# Console output
|
# Console output
|
||||||
log.info("{} has been disconnected.".format(username))
|
log.info("{} has been disconnected. (logout)".format(username))
|
||||||
|
@@ -1,7 +1,6 @@
|
|||||||
from objects import glob
|
from objects import glob
|
||||||
from constants import slotStatuses
|
from constants import slotStatuses
|
||||||
from constants import serverPackets
|
from constants import serverPackets
|
||||||
from helpers import logHelper as log
|
|
||||||
|
|
||||||
def handle(userToken, packetData):
|
def handle(userToken, packetData):
|
||||||
# Get usertoken data
|
# Get usertoken data
|
||||||
@@ -25,8 +24,4 @@ def handle(userToken, packetData):
|
|||||||
slotID = match.getUserSlotID(userID)
|
slotID = match.getUserSlotID(userID)
|
||||||
|
|
||||||
# Enqueue frames to who's playing
|
# Enqueue frames to who's playing
|
||||||
for i in range(0,16):
|
glob.streams.broadcast(match.playingStreamName, serverPackets.matchFrames(slotID, packetData))
|
||||||
if match.slots[i]["userID"] > -1 and match.slots[i]["status"] == slotStatuses.playing:
|
|
||||||
token = glob.tokens.getTokenFromUserID(match.slots[i]["userID"])
|
|
||||||
if token != None:
|
|
||||||
token.enqueue(serverPackets.matchFrames(slotID, packetData))
|
|
@@ -1,3 +1,4 @@
|
|||||||
from events import matchBeatmapEvent
|
from events import matchBeatmapEvent
|
||||||
|
|
||||||
def handle(userToken, packetData):
|
def handle(userToken, packetData):
|
||||||
matchBeatmapEvent.handle(userToken, packetData, True)
|
matchBeatmapEvent.handle(userToken, packetData, True)
|
||||||
|
@@ -14,6 +14,10 @@ def handle(userToken, packetData):
|
|||||||
return
|
return
|
||||||
match = glob.matches.matches[matchID]
|
match = glob.matches.matches[matchID]
|
||||||
|
|
||||||
|
# Host check
|
||||||
|
if userID != match.hostUserID:
|
||||||
|
return
|
||||||
|
|
||||||
# Make sure we aren't locking our slot
|
# Make sure we aren't locking our slot
|
||||||
ourSlot = match.getUserSlotID(userID)
|
ourSlot = match.getUserSlotID(userID)
|
||||||
if packetData["slotID"] == ourSlot:
|
if packetData["slotID"] == ourSlot:
|
||||||
|
@@ -1,3 +1,4 @@
|
|||||||
from events import matchBeatmapEvent
|
from events import matchBeatmapEvent
|
||||||
|
|
||||||
def handle(userToken, packetData):
|
def handle(userToken, packetData):
|
||||||
matchBeatmapEvent.handle(userToken, packetData, False)
|
matchBeatmapEvent.handle(userToken, packetData, False)
|
||||||
|
@@ -12,5 +12,5 @@ def handle(userToken, _):
|
|||||||
|
|
||||||
# Get our slotID and change ready status
|
# Get our slotID and change ready status
|
||||||
slotID = match.getUserSlotID(userID)
|
slotID = match.getUserSlotID(userID)
|
||||||
if slotID != None:
|
if slotID is not None:
|
||||||
match.toggleSlotReady(slotID)
|
match.toggleSlotReady(slotID)
|
||||||
|
@@ -3,7 +3,6 @@ from constants import slotStatuses
|
|||||||
from constants import serverPackets
|
from constants import serverPackets
|
||||||
|
|
||||||
def handle(userToken, _):
|
def handle(userToken, _):
|
||||||
# TODO: Host check
|
|
||||||
|
|
||||||
# Get match ID and match object
|
# Get match ID and match object
|
||||||
matchID = userToken.matchID
|
matchID = userToken.matchID
|
||||||
@@ -19,29 +18,8 @@ def handle(userToken, _):
|
|||||||
# The match exists, get object
|
# The match exists, get object
|
||||||
match = glob.matches.matches[matchID]
|
match = glob.matches.matches[matchID]
|
||||||
|
|
||||||
force = False # TODO: Force thing
|
# Host check
|
||||||
|
if userToken.userID != match.hostUserID:
|
||||||
# Make sure we have enough players
|
|
||||||
if (match.countUsers() < 2 or not match.checkTeams()) and not force:
|
|
||||||
return
|
return
|
||||||
|
|
||||||
# Change inProgress value
|
match.start()
|
||||||
match.inProgress = True
|
|
||||||
|
|
||||||
# Set playing to ready players and set load, skip and complete to False
|
|
||||||
for i in range(0,16):
|
|
||||||
if (match.slots[i]["status"] & slotStatuses.ready) > 0:
|
|
||||||
match.slots[i]["status"] = slotStatuses.playing
|
|
||||||
match.slots[i]["loaded"] = False
|
|
||||||
match.slots[i]["skip"] = False
|
|
||||||
match.slots[i]["complete"] = False
|
|
||||||
|
|
||||||
# Send match start packet
|
|
||||||
for i in range(0,16):
|
|
||||||
if (match.slots[i]["status"] & slotStatuses.playing) > 0 and match.slots[i]["userID"] != -1:
|
|
||||||
token = glob.tokens.getTokenFromUserID(match.slots[i]["userID"])
|
|
||||||
if token != None:
|
|
||||||
token.enqueue(serverPackets.matchStart(matchID))
|
|
||||||
|
|
||||||
# Send updates
|
|
||||||
match.sendUpdate()
|
|
||||||
|
@@ -19,5 +19,9 @@ def handle(userToken, packetData):
|
|||||||
# Match exists, get object
|
# Match exists, get object
|
||||||
match = glob.matches.matches[matchID]
|
match = glob.matches.matches[matchID]
|
||||||
|
|
||||||
|
# Host check
|
||||||
|
if userToken.userID != match.hostUserID:
|
||||||
|
return
|
||||||
|
|
||||||
# Transfer host
|
# Transfer host
|
||||||
match.transferHost(packetData["slotID"])
|
match.transferHost(packetData["slotID"])
|
||||||
|
@@ -1,7 +1,7 @@
|
|||||||
from objects import glob
|
from common.log import logUtils as log
|
||||||
from events import channelPartEvent
|
|
||||||
from helpers import logHelper as log
|
|
||||||
from helpers import chatHelper as chat
|
from helpers import chatHelper as chat
|
||||||
|
from objects import glob
|
||||||
|
|
||||||
|
|
||||||
def handle(userToken, _):
|
def handle(userToken, _):
|
||||||
# Get usertoken data
|
# Get usertoken data
|
||||||
@@ -9,7 +9,7 @@ def handle(userToken, _):
|
|||||||
username = userToken.username
|
username = userToken.username
|
||||||
|
|
||||||
# Remove user from users in lobby
|
# Remove user from users in lobby
|
||||||
glob.matches.lobbyUserPart(userID)
|
userToken.leaveStream("lobby")
|
||||||
|
|
||||||
# Part lobby channel
|
# Part lobby channel
|
||||||
chat.partChannel(channel="#lobby", token=userToken, kick=True)
|
chat.partChannel(channel="#lobby", token=userToken, kick=True)
|
||||||
|
@@ -1,29 +1,2 @@
|
|||||||
from objects import glob
|
def handle(userToken, _=None):
|
||||||
from helpers import chatHelper as chat
|
userToken.leaveMatch()
|
||||||
|
|
||||||
def handle(userToken, _):
|
|
||||||
# get data from usertoken
|
|
||||||
userID = userToken.userID
|
|
||||||
|
|
||||||
# Get match ID and match object
|
|
||||||
matchID = userToken.matchID
|
|
||||||
|
|
||||||
# Make sure we are in a match
|
|
||||||
if matchID == -1:
|
|
||||||
return
|
|
||||||
|
|
||||||
# Make sure the match exists
|
|
||||||
if matchID not in glob.matches.matches:
|
|
||||||
return
|
|
||||||
|
|
||||||
# The match exists, get object
|
|
||||||
match = glob.matches.matches[matchID]
|
|
||||||
|
|
||||||
# Set slot to free
|
|
||||||
match.userLeft(userID)
|
|
||||||
|
|
||||||
# Part #multiplayer channel
|
|
||||||
#chat.partChannel(token=userToken, channel="#multi_{}".format(matchID), kick=True)
|
|
||||||
|
|
||||||
# Set usertoken match to -1
|
|
||||||
userToken.partMatch()
|
|
@@ -1,11 +1,7 @@
|
|||||||
from constants import clientPackets
|
|
||||||
from constants import serverPackets
|
from constants import serverPackets
|
||||||
from helpers import userHelper
|
|
||||||
from helpers import logHelper as log
|
|
||||||
|
|
||||||
def handle(userToken, packetData):
|
def handle(userToken, packetData):
|
||||||
log.debug("Requested status update")
|
|
||||||
|
|
||||||
# Update cache and send new stats
|
# Update cache and send new stats
|
||||||
userToken.updateCachedStats()
|
userToken.updateCachedStats()
|
||||||
userToken.enqueue(serverPackets.userStats(userToken.userID))
|
userToken.enqueue(serverPackets.userStats(userToken.userID))
|
||||||
|
@@ -1,6 +1,7 @@
|
|||||||
|
from common.log import logUtils as log
|
||||||
from constants import clientPackets
|
from constants import clientPackets
|
||||||
from constants import serverPackets
|
from constants import serverPackets
|
||||||
from helpers import logHelper as log
|
|
||||||
|
|
||||||
def handle(userToken, packetData):
|
def handle(userToken, packetData):
|
||||||
# get token data
|
# get token data
|
||||||
|
@@ -7,7 +7,8 @@ def handle(userToken, packetData):
|
|||||||
userID = userToken.userID
|
userID = userToken.userID
|
||||||
|
|
||||||
# Send spectator frames to every spectator
|
# Send spectator frames to every spectator
|
||||||
for i in userToken.spectators:
|
glob.streams.broadcast("spect/{}".format(userID), serverPackets.spectatorFrames(packetData[7:]))
|
||||||
|
'''for i in userToken.spectators:
|
||||||
# Send to every user but host
|
# Send to every user but host
|
||||||
if i != userID:
|
if i != userID:
|
||||||
try:
|
try:
|
||||||
@@ -15,7 +16,7 @@ def handle(userToken, packetData):
|
|||||||
spectatorToken = glob.tokens.getTokenFromUserID(i)
|
spectatorToken = glob.tokens.getTokenFromUserID(i)
|
||||||
|
|
||||||
# Make sure the token exists
|
# Make sure the token exists
|
||||||
if spectatorToken == None:
|
if spectatorToken is None:
|
||||||
raise exceptions.stopSpectating
|
raise exceptions.stopSpectating
|
||||||
|
|
||||||
# Make sure this user is spectating us
|
# Make sure this user is spectating us
|
||||||
@@ -27,4 +28,4 @@ def handle(userToken, packetData):
|
|||||||
except exceptions.stopSpectating:
|
except exceptions.stopSpectating:
|
||||||
# Remove this user from spectators
|
# Remove this user from spectators
|
||||||
userToken.removeSpectator(i)
|
userToken.removeSpectator(i)
|
||||||
userToken.enqueue(serverPackets.removeSpectator(i))
|
userToken.enqueue(serverPackets.removeSpectator(i))'''
|
||||||
|
@@ -1,56 +1,20 @@
|
|||||||
|
from common.log import logUtils as log
|
||||||
from constants import clientPackets
|
from constants import clientPackets
|
||||||
from constants import serverPackets
|
|
||||||
from constants import exceptions
|
from constants import exceptions
|
||||||
from objects import glob
|
from objects import glob
|
||||||
from helpers import userHelper
|
|
||||||
from helpers import logHelper as log
|
|
||||||
from helpers import chatHelper as chat
|
|
||||||
|
|
||||||
def handle(userToken, packetData):
|
def handle(userToken, packetData):
|
||||||
try:
|
try:
|
||||||
# Get usertoken data
|
|
||||||
userID = userToken.userID
|
|
||||||
username = userToken.username
|
|
||||||
|
|
||||||
# Start spectating packet
|
# Start spectating packet
|
||||||
packetData = clientPackets.startSpectating(packetData)
|
packetData = clientPackets.startSpectating(packetData)
|
||||||
|
|
||||||
# Stop spectating old user if needed
|
|
||||||
if userToken.spectating != 0:
|
|
||||||
oldTargetToken = glob.tokens.getTokenFromUserID(userToken.spectating)
|
|
||||||
oldTargetToken.enqueue(serverPackets.removeSpectator(userID))
|
|
||||||
userToken.stopSpectating()
|
|
||||||
|
|
||||||
# Start spectating new user
|
|
||||||
userToken.startSpectating(packetData["userID"])
|
|
||||||
|
|
||||||
# Get host token
|
# Get host token
|
||||||
targetToken = glob.tokens.getTokenFromUserID(packetData["userID"])
|
targetToken = glob.tokens.getTokenFromUserID(packetData["userID"])
|
||||||
if targetToken == None:
|
if targetToken is None:
|
||||||
raise exceptions.tokenNotFoundException
|
raise exceptions.tokenNotFoundException
|
||||||
|
|
||||||
# Add us to host's spectators
|
# Start spectating new user
|
||||||
targetToken.addSpectator(userID)
|
userToken.startSpectating(targetToken)
|
||||||
|
|
||||||
# Send spectator join packet to host
|
|
||||||
targetToken.enqueue(serverPackets.addSpectator(userID))
|
|
||||||
|
|
||||||
# Create and join #spectator (#spect_userid) channel
|
|
||||||
glob.channels.addTempChannel("#spect_{}".format(targetToken.userID))
|
|
||||||
chat.joinChannel(token=userToken, channel="#spect_{}".format(targetToken.userID))
|
|
||||||
if len(targetToken.spectators) == 1:
|
|
||||||
# First spectator, send #spectator join to host too
|
|
||||||
chat.joinChannel(token=targetToken, channel="#spect_{}".format(targetToken.userID))
|
|
||||||
|
|
||||||
# send fellowSpectatorJoined to all spectators
|
|
||||||
for spec in targetToken.spectators:
|
|
||||||
if spec is not userID:
|
|
||||||
c = glob.tokens.getTokenFromUserID(spec)
|
|
||||||
userToken.enqueue(serverPackets.fellowSpectatorJoined(c.userID))
|
|
||||||
c.enqueue(serverPackets.fellowSpectatorJoined(userID))
|
|
||||||
|
|
||||||
# Console output
|
|
||||||
log.info("{} are spectating {}".format(username, userHelper.getUsername(packetData["userID"])))
|
|
||||||
except exceptions.tokenNotFoundException:
|
except exceptions.tokenNotFoundException:
|
||||||
# Stop spectating if token not found
|
# Stop spectating if token not found
|
||||||
log.warning("Spectator start: token not found")
|
log.warning("Spectator start: token not found")
|
||||||
|
@@ -1,37 +1,2 @@
|
|||||||
from objects import glob
|
def handle(userToken, _=None):
|
||||||
from constants import serverPackets
|
|
||||||
from constants import exceptions
|
|
||||||
from helpers import logHelper as log
|
|
||||||
from helpers import chatHelper as chat
|
|
||||||
|
|
||||||
def handle(userToken, _):
|
|
||||||
try:
|
|
||||||
# get user token data
|
|
||||||
userID = userToken.userID
|
|
||||||
username = userToken.username
|
|
||||||
|
|
||||||
# Remove our userID from host's spectators
|
|
||||||
target = userToken.spectating
|
|
||||||
targetToken = glob.tokens.getTokenFromUserID(target)
|
|
||||||
if targetToken == None:
|
|
||||||
raise exceptions.tokenNotFoundException
|
|
||||||
targetToken.removeSpectator(userID)
|
|
||||||
|
|
||||||
# Part #spectator channel
|
|
||||||
chat.partChannel(token=userToken, channel="#spect_{}".format(target))
|
|
||||||
|
|
||||||
# Send the spectator left packet to host
|
|
||||||
targetToken.enqueue(serverPackets.removeSpectator(userID))
|
|
||||||
for c in targetToken.spectators:
|
|
||||||
spec = glob.tokens.getTokenFromUserID(c)
|
|
||||||
spec.enqueue(serverPackets.fellowSpectatorLeft(userID))
|
|
||||||
|
|
||||||
#targetToken.enqueue(serverPackets.fellowSpectatorLeft(userID))
|
|
||||||
|
|
||||||
# Console output
|
|
||||||
log.info("{} are no longer spectating {}".format(username, target))
|
|
||||||
except exceptions.tokenNotFoundException:
|
|
||||||
log.warning("Spectator stop: token not found")
|
|
||||||
finally:
|
|
||||||
# Set our spectating user to 0
|
|
||||||
userToken.stopSpectating()
|
userToken.stopSpectating()
|
||||||
|
11
events/tournamentJoinMatchChannelEvent.py
Normal file
11
events/tournamentJoinMatchChannelEvent.py
Normal file
@@ -0,0 +1,11 @@
|
|||||||
|
from constants import clientPackets
|
||||||
|
from objects import glob
|
||||||
|
from helpers import chatHelper as chat
|
||||||
|
|
||||||
|
def handle(userToken, packetData):
|
||||||
|
packetData = clientPackets.tournamentJoinMatchChannel(packetData)
|
||||||
|
matchID = packetData["matchID"]
|
||||||
|
if matchID not in glob.matches.matches:
|
||||||
|
return
|
||||||
|
userToken.matchID = matchID
|
||||||
|
chat.joinChannel(token=userToken, channel="#multi_{}".format(matchID))
|
11
events/tournamentLeaveMatchChannelEvent.py
Normal file
11
events/tournamentLeaveMatchChannelEvent.py
Normal file
@@ -0,0 +1,11 @@
|
|||||||
|
from constants import clientPackets
|
||||||
|
from objects import glob
|
||||||
|
from helpers import chatHelper as chat
|
||||||
|
|
||||||
|
def handle(userToken, packetData):
|
||||||
|
packetData = clientPackets.tournamentLeaveMatchChannel(packetData)
|
||||||
|
matchID = packetData["matchID"]
|
||||||
|
if matchID not in glob.matches.matches:
|
||||||
|
return
|
||||||
|
chat.partChannel(token=userToken, channel="#multi_{}".format(matchID))
|
||||||
|
userToken.matchID = 0
|
10
events/tournamentMatchInfoRequestEvent.py
Normal file
10
events/tournamentMatchInfoRequestEvent.py
Normal file
@@ -0,0 +1,10 @@
|
|||||||
|
from constants import clientPackets
|
||||||
|
from constants import serverPackets
|
||||||
|
from objects import glob
|
||||||
|
|
||||||
|
def handle(userToken, packetData):
|
||||||
|
packetData = clientPackets.tournamentMatchInfoRequest(packetData)
|
||||||
|
matchID = packetData["matchID"]
|
||||||
|
if matchID not in glob.matches.matches:
|
||||||
|
return
|
||||||
|
userToken.enqueue(glob.matches.matches[matchID].matchDataCache)
|
@@ -1,6 +1,7 @@
|
|||||||
|
from common.log import logUtils as log
|
||||||
from constants import clientPackets
|
from constants import clientPackets
|
||||||
from constants import serverPackets
|
from constants import serverPackets
|
||||||
from helpers import logHelper as log
|
|
||||||
|
|
||||||
def handle(userToken, packetData):
|
def handle(userToken, packetData):
|
||||||
# Read userIDs list
|
# Read userIDs list
|
||||||
|
@@ -1,6 +1,7 @@
|
|||||||
|
from common.log import logUtils as log
|
||||||
from constants import clientPackets
|
from constants import clientPackets
|
||||||
from constants import serverPackets
|
from constants import serverPackets
|
||||||
from helpers import logHelper as log
|
|
||||||
|
|
||||||
def handle(userToken, packetData):
|
def handle(userToken, packetData):
|
||||||
# Read userIDs list
|
# Read userIDs list
|
||||||
|
@@ -1,17 +1,19 @@
|
|||||||
from helpers import requestHelper
|
|
||||||
from constants import exceptions
|
|
||||||
import json
|
import json
|
||||||
from objects import glob
|
|
||||||
from helpers import chatHelper
|
|
||||||
from helpers import logHelper as log
|
|
||||||
|
|
||||||
class handler(requestHelper.asyncRequestHandler):
|
from common.log import logUtils as log
|
||||||
|
from common.web import requestsManager
|
||||||
|
from constants import exceptions
|
||||||
|
from helpers import chatHelper
|
||||||
|
from objects import glob
|
||||||
|
|
||||||
|
|
||||||
|
class handler(requestsManager.asyncRequestHandler):
|
||||||
def asyncGet(self):
|
def asyncGet(self):
|
||||||
statusCode = 400
|
statusCode = 400
|
||||||
data = {"message": "unknown error"}
|
data = {"message": "unknown error"}
|
||||||
try:
|
try:
|
||||||
# Check arguments
|
# Check arguments
|
||||||
if requestHelper.checkArguments(self.request.arguments, ["k", "to", "msg"]) == False:
|
if not requestsManager.checkArguments(self.request.arguments, ["k", "to", "msg"]):
|
||||||
raise exceptions.invalidArgumentsException()
|
raise exceptions.invalidArgumentsException()
|
||||||
|
|
||||||
# Check ci key
|
# Check ci key
|
@@ -1,23 +1,37 @@
|
|||||||
from helpers import requestHelper
|
|
||||||
from constants import exceptions
|
|
||||||
import json
|
import json
|
||||||
|
|
||||||
|
from common.web import requestsManager
|
||||||
|
from constants import exceptions
|
||||||
from objects import glob
|
from objects import glob
|
||||||
|
|
||||||
class handler(requestHelper.asyncRequestHandler):
|
|
||||||
|
class handler(requestsManager.asyncRequestHandler):
|
||||||
def asyncGet(self):
|
def asyncGet(self):
|
||||||
statusCode = 400
|
statusCode = 400
|
||||||
data = {"message": "unknown error"}
|
data = {"message": "unknown error"}
|
||||||
try:
|
try:
|
||||||
# Check arguments
|
# Check arguments
|
||||||
if requestHelper.checkArguments(self.request.arguments, ["u"]) == False:
|
if "u" not in self.request.arguments and "id" not in self.request.arguments:
|
||||||
raise exceptions.invalidArgumentsException()
|
raise exceptions.invalidArgumentsException()
|
||||||
|
|
||||||
# Get online staus
|
# Get online staus
|
||||||
|
username = None
|
||||||
|
userID = None
|
||||||
|
if "u" in self.request.arguments:
|
||||||
username = self.get_argument("u")
|
username = self.get_argument("u")
|
||||||
if username == None:
|
else:
|
||||||
|
try:
|
||||||
|
userID = int(self.get_argument("id"))
|
||||||
|
except:
|
||||||
|
raise exceptions.invalidArgumentsException()
|
||||||
|
|
||||||
|
if username is None and userID is None:
|
||||||
data["result"] = False
|
data["result"] = False
|
||||||
else:
|
else:
|
||||||
data["result"] = True if glob.tokens.getTokenFromUsername(username) != None else False
|
if username is not None:
|
||||||
|
data["result"] = True if glob.tokens.getTokenFromUsername(username) is not None else False
|
||||||
|
else:
|
||||||
|
data["result"] = True if glob.tokens.getTokenFromUserID(userID) is not None else False
|
||||||
|
|
||||||
# Status code and message
|
# Status code and message
|
||||||
statusCode = 200
|
statusCode = 200
|
||||||
|
@@ -1,8 +1,10 @@
|
|||||||
from helpers import requestHelper
|
|
||||||
import json
|
import json
|
||||||
|
|
||||||
|
from common.web import requestsManager
|
||||||
from objects import glob
|
from objects import glob
|
||||||
|
|
||||||
class handler(requestHelper.asyncRequestHandler):
|
|
||||||
|
class handler(requestsManager.asyncRequestHandler):
|
||||||
def asyncGet(self):
|
def asyncGet(self):
|
||||||
statusCode = 400
|
statusCode = 400
|
||||||
data = {"message": "unknown error"}
|
data = {"message": "unknown error"}
|
||||||
|
@@ -1,8 +1,10 @@
|
|||||||
from helpers import requestHelper
|
|
||||||
import json
|
import json
|
||||||
|
|
||||||
|
from common.web import requestsManager
|
||||||
from objects import glob
|
from objects import glob
|
||||||
|
|
||||||
class handler(requestHelper.asyncRequestHandler):
|
|
||||||
|
class handler(requestsManager.asyncRequestHandler):
|
||||||
def asyncGet(self):
|
def asyncGet(self):
|
||||||
statusCode = 400
|
statusCode = 400
|
||||||
data = {"message": "unknown error"}
|
data = {"message": "unknown error"}
|
||||||
|
@@ -1,16 +1,17 @@
|
|||||||
from helpers import requestHelper
|
|
||||||
from helpers import logHelper as log
|
|
||||||
import json
|
import json
|
||||||
from objects import glob
|
|
||||||
from constants import exceptions
|
|
||||||
|
|
||||||
class handler(requestHelper.asyncRequestHandler):
|
from common.web import requestsManager
|
||||||
|
from constants import exceptions
|
||||||
|
from objects import glob
|
||||||
|
|
||||||
|
|
||||||
|
class handler(requestsManager.asyncRequestHandler):
|
||||||
def asyncGet(self):
|
def asyncGet(self):
|
||||||
statusCode = 400
|
statusCode = 400
|
||||||
data = {"message": "unknown error"}
|
data = {"message": "unknown error"}
|
||||||
try:
|
try:
|
||||||
# Check arguments
|
# Check arguments
|
||||||
if requestHelper.checkArguments(self.request.arguments, ["u"]) == False:
|
if not requestsManager.checkArguments(self.request.arguments, ["u"]):
|
||||||
raise exceptions.invalidArgumentsException()
|
raise exceptions.invalidArgumentsException()
|
||||||
|
|
||||||
# Get userID and its verified cache thing
|
# Get userID and its verified cache thing
|
||||||
|
@@ -1,17 +1,19 @@
|
|||||||
from helpers import requestHelper
|
|
||||||
from constants import exceptions
|
|
||||||
import json
|
import json
|
||||||
from objects import glob
|
|
||||||
from helpers import systemHelper
|
|
||||||
from helpers import logHelper as log
|
|
||||||
|
|
||||||
class handler(requestHelper.asyncRequestHandler):
|
from common.log import logUtils as log
|
||||||
|
from common.web import requestsManager
|
||||||
|
from constants import exceptions
|
||||||
|
from helpers import systemHelper
|
||||||
|
from objects import glob
|
||||||
|
|
||||||
|
|
||||||
|
class handler(requestsManager.asyncRequestHandler):
|
||||||
def asyncGet(self):
|
def asyncGet(self):
|
||||||
statusCode = 400
|
statusCode = 400
|
||||||
data = {"message": "unknown error"}
|
data = {"message": "unknown error"}
|
||||||
try:
|
try:
|
||||||
# Check arguments
|
# Check arguments
|
||||||
if requestHelper.checkArguments(self.request.arguments, ["k"]) == False:
|
if not requestsManager.checkArguments(self.request.arguments, ["k"]):
|
||||||
raise exceptions.invalidArgumentsException()
|
raise exceptions.invalidArgumentsException()
|
||||||
|
|
||||||
# Check ci key
|
# Check ci key
|
||||||
@@ -33,7 +35,5 @@ class handler(requestHelper.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))
|
|
||||||
|
25
handlers/heavyHandler.py
Normal file
25
handlers/heavyHandler.py
Normal file
@@ -0,0 +1,25 @@
|
|||||||
|
import tornado.gen
|
||||||
|
import tornado.web
|
||||||
|
from common.web import requestsManager
|
||||||
|
from objects import glob
|
||||||
|
import time
|
||||||
|
|
||||||
|
class handler(requestsManager.asyncRequestHandler):
|
||||||
|
@tornado.web.asynchronous
|
||||||
|
@tornado.gen.engine
|
||||||
|
def asyncGet(self):
|
||||||
|
if not glob.debug:
|
||||||
|
self.write("Nope")
|
||||||
|
return
|
||||||
|
time.sleep(0.5)
|
||||||
|
self.write("meemmeemmeemmeemmeemmeemmeemmeemmeemmeemmeemmeemmeemmeemmeemmeemmeemmeemmeemmeemmeemmeemmeemmeemmeemmeemmeemmeem")
|
||||||
|
self.set_status(200)
|
||||||
|
self.add_header("cho-token", "tua madre")
|
||||||
|
self.add_header("cho-protocol", "19")
|
||||||
|
self.add_header("Connection", "keep-alive")
|
||||||
|
self.add_header("Keep-Alive", "timeout=5, max=100")
|
||||||
|
self.add_header("Content-Type", "text/html; charset=UTF-8")
|
||||||
|
#glob.db.fetchAll("SELECT SQL_NO_CACHE * FROM beatmaps")
|
||||||
|
#glob.db.fetchAll("SELECT SQL_NO_CACHE * FROM users")
|
||||||
|
#glob.db.fetchAll("SELECT SQL_NO_CACHE * FROM scores")
|
||||||
|
#self.write("ibmd")
|
@@ -1,66 +1,70 @@
|
|||||||
import datetime
|
import datetime
|
||||||
import gzip
|
import gzip
|
||||||
from helpers import requestHelper
|
|
||||||
from objects import glob
|
|
||||||
from constants import exceptions
|
|
||||||
from constants import packetIDs
|
|
||||||
from helpers import packetHelper
|
|
||||||
from constants import serverPackets
|
|
||||||
from events import sendPublicMessageEvent
|
|
||||||
from events import sendPrivateMessageEvent
|
|
||||||
from events import channelJoinEvent
|
|
||||||
from events import channelPartEvent
|
|
||||||
from events import changeActionEvent
|
|
||||||
from events import cantSpectateEvent
|
|
||||||
from events import startSpectatingEvent
|
|
||||||
from events import stopSpectatingEvent
|
|
||||||
from events import spectateFramesEvent
|
|
||||||
from events import friendAddEvent
|
|
||||||
from events import friendRemoveEvent
|
|
||||||
from events import logoutEvent
|
|
||||||
from events import loginEvent
|
|
||||||
from events import setAwayMessageEvent
|
|
||||||
from events import joinLobbyEvent
|
|
||||||
from events import createMatchEvent
|
|
||||||
from events import partLobbyEvent
|
|
||||||
from events import changeSlotEvent
|
|
||||||
from events import joinMatchEvent
|
|
||||||
from events import partMatchEvent
|
|
||||||
from events import changeMatchSettingsEvent
|
|
||||||
from events import changeMatchPasswordEvent
|
|
||||||
from events import changeMatchModsEvent
|
|
||||||
from events import matchReadyEvent
|
|
||||||
from events import matchLockEvent
|
|
||||||
from events import matchStartEvent
|
|
||||||
from events import matchPlayerLoadEvent
|
|
||||||
from events import matchSkipEvent
|
|
||||||
from events import matchFramesEvent
|
|
||||||
from events import matchCompleteEvent
|
|
||||||
from events import matchNoBeatmapEvent
|
|
||||||
from events import matchHasBeatmapEvent
|
|
||||||
from events import matchTransferHostEvent
|
|
||||||
from events import matchFailedEvent
|
|
||||||
from events import matchInviteEvent
|
|
||||||
from events import matchChangeTeamEvent
|
|
||||||
from events import userStatsRequestEvent
|
|
||||||
from events import requestStatusUpdateEvent
|
|
||||||
from events import userPanelRequestEvent
|
|
||||||
|
|
||||||
# Exception tracking
|
|
||||||
import tornado.web
|
|
||||||
import tornado.gen
|
|
||||||
import sys
|
import sys
|
||||||
import traceback
|
import traceback
|
||||||
from raven.contrib.tornado import SentryMixin
|
|
||||||
from helpers import logHelper as log
|
|
||||||
|
|
||||||
class handler(SentryMixin, requestHelper.asyncRequestHandler):
|
import tornado.gen
|
||||||
|
import tornado.web
|
||||||
|
from raven.contrib.tornado import SentryMixin
|
||||||
|
|
||||||
|
from common.log import logUtils as log
|
||||||
|
from common.web import requestsManager
|
||||||
|
from constants import exceptions
|
||||||
|
from constants import packetIDs
|
||||||
|
from constants import serverPackets
|
||||||
|
from events import cantSpectateEvent
|
||||||
|
from events import changeActionEvent
|
||||||
|
from events import changeMatchModsEvent
|
||||||
|
from events import changeMatchPasswordEvent
|
||||||
|
from events import changeMatchSettingsEvent
|
||||||
|
from events import changeSlotEvent
|
||||||
|
from events import channelJoinEvent
|
||||||
|
from events import channelPartEvent
|
||||||
|
from events import createMatchEvent
|
||||||
|
from events import friendAddEvent
|
||||||
|
from events import friendRemoveEvent
|
||||||
|
from events import joinLobbyEvent
|
||||||
|
from events import joinMatchEvent
|
||||||
|
from events import loginEvent
|
||||||
|
from events import logoutEvent
|
||||||
|
from events import matchChangeTeamEvent
|
||||||
|
from events import matchCompleteEvent
|
||||||
|
from events import matchFailedEvent
|
||||||
|
from events import matchFramesEvent
|
||||||
|
from events import matchHasBeatmapEvent
|
||||||
|
from events import matchInviteEvent
|
||||||
|
from events import matchLockEvent
|
||||||
|
from events import matchNoBeatmapEvent
|
||||||
|
from events import matchPlayerLoadEvent
|
||||||
|
from events import matchReadyEvent
|
||||||
|
from events import matchSkipEvent
|
||||||
|
from events import matchStartEvent
|
||||||
|
from events import matchTransferHostEvent
|
||||||
|
from events import partLobbyEvent
|
||||||
|
from events import partMatchEvent
|
||||||
|
from events import requestStatusUpdateEvent
|
||||||
|
from events import sendPrivateMessageEvent
|
||||||
|
from events import sendPublicMessageEvent
|
||||||
|
from events import setAwayMessageEvent
|
||||||
|
from events import spectateFramesEvent
|
||||||
|
from events import startSpectatingEvent
|
||||||
|
from events import stopSpectatingEvent
|
||||||
|
from events import userPanelRequestEvent
|
||||||
|
from events import userStatsRequestEvent
|
||||||
|
from events import tournamentMatchInfoRequestEvent
|
||||||
|
from events import tournamentJoinMatchChannelEvent
|
||||||
|
from events import tournamentLeaveMatchChannelEvent
|
||||||
|
from helpers import packetHelper
|
||||||
|
from objects import glob
|
||||||
|
|
||||||
|
|
||||||
|
class handler(SentryMixin, requestsManager.asyncRequestHandler):
|
||||||
@tornado.web.asynchronous
|
@tornado.web.asynchronous
|
||||||
@tornado.gen.engine
|
@tornado.gen.engine
|
||||||
def asyncPost(self):
|
def asyncPost(self):
|
||||||
try:
|
try:
|
||||||
# Track time if needed
|
# Track time if needed
|
||||||
if glob.outputRequestTime == True:
|
if glob.outputRequestTime:
|
||||||
# Start time
|
# Start time
|
||||||
st = datetime.datetime.now()
|
st = datetime.datetime.now()
|
||||||
|
|
||||||
@@ -72,7 +76,7 @@ class handler(SentryMixin, requestHelper.asyncRequestHandler):
|
|||||||
responseTokenString = "ayy"
|
responseTokenString = "ayy"
|
||||||
responseData = bytes()
|
responseData = bytes()
|
||||||
|
|
||||||
if requestTokenString == None:
|
if requestTokenString is None:
|
||||||
# No token, first request. Handle login.
|
# No token, first request. Handle login.
|
||||||
responseTokenString, responseData = loginEvent.handle(self)
|
responseTokenString, responseData = loginEvent.handle(self)
|
||||||
else:
|
else:
|
||||||
@@ -155,6 +159,10 @@ class handler(SentryMixin, requestHelper.asyncRequestHandler):
|
|||||||
packetIDs.client_matchFailed: handleEvent(matchFailedEvent),
|
packetIDs.client_matchFailed: handleEvent(matchFailedEvent),
|
||||||
packetIDs.client_matchChangeTeam: handleEvent(matchChangeTeamEvent),
|
packetIDs.client_matchChangeTeam: handleEvent(matchChangeTeamEvent),
|
||||||
packetIDs.client_invite: handleEvent(matchInviteEvent),
|
packetIDs.client_invite: handleEvent(matchInviteEvent),
|
||||||
|
|
||||||
|
packetIDs.client_tournamentMatchInfoRequest: handleEvent(tournamentMatchInfoRequestEvent),
|
||||||
|
packetIDs.client_tournamentJoinMatchChannel: handleEvent(tournamentJoinMatchChannelEvent),
|
||||||
|
packetIDs.client_tournamentLeaveMatchChannel: handleEvent(tournamentLeaveMatchChannelEvent),
|
||||||
}
|
}
|
||||||
|
|
||||||
# Packets processed if in restricted mode.
|
# Packets processed if in restricted mode.
|
||||||
@@ -187,9 +195,6 @@ class handler(SentryMixin, requestHelper.asyncRequestHandler):
|
|||||||
responseTokenString = userToken.token
|
responseTokenString = userToken.token
|
||||||
responseData = userToken.queue
|
responseData = userToken.queue
|
||||||
userToken.resetQueue()
|
userToken.resetQueue()
|
||||||
|
|
||||||
# Update ping time for timeout
|
|
||||||
userToken.updatePingTime()
|
|
||||||
except exceptions.tokenNotFoundException:
|
except exceptions.tokenNotFoundException:
|
||||||
# Token not found. Disconnect that user
|
# Token not found. Disconnect that user
|
||||||
responseData = serverPackets.loginError()
|
responseData = serverPackets.loginError()
|
||||||
@@ -198,10 +203,13 @@ class handler(SentryMixin, requestHelper.asyncRequestHandler):
|
|||||||
log.info("{} has been disconnected (invalid token)".format(requestTokenString))
|
log.info("{} has been disconnected (invalid token)".format(requestTokenString))
|
||||||
finally:
|
finally:
|
||||||
# Unlock token
|
# Unlock token
|
||||||
if userToken != None:
|
if userToken is not None:
|
||||||
|
# Update ping time for timeout
|
||||||
|
userToken.updatePingTime()
|
||||||
|
# Release token lock
|
||||||
userToken.lock.release()
|
userToken.lock.release()
|
||||||
|
|
||||||
if glob.outputRequestTime == True:
|
if glob.outputRequestTime:
|
||||||
# End time
|
# End time
|
||||||
et = datetime.datetime.now()
|
et = datetime.datetime.now()
|
||||||
|
|
||||||
@@ -211,7 +219,7 @@ class handler(SentryMixin, requestHelper.asyncRequestHandler):
|
|||||||
|
|
||||||
# Send server's response to client
|
# Send server's response to client
|
||||||
# We don't use token object because we might not have a token (failed login)
|
# We don't use token object because we might not have a token (failed login)
|
||||||
if glob.gzip == True:
|
if glob.gzip:
|
||||||
# First, write the gzipped response
|
# First, write the gzipped response
|
||||||
self.write(gzip.compress(responseData, int(glob.conf.config["server"]["gziplevel"])))
|
self.write(gzip.compress(responseData, int(glob.conf.config["server"]["gziplevel"])))
|
||||||
|
|
||||||
@@ -226,8 +234,8 @@ class handler(SentryMixin, requestHelper.asyncRequestHandler):
|
|||||||
self.set_status(200)
|
self.set_status(200)
|
||||||
self.add_header("cho-token", responseTokenString)
|
self.add_header("cho-token", responseTokenString)
|
||||||
self.add_header("cho-protocol", "19")
|
self.add_header("cho-protocol", "19")
|
||||||
#self.add_header("Keep-Alive", "timeout=5, max=100")
|
self.add_header("Connection", "keep-alive")
|
||||||
#self.add_header("Connection", "keep-alive")
|
self.add_header("Keep-Alive", "timeout=5, max=100")
|
||||||
self.add_header("Content-Type", "text/html; charset=UTF-8")
|
self.add_header("Content-Type", "text/html; charset=UTF-8")
|
||||||
except:
|
except:
|
||||||
log.error("Unknown error!\n```\n{}\n{}```".format(sys.exc_info(), traceback.format_exc()))
|
log.error("Unknown error!\n```\n{}\n{}```".format(sys.exc_info(), traceback.format_exc()))
|
||||||
@@ -260,5 +268,3 @@ class handler(SentryMixin, requestHelper.asyncRequestHandler):
|
|||||||
html += "^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^<br>"
|
html += "^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^<br>"
|
||||||
html += "</marquee><br><strike>reverse engineering a protocol impossible to reverse engineer since always</strike><br>we are actually reverse engineering bancho successfully. for the third time.<br><br><i>© Ripple team, 2016</i></pre></body></html>"
|
html += "</marquee><br><strike>reverse engineering a protocol impossible to reverse engineer since always</strike><br>we are actually reverse engineering bancho successfully. for the third time.<br><br><i>© Ripple team, 2016</i></pre></body></html>"
|
||||||
self.write(html)
|
self.write(html)
|
||||||
#yield tornado.gen.Task(self.captureMessage, "test")
|
|
||||||
#self.finish()
|
|
||||||
|
@@ -1,52 +0,0 @@
|
|||||||
"""
|
|
||||||
WIP feature that will come in the future.
|
|
||||||
Don't import
|
|
||||||
"""
|
|
||||||
import flask
|
|
||||||
from objects import glob
|
|
||||||
from constants import exceptions
|
|
||||||
|
|
||||||
@app.route("/api/online-users-count")
|
|
||||||
def APIonlineUsersCount():
|
|
||||||
return flask.jsonify({"count" : len(glob.tokens.tokens)-1})
|
|
||||||
|
|
||||||
@app.route("/api/user-info")
|
|
||||||
def APIonlineUsers():
|
|
||||||
resp = {}
|
|
||||||
|
|
||||||
try:
|
|
||||||
u = flask.request.args.get('u')
|
|
||||||
|
|
||||||
# Username/userID
|
|
||||||
if u.isdigit():
|
|
||||||
u = int(u)
|
|
||||||
else:
|
|
||||||
u = userHelper.getID(u)
|
|
||||||
if u == None:
|
|
||||||
raise exceptions.userNotFoundException
|
|
||||||
|
|
||||||
# Make sure this user is online
|
|
||||||
userToken = glob.tokens.getTokenFromUserID(u)
|
|
||||||
if userToken == None:
|
|
||||||
raise exceptions.tokenNotFoundException
|
|
||||||
|
|
||||||
# Build response dictionary
|
|
||||||
resp["response"] = "1"
|
|
||||||
resp[userToken.username] = {
|
|
||||||
"userID" : userToken.userID,
|
|
||||||
"actionID" : userToken.actionID,
|
|
||||||
"actionText" : userToken.actionText,
|
|
||||||
"actionMd5" : userToken.actionMd5,
|
|
||||||
"actionMods": userToken.actionMods,
|
|
||||||
"gameMode": userToken.gameMode,
|
|
||||||
"country": countryHelper.getCountryLetters(userToken.country),
|
|
||||||
"position": userToken.location,
|
|
||||||
"spectating": userToken.spectating,
|
|
||||||
"spectators": userToken.spectators
|
|
||||||
}
|
|
||||||
except exceptions.userNotFoundException:
|
|
||||||
resp["response"] = "-1"
|
|
||||||
except exceptions.tokenNotFoundException:
|
|
||||||
resp["response"] = "-2"
|
|
||||||
finally:
|
|
||||||
return flask.jsonify(resp)
|
|
@@ -1,12 +1,12 @@
|
|||||||
from objects import glob
|
from common.log import logUtils as log
|
||||||
from helpers import logHelper as log
|
from common.ripple import userUtils
|
||||||
from constants import exceptions
|
from constants import exceptions
|
||||||
from constants import serverPackets
|
|
||||||
from objects import fokabot
|
|
||||||
from helpers import discordBotHelper
|
|
||||||
from helpers import userHelper
|
|
||||||
from events import logoutEvent
|
|
||||||
from constants import messageTemplates
|
from constants import messageTemplates
|
||||||
|
from constants import serverPackets
|
||||||
|
from events import logoutEvent
|
||||||
|
from objects import fokabot
|
||||||
|
from objects import glob
|
||||||
|
|
||||||
|
|
||||||
def joinChannel(userID = 0, channel = "", token = None, toIRC = True):
|
def joinChannel(userID = 0, channel = "", token = None, toIRC = True):
|
||||||
"""
|
"""
|
||||||
@@ -23,10 +23,10 @@ def joinChannel(userID = 0, channel = "", token = None, toIRC = True):
|
|||||||
"""
|
"""
|
||||||
try:
|
try:
|
||||||
# Get token if not defined
|
# Get token if not defined
|
||||||
if token == None:
|
if token is None:
|
||||||
token = glob.tokens.getTokenFromUserID(userID)
|
token = glob.tokens.getTokenFromUserID(userID)
|
||||||
# Make sure the token exists
|
# Make sure the token exists
|
||||||
if token == None:
|
if token is None:
|
||||||
raise exceptions.userNotFoundException
|
raise exceptions.userNotFoundException
|
||||||
else:
|
else:
|
||||||
token = token
|
token = token
|
||||||
@@ -89,10 +89,10 @@ def partChannel(userID = 0, channel = "", token = None, toIRC = True, kick = Fal
|
|||||||
"""
|
"""
|
||||||
try:
|
try:
|
||||||
# Get token if not defined
|
# Get token if not defined
|
||||||
if token == None:
|
if token is None:
|
||||||
token = glob.tokens.getTokenFromUserID(userID)
|
token = glob.tokens.getTokenFromUserID(userID)
|
||||||
# Make sure the token exists
|
# Make sure the token exists
|
||||||
if token == None:
|
if token is None:
|
||||||
raise exceptions.userNotFoundException
|
raise exceptions.userNotFoundException
|
||||||
else:
|
else:
|
||||||
token = token
|
token = token
|
||||||
@@ -105,10 +105,10 @@ def partChannel(userID = 0, channel = "", token = None, toIRC = True, kick = Fal
|
|||||||
# (toclient is used clientwise for #multiplayer and #spectator channels)
|
# (toclient is used clientwise for #multiplayer and #spectator channels)
|
||||||
channelClient = channel
|
channelClient = channel
|
||||||
if channel == "#spectator":
|
if channel == "#spectator":
|
||||||
if token.spectating == 0:
|
if token.spectating is None:
|
||||||
s = userID
|
s = userID
|
||||||
else:
|
else:
|
||||||
s = token.spectating
|
s = token.spectatingUserID
|
||||||
channel = "#spect_{}".format(s)
|
channel = "#spect_{}".format(s)
|
||||||
elif channel == "#multiplayer":
|
elif channel == "#multiplayer":
|
||||||
channel = "#multi_{}".format(token.matchID)
|
channel = "#multi_{}".format(token.matchID)
|
||||||
@@ -128,7 +128,7 @@ def partChannel(userID = 0, channel = "", token = None, toIRC = True, kick = Fal
|
|||||||
|
|
||||||
# Force close tab if needed
|
# Force close tab if needed
|
||||||
# NOTE: Maybe always needed, will check later
|
# NOTE: Maybe always needed, will check later
|
||||||
if kick == True:
|
if kick:
|
||||||
token.enqueue(serverPackets.channelKicked(channelClient))
|
token.enqueue(serverPackets.channelKicked(channelClient))
|
||||||
|
|
||||||
# IRC part
|
# IRC part
|
||||||
@@ -147,9 +147,6 @@ def partChannel(userID = 0, channel = "", token = None, toIRC = True, kick = Fal
|
|||||||
log.warning("User not connected to IRC/Bancho")
|
log.warning("User not connected to IRC/Bancho")
|
||||||
return 442 # idk
|
return 442 # idk
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
def sendMessage(fro = "", to = "", message = "", token = None, toIRC = True):
|
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
|
||||||
@@ -167,9 +164,9 @@ def sendMessage(fro = "", to = "", message = "", token = None, toIRC = True):
|
|||||||
try:
|
try:
|
||||||
tokenString = ""
|
tokenString = ""
|
||||||
# Get token object if not passed
|
# Get token object if not passed
|
||||||
if token == None:
|
if token is None:
|
||||||
token = glob.tokens.getTokenFromUsername(fro)
|
token = glob.tokens.getTokenFromUsername(fro)
|
||||||
if token == None:
|
if token is None:
|
||||||
raise exceptions.userNotFoundException
|
raise exceptions.userNotFoundException
|
||||||
else:
|
else:
|
||||||
# token object alredy passed, get its string and its username (fro)
|
# token object alredy passed, get its string and its username (fro)
|
||||||
@@ -179,24 +176,27 @@ def sendMessage(fro = "", to = "", message = "", token = None, toIRC = True):
|
|||||||
# Set some variables
|
# Set some variables
|
||||||
userID = token.userID
|
userID = token.userID
|
||||||
username = token.username
|
username = token.username
|
||||||
recipients = []
|
|
||||||
|
# Make sure this is not a tournament client
|
||||||
|
if token.tournament:
|
||||||
|
raise exceptions.userTournamentException()
|
||||||
|
|
||||||
# Make sure the user is not in restricted mode
|
# Make sure the user is not in restricted mode
|
||||||
if token.restricted == True:
|
if token.restricted:
|
||||||
raise exceptions.userRestrictedException
|
raise exceptions.userRestrictedException()
|
||||||
|
|
||||||
# Make sure the user is not silenced
|
# Make sure the user is not silenced
|
||||||
if token.isSilenced() == True:
|
if token.isSilenced():
|
||||||
raise exceptions.userSilencedException
|
raise exceptions.userSilencedException()
|
||||||
|
|
||||||
# Determine internal name if needed
|
# Determine internal name if needed
|
||||||
# (toclient is used clientwise for #multiplayer and #spectator channels)
|
# (toclient is used clientwise for #multiplayer and #spectator channels)
|
||||||
toClient = to
|
toClient = to
|
||||||
if to == "#spectator":
|
if to == "#spectator":
|
||||||
if token.spectating == 0:
|
if token.spectating is None:
|
||||||
s = userID
|
s = userID
|
||||||
else:
|
else:
|
||||||
s = token.spectating
|
s = token.spectatingUserID
|
||||||
to = "#spect_{}".format(s)
|
to = "#spect_{}".format(s)
|
||||||
elif to == "#multiplayer":
|
elif to == "#multiplayer":
|
||||||
to = "#multi_{}".format(token.matchID)
|
to = "#multi_{}".format(token.matchID)
|
||||||
@@ -216,7 +216,7 @@ def sendMessage(fro = "", to = "", message = "", token = None, toIRC = True):
|
|||||||
|
|
||||||
# Send the message
|
# Send the message
|
||||||
isChannel = to.startswith("#")
|
isChannel = to.startswith("#")
|
||||||
if isChannel == True:
|
if isChannel:
|
||||||
# CHANNEL
|
# CHANNEL
|
||||||
# Make sure the channel exists
|
# Make sure the channel exists
|
||||||
if to not in glob.channels.channels:
|
if to not in glob.channels.channels:
|
||||||
@@ -243,12 +243,16 @@ def sendMessage(fro = "", to = "", message = "", token = None, toIRC = True):
|
|||||||
# USER
|
# USER
|
||||||
# Make sure recipient user is connected
|
# Make sure recipient user is connected
|
||||||
recipientToken = glob.tokens.getTokenFromUsername(to)
|
recipientToken = glob.tokens.getTokenFromUsername(to)
|
||||||
if recipientToken == None:
|
if recipientToken is None:
|
||||||
raise exceptions.userNotFoundException
|
raise exceptions.userNotFoundException
|
||||||
|
|
||||||
|
# Make sure the recipient is not a tournament client
|
||||||
|
if recipientToken.tournament:
|
||||||
|
raise exceptions.userTournamentException()
|
||||||
|
|
||||||
# Make sure the recipient is not restricted or we are FokaBot
|
# Make sure the recipient is not restricted or we are FokaBot
|
||||||
if recipientToken.restricted == True and fro.lower() != "fokabot":
|
if recipientToken.restricted == True and fro.lower() != "fokabot":
|
||||||
raise exceptions.userRestrictedException
|
raise exceptions.userRestrictedException()
|
||||||
|
|
||||||
# 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
|
||||||
|
|
||||||
@@ -270,13 +274,13 @@ def sendMessage(fro = "", to = "", message = "", token = None, toIRC = True):
|
|||||||
# Fokabot message
|
# Fokabot message
|
||||||
if isChannel == True or to.lower() == "fokabot":
|
if isChannel == True or to.lower() == "fokabot":
|
||||||
fokaMessage = fokabot.fokabotResponse(username, to, message)
|
fokaMessage = fokabot.fokabotResponse(username, to, message)
|
||||||
if fokaMessage != False:
|
if fokaMessage:
|
||||||
sendMessage("FokaBot", to if isChannel else fro, fokaMessage)
|
sendMessage("FokaBot", to if isChannel else fro, fokaMessage)
|
||||||
|
|
||||||
# File and discord logs (public chat only)
|
# File and discord logs (public chat only)
|
||||||
if to.startswith("#") == True:
|
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"))))
|
||||||
discordBotHelper.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
|
||||||
except exceptions.userSilencedException:
|
except exceptions.userSilencedException:
|
||||||
token.enqueue(serverPackets.silenceEndTime(token.getSilenceSecondsLeft()))
|
token.enqueue(serverPackets.silenceEndTime(token.getSilenceSecondsLeft()))
|
||||||
@@ -294,34 +298,53 @@ def sendMessage(fro = "", to = "", message = "", token = None, toIRC = True):
|
|||||||
except exceptions.userRestrictedException:
|
except exceptions.userRestrictedException:
|
||||||
log.warning("{} tried to send a message {}, but the recipient is in restricted mode".format(username, to))
|
log.warning("{} tried to send a message {}, but the recipient is in restricted mode".format(username, to))
|
||||||
return 404
|
return 404
|
||||||
|
except exceptions.userTournamentException:
|
||||||
|
log.warning("{} tried to send a message {}, but the recipient is a tournament client".format(username, to))
|
||||||
|
return 404
|
||||||
except exceptions.userNotFoundException:
|
except exceptions.userNotFoundException:
|
||||||
log.warning("User not connected to IRC/Bancho")
|
log.warning("User not connected to IRC/Bancho")
|
||||||
return 401
|
return 401
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
""" IRC-Bancho Connect/Disconnect/Join/Part interfaces"""
|
""" IRC-Bancho Connect/Disconnect/Join/Part interfaces"""
|
||||||
|
def fixUsernameForBancho(username):
|
||||||
|
# If there are no spaces or underscores in the name
|
||||||
|
# return it
|
||||||
|
if " " not in username and "_" not in username:
|
||||||
|
return username
|
||||||
|
|
||||||
|
# Exact match first
|
||||||
|
result = glob.db.fetch("SELECT id FROM users WHERE username = %s LIMIT 1", [username])
|
||||||
|
if result is not None:
|
||||||
|
return username
|
||||||
|
|
||||||
|
# Username not found, replace _ with space
|
||||||
|
return username.replace("_", " ")
|
||||||
|
|
||||||
|
def fixUsernameForIRC(username):
|
||||||
|
return username.replace(" ", "_")
|
||||||
|
|
||||||
def IRCConnect(username):
|
def IRCConnect(username):
|
||||||
userID = userHelper.getID(username)
|
userID = userUtils.getID(username)
|
||||||
if userID == False:
|
if not userID:
|
||||||
log.warning("{} doesn't exist".format(username))
|
log.warning("{} doesn't exist".format(username))
|
||||||
return
|
return
|
||||||
glob.tokens.deleteOldTokens(userID)
|
glob.tokens.deleteOldTokens(userID)
|
||||||
glob.tokens.addToken(userID, irc=True)
|
glob.tokens.addToken(userID, irc=True)
|
||||||
glob.tokens.enqueueAll(serverPackets.userPanel(userID))
|
glob.streams.broadcast("main", serverPackets.userPanel(userID))
|
||||||
log.info("{} logged in from IRC".format(username))
|
log.info("{} logged in from IRC".format(username))
|
||||||
|
|
||||||
def IRCDisconnect(username):
|
def IRCDisconnect(username):
|
||||||
token = glob.tokens.getTokenFromUsername(username)
|
token = glob.tokens.getTokenFromUsername(username)
|
||||||
if token == None:
|
if token is None:
|
||||||
log.warning("{} doesn't exist".format(username))
|
log.warning("{} doesn't exist".format(username))
|
||||||
return
|
return
|
||||||
logoutEvent.handle(token)
|
logoutEvent.handle(token)
|
||||||
log.info("{} disconnected from IRC".format(username))
|
log.info("{} disconnected from IRC".format(username))
|
||||||
|
|
||||||
def IRCJoinChannel(username, channel):
|
def IRCJoinChannel(username, channel):
|
||||||
userID = userHelper.getID(username)
|
userID = userUtils.getID(username)
|
||||||
if userID == False:
|
if not userID:
|
||||||
log.warning("{} doesn't exist".format(username))
|
log.warning("{} doesn't exist".format(username))
|
||||||
return
|
return
|
||||||
# NOTE: This should have also `toIRC` = False` tho,
|
# NOTE: This should have also `toIRC` = False` tho,
|
||||||
@@ -330,8 +353,8 @@ def IRCJoinChannel(username, channel):
|
|||||||
return joinChannel(userID, channel)
|
return joinChannel(userID, channel)
|
||||||
|
|
||||||
def IRCPartChannel(username, channel):
|
def IRCPartChannel(username, channel):
|
||||||
userID = userHelper.getID(username)
|
userID = userUtils.getID(username)
|
||||||
if userID == False:
|
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)
|
@@ -2,26 +2,16 @@ import os
|
|||||||
import configparser
|
import configparser
|
||||||
|
|
||||||
class config:
|
class config:
|
||||||
"""
|
|
||||||
config.ini object
|
|
||||||
|
|
||||||
config -- list with ini data
|
|
||||||
default -- if true, we have generated a default config.ini
|
|
||||||
"""
|
|
||||||
|
|
||||||
config = configparser.ConfigParser()
|
|
||||||
fileName = "" # config filename
|
|
||||||
default = True
|
|
||||||
|
|
||||||
# Check if config.ini exists and load/generate it
|
# Check if config.ini exists and load/generate it
|
||||||
def __init__(self, __file):
|
def __init__(self, file):
|
||||||
"""
|
"""
|
||||||
Initialize a config object
|
Initialize a config object
|
||||||
|
|
||||||
__file -- filename
|
file -- filename
|
||||||
"""
|
"""
|
||||||
|
self.config = configparser.ConfigParser()
|
||||||
self.fileName = __file
|
self.default = True
|
||||||
|
self.fileName = file
|
||||||
if os.path.isfile(self.fileName):
|
if os.path.isfile(self.fileName):
|
||||||
# config.ini found, load it
|
# config.ini found, load it
|
||||||
self.config.read(self.fileName)
|
self.config.read(self.fileName)
|
||||||
@@ -39,7 +29,6 @@ class config:
|
|||||||
|
|
||||||
return -- True if valid, False if not
|
return -- True if valid, False if not
|
||||||
"""
|
"""
|
||||||
|
|
||||||
try:
|
try:
|
||||||
# Try to get all the required keys
|
# Try to get all the required keys
|
||||||
self.config.get("db","host")
|
self.config.get("db","host")
|
||||||
@@ -49,11 +38,15 @@ class config:
|
|||||||
self.config.get("db","workers")
|
self.config.get("db","workers")
|
||||||
|
|
||||||
self.config.get("server","port")
|
self.config.get("server","port")
|
||||||
|
self.config.get("server","threads")
|
||||||
self.config.get("server","gzip")
|
self.config.get("server","gzip")
|
||||||
self.config.get("server","gziplevel")
|
self.config.get("server","gziplevel")
|
||||||
self.config.get("server","cikey")
|
self.config.get("server","cikey")
|
||||||
self.config.get("server","cloudflare")
|
self.config.get("server","cloudflare")
|
||||||
|
|
||||||
|
self.config.get("mirror","apiurl")
|
||||||
|
self.config.get("mirror","apikey")
|
||||||
|
|
||||||
self.config.get("debug","enable")
|
self.config.get("debug","enable")
|
||||||
self.config.get("debug","packets")
|
self.config.get("debug","packets")
|
||||||
self.config.get("debug","time")
|
self.config.get("debug","time")
|
||||||
@@ -66,8 +59,13 @@ class config:
|
|||||||
self.config.get("discord","boturl")
|
self.config.get("discord","boturl")
|
||||||
self.config.get("discord","devgroup")
|
self.config.get("discord","devgroup")
|
||||||
|
|
||||||
|
self.config.get("datadog", "enable")
|
||||||
|
self.config.get("datadog", "apikey")
|
||||||
|
self.config.get("datadog", "appkey")
|
||||||
|
|
||||||
self.config.get("irc","enable")
|
self.config.get("irc","enable")
|
||||||
self.config.get("irc","port")
|
self.config.get("irc","port")
|
||||||
|
self.config.get("irc","hostname")
|
||||||
|
|
||||||
self.config.get("localize","enable")
|
self.config.get("localize","enable")
|
||||||
self.config.get("localize","ipapiurl")
|
self.config.get("localize","ipapiurl")
|
||||||
@@ -75,11 +73,10 @@ class config:
|
|||||||
except:
|
except:
|
||||||
return False
|
return False
|
||||||
|
|
||||||
|
|
||||||
# Generate a default config.ini
|
|
||||||
def generateDefaultConfig(self):
|
def generateDefaultConfig(self):
|
||||||
"""Open and set default keys for that config file"""
|
"""
|
||||||
|
Open and set default keys for that config file
|
||||||
|
"""
|
||||||
# Open config.ini in write mode
|
# Open config.ini in write mode
|
||||||
f = open(self.fileName, "w")
|
f = open(self.fileName, "w")
|
||||||
|
|
||||||
@@ -93,11 +90,16 @@ class config:
|
|||||||
|
|
||||||
self.config.add_section("server")
|
self.config.add_section("server")
|
||||||
self.config.set("server", "port", "5001")
|
self.config.set("server", "port", "5001")
|
||||||
|
self.config.set("server", "threads", "16")
|
||||||
self.config.set("server", "gzip", "1")
|
self.config.set("server", "gzip", "1")
|
||||||
self.config.set("server", "gziplevel", "6")
|
self.config.set("server", "gziplevel", "6")
|
||||||
self.config.set("server", "cikey", "changeme")
|
self.config.set("server", "cikey", "changeme")
|
||||||
self.config.set("server", "cloudflare", "0")
|
self.config.set("server", "cloudflare", "0")
|
||||||
|
|
||||||
|
self.config.add_section("mirror")
|
||||||
|
self.config.set("mirror", "apiurl", "http://storage.ripple.moe")
|
||||||
|
self.config.set("mirror", "apikey", "anotherkey")
|
||||||
|
|
||||||
self.config.add_section("debug")
|
self.config.add_section("debug")
|
||||||
self.config.set("debug", "enable", "0")
|
self.config.set("debug", "enable", "0")
|
||||||
self.config.set("debug", "packets", "0")
|
self.config.set("debug", "packets", "0")
|
||||||
@@ -113,9 +115,15 @@ class config:
|
|||||||
self.config.set("discord", "boturl", "")
|
self.config.set("discord", "boturl", "")
|
||||||
self.config.set("discord", "devgroup", "")
|
self.config.set("discord", "devgroup", "")
|
||||||
|
|
||||||
|
self.config.add_section("datadog")
|
||||||
|
self.config.set("datadog", "enable")
|
||||||
|
self.config.set("datadog", "apikey")
|
||||||
|
self.config.set("datadog", "appkey")
|
||||||
|
|
||||||
self.config.add_section("irc")
|
self.config.add_section("irc")
|
||||||
self.config.set("irc", "enable", "1")
|
self.config.set("irc", "enable", "1")
|
||||||
self.config.set("irc", "port", "6667")
|
self.config.set("irc", "port", "6667")
|
||||||
|
self.config.set("irc", "hostname", "ripple")
|
||||||
|
|
||||||
self.config.add_section("localize")
|
self.config.add_section("localize")
|
||||||
self.config.set("localize", "enable", "1")
|
self.config.set("localize", "enable", "1")
|
||||||
|
@@ -1,14 +1,13 @@
|
|||||||
"""Some console related functions"""
|
from common.constants import bcolors
|
||||||
|
|
||||||
from constants import bcolors
|
|
||||||
from objects import glob
|
from objects import glob
|
||||||
|
|
||||||
def printServerStartHeader(asciiArt):
|
def printServerStartHeader(asciiArt):
|
||||||
"""Print server start header with optional ascii art
|
"""
|
||||||
|
Print server start header with optional ascii art
|
||||||
|
|
||||||
asciiArt -- if True, will print ascii art too"""
|
asciiArt -- if True, will print ascii art too
|
||||||
|
"""
|
||||||
if asciiArt == True:
|
if asciiArt:
|
||||||
print("{} _ __".format(bcolors.GREEN))
|
print("{} _ __".format(bcolors.GREEN))
|
||||||
print(" (_) / /")
|
print(" (_) / /")
|
||||||
print(" ______ __ ____ ____ / /____")
|
print(" ______ __ ____ ____ / /____")
|
||||||
@@ -28,20 +27,17 @@ def printServerStartHeader(asciiArt):
|
|||||||
|
|
||||||
printColored("> Welcome to pep.py osu!bancho server v{}".format(glob.VERSION), bcolors.GREEN)
|
printColored("> Welcome to pep.py osu!bancho server v{}".format(glob.VERSION), bcolors.GREEN)
|
||||||
printColored("> Made by the Ripple team", bcolors.GREEN)
|
printColored("> Made by the Ripple team", bcolors.GREEN)
|
||||||
printColored("> {}https://github.com/osuripple/ripple".format(bcolors.UNDERLINE), bcolors.GREEN)
|
printColored("> {}https://git.zxq.co/ripple/pep.py".format(bcolors.UNDERLINE), bcolors.GREEN)
|
||||||
printColored("> Press CTRL+C to exit\n", bcolors.GREEN)
|
printColored("> Press CTRL+C to exit\n", bcolors.GREEN)
|
||||||
|
|
||||||
|
|
||||||
def printNoNl(string):
|
def printNoNl(string):
|
||||||
"""
|
"""
|
||||||
Print string without new line at the end
|
Print string without new line at the end
|
||||||
|
|
||||||
string -- string to print
|
string -- string to print
|
||||||
"""
|
"""
|
||||||
|
|
||||||
print(string, end="")
|
print(string, end="")
|
||||||
|
|
||||||
|
|
||||||
def printColored(string, color):
|
def printColored(string, color):
|
||||||
"""
|
"""
|
||||||
Print colored string
|
Print colored string
|
||||||
@@ -49,23 +45,22 @@ def printColored(string, color):
|
|||||||
string -- string to print
|
string -- string to print
|
||||||
color -- see bcolors.py
|
color -- see bcolors.py
|
||||||
"""
|
"""
|
||||||
|
|
||||||
print("{}{}{}".format(color, string, bcolors.ENDC))
|
print("{}{}{}".format(color, string, bcolors.ENDC))
|
||||||
|
|
||||||
|
|
||||||
def printError():
|
def printError():
|
||||||
"""Print error text FOR LOADING"""
|
"""
|
||||||
|
Print error text FOR LOADING
|
||||||
|
"""
|
||||||
printColored("Error", bcolors.RED)
|
printColored("Error", bcolors.RED)
|
||||||
|
|
||||||
|
|
||||||
def printDone():
|
def printDone():
|
||||||
"""Print error text FOR LOADING"""
|
"""
|
||||||
|
Print error text FOR LOADING
|
||||||
|
"""
|
||||||
printColored("Done", bcolors.GREEN)
|
printColored("Done", bcolors.GREEN)
|
||||||
|
|
||||||
|
|
||||||
def printWarning():
|
def printWarning():
|
||||||
"""Print error text FOR LOADING"""
|
"""
|
||||||
|
Print error text FOR LOADING
|
||||||
|
"""
|
||||||
printColored("Warning", bcolors.YELLOW)
|
printColored("Warning", bcolors.YELLOW)
|
||||||
|
@@ -253,7 +253,6 @@ countryCodes = {
|
|||||||
"AI": 7
|
"AI": 7
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
def getCountryID(code):
|
def getCountryID(code):
|
||||||
"""
|
"""
|
||||||
Get country ID for osu client
|
Get country ID for osu client
|
||||||
|
@@ -1,138 +0,0 @@
|
|||||||
import pymysql
|
|
||||||
from constants import bcolors
|
|
||||||
from helpers import consoleHelper
|
|
||||||
import threading
|
|
||||||
from objects import glob
|
|
||||||
|
|
||||||
class db:
|
|
||||||
"""A MySQL database connection"""
|
|
||||||
|
|
||||||
connection = None
|
|
||||||
disconnected = False
|
|
||||||
pingTime = 600
|
|
||||||
|
|
||||||
def __init__(self, __host, __username, __password, __database, __pingTime = 600):
|
|
||||||
"""
|
|
||||||
Connect to MySQL database
|
|
||||||
|
|
||||||
__host -- MySQL host name
|
|
||||||
__username -- MySQL username
|
|
||||||
__password -- MySQL password
|
|
||||||
__database -- MySQL database name
|
|
||||||
__pingTime -- MySQL database ping time (default: 600)
|
|
||||||
"""
|
|
||||||
|
|
||||||
self.connection = pymysql.connect(host=__host, user=__username, password=__password, db=__database, cursorclass=pymysql.cursors.DictCursor, autocommit=True)
|
|
||||||
self.pingTime = __pingTime
|
|
||||||
self.pingLoop()
|
|
||||||
|
|
||||||
|
|
||||||
def bindParams(self, __query, __params):
|
|
||||||
"""
|
|
||||||
Replace every ? with the respective **escaped** parameter in array
|
|
||||||
|
|
||||||
__query -- query with ?s
|
|
||||||
__params -- array with params
|
|
||||||
|
|
||||||
return -- new query
|
|
||||||
"""
|
|
||||||
|
|
||||||
for i in __params:
|
|
||||||
escaped = self.connection.escape(i)
|
|
||||||
__query = __query.replace("?", str(escaped), 1)
|
|
||||||
|
|
||||||
return __query
|
|
||||||
|
|
||||||
|
|
||||||
def execute(self, __query, __params = None):
|
|
||||||
"""
|
|
||||||
Execute a SQL query
|
|
||||||
|
|
||||||
__query -- query, can contain ?s
|
|
||||||
__params -- array with params. Optional
|
|
||||||
"""
|
|
||||||
|
|
||||||
log.debug(query)
|
|
||||||
with self.connection.cursor() as cursor:
|
|
||||||
try:
|
|
||||||
# Bind params if needed
|
|
||||||
if __params != None:
|
|
||||||
__query = self.bindParams(__query, __params)
|
|
||||||
|
|
||||||
# Execute the query
|
|
||||||
cursor.execute(__query)
|
|
||||||
finally:
|
|
||||||
# Close this connection
|
|
||||||
cursor.close()
|
|
||||||
|
|
||||||
|
|
||||||
def fetch(self, __query, __params = None, __all = False):
|
|
||||||
"""
|
|
||||||
Fetch the first (or all) element(s) of SQL query result
|
|
||||||
|
|
||||||
__query -- query, can contain ?s
|
|
||||||
__params -- array with params. Optional
|
|
||||||
__all -- if true, will fetch all values. Same as fetchAll
|
|
||||||
|
|
||||||
return -- dictionary with result data or False if failed
|
|
||||||
"""
|
|
||||||
|
|
||||||
log.debug(query)
|
|
||||||
with self.connection.cursor() as cursor:
|
|
||||||
try:
|
|
||||||
# Bind params if needed
|
|
||||||
if __params != None:
|
|
||||||
__query = self.bindParams(__query, __params)
|
|
||||||
|
|
||||||
# Execute the query with binded params
|
|
||||||
cursor.execute(__query)
|
|
||||||
|
|
||||||
# Get first result and return it
|
|
||||||
if __all == False:
|
|
||||||
return cursor.fetchone()
|
|
||||||
else:
|
|
||||||
return cursor.fetchall()
|
|
||||||
finally:
|
|
||||||
# Close this connection
|
|
||||||
cursor.close()
|
|
||||||
|
|
||||||
|
|
||||||
def fetchAll(self, __query, __params = None):
|
|
||||||
"""
|
|
||||||
Fetch the all elements of SQL query result
|
|
||||||
|
|
||||||
__query -- query, can contain ?s
|
|
||||||
__params -- array with params. Optional
|
|
||||||
|
|
||||||
return -- dictionary with result data
|
|
||||||
"""
|
|
||||||
|
|
||||||
return self.fetch(__query, __params, True)
|
|
||||||
|
|
||||||
def pingLoop(self):
|
|
||||||
"""
|
|
||||||
Pings MySQL server. We need to ping/execute a query at least once every 8 hours
|
|
||||||
or the connection will die.
|
|
||||||
If called once, will recall after 30 minutes and so on, forever
|
|
||||||
CALL THIS FUNCTION ONLY ONCE!
|
|
||||||
"""
|
|
||||||
|
|
||||||
# Default loop time
|
|
||||||
time = self.pingTime
|
|
||||||
|
|
||||||
# Make sure the connection is alive
|
|
||||||
try:
|
|
||||||
# Try to ping and reconnect if not connected
|
|
||||||
self.connection.ping()
|
|
||||||
if self.disconnected == True:
|
|
||||||
# If we were disconnected, set disconnected to false and print message
|
|
||||||
self.disconnected = False
|
|
||||||
log.error("> Reconnected to MySQL server!", bcolors.GREEN)
|
|
||||||
except:
|
|
||||||
# Can't ping MySQL server. Show error and call loop in 5 seconds
|
|
||||||
log.error("[!] CRITICAL!! MySQL connection died! Make sure your MySQL server is running! Checking again in 5 seconds...", bcolors.RED)
|
|
||||||
self.disconnected = True
|
|
||||||
time = 5
|
|
||||||
|
|
||||||
# Schedule a new check (endless loop)
|
|
||||||
threading.Timer(time, self.pingLoop).start()
|
|
@@ -1,121 +0,0 @@
|
|||||||
import MySQLdb
|
|
||||||
import threading
|
|
||||||
from helpers import logHelper as log
|
|
||||||
|
|
||||||
class mysqlWorker:
|
|
||||||
"""
|
|
||||||
Instance of a pettirosso meme
|
|
||||||
"""
|
|
||||||
def __init__(self, wid, host, username, password, database):
|
|
||||||
"""
|
|
||||||
Create a pettirosso meme (mysql worker)
|
|
||||||
|
|
||||||
wid -- worker id
|
|
||||||
host -- hostname
|
|
||||||
username -- MySQL username
|
|
||||||
password -- MySQL password
|
|
||||||
database -- MySQL database name
|
|
||||||
"""
|
|
||||||
self.wid = wid
|
|
||||||
self.connection = MySQLdb.connect(host, username, password, database)
|
|
||||||
self.connection.autocommit(True)
|
|
||||||
self.ready = True
|
|
||||||
self.lock = threading.Lock()
|
|
||||||
|
|
||||||
class db:
|
|
||||||
"""
|
|
||||||
A MySQL db connection with multiple workers
|
|
||||||
"""
|
|
||||||
|
|
||||||
def __init__(self, host, username, password, database, workers):
|
|
||||||
"""
|
|
||||||
Create MySQL workers aka pettirossi meme
|
|
||||||
|
|
||||||
host -- hostname
|
|
||||||
username -- MySQL username
|
|
||||||
password -- MySQL password
|
|
||||||
database -- MySQL database name
|
|
||||||
workers -- Number of workers to spawn
|
|
||||||
"""
|
|
||||||
#self.lock = threading.Lock()
|
|
||||||
#self.connection = MySQLdb.connect(host, username, password, database)
|
|
||||||
|
|
||||||
self.workers = []
|
|
||||||
self.lastWorker = 0
|
|
||||||
self.workersNumber = workers
|
|
||||||
for i in range(0,self.workersNumber):
|
|
||||||
print(".", end="")
|
|
||||||
self.workers.append(mysqlWorker(i, host, username, password, database))
|
|
||||||
|
|
||||||
def getWorker(self):
|
|
||||||
"""
|
|
||||||
Return a worker object (round-robin way)
|
|
||||||
|
|
||||||
return -- worker object
|
|
||||||
"""
|
|
||||||
if self.lastWorker >= self.workersNumber-1:
|
|
||||||
self.lastWorker = 0
|
|
||||||
else:
|
|
||||||
self.lastWorker += 1
|
|
||||||
#print("Using worker {}".format(self.lastWorker))
|
|
||||||
return self.workers[self.lastWorker]
|
|
||||||
|
|
||||||
def execute(self, query, params = ()):
|
|
||||||
"""
|
|
||||||
Executes a query
|
|
||||||
|
|
||||||
query -- Query to execute. You can bind parameters with %s
|
|
||||||
params -- Parameters list. First element replaces first %s and so on. Optional.
|
|
||||||
"""
|
|
||||||
log.debug(query)
|
|
||||||
# Get a worker and acquire its lock
|
|
||||||
worker = self.getWorker()
|
|
||||||
worker.lock.acquire()
|
|
||||||
|
|
||||||
try:
|
|
||||||
# Create cursor, execute query and commit
|
|
||||||
cursor = worker.connection.cursor(MySQLdb.cursors.DictCursor)
|
|
||||||
cursor.execute(query, params)
|
|
||||||
return cursor.lastrowid
|
|
||||||
finally:
|
|
||||||
# Close the cursor and release worker's lock
|
|
||||||
if cursor:
|
|
||||||
cursor.close()
|
|
||||||
worker.lock.release()
|
|
||||||
|
|
||||||
def fetch(self, query, params = (), all = False):
|
|
||||||
"""
|
|
||||||
Fetch a single value from db that matches given query
|
|
||||||
|
|
||||||
query -- Query to execute. You can bind parameters with %s
|
|
||||||
params -- Parameters list. First element replaces first %s and so on. Optional.
|
|
||||||
all -- Fetch one or all values. Used internally. Use fetchAll if you want to fetch all values.
|
|
||||||
"""
|
|
||||||
log.debug(query)
|
|
||||||
# Get a worker and acquire its lock
|
|
||||||
worker = self.getWorker()
|
|
||||||
worker.lock.acquire()
|
|
||||||
|
|
||||||
try:
|
|
||||||
# Create cursor, execute the query and fetch one/all result(s)
|
|
||||||
cursor = worker.connection.cursor(MySQLdb.cursors.DictCursor)
|
|
||||||
cursor.execute(query, params)
|
|
||||||
if all == True:
|
|
||||||
return cursor.fetchall()
|
|
||||||
else:
|
|
||||||
return cursor.fetchone()
|
|
||||||
finally:
|
|
||||||
# Close the cursor and release worker's lock
|
|
||||||
if cursor:
|
|
||||||
cursor.close()
|
|
||||||
worker.lock.release()
|
|
||||||
|
|
||||||
def fetchAll(self, query, params = ()):
|
|
||||||
"""
|
|
||||||
Fetch all values from db that matche given query.
|
|
||||||
Calls self.fetch with all = True.
|
|
||||||
|
|
||||||
query -- Query to execute. You can bind parameters with %s
|
|
||||||
params -- Parameters list. First element replaces first %s and so on. Optional.
|
|
||||||
"""
|
|
||||||
return self.fetch(query, params, True)
|
|
@@ -1,69 +0,0 @@
|
|||||||
import requests
|
|
||||||
from objects import glob
|
|
||||||
from helpers import generalFunctions
|
|
||||||
from urllib.parse import urlencode
|
|
||||||
from helpers import consoleHelper
|
|
||||||
from constants import bcolors
|
|
||||||
|
|
||||||
def sendDiscordMessage(channel, message, alertDev = False, prefix = "**pep.py**"):
|
|
||||||
"""
|
|
||||||
Send a message to a discord server.
|
|
||||||
This is used with ripple's schiavobot.
|
|
||||||
|
|
||||||
channel -- bunk, staff or general
|
|
||||||
message -- message to send
|
|
||||||
alertDev -- if True, hl developers group
|
|
||||||
prefix -- string to prepend to message
|
|
||||||
"""
|
|
||||||
if glob.discord == True:
|
|
||||||
for _ in range(0,20):
|
|
||||||
try:
|
|
||||||
finalMsg = "{prefix} {message}".format(prefix=prefix, message=message) if alertDev == False else "{prefix} {hl} - {message}".format(prefix=prefix, hl=glob.conf.config["discord"]["devgroup"], message=message)
|
|
||||||
requests.get("{}/{}?{}".format(glob.conf.config["discord"]["boturl"], channel, urlencode({ "message": finalMsg })))
|
|
||||||
break
|
|
||||||
except:
|
|
||||||
continue
|
|
||||||
|
|
||||||
|
|
||||||
def sendConfidential(message, alertDev = False):
|
|
||||||
"""
|
|
||||||
Send a message to #bunker
|
|
||||||
|
|
||||||
message -- message to send
|
|
||||||
"""
|
|
||||||
sendDiscordMessage("bunk", message, alertDev)
|
|
||||||
|
|
||||||
|
|
||||||
def sendStaff(message):
|
|
||||||
"""
|
|
||||||
Send a message to #staff
|
|
||||||
|
|
||||||
message -- message to send
|
|
||||||
"""
|
|
||||||
sendDiscordMessage("staff", message)
|
|
||||||
|
|
||||||
|
|
||||||
def sendGeneral(message):
|
|
||||||
"""
|
|
||||||
Send a message to #general
|
|
||||||
|
|
||||||
message -- message to send
|
|
||||||
"""
|
|
||||||
sendDiscordMessage("general", message)
|
|
||||||
|
|
||||||
|
|
||||||
def sendChatlog(message):
|
|
||||||
"""
|
|
||||||
Send a message to #chatlog
|
|
||||||
|
|
||||||
message -- message to send
|
|
||||||
"""
|
|
||||||
sendDiscordMessage("chatlog", message, prefix="")
|
|
||||||
|
|
||||||
def sendCM(message):
|
|
||||||
"""
|
|
||||||
Send a message to #communitymanagers
|
|
||||||
|
|
||||||
message -- message to send
|
|
||||||
"""
|
|
||||||
sendDiscordMessage("cm", message)
|
|
@@ -1,128 +0,0 @@
|
|||||||
"""Some functions that don't fit in any other file"""
|
|
||||||
from constants import mods
|
|
||||||
from time import gmtime, strftime
|
|
||||||
|
|
||||||
def stringToBool(s):
|
|
||||||
"""
|
|
||||||
Convert a string (True/true/1) to bool
|
|
||||||
|
|
||||||
s -- string/int value
|
|
||||||
return -- True/False
|
|
||||||
"""
|
|
||||||
|
|
||||||
return (s == "True" or s== "true" or s == "1" or s == 1)
|
|
||||||
|
|
||||||
|
|
||||||
def hexString(s):
|
|
||||||
"""
|
|
||||||
Output s' bytes in HEX
|
|
||||||
|
|
||||||
s -- string
|
|
||||||
return -- string with hex value
|
|
||||||
"""
|
|
||||||
|
|
||||||
return ":".join("{:02x}".format(ord(str(c))) for c in s)
|
|
||||||
|
|
||||||
def readableMods(__mods):
|
|
||||||
"""
|
|
||||||
Return a string with readable std mods.
|
|
||||||
Used to convert a mods number for oppai
|
|
||||||
|
|
||||||
__mods -- mods bitwise number
|
|
||||||
return -- readable mods string, eg HDDT
|
|
||||||
"""
|
|
||||||
r = ""
|
|
||||||
if __mods == 0:
|
|
||||||
return r
|
|
||||||
if __mods & mods.NoFail > 0:
|
|
||||||
r += "NF"
|
|
||||||
if __mods & mods.Easy > 0:
|
|
||||||
r += "EZ"
|
|
||||||
if __mods & mods.Hidden > 0:
|
|
||||||
r += "HD"
|
|
||||||
if __mods & mods.HardRock > 0:
|
|
||||||
r += "HR"
|
|
||||||
if __mods & mods.DoubleTime > 0:
|
|
||||||
r += "DT"
|
|
||||||
if __mods & mods.HalfTime > 0:
|
|
||||||
r += "HT"
|
|
||||||
if __mods & mods.Flashlight > 0:
|
|
||||||
r += "FL"
|
|
||||||
if __mods & mods.SpunOut > 0:
|
|
||||||
r += "SO"
|
|
||||||
|
|
||||||
return r
|
|
||||||
|
|
||||||
def getRank(gameMode, __mods, acc, c300, c100, c50, cmiss):
|
|
||||||
"""
|
|
||||||
Return a string with rank/grade for a given score.
|
|
||||||
Used mainly for "tillerino"
|
|
||||||
|
|
||||||
gameMode -- mode (0 = osu!, 1 = Taiko, 2 = CtB, 3 = osu!mania)
|
|
||||||
__mods -- mods bitwise number
|
|
||||||
acc -- accuracy
|
|
||||||
c300 -- 300 hit count
|
|
||||||
c100 -- 100 hit count
|
|
||||||
c50 -- 50 hit count
|
|
||||||
cmiss -- miss count
|
|
||||||
return -- rank/grade string
|
|
||||||
"""
|
|
||||||
total = c300 + c100 + c50 + cmiss
|
|
||||||
hdfl = (__mods & (mods.Hidden | mods.Flashlight | mods.FadeIn)) > 0
|
|
||||||
|
|
||||||
ss = "sshd" if hdfl else "ss"
|
|
||||||
s = "shd" if hdfl else "s"
|
|
||||||
|
|
||||||
if gameMode == 0 or gameMode == 1:
|
|
||||||
# osu!std / taiko
|
|
||||||
ratio300 = c300 / total
|
|
||||||
ratio50 = c50 / total
|
|
||||||
if ratio300 == 1:
|
|
||||||
return ss
|
|
||||||
if ratio300 > 0.9 and ratio50 <= 0.01 and cmiss == 0:
|
|
||||||
return s
|
|
||||||
if (ratio300 > 0.8 and cmiss == 0) or (ratio300 > 0.9):
|
|
||||||
return "a"
|
|
||||||
if (ratio300 > 0.7 and cmiss == 0) or (ratio300 > 0.8):
|
|
||||||
return "b"
|
|
||||||
if ratio300 > 0.6:
|
|
||||||
return "c"
|
|
||||||
return "d"
|
|
||||||
elif gameMode == 2:
|
|
||||||
# CtB
|
|
||||||
if acc == 100:
|
|
||||||
return ss
|
|
||||||
if acc > 98:
|
|
||||||
return s
|
|
||||||
if acc > 94:
|
|
||||||
return "a"
|
|
||||||
if acc > 90:
|
|
||||||
return "b"
|
|
||||||
if acc > 85:
|
|
||||||
return "c"
|
|
||||||
return "d"
|
|
||||||
elif gameMode == 3:
|
|
||||||
# osu!mania
|
|
||||||
if acc == 100:
|
|
||||||
return ss
|
|
||||||
if acc > 95:
|
|
||||||
return s
|
|
||||||
if acc > 90:
|
|
||||||
return "a"
|
|
||||||
if acc > 80:
|
|
||||||
return "b"
|
|
||||||
if acc > 70:
|
|
||||||
return "c"
|
|
||||||
return "d"
|
|
||||||
|
|
||||||
return "a"
|
|
||||||
|
|
||||||
def strContains(s, w):
|
|
||||||
return (' ' + w + ' ') in (' ' + s + ' ')
|
|
||||||
|
|
||||||
def getTimestamp():
|
|
||||||
"""
|
|
||||||
Return current time in YYYY-MM-DD HH:MM:SS format.
|
|
||||||
Used in logs.
|
|
||||||
"""
|
|
||||||
return strftime("%Y-%m-%d %H:%M:%S", gmtime())
|
|
@@ -1,8 +1,9 @@
|
|||||||
import urllib.request
|
|
||||||
import json
|
import json
|
||||||
|
import urllib.request
|
||||||
|
|
||||||
|
from common.log import logUtils as log
|
||||||
from objects import glob
|
from objects import glob
|
||||||
|
|
||||||
from helpers import logHelper as log
|
|
||||||
|
|
||||||
def getCountry(ip):
|
def getCountry(ip):
|
||||||
"""
|
"""
|
||||||
@@ -11,7 +12,6 @@ def getCountry(ip):
|
|||||||
ip -- IP Address
|
ip -- IP Address
|
||||||
return -- Country code (2 letters)
|
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
|
||||||
result = json.loads(urllib.request.urlopen("{}/{}".format(glob.conf.config["localize"]["ipapiurl"], ip), timeout=3).read().decode())["country"]
|
result = json.loads(urllib.request.urlopen("{}/{}".format(glob.conf.config["localize"]["ipapiurl"], ip), timeout=3).read().decode())["country"]
|
||||||
@@ -20,7 +20,6 @@ def getCountry(ip):
|
|||||||
log.error("Error in get country")
|
log.error("Error in get country")
|
||||||
return "XX"
|
return "XX"
|
||||||
|
|
||||||
|
|
||||||
def getLocation(ip):
|
def getLocation(ip):
|
||||||
"""
|
"""
|
||||||
Get latitude and longitude from IP address
|
Get latitude and longitude from IP address
|
||||||
@@ -28,7 +27,6 @@ def getLocation(ip):
|
|||||||
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(",")
|
||||||
|
@@ -1,140 +0,0 @@
|
|||||||
from constants import bcolors
|
|
||||||
from helpers import discordBotHelper
|
|
||||||
from helpers import generalFunctions
|
|
||||||
from objects import glob
|
|
||||||
from helpers import userHelper
|
|
||||||
import time
|
|
||||||
import os
|
|
||||||
ENDL = "\n" if os.name == "posix" else "\r\n"
|
|
||||||
|
|
||||||
def logMessage(message, alertType = "INFO", messageColor = bcolors.ENDC, discord = None, alertDev = False, of = None, stdout = True):
|
|
||||||
"""
|
|
||||||
Logs a message to stdout/discord/file
|
|
||||||
|
|
||||||
message -- message to log
|
|
||||||
alertType -- can be any string. Standard types: INFO, WARNING and ERRORS. Defalt: INFO
|
|
||||||
messageColor -- message color (see constants.bcolors). Default = bcolots.ENDC (no color)
|
|
||||||
discord -- discord channel (bunker/cm/staff/general). Optional. Default = None
|
|
||||||
alertDev -- if True, devs will receive an hl on discord. Default: False
|
|
||||||
of -- if not None but a string, log the message to that file (inside .data folder). Eg: "warnings.txt" Default: None (don't log to file)
|
|
||||||
stdout -- if True, print the message to stdout. Default: True
|
|
||||||
"""
|
|
||||||
# Get type color from alertType
|
|
||||||
if alertType == "INFO":
|
|
||||||
typeColor = bcolors.GREEN
|
|
||||||
elif alertType == "WARNING":
|
|
||||||
typeColor = bcolors.YELLOW
|
|
||||||
elif alertType == "ERROR":
|
|
||||||
typeColor = bcolors.RED
|
|
||||||
elif alertType == "CHAT":
|
|
||||||
typeColor = bcolors.BLUE
|
|
||||||
elif alertType == "DEBUG":
|
|
||||||
typeColor = bcolors.PINK
|
|
||||||
else:
|
|
||||||
typeColor = bcolors.ENDC
|
|
||||||
|
|
||||||
# Message without colors
|
|
||||||
finalMessage = "[{time}] {type} - {message}".format(time=generalFunctions.getTimestamp(), type=alertType, message=message)
|
|
||||||
|
|
||||||
# Message with colors
|
|
||||||
finalMessageConsole = "{typeColor}[{time}] {type}{endc} - {messageColor}{message}{endc}".format(
|
|
||||||
time=generalFunctions.getTimestamp(),
|
|
||||||
type=alertType,
|
|
||||||
message=message,
|
|
||||||
|
|
||||||
typeColor=typeColor,
|
|
||||||
messageColor=messageColor,
|
|
||||||
endc=bcolors.ENDC)
|
|
||||||
|
|
||||||
# Log to console
|
|
||||||
if stdout == True:
|
|
||||||
print(finalMessageConsole)
|
|
||||||
|
|
||||||
# Log to discord if needed
|
|
||||||
if discord != None:
|
|
||||||
if discord == "bunker":
|
|
||||||
discordBotHelper.sendConfidential(message, alertDev)
|
|
||||||
elif discord == "cm":
|
|
||||||
discordBotHelper.sendCM(message)
|
|
||||||
elif discord == "staff":
|
|
||||||
discordBotHelper.sendStaff(message)
|
|
||||||
elif discord == "general":
|
|
||||||
discordBotHelper.sendGeneral(message)
|
|
||||||
|
|
||||||
# Log to file if needed
|
|
||||||
if of != None:
|
|
||||||
try:
|
|
||||||
glob.fLocks.lockFile(of)
|
|
||||||
with open(".data/{}".format(of), "a") as f:
|
|
||||||
f.write(finalMessage+ENDL)
|
|
||||||
finally:
|
|
||||||
glob.fLocks.unlockFile(of)
|
|
||||||
|
|
||||||
def warning(message, discord = None, alertDev = False):
|
|
||||||
"""
|
|
||||||
Log a warning to stdout, warnings.log (always) and discord (optional)
|
|
||||||
|
|
||||||
message -- warning message
|
|
||||||
discord -- if not None, send message to that discord channel through schiavo. Optional. Default = None
|
|
||||||
alertDev -- if True, send al hl to devs on discord. Optional. Default = False.
|
|
||||||
"""
|
|
||||||
logMessage(message, "WARNING", bcolors.YELLOW, discord, alertDev, "warnings.txt")
|
|
||||||
|
|
||||||
def error(message, discord = None, alertDev = True):
|
|
||||||
"""
|
|
||||||
Log an error to stdout, errors.log (always) and discord (optional)
|
|
||||||
|
|
||||||
message -- error message
|
|
||||||
discord -- if not None, send message to that discord channel through schiavo. Optional. Default = None
|
|
||||||
alertDev -- if True, send al hl to devs on discord. Optional. Default = False.
|
|
||||||
"""
|
|
||||||
logMessage(message, "ERROR", bcolors.RED, discord, alertDev, "errors.txt")
|
|
||||||
|
|
||||||
def info(message, discord = None, alertDev = False):
|
|
||||||
"""
|
|
||||||
Log an error to stdout (and info.log)
|
|
||||||
|
|
||||||
message -- info message
|
|
||||||
discord -- if not None, send message to that discord channel through schiavo. Optional. Default = None
|
|
||||||
alertDev -- if True, send al hl to devs on discord. Optional. Default = False.
|
|
||||||
"""
|
|
||||||
logMessage(message, "INFO", bcolors.ENDC, discord, alertDev, "info.txt")
|
|
||||||
|
|
||||||
def debug(message):
|
|
||||||
"""
|
|
||||||
Log a debug message to stdout and debug.log if server is running in debug mode
|
|
||||||
|
|
||||||
message -- debug message
|
|
||||||
"""
|
|
||||||
if glob.debug == True:
|
|
||||||
logMessage(message, "DEBUG", bcolors.PINK, of="debug.txt")
|
|
||||||
|
|
||||||
def chat(message):
|
|
||||||
"""
|
|
||||||
Log public messages to stdout and chatlog_public.txt
|
|
||||||
|
|
||||||
message -- chat message
|
|
||||||
"""
|
|
||||||
logMessage(message, "CHAT", bcolors.BLUE, of="chatlog_public.txt")
|
|
||||||
|
|
||||||
def pm(message):
|
|
||||||
"""
|
|
||||||
Log private messages to stdout and chatlog_private.txt
|
|
||||||
|
|
||||||
message -- chat message
|
|
||||||
"""
|
|
||||||
logMessage(message, "CHAT", bcolors.BLUE, of="chatlog_private.txt")
|
|
||||||
|
|
||||||
def rap(userID, message, discord=False, through="FokaBot"):
|
|
||||||
"""
|
|
||||||
Log a private message to Admin logs
|
|
||||||
|
|
||||||
userID -- userID of who made the action
|
|
||||||
message -- message without subject (eg: "is a meme" becomes "user is a meme")
|
|
||||||
discord -- if True, send message to discord
|
|
||||||
through -- "through" thing string. Optional. Default: "FokaBot"
|
|
||||||
"""
|
|
||||||
glob.db.execute("INSERT INTO rap_logs (id, userid, text, datetime, through) VALUES (NULL, %s, %s, %s, %s)", [userID, message, int(time.time()), through])
|
|
||||||
if discord == True:
|
|
||||||
username = userHelper.getUsername(userID)
|
|
||||||
logMessage("{} {}".format(username, message), discord=True)
|
|
@@ -8,7 +8,6 @@ def uleb128Encode(num):
|
|||||||
num -- int to encode
|
num -- int to encode
|
||||||
return -- bytearray with encoded number
|
return -- bytearray with encoded number
|
||||||
"""
|
"""
|
||||||
|
|
||||||
arr = bytearray()
|
arr = bytearray()
|
||||||
length = 0
|
length = 0
|
||||||
|
|
||||||
@@ -17,14 +16,13 @@ def uleb128Encode(num):
|
|||||||
|
|
||||||
while num > 0:
|
while num > 0:
|
||||||
arr.append(num & 127)
|
arr.append(num & 127)
|
||||||
num = num >> 7
|
num >>= 7
|
||||||
if num != 0:
|
if num != 0:
|
||||||
arr[length] = arr[length] | 128
|
arr[length] |= 128
|
||||||
length+=1
|
length+=1
|
||||||
|
|
||||||
return arr
|
return arr
|
||||||
|
|
||||||
|
|
||||||
def uleb128Decode(num):
|
def uleb128Decode(num):
|
||||||
"""
|
"""
|
||||||
Decode uleb128 -> int
|
Decode uleb128 -> int
|
||||||
@@ -32,57 +30,53 @@ def uleb128Decode(num):
|
|||||||
num -- encoded uleb128
|
num -- encoded uleb128
|
||||||
return -- list. [total, length]
|
return -- list. [total, length]
|
||||||
"""
|
"""
|
||||||
|
|
||||||
shift = 0
|
shift = 0
|
||||||
|
|
||||||
arr = [0,0] #total, length
|
arr = [0,0] #total, length
|
||||||
|
|
||||||
while True:
|
while True:
|
||||||
b = num[arr[1]]
|
b = num[arr[1]]
|
||||||
arr[1]+=1
|
arr[1]+=1
|
||||||
arr[0] = arr[0] | (int(b & 127) << shift)
|
arr[0] |= int(b & 127) << shift
|
||||||
if b & 128 == 0:
|
if b & 128 == 0:
|
||||||
break
|
break
|
||||||
shift += 7
|
shift += 7
|
||||||
|
|
||||||
return arr
|
return arr
|
||||||
|
|
||||||
|
def unpackData(data, dataType):
|
||||||
def unpackData(__data, __dataType):
|
|
||||||
"""
|
"""
|
||||||
Unpacks data according to dataType
|
Unpacks data according to dataType
|
||||||
|
|
||||||
__data -- bytes array to unpack
|
data -- bytes array to unpack
|
||||||
__dataType -- data type. See dataTypes.py
|
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"
|
||||||
elif __dataType == dataTypes.sInt16:
|
elif dataType == dataTypes.SINT16:
|
||||||
unpackType = "<h"
|
unpackType = "<h"
|
||||||
elif __dataType == dataTypes.uInt32:
|
elif dataType == dataTypes.UINT32:
|
||||||
unpackType = "<L"
|
unpackType = "<L"
|
||||||
elif __dataType == dataTypes.sInt32:
|
elif dataType == dataTypes.SINT32:
|
||||||
unpackType = "<l"
|
unpackType = "<l"
|
||||||
elif __dataType == dataTypes.uInt64:
|
elif dataType == dataTypes.UINT64:
|
||||||
unpackType = "<Q"
|
unpackType = "<Q"
|
||||||
elif __dataType == dataTypes.sInt64:
|
elif dataType == dataTypes.SINT64:
|
||||||
unpackType = "<q"
|
unpackType = "<q"
|
||||||
elif __dataType == dataTypes.string:
|
elif dataType == dataTypes.STRING:
|
||||||
unpackType = "<s"
|
unpackType = "<s"
|
||||||
elif __dataType == dataTypes.ffloat:
|
elif dataType == dataTypes.FFLOAT:
|
||||||
unpackType = "<f"
|
unpackType = "<f"
|
||||||
else:
|
else:
|
||||||
unpackType = "<B"
|
unpackType = "<B"
|
||||||
|
|
||||||
# Unpack
|
# Unpack
|
||||||
return struct.unpack(unpackType, bytes(__data))[0]
|
return struct.unpack(unpackType, bytes(data))[0]
|
||||||
|
|
||||||
|
def packData(__data, dataType):
|
||||||
def packData(__data, __dataType):
|
|
||||||
"""
|
"""
|
||||||
Packs data according to dataType
|
Packs data according to dataType
|
||||||
|
|
||||||
@@ -96,19 +90,19 @@ def packData(__data, __dataType):
|
|||||||
pack = True # if True, use pack. False only with strings
|
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:
|
||||||
# Bytes, do not use pack, do manually
|
# Bytes, do not use pack, do manually
|
||||||
pack = False
|
pack = False
|
||||||
data = __data
|
data = __data
|
||||||
elif __dataType == dataTypes.intList:
|
elif dataType == dataTypes.INT_LIST:
|
||||||
# Pack manually
|
# Pack manually
|
||||||
pack = False
|
pack = False
|
||||||
# Add length
|
# Add length
|
||||||
data = packData(len(__data), dataTypes.uInt16)
|
data = packData(len(__data), dataTypes.UINT16)
|
||||||
# Add all elements
|
# Add all elements
|
||||||
for i in __data:
|
for i in __data:
|
||||||
data += packData(i, dataTypes.sInt32)
|
data += packData(i, dataTypes.SINT32)
|
||||||
elif __dataType == dataTypes.string:
|
elif dataType == dataTypes.STRING:
|
||||||
# String, do not use pack, do manually
|
# String, do not use pack, do manually
|
||||||
pack = False
|
pack = False
|
||||||
if len(__data) == 0:
|
if len(__data) == 0:
|
||||||
@@ -119,33 +113,32 @@ def packData(__data, __dataType):
|
|||||||
data += b"\x0B"
|
data += b"\x0B"
|
||||||
data += uleb128Encode(len(__data))
|
data += uleb128Encode(len(__data))
|
||||||
data += str.encode(__data, "latin_1", "ignore")
|
data += str.encode(__data, "latin_1", "ignore")
|
||||||
elif __dataType == dataTypes.uInt16:
|
elif dataType == dataTypes.UINT16:
|
||||||
packType = "<H"
|
packType = "<H"
|
||||||
elif __dataType == dataTypes.sInt16:
|
elif dataType == dataTypes.SINT16:
|
||||||
packType = "<h"
|
packType = "<h"
|
||||||
elif __dataType == dataTypes.uInt32:
|
elif dataType == dataTypes.UINT32:
|
||||||
packType = "<L"
|
packType = "<L"
|
||||||
elif __dataType == dataTypes.sInt32:
|
elif dataType == dataTypes.SINT32:
|
||||||
packType = "<l"
|
packType = "<l"
|
||||||
elif __dataType == dataTypes.uInt64:
|
elif dataType == dataTypes.UINT64:
|
||||||
packType = "<Q"
|
packType = "<Q"
|
||||||
elif __dataType == dataTypes.sInt64:
|
elif dataType == dataTypes.SINT64:
|
||||||
packType = "<q"
|
packType = "<q"
|
||||||
elif __dataType == dataTypes.string:
|
elif dataType == dataTypes.STRING:
|
||||||
packType = "<s"
|
packType = "<s"
|
||||||
elif __dataType == dataTypes.ffloat:
|
elif dataType == dataTypes.FFLOAT:
|
||||||
packType = "<f"
|
packType = "<f"
|
||||||
else:
|
else:
|
||||||
packType = "<B"
|
packType = "<B"
|
||||||
|
|
||||||
# Pack if needed
|
# Pack if needed
|
||||||
if pack == True:
|
if pack:
|
||||||
data += struct.pack(packType, __data)
|
data += struct.pack(packType, __data)
|
||||||
|
|
||||||
return data
|
return data
|
||||||
|
|
||||||
# TODO: Wat dangerous
|
def buildPacket(__packet, __packetData=None):
|
||||||
def buildPacket(__packet, __packetData = []):
|
|
||||||
"""
|
"""
|
||||||
Build a packet
|
Build a packet
|
||||||
|
|
||||||
@@ -154,8 +147,9 @@ def buildPacket(__packet, __packetData = []):
|
|||||||
|
|
||||||
return -- packet bytes
|
return -- packet bytes
|
||||||
"""
|
"""
|
||||||
|
|
||||||
# Set some variables
|
# Set some variables
|
||||||
|
if __packetData is None:
|
||||||
|
__packetData = []
|
||||||
packetData = bytes()
|
packetData = bytes()
|
||||||
packetLength = 0
|
packetLength = 0
|
||||||
packetBytes = bytes()
|
packetBytes = bytes()
|
||||||
@@ -174,7 +168,6 @@ def buildPacket(__packet, __packetData = []):
|
|||||||
packetBytes += packetData # packet data
|
packetBytes += packetData # packet data
|
||||||
return packetBytes
|
return packetBytes
|
||||||
|
|
||||||
|
|
||||||
def readPacketID(stream):
|
def readPacketID(stream):
|
||||||
"""
|
"""
|
||||||
Read packetID from stream (0-1 bytes)
|
Read packetID from stream (0-1 bytes)
|
||||||
@@ -182,9 +175,7 @@ def readPacketID(stream):
|
|||||||
stream -- data stream
|
stream -- data stream
|
||||||
return -- packet ID (int)
|
return -- packet ID (int)
|
||||||
"""
|
"""
|
||||||
|
return unpackData(stream[0:2], dataTypes.UINT16)
|
||||||
return unpackData(stream[0:2], dataTypes.uInt16)
|
|
||||||
|
|
||||||
|
|
||||||
def readPacketLength(stream):
|
def readPacketLength(stream):
|
||||||
"""
|
"""
|
||||||
@@ -193,11 +184,10 @@ def readPacketLength(stream):
|
|||||||
stream -- data stream
|
stream -- data stream
|
||||||
return -- packet length (int)
|
return -- packet length (int)
|
||||||
"""
|
"""
|
||||||
|
return unpackData(stream[3:7], dataTypes.UINT32)
|
||||||
return unpackData(stream[3:7], dataTypes.uInt32)
|
|
||||||
|
|
||||||
|
|
||||||
def readPacketData(stream, structure = [], 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
|
||||||
|
|
||||||
@@ -208,12 +198,13 @@ def readPacketData(stream, structure = [], hasFirstBytes = True):
|
|||||||
Optional. Default: True
|
Optional. Default: True
|
||||||
return -- dictionary. key: name, value: read data
|
return -- dictionary. key: name, value: read data
|
||||||
"""
|
"""
|
||||||
|
|
||||||
# Read packet ID (first 2 bytes)
|
# Read packet ID (first 2 bytes)
|
||||||
|
if structure is None:
|
||||||
|
structure = []
|
||||||
data = {}
|
data = {}
|
||||||
|
|
||||||
# Skip packet ID and packet length if needed
|
# Skip packet ID and packet length if needed
|
||||||
if hasFirstBytes == True:
|
if hasFirstBytes:
|
||||||
end = 7
|
end = 7
|
||||||
start = 7
|
start = 7
|
||||||
else:
|
else:
|
||||||
@@ -224,22 +215,22 @@ def readPacketData(stream, structure = [], hasFirstBytes = True):
|
|||||||
for i in structure:
|
for i in structure:
|
||||||
start = end
|
start = end
|
||||||
unpack = True
|
unpack = True
|
||||||
if i[1] == dataTypes.intList:
|
if i[1] == dataTypes.INT_LIST:
|
||||||
# sInt32 list.
|
# sInt32 list.
|
||||||
# Unpack manually with for loop
|
# Unpack manually with for loop
|
||||||
unpack = False
|
unpack = False
|
||||||
|
|
||||||
# Read length (uInt16)
|
# Read length (uInt16)
|
||||||
length = unpackData(stream[start:start+2], dataTypes.uInt16)
|
length = unpackData(stream[start:start+2], dataTypes.UINT16)
|
||||||
|
|
||||||
# Read all int inside list
|
# Read all int inside list
|
||||||
data[i[0]] = []
|
data[i[0]] = []
|
||||||
for j in range(0,length):
|
for j in range(0,length):
|
||||||
data[i[0]].append(unpackData(stream[start+2+(4*j):start+2+(4*(j+1))], dataTypes.sInt32))
|
data[i[0]].append(unpackData(stream[start+2+(4*j):start+2+(4*(j+1))], dataTypes.SINT32))
|
||||||
|
|
||||||
# Update end
|
# Update end
|
||||||
end = start+2+(4*length)
|
end = start+2+(4*length)
|
||||||
elif i[1] == dataTypes.string:
|
elif i[1] == dataTypes.STRING:
|
||||||
# String, don't unpack
|
# String, don't unpack
|
||||||
unpack = False
|
unpack = False
|
||||||
|
|
||||||
@@ -256,17 +247,17 @@ def readPacketData(stream, structure = [], hasFirstBytes = True):
|
|||||||
|
|
||||||
# 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])
|
||||||
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:
|
||||||
end = start+2
|
end = start+2
|
||||||
elif i[1] == dataTypes.uInt32 or i[1] == dataTypes.sInt32:
|
elif i[1] == dataTypes.UINT32 or i[1] == dataTypes.SINT32:
|
||||||
end = start+4
|
end = start+4
|
||||||
elif i[1] == dataTypes.uInt64 or i[1] == dataTypes.sInt64:
|
elif i[1] == dataTypes.UINT64 or i[1] == dataTypes.SINT64:
|
||||||
end = start+8
|
end = start+8
|
||||||
|
|
||||||
# Unpack if needed
|
# Unpack if needed
|
||||||
if unpack == True:
|
if unpack:
|
||||||
data[i[0]] = unpackData(stream[start:end], i[1])
|
data[i[0]] = unpackData(stream[start:end], i[1])
|
||||||
|
|
||||||
return data
|
return data
|
||||||
|
@@ -1,36 +0,0 @@
|
|||||||
from helpers import cryptHelper
|
|
||||||
import base64
|
|
||||||
import bcrypt
|
|
||||||
|
|
||||||
def checkOldPassword(password, salt, rightPassword):
|
|
||||||
"""
|
|
||||||
Check if password+salt corresponds to rightPassword
|
|
||||||
|
|
||||||
password -- input password
|
|
||||||
salt -- password's salt
|
|
||||||
rightPassword -- right password
|
|
||||||
return -- bool
|
|
||||||
"""
|
|
||||||
|
|
||||||
return (rightPassword == cryptHelper.crypt(password, "$2y$"+str(base64.b64decode(salt))))
|
|
||||||
|
|
||||||
def checkNewPassword(password, dbPassword):
|
|
||||||
"""
|
|
||||||
Check if a password (version 2) is right.
|
|
||||||
|
|
||||||
password -- input password
|
|
||||||
dbPassword -- the password in the database
|
|
||||||
return -- bool
|
|
||||||
"""
|
|
||||||
password = password.encode("utf8")
|
|
||||||
dbPassword = dbPassword.encode("utf8")
|
|
||||||
return bcrypt.hashpw(password, dbPassword) == dbPassword
|
|
||||||
|
|
||||||
def genBcrypt(password):
|
|
||||||
"""
|
|
||||||
Bcrypts a password.
|
|
||||||
|
|
||||||
password -- the password to hash.
|
|
||||||
return -- bytestring
|
|
||||||
"""
|
|
||||||
return bcrypt.hashpw(password.encode("utf8"), bcrypt.gensalt(10, b'2a'))
|
|
@@ -1,89 +0,0 @@
|
|||||||
import tornado
|
|
||||||
import tornado.web
|
|
||||||
import tornado.gen
|
|
||||||
from tornado.ioloop import IOLoop
|
|
||||||
from objects import glob
|
|
||||||
from raven.contrib.tornado import SentryMixin
|
|
||||||
from raven.contrib.tornado import AsyncSentryClient
|
|
||||||
import gevent
|
|
||||||
|
|
||||||
class asyncRequestHandler(tornado.web.RequestHandler):
|
|
||||||
"""
|
|
||||||
Tornado asynchronous request handler
|
|
||||||
create a class that extends this one (requestHelper.asyncRequestHandler)
|
|
||||||
use asyncGet() and asyncPost() instad of get() and post().
|
|
||||||
Done. I'm not kidding.
|
|
||||||
"""
|
|
||||||
@tornado.web.asynchronous
|
|
||||||
@tornado.gen.engine
|
|
||||||
def get(self, *args, **kwargs):
|
|
||||||
try:
|
|
||||||
yield tornado.gen.Task(runBackground, (self.asyncGet, tuple(args), dict(kwargs)))
|
|
||||||
except Exception as e:
|
|
||||||
yield tornado.gen.Task(self.captureException, exc_info=True)
|
|
||||||
finally:
|
|
||||||
if not self._finished:
|
|
||||||
self.finish()
|
|
||||||
|
|
||||||
@tornado.web.asynchronous
|
|
||||||
@tornado.gen.engine
|
|
||||||
def post(self, *args, **kwargs):
|
|
||||||
try:
|
|
||||||
yield tornado.gen.Task(runBackground, (self.asyncPost, tuple(args), dict(kwargs)))
|
|
||||||
except Exception as e:
|
|
||||||
yield tornado.gen.Task(self.captureException, exc_info=True)
|
|
||||||
finally:
|
|
||||||
if not self._finished:
|
|
||||||
self.finish()
|
|
||||||
|
|
||||||
def asyncGet(self, *args, **kwargs):
|
|
||||||
self.send_error(405)
|
|
||||||
self.finish()
|
|
||||||
|
|
||||||
def asyncPost(self, *args, **kwargs):
|
|
||||||
self.send_error(405)
|
|
||||||
self.finish()
|
|
||||||
|
|
||||||
def getRequestIP(self):
|
|
||||||
realIP = self.request.headers.get("X-Forwarded-For") if glob.cloudflare == True else self.request.headers.get("X-Real-IP")
|
|
||||||
if realIP != None:
|
|
||||||
return realIP
|
|
||||||
return self.request.remote_ip
|
|
||||||
|
|
||||||
|
|
||||||
def runBackground(data, callback):
|
|
||||||
"""
|
|
||||||
Run a function in the background.
|
|
||||||
Used to handle multiple requests at the same time
|
|
||||||
"""
|
|
||||||
func, args, kwargs = data
|
|
||||||
def _callback(result):
|
|
||||||
IOLoop.instance().add_callback(lambda: callback(result))
|
|
||||||
#glob.pool.apply_async(func, args, kwargs, _callback)
|
|
||||||
g = gevent.Greenlet(func, *args, **kwargs)
|
|
||||||
g.link(_callback)
|
|
||||||
g.start()
|
|
||||||
|
|
||||||
def checkArguments(arguments, requiredArguments):
|
|
||||||
"""
|
|
||||||
Check that every requiredArguments elements are in arguments
|
|
||||||
|
|
||||||
arguments -- full argument list, from tornado
|
|
||||||
requiredArguments -- required arguments list es: ["u", "ha"]
|
|
||||||
handler -- handler string name to print in exception. Optional
|
|
||||||
return -- True if all arguments are passed, none if not
|
|
||||||
"""
|
|
||||||
for i in requiredArguments:
|
|
||||||
if i not in arguments:
|
|
||||||
return False
|
|
||||||
return True
|
|
||||||
|
|
||||||
def printArguments(t):
|
|
||||||
"""
|
|
||||||
Print passed arguments, for debug purposes
|
|
||||||
|
|
||||||
t -- tornado object (self)
|
|
||||||
"""
|
|
||||||
print("ARGS::")
|
|
||||||
for i in t.request.arguments:
|
|
||||||
print ("{}={}".format(i, t.get_argument(i)))
|
|
@@ -1,11 +1,27 @@
|
|||||||
from objects import glob
|
import math
|
||||||
from constants import serverPackets
|
|
||||||
import psutil
|
|
||||||
import os
|
import os
|
||||||
|
import signal
|
||||||
import sys
|
import sys
|
||||||
import threading
|
import threading
|
||||||
import signal
|
import time
|
||||||
from helpers import logHelper as log
|
|
||||||
|
import psutil
|
||||||
|
|
||||||
|
from common.constants import bcolors
|
||||||
|
from common.log import logUtils as log
|
||||||
|
from constants import serverPackets
|
||||||
|
from helpers import consoleHelper
|
||||||
|
from objects import glob
|
||||||
|
|
||||||
|
|
||||||
|
def dispose():
|
||||||
|
"""
|
||||||
|
Perform some clean up. Called on shutdown.
|
||||||
|
:return:
|
||||||
|
"""
|
||||||
|
print("> Disposing server... ")
|
||||||
|
glob.fileBuffers.flushAll()
|
||||||
|
consoleHelper.printColored("Goodbye!", bcolors.GREEN)
|
||||||
|
|
||||||
def runningUnderUnix():
|
def runningUnderUnix():
|
||||||
"""
|
"""
|
||||||
@@ -13,11 +29,9 @@ def runningUnderUnix():
|
|||||||
|
|
||||||
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
|
||||||
|
|
||||||
|
def scheduleShutdown(sendRestartTime, restart, message = "", delay=20):
|
||||||
def scheduleShutdown(sendRestartTime, restart, message = ""):
|
|
||||||
"""
|
"""
|
||||||
Schedule a server shutdown/restart
|
Schedule a server shutdown/restart
|
||||||
|
|
||||||
@@ -25,17 +39,16 @@ def scheduleShutdown(sendRestartTime, restart, message = ""):
|
|||||||
restart -- if True, server will restart. if False, server will shudown
|
restart -- if True, server will restart. if False, server will shudown
|
||||||
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
|
||||||
"""
|
"""
|
||||||
|
|
||||||
# Console output
|
# Console output
|
||||||
log.info("Pep.py will {} in {} seconds!".format("restart" if restart else "shutdown", sendRestartTime+20))
|
log.info("Pep.py will {} in {} seconds!".format("restart" if restart else "shutdown", sendRestartTime+delay))
|
||||||
log.info("Sending server restart packets in {} seconds...".format(sendRestartTime))
|
log.info("Sending server restart packets in {} seconds...".format(sendRestartTime))
|
||||||
|
|
||||||
# Send notification if set
|
# Send notification if set
|
||||||
if message != "":
|
if message != "":
|
||||||
glob.tokens.enqueueAll(serverPackets.notification(message))
|
glob.streams.broadcast("main", serverPackets.notification(message))
|
||||||
|
|
||||||
# Schedule server restart packet
|
# Schedule server restart packet
|
||||||
threading.Timer(sendRestartTime, glob.tokens.enqueueAll, [serverPackets.banchoRestart(50000)]).start()
|
threading.Timer(sendRestartTime, glob.streams.broadcast, ["main", serverPackets.banchoRestart(delay*2*1000)]).start()
|
||||||
glob.restarting = True
|
glob.restarting = True
|
||||||
|
|
||||||
# Restart/shutdown
|
# Restart/shutdown
|
||||||
@@ -44,44 +57,51 @@ def scheduleShutdown(sendRestartTime, restart, message = ""):
|
|||||||
else:
|
else:
|
||||||
action = shutdownServer
|
action = shutdownServer
|
||||||
|
|
||||||
# Schedule actual server shutdown/restart 20 seconds after server restart packet, so everyone gets it
|
# Schedule actual server shutdown/restart some seconds after server restart packet, so everyone gets it
|
||||||
threading.Timer(sendRestartTime+20, action).start()
|
threading.Timer(sendRestartTime+delay, action).start()
|
||||||
|
|
||||||
|
|
||||||
def restartServer():
|
def restartServer():
|
||||||
"""Restart pep.py script"""
|
"""Restart pep.py script"""
|
||||||
log.info("Restarting pep.py...")
|
log.info("Restarting pep.py...")
|
||||||
|
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"""
|
||||||
log.info("> Shutting down pep.py...")
|
log.info("Shutting down pep.py...")
|
||||||
|
dispose()
|
||||||
sig = signal.SIGKILL if runningUnderUnix() else signal.CTRL_C_EVENT
|
sig = signal.SIGKILL if runningUnderUnix() else signal.CTRL_C_EVENT
|
||||||
os.kill(os.getpid(), sig)
|
os.kill(os.getpid(), sig)
|
||||||
|
|
||||||
|
|
||||||
def getSystemInfo():
|
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 = {}
|
|
||||||
|
|
||||||
# Get if server is running under unix/nt
|
|
||||||
data["unix"] = runningUnderUnix()
|
|
||||||
|
|
||||||
# General stats
|
# General stats
|
||||||
data["connectedUsers"] = len(glob.tokens.tokens)
|
delta = time.time()-glob.startTime
|
||||||
data["matches"] = len(glob.matches.matches)
|
days = math.floor(delta/86400)
|
||||||
|
delta -= days*86400
|
||||||
|
|
||||||
|
hours = math.floor(delta/3600)
|
||||||
|
delta -= hours*3600
|
||||||
|
|
||||||
|
minutes = math.floor(delta/60)
|
||||||
|
delta -= minutes*60
|
||||||
|
|
||||||
|
seconds = math.floor(delta)
|
||||||
|
|
||||||
|
data["uptime"] = "{}d {}h {}m {}s".format(days, hours, minutes, seconds)
|
||||||
data["cpuUsage"] = psutil.cpu_percent()
|
data["cpuUsage"] = psutil.cpu_percent()
|
||||||
data["totalMemory"] = "{0:.2f}".format(psutil.virtual_memory()[0]/1074000000)
|
memory = psutil.virtual_memory()
|
||||||
data["usedMemory"] = "{0:.2f}".format(psutil.virtual_memory()[3]/1074000000)
|
data["totalMemory"] = "{0:.2f}".format(memory.total/1074000000)
|
||||||
|
data["usedMemory"] = "{0:.2f}".format(memory.active/1074000000)
|
||||||
|
|
||||||
# Unix only stats
|
# Unix only stats
|
||||||
if data["unix"] == True:
|
if data["unix"]:
|
||||||
data["loadAverage"] = os.getloadavg()
|
data["loadAverage"] = os.getloadavg()
|
||||||
else:
|
else:
|
||||||
data["loadAverage"] = (0,0,0)
|
data["loadAverage"] = (0,0,0)
|
||||||
|
@@ -1,621 +0,0 @@
|
|||||||
from helpers import passwordHelper
|
|
||||||
from constants import gameModes
|
|
||||||
from helpers import generalFunctions
|
|
||||||
from objects import glob
|
|
||||||
from helpers import logHelper as log
|
|
||||||
import time
|
|
||||||
from constants import privileges
|
|
||||||
|
|
||||||
def getID(username):
|
|
||||||
"""
|
|
||||||
Get username's user ID
|
|
||||||
|
|
||||||
db -- database connection
|
|
||||||
username -- user
|
|
||||||
return -- user id or False
|
|
||||||
"""
|
|
||||||
|
|
||||||
# Get user ID from db
|
|
||||||
userID = glob.db.fetch("SELECT id FROM users WHERE username = %s", [username])
|
|
||||||
|
|
||||||
# Make sure the query returned something
|
|
||||||
if userID == None:
|
|
||||||
return False
|
|
||||||
|
|
||||||
# Return user ID
|
|
||||||
return userID["id"]
|
|
||||||
|
|
||||||
|
|
||||||
def checkLogin(userID, password):
|
|
||||||
"""
|
|
||||||
Check userID's login with specified password
|
|
||||||
|
|
||||||
db -- database connection
|
|
||||||
userID -- user id
|
|
||||||
password -- plain md5 password
|
|
||||||
return -- True or False
|
|
||||||
"""
|
|
||||||
|
|
||||||
# Get password data
|
|
||||||
passwordData = glob.db.fetch("SELECT password_md5, salt, password_version FROM users WHERE id = %s", [userID])
|
|
||||||
|
|
||||||
# Make sure the query returned something
|
|
||||||
if passwordData == None:
|
|
||||||
return False
|
|
||||||
|
|
||||||
|
|
||||||
# Return valid/invalid based on the password version.
|
|
||||||
if passwordData["password_version"] == 2:
|
|
||||||
return passwordHelper.checkNewPassword(password, passwordData["password_md5"])
|
|
||||||
if passwordData["password_version"] == 1:
|
|
||||||
ok = passwordHelper.checkOldPassword(password, passwordData["salt"], passwordData["password_md5"])
|
|
||||||
if not ok: return False
|
|
||||||
newpass = passwordHelper.genBcrypt(password)
|
|
||||||
glob.db.execute("UPDATE users SET password_md5=%s, salt='', password_version='2' WHERE id = %s", [newpass, userID])
|
|
||||||
|
|
||||||
|
|
||||||
def exists(userID):
|
|
||||||
"""
|
|
||||||
Check if userID exists
|
|
||||||
|
|
||||||
userID -- user ID to check
|
|
||||||
return -- bool
|
|
||||||
"""
|
|
||||||
|
|
||||||
result = glob.db.fetch("SELECT id FROM users WHERE id = %s", [userID])
|
|
||||||
if result == None:
|
|
||||||
return False
|
|
||||||
else:
|
|
||||||
return True
|
|
||||||
|
|
||||||
def getSilenceEnd(userID):
|
|
||||||
"""
|
|
||||||
Get userID's **ABSOLUTE** silence end UNIX time
|
|
||||||
Remember to subtract time.time() to get the actual silence time
|
|
||||||
|
|
||||||
userID -- userID
|
|
||||||
return -- UNIX time
|
|
||||||
"""
|
|
||||||
|
|
||||||
return glob.db.fetch("SELECT silence_end FROM users WHERE id = %s", [userID])["silence_end"]
|
|
||||||
|
|
||||||
|
|
||||||
def silence(userID, seconds, silenceReason, author = 999):
|
|
||||||
"""
|
|
||||||
Silence someone
|
|
||||||
|
|
||||||
userID -- userID
|
|
||||||
seconds -- silence length in seconds
|
|
||||||
silenceReason -- Silence reason shown on website
|
|
||||||
author -- userID of who silenced the user. Default: 999
|
|
||||||
"""
|
|
||||||
# db qurey
|
|
||||||
silenceEndTime = int(time.time())+seconds
|
|
||||||
glob.db.execute("UPDATE users SET silence_end = %s, silence_reason = %s WHERE id = %s", [silenceEndTime, silenceReason, userID])
|
|
||||||
|
|
||||||
# Loh
|
|
||||||
targetUsername = getUsername(userID)
|
|
||||||
# TODO: exists check im drunk rn i need to sleep (stampa piede ubriaco confirmed)
|
|
||||||
if seconds > 0:
|
|
||||||
log.rap(author, "has silenced {} for {} seconds for the following reason: \"{}\"".format(targetUsername, seconds, silenceReason), True)
|
|
||||||
else:
|
|
||||||
log.rap(author, "has removed {}'s silence".format(targetUsername), True)
|
|
||||||
|
|
||||||
def getRankedScore(userID, gameMode):
|
|
||||||
"""
|
|
||||||
Get userID's ranked score relative to gameMode
|
|
||||||
|
|
||||||
userID -- userID
|
|
||||||
gameMode -- int value, see gameModes
|
|
||||||
return -- ranked score
|
|
||||||
"""
|
|
||||||
|
|
||||||
modeForDB = gameModes.getGameModeForDB(gameMode)
|
|
||||||
return glob.db.fetch("SELECT ranked_score_"+modeForDB+" FROM users_stats WHERE id = %s", [userID])["ranked_score_"+modeForDB]
|
|
||||||
|
|
||||||
|
|
||||||
def getTotalScore(userID, gameMode):
|
|
||||||
"""
|
|
||||||
Get userID's total score relative to gameMode
|
|
||||||
|
|
||||||
userID -- userID
|
|
||||||
gameMode -- int value, see gameModes
|
|
||||||
return -- total score
|
|
||||||
"""
|
|
||||||
|
|
||||||
modeForDB = gameModes.getGameModeForDB(gameMode)
|
|
||||||
return glob.db.fetch("SELECT total_score_"+modeForDB+" FROM users_stats WHERE id = %s", [userID])["total_score_"+modeForDB]
|
|
||||||
|
|
||||||
|
|
||||||
def getAccuracy(userID, gameMode):
|
|
||||||
"""
|
|
||||||
Get userID's average accuracy relative to gameMode
|
|
||||||
|
|
||||||
userID -- userID
|
|
||||||
gameMode -- int value, see gameModes
|
|
||||||
return -- accuracy
|
|
||||||
"""
|
|
||||||
|
|
||||||
modeForDB = gameModes.getGameModeForDB(gameMode)
|
|
||||||
return glob.db.fetch("SELECT avg_accuracy_"+modeForDB+" FROM users_stats WHERE id = %s", [userID])["avg_accuracy_"+modeForDB]
|
|
||||||
|
|
||||||
|
|
||||||
def getGameRank(userID, gameMode):
|
|
||||||
"""
|
|
||||||
Get userID's **in-game rank** (eg: #1337) relative to gameMode
|
|
||||||
|
|
||||||
userID -- userID
|
|
||||||
gameMode -- int value, see gameModes
|
|
||||||
return -- game rank
|
|
||||||
"""
|
|
||||||
|
|
||||||
modeForDB = gameModes.getGameModeForDB(gameMode)
|
|
||||||
result = glob.db.fetch("SELECT position FROM leaderboard_"+modeForDB+" WHERE user = %s", [userID])
|
|
||||||
if result == None:
|
|
||||||
return 0
|
|
||||||
else:
|
|
||||||
return result["position"]
|
|
||||||
|
|
||||||
|
|
||||||
def getPlaycount(userID, gameMode):
|
|
||||||
"""
|
|
||||||
Get userID's playcount relative to gameMode
|
|
||||||
|
|
||||||
userID -- userID
|
|
||||||
gameMode -- int value, see gameModes
|
|
||||||
return -- playcount
|
|
||||||
"""
|
|
||||||
|
|
||||||
modeForDB = gameModes.getGameModeForDB(gameMode)
|
|
||||||
return glob.db.fetch("SELECT playcount_"+modeForDB+" FROM users_stats WHERE id = %s", [userID])["playcount_"+modeForDB]
|
|
||||||
|
|
||||||
|
|
||||||
def getUsername(userID):
|
|
||||||
"""
|
|
||||||
Get userID's username
|
|
||||||
|
|
||||||
userID -- userID
|
|
||||||
return -- username
|
|
||||||
"""
|
|
||||||
|
|
||||||
return glob.db.fetch("SELECT username FROM users WHERE id = %s", [userID])["username"]
|
|
||||||
|
|
||||||
|
|
||||||
def getFriendList(userID):
|
|
||||||
"""
|
|
||||||
Get userID's friendlist
|
|
||||||
|
|
||||||
userID -- userID
|
|
||||||
return -- list with friends userIDs. [0] if no friends.
|
|
||||||
"""
|
|
||||||
|
|
||||||
# Get friends from db
|
|
||||||
friends = glob.db.fetchAll("SELECT user2 FROM users_relationships WHERE user1 = %s", [userID])
|
|
||||||
|
|
||||||
if friends == None or len(friends) == 0:
|
|
||||||
# We have no friends, return 0 list
|
|
||||||
return [0]
|
|
||||||
else:
|
|
||||||
# Get only friends
|
|
||||||
friends = [i["user2"] for i in friends]
|
|
||||||
|
|
||||||
# Return friend IDs
|
|
||||||
return friends
|
|
||||||
|
|
||||||
|
|
||||||
def addFriend(userID, friendID):
|
|
||||||
"""
|
|
||||||
Add friendID to userID's friend list
|
|
||||||
|
|
||||||
userID -- user
|
|
||||||
friendID -- new friend
|
|
||||||
"""
|
|
||||||
|
|
||||||
# Make sure we aren't adding us to our friends
|
|
||||||
if userID == friendID:
|
|
||||||
return
|
|
||||||
|
|
||||||
# check user isn't already a friend of ours
|
|
||||||
if glob.db.fetch("SELECT id FROM users_relationships WHERE user1 = %s AND user2 = %s", [userID, friendID]) != None:
|
|
||||||
return
|
|
||||||
|
|
||||||
# Set new value
|
|
||||||
glob.db.execute("INSERT INTO users_relationships (user1, user2) VALUES (%s, %s)", [userID, friendID])
|
|
||||||
|
|
||||||
|
|
||||||
def removeFriend(userID, friendID):
|
|
||||||
"""
|
|
||||||
Remove friendID from userID's friend list
|
|
||||||
|
|
||||||
userID -- user
|
|
||||||
friendID -- old friend
|
|
||||||
"""
|
|
||||||
|
|
||||||
# Delete user relationship. We don't need to check if the relationship was there, because who gives a shit,
|
|
||||||
# if they were not friends and they don't want to be anymore, be it. ¯\_(ツ)_/¯
|
|
||||||
glob.db.execute("DELETE FROM users_relationships WHERE user1 = %s AND user2 = %s", [userID, friendID])
|
|
||||||
|
|
||||||
|
|
||||||
def getCountry(userID):
|
|
||||||
"""
|
|
||||||
Get userID's country **(two letters)**.
|
|
||||||
Use countryHelper.getCountryID with what that function returns
|
|
||||||
to get osu! country ID relative to that user
|
|
||||||
|
|
||||||
userID -- user
|
|
||||||
return -- country code (two letters)
|
|
||||||
"""
|
|
||||||
|
|
||||||
return glob.db.fetch("SELECT country FROM users_stats WHERE id = %s", [userID])["country"]
|
|
||||||
|
|
||||||
def getPP(userID, gameMode):
|
|
||||||
"""
|
|
||||||
Get userID's PP relative to gameMode
|
|
||||||
|
|
||||||
userID -- user
|
|
||||||
return -- PP
|
|
||||||
"""
|
|
||||||
|
|
||||||
modeForDB = gameModes.getGameModeForDB(gameMode)
|
|
||||||
return glob.db.fetch("SELECT pp_{} FROM users_stats WHERE id = %s".format(modeForDB), [userID])["pp_{}".format(modeForDB)]
|
|
||||||
|
|
||||||
def setCountry(userID, country):
|
|
||||||
"""
|
|
||||||
Set userID's country (two letters)
|
|
||||||
|
|
||||||
userID -- userID
|
|
||||||
country -- country letters
|
|
||||||
"""
|
|
||||||
glob.db.execute("UPDATE users_stats SET country = %s WHERE id = %s", [country, userID])
|
|
||||||
|
|
||||||
def getShowCountry(userID):
|
|
||||||
"""
|
|
||||||
Get userID's show country status
|
|
||||||
|
|
||||||
userID -- userID
|
|
||||||
return -- True if country is shown, False if it's hidden
|
|
||||||
"""
|
|
||||||
country = glob.db.fetch("SELECT show_country FROM users_stats WHERE id = %s", [userID])
|
|
||||||
if country == None:
|
|
||||||
return False
|
|
||||||
return generalFunctions.stringToBool(country)
|
|
||||||
|
|
||||||
def logIP(userID, ip):
|
|
||||||
"""
|
|
||||||
User IP log
|
|
||||||
USED FOR MULTIACCOUNT DETECTION
|
|
||||||
"""
|
|
||||||
glob.db.execute("""INSERT INTO ip_user (userid, ip, occurencies) VALUES (%s, %s, 1)
|
|
||||||
ON DUPLICATE KEY UPDATE occurencies = occurencies + 1""", [userID, ip])
|
|
||||||
|
|
||||||
def saveBanchoSession(userID, ip):
|
|
||||||
"""
|
|
||||||
Save userid and ip of this token in bancho_sessions table.
|
|
||||||
Used to cache logins on LETS requests
|
|
||||||
"""
|
|
||||||
log.debug("Saving bancho session ({}::{}) in db".format(userID, ip))
|
|
||||||
glob.db.execute("INSERT INTO bancho_sessions (id, userid, ip) VALUES (NULL, %s, %s)", [userID, ip])
|
|
||||||
|
|
||||||
def deleteBanchoSessions(userID, ip):
|
|
||||||
"""Delete this bancho session from DB"""
|
|
||||||
log.debug("Deleting bancho session ({}::{}) from db".format(userID, ip))
|
|
||||||
try:
|
|
||||||
glob.db.execute("DELETE FROM bancho_sessions WHERE userid = %s AND ip = %s", [userID, ip])
|
|
||||||
except:
|
|
||||||
log.warning("Token for user: {} ip: {} doesn't exist".format(userID, ip))
|
|
||||||
|
|
||||||
def is2FAEnabled(userID):
|
|
||||||
"""Returns True if 2FA is enable for this account"""
|
|
||||||
result = glob.db.fetch("SELECT id FROM 2fa_telegram WHERE userid = %s LIMIT 1", [userID])
|
|
||||||
return True if result is not None else False
|
|
||||||
|
|
||||||
def check2FA(userID, ip):
|
|
||||||
"""Returns True if this IP is untrusted"""
|
|
||||||
if is2FAEnabled(userID) == False:
|
|
||||||
return False
|
|
||||||
|
|
||||||
result = glob.db.fetch("SELECT id FROM ip_user WHERE userid = %s AND ip = %s", [userID, ip])
|
|
||||||
return True if result is None else False
|
|
||||||
|
|
||||||
def getUserStats(userID, gameMode):
|
|
||||||
"""
|
|
||||||
Get all user stats relative to gameMode with only two queries
|
|
||||||
|
|
||||||
userID --
|
|
||||||
gameMode -- gameMode number
|
|
||||||
return -- dictionary with results
|
|
||||||
"""
|
|
||||||
modeForDB = gameModes.getGameModeForDB(gameMode)
|
|
||||||
|
|
||||||
# Get stats
|
|
||||||
stats = glob.db.fetch("""SELECT
|
|
||||||
ranked_score_{gm} AS rankedScore,
|
|
||||||
avg_accuracy_{gm} AS accuracy,
|
|
||||||
playcount_{gm} AS playcount,
|
|
||||||
total_score_{gm} AS totalScore,
|
|
||||||
pp_{gm} AS pp
|
|
||||||
FROM users_stats WHERE id = %s LIMIT 1""".format(gm=modeForDB), [userID])
|
|
||||||
|
|
||||||
# Get game rank
|
|
||||||
result = glob.db.fetch("SELECT position FROM leaderboard_{} WHERE user = %s LIMIT 1".format(modeForDB), [userID])
|
|
||||||
if result == None:
|
|
||||||
stats["gameRank"] = 0
|
|
||||||
else:
|
|
||||||
stats["gameRank"] = result["position"]
|
|
||||||
|
|
||||||
# Return stats + game rank
|
|
||||||
return stats
|
|
||||||
|
|
||||||
def isAllowed(userID):
|
|
||||||
"""
|
|
||||||
Check if userID is not banned or restricted
|
|
||||||
|
|
||||||
userID -- id of the user
|
|
||||||
return -- True if not banned or restricted, otherwise false.
|
|
||||||
"""
|
|
||||||
result = glob.db.fetch("SELECT privileges FROM users WHERE id = %s", [userID])
|
|
||||||
if result != None:
|
|
||||||
return (result["privileges"] & privileges.USER_NORMAL) and (result["privileges"] & privileges.USER_PUBLIC)
|
|
||||||
else:
|
|
||||||
return False
|
|
||||||
|
|
||||||
def isRestricted(userID):
|
|
||||||
"""
|
|
||||||
Check if userID is restricted
|
|
||||||
|
|
||||||
userID -- id of the user
|
|
||||||
return -- True if not restricted, otherwise false.
|
|
||||||
"""
|
|
||||||
result = glob.db.fetch("SELECT privileges FROM users WHERE id = %s", [userID])
|
|
||||||
if result != None:
|
|
||||||
return (result["privileges"] & privileges.USER_NORMAL) and not (result["privileges"] & privileges.USER_PUBLIC)
|
|
||||||
else:
|
|
||||||
return False
|
|
||||||
|
|
||||||
def isBanned(userID):
|
|
||||||
"""
|
|
||||||
Check if userID is banned
|
|
||||||
|
|
||||||
userID -- id of the user
|
|
||||||
return -- True if not banned, otherwise false.
|
|
||||||
"""
|
|
||||||
result = glob.db.fetch("SELECT privileges FROM users WHERE id = %s", [userID])
|
|
||||||
if result != None:
|
|
||||||
return not (result["privileges"] & 3 > 0)
|
|
||||||
else:
|
|
||||||
return True
|
|
||||||
|
|
||||||
def ban(userID):
|
|
||||||
"""
|
|
||||||
Ban userID
|
|
||||||
|
|
||||||
userID -- id of user
|
|
||||||
"""
|
|
||||||
banDateTime = int(time.time())
|
|
||||||
glob.db.execute("UPDATE users SET privileges = privileges & %s, ban_datetime = %s WHERE id = %s", [ ~(privileges.USER_NORMAL | privileges.USER_PUBLIC | privileges.USER_PENDING_VERIFICATION) , banDateTime, userID])
|
|
||||||
|
|
||||||
def unban(userID):
|
|
||||||
"""
|
|
||||||
Unban userID
|
|
||||||
|
|
||||||
userID -- id of user
|
|
||||||
"""
|
|
||||||
glob.db.execute("UPDATE users SET privileges = privileges | %s, ban_datetime = 0 WHERE id = %s", [ (privileges.USER_NORMAL | privileges.USER_PUBLIC) , userID])
|
|
||||||
|
|
||||||
def restrict(userID):
|
|
||||||
"""
|
|
||||||
Put userID in restricted mode
|
|
||||||
|
|
||||||
userID -- id of user
|
|
||||||
"""
|
|
||||||
banDateTime = int(time.time())
|
|
||||||
glob.db.execute("UPDATE users SET privileges = privileges & %s, ban_datetime = %s WHERE id = %s", [~privileges.USER_PUBLIC, banDateTime, userID])
|
|
||||||
|
|
||||||
def unrestrict(userID):
|
|
||||||
"""
|
|
||||||
Remove restricted mode from userID.
|
|
||||||
Same as unban().
|
|
||||||
|
|
||||||
userID -- id of user
|
|
||||||
"""
|
|
||||||
unban(userID)
|
|
||||||
|
|
||||||
def getPrivileges(userID):
|
|
||||||
"""
|
|
||||||
Return privileges for userID
|
|
||||||
|
|
||||||
userID -- id of user
|
|
||||||
return -- privileges number
|
|
||||||
"""
|
|
||||||
result = glob.db.fetch("SELECT privileges FROM users WHERE id = %s", [userID])
|
|
||||||
if result != None:
|
|
||||||
return result["privileges"]
|
|
||||||
else:
|
|
||||||
return 0
|
|
||||||
|
|
||||||
def setPrivileges(userID, priv):
|
|
||||||
"""
|
|
||||||
Set userID's privileges in db
|
|
||||||
|
|
||||||
userID -- id of user
|
|
||||||
priv -- privileges number
|
|
||||||
"""
|
|
||||||
glob.db.execute("UPDATE users SET privileges = %s WHERE id = %s", [priv, userID])
|
|
||||||
|
|
||||||
def isInPrivilegeGroup(userID, groupName):
|
|
||||||
groupPrivileges = glob.db.fetch("SELECT privileges FROM privileges_groups WHERE name = %s", [groupName])
|
|
||||||
if groupPrivileges == None:
|
|
||||||
return False
|
|
||||||
groupPrivileges = groupPrivileges["privileges"]
|
|
||||||
userToken = glob.tokens.getTokenFromUserID(userID)
|
|
||||||
if userToken != None:
|
|
||||||
userPrivileges = userToken.privileges
|
|
||||||
else:
|
|
||||||
userPrivileges = getPrivileges(userID)
|
|
||||||
return (userPrivileges == groupPrivileges) or (userPrivileges == (groupPrivileges | privileges.USER_DONOR))
|
|
||||||
|
|
||||||
|
|
||||||
def appendNotes(userID, notes, addNl = True):
|
|
||||||
"""
|
|
||||||
Append "notes" to current userID's "notes for CM"
|
|
||||||
|
|
||||||
userID -- id of user
|
|
||||||
notes -- text to append
|
|
||||||
addNl -- if True, prepend \n to notes. Optional. Default: True.
|
|
||||||
"""
|
|
||||||
if addNl == True:
|
|
||||||
notes = "\n"+notes
|
|
||||||
glob.db.execute("UPDATE users SET notes=CONCAT(COALESCE(notes, ''),%s) WHERE id = %s", [notes, userID])
|
|
||||||
|
|
||||||
|
|
||||||
def logHardware(userID, hashes, activation = False):
|
|
||||||
"""
|
|
||||||
Hardware log
|
|
||||||
USED FOR MULTIACCOUNT DETECTION
|
|
||||||
|
|
||||||
Peppy's botnet (client data) structure (new line = "|", already split)
|
|
||||||
[0] osu! version
|
|
||||||
[1] plain mac addressed, separated by "."
|
|
||||||
[2] mac addresses hash set
|
|
||||||
[3] unique ID
|
|
||||||
[4] disk ID
|
|
||||||
|
|
||||||
return -- True if hw is not banned, otherwise false
|
|
||||||
"""
|
|
||||||
# Make sure the strings are not empty
|
|
||||||
for i in hashes[2:5]:
|
|
||||||
if i == "":
|
|
||||||
log.warning("Invalid hash set ({}) for user {} in HWID check".format(hashes, userID), "bunk")
|
|
||||||
return False
|
|
||||||
|
|
||||||
# Run some HWID checks on that user if he is not restricted
|
|
||||||
if isRestricted(userID) == False:
|
|
||||||
# Get username
|
|
||||||
username = getUsername(userID)
|
|
||||||
|
|
||||||
# Get the list of banned or restricted users that have logged in from this or similar HWID hash set
|
|
||||||
banned = glob.db.fetchAll("""SELECT users.id as userid, hw_user.occurencies, users.username FROM hw_user
|
|
||||||
LEFT JOIN users ON users.id = hw_user.userid
|
|
||||||
WHERE hw_user.userid != %(userid)s
|
|
||||||
AND (IF(%(mac)s!='b4ec3c4334a0249dae95c284ec5983df', hw_user.mac = %(mac)s, 1) AND hw_user.unique_id = %(uid)s AND hw_user.disk_id = %(diskid)s)
|
|
||||||
AND (users.privileges & 3 != 3)""", {
|
|
||||||
"userid": userID,
|
|
||||||
"mac": hashes[2],
|
|
||||||
"uid": hashes[3],
|
|
||||||
"diskid": hashes[4],
|
|
||||||
})
|
|
||||||
|
|
||||||
for i in banned:
|
|
||||||
# Get the total numbers of logins
|
|
||||||
total = glob.db.fetch("SELECT COUNT(*) AS count FROM hw_user WHERE userid = %s LIMIT 1", [userID])
|
|
||||||
# and make sure it is valid
|
|
||||||
if total == None:
|
|
||||||
continue
|
|
||||||
total = total["count"]
|
|
||||||
|
|
||||||
# Calculate 10% of total
|
|
||||||
perc = (total*10)/100
|
|
||||||
|
|
||||||
if i["occurencies"] >= perc:
|
|
||||||
# If the banned user has logged in more than 10% of the times from this user, restrict this user
|
|
||||||
restrict(userID)
|
|
||||||
appendNotes(userID, "-- Logged in from HWID ({hwid}) used more than 10% from user {banned} ({bannedUserID}), who is banned/restricted.".format(
|
|
||||||
hwid=hashes[2:5],
|
|
||||||
banned=i["username"],
|
|
||||||
bannedUserID=i["userid"]
|
|
||||||
))
|
|
||||||
log.warning("**{user}** ({userID}) has been restricted because he has logged in from HWID _({hwid})_ used more than 10% from banned/restricted user **{banned}** ({bannedUserID}), **possible multiaccount**.".format(
|
|
||||||
user=username,
|
|
||||||
userID=userID,
|
|
||||||
hwid=hashes[2:5],
|
|
||||||
banned=i["username"],
|
|
||||||
bannedUserID=i["userid"]
|
|
||||||
), "cm")
|
|
||||||
|
|
||||||
# Update hash set occurencies
|
|
||||||
glob.db.execute("""
|
|
||||||
INSERT INTO hw_user (id, userid, mac, unique_id, disk_id, occurencies) VALUES (NULL, %s, %s, %s, %s, 1)
|
|
||||||
ON DUPLICATE KEY UPDATE occurencies = occurencies + 1
|
|
||||||
""", [userID, hashes[2], hashes[3], hashes[4]])
|
|
||||||
|
|
||||||
# Optionally, set this hash as 'used for activation'
|
|
||||||
if activation == True:
|
|
||||||
glob.db.execute("UPDATE hw_user SET activated = 1 WHERE userid = %s AND mac = %s AND unique_id = %s AND disk_id = %s", [userID, hashes[2], hashes[3], hashes[4]])
|
|
||||||
|
|
||||||
# Access granted, abbiamo impiegato 3 giorni
|
|
||||||
# We grant access even in case of login from banned HWID
|
|
||||||
# because we call restrict() above so there's no need to deny the access.
|
|
||||||
return True
|
|
||||||
|
|
||||||
|
|
||||||
def resetPendingFlag(userID, success=True):
|
|
||||||
"""
|
|
||||||
Remove pending flag from an user.
|
|
||||||
|
|
||||||
userID -- ID of the user
|
|
||||||
success -- if True, set USER_PUBLIC and USER_NORMAL flags too
|
|
||||||
"""
|
|
||||||
glob.db.execute("UPDATE users SET privileges = privileges & %s WHERE id = %s LIMIT 1", [~privileges.USER_PENDING_VERIFICATION, userID])
|
|
||||||
if success == True:
|
|
||||||
glob.db.execute("UPDATE users SET privileges = privileges | %s WHERE id = %s LIMIT 1", [(privileges.USER_PUBLIC | privileges.USER_NORMAL), userID])
|
|
||||||
|
|
||||||
def verifyUser(userID, hashes):
|
|
||||||
# Check for valid hash set
|
|
||||||
for i in hashes[2:5]:
|
|
||||||
if i == "":
|
|
||||||
log.warning("Invalid hash set ({}) for user {} while verifying the account".format(str(hashes), userID), "bunk")
|
|
||||||
return False
|
|
||||||
|
|
||||||
# Get username
|
|
||||||
username = getUsername(userID)
|
|
||||||
|
|
||||||
# Make sure there are no other accounts activated with this exact mac/unique id/hwid
|
|
||||||
match = glob.db.fetchAll("SELECT userid FROM hw_user WHERE (IF(%(mac)s != 'b4ec3c4334a0249dae95c284ec5983df', mac = %(mac)s, 1) AND unique_id = %(uid)s AND disk_id = %(diskid)s) AND userid != %(userid)s AND activated = 1 LIMIT 1", {
|
|
||||||
"mac": hashes[2],
|
|
||||||
"uid": hashes[3],
|
|
||||||
"diskid": hashes[4],
|
|
||||||
"userid": userID
|
|
||||||
})
|
|
||||||
|
|
||||||
if match:
|
|
||||||
# This is a multiaccount, restrict other account and ban this account
|
|
||||||
|
|
||||||
# Get original userID and username (lowest ID)
|
|
||||||
originalUserID = match[0]["userid"]
|
|
||||||
originalUsername = getUsername(originalUserID)
|
|
||||||
|
|
||||||
# Ban this user and append notes
|
|
||||||
ban(userID) # this removes the USER_PENDING_VERIFICATION flag too
|
|
||||||
appendNotes(userID, "-- {}'s multiaccount ({}), found HWID match while verifying account ({})".format(originalUsername, originalUserID, hashes[2:5]))
|
|
||||||
appendNotes(originalUserID, "-- Has created multiaccount {} ({})".format(username, userID))
|
|
||||||
|
|
||||||
# Restrict the original
|
|
||||||
restrict(originalUserID)
|
|
||||||
|
|
||||||
# Discord message
|
|
||||||
log.warning("User **{originalUsername}** ({originalUserID}) has been restricted because he has created multiaccount **{username}** ({userID}). The multiaccount has been banned.".format(
|
|
||||||
originalUsername=originalUsername,
|
|
||||||
originalUserID=originalUserID,
|
|
||||||
username=username,
|
|
||||||
userID=userID
|
|
||||||
), "cm")
|
|
||||||
|
|
||||||
# Disallow login
|
|
||||||
return False
|
|
||||||
else:
|
|
||||||
# No matches found, set USER_PUBLIC and USER_NORMAL flags and reset USER_PENDING_VERIFICATION flag
|
|
||||||
resetPendingFlag(userID)
|
|
||||||
log.info("User **{}** ({}) has verified his account with hash set _{}_".format(username, userID, hashes[2:5]), "cm")
|
|
||||||
|
|
||||||
# Allow login
|
|
||||||
return True
|
|
||||||
|
|
||||||
def hasVerifiedHardware(userID):
|
|
||||||
"""
|
|
||||||
userID -- id of the user
|
|
||||||
return -- True if hwid activation data is in db, otherwise false
|
|
||||||
"""
|
|
||||||
data = glob.db.fetch("SELECT id FROM hw_user WHERE userid = %s AND activated = 1 LIMIT 1", [userID])
|
|
||||||
if data != None:
|
|
||||||
return True
|
|
||||||
return False
|
|
133
irc/ircserver.py
133
irc/ircserver.py
@@ -6,19 +6,21 @@ by Joel Rosdahl, licensed under the GNU GPL 2 License.
|
|||||||
Most of the reference code from miniircd was used for the low-level logic.
|
Most of the reference code from miniircd was used for the low-level logic.
|
||||||
The high-level code has been rewritten to make it compatible with pep.py.
|
The high-level code has been rewritten to make it compatible with pep.py.
|
||||||
"""
|
"""
|
||||||
import sys
|
|
||||||
import traceback
|
|
||||||
import socket
|
|
||||||
import select
|
|
||||||
import time
|
|
||||||
import re
|
|
||||||
import hashlib
|
import hashlib
|
||||||
from helpers import logHelper as log
|
import re
|
||||||
|
import select
|
||||||
|
import socket
|
||||||
|
import sys
|
||||||
|
import time
|
||||||
|
import traceback
|
||||||
|
|
||||||
from objects import glob
|
|
||||||
from helpers import chatHelper as chat
|
|
||||||
import raven
|
import raven
|
||||||
|
|
||||||
|
from common.log import logUtils as log
|
||||||
|
from helpers import chatHelper as chat
|
||||||
|
from objects import glob
|
||||||
|
|
||||||
|
|
||||||
class Client:
|
class Client:
|
||||||
"""
|
"""
|
||||||
IRC Client object
|
IRC Client object
|
||||||
@@ -42,7 +44,8 @@ class Client:
|
|||||||
self.server = server
|
self.server = server
|
||||||
self.socket = sock
|
self.socket = sock
|
||||||
(self.ip, self.port) = sock.getpeername()
|
(self.ip, self.port) = sock.getpeername()
|
||||||
self.username = ""
|
self.IRCUsername = ""
|
||||||
|
self.banchoUsername = ""
|
||||||
self.supposedUsername = ""
|
self.supposedUsername = ""
|
||||||
self.joinedChannels = []
|
self.joinedChannels = []
|
||||||
|
|
||||||
@@ -90,7 +93,7 @@ class Client:
|
|||||||
channel -- optional
|
channel -- optional
|
||||||
"""
|
"""
|
||||||
if nickname == "":
|
if nickname == "":
|
||||||
nickname = self.username
|
nickname = self.IRCUsername
|
||||||
if channel != "":
|
if channel != "":
|
||||||
channel = " "+channel
|
channel = " "+channel
|
||||||
self.reply("{code:03d} {nickname}{channel} :{message}".format(code=code, nickname=nickname, channel=channel, message=message))
|
self.reply("{code:03d} {nickname}{channel} :{message}".format(code=code, nickname=nickname, channel=channel, message=message))
|
||||||
@@ -130,8 +133,8 @@ class Client:
|
|||||||
self.server.removeClient(self, quitmsg)
|
self.server.removeClient(self, quitmsg)
|
||||||
|
|
||||||
# Bancho logout
|
# Bancho logout
|
||||||
if callLogout == True:
|
if callLogout:
|
||||||
chat.IRCDisconnect(self.username)
|
chat.IRCDisconnect(self.IRCUsername)
|
||||||
|
|
||||||
|
|
||||||
def readSocket(self):
|
def readSocket(self):
|
||||||
@@ -143,7 +146,7 @@ class Client:
|
|||||||
quitmsg = "EOT"
|
quitmsg = "EOT"
|
||||||
except socket.error as x:
|
except socket.error as x:
|
||||||
# Error while reading data, this client will be disconnected
|
# Error while reading data, this client will be disconnected
|
||||||
data = ""
|
data = bytes()
|
||||||
quitmsg = x
|
quitmsg = x
|
||||||
|
|
||||||
if data:
|
if data:
|
||||||
@@ -201,7 +204,7 @@ class Client:
|
|||||||
log.debug("[IRC] [{}:{}] <- {}".format(self.ip, self.port, self.__writebuffer[:sent]))
|
log.debug("[IRC] [{}:{}] <- {}".format(self.ip, self.port, self.__writebuffer[:sent]))
|
||||||
self.__writebuffer = self.__writebuffer[sent:]
|
self.__writebuffer = self.__writebuffer[sent:]
|
||||||
except socket.error as x:
|
except socket.error as x:
|
||||||
self.disconnect(x)
|
self.disconnect(str(x))
|
||||||
|
|
||||||
|
|
||||||
def checkAlive(self):
|
def checkAlive(self):
|
||||||
@@ -252,7 +255,7 @@ class Client:
|
|||||||
tokenHash = m.hexdigest()
|
tokenHash = m.hexdigest()
|
||||||
supposedUsername = glob.db.fetch("SELECT users.username FROM users LEFT JOIN irc_tokens ON users.id = irc_tokens.userid WHERE irc_tokens.token = %s LIMIT 1", [tokenHash])
|
supposedUsername = glob.db.fetch("SELECT users.username FROM users LEFT JOIN irc_tokens ON users.id = irc_tokens.userid WHERE irc_tokens.token = %s LIMIT 1", [tokenHash])
|
||||||
if supposedUsername:
|
if supposedUsername:
|
||||||
self.supposedUsername = supposedUsername["username"]
|
self.supposedUsername = chat.fixUsernameForIRC(supposedUsername["username"])
|
||||||
self.__handleCommand = self.registerHandler
|
self.__handleCommand = self.registerHandler
|
||||||
else:
|
else:
|
||||||
# Wrong IRC Token
|
# Wrong IRC Token
|
||||||
@@ -270,29 +273,32 @@ class Client:
|
|||||||
nick = arguments[0]
|
nick = arguments[0]
|
||||||
|
|
||||||
# Make sure this is the first time we set our nickname
|
# Make sure this is the first time we set our nickname
|
||||||
if self.username != "":
|
if self.IRCUsername != "":
|
||||||
self.reply("432 * %s :Erroneous nickname" % nick)
|
self.reply("432 * %s :Erroneous nickname" % nick)
|
||||||
return
|
return
|
||||||
|
|
||||||
# Make sure the IRC token was correct:
|
# Make sure the IRC token was correct:
|
||||||
|
# (self.supposedUsername is already fixed for IRC)
|
||||||
if nick.lower() != self.supposedUsername.lower():
|
if nick.lower() != self.supposedUsername.lower():
|
||||||
self.reply("464 :Password incorrect")
|
self.reply("464 :Password incorrect")
|
||||||
return
|
return
|
||||||
|
|
||||||
# Make sure we are not connected to Bancho
|
# Make sure we are not connected to Bancho
|
||||||
token = glob.tokens.getTokenFromUsername(nick)
|
token = glob.tokens.getTokenFromUsername(chat.fixUsernameForBancho(nick), True)
|
||||||
if token != None:
|
if token is not None:
|
||||||
self.reply("433 * {} :Nickname is already in use".format(nick))
|
|
||||||
return
|
|
||||||
|
|
||||||
# Make sure we are not already connected from IRC with that name
|
|
||||||
for _, value in self.server.clients.items():
|
|
||||||
if value.username == self.username and value != self:
|
|
||||||
self.reply("433 * {} :Nickname is already in use".format(nick))
|
self.reply("433 * {} :Nickname is already in use".format(nick))
|
||||||
return
|
return
|
||||||
|
|
||||||
# Everything seems fine, set username (nickname)
|
# Everything seems fine, set username (nickname)
|
||||||
self.username = nick
|
self.IRCUsername = nick # username for IRC
|
||||||
|
self.banchoUsername = chat.fixUsernameForBancho(self.IRCUsername) # username for bancho
|
||||||
|
|
||||||
|
# Disconnect other IRC clients from the same user
|
||||||
|
for _, value in self.server.clients.items():
|
||||||
|
if value.IRCUsername.lower() == self.IRCUsername.lower() and value != self:
|
||||||
|
print("DISCONNECTERINOOOOOOOOOOOOOOOOOOOOO")
|
||||||
|
value.disconnect(quitmsg="Connected from another client")
|
||||||
|
return
|
||||||
elif command == "USER":
|
elif command == "USER":
|
||||||
# Ignore USER command, we use nickname only
|
# Ignore USER command, we use nickname only
|
||||||
return
|
return
|
||||||
@@ -305,9 +311,9 @@ class Client:
|
|||||||
return
|
return
|
||||||
|
|
||||||
# If we now have a valid username, connect to bancho and send IRC welcome stuff
|
# If we now have a valid username, connect to bancho and send IRC welcome stuff
|
||||||
if self.username != "":
|
if self.IRCUsername != "":
|
||||||
# Bancho connection
|
# Bancho connection
|
||||||
chat.IRCConnect(self.username)
|
chat.IRCConnect(self.banchoUsername)
|
||||||
|
|
||||||
# IRC reply
|
# IRC reply
|
||||||
self.replyCode(1, "Welcome to the Internet Relay Network")
|
self.replyCode(1, "Welcome to the Internet Relay Network")
|
||||||
@@ -320,7 +326,7 @@ class Client:
|
|||||||
|
|
||||||
def quitHandler(self, command, arguments):
|
def quitHandler(self, command, arguments):
|
||||||
"""QUIT command handler"""
|
"""QUIT command handler"""
|
||||||
self.disconnect(self.username if len(arguments) < 1 else arguments[0])
|
self.disconnect(self.IRCUsername if len(arguments) < 1 else arguments[0])
|
||||||
|
|
||||||
def joinHandler(self, command, arguments):
|
def joinHandler(self, command, arguments):
|
||||||
"""JOIN command handler"""
|
"""JOIN command handler"""
|
||||||
@@ -329,8 +335,8 @@ class Client:
|
|||||||
return
|
return
|
||||||
|
|
||||||
# Get bancho token object
|
# Get bancho token object
|
||||||
token = glob.tokens.getTokenFromUsername(self.username)
|
token = glob.tokens.getTokenFromUsername(self.banchoUsername)
|
||||||
if token == None:
|
if token is None:
|
||||||
return
|
return
|
||||||
|
|
||||||
# TODO: Part all channels
|
# TODO: Part all channels
|
||||||
@@ -354,13 +360,13 @@ class Client:
|
|||||||
continue
|
continue
|
||||||
|
|
||||||
# Attempt to join the channel
|
# Attempt to join the channel
|
||||||
response = chat.IRCJoinChannel(self.username, channel)
|
response = chat.IRCJoinChannel(self.banchoUsername, channel)
|
||||||
if response == 0:
|
if response == 0:
|
||||||
# Joined successfully
|
# Joined successfully
|
||||||
self.joinedChannels.append(channel)
|
self.joinedChannels.append(channel)
|
||||||
|
|
||||||
# Let everyone in this channel know that we've joined
|
# Let everyone in this channel know that we've joined
|
||||||
self.messageChannel(channel, "{} JOIN".format(self.username), channel, True)
|
self.messageChannel(channel, "{} JOIN".format(self.IRCUsername), channel, True)
|
||||||
|
|
||||||
# Send channel description (topic)
|
# Send channel description (topic)
|
||||||
description = glob.channels.channels[channel].description
|
description = glob.channels.channels[channel].description
|
||||||
@@ -374,12 +380,12 @@ class Client:
|
|||||||
usernames = []
|
usernames = []
|
||||||
for user in users:
|
for user in users:
|
||||||
token = glob.tokens.getTokenFromUserID(user)
|
token = glob.tokens.getTokenFromUserID(user)
|
||||||
if token == None:
|
if token is None:
|
||||||
continue
|
continue
|
||||||
usernames.append(token.username)
|
usernames.append(chat.fixUsernameForIRC(token.username))
|
||||||
usernames = " ".join(usernames)
|
usernames = " ".join(usernames)
|
||||||
|
|
||||||
# Send IRC users lis
|
# Send IRC users list
|
||||||
self.replyCode(353, usernames, channel="= {}".format(channel))
|
self.replyCode(353, usernames, channel="= {}".format(channel))
|
||||||
self.replyCode(366, "End of NAMES list", channel=channel)
|
self.replyCode(366, "End of NAMES list", channel=channel)
|
||||||
elif response == 403:
|
elif response == 403:
|
||||||
@@ -394,8 +400,8 @@ class Client:
|
|||||||
return
|
return
|
||||||
|
|
||||||
# Get bancho token object
|
# Get bancho token object
|
||||||
token = glob.tokens.getTokenFromUsername(self.username)
|
token = glob.tokens.getTokenFromUsername(self.banchoUsername)
|
||||||
if token == None:
|
if token is None:
|
||||||
return
|
return
|
||||||
|
|
||||||
# Get channels to part list
|
# Get channels to part list
|
||||||
@@ -409,7 +415,7 @@ class Client:
|
|||||||
continue
|
continue
|
||||||
|
|
||||||
# Attempt to part the channel
|
# Attempt to part the channel
|
||||||
response = chat.IRCPartChannel(self.username, channel)
|
response = chat.IRCPartChannel(self.banchoUsername, channel)
|
||||||
if response == 0:
|
if response == 0:
|
||||||
# No errors, remove channel from joinedChannels
|
# No errors, remove channel from joinedChannels
|
||||||
self.joinedChannels.remove(channel)
|
self.joinedChannels.remove(channel)
|
||||||
@@ -429,36 +435,40 @@ class Client:
|
|||||||
if len(arguments) == 1:
|
if len(arguments) == 1:
|
||||||
self.replyCode(412, "No text to send")
|
self.replyCode(412, "No text to send")
|
||||||
return
|
return
|
||||||
recipient = arguments[0]
|
recipientIRC = arguments[0]
|
||||||
message = arguments[1]
|
message = arguments[1]
|
||||||
|
|
||||||
# Send the message to bancho and reply
|
# Send the message to bancho and reply
|
||||||
response = chat.sendMessage(self.username, recipient, message, toIRC=False)
|
if not recipientIRC.startswith("#"):
|
||||||
|
print("PMPMPM!!!!!!!!!!")
|
||||||
|
recipientBancho = chat.fixUsernameForBancho(recipientIRC)
|
||||||
|
else:
|
||||||
|
recipientBancho = recipientIRC
|
||||||
|
response = chat.sendMessage(self.banchoUsername, recipientBancho, message, toIRC=False)
|
||||||
if response == 404:
|
if response == 404:
|
||||||
self.replyCode(404, "Cannot send to channel", channel=recipient)
|
self.replyCode(404, "Cannot send to channel", channel=recipientIRC)
|
||||||
return
|
return
|
||||||
elif response == 403:
|
elif response == 403:
|
||||||
self.replyCode(403, "No such channel", channel=recipient)
|
self.replyCode(403, "No such channel", channel=recipientIRC)
|
||||||
return
|
return
|
||||||
elif response == 401:
|
elif response == 401:
|
||||||
self.replyCode(401, "No such nick/channel", channel=recipient)
|
self.replyCode(401, "No such nick/channel", channel=recipientIRC)
|
||||||
return
|
return
|
||||||
|
|
||||||
# Send the message to IRC and bancho
|
# Send the message to IRC and bancho
|
||||||
if recipient.startswith("#"):
|
if recipientIRC.startswith("#"):
|
||||||
# Public message (IRC)
|
# Public message (IRC)
|
||||||
if recipient not in glob.channels.channels:
|
if recipientIRC not in glob.channels.channels:
|
||||||
self.replyCode(401, "No such nick/channel", channel=recipient)
|
self.replyCode(401, "No such nick/channel", channel=recipientIRC)
|
||||||
return
|
return
|
||||||
for _, value in self.server.clients.items():
|
for _, value in self.server.clients.items():
|
||||||
if recipient in value.joinedChannels and value != self:
|
if recipientIRC in value.joinedChannels and value != self:
|
||||||
value.message(":{} PRIVMSG {} :{}".format(self.username, recipient, message))
|
value.message(":{} PRIVMSG {} :{}".format(self.IRCUsername, recipientIRC, message))
|
||||||
#self.messageChannel(recipient, command, "{} :{}".format(recipient, message))
|
|
||||||
else:
|
else:
|
||||||
# Private message (IRC)
|
# Private message (IRC)
|
||||||
for _, value in self.server.clients.items():
|
for _, value in self.server.clients.items():
|
||||||
if value.username == recipient:
|
if value.IRCUsername == recipientIRC:
|
||||||
value.message(":{} PRIVMSG {} :{}".format(self.username, recipient, message))
|
value.message(":{} PRIVMSG {} :{}".format(self.IRCUsername, recipientIRC, message))
|
||||||
|
|
||||||
def motdHandler(self, command, arguments):
|
def motdHandler(self, command, arguments):
|
||||||
"""MOTD command handler"""
|
"""MOTD command handler"""
|
||||||
@@ -515,19 +525,20 @@ class Client:
|
|||||||
|
|
||||||
class Server:
|
class Server:
|
||||||
def __init__(self, port):
|
def __init__(self, port):
|
||||||
self.host = socket.getfqdn("127.0.0.1")[:63]
|
#self.host = socket.getfqdn("127.0.0.1")[:63]
|
||||||
|
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):
|
def forceDisconnection(self, username, isBanchoUsername=True):
|
||||||
"""
|
"""
|
||||||
Disconnect someone from IRC if connected
|
Disconnect someone from IRC if connected
|
||||||
|
|
||||||
username -- victim
|
username -- victim
|
||||||
"""
|
"""
|
||||||
for _, value in self.clients.items():
|
for _, value in self.clients.items():
|
||||||
if value.username == username:
|
if (value.IRCUsername == username and not isBanchoUsername) or (value.banchoUsername == username and isBanchoUsername):
|
||||||
value.disconnect(callLogout=False)
|
value.disconnect(callLogout=False)
|
||||||
break # or dictionary changes size during iteration
|
break # or dictionary changes size during iteration
|
||||||
|
|
||||||
@@ -538,6 +549,7 @@ class Server:
|
|||||||
username -- username of bancho user
|
username -- username of bancho user
|
||||||
channel -- joined channel name
|
channel -- joined channel name
|
||||||
"""
|
"""
|
||||||
|
username = chat.fixUsernameForIRC(username)
|
||||||
for _, value in self.clients.items():
|
for _, value in self.clients.items():
|
||||||
if channel in value.joinedChannels:
|
if channel in value.joinedChannels:
|
||||||
value.message(":{} JOIN {}".format(username, channel))
|
value.message(":{} JOIN {}".format(username, channel))
|
||||||
@@ -549,6 +561,7 @@ class Server:
|
|||||||
username -- username of bancho user
|
username -- username of bancho user
|
||||||
channel -- joined channel name
|
channel -- joined channel name
|
||||||
"""
|
"""
|
||||||
|
username = chat.fixUsernameForIRC(username)
|
||||||
for _, value in self.clients.items():
|
for _, value in self.clients.items():
|
||||||
if channel in value.joinedChannels:
|
if channel in value.joinedChannels:
|
||||||
value.message(":{} PART {}".format(username, channel))
|
value.message(":{} PART {}".format(username, channel))
|
||||||
@@ -561,15 +574,17 @@ class Server:
|
|||||||
to -- receiver username
|
to -- receiver username
|
||||||
message -- text of the message
|
message -- text of the message
|
||||||
"""
|
"""
|
||||||
|
fro = chat.fixUsernameForIRC(fro)
|
||||||
|
to = chat.fixUsernameForIRC(to)
|
||||||
if to.startswith("#"):
|
if to.startswith("#"):
|
||||||
# Public message
|
# Public message
|
||||||
for _, value in self.clients.items():
|
for _, value in self.clients.items():
|
||||||
if to in value.joinedChannels and value.username != fro:
|
if to in value.joinedChannels and value.IRCUsername != fro:
|
||||||
value.message(":{} PRIVMSG {} :{}".format(fro, to, message))
|
value.message(":{} PRIVMSG {} :{}".format(fro, to, message))
|
||||||
else:
|
else:
|
||||||
# Private message
|
# Private message
|
||||||
for _, value in self.clients.items():
|
for _, value in self.clients.items():
|
||||||
if value.username == to and value.username != fro:
|
if value.IRCUsername == to and value.IRCUsername != fro:
|
||||||
value.message(":{} PRIVMSG {} :{}".format(fro, to, message))
|
value.message(":{} PRIVMSG {} :{}".format(fro, to, message))
|
||||||
|
|
||||||
|
|
||||||
@@ -586,7 +601,7 @@ class Server:
|
|||||||
def start(self):
|
def start(self):
|
||||||
"""Start IRC server main loop"""
|
"""Start IRC server main loop"""
|
||||||
# Sentry
|
# Sentry
|
||||||
if glob.sentry == True:
|
if glob.sentry:
|
||||||
sentryClient = raven.Client(glob.conf.config["sentry"]["ircdns"])
|
sentryClient = raven.Client(glob.conf.config["sentry"]["ircdns"])
|
||||||
|
|
||||||
serversocket = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
|
serversocket = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
|
||||||
@@ -637,7 +652,7 @@ class Server:
|
|||||||
lastAliveCheck = now
|
lastAliveCheck = now
|
||||||
except:
|
except:
|
||||||
log.error("[IRC] Unknown error!\n```\n{}\n{}```".format(sys.exc_info(), traceback.format_exc()))
|
log.error("[IRC] Unknown error!\n```\n{}\n{}```".format(sys.exc_info(), traceback.format_exc()))
|
||||||
if glob.sentry == True:
|
if glob.sentry:
|
||||||
sentryClient.captureException()
|
sentryClient.captureException()
|
||||||
|
|
||||||
def main(port=6667):
|
def main(port=6667):
|
||||||
|
@@ -1,5 +1,7 @@
|
|||||||
|
# TODO: Rewrite this shit
|
||||||
|
from common import generalUtils
|
||||||
from objects import glob
|
from objects import glob
|
||||||
from helpers import generalFunctions
|
|
||||||
|
|
||||||
class banchoConfig:
|
class banchoConfig:
|
||||||
"""
|
"""
|
||||||
@@ -8,35 +10,34 @@ class banchoConfig:
|
|||||||
|
|
||||||
config = {"banchoMaintenance": False, "freeDirect": True, "menuIcon": "", "loginNotification": ""}
|
config = {"banchoMaintenance": False, "freeDirect": True, "menuIcon": "", "loginNotification": ""}
|
||||||
|
|
||||||
def __init__(self, __loadFromDB = True):
|
def __init__(self, loadFromDB = True):
|
||||||
"""
|
"""
|
||||||
Initialize a banchoConfig object (and load bancho_settings from db)
|
Initialize a banchoConfig object (and load bancho_settings from db)
|
||||||
|
|
||||||
[__loadFromDB -- if True, load values from db. If False, don't load values. Default: True]
|
loadFromDB -- if True, load values from db. If False, don't load values. Optional.
|
||||||
"""
|
"""
|
||||||
|
if loadFromDB:
|
||||||
if __loadFromDB:
|
|
||||||
try:
|
try:
|
||||||
self.loadSettings()
|
self.loadSettings()
|
||||||
except:
|
except:
|
||||||
raise
|
raise
|
||||||
|
|
||||||
|
|
||||||
def loadSettings(self):
|
def loadSettings(self):
|
||||||
"""
|
"""
|
||||||
(re)load bancho_settings from DB and set values in config array
|
(re)load bancho_settings from DB and set values in config array
|
||||||
"""
|
"""
|
||||||
|
self.config["banchoMaintenance"] = generalUtils.stringToBool(glob.db.fetch("SELECT value_int FROM bancho_settings WHERE name = 'bancho_maintenance'")["value_int"])
|
||||||
self.config["banchoMaintenance"] = generalFunctions.stringToBool(glob.db.fetch("SELECT value_int FROM bancho_settings WHERE name = 'bancho_maintenance'")["value_int"])
|
self.config["freeDirect"] = generalUtils.stringToBool(glob.db.fetch("SELECT value_int FROM bancho_settings WHERE name = 'free_direct'")["value_int"])
|
||||||
self.config["freeDirect"] = generalFunctions.stringToBool(glob.db.fetch("SELECT value_int FROM bancho_settings WHERE name = 'free_direct'")["value_int"])
|
|
||||||
self.config["menuIcon"] = glob.db.fetch("SELECT value_string FROM bancho_settings WHERE name = 'menu_icon'")["value_string"]
|
self.config["menuIcon"] = glob.db.fetch("SELECT value_string FROM bancho_settings WHERE name = 'menu_icon'")["value_string"]
|
||||||
self.config["loginNotification"] = glob.db.fetch("SELECT value_string FROM bancho_settings WHERE name = 'login_notification'")["value_string"]
|
self.config["loginNotification"] = glob.db.fetch("SELECT value_string FROM bancho_settings WHERE name = 'login_notification'")["value_string"]
|
||||||
|
|
||||||
def setMaintenance(self, __maintenance):
|
|
||||||
|
def setMaintenance(self, maintenance):
|
||||||
"""
|
"""
|
||||||
Turn on/off bancho maintenance mode. Write new value to db too
|
Turn on/off bancho maintenance mode. Write new value to db too
|
||||||
|
|
||||||
__maintenance -- if True, turn on maintenance mode. If false, turn it off
|
maintenance -- if True, turn on maintenance mode. If false, turn it off
|
||||||
"""
|
"""
|
||||||
|
self.config["banchoMaintenance"] = maintenance
|
||||||
self.config["banchoMaintenance"] = __maintenance
|
glob.db.execute("UPDATE bancho_settings SET value_int = %s WHERE name = 'bancho_maintenance'", [int(maintenance)])
|
||||||
glob.db.execute("UPDATE bancho_settings SET value_int = %s WHERE name = 'bancho_maintenance'", [int(__maintenance)])
|
|
||||||
|
@@ -5,22 +5,21 @@ class channel:
|
|||||||
A chat channel
|
A chat channel
|
||||||
"""
|
"""
|
||||||
|
|
||||||
def __init__(self, __name, __description, __publicRead, __publicWrite, temp, hidden):
|
def __init__(self, name, description, publicRead, publicWrite, temp, hidden):
|
||||||
"""
|
"""
|
||||||
Create a new chat channel object
|
Create a new chat channel object
|
||||||
|
|
||||||
__name -- channel name
|
name -- channel name
|
||||||
__description -- channel description
|
description -- channel description
|
||||||
__publicRead -- bool, if true channel can be read by everyone, if false it can be read only by mods/admins
|
publicRead -- bool, if true channel can be read by everyone, if false it can be read only by mods/admins
|
||||||
__publicWrite -- bool, same as public read but relative to write permissions
|
publicWrite -- bool, same as public read but relative to write permissions
|
||||||
temp -- if True, channel will be deleted when there's no one in the channel
|
temp -- if True, channel will be deleted when there's no one in the channel
|
||||||
hidden -- if True, channel won't be shown in channels list
|
hidden -- if True, channel won't be shown in channels list
|
||||||
"""
|
"""
|
||||||
|
self.name = name
|
||||||
self.name = __name
|
self.description = description
|
||||||
self.description = __description
|
self.publicRead = publicRead
|
||||||
self.publicRead = __publicRead
|
self.publicWrite = publicWrite
|
||||||
self.publicWrite = __publicWrite
|
|
||||||
self.moderated = False
|
self.moderated = False
|
||||||
self.temp = temp
|
self.temp = temp
|
||||||
self.connectedUsers = [999] # Fokabot is always connected to every channels (otherwise it doesn't show up in IRC users list)
|
self.connectedUsers = [999] # Fokabot is always connected to every channels (otherwise it doesn't show up in IRC users list)
|
||||||
@@ -33,34 +32,29 @@ class channel:
|
|||||||
elif self.name.startswith("#multi_"):
|
elif self.name.startswith("#multi_"):
|
||||||
self.clientName = "#multiplayer"
|
self.clientName = "#multiplayer"
|
||||||
|
|
||||||
|
def userJoin(self, userID):
|
||||||
def userJoin(self, __userID):
|
|
||||||
"""
|
"""
|
||||||
Add a user to connected users
|
Add a user to connected users
|
||||||
|
|
||||||
__userID -- user ID that joined the channel
|
userID -- user ID that joined the channel
|
||||||
"""
|
"""
|
||||||
|
if userID not in self.connectedUsers:
|
||||||
|
self.connectedUsers.append(userID)
|
||||||
|
|
||||||
if __userID not in self.connectedUsers:
|
def userPart(self, userID):
|
||||||
self.connectedUsers.append(__userID)
|
|
||||||
|
|
||||||
|
|
||||||
def userPart(self, __userID):
|
|
||||||
"""
|
"""
|
||||||
Remove a user from connected users
|
Remove a user from connected users
|
||||||
|
|
||||||
__userID -- user ID that left the channel
|
userID -- user ID that left the channel
|
||||||
"""
|
"""
|
||||||
|
if userID in self.connectedUsers:
|
||||||
if __userID in self.connectedUsers:
|
self.connectedUsers.remove(userID)
|
||||||
self.connectedUsers.remove(__userID)
|
|
||||||
|
|
||||||
# Remove temp channels if empty or there's only fokabot connected
|
# Remove temp channels if empty or there's only fokabot connected
|
||||||
l = len(self.connectedUsers)
|
l = len(self.connectedUsers)
|
||||||
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):
|
def getConnectedUsers(self):
|
||||||
"""
|
"""
|
||||||
Get connected user IDs list
|
Get connected user IDs list
|
||||||
@@ -69,7 +63,6 @@ class channel:
|
|||||||
"""
|
"""
|
||||||
return self.connectedUsers
|
return self.connectedUsers
|
||||||
|
|
||||||
|
|
||||||
def getConnectedUsersCount(self):
|
def getConnectedUsersCount(self):
|
||||||
"""
|
"""
|
||||||
Count connected users
|
Count connected users
|
||||||
|
@@ -1,6 +1,7 @@
|
|||||||
from objects import glob
|
from common.log import logUtils as log
|
||||||
from objects import channel
|
from objects import channel
|
||||||
from helpers import logHelper as log
|
from objects import glob
|
||||||
|
|
||||||
|
|
||||||
class channelList:
|
class channelList:
|
||||||
"""
|
"""
|
||||||
@@ -8,10 +9,8 @@ class channelList:
|
|||||||
|
|
||||||
channels -- dictionary. key: channel name, value: channel object
|
channels -- dictionary. key: channel name, value: channel object
|
||||||
"""
|
"""
|
||||||
|
|
||||||
channels = {}
|
channels = {}
|
||||||
|
|
||||||
|
|
||||||
def loadChannels(self):
|
def loadChannels(self):
|
||||||
"""
|
"""
|
||||||
Load chat channels from db and add them to channels dictionary
|
Load chat channels from db and add them to channels dictionary
|
||||||
@@ -27,7 +26,6 @@ class channelList:
|
|||||||
publicWrite = True if i["public_write"] == 1 else False
|
publicWrite = True if i["public_write"] == 1 else False
|
||||||
self.addChannel(i["name"], i["description"], publicRead, publicWrite)
|
self.addChannel(i["name"], i["description"], publicRead, publicWrite)
|
||||||
|
|
||||||
|
|
||||||
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 object to channels dictionary
|
Add a channel object to channels dictionary
|
||||||
@@ -42,7 +40,6 @@ class channelList:
|
|||||||
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))
|
||||||
|
|
||||||
|
|
||||||
def addTempChannel(self, name):
|
def addTempChannel(self, name):
|
||||||
"""
|
"""
|
||||||
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
|
||||||
|
@@ -16,7 +16,7 @@ class chatFilters:
|
|||||||
for line in data:
|
for line in data:
|
||||||
# Get old/new word and save it in dictionary
|
# Get old/new word and save it in dictionary
|
||||||
lineSplit = line.split("=")
|
lineSplit = line.split("=")
|
||||||
self.filters[lineSplit[0]] = lineSplit[1].replace("\n", "")
|
self.filters[lineSplit[0].lower()] = lineSplit[1].replace("\n", "")
|
||||||
|
|
||||||
def filterMessage(self, message):
|
def filterMessage(self, message):
|
||||||
# Split words by spaces
|
# Split words by spaces
|
||||||
@@ -24,9 +24,11 @@ class chatFilters:
|
|||||||
|
|
||||||
# Check each word
|
# Check each word
|
||||||
for word in messageTemp:
|
for word in messageTemp:
|
||||||
|
lowerWord = word.lower()
|
||||||
|
|
||||||
# If the word is filtered, replace it
|
# If the word is filtered, replace it
|
||||||
if word in self.filters:
|
if lowerWord in self.filters:
|
||||||
message = message.replace(word, self.filters[word])
|
message = message.replace(word, self.filters[lowerWord])
|
||||||
|
|
||||||
# Return filtered message
|
# Return filtered message
|
||||||
return message
|
return message
|
||||||
|
@@ -1,20 +0,0 @@
|
|||||||
import threading
|
|
||||||
|
|
||||||
class fileLocks:
|
|
||||||
def __init__(self):
|
|
||||||
# Dictionary containing threading.Lock s
|
|
||||||
self.locks = {}
|
|
||||||
|
|
||||||
def lockFile(self, fileName):
|
|
||||||
if fileName in self.locks:
|
|
||||||
# Acquire existing lock
|
|
||||||
self.locks[fileName].acquire()
|
|
||||||
else:
|
|
||||||
# Create new lock and acquire it
|
|
||||||
self.locks[fileName] = threading.Lock()
|
|
||||||
self.locks[fileName].acquire()
|
|
||||||
|
|
||||||
def unlockFile(self, fileName):
|
|
||||||
if fileName in self.locks:
|
|
||||||
# Release lock if it exists
|
|
||||||
self.locks[fileName].release()
|
|
@@ -1,32 +1,25 @@
|
|||||||
"""FokaBot related functions"""
|
"""FokaBot related functions"""
|
||||||
from helpers import userHelper
|
|
||||||
from objects import glob
|
|
||||||
from constants import actions
|
|
||||||
from constants import serverPackets
|
|
||||||
from constants import fokabotCommands
|
|
||||||
import re
|
import re
|
||||||
from helpers import generalFunctions
|
|
||||||
|
from common import generalUtils
|
||||||
|
from common.constants import actions
|
||||||
|
from common.ripple import userUtils
|
||||||
|
from constants import fokabotCommands
|
||||||
|
from constants import serverPackets
|
||||||
|
from objects import glob
|
||||||
|
|
||||||
# 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"""
|
"""Add FokaBot to connected users and send userpanel/stats packet to everyone"""
|
||||||
|
|
||||||
token = glob.tokens.addToken(999)
|
token = glob.tokens.addToken(999)
|
||||||
token.actionID = actions.idle
|
token.actionID = actions.IDLE
|
||||||
glob.tokens.enqueueAll(serverPackets.userPanel(999))
|
glob.streams.broadcast("main", serverPackets.userPanel(999))
|
||||||
####glob.tokens.enqueueAll(serverPackets.userStats(999))
|
glob.streams.broadcast("main", serverPackets.userStats(999))
|
||||||
|
|
||||||
# NOTE: Debug thing to set all users as connected
|
|
||||||
#users = glob.db.fetchAll("SELECT id FROM users")
|
|
||||||
#for i in users:
|
|
||||||
# t = glob.tokens.addToken(i["id"])
|
|
||||||
# t.actionID = actions.idle
|
|
||||||
|
|
||||||
def disconnect():
|
def disconnect():
|
||||||
"""Remove FokaBot from connected users"""
|
"""Remove FokaBot from connected users"""
|
||||||
|
|
||||||
glob.tokens.deleteToken(glob.tokens.getTokenFromUserID(999))
|
glob.tokens.deleteToken(glob.tokens.getTokenFromUserID(999))
|
||||||
|
|
||||||
def fokabotResponse(fro, chan, message):
|
def fokabotResponse(fro, chan, message):
|
||||||
@@ -39,17 +32,16 @@ def fokabotResponse(fro, chan, message):
|
|||||||
|
|
||||||
return -- fokabot's response string or False
|
return -- fokabot's response string or False
|
||||||
"""
|
"""
|
||||||
|
|
||||||
for i in fokabotCommands.commands:
|
for i in fokabotCommands.commands:
|
||||||
# Loop though all commands
|
# Loop though all commands
|
||||||
#if i["trigger"] in message:
|
#if i["trigger"] in message:
|
||||||
if generalFunctions.strContains(message, i["trigger"]):
|
if generalUtils.strContains(message, i["trigger"]):
|
||||||
# message has triggered a command
|
# message has triggered a command
|
||||||
|
|
||||||
# Make sure the user has right permissions
|
# Make sure the user has right permissions
|
||||||
if i["privileges"] != None:
|
if i["privileges"] is not None:
|
||||||
# Rank = x
|
# Rank = x
|
||||||
if userHelper.getPrivileges(userHelper.getID(fro)) & i["privileges"] == 0:
|
if userUtils.getPrivileges(userUtils.getID(fro)) & i["privileges"] == 0:
|
||||||
return False
|
return False
|
||||||
|
|
||||||
# Check argument number
|
# Check argument number
|
||||||
@@ -58,7 +50,7 @@ def fokabotResponse(fro, chan, message):
|
|||||||
return "Wrong syntax: {} {}".format(i["trigger"], i["syntax"])
|
return "Wrong syntax: {} {}".format(i["trigger"], i["syntax"])
|
||||||
|
|
||||||
# Return response or execute callback
|
# Return response or execute callback
|
||||||
if i["callback"] == None:
|
if i["callback"] is None:
|
||||||
return i["response"]
|
return i["response"]
|
||||||
else:
|
else:
|
||||||
return i["callback"](fro, chan, message[1:])
|
return i["callback"](fro, chan, message[1:])
|
||||||
|
@@ -1,9 +1,14 @@
|
|||||||
"""Global objects and variables"""
|
"""Global objects and variables"""
|
||||||
|
|
||||||
from objects import tokenList
|
import time
|
||||||
|
|
||||||
|
from common.ddog import datadogClient
|
||||||
|
from common.files import fileBuffer, fileLocks
|
||||||
from objects import channelList
|
from objects import channelList
|
||||||
from objects import matchList
|
from objects import matchList
|
||||||
from objects import fileLocks
|
from objects import streamList
|
||||||
|
from objects import tokenList
|
||||||
|
from common.web import schiavo
|
||||||
|
|
||||||
try:
|
try:
|
||||||
with open("version") as f:
|
with open("version") as f:
|
||||||
@@ -13,6 +18,8 @@ try:
|
|||||||
except:
|
except:
|
||||||
VERSION = "¯\_(xd)_/¯"
|
VERSION = "¯\_(xd)_/¯"
|
||||||
|
|
||||||
|
DATADOG_PREFIX = "peppy"
|
||||||
|
application = None
|
||||||
db = None
|
db = None
|
||||||
conf = None
|
conf = None
|
||||||
banchoConf = None
|
banchoConf = None
|
||||||
@@ -21,14 +28,26 @@ channels = channelList.channelList()
|
|||||||
matches = matchList.matchList()
|
matches = matchList.matchList()
|
||||||
restarting = False
|
restarting = False
|
||||||
fLocks = fileLocks.fileLocks()
|
fLocks = fileLocks.fileLocks()
|
||||||
|
fileBuffers = fileBuffer.buffersList()
|
||||||
|
schiavo = schiavo.schiavo()
|
||||||
|
dog = datadogClient.datadogClient()
|
||||||
verifiedCache = {}
|
verifiedCache = {}
|
||||||
cloudflare = False
|
cloudflare = False
|
||||||
chatFilters = None
|
chatFilters = None
|
||||||
|
userIDCache = {}
|
||||||
|
pool = None
|
||||||
|
ircServer = None
|
||||||
|
busyThreads = 0
|
||||||
|
|
||||||
debug = False
|
debug = False
|
||||||
outputRequestTime = False
|
outputRequestTime = False
|
||||||
outputPackets = False
|
outputPackets = False
|
||||||
discord = False
|
|
||||||
gzip = False
|
gzip = False
|
||||||
localize = False
|
localize = False
|
||||||
sentry = False
|
sentry = False
|
||||||
|
irc = False
|
||||||
|
|
||||||
|
startTime = int(time.time())
|
||||||
|
|
||||||
|
|
||||||
|
streams = streamList.streamList()
|
||||||
|
@@ -1,24 +0,0 @@
|
|||||||
'''
|
|
||||||
import threading
|
|
||||||
|
|
||||||
class task:
|
|
||||||
def __init__(self, function, args = (), kwargs = {}):
|
|
||||||
self.function = function
|
|
||||||
self.args = args
|
|
||||||
self.kwargs = kwargs
|
|
||||||
|
|
||||||
class logThread:
|
|
||||||
def __init__(self):
|
|
||||||
self.thread = threading.Thread()
|
|
||||||
self.queue = []
|
|
||||||
|
|
||||||
def enqueue(self, function, args = (), kwargs = {}):
|
|
||||||
self.queue.append(task(function, args, kwargs))
|
|
||||||
|
|
||||||
def run(self):
|
|
||||||
for i in self.queue:
|
|
||||||
self.thread = threading.Thread(i.function, i.args, i.kwargs)
|
|
||||||
self.thread.run()
|
|
||||||
self.thread.join()
|
|
||||||
self.queue = []
|
|
||||||
'''
|
|
465
objects/match.py
465
objects/match.py
@@ -1,174 +1,161 @@
|
|||||||
# TODO: Enqueue all
|
import copy
|
||||||
from constants import gameModes
|
from common.log import logUtils as log
|
||||||
|
from constants import dataTypes
|
||||||
|
from constants import matchModModes
|
||||||
from constants import matchScoringTypes
|
from constants import matchScoringTypes
|
||||||
from constants import matchTeamTypes
|
from constants import matchTeamTypes
|
||||||
from constants import matchModModes
|
|
||||||
from constants import slotStatuses
|
|
||||||
from objects import glob
|
|
||||||
from constants import serverPackets
|
|
||||||
from constants import dataTypes
|
|
||||||
from constants import matchTeams
|
from constants import matchTeams
|
||||||
from helpers import logHelper as log
|
from constants import serverPackets
|
||||||
|
from constants import slotStatuses
|
||||||
from helpers import chatHelper as chat
|
from helpers import chatHelper as chat
|
||||||
|
from objects import glob
|
||||||
|
|
||||||
|
|
||||||
|
class slot:
|
||||||
|
def __init__(self):
|
||||||
|
self.status = slotStatuses.free
|
||||||
|
self.team = 0
|
||||||
|
self.userID = -1
|
||||||
|
self.user = None
|
||||||
|
self.mods = 0
|
||||||
|
self.loaded = False
|
||||||
|
self.skip = False
|
||||||
|
self.complete = False
|
||||||
|
|
||||||
class match:
|
class match:
|
||||||
"""Multiplayer match object"""
|
"""Multiplayer match object"""
|
||||||
matchID = 0
|
def __init__(self, matchID, matchName, matchPassword, beatmapID, beatmapName, beatmapMD5, gameMode, hostUserID):
|
||||||
inProgress = False
|
|
||||||
mods = 0
|
|
||||||
matchName = ""
|
|
||||||
matchPassword = ""
|
|
||||||
beatmapName = ""
|
|
||||||
beatmapID = 0
|
|
||||||
beatmapMD5 = ""
|
|
||||||
slots = [] # list of dictionaries {"status": 0, "team": 0, "userID": -1, "mods": 0, "loaded": False, "skip": False, "complete": False}
|
|
||||||
hostUserID = 0
|
|
||||||
gameMode = gameModes.std
|
|
||||||
matchScoringType = matchScoringTypes.score
|
|
||||||
matchTeamType = matchTeamTypes.headToHead
|
|
||||||
matchModMode = matchModModes.normal
|
|
||||||
seed = 0
|
|
||||||
|
|
||||||
def __init__(self, __matchID, __matchName, __matchPassword, __beatmapID, __beatmapName, __beatmapMD5, __gameMode, __hostUserID):
|
|
||||||
"""
|
"""
|
||||||
Create a new match object
|
Create a new match object
|
||||||
|
|
||||||
__matchID -- match progressive identifier
|
matchID -- match progressive identifier
|
||||||
__matchName -- match name, string
|
matchName -- match name, string
|
||||||
__matchPassword -- match md5 password. Leave empty for no password
|
matchPassword -- match md5 password. Leave empty for no password
|
||||||
__beatmapID -- beatmap ID
|
beatmapID -- beatmap ID
|
||||||
__beatmapName -- beatmap name, string
|
beatmapName -- beatmap name, string
|
||||||
__beatmapMD5 -- beatmap md5 hash, string
|
beatmapMD5 -- beatmap md5 hash, string
|
||||||
__gameMode -- game mode ID. See gameModes.py
|
gameMode -- game mode ID. See gameModes.py
|
||||||
__hostUserID -- user id of the host
|
hostUserID -- user id of the host
|
||||||
"""
|
"""
|
||||||
self.matchID = __matchID
|
self.matchID = matchID
|
||||||
|
self.streamName = "multi/{}".format(self.matchID)
|
||||||
|
self.playingStreamName = "{}/playing".format(self.streamName)
|
||||||
self.inProgress = False
|
self.inProgress = False
|
||||||
self.mods = 0
|
self.mods = 0
|
||||||
self.matchName = __matchName
|
self.matchName = matchName
|
||||||
self.matchPassword = __matchPassword
|
self.matchPassword = matchPassword
|
||||||
self.beatmapID = __beatmapID
|
self.beatmapID = beatmapID
|
||||||
self.beatmapName = __beatmapName
|
self.beatmapName = beatmapName
|
||||||
self.beatmapMD5 = __beatmapMD5
|
self.beatmapMD5 = beatmapMD5
|
||||||
self.hostUserID = __hostUserID
|
self.hostUserID = hostUserID
|
||||||
self.gameMode = __gameMode
|
self.gameMode = gameMode
|
||||||
self.matchScoringTypes = matchScoringTypes.score # default values
|
self.matchScoringType = matchScoringTypes.score # default values
|
||||||
self.matchTeamType = matchTeamTypes.headToHead # default value
|
self.matchTeamType = matchTeamTypes.headToHead # default value
|
||||||
self.matchModMode = matchModModes.normal # default value
|
self.matchModMode = matchModModes.normal # default value
|
||||||
self.seed = 0
|
self.seed = 0
|
||||||
|
self.matchDataCache = bytes()
|
||||||
|
|
||||||
# Create all slots and reset them
|
# Create all slots and reset them
|
||||||
self.slots = []
|
self.slots = []
|
||||||
for _ in range(0,16):
|
for _ in range(0,16):
|
||||||
self.slots.append({"status": slotStatuses.free, "team": 0, "userID": -1, "mods": 0, "loaded": False, "skip": False, "complete": False})
|
self.slots.append(slot())
|
||||||
|
|
||||||
|
# Create streams
|
||||||
|
glob.streams.add(self.streamName)
|
||||||
|
glob.streams.add(self.playingStreamName)
|
||||||
|
|
||||||
# Create #multiplayer channel
|
# Create #multiplayer channel
|
||||||
glob.channels.addTempChannel("#multi_{}".format(self.matchID))
|
glob.channels.addTempChannel("#multi_{}".format(self.matchID))
|
||||||
|
|
||||||
|
|
||||||
def getMatchData(self):
|
def getMatchData(self):
|
||||||
"""
|
"""
|
||||||
Return binary match data structure for packetHelper
|
Return binary match data structure for packetHelper
|
||||||
"""
|
"""
|
||||||
# General match info
|
# General match info
|
||||||
|
# TODO: Test without safe copy, the error might have been caused by outdated python bytecode cache
|
||||||
|
safeMatch = copy.deepcopy(self)
|
||||||
struct = [
|
struct = [
|
||||||
[self.matchID, dataTypes.uInt16],
|
[safeMatch.matchID, dataTypes.UINT16],
|
||||||
[int(self.inProgress), dataTypes.byte],
|
[int(safeMatch.inProgress), dataTypes.BYTE],
|
||||||
[0, dataTypes.byte],
|
[0, dataTypes.BYTE],
|
||||||
[self.mods, dataTypes.uInt32],
|
[safeMatch.mods, dataTypes.UINT32],
|
||||||
[self.matchName, dataTypes.string],
|
[safeMatch.matchName, dataTypes.STRING],
|
||||||
[self.matchPassword, dataTypes.string],
|
[safeMatch.matchPassword, dataTypes.STRING],
|
||||||
[self.beatmapName, dataTypes.string],
|
[safeMatch.beatmapName, dataTypes.STRING],
|
||||||
[self.beatmapID, dataTypes.uInt32],
|
[safeMatch.beatmapID, dataTypes.UINT32],
|
||||||
[self.beatmapMD5, dataTypes.string],
|
[safeMatch.beatmapMD5, dataTypes.STRING],
|
||||||
]
|
]
|
||||||
|
|
||||||
# Slots status IDs, always 16 elements
|
# Slots status IDs, always 16 elements
|
||||||
for i in range(0,16):
|
for i in range(0,16):
|
||||||
struct.append([self.slots[i]["status"], dataTypes.byte])
|
struct.append([safeMatch.slots[i].status, dataTypes.BYTE])
|
||||||
|
|
||||||
# Slot teams, always 16 elements
|
# Slot teams, always 16 elements
|
||||||
for i in range(0,16):
|
for i in range(0,16):
|
||||||
struct.append([self.slots[i]["team"], dataTypes.byte])
|
struct.append([safeMatch.slots[i].team, dataTypes.BYTE])
|
||||||
|
|
||||||
# Slot user ID. Write only if slot is occupied
|
# Slot user ID. Write only if slot is occupied
|
||||||
for i in range(0,16):
|
for i in range(0,16):
|
||||||
uid = self.slots[i]["userID"]
|
if safeMatch.slots[i].user is not None and safeMatch.slots[i].user in glob.tokens.tokens:
|
||||||
if uid > -1:
|
struct.append([glob.tokens.tokens[safeMatch.slots[i].user].userID, dataTypes.UINT32])
|
||||||
struct.append([uid, dataTypes.uInt32])
|
|
||||||
|
|
||||||
# Other match data
|
# Other match data
|
||||||
struct.extend([
|
struct.extend([
|
||||||
[self.hostUserID, dataTypes.sInt32],
|
[safeMatch.hostUserID, dataTypes.SINT32],
|
||||||
[self.gameMode, dataTypes.byte],
|
[safeMatch.gameMode, dataTypes.BYTE],
|
||||||
[self.matchScoringType, dataTypes.byte],
|
[safeMatch.matchScoringType, dataTypes.BYTE],
|
||||||
[self.matchTeamType, dataTypes.byte],
|
[safeMatch.matchTeamType, dataTypes.BYTE],
|
||||||
[self.matchModMode, dataTypes.byte],
|
[safeMatch.matchModMode, dataTypes.BYTE],
|
||||||
])
|
])
|
||||||
|
|
||||||
# Slot mods if free mod is enabled
|
# Slot mods if free mod is enabled
|
||||||
if self.matchModMode == matchModModes.freeMod:
|
if safeMatch.matchModMode == matchModModes.freeMod:
|
||||||
for i in range(0,16):
|
for i in range(0,16):
|
||||||
struct.append([self.slots[i]["mods"], dataTypes.uInt32])
|
struct.append([safeMatch.slots[i].mods, dataTypes.UINT32])
|
||||||
|
|
||||||
# Seed idk
|
# Seed idk
|
||||||
struct.append([self.seed, dataTypes.uInt32])
|
# TODO: Implement this, it should be used for mania "random" mod
|
||||||
|
struct.append([safeMatch.seed, dataTypes.UINT32])
|
||||||
|
|
||||||
return struct
|
return struct
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
def setHost(self, newHost):
|
def setHost(self, newHost):
|
||||||
"""
|
"""
|
||||||
Set room host to newHost and send him host packet
|
Set room host to newHost and send him host packet
|
||||||
|
|
||||||
newHost -- new host userID
|
newHost -- new host userID
|
||||||
"""
|
"""
|
||||||
|
slotID = self.getUserSlotID(newHost)
|
||||||
|
if slotID is None or self.slots[slotID].user not in glob.tokens.tokens:
|
||||||
|
return
|
||||||
|
token = glob.tokens.tokens[self.slots[slotID].user]
|
||||||
self.hostUserID = newHost
|
self.hostUserID = newHost
|
||||||
|
|
||||||
# Send host packet to new host
|
|
||||||
token = glob.tokens.getTokenFromUserID(newHost)
|
|
||||||
if token != None:
|
|
||||||
token.enqueue(serverPackets.matchTransferHost())
|
token.enqueue(serverPackets.matchTransferHost())
|
||||||
|
self.sendUpdates()
|
||||||
|
log.info("MPROOM{}: {} is now the host".format(self.matchID, token.username))
|
||||||
|
|
||||||
log.info("MPROOM{}: {} is now the host".format(self.matchID, newHost))
|
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)
|
||||||
|
if status is not None:
|
||||||
|
self.slots[slotID].status = status
|
||||||
|
|
||||||
def setSlot(self, slotID, slotStatus = None, slotTeam = None, slotUserID = None, slotMods = None, slotLoaded = None, slotSkip = None, slotComplete = None):
|
if team is not None:
|
||||||
"""
|
self.slots[slotID].team = team
|
||||||
Set a slot to a specific userID and status
|
|
||||||
|
|
||||||
slotID -- id of that slot (0-15)
|
if user is not "":
|
||||||
slotStatus -- see slotStatuses.py
|
self.slots[slotID].user = user
|
||||||
slotTeam -- team id
|
|
||||||
slotUserID -- user ID of user in that slot
|
|
||||||
slotMods -- mods enabled in that slot. 0 if not free mod.
|
|
||||||
slotLoaded -- loaded status True/False
|
|
||||||
slotSkip -- skip status True/False
|
|
||||||
slotComplete -- completed status True/False
|
|
||||||
|
|
||||||
If Null is passed, that value won't be edited
|
if mods is not None:
|
||||||
"""
|
self.slots[slotID].mods = mods
|
||||||
if slotStatus != None:
|
|
||||||
self.slots[slotID]["status"] = slotStatus
|
|
||||||
|
|
||||||
if slotTeam != None:
|
if loaded is not None:
|
||||||
self.slots[slotID]["team"] = slotTeam
|
self.slots[slotID].loaded = loaded
|
||||||
|
|
||||||
if slotUserID != None:
|
if skip is not None:
|
||||||
self.slots[slotID]["userID"] = slotUserID
|
self.slots[slotID].skip = skip
|
||||||
|
|
||||||
if slotMods != None:
|
|
||||||
self.slots[slotID]["mods"] = slotMods
|
|
||||||
|
|
||||||
if slotLoaded != None:
|
|
||||||
self.slots[slotID]["loaded"] = slotLoaded
|
|
||||||
|
|
||||||
if slotSkip != None:
|
|
||||||
self.slots[slotID]["skip"] = slotSkip
|
|
||||||
|
|
||||||
if slotComplete != None:
|
|
||||||
self.slots[slotID]["complete"] = slotComplete
|
|
||||||
|
|
||||||
|
if complete is not None:
|
||||||
|
self.slots[slotID].complete = complete
|
||||||
|
|
||||||
def setSlotMods(self, slotID, mods):
|
def setSlotMods(self, slotID, mods):
|
||||||
"""
|
"""
|
||||||
@@ -178,11 +165,10 @@ class match:
|
|||||||
mods -- new mods
|
mods -- new mods
|
||||||
"""
|
"""
|
||||||
# Set new slot data and send update
|
# Set new slot data and send update
|
||||||
self.setSlot(slotID, None, None, None, mods)
|
self.setSlot(slotID, mods=mods)
|
||||||
self.sendUpdate()
|
self.sendUpdates()
|
||||||
log.info("MPROOM{}: Slot{} mods changed to {}".format(self.matchID, slotID, mods))
|
log.info("MPROOM{}: Slot{} mods changed to {}".format(self.matchID, slotID, mods))
|
||||||
|
|
||||||
|
|
||||||
def toggleSlotReady(self, slotID):
|
def toggleSlotReady(self, slotID):
|
||||||
"""
|
"""
|
||||||
Switch slotID ready/not ready status
|
Switch slotID ready/not ready status
|
||||||
@@ -191,14 +177,14 @@ class match:
|
|||||||
slotID -- slot number
|
slotID -- slot number
|
||||||
"""
|
"""
|
||||||
# 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.notReady
|
newStatus = slotStatuses.notReady
|
||||||
else:
|
else:
|
||||||
newStatus = slotStatuses.ready
|
newStatus = slotStatuses.ready
|
||||||
self.setSlot(slotID, newStatus, None, None, None)
|
self.setSlot(slotID, newStatus)
|
||||||
self.sendUpdate()
|
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))
|
||||||
|
|
||||||
def toggleSlotLock(self, slotID):
|
def toggleSlotLock(self, slotID):
|
||||||
"""
|
"""
|
||||||
@@ -207,26 +193,21 @@ class match:
|
|||||||
|
|
||||||
slotID -- slot number
|
slotID -- slot number
|
||||||
"""
|
"""
|
||||||
# Get token of user in that slot (if there's someone)
|
|
||||||
if self.slots[slotID]["userID"] > -1:
|
|
||||||
token = glob.tokens.getTokenFromUserID(self.slots[slotID]["userID"])
|
|
||||||
else:
|
|
||||||
token = None
|
|
||||||
|
|
||||||
# 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
|
||||||
|
|
||||||
# Set new slot status
|
|
||||||
self.setSlot(slotID, newStatus, 0, -1, 0)
|
|
||||||
if token != None:
|
|
||||||
# Send updated settings to kicked user, so he returns to lobby
|
# Send updated settings to kicked user, so he returns to lobby
|
||||||
token.enqueue(serverPackets.updateMatch(self.matchID))
|
if self.slots[slotID].user is not None and self.slots[slotID].user in glob.tokens.tokens:
|
||||||
|
glob.tokens.tokens[self.slots[slotID].user].enqueue(serverPackets.updateMatch(self.matchID))
|
||||||
|
|
||||||
|
# Set new slot status
|
||||||
|
self.setSlot(slotID, status=newStatus, team=0, user=None, mods=0)
|
||||||
|
|
||||||
# Send updates to everyone else
|
# Send updates to everyone else
|
||||||
self.sendUpdate()
|
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):
|
||||||
@@ -236,37 +217,30 @@ class match:
|
|||||||
userID -- ID of user
|
userID -- ID of user
|
||||||
"""
|
"""
|
||||||
slotID = self.getUserSlotID(userID)
|
slotID = self.getUserSlotID(userID)
|
||||||
if slotID == None:
|
if slotID is None:
|
||||||
return
|
return
|
||||||
|
|
||||||
# Set loaded to True
|
# Set loaded to True
|
||||||
self.slots[slotID]["loaded"] = True
|
self.slots[slotID].loaded = True
|
||||||
log.info("MPROOM{}: User {} loaded".format(self.matchID, userID))
|
log.info("MPROOM{}: User {} loaded".format(self.matchID, userID))
|
||||||
|
|
||||||
# Check all loaded
|
# Check all loaded
|
||||||
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"] == True:
|
if self.slots[i].loaded:
|
||||||
loaded+=1
|
loaded+=1
|
||||||
|
|
||||||
if total == loaded:
|
if total == loaded:
|
||||||
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"""
|
||||||
for i in range(0,16):
|
glob.streams.broadcast(self.playingStreamName, serverPackets.allPlayersLoaded())
|
||||||
if self.slots[i]["userID"] > -1 and self.slots[i]["status"] == slotStatuses.playing:
|
|
||||||
token = glob.tokens.getTokenFromUserID(self.slots[i]["userID"])
|
|
||||||
if token != None:
|
|
||||||
token.enqueue(serverPackets.allPlayersLoaded())
|
|
||||||
|
|
||||||
log.info("MPROOM{}: All players loaded! Match starting...".format(self.matchID))
|
log.info("MPROOM{}: All players loaded! Match starting...".format(self.matchID))
|
||||||
|
|
||||||
|
|
||||||
def playerSkip(self, userID):
|
def playerSkip(self, userID):
|
||||||
"""
|
"""
|
||||||
Set a player skip status to True
|
Set a player skip status to True
|
||||||
@@ -274,28 +248,24 @@ class match:
|
|||||||
userID -- ID of user
|
userID -- ID of user
|
||||||
"""
|
"""
|
||||||
slotID = self.getUserSlotID(userID)
|
slotID = self.getUserSlotID(userID)
|
||||||
if slotID == None:
|
if slotID is None:
|
||||||
return
|
return
|
||||||
|
|
||||||
# Set skip to True
|
# Set skip to True
|
||||||
self.slots[slotID]["skip"] = True
|
self.slots[slotID].skip = True
|
||||||
log.info("MPROOM{}: User {} skipped".format(self.matchID, userID))
|
log.info("MPROOM{}: User {} skipped".format(self.matchID, userID))
|
||||||
|
|
||||||
# Send skip packet to every playing useR
|
# Send skip packet to every playing user
|
||||||
for i in range(0,16):
|
#glob.streams.broadcast(self.playingStreamName, serverPackets.playerSkipped(glob.tokens.tokens[self.slots[slotID].user].userID))
|
||||||
uid = self.slots[i]["userID"]
|
glob.streams.broadcast(self.playingStreamName, serverPackets.playerSkipped(slotID))
|
||||||
if self.slots[i]["status"] == slotStatuses.playing and uid > -1:
|
|
||||||
token = glob.tokens.getTokenFromUserID(uid)
|
|
||||||
if token != None:
|
|
||||||
token.enqueue(serverPackets.playerSkipped(uid))
|
|
||||||
|
|
||||||
# Check all skipped
|
# Check all skipped
|
||||||
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"] == True:
|
if self.slots[i].skip:
|
||||||
skipped+=1
|
skipped+=1
|
||||||
|
|
||||||
if total == skipped:
|
if total == skipped:
|
||||||
@@ -303,12 +273,7 @@ class match:
|
|||||||
|
|
||||||
def allPlayersSkipped(self):
|
def allPlayersSkipped(self):
|
||||||
"""Send allPlayersSkipped packet to every playing usr in match"""
|
"""Send allPlayersSkipped packet to every playing usr in match"""
|
||||||
for i in range(0,16):
|
glob.streams.broadcast(self.playingStreamName, serverPackets.allPlayersSkipped())
|
||||||
if self.slots[i]["userID"] > -1 and self.slots[i]["status"] == slotStatuses.playing:
|
|
||||||
token = glob.tokens.getTokenFromUserID(self.slots[i]["userID"])
|
|
||||||
if token != None:
|
|
||||||
token.enqueue(serverPackets.allPlayersSkipped())
|
|
||||||
|
|
||||||
log.info("MPROOM{}: All players have skipped!".format(self.matchID))
|
log.info("MPROOM{}: All players have skipped!".format(self.matchID))
|
||||||
|
|
||||||
def playerCompleted(self, userID):
|
def playerCompleted(self, userID):
|
||||||
@@ -318,9 +283,9 @@ class match:
|
|||||||
userID -- ID of user
|
userID -- ID of user
|
||||||
"""
|
"""
|
||||||
slotID = self.getUserSlotID(userID)
|
slotID = self.getUserSlotID(userID)
|
||||||
if slotID == None:
|
if slotID is None:
|
||||||
return
|
return
|
||||||
self.setSlot(slotID, None, None, None, None, None, None, True)
|
self.setSlot(slotID, complete=True)
|
||||||
|
|
||||||
# Console output
|
# Console output
|
||||||
log.info("MPROOM{}: User {} has completed his play".format(self.matchID, userID))
|
log.info("MPROOM{}: User {} has completed his play".format(self.matchID, userID))
|
||||||
@@ -329,9 +294,9 @@ 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"] == True:
|
if self.slots[i].complete:
|
||||||
completed+=1
|
completed+=1
|
||||||
|
|
||||||
if total == completed:
|
if total == completed:
|
||||||
@@ -345,41 +310,36 @@ class match:
|
|||||||
|
|
||||||
# Reset slots
|
# Reset slots
|
||||||
for i in range(0,16):
|
for i in range(0,16):
|
||||||
if self.slots[i]["userID"] > -1 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.notReady
|
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
|
||||||
|
|
||||||
# Send match update
|
# Send match update
|
||||||
self.sendUpdate()
|
self.sendUpdates()
|
||||||
|
|
||||||
# Send match complete
|
# Send match complete
|
||||||
for i in range(0,16):
|
glob.streams.broadcast(self.streamName, serverPackets.matchComplete())
|
||||||
if self.slots[i]["userID"] > -1:
|
|
||||||
token = glob.tokens.getTokenFromUserID(self.slots[i]["userID"])
|
# Destroy playing stream
|
||||||
if token != None:
|
glob.streams.remove(self.playingStreamName)
|
||||||
token.enqueue(serverPackets.matchComplete())
|
|
||||||
|
|
||||||
# Console output
|
# Console output
|
||||||
log.info("MPROOM{}: Match completed".format(self.matchID))
|
log.info("MPROOM{}: Match completed".format(self.matchID))
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
def getUserSlotID(self, userID):
|
def getUserSlotID(self, userID):
|
||||||
"""
|
"""
|
||||||
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]["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:
|
||||||
return i
|
return i
|
||||||
|
|
||||||
return None
|
return None
|
||||||
|
|
||||||
def userJoin(self, userID):
|
def userJoin(self, user):
|
||||||
"""
|
"""
|
||||||
Add someone to users in match
|
Add someone to users in match
|
||||||
|
|
||||||
@@ -387,36 +347,40 @@ class match:
|
|||||||
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
|
||||||
|
for i in range(0,16):
|
||||||
|
if self.slots[i].user == user.token:
|
||||||
|
# Set bugged slot to free
|
||||||
|
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.notReady, 0, userID, 0)
|
self.setSlot(i, slotStatuses.notReady, 0, user.token, 0)
|
||||||
|
|
||||||
# Send updated match data
|
# Send updated match data
|
||||||
self.sendUpdate()
|
self.sendUpdates()
|
||||||
|
|
||||||
# Console output
|
# Console output
|
||||||
log.info("MPROOM{}: {} joined the room".format(self.matchID, userID))
|
log.info("MPROOM{}: {} joined the room".format(self.matchID, user.username))
|
||||||
|
|
||||||
return True
|
return True
|
||||||
|
|
||||||
return False
|
return False
|
||||||
|
|
||||||
def userLeft(self, userID):
|
def userLeft(self, user):
|
||||||
"""
|
"""
|
||||||
Remove someone from users in match
|
Remove someone from users in match
|
||||||
|
|
||||||
userID -- user if of the user
|
userID -- user if of the user
|
||||||
"""
|
"""
|
||||||
|
|
||||||
# Make sure the user is in room
|
# Make sure the user is in room
|
||||||
slotID = self.getUserSlotID(userID)
|
slotID = self.getUserSlotID(user.userID)
|
||||||
if slotID == None:
|
if slotID is None:
|
||||||
return
|
return
|
||||||
|
|
||||||
# Set that slot to free
|
# Set that slot to free
|
||||||
self.setSlot(slotID, slotStatuses.free, 0, -1, 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:
|
||||||
@@ -426,20 +390,18 @@ class match:
|
|||||||
return
|
return
|
||||||
|
|
||||||
# Check if host left
|
# Check if host left
|
||||||
if userID == self.hostUserID:
|
if user.userID == self.hostUserID:
|
||||||
# Give host to someone else
|
# Give host to someone else
|
||||||
for i in range(0,16):
|
for i in range(0,16):
|
||||||
uid = self.slots[i]["userID"]
|
if self.slots[i].user is not None and self.slots[i].user in glob.tokens.tokens:
|
||||||
if uid > -1:
|
self.setHost(glob.tokens.tokens[self.slots[i].user].userID)
|
||||||
self.setHost(uid)
|
|
||||||
break
|
break
|
||||||
|
|
||||||
# Send updated match data
|
# Send updated match data
|
||||||
self.sendUpdate()
|
self.sendUpdates()
|
||||||
|
|
||||||
# Console output
|
# Console output
|
||||||
log.info("MPROOM{}: {} left the room".format(self.matchID, userID))
|
log.info("MPROOM{}: {} left the room".format(self.matchID, user.username))
|
||||||
|
|
||||||
|
|
||||||
def userChangeSlot(self, userID, newSlotID):
|
def userChangeSlot(self, userID, newSlotID):
|
||||||
"""
|
"""
|
||||||
@@ -448,27 +410,27 @@ class match:
|
|||||||
userID -- user that changed slot
|
userID -- user that changed slot
|
||||||
newSlotID -- slot id of new slot
|
newSlotID -- slot id of new slot
|
||||||
"""
|
"""
|
||||||
|
|
||||||
# Make sure the user is in room
|
# Make sure the user is in room
|
||||||
oldSlotID = self.getUserSlotID(userID)
|
oldSlotID = self.getUserSlotID(userID)
|
||||||
if oldSlotID == None:
|
if oldSlotID is None:
|
||||||
return
|
return
|
||||||
|
|
||||||
# Make sure there is no one inside new slot
|
# Make sure there is no one inside new slot
|
||||||
if self.slots[newSlotID]["userID"] > -1:
|
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
|
||||||
oldData = self.slots[oldSlotID].copy()
|
#oldData = dill.copy(self.slots[oldSlotID])
|
||||||
|
oldData = copy.deepcopy(self.slots[oldSlotID])
|
||||||
|
|
||||||
# Free old slot
|
# Free old slot
|
||||||
self.setSlot(oldSlotID, slotStatuses.free, 0, -1, 0)
|
self.setSlot(oldSlotID, slotStatuses.free, 0, None, 0, False, False, False)
|
||||||
|
|
||||||
# Occupy new slot
|
# Occupy new slot
|
||||||
self.setSlot(newSlotID, oldData["status"], oldData["team"], userID, oldData["mods"])
|
self.setSlot(newSlotID, oldData.status, oldData.team, oldData.user, oldData.mods)
|
||||||
|
|
||||||
# Send updated match data
|
# Send updated match data
|
||||||
self.sendUpdate()
|
self.sendUpdates()
|
||||||
|
|
||||||
# Console output
|
# Console output
|
||||||
log.info("MPROOM{}: {} moved to slot {}".format(self.matchID, userID, newSlotID))
|
log.info("MPROOM{}: {} moved to slot {}".format(self.matchID, userID, newSlotID))
|
||||||
@@ -480,22 +442,21 @@ class match:
|
|||||||
newPassword -- new password string
|
newPassword -- new password string
|
||||||
"""
|
"""
|
||||||
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
|
||||||
for i in range(0,16):
|
glob.streams.broadcast(self.streamName, serverPackets.changeMatchPassword(self.matchPassword))
|
||||||
if self.slots[i]["userID"] > -1:
|
|
||||||
token = glob.tokens.getTokenFromUserID(self.slots[i]["userID"])
|
|
||||||
if token != None:
|
|
||||||
token.enqueue(serverPackets.changeMatchPassword(self.matchPassword))
|
|
||||||
|
|
||||||
# Send new match settings too
|
# Send new match settings too
|
||||||
self.sendUpdate()
|
self.sendUpdates()
|
||||||
|
|
||||||
# Console output
|
# Console output
|
||||||
log.info("MPROOM{}: Password changed to {}".format(self.matchID, self.matchPassword))
|
log.info("MPROOM{}: Password changed to {}".format(self.matchID, self.matchPassword))
|
||||||
|
|
||||||
|
def changeMods(self, mods):
|
||||||
def changeMatchMods(self, mods):
|
|
||||||
"""
|
"""
|
||||||
Set match global mods
|
Set match global mods
|
||||||
|
|
||||||
@@ -503,7 +464,7 @@ class match:
|
|||||||
"""
|
"""
|
||||||
# Set new mods and send update
|
# Set new mods and send update
|
||||||
self.mods = mods
|
self.mods = mods
|
||||||
self.sendUpdate()
|
self.sendUpdates()
|
||||||
log.info("MPROOM{}: Mods changed to {}".format(self.matchID, self.mods))
|
log.info("MPROOM{}: Mods changed to {}".format(self.matchID, self.mods))
|
||||||
|
|
||||||
def userHasBeatmap(self, userID, has = True):
|
def userHasBeatmap(self, userID, has = True):
|
||||||
@@ -515,14 +476,14 @@ class match:
|
|||||||
"""
|
"""
|
||||||
# Make sure the user is in room
|
# Make sure the user is in room
|
||||||
slotID = self.getUserSlotID(userID)
|
slotID = self.getUserSlotID(userID)
|
||||||
if slotID == None:
|
if slotID is None:
|
||||||
return
|
return
|
||||||
|
|
||||||
# Set slot
|
# Set slot
|
||||||
self.setSlot(slotID, slotStatuses.noMap if not has else slotStatuses.notReady)
|
self.setSlot(slotID, slotStatuses.noMap if not has else slotStatuses.notReady)
|
||||||
|
|
||||||
# Send updates
|
# Send updates
|
||||||
self.sendUpdate()
|
self.sendUpdates()
|
||||||
|
|
||||||
def transferHost(self, slotID):
|
def transferHost(self, slotID):
|
||||||
"""
|
"""
|
||||||
@@ -531,16 +492,14 @@ class match:
|
|||||||
slotID -- ID of slot
|
slotID -- ID of slot
|
||||||
"""
|
"""
|
||||||
# Make sure there is someone in that slot
|
# Make sure there is someone in that slot
|
||||||
uid = self.slots[slotID]["userID"]
|
if self.slots[slotID].user is None or self.slots[slotID].user not in glob.tokens.tokens:
|
||||||
if uid == -1:
|
|
||||||
return
|
return
|
||||||
|
|
||||||
# Transfer host
|
# Transfer host
|
||||||
self.setHost(uid)
|
self.setHost(glob.tokens.tokens[self.slots[slotID].user].userID)
|
||||||
|
|
||||||
# Send updates
|
# Send updates
|
||||||
self.sendUpdate()
|
self.sendUpdates()
|
||||||
|
|
||||||
|
|
||||||
def playerFailed(self, userID):
|
def playerFailed(self, userID):
|
||||||
"""
|
"""
|
||||||
@@ -550,21 +509,15 @@ class match:
|
|||||||
"""
|
"""
|
||||||
# Make sure the user is in room
|
# Make sure the user is in room
|
||||||
slotID = self.getUserSlotID(userID)
|
slotID = self.getUserSlotID(userID)
|
||||||
if slotID == None:
|
if slotID is None:
|
||||||
return
|
return
|
||||||
|
|
||||||
# Send packet to everyone
|
# Send packet to everyone
|
||||||
for i in range(0,16):
|
glob.streams.broadcast(self.playingStreamName, serverPackets.playerFailed(slotID))
|
||||||
uid = self.slots[i]["userID"]
|
|
||||||
if uid > -1:
|
|
||||||
token = glob.tokens.getTokenFromUserID(uid)
|
|
||||||
if token != None:
|
|
||||||
token.enqueue(serverPackets.playerFailed(slotID))
|
|
||||||
|
|
||||||
# Console output
|
# Console output
|
||||||
log.info("MPROOM{}: {} has failed!".format(self.matchID, userID))
|
log.info("MPROOM{}: {} has failed!".format(self.matchID, userID))
|
||||||
|
|
||||||
|
|
||||||
def invite(self, fro, to):
|
def invite(self, fro, to):
|
||||||
"""
|
"""
|
||||||
Fro invites to in this match.
|
Fro invites to in this match.
|
||||||
@@ -576,7 +529,7 @@ class match:
|
|||||||
# Get tokens
|
# Get tokens
|
||||||
froToken = glob.tokens.getTokenFromUserID(fro)
|
froToken = glob.tokens.getTokenFromUserID(fro)
|
||||||
toToken = glob.tokens.getTokenFromUserID(to)
|
toToken = glob.tokens.getTokenFromUserID(to)
|
||||||
if froToken == None or toToken == None:
|
if froToken is None or toToken is None:
|
||||||
return
|
return
|
||||||
|
|
||||||
# FokaBot is too busy
|
# FokaBot is too busy
|
||||||
@@ -587,19 +540,16 @@ class match:
|
|||||||
message = "Come join my multiplayer match: \"[osump://{}/{} {}]\"".format(self.matchID, self.matchPassword.replace(" ", "_"), self.matchName)
|
message = "Come join my multiplayer match: \"[osump://{}/{} {}]\"".format(self.matchID, self.matchPassword.replace(" ", "_"), self.matchName)
|
||||||
chat.sendMessage(token=froToken, to=toToken.username, message=message)
|
chat.sendMessage(token=froToken, to=toToken.username, message=message)
|
||||||
|
|
||||||
|
|
||||||
def countUsers(self):
|
def countUsers(self):
|
||||||
"""
|
"""
|
||||||
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):
|
||||||
if self.slots[i]["userID"] > -1:
|
if self.slots[i].user is not None:
|
||||||
c+=1
|
c+=1
|
||||||
|
|
||||||
return c
|
return c
|
||||||
|
|
||||||
def changeTeam(self, userID):
|
def changeTeam(self, userID):
|
||||||
@@ -610,29 +560,21 @@ class match:
|
|||||||
"""
|
"""
|
||||||
# Make sure the user is in room
|
# Make sure the user is in room
|
||||||
slotID = self.getUserSlotID(userID)
|
slotID = self.getUserSlotID(userID)
|
||||||
if slotID == None:
|
if slotID is None:
|
||||||
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.sendUpdate()
|
self.sendUpdates()
|
||||||
|
|
||||||
|
def sendUpdates(self):
|
||||||
|
self.matchDataCache = serverPackets.updateMatch(self.matchID)
|
||||||
def sendUpdate(self):
|
if self.matchDataCache is not None:
|
||||||
# Send to users in room
|
glob.streams.broadcast(self.streamName, self.matchDataCache)
|
||||||
for i in range(0,16):
|
glob.streams.broadcast("lobby", self.matchDataCache)
|
||||||
if self.slots[i]["userID"] > -1:
|
else:
|
||||||
token = glob.tokens.getTokenFromUserID(self.slots[i]["userID"])
|
log.error("MPROOM{}: Can't send match update packet, match data is None!!!".format(self.matchID))
|
||||||
if token != None:
|
|
||||||
token.enqueue(serverPackets.updateMatch(self.matchID))
|
|
||||||
|
|
||||||
# Send to users in lobby
|
|
||||||
for i in glob.matches.usersInLobby:
|
|
||||||
token = glob.tokens.getTokenFromUserID(i)
|
|
||||||
if token != None:
|
|
||||||
token.enqueue(serverPackets.updateMatch(self.matchID))
|
|
||||||
|
|
||||||
def checkTeams(self):
|
def checkTeams(self):
|
||||||
"""
|
"""
|
||||||
@@ -640,19 +582,46 @@ class match:
|
|||||||
|
|
||||||
return -- True if valid, False if invalid
|
return -- True if valid, False if invalid
|
||||||
"""
|
"""
|
||||||
if match.matchTeamType != matchTeamTypes.teamVs or matchTeamTypes != matchTeamTypes.tagTeamVs:
|
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]["userID"] > -1 and (self.slots[i]["status"]&slotStatuses.noMap) == 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]["teams"]:
|
elif firstTeam != self.slots[i].team:
|
||||||
log.info("MPROOM{}: Teams are valid".format(self.matchID))
|
log.info("MPROOM{}: Teams are valid".format(self.matchID))
|
||||||
return True
|
return True
|
||||||
|
|
||||||
log.warning("MPROOM{}: Invalid teams!".format(self.matchID))
|
log.warning("MPROOM{}: Invalid teams!".format(self.matchID))
|
||||||
return False
|
return False
|
||||||
|
|
||||||
|
def start(self):
|
||||||
|
# Make sure we have enough players
|
||||||
|
if self.countUsers() < 2 or not self.checkTeams():
|
||||||
|
return
|
||||||
|
|
||||||
|
# Create playing channel
|
||||||
|
glob.streams.add(self.playingStreamName)
|
||||||
|
|
||||||
|
# Change inProgress value
|
||||||
|
match.inProgress = True
|
||||||
|
|
||||||
|
# Set playing to ready players and set load, skip and complete to False
|
||||||
|
# Make clients join playing stream
|
||||||
|
for i in range(0, 16):
|
||||||
|
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].loaded = False
|
||||||
|
self.slots[i].skip = False
|
||||||
|
self.slots[i].complete = False
|
||||||
|
glob.tokens.tokens[self.slots[i].user].joinStream(self.playingStreamName)
|
||||||
|
|
||||||
|
# Send match start packet
|
||||||
|
glob.streams.broadcast(self.playingStreamName, serverPackets.matchStart(self.matchID))
|
||||||
|
|
||||||
|
# Send updates
|
||||||
|
self.sendUpdates()
|
@@ -1,80 +1,47 @@
|
|||||||
from objects import match
|
from objects import match
|
||||||
from objects import glob
|
from objects import glob
|
||||||
from constants import serverPackets
|
from constants import serverPackets
|
||||||
|
from common.log import logUtils as log
|
||||||
|
|
||||||
class matchList:
|
class matchList:
|
||||||
matches = {}
|
|
||||||
usersInLobby = []
|
|
||||||
lastID = 1
|
|
||||||
|
|
||||||
def __init__(self):
|
def __init__(self):
|
||||||
"""Initialize a matchList object"""
|
"""Initialize a matchList object"""
|
||||||
self.matches = {}
|
self.matches = {}
|
||||||
self.usersInLobby = []
|
|
||||||
self.lastID = 1
|
self.lastID = 1
|
||||||
|
|
||||||
def createMatch(self, __matchName, __matchPassword, __beatmapID, __beatmapName, __beatmapMD5, __gameMode, __hostUserID):
|
def createMatch(self, matchName, matchPassword, beatmapID, beatmapName, beatmapMD5, gameMode, hostUserID):
|
||||||
"""
|
"""
|
||||||
Add a new match to matches list
|
Add a new match to matches list
|
||||||
|
|
||||||
__matchName -- match name, string
|
matchName -- match name, string
|
||||||
__matchPassword -- match md5 password. Leave empty for no password
|
matchPassword -- match md5 password. Leave empty for no password
|
||||||
__beatmapID -- beatmap ID
|
beatmapID -- beatmap ID
|
||||||
__beatmapName -- beatmap name, string
|
beatmapName -- beatmap name, string
|
||||||
__beatmapMD5 -- beatmap md5 hash, string
|
beatmapMD5 -- beatmap md5 hash, string
|
||||||
__gameMode -- game mode ID. See gameModes.py
|
gameMode -- game mode ID. See gameModes.py
|
||||||
__hostUserID -- user id of who created the match
|
hostUserID -- user id of who created the match
|
||||||
return -- match ID
|
return -- match ID
|
||||||
"""
|
"""
|
||||||
# Add a new match to matches list
|
# Add a new match to matches list and create its stream
|
||||||
matchID = self.lastID
|
matchID = self.lastID
|
||||||
self.lastID+=1
|
self.lastID+=1
|
||||||
self.matches[matchID] = match.match(matchID, __matchName, __matchPassword, __beatmapID, __beatmapName, __beatmapMD5, __gameMode, __hostUserID)
|
self.matches[matchID] = match.match(matchID, matchName, matchPassword, beatmapID, beatmapName, beatmapMD5, gameMode, hostUserID)
|
||||||
return matchID
|
return matchID
|
||||||
|
|
||||||
|
def disposeMatch(self, matchID):
|
||||||
def lobbyUserJoin(self, __userID):
|
|
||||||
"""
|
"""
|
||||||
Add userID to users in lobby
|
Destroy match object with id = matchID
|
||||||
|
|
||||||
__userID -- user who joined mp lobby
|
matchID -- ID of match to dispose
|
||||||
"""
|
"""
|
||||||
|
|
||||||
# Make sure the user is not already in mp lobby
|
|
||||||
if __userID not in self.usersInLobby:
|
|
||||||
# We don't need to join #lobby, client will automatically send a packet for it
|
|
||||||
self.usersInLobby.append(__userID)
|
|
||||||
|
|
||||||
|
|
||||||
def lobbyUserPart(self, __userID):
|
|
||||||
"""
|
|
||||||
Remove userID from users in lobby
|
|
||||||
|
|
||||||
__userID -- user who left mp lobby
|
|
||||||
"""
|
|
||||||
|
|
||||||
# Make sure the user is in mp lobby
|
|
||||||
if __userID in self.usersInLobby:
|
|
||||||
# Part lobby and #lobby channel
|
|
||||||
self.usersInLobby.remove(__userID)
|
|
||||||
|
|
||||||
|
|
||||||
def disposeMatch(self, __matchID):
|
|
||||||
"""
|
|
||||||
Destroy match object with id = __matchID
|
|
||||||
|
|
||||||
__matchID -- ID of match to dispose
|
|
||||||
"""
|
|
||||||
|
|
||||||
# Make sure the match exists
|
# Make sure the match exists
|
||||||
if __matchID not in self.matches:
|
if matchID not in self.matches:
|
||||||
return
|
return
|
||||||
|
|
||||||
# Remove match object
|
# Remove match object and stream
|
||||||
self.matches.pop(__matchID)
|
match = self.matches.pop(matchID)
|
||||||
|
glob.streams.remove(match.streamName)
|
||||||
|
glob.streams.remove(match.playingStreamName)
|
||||||
|
|
||||||
# Send match dispose packet to everyone in lobby
|
# Send match dispose packet to everyone in lobby
|
||||||
for i in self.usersInLobby:
|
glob.streams.broadcast("lobby", serverPackets.disposeMatch(matchID))
|
||||||
token = glob.tokens.getTokenFromUserID(i)
|
|
||||||
if token != None:
|
|
||||||
token.enqueue(serverPackets.disposeMatch(__matchID))
|
|
@@ -1,66 +1,50 @@
|
|||||||
from constants import actions
|
import threading
|
||||||
from constants import gameModes
|
import time
|
||||||
from helpers import userHelper
|
import uuid
|
||||||
|
|
||||||
|
from common.constants import gameModes, actions
|
||||||
|
from common.log import logUtils as log
|
||||||
|
from common.ripple import userUtils
|
||||||
from constants import serverPackets
|
from constants import serverPackets
|
||||||
from events import logoutEvent
|
from events import logoutEvent
|
||||||
from helpers import logHelper as log
|
|
||||||
from objects import glob
|
|
||||||
import uuid
|
|
||||||
import time
|
|
||||||
import threading
|
|
||||||
from helpers import logHelper as log
|
|
||||||
from helpers import chatHelper as chat
|
from helpers import chatHelper as chat
|
||||||
|
from objects import glob
|
||||||
|
|
||||||
|
|
||||||
class token:
|
class token:
|
||||||
"""
|
|
||||||
Osu Token object
|
|
||||||
|
|
||||||
token -- token string
|
def __init__(self, userID, token_ = None, ip ="", irc = False, timeOffset = 0, tournament = False):
|
||||||
userID -- userID associated to that token
|
|
||||||
username -- username relative to userID (cache)
|
|
||||||
actionID -- current user action (see actions.py)
|
|
||||||
actionText -- current user action text
|
|
||||||
actionMd5 -- md5 relative to user action
|
|
||||||
actionMods -- current acton mods
|
|
||||||
gameMode -- current user game mode
|
|
||||||
location -- [latitude,longitude]
|
|
||||||
queue -- packets queue
|
|
||||||
joinedChannels -- list. Contains joined channel names
|
|
||||||
spectating -- userID of spectating user. 0 if not spectating.
|
|
||||||
spectators -- list. Contains userIDs of spectators
|
|
||||||
country -- osu country code. Use countryHelper to convert from letter country code to osu country code
|
|
||||||
pingTime -- latest packet received UNIX time
|
|
||||||
loginTime -- login UNIX time
|
|
||||||
latestTillerino -- beatmap ID of latest song from tillerino bot
|
|
||||||
"""
|
|
||||||
|
|
||||||
|
|
||||||
def __init__(self, __userID, token = None, ip = "", irc = False, timeOffset = 0):
|
|
||||||
"""
|
"""
|
||||||
Create a token object and set userID and token
|
Create a token object and set userID and token
|
||||||
|
|
||||||
__userID -- user associated to this token
|
userID -- user associated to this token
|
||||||
token -- if passed, set token to that value
|
token -- if passed, set token to that value
|
||||||
if not passed, token will be generated
|
if not passed, token will be generated
|
||||||
ip -- client ip. optional.
|
ip -- client ip. optional.
|
||||||
irc -- if True, set this token as IRC client. optional.
|
irc -- if True, set this token as IRC client. optional.
|
||||||
|
timeOffset -- the time offset from UTC for this user. optional.
|
||||||
"""
|
"""
|
||||||
|
|
||||||
# Set stuff
|
# Set stuff
|
||||||
self.userID = __userID
|
self.userID = userID
|
||||||
self.username = userHelper.getUsername(self.userID)
|
self.username = userUtils.getUsername(self.userID)
|
||||||
self.privileges = userHelper.getPrivileges(self.userID)
|
self.privileges = userUtils.getPrivileges(self.userID)
|
||||||
self.admin = userHelper.isInPrivilegeGroup(self.userID, "developer") or userHelper.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.restricted = userHelper.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
|
||||||
self.timeOffset = timeOffset
|
self.timeOffset = timeOffset
|
||||||
self.lock = threading.Lock() # Sync primitive
|
self.lock = threading.Lock() # Sync primitive
|
||||||
|
self.streams = []
|
||||||
|
self.tournament = tournament
|
||||||
|
|
||||||
# Default variables
|
# Default variables
|
||||||
self.spectators = []
|
self.spectators = []
|
||||||
self.spectating = 0
|
|
||||||
|
# TODO: Move those two vars to a class
|
||||||
|
self.spectating = None
|
||||||
|
self.spectatingUserID = 0 # we need this in case we the host gets DCed
|
||||||
|
|
||||||
self.location = [0,0]
|
self.location = [0,0]
|
||||||
self.joinedChannels = []
|
self.joinedChannels = []
|
||||||
self.ip = ip
|
self.ip = ip
|
||||||
@@ -71,17 +55,17 @@ class token:
|
|||||||
self.tillerino = [0,0,-1.0] # beatmap, mods, acc
|
self.tillerino = [0,0,-1.0] # beatmap, mods, acc
|
||||||
self.silenceEndTime = 0
|
self.silenceEndTime = 0
|
||||||
self.queue = bytes()
|
self.queue = bytes()
|
||||||
self.osuDirectAlert = False # NOTE: Remove this when osu!direct will be fixed
|
|
||||||
|
|
||||||
# Spam protection
|
# Spam protection
|
||||||
self.spamRate = 0
|
self.spamRate = 0
|
||||||
|
|
||||||
# Stats cache
|
# Stats cache
|
||||||
self.actionID = actions.idle
|
self.actionID = actions.IDLE
|
||||||
self.actionText = ""
|
self.actionText = ""
|
||||||
self.actionMd5 = ""
|
self.actionMd5 = ""
|
||||||
self.actionMods = 0
|
self.actionMods = 0
|
||||||
self.gameMode = gameModes.std
|
self.gameMode = gameModes.STD
|
||||||
|
self.beatmapID = 0
|
||||||
self.rankedScore = 0
|
self.rankedScore = 0
|
||||||
self.accuracy = 0.0
|
self.accuracy = 0.0
|
||||||
self.playcount = 0
|
self.playcount = 0
|
||||||
@@ -90,8 +74,8 @@ class token:
|
|||||||
self.pp = 0
|
self.pp = 0
|
||||||
|
|
||||||
# Generate/set token
|
# Generate/set token
|
||||||
if token != None:
|
if token_ is not None:
|
||||||
self.token = token
|
self.token = token_
|
||||||
else:
|
else:
|
||||||
self.token = str(uuid.uuid4())
|
self.token = str(uuid.uuid4())
|
||||||
|
|
||||||
@@ -100,22 +84,22 @@ class token:
|
|||||||
|
|
||||||
# If we have a valid ip, save bancho session in DB so we can cache LETS logins
|
# If we have a valid ip, save bancho session in DB so we can cache LETS logins
|
||||||
if ip != "":
|
if ip != "":
|
||||||
userHelper.saveBanchoSession(self.userID, self.ip)
|
userUtils.saveBanchoSession(self.userID, self.ip)
|
||||||
|
|
||||||
# If we are restricted, send message from FokaBot to user
|
# Join main stream
|
||||||
# NOTE: Sent later
|
self.joinStream("main")
|
||||||
#if self.restricted == True:
|
|
||||||
# self.setRestricted()
|
|
||||||
|
|
||||||
|
def enqueue(self, bytes_):
|
||||||
def enqueue(self, __bytes):
|
|
||||||
"""
|
"""
|
||||||
Add bytes (packets) to queue
|
Add bytes (packets) to queue
|
||||||
|
|
||||||
__bytes -- (packet) bytes to enqueue
|
bytes -- (packet) bytes to enqueue
|
||||||
"""
|
"""
|
||||||
if self.irc == False:
|
if not self.irc:
|
||||||
self.queue += __bytes
|
if len(bytes_) < 10 * 10 ** 6:
|
||||||
|
self.queue += bytes_
|
||||||
|
else:
|
||||||
|
log.warning("{}'s packets buffer is above 10M!! Lost some data!".format(self.username))
|
||||||
|
|
||||||
|
|
||||||
def resetQueue(self):
|
def resetQueue(self):
|
||||||
@@ -123,95 +107,146 @@ class token:
|
|||||||
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
|
||||||
|
|
||||||
__channel -- channel name"""
|
channel -- channel name
|
||||||
|
"""
|
||||||
|
if channel not in self.joinedChannels:
|
||||||
|
self.joinedChannels.append(channel)
|
||||||
|
|
||||||
if __channel not in self.joinedChannels:
|
def partChannel(self, channel):
|
||||||
self.joinedChannels.append(__channel)
|
"""
|
||||||
|
Remove channel from joined channels list
|
||||||
|
|
||||||
|
channel -- channel name
|
||||||
|
"""
|
||||||
|
if channel in self.joinedChannels:
|
||||||
|
self.joinedChannels.remove(channel)
|
||||||
|
|
||||||
def partChannel(self, __channel):
|
def setLocation(self, location):
|
||||||
"""Remove __channel from joined channels list
|
"""
|
||||||
|
Set location (latitude and longitude)
|
||||||
__channel -- channel name"""
|
|
||||||
|
|
||||||
if __channel in self.joinedChannels:
|
|
||||||
self.joinedChannels.remove(__channel)
|
|
||||||
|
|
||||||
|
|
||||||
def setLocation(self, __location):
|
|
||||||
"""Set location (latitude and longitude)
|
|
||||||
|
|
||||||
__location -- [latitude, longitude]"""
|
|
||||||
|
|
||||||
self.location = __location
|
|
||||||
|
|
||||||
|
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]
|
||||||
|
|
||||||
|
|
||||||
def getLongitude(self):
|
def getLongitude(self):
|
||||||
"""Get longitude
|
"""
|
||||||
|
Get longitude
|
||||||
|
|
||||||
return -- longitude"""
|
return -- longitude
|
||||||
|
"""
|
||||||
return self.location[1]
|
return self.location[1]
|
||||||
|
|
||||||
|
def startSpectating(self, host):
|
||||||
|
"""
|
||||||
|
Set the spectating user to userID
|
||||||
|
|
||||||
def startSpectating(self, __userID):
|
user -- user object
|
||||||
"""Set the spectating user to __userID
|
"""
|
||||||
|
# Stop spectating old client
|
||||||
|
self.stopSpectating()
|
||||||
|
|
||||||
__userID -- target userID"""
|
# Set new spectator host
|
||||||
self.spectating = __userID
|
self.spectating = host.token
|
||||||
|
self.spectatingUserID = host.userID
|
||||||
|
|
||||||
|
# Add us to host's spectator list
|
||||||
|
host.spectators.append(self.token)
|
||||||
|
|
||||||
|
# Create and join spectator stream
|
||||||
|
streamName = "spect/{}".format(host.userID)
|
||||||
|
glob.streams.add(streamName)
|
||||||
|
self.joinStream(streamName)
|
||||||
|
host.joinStream(streamName)
|
||||||
|
|
||||||
|
# Send spectator join packet to host
|
||||||
|
host.enqueue(serverPackets.addSpectator(self.userID))
|
||||||
|
|
||||||
|
# Create and join #spectator (#spect_userid) channel
|
||||||
|
glob.channels.addTempChannel("#spect_{}".format(host.userID))
|
||||||
|
chat.joinChannel(token=self, channel="#spect_{}".format(host.userID))
|
||||||
|
if len(host.spectators) == 1:
|
||||||
|
# First spectator, send #spectator join to host too
|
||||||
|
chat.joinChannel(token=host, channel="#spect_{}".format(host.userID))
|
||||||
|
|
||||||
|
# Send fellow spectator join to all clients
|
||||||
|
glob.streams.broadcast(streamName, serverPackets.fellowSpectatorJoined(self.userID))
|
||||||
|
|
||||||
|
# Get current spectators list
|
||||||
|
for i in host.spectators:
|
||||||
|
if i != self.token and i in glob.tokens.tokens:
|
||||||
|
self.enqueue(serverPackets.fellowSpectatorJoined(glob.tokens.tokens[i].userID))
|
||||||
|
|
||||||
|
# Log
|
||||||
|
log.info("{} is spectating {}".format(self.username, host.username))
|
||||||
|
|
||||||
def stopSpectating(self):
|
def stopSpectating(self):
|
||||||
"""Set the spectating user to 0, aka no user"""
|
# Remove our userID from host's spectators
|
||||||
self.spectating = 0
|
if self.spectating is None:
|
||||||
|
return
|
||||||
|
if self.spectating in glob.tokens.tokens:
|
||||||
|
hostToken = glob.tokens.tokens[self.spectating]
|
||||||
|
else:
|
||||||
|
hostToken = None
|
||||||
|
streamName = "spect/{}".format(self.spectatingUserID)
|
||||||
|
|
||||||
|
# Remove us from host's spectators list,
|
||||||
|
# leave spectator stream
|
||||||
|
# and end the spectator left packet to host
|
||||||
|
self.leaveStream(streamName)
|
||||||
|
if hostToken is not None:
|
||||||
|
hostToken.spectators.remove(self.token)
|
||||||
|
hostToken.enqueue(serverPackets.removeSpectator(self.userID))
|
||||||
|
|
||||||
def addSpectator(self, __userID):
|
# and to all other spectators
|
||||||
"""Add __userID to our spectators
|
for i in hostToken.spectators:
|
||||||
|
if i in glob.tokens.tokens:
|
||||||
|
glob.tokens.tokens[i].enqueue(serverPackets.fellowSpectatorLeft(self.userID))
|
||||||
|
|
||||||
userID -- new spectator userID"""
|
# If nobody is spectating the host anymore, close #spectator channel
|
||||||
|
# and remove host from spect stream too
|
||||||
|
if len(hostToken.spectators) == 0:
|
||||||
|
chat.partChannel(token=hostToken, channel="#spect_{}".format(hostToken.userID), kick=True)
|
||||||
|
hostToken.leaveStream(streamName)
|
||||||
|
|
||||||
# Add userID to spectators if not already in
|
# Part #spectator channel
|
||||||
if __userID not in self.spectators:
|
chat.partChannel(token=self, channel="#spect_{}".format(self.spectatingUserID), kick=True)
|
||||||
self.spectators.append(__userID)
|
|
||||||
|
|
||||||
|
# Console output
|
||||||
|
log.info("{} is no longer spectating {}".format(self.username, self.spectatingUserID))
|
||||||
|
|
||||||
def removeSpectator(self, __userID):
|
# Set our spectating user to 0
|
||||||
"""Remove __userID from our spectators
|
self.spectating = None
|
||||||
|
self.spectatingUserID = 0
|
||||||
|
|
||||||
userID -- old spectator userID"""
|
def setCountry(self, countryID):
|
||||||
|
"""
|
||||||
# Remove spectator
|
Set country to countryID
|
||||||
if __userID in self.spectators:
|
|
||||||
self.spectators.remove(__userID)
|
|
||||||
|
|
||||||
|
|
||||||
def setCountry(self, __countryID):
|
|
||||||
"""Set country to __countryID
|
|
||||||
|
|
||||||
__countryID -- numeric country ID. See countryHelper.py"""
|
|
||||||
|
|
||||||
self.country = __countryID
|
|
||||||
|
|
||||||
|
countryID -- numeric country ID. See countryHelper.py
|
||||||
|
"""
|
||||||
|
self.country = countryID
|
||||||
|
|
||||||
def getCountry(self):
|
def getCountry(self):
|
||||||
"""Get numeric country ID
|
"""
|
||||||
|
Get numeric country ID
|
||||||
return -- numeric country ID. See countryHelper.py"""
|
|
||||||
|
|
||||||
|
return -- numeric country ID. See countryHelper.py
|
||||||
|
"""
|
||||||
return self.country
|
return self.country
|
||||||
|
|
||||||
|
|
||||||
def updatePingTime(self):
|
def updatePingTime(self):
|
||||||
"""Update latest ping time"""
|
"""Update latest ping time"""
|
||||||
self.pingTime = int(time.time())
|
self.pingTime = int(time.time())
|
||||||
@@ -220,22 +255,76 @@ class token:
|
|||||||
"""Set a new away message"""
|
"""Set a new away message"""
|
||||||
self.awayMessage = __awayMessage
|
self.awayMessage = __awayMessage
|
||||||
|
|
||||||
def joinMatch(self, __matchID):
|
|
||||||
"""
|
|
||||||
Set match to matchID
|
|
||||||
|
|
||||||
__matchID -- new match ID
|
def joinMatch(self, matchID):
|
||||||
"""
|
"""
|
||||||
self.matchID = __matchID
|
Set match to matchID, join match stream and channel
|
||||||
|
|
||||||
def partMatch(self):
|
matchID -- new match ID
|
||||||
"""Set match to -1"""
|
"""
|
||||||
|
# Make sure the match exists
|
||||||
|
if matchID not in glob.matches.matches:
|
||||||
|
return
|
||||||
|
|
||||||
|
# Match exists, get object
|
||||||
|
match = glob.matches.matches[matchID]
|
||||||
|
|
||||||
|
# Stop spectating
|
||||||
|
self.stopSpectating()
|
||||||
|
|
||||||
|
# Leave other matches
|
||||||
|
if self.matchID > -1 and self.matchID != matchID:
|
||||||
|
self.leaveMatch()
|
||||||
|
|
||||||
|
# Try to join match
|
||||||
|
joined = match.userJoin(self)
|
||||||
|
if not joined:
|
||||||
|
self.enqueue(serverPackets.matchJoinFail())
|
||||||
|
return
|
||||||
|
|
||||||
|
# Set matchID, join stream, channel and send packet
|
||||||
|
self.matchID = matchID
|
||||||
|
self.joinStream(match.streamName)
|
||||||
|
chat.joinChannel(token=self, channel="#multi_{}".format(self.matchID))
|
||||||
|
self.enqueue(serverPackets.matchJoinSuccess(matchID))
|
||||||
|
|
||||||
|
def leaveMatch(self):
|
||||||
|
"""
|
||||||
|
Leave joined match, match stream and match channel
|
||||||
|
|
||||||
|
:return:
|
||||||
|
"""
|
||||||
|
# Make sure we are in a match
|
||||||
|
if self.matchID == -1:
|
||||||
|
return
|
||||||
|
|
||||||
|
# Part #multiplayer channel and streams (/ and /playing)
|
||||||
|
chat.partChannel(token=self, channel="#multi_{}".format(self.matchID), kick=True)
|
||||||
|
self.leaveStream("multi/{}".format(self.matchID))
|
||||||
|
self.leaveStream("multi/{}/playing".format(self.matchID)) # optional
|
||||||
|
|
||||||
|
# Make sure the match exists
|
||||||
|
if self.matchID not in glob.matches.matches:
|
||||||
|
return
|
||||||
|
|
||||||
|
# The match exists, get object
|
||||||
|
match = glob.matches.matches[self.matchID]
|
||||||
|
|
||||||
|
# Set slot to free
|
||||||
|
match.userLeft(self)
|
||||||
|
|
||||||
|
# Set usertoken match to -1
|
||||||
self.matchID = -1
|
self.matchID = -1
|
||||||
|
|
||||||
def kick(self, message="You have been kicked from the server. Please login again."):
|
def kick(self, message="You have been kicked from the server. Please login again.", reason="kick"):
|
||||||
"""Kick this user from the server"""
|
"""
|
||||||
|
Kick this user from the server
|
||||||
|
|
||||||
|
message -- Notification message to send to this user. Optional.
|
||||||
|
"""
|
||||||
# Send packet to target
|
# Send packet to target
|
||||||
log.info("{} has been disconnected. (kick)".format(self.username))
|
log.info("{} has been disconnected. ({})".format(self.username, reason))
|
||||||
|
if message != "":
|
||||||
self.enqueue(serverPackets.notification(message))
|
self.enqueue(serverPackets.notification(message))
|
||||||
self.enqueue(serverPackets.loginFailed())
|
self.enqueue(serverPackets.loginFailed())
|
||||||
|
|
||||||
@@ -252,13 +341,13 @@ class token:
|
|||||||
"""
|
"""
|
||||||
# Silence in db and token
|
# Silence in db and token
|
||||||
self.silenceEndTime = int(time.time())+seconds
|
self.silenceEndTime = int(time.time())+seconds
|
||||||
userHelper.silence(self.userID, seconds, reason, author)
|
userUtils.silence(self.userID, seconds, reason, author)
|
||||||
|
|
||||||
# Send silence packet to target
|
# Send silence packet to target
|
||||||
self.enqueue(serverPackets.silenceEndTime(seconds))
|
self.enqueue(serverPackets.silenceEndTime(seconds))
|
||||||
|
|
||||||
# Send silenced packet to everyone else
|
# Send silenced packet to everyone else
|
||||||
glob.tokens.enqueueAll(serverPackets.userSilenced(self.userID))
|
glob.streams.broadcast("main", serverPackets.userSilenced(self.userID))
|
||||||
|
|
||||||
def spamProtection(self, increaseSpamRate = True):
|
def spamProtection(self, increaseSpamRate = True):
|
||||||
"""
|
"""
|
||||||
@@ -267,7 +356,7 @@ class token:
|
|||||||
increaseSpamRate -- pass True if the user has sent a new message. Optional. Default: True
|
increaseSpamRate -- pass True if the user has sent a new message. Optional. Default: True
|
||||||
"""
|
"""
|
||||||
# Increase the spam rate if needed
|
# Increase the spam rate if needed
|
||||||
if increaseSpamRate == True:
|
if increaseSpamRate:
|
||||||
self.spamRate += 1
|
self.spamRate += 1
|
||||||
|
|
||||||
# Silence the user if needed
|
# Silence the user if needed
|
||||||
@@ -293,9 +382,9 @@ class token:
|
|||||||
|
|
||||||
def updateCachedStats(self):
|
def updateCachedStats(self):
|
||||||
"""Update all cached stats for this token"""
|
"""Update all cached stats for this token"""
|
||||||
stats = userHelper.getUserStats(self.userID, self.gameMode)
|
stats = userUtils.getUserStats(self.userID, self.gameMode)
|
||||||
log.debug(str(stats))
|
log.debug(str(stats))
|
||||||
if stats == None:
|
if stats is None:
|
||||||
log.warning("Stats query returned None")
|
log.warning("Stats query returned None")
|
||||||
return
|
return
|
||||||
self.rankedScore = stats["rankedScore"]
|
self.rankedScore = stats["rankedScore"]
|
||||||
@@ -312,9 +401,9 @@ class token:
|
|||||||
force -- If True, get restricted value from db.
|
force -- If True, get restricted value from db.
|
||||||
If false, get the cached one. Optional. Default: False
|
If false, get the cached one. Optional. Default: False
|
||||||
"""
|
"""
|
||||||
if force == True:
|
if force:
|
||||||
self.restricted = userHelper.isRestricted(self.userID)
|
self.restricted = userUtils.isRestricted(self.userID)
|
||||||
if self.restricted == True:
|
if self.restricted:
|
||||||
self.setRestricted()
|
self.setRestricted()
|
||||||
|
|
||||||
def setRestricted(self):
|
def setRestricted(self):
|
||||||
@@ -324,3 +413,17 @@ class token:
|
|||||||
"""
|
"""
|
||||||
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 joinStream(self, name):
|
||||||
|
glob.streams.join(name, token=self.token)
|
||||||
|
if name not in self.streams:
|
||||||
|
self.streams.append(name)
|
||||||
|
|
||||||
|
def leaveStream(self, name):
|
||||||
|
glob.streams.leave(name, token=self.token)
|
||||||
|
if name in self.streams:
|
||||||
|
self.streams.remove(name)
|
||||||
|
|
||||||
|
def leaveAllStreams(self):
|
||||||
|
for i in self.streams:
|
||||||
|
self.leaveStream(i)
|
57
objects/stream.py
Normal file
57
objects/stream.py
Normal file
@@ -0,0 +1,57 @@
|
|||||||
|
from common.log import logUtils as log
|
||||||
|
from objects import glob
|
||||||
|
|
||||||
|
class stream:
|
||||||
|
def __init__(self, name):
|
||||||
|
"""
|
||||||
|
Initialize a stream object
|
||||||
|
|
||||||
|
:param name: stream name
|
||||||
|
"""
|
||||||
|
self.name = name
|
||||||
|
self.clients = []
|
||||||
|
|
||||||
|
def addClient(self, client=None, token=None):
|
||||||
|
"""
|
||||||
|
Add a client to this stream if not already in
|
||||||
|
|
||||||
|
:param client: client (osuToken) object
|
||||||
|
:param token: client uuid string
|
||||||
|
:return:
|
||||||
|
"""
|
||||||
|
if client is None and token is None:
|
||||||
|
return
|
||||||
|
if client is not None:
|
||||||
|
token = client.token
|
||||||
|
if token not in self.clients:
|
||||||
|
log.info("{} has joined stream {}".format(token, self.name))
|
||||||
|
self.clients.append(token)
|
||||||
|
|
||||||
|
def removeClient(self, client=None, token=None):
|
||||||
|
"""
|
||||||
|
Remove a client from this stream if in
|
||||||
|
|
||||||
|
:param client: client (osuToken) object
|
||||||
|
:param token: client uuid string
|
||||||
|
:return:
|
||||||
|
"""
|
||||||
|
if client is None and token is None:
|
||||||
|
return
|
||||||
|
if client is not None:
|
||||||
|
token = client.token
|
||||||
|
if token in self.clients:
|
||||||
|
log.info("{} has left stream {}".format(token, self.name))
|
||||||
|
self.clients.remove(token)
|
||||||
|
|
||||||
|
def broadcast(self, data):
|
||||||
|
"""
|
||||||
|
Send some data to all clients connected to this stream
|
||||||
|
|
||||||
|
:param data: data to send
|
||||||
|
:return:
|
||||||
|
"""
|
||||||
|
for i in self.clients:
|
||||||
|
if i in glob.tokens.tokens:
|
||||||
|
glob.tokens.tokens[i].enqueue(data)
|
||||||
|
else:
|
||||||
|
self.removeClient(token=i)
|
79
objects/streamList.py
Normal file
79
objects/streamList.py
Normal file
@@ -0,0 +1,79 @@
|
|||||||
|
from objects import stream
|
||||||
|
from objects import glob
|
||||||
|
|
||||||
|
class streamList:
|
||||||
|
def __init__(self):
|
||||||
|
self.streams = {}
|
||||||
|
|
||||||
|
def add(self, name):
|
||||||
|
"""
|
||||||
|
Create a new stream list if it doesn't already exist
|
||||||
|
|
||||||
|
:param name: stream name
|
||||||
|
:return:
|
||||||
|
"""
|
||||||
|
if name not in self.streams:
|
||||||
|
self.streams[name] = stream.stream(name)
|
||||||
|
|
||||||
|
def remove(self, name):
|
||||||
|
"""
|
||||||
|
Removes an existing stream and kick every user in it
|
||||||
|
|
||||||
|
:param name: stream name
|
||||||
|
:return:
|
||||||
|
"""
|
||||||
|
if name in self.streams:
|
||||||
|
for i in self.streams[name].clients:
|
||||||
|
if i in glob.tokens.tokens:
|
||||||
|
glob.tokens.tokens[i].leaveStream(name)
|
||||||
|
self.streams.pop(name)
|
||||||
|
|
||||||
|
|
||||||
|
def join(self, streamName, client=None, token=None):
|
||||||
|
"""
|
||||||
|
Add a client to a stream
|
||||||
|
|
||||||
|
:param streamName: stream name
|
||||||
|
:param client: client (osuToken) object
|
||||||
|
:param token: client uuid string
|
||||||
|
:return:
|
||||||
|
"""
|
||||||
|
if streamName not in self.streams:
|
||||||
|
return
|
||||||
|
self.streams[streamName].addClient(client=client, token=token)
|
||||||
|
|
||||||
|
def leave(self, streamName, client=None, token=None):
|
||||||
|
"""
|
||||||
|
Remove a client from a stream
|
||||||
|
|
||||||
|
:param streamName: stream name
|
||||||
|
:param client: client (osuToken) object
|
||||||
|
:param token: client uuid string
|
||||||
|
:return:
|
||||||
|
"""
|
||||||
|
if streamName not in self.streams:
|
||||||
|
return
|
||||||
|
self.streams[streamName].removeClient(client=client, token=token)
|
||||||
|
|
||||||
|
def broadcast(self, streamName, data):
|
||||||
|
"""
|
||||||
|
Send some data to all clients in a stream
|
||||||
|
|
||||||
|
:param streamName: stream name
|
||||||
|
:param data: data to send
|
||||||
|
:return:
|
||||||
|
"""
|
||||||
|
if streamName not in self.streams:
|
||||||
|
return
|
||||||
|
self.streams[streamName].broadcast(data)
|
||||||
|
|
||||||
|
'''def getClients(self, streamName):
|
||||||
|
"""
|
||||||
|
Get all clients in a stream
|
||||||
|
|
||||||
|
:param streamName: name of the stream
|
||||||
|
:return:
|
||||||
|
"""
|
||||||
|
if streamName not in self.streams:
|
||||||
|
return
|
||||||
|
return self.streams[streamName].clients'''
|
@@ -1,10 +1,13 @@
|
|||||||
from objects import osuToken
|
|
||||||
from objects import glob
|
|
||||||
import time
|
|
||||||
import threading
|
import threading
|
||||||
|
import time
|
||||||
|
|
||||||
|
from common.ripple import userUtils
|
||||||
|
from common.log import logUtils as log
|
||||||
|
from constants import serverPackets
|
||||||
from events import logoutEvent
|
from events import logoutEvent
|
||||||
from helpers import logHelper as log
|
from objects import glob
|
||||||
from helpers import userHelper
|
from objects import osuToken
|
||||||
|
|
||||||
|
|
||||||
class tokenList:
|
class tokenList:
|
||||||
"""
|
"""
|
||||||
@@ -19,7 +22,7 @@ class tokenList:
|
|||||||
"""
|
"""
|
||||||
self.tokens = {}
|
self.tokens = {}
|
||||||
|
|
||||||
def addToken(self, userID, ip = "", irc = False, timeOffset=0):
|
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
|
||||||
|
|
||||||
@@ -27,8 +30,7 @@ class tokenList:
|
|||||||
irc -- if True, set this token as IRC client
|
irc -- if True, set this token as IRC client
|
||||||
return -- token object
|
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)
|
|
||||||
self.tokens[newToken.token] = newToken
|
self.tokens[newToken.token] = newToken
|
||||||
return newToken
|
return newToken
|
||||||
|
|
||||||
@@ -38,25 +40,21 @@ class tokenList:
|
|||||||
|
|
||||||
token -- token string
|
token -- token string
|
||||||
"""
|
"""
|
||||||
|
|
||||||
if token in self.tokens:
|
if token in self.tokens:
|
||||||
# Delete session from DB
|
# Delete session from DB
|
||||||
if self.tokens[token].ip != "":
|
if self.tokens[token].ip != "":
|
||||||
userHelper.deleteBanchoSessions(self.tokens[token].userID, self.tokens[token].ip)
|
userUtils.deleteBanchoSessions(self.tokens[token].userID, self.tokens[token].ip)
|
||||||
|
|
||||||
# Pop token from list
|
# Pop token from list
|
||||||
self.tokens.pop(token)
|
self.tokens.pop(token)
|
||||||
|
|
||||||
|
|
||||||
def getUserIDFromToken(self, token):
|
def getUserIDFromToken(self, token):
|
||||||
"""
|
"""
|
||||||
Get user ID from a token
|
Get user ID from a token
|
||||||
|
|
||||||
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:
|
||||||
return False
|
return False
|
||||||
@@ -64,44 +62,43 @@ class tokenList:
|
|||||||
# Get userID associated to that token
|
# Get userID associated to that token
|
||||||
return self.tokens[token].userID
|
return self.tokens[token].userID
|
||||||
|
|
||||||
|
def getTokenFromUserID(self, userID, ignoreIRC=False):
|
||||||
def getTokenFromUserID(self, userID):
|
|
||||||
"""
|
"""
|
||||||
Get token from a user ID
|
Get token from a user ID
|
||||||
|
|
||||||
userID -- user ID to find
|
userID -- user ID to find
|
||||||
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():
|
||||||
if value.userID == userID:
|
if value.userID == userID:
|
||||||
|
if ignoreIRC and value.irc:
|
||||||
|
continue
|
||||||
return value
|
return value
|
||||||
|
|
||||||
# Return none if not found
|
# Return none if not found
|
||||||
return None
|
return None
|
||||||
|
|
||||||
|
def getTokenFromUsername(self, username, ignoreIRC=False):
|
||||||
def getTokenFromUsername(self, username):
|
|
||||||
"""
|
"""
|
||||||
Get token from a username
|
Get token from a username
|
||||||
|
|
||||||
username -- username to find
|
username -- username to find
|
||||||
return -- False if not found, token object if found
|
return -- False if not found, token object if found
|
||||||
"""
|
"""
|
||||||
|
|
||||||
# lowercase
|
# lowercase
|
||||||
who = username.lower()
|
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 value.username.lower() == who:
|
if value.username.lower() == who:
|
||||||
|
if ignoreIRC and value.irc:
|
||||||
|
continue
|
||||||
return value
|
return value
|
||||||
|
|
||||||
# Return none if not found
|
# Return none if not found
|
||||||
return None
|
return None
|
||||||
|
|
||||||
|
|
||||||
def deleteOldTokens(self, userID):
|
def deleteOldTokens(self, userID):
|
||||||
"""
|
"""
|
||||||
Delete old userID's tokens if found
|
Delete old userID's tokens if found
|
||||||
@@ -113,12 +110,7 @@ class tokenList:
|
|||||||
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.")
|
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.pop(key)
|
|
||||||
|
|
||||||
# break or items() function throws errors
|
|
||||||
#break
|
|
||||||
|
|
||||||
|
|
||||||
def multipleEnqueue(self, packet, who, but = False):
|
def multipleEnqueue(self, packet, who, but = False):
|
||||||
"""
|
"""
|
||||||
@@ -128,7 +120,6 @@ class tokenList:
|
|||||||
who -- userIDs array
|
who -- userIDs array
|
||||||
but -- if True, enqueue to everyone but users in who array
|
but -- if True, enqueue to everyone but users in who array
|
||||||
"""
|
"""
|
||||||
|
|
||||||
for _, value in self.tokens.items():
|
for _, value in self.tokens.items():
|
||||||
shouldEnqueue = False
|
shouldEnqueue = False
|
||||||
if value.userID in who and not but:
|
if value.userID in who and not but:
|
||||||
@@ -145,25 +136,24 @@ class tokenList:
|
|||||||
|
|
||||||
packet -- packet bytes to enqueue
|
packet -- packet bytes to enqueue
|
||||||
"""
|
"""
|
||||||
|
|
||||||
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):
|
||||||
"""
|
"""
|
||||||
Deletes all timed out users.
|
Deletes all timed out users.
|
||||||
If called once, will recall after __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!
|
||||||
|
|
||||||
__timeoutTime - seconds of inactivity required to disconnect someone (Default: 100)
|
timeoutTime - seconds of inactivity required to disconnect someone (Default: 100)
|
||||||
__checkTime - seconds between loops (Default: 100)
|
checkTime - seconds between loops (Default: 100)
|
||||||
"""
|
"""
|
||||||
|
log.debug("Checking timed out clients")
|
||||||
timedOutTokens = [] # timed out users
|
timedOutTokens = [] # timed out users
|
||||||
timeoutLimit = time.time()-__timeoutTime
|
timeoutLimit = int(time.time())-timeoutTime
|
||||||
for key, value in self.tokens.items():
|
for key, value in self.tokens.items():
|
||||||
# Check timeout (fokabot is ignored)
|
# Check timeout (fokabot is ignored)
|
||||||
if value.pingTime < timeoutLimit and value.userID != 999 and value.irc == False:
|
if value.pingTime < timeoutLimit and value.userID != 999 and value.irc == False and value.tournament == False:
|
||||||
# That user has timed out, add to disconnected tokens
|
# That user has timed out, add to disconnected tokens
|
||||||
# We can't delete it while iterating or items() throws an error
|
# We can't delete it while iterating or items() throws an error
|
||||||
timedOutTokens.append(key)
|
timedOutTokens.append(key)
|
||||||
@@ -171,18 +161,18 @@ class tokenList:
|
|||||||
# Delete timed out users from self.tokens
|
# Delete timed out users from self.tokens
|
||||||
# i is token string (dictionary key)
|
# i is token string (dictionary key)
|
||||||
for i in timedOutTokens:
|
for i in timedOutTokens:
|
||||||
|
log.debug("{} timed out!!".format(self.tokens[i].username))
|
||||||
|
self.tokens[i].enqueue(serverPackets.notification("Your connection to the server timed out."))
|
||||||
logoutEvent.handle(self.tokens[i], None)
|
logoutEvent.handle(self.tokens[i], None)
|
||||||
|
|
||||||
# Schedule a new check (endless loop)
|
# Schedule a new check (endless loop)
|
||||||
threading.Timer(__checkTime, self.usersTimeoutCheckLoop, [__timeoutTime, __checkTime]).start()
|
threading.Timer(checkTime, self.usersTimeoutCheckLoop, [timeoutTime, checkTime]).start()
|
||||||
|
|
||||||
def spamProtectionResetLoop(self):
|
def spamProtectionResetLoop(self):
|
||||||
"""
|
"""
|
||||||
Reset spam rate every 10 seconds.
|
Reset spam rate every 10 seconds.
|
||||||
CALL THIS FUNCTION ONLY ONCE!
|
CALL THIS FUNCTION ONLY ONCE!
|
||||||
"""
|
"""
|
||||||
#log.debug("Resetting spam protection...")
|
|
||||||
|
|
||||||
# Reset spamRate for every token
|
# Reset spamRate for every token
|
||||||
for _, value in self.tokens.items():
|
for _, value in self.tokens.items():
|
||||||
value.spamRate = 0
|
value.spamRate = 0
|
||||||
|
152
pep.py
152
pep.py
@@ -1,40 +1,39 @@
|
|||||||
"""Hello, pep.py here, ex-owner of ripple and prime minister of Ripwot."""
|
"""Hello, pep.py here, ex-owner of ripple and prime minister of Ripwot."""
|
||||||
import sys
|
|
||||||
import os
|
import os
|
||||||
|
import sys
|
||||||
import threading
|
import threading
|
||||||
|
from multiprocessing.pool import ThreadPool
|
||||||
|
|
||||||
# Tornado
|
import tornado.gen
|
||||||
|
import tornado.httpserver
|
||||||
import tornado.ioloop
|
import tornado.ioloop
|
||||||
import tornado.web
|
import tornado.web
|
||||||
import tornado.httpserver
|
|
||||||
import tornado.gen
|
|
||||||
from gevent import monkey as brit_monkey
|
|
||||||
brit_monkey.patch_all()
|
|
||||||
|
|
||||||
# Raven
|
|
||||||
from raven.contrib.tornado import AsyncSentryClient
|
from raven.contrib.tornado import AsyncSentryClient
|
||||||
|
|
||||||
# pep.py files
|
from common import generalUtils
|
||||||
from constants import bcolors
|
from common.constants import bcolors
|
||||||
from helpers import configHelper
|
from common.db import dbConnector
|
||||||
from objects import glob
|
from common.ddog import datadogClient
|
||||||
from objects import fokabot
|
from common.log import logUtils as log
|
||||||
from objects import banchoConfig
|
from common.ripple import userUtils
|
||||||
from objects import chatFilters
|
from common.web import schiavo
|
||||||
from helpers import consoleHelper
|
from handlers import apiFokabotMessageHandler
|
||||||
from helpers import databaseHelperNew
|
|
||||||
from helpers import generalFunctions
|
|
||||||
from helpers import logHelper as log
|
|
||||||
|
|
||||||
from handlers import mainHandler
|
|
||||||
from handlers import apiIsOnlineHandler
|
from handlers import apiIsOnlineHandler
|
||||||
from handlers import apiOnlineUsersHandler
|
from handlers import apiOnlineUsersHandler
|
||||||
from handlers import apiServerStatusHandler
|
from handlers import apiServerStatusHandler
|
||||||
from handlers import ciTriggerHandler
|
|
||||||
from handlers import apiVerifiedStatusHandler
|
from handlers import apiVerifiedStatusHandler
|
||||||
from handlers import fokabotMessageHandler
|
from handlers import ciTriggerHandler
|
||||||
|
from handlers import mainHandler
|
||||||
|
from handlers import heavyHandler
|
||||||
|
from helpers import configHelper
|
||||||
|
from helpers import consoleHelper
|
||||||
|
from helpers import systemHelper as system
|
||||||
from irc import ircserver
|
from irc import ircserver
|
||||||
|
from objects import banchoConfig
|
||||||
|
from objects import chatFilters
|
||||||
|
from objects import fokabot
|
||||||
|
from objects import glob
|
||||||
|
|
||||||
|
|
||||||
def make_app():
|
def make_app():
|
||||||
return tornado.web.Application([
|
return tornado.web.Application([
|
||||||
@@ -44,10 +43,12 @@ def make_app():
|
|||||||
(r"/api/v1/serverStatus", apiServerStatusHandler.handler),
|
(r"/api/v1/serverStatus", apiServerStatusHandler.handler),
|
||||||
(r"/api/v1/ciTrigger", ciTriggerHandler.handler),
|
(r"/api/v1/ciTrigger", ciTriggerHandler.handler),
|
||||||
(r"/api/v1/verifiedStatus", apiVerifiedStatusHandler.handler),
|
(r"/api/v1/verifiedStatus", apiVerifiedStatusHandler.handler),
|
||||||
(r"/api/v1/fokabotMessage", fokabotMessageHandler.handler)
|
(r"/api/v1/fokabotMessage", apiFokabotMessageHandler.handler),
|
||||||
|
(r"/stress", heavyHandler.handler)
|
||||||
])
|
])
|
||||||
|
|
||||||
if __name__ == "__main__":
|
if __name__ == "__main__":
|
||||||
|
try:
|
||||||
# Server start
|
# Server start
|
||||||
consoleHelper.printServerStartHeader(True)
|
consoleHelper.printServerStartHeader(True)
|
||||||
|
|
||||||
@@ -55,7 +56,7 @@ if __name__ == "__main__":
|
|||||||
consoleHelper.printNoNl("> Loading config file... ")
|
consoleHelper.printNoNl("> Loading config file... ")
|
||||||
glob.conf = configHelper.config("config.ini")
|
glob.conf = configHelper.config("config.ini")
|
||||||
|
|
||||||
if glob.conf.default == True:
|
if glob.conf.default:
|
||||||
# We have generated a default config.ini, quit server
|
# We have generated a default config.ini, quit server
|
||||||
consoleHelper.printWarning()
|
consoleHelper.printWarning()
|
||||||
consoleHelper.printColored("[!] config.ini not found. A default one has been generated.", bcolors.YELLOW)
|
consoleHelper.printColored("[!] config.ini not found. A default one has been generated.", bcolors.YELLOW)
|
||||||
@@ -63,7 +64,7 @@ if __name__ == "__main__":
|
|||||||
sys.exit()
|
sys.exit()
|
||||||
|
|
||||||
# If we haven't generated a default config.ini, check if it's valid
|
# If we haven't generated a default config.ini, check if it's valid
|
||||||
if glob.conf.checkConfig() == False:
|
if not glob.conf.checkConfig():
|
||||||
consoleHelper.printError()
|
consoleHelper.printError()
|
||||||
consoleHelper.printColored("[!] Invalid config.ini. Please configure it properly", bcolors.RED)
|
consoleHelper.printColored("[!] Invalid config.ini. Please configure it properly", bcolors.RED)
|
||||||
consoleHelper.printColored("[!] Delete your config.ini to generate a default one", bcolors.RED)
|
consoleHelper.printColored("[!] Delete your config.ini to generate a default one", bcolors.RED)
|
||||||
@@ -71,11 +72,18 @@ if __name__ == "__main__":
|
|||||||
else:
|
else:
|
||||||
consoleHelper.printDone()
|
consoleHelper.printDone()
|
||||||
|
|
||||||
|
# Create data folder if needed
|
||||||
|
consoleHelper.printNoNl("> Checking folders... ")
|
||||||
|
paths = [".data"]
|
||||||
|
for i in paths:
|
||||||
|
if not os.path.exists(i):
|
||||||
|
os.makedirs(i, 0o770)
|
||||||
|
consoleHelper.printDone()
|
||||||
|
|
||||||
# Connect to db
|
# Connect to db
|
||||||
try:
|
try:
|
||||||
consoleHelper.printNoNl("> Connecting to MySQL db")
|
consoleHelper.printNoNl("> Connecting to MySQL database...")
|
||||||
glob.db = databaseHelperNew.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()
|
||||||
except:
|
except:
|
||||||
@@ -99,6 +107,15 @@ if __name__ == "__main__":
|
|||||||
glob.tokens.deleteBanchoSessions()
|
glob.tokens.deleteBanchoSessions()
|
||||||
consoleHelper.printDone()
|
consoleHelper.printDone()
|
||||||
|
|
||||||
|
# Create threads pool
|
||||||
|
try:
|
||||||
|
consoleHelper.printNoNl("> Creating threads pool... ")
|
||||||
|
glob.pool = ThreadPool(int(glob.conf.config["server"]["threads"]))
|
||||||
|
consoleHelper.printDone()
|
||||||
|
except:
|
||||||
|
consoleHelper.printError()
|
||||||
|
consoleHelper.printColored("[!] Error while creating threads pool. Please check your config.ini and run the server again", bcolors.RED)
|
||||||
|
|
||||||
try:
|
try:
|
||||||
consoleHelper.printNoNl("> Loading chat filters... ")
|
consoleHelper.printNoNl("> Loading chat filters... ")
|
||||||
glob.chatFilters = chatFilters.chatFilters()
|
glob.chatFilters = chatFilters.chatFilters()
|
||||||
@@ -108,19 +125,17 @@ if __name__ == "__main__":
|
|||||||
consoleHelper.printColored("[!] Error while loading chat filters. Make sure there is a filters.txt file present", bcolors.RED)
|
consoleHelper.printColored("[!] Error while loading chat filters. Make sure there is a filters.txt file present", bcolors.RED)
|
||||||
raise
|
raise
|
||||||
|
|
||||||
# Create data folder if needed
|
|
||||||
consoleHelper.printNoNl("> Checking folders... ")
|
|
||||||
paths = [".data"]
|
|
||||||
for i in paths:
|
|
||||||
if not os.path.exists(i):
|
|
||||||
os.makedirs(i, 0o770)
|
|
||||||
consoleHelper.printDone()
|
|
||||||
|
|
||||||
# Initialize chat channels
|
# Initialize chat channels
|
||||||
print("> Initializing chat channels... ")
|
print("> Initializing chat channels... ")
|
||||||
glob.channels.loadChannels()
|
glob.channels.loadChannels()
|
||||||
consoleHelper.printDone()
|
consoleHelper.printDone()
|
||||||
|
|
||||||
|
# Initialize stremas
|
||||||
|
consoleHelper.printNoNl("> Creating packets streams... ")
|
||||||
|
glob.streams.add("main")
|
||||||
|
glob.streams.add("lobby")
|
||||||
|
consoleHelper.printDone()
|
||||||
|
|
||||||
# Start fokabot
|
# Start fokabot
|
||||||
consoleHelper.printNoNl("> Connecting FokaBot... ")
|
consoleHelper.printNoNl("> Connecting FokaBot... ")
|
||||||
fokabot.connect()
|
fokabot.connect()
|
||||||
@@ -136,54 +151,75 @@ if __name__ == "__main__":
|
|||||||
glob.tokens.spamProtectionResetLoop()
|
glob.tokens.spamProtectionResetLoop()
|
||||||
consoleHelper.printDone()
|
consoleHelper.printDone()
|
||||||
|
|
||||||
|
# Cache user ids
|
||||||
|
consoleHelper.printNoNl("> Caching user IDs... ")
|
||||||
|
userUtils.cacheUserIDs()
|
||||||
|
consoleHelper.printDone()
|
||||||
|
|
||||||
# Localize warning
|
# Localize warning
|
||||||
glob.localize = generalFunctions.stringToBool(glob.conf.config["localize"]["enable"])
|
glob.localize = generalUtils.stringToBool(glob.conf.config["localize"]["enable"])
|
||||||
if glob.localize == False:
|
if not glob.localize:
|
||||||
consoleHelper.printColored("[!] Warning! Users localization is disabled!", bcolors.YELLOW)
|
consoleHelper.printColored("[!] Warning! Users localization is disabled!", bcolors.YELLOW)
|
||||||
|
|
||||||
# Discord
|
# Discord
|
||||||
glob.discord = generalFunctions.stringToBool(glob.conf.config["discord"]["enable"])
|
if generalUtils.stringToBool(glob.conf.config["discord"]["enable"]):
|
||||||
if glob.discord == False:
|
glob.schiavo = schiavo.schiavo(glob.conf.config["discord"]["boturl"])
|
||||||
|
else:
|
||||||
consoleHelper.printColored("[!] Warning! Discord logging is disabled!", bcolors.YELLOW)
|
consoleHelper.printColored("[!] Warning! Discord logging is disabled!", bcolors.YELLOW)
|
||||||
|
|
||||||
# Gzip
|
# Gzip
|
||||||
glob.gzip = generalFunctions.stringToBool(glob.conf.config["server"]["gzip"])
|
glob.gzip = generalUtils.stringToBool(glob.conf.config["server"]["gzip"])
|
||||||
glob.gziplevel = int(glob.conf.config["server"]["gziplevel"])
|
glob.gziplevel = int(glob.conf.config["server"]["gziplevel"])
|
||||||
if glob.gzip == False:
|
if not glob.gzip:
|
||||||
consoleHelper.printColored("[!] Warning! Gzip compression is disabled!", bcolors.YELLOW)
|
consoleHelper.printColored("[!] Warning! Gzip compression is disabled!", bcolors.YELLOW)
|
||||||
|
|
||||||
# Debug mode
|
# Debug mode
|
||||||
glob.debug = generalFunctions.stringToBool(glob.conf.config["debug"]["enable"])
|
glob.debug = generalUtils.stringToBool(glob.conf.config["debug"]["enable"])
|
||||||
glob.outputPackets = generalFunctions.stringToBool(glob.conf.config["debug"]["packets"])
|
glob.outputPackets = generalUtils.stringToBool(glob.conf.config["debug"]["packets"])
|
||||||
glob.outputRequestTime = generalFunctions.stringToBool(glob.conf.config["debug"]["time"])
|
glob.outputRequestTime = generalUtils.stringToBool(glob.conf.config["debug"]["time"])
|
||||||
if glob.debug == True:
|
if glob.debug:
|
||||||
consoleHelper.printColored("[!] Warning! Server running in debug mode!", bcolors.YELLOW)
|
consoleHelper.printColored("[!] Warning! Server running in debug mode!", bcolors.YELLOW)
|
||||||
|
|
||||||
# Make app
|
# Make app
|
||||||
application = make_app()
|
glob.application = make_app()
|
||||||
|
|
||||||
# Set up sentry
|
# Set up sentry
|
||||||
try:
|
try:
|
||||||
glob.sentry = generalFunctions.stringToBool(glob.conf.config["sentry"]["enable"])
|
glob.sentry = generalUtils.stringToBool(glob.conf.config["sentry"]["enable"])
|
||||||
if glob.sentry == True:
|
if glob.sentry:
|
||||||
application.sentry_client = AsyncSentryClient(glob.conf.config["sentry"]["banchodns"], release=glob.VERSION)
|
glob.application.sentry_client = AsyncSentryClient(glob.conf.config["sentry"]["banchodns"], release=glob.VERSION)
|
||||||
else:
|
else:
|
||||||
consoleHelper.printColored("[!] Warning! Sentry logging is disabled!", bcolors.YELLOW)
|
consoleHelper.printColored("[!] Warning! Sentry logging is disabled!", bcolors.YELLOW)
|
||||||
except:
|
except:
|
||||||
consoleHelper.printColored("[!] Error while starting sentry client! Please check your config.ini and run the server again", bcolors.RED)
|
consoleHelper.printColored("[!] Error while starting sentry client! Please check your config.ini and run the server again", bcolors.RED)
|
||||||
|
|
||||||
|
# Set up datadog
|
||||||
|
try:
|
||||||
|
if generalUtils.stringToBool(glob.conf.config["datadog"]["enable"]):
|
||||||
|
glob.dog = datadogClient.datadogClient(
|
||||||
|
glob.conf.config["datadog"]["apikey"],
|
||||||
|
glob.conf.config["datadog"]["appkey"],
|
||||||
|
[
|
||||||
|
datadogClient.periodicCheck("online_users", lambda: len(glob.tokens.tokens)),
|
||||||
|
datadogClient.periodicCheck("multiplayer_matches", lambda: len(glob.matches.matches)),
|
||||||
|
])
|
||||||
|
else:
|
||||||
|
consoleHelper.printColored("[!] Warning! Datadog stats tracking is disabled!", bcolors.YELLOW)
|
||||||
|
except:
|
||||||
|
consoleHelper.printColored("[!] Error while starting Datadog client! Please check your config.ini and run the server again", bcolors.RED)
|
||||||
|
|
||||||
# Cloudflare memes
|
# Cloudflare memes
|
||||||
glob.cloudflare = generalFunctions.stringToBool(glob.conf.config["server"]["cloudflare"])
|
glob.cloudflare = generalUtils.stringToBool(glob.conf.config["server"]["cloudflare"])
|
||||||
|
|
||||||
# IRC start message and console output
|
# IRC start message and console output
|
||||||
glob.irc = generalFunctions.stringToBool(glob.conf.config["irc"]["enable"])
|
glob.irc = generalUtils.stringToBool(glob.conf.config["irc"]["enable"])
|
||||||
if glob.irc == True:
|
if glob.irc:
|
||||||
# IRC port
|
# IRC port
|
||||||
try:
|
try:
|
||||||
ircPort = int(glob.conf.config["irc"]["port"])
|
ircPort = int(glob.conf.config["irc"]["port"])
|
||||||
except:
|
except:
|
||||||
consoleHelper.printColored("[!] Invalid IRC port! Please check your config.ini and run the server again", bcolors.RED)
|
consoleHelper.printColored("[!] Invalid IRC port! Please check your config.ini and run the server again", bcolors.RED)
|
||||||
log.logMessage("IRC server started!", discord=True, of="info.txt", stdout=False)
|
log.logMessage("**pep.py** IRC server started!", discord="bunker", of="info.txt", stdout=False)
|
||||||
consoleHelper.printColored("> IRC server listening on 127.0.0.1:{}...".format(ircPort), bcolors.GREEN)
|
consoleHelper.printColored("> IRC server listening on 127.0.0.1:{}...".format(ircPort), bcolors.GREEN)
|
||||||
threading.Thread(target=lambda: ircserver.main(port=ircPort)).start()
|
threading.Thread(target=lambda: ircserver.main(port=ircPort)).start()
|
||||||
else:
|
else:
|
||||||
@@ -196,9 +232,11 @@ if __name__ == "__main__":
|
|||||||
consoleHelper.printColored("[!] Invalid server port! Please check your config.ini and run the server again", bcolors.RED)
|
consoleHelper.printColored("[!] Invalid server port! Please check your config.ini and run the server again", bcolors.RED)
|
||||||
|
|
||||||
# Server start message and console output
|
# Server start message and console output
|
||||||
log.logMessage("Server started!", discord=True, of="info.txt", stdout=False)
|
log.logMessage("**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)
|
||||||
|
|
||||||
# Start tornado
|
# Start tornado
|
||||||
application.listen(serverPort)
|
glob.application.listen(serverPort)
|
||||||
tornado.ioloop.IOLoop.instance().start()
|
tornado.ioloop.IOLoop.instance().start()
|
||||||
|
finally:
|
||||||
|
system.dispose()
|
6
requirements.txt
Normal file
6
requirements.txt
Normal file
@@ -0,0 +1,6 @@
|
|||||||
|
requests
|
||||||
|
tornado
|
||||||
|
mysqlclient
|
||||||
|
psutil
|
||||||
|
raven
|
||||||
|
bcrypt
|
@@ -1,4 +0,0 @@
|
|||||||
D:
|
|
||||||
cd D:\DevStuff\newripple\pep.py
|
|
||||||
python pep.py
|
|
||||||
pause
|
|
Reference in New Issue
Block a user