From 2ce852d7225310dce8d7fee57d1af0ae121ed440 Mon Sep 17 00:00:00 2001 From: RealistikDash Date: Fri, 31 May 2024 23:59:12 +0100 Subject: [PATCH 01/10] refactor: remove cython --- handlers/{mainHandler.pyx => mainHandler.py} | 0 helpers/{packetHelper.pyx => packetHelper.py} | 52 +++++++++---------- requirements.txt | 1 - setup.py | 17 ------ 4 files changed, 25 insertions(+), 45 deletions(-) rename handlers/{mainHandler.pyx => mainHandler.py} (100%) mode change 100755 => 100644 rename helpers/{packetHelper.pyx => packetHelper.py} (86%) mode change 100755 => 100644 delete mode 100644 setup.py diff --git a/handlers/mainHandler.pyx b/handlers/mainHandler.py old mode 100755 new mode 100644 similarity index 100% rename from handlers/mainHandler.pyx rename to handlers/mainHandler.py diff --git a/helpers/packetHelper.pyx b/helpers/packetHelper.py old mode 100755 new mode 100644 similarity index 86% rename from helpers/packetHelper.pyx rename to helpers/packetHelper.py index ae82728..d57a9ec --- a/helpers/packetHelper.pyx +++ b/helpers/packetHelper.py @@ -1,15 +1,15 @@ import struct from constants import dataTypes -cpdef bytearray uleb128Encode(int num): +def uleb128Encode(num: int) -> bytearray: """ Encode an int to uleb128 :param num: int to encode :return: bytearray with encoded number """ - cdef bytearray arr = bytearray() - cdef int length = 0 + arr = bytearray() + length = 0 if num == 0: return bytearray(b"\x00") @@ -23,28 +23,29 @@ return arr -cpdef list uleb128Decode(bytes num): +def uleb128Decode(num: bytes) -> tuple[int, int]: """ Decode a uleb128 to int :param num: encoded uleb128 int :return: (total, length) """ - cdef int shift = 0 - cdef list arr = [0,0] #total, length - cdef int b + + shift = 0 + value = 0 + length = 0 while True: - b = num[arr[1]] - arr[1]+=1 - arr[0] |= int(b & 127) << shift + b = num[length] + length += 1 + value |= int(b & 127) << shift if b & 128 == 0: break shift += 7 - return arr + return value, length -cpdef unpackData(bytes data, int dataType): +def unpackData(data: bytes, dataType: int): """ Unpacks a single section of a packet. @@ -75,7 +76,7 @@ # Unpack return struct.unpack(unpackType, bytes(data))[0] -cpdef bytes packData(__data, int dataType): +def packData(__data, dataType: int) -> bytes: """ Packs a single section of a packet. @@ -83,9 +84,9 @@ :param dataType: data type :return: packed bytes """ - cdef bytes data = bytes() # data to return - cdef bint pack = True # if True, use pack. False only with strings - cdef str packType + data = bytes() # data to return + pack = True # if True, use pack. False only with strings + packType = "" # Get right pack Type if dataType == dataTypes.BBYTES: @@ -137,7 +138,7 @@ return data -cpdef bytes buildPacket(int __packet, __packetData = None): +def buildPacket(__packet: int, __packetData = None) -> bytes: """ Builds a packet @@ -149,9 +150,9 @@ if __packetData is None: __packetData = [] # Set some variables - cdef bytes packetData = bytes() - cdef int packetLength = 0 - cdef bytes packetBytes = bytes() + packetData = bytes() + packetLength = 0 + packetBytes = bytes() # Pack packet data for i in __packetData: @@ -167,7 +168,7 @@ packetBytes += packetData # packet data return packetBytes -cpdef int readPacketID(bytes stream): +def readPacketID(stream: bytes) -> int: """ Read packetID (first two bytes) from a packet @@ -176,7 +177,7 @@ """ return unpackData(stream[0:2], dataTypes.UINT16) -cpdef int readPacketLength(bytes stream): +def readPacketLength(stream: bytes) -> int: """ Read packet data length (3:7 bytes) from a packet @@ -186,7 +187,7 @@ return unpackData(stream[3:7], dataTypes.UINT32) -cpdef readPacketData(bytes stream, list structure=None, bint hasFirstBytes = True): +def readPacketData(stream: bytes, structure = None, hasFirstBytes = True): """ Read packet data from `stream` according to `structure` :param stream: packet bytes @@ -200,10 +201,9 @@ structure = [] # Read packet ID (first 2 bytes) - cdef dict data = {} + data = {} # Skip packet ID and packet length if needed - cdef start, end if hasFirstBytes: end = 7 start = 7 @@ -212,8 +212,6 @@ start = 0 # Read packet - cdef list i - cdef bint unpack for i in structure: start = end unpack = True diff --git a/requirements.txt b/requirements.txt index 288e6ed..949f1d6 100755 --- a/requirements.txt +++ b/requirements.txt @@ -1,6 +1,5 @@ bcrypt==4.0.0 colorama==0.4.5 -cython==0.29.32 discord-webhook==0.17.0 mysqlclient==2.0.3 osupyparser diff --git a/setup.py b/setup.py deleted file mode 100644 index ce1c0ec..0000000 --- a/setup.py +++ /dev/null @@ -1,17 +0,0 @@ -from __future__ import annotations - -from Cython.Build import cythonize -from setuptools import Extension -from setuptools import setup - -# List of Cython modules to build -cython_modules = [ - Extension("handlers.mainHandler", ["handlers/mainHandler.pyx"]), - Extension("helpers.packetHelper", ["helpers/packetHelper.pyx"]), -] - -# Build the Cython modules -setup( - name="pep.py Cython modules", - ext_modules=cythonize(cython_modules, nthreads=4), -) From 0abb840c93c7182d8f39839a3ff0488dc5dfbb57 Mon Sep 17 00:00:00 2001 From: RealistikDash Date: Sat, 1 Jun 2024 00:03:58 +0100 Subject: [PATCH 02/10] fix: correct readme to 2024 --- README.md | 33 ++++----------------------------- 1 file changed, 4 insertions(+), 29 deletions(-) diff --git a/README.md b/README.md index c144326..9ef32c8 100755 --- a/README.md +++ b/README.md @@ -14,42 +14,17 @@ This portion of the RealistikOsu manages all of the real-time, packet related po ## Why is our fork better? This fork of pep.py has been developed specifically to suit the need of RealistikOsu. With the rapid growth of the server, more and more demand has been placed on us in regards of features alongside performance. The original repo features a large quantity of fatal flaws alongside performance hogs, and through our usage of the software, we have solved a majority of those issues. +- Full Dockerisation - Fixed multiplayer -- MASSIVE OPTIMISATIONS (your database will thank you) +- Major performance optimisations. - Relax and Autopilot support - Extended Redis API - Extended 3rd party API support - Customised HWID system - Extended in-game bot commands -- Python 3.9 support! +- Python 3.9 support ## Requirements To run pep.py, there is an list of requirements to ensure the server runs at all. -- Python >=3.6 +- Python >=3.9 - RealistikOsu MySQL Database -- Cython + GCC -- Linux (preferably Ubuntu 18.04) - -## Notes for potential users -If you are planning on using our fork of pep.py, there is a multitude of things to consider that are unique to our variant -- Low reliance on `userutils` for performance reasons. - -The entire `userutils` module promotes inefficient use of the database. This is especially bad on established servers with large -databases, where the cost of each query becomes more and more expensive with every user. This appends unnecessary stress on the -database and as a consequence, the server as a whole. -- Tendency to hardcode things. - -I, RealistikDash, have a bad habit of hardcoding things. While this is usually fine for the intended application of this, being used -on RealistikOsu, it may be a pain to scan through the code if you are attempting to run this on your server. In this scenario, I would -advise searching through `constants/rosuprivs.py` and `constants/serverPackets.py` for any references you would like to change. -- Private database - -As expected, our variant uses our own database schema. A copy of our database schema (designed for use with [USSR](https://github.com/RealistikOsu/USSR)) can be found [here!](https://github.com/RealistikOsu/USSR/blob/master/extras/db.sql) - -Due to the old nature of the origin code, the age of the modules is **quite large**. This means that we do not benefit from any improvements, -bugfixes or any other quality of life improvements of any new module updates. This is an issue with the whole Python based Ripple stack, and is -not an exclusive to RealistikOsu pep.py. **This issue is however planned on being addressed soon.** -- No IRC - -Due to the lack of usage from the RealistikOsu community, the entire IRC server has essentially been nuked. This is because while not being used, it -still took up a thread and served as dead code in the repo. Not much else to say other than that it was pretty much never used. From 8876c61049dd5c3d43a082d575ae1cf63424307b Mon Sep 17 00:00:00 2001 From: RealistikDash Date: Sat, 1 Jun 2024 00:06:53 +0100 Subject: [PATCH 03/10] cleanup old directories --- .gitignore | 1 + .gitmodules | 0 .vscode/c_cpp_properties.json | 16 ---------------- Makefile | 7 ------- build.sh | 1 - common/.gitignore | 6 ------ pep.py => main.py | 0 7 files changed, 1 insertion(+), 30 deletions(-) delete mode 100755 .gitmodules delete mode 100644 .vscode/c_cpp_properties.json delete mode 100644 Makefile delete mode 100755 build.sh delete mode 100755 common/.gitignore rename pep.py => main.py (100%) diff --git a/.gitignore b/.gitignore index b9b2c82..c4c34d6 100755 --- a/.gitignore +++ b/.gitignore @@ -9,3 +9,4 @@ redistest.py *.so .pyenv config.json +.vscode/ diff --git a/.gitmodules b/.gitmodules deleted file mode 100755 index e69de29..0000000 diff --git a/.vscode/c_cpp_properties.json b/.vscode/c_cpp_properties.json deleted file mode 100644 index baf324f..0000000 --- a/.vscode/c_cpp_properties.json +++ /dev/null @@ -1,16 +0,0 @@ -{ - "configurations": [ - { - "name": "Linux", - "includePath": [ - "${workspaceFolder}/**" - ], - "defines": [], - "compilerPath": "/usr/bin/gcc", - "cStandard": "gnu11", - "cppStandard": "gnu++14", - "intelliSenseMode": "linux-gcc-x64" - } - ], - "version": 4 -} diff --git a/Makefile b/Makefile deleted file mode 100644 index cd5080c..0000000 --- a/Makefile +++ /dev/null @@ -1,7 +0,0 @@ -all: build run - -build: - python3.9 setup.py build_ext --inplace - -run: - python3.9 pep.py diff --git a/build.sh b/build.sh deleted file mode 100755 index 6227939..0000000 --- a/build.sh +++ /dev/null @@ -1 +0,0 @@ -python3.9 setup.py build_ext --inplace diff --git a/common/.gitignore b/common/.gitignore deleted file mode 100755 index 88ce1ac..0000000 --- a/common/.gitignore +++ /dev/null @@ -1,6 +0,0 @@ -**/build -**/__pycache__ -.idea -*.c -*.so -config.json diff --git a/pep.py b/main.py similarity index 100% rename from pep.py rename to main.py From 3cbc989a4eb1d969f872c809f6165be7389d4dbf Mon Sep 17 00:00:00 2001 From: RealistikDash Date: Sat, 1 Jun 2024 00:14:22 +0100 Subject: [PATCH 04/10] refactor: reorganise project structure --- {collection => peppy/collection}/channels.py | 0 {collection => peppy/collection}/matches.py | 0 {collection => peppy/collection}/streams.py | 0 {collection => peppy/collection}/tokens.py | 0 {common => peppy/common}/__init__.py | 0 .../common}/constants/__init__.py | 0 {common => peppy/common}/constants/actions.py | 0 {common => peppy/common}/constants/bcolors.py | 0 .../common}/constants/gameModes.py | 0 {common => peppy/common}/constants/mods.py | 0 .../common}/constants/privileges.py | 0 {common => peppy/common}/db/__init__.py | 0 {common => peppy/common}/db/dbConnector.py | 0 {common => peppy/common}/generalUtils.py | 0 {common => peppy/common}/redis/__init__.py | 0 .../common}/redis/generalPubSubHandler.py | 0 {common => peppy/common}/redis/pubSub.py | 0 {common => peppy/common}/ripple/__init__.py | 0 {common => peppy/common}/ripple/scoreUtils.py | 0 {common => peppy/common}/ripple/userUtils.py | 0 {common => peppy/common}/web/__init__.py | 0 .../common}/web/requestsManager.py | 0 config.py => peppy/config.py | 0 {constants => peppy/constants}/__init__.py | 0 .../constants}/clientPackets.py | 0 {constants => peppy/constants}/dataTypes.py | 0 {constants => peppy/constants}/exceptions.py | 0 .../constants}/fokabotCommands.py | 0 .../constants}/matchModModes.py | 0 .../constants}/matchScoringTypes.py | 0 .../constants}/matchTeamTypes.py | 0 {constants => peppy/constants}/matchTeams.py | 0 {constants => peppy/constants}/packetIDs.py | 0 {constants => peppy/constants}/rosuprivs.py | 0 .../constants}/serverPackets.py | 0 .../constants}/slotStatuses.py | 0 {constants => peppy/constants}/userRanks.py | 0 {events => peppy/events}/__init__.py | 0 .../events}/beatmapInfoRequest.py | 0 {events => peppy/events}/cantSpectateEvent.py | 0 {events => peppy/events}/changeActionEvent.py | 0 .../events}/changeMatchModsEvent.py | 0 .../events}/changeMatchPasswordEvent.py | 0 .../events}/changeMatchSettingsEvent.py | 0 {events => peppy/events}/changeSlotEvent.py | 0 {events => peppy/events}/channelJoinEvent.py | 0 {events => peppy/events}/channelPartEvent.py | 0 {events => peppy/events}/createMatchEvent.py | 0 {events => peppy/events}/friendAddEvent.py | 0 {events => peppy/events}/friendRemoveEvent.py | 0 {events => peppy/events}/joinLobbyEvent.py | 0 {events => peppy/events}/joinMatchEvent.py | 0 {events => peppy/events}/loginEvent.py | 0 {events => peppy/events}/logoutEvent.py | 0 {events => peppy/events}/matchBeatmapEvent.py | 0 .../events}/matchChangeTeamEvent.py | 0 .../events}/matchCompleteEvent.py | 0 {events => peppy/events}/matchFailedEvent.py | 0 {events => peppy/events}/matchFramesEvent.py | 0 .../events}/matchHasBeatmapEvent.py | 0 {events => peppy/events}/matchInviteEvent.py | 0 {events => peppy/events}/matchLockEvent.py | 0 .../events}/matchNoBeatmapEvent.py | 0 .../events}/matchPlayerLoadEvent.py | 0 {events => peppy/events}/matchReadyEvent.py | 0 {events => peppy/events}/matchSkipEvent.py | 0 {events => peppy/events}/matchStartEvent.py | 0 .../events}/matchTransferHostEvent.py | 0 {events => peppy/events}/partLobbyEvent.py | 0 {events => peppy/events}/partMatchEvent.py | 0 .../events}/requestStatusUpdateEvent.py | 0 .../events}/sendPrivateMessageEvent.py | 0 .../events}/sendPublicMessageEvent.py | 0 .../events}/setAwayMessageEvent.py | 0 .../events}/spectateFramesEvent.py | 0 .../events}/startSpectatingEvent.py | 0 .../events}/stopSpectatingEvent.py | 0 .../tournamentJoinMatchChannelEvent.py | 0 .../tournamentLeaveMatchChannelEvent.py | 0 .../tournamentMatchInfoRequestEvent.py | 0 .../events}/userPanelRequestEvent.py | 0 .../events}/userStatsRequestEvent.py | 0 {handlers => peppy/handlers}/__init__.py | 0 {handlers => peppy/handlers}/apiAerisThing.py | 0 .../handlers}/apiOnlineUsers.py | 56 +++++++++--------- .../handlers}/apiOnlineUsersHandler.py | 0 .../handlers}/apiServerStatusHandler.py | 0 {handlers => peppy/handlers}/api_status.py | 0 {handlers => peppy/handlers}/mainHandler.py | 0 {helpers => peppy/helpers}/__init__.py | 0 {helpers => peppy/helpers}/chatHelper.py | 0 {helpers => peppy/helpers}/consoleHelper.py | 0 {helpers => peppy/helpers}/geo_helper.py | 0 {helpers => peppy/helpers}/packetHelper.py | 0 {helpers => peppy/helpers}/realistik_stuff.py | 0 {helpers => peppy/helpers}/status_helper.py | 0 {helpers => peppy/helpers}/systemHelper.py | 0 {helpers => peppy/helpers}/user_helper.py | 0 logger.py => peppy/logger.py | 0 main.py => peppy/main.py | 15 +++-- {objects => peppy/objects}/__init__.py | 0 {objects => peppy/objects}/banchoConfig.py | 0 {objects => peppy/objects}/channel.py | 0 {objects => peppy/objects}/fokabot.py | 0 {objects => peppy/objects}/glob.py | 0 {objects => peppy/objects}/match.py | 0 {objects => peppy/objects}/osuToken.py | 0 {objects => peppy/objects}/stream.py | 0 .../redis_handlers}/__init__.py | 0 .../redis_handlers}/banHandler.py | 0 .../redis_handlers}/bot_msg_handler.py | 0 .../redis_handlers}/disconnectHandler.py | 0 .../redis_handlers}/notificationHandler.py | 0 .../redis_handlers}/refreshPrivsHandler.py | 0 .../redis_handlers}/updateSilenceHandler.py | 0 .../redis_handlers}/updateStatsHandler.py | 0 requirements/dev.txt | 2 + requirements.txt => requirements/main.txt | 0 bible.txt => resources/bible.txt | 0 .../geolocation_database.mmdb | Bin 120 files changed, 37 insertions(+), 36 deletions(-) rename {collection => peppy/collection}/channels.py (100%) mode change 100755 => 100644 rename {collection => peppy/collection}/matches.py (100%) mode change 100755 => 100644 rename {collection => peppy/collection}/streams.py (100%) mode change 100755 => 100644 rename {collection => peppy/collection}/tokens.py (100%) mode change 100755 => 100644 rename {common => peppy/common}/__init__.py (100%) mode change 100755 => 100644 rename {common => peppy/common}/constants/__init__.py (100%) mode change 100755 => 100644 rename {common => peppy/common}/constants/actions.py (100%) mode change 100755 => 100644 rename {common => peppy/common}/constants/bcolors.py (100%) mode change 100755 => 100644 rename {common => peppy/common}/constants/gameModes.py (100%) mode change 100755 => 100644 rename {common => peppy/common}/constants/mods.py (100%) mode change 100755 => 100644 rename {common => peppy/common}/constants/privileges.py (100%) mode change 100755 => 100644 rename {common => peppy/common}/db/__init__.py (100%) mode change 100755 => 100644 rename {common => peppy/common}/db/dbConnector.py (100%) mode change 100755 => 100644 rename {common => peppy/common}/generalUtils.py (100%) mode change 100755 => 100644 rename {common => peppy/common}/redis/__init__.py (100%) mode change 100755 => 100644 rename {common => peppy/common}/redis/generalPubSubHandler.py (100%) mode change 100755 => 100644 rename {common => peppy/common}/redis/pubSub.py (100%) mode change 100755 => 100644 rename {common => peppy/common}/ripple/__init__.py (100%) mode change 100755 => 100644 rename {common => peppy/common}/ripple/scoreUtils.py (100%) mode change 100755 => 100644 rename {common => peppy/common}/ripple/userUtils.py (100%) mode change 100755 => 100644 rename {common => peppy/common}/web/__init__.py (100%) mode change 100755 => 100644 rename {common => peppy/common}/web/requestsManager.py (100%) mode change 100755 => 100644 rename config.py => peppy/config.py (100%) rename {constants => peppy/constants}/__init__.py (100%) mode change 100755 => 100644 rename {constants => peppy/constants}/clientPackets.py (100%) mode change 100755 => 100644 rename {constants => peppy/constants}/dataTypes.py (100%) mode change 100755 => 100644 rename {constants => peppy/constants}/exceptions.py (100%) mode change 100755 => 100644 rename {constants => peppy/constants}/fokabotCommands.py (100%) rename {constants => peppy/constants}/matchModModes.py (100%) mode change 100755 => 100644 rename {constants => peppy/constants}/matchScoringTypes.py (100%) mode change 100755 => 100644 rename {constants => peppy/constants}/matchTeamTypes.py (100%) mode change 100755 => 100644 rename {constants => peppy/constants}/matchTeams.py (100%) mode change 100755 => 100644 rename {constants => peppy/constants}/packetIDs.py (100%) mode change 100755 => 100644 rename {constants => peppy/constants}/rosuprivs.py (100%) rename {constants => peppy/constants}/serverPackets.py (100%) mode change 100755 => 100644 rename {constants => peppy/constants}/slotStatuses.py (100%) mode change 100755 => 100644 rename {constants => peppy/constants}/userRanks.py (100%) mode change 100755 => 100644 rename {events => peppy/events}/__init__.py (100%) mode change 100755 => 100644 rename {events => peppy/events}/beatmapInfoRequest.py (100%) rename {events => peppy/events}/cantSpectateEvent.py (100%) mode change 100755 => 100644 rename {events => peppy/events}/changeActionEvent.py (100%) mode change 100755 => 100644 rename {events => peppy/events}/changeMatchModsEvent.py (100%) mode change 100755 => 100644 rename {events => peppy/events}/changeMatchPasswordEvent.py (100%) mode change 100755 => 100644 rename {events => peppy/events}/changeMatchSettingsEvent.py (100%) mode change 100755 => 100644 rename {events => peppy/events}/changeSlotEvent.py (100%) mode change 100755 => 100644 rename {events => peppy/events}/channelJoinEvent.py (100%) mode change 100755 => 100644 rename {events => peppy/events}/channelPartEvent.py (100%) mode change 100755 => 100644 rename {events => peppy/events}/createMatchEvent.py (100%) mode change 100755 => 100644 rename {events => peppy/events}/friendAddEvent.py (100%) mode change 100755 => 100644 rename {events => peppy/events}/friendRemoveEvent.py (100%) mode change 100755 => 100644 rename {events => peppy/events}/joinLobbyEvent.py (100%) mode change 100755 => 100644 rename {events => peppy/events}/joinMatchEvent.py (100%) mode change 100755 => 100644 rename {events => peppy/events}/loginEvent.py (100%) mode change 100755 => 100644 rename {events => peppy/events}/logoutEvent.py (100%) mode change 100755 => 100644 rename {events => peppy/events}/matchBeatmapEvent.py (100%) mode change 100755 => 100644 rename {events => peppy/events}/matchChangeTeamEvent.py (100%) mode change 100755 => 100644 rename {events => peppy/events}/matchCompleteEvent.py (100%) mode change 100755 => 100644 rename {events => peppy/events}/matchFailedEvent.py (100%) mode change 100755 => 100644 rename {events => peppy/events}/matchFramesEvent.py (100%) mode change 100755 => 100644 rename {events => peppy/events}/matchHasBeatmapEvent.py (100%) mode change 100755 => 100644 rename {events => peppy/events}/matchInviteEvent.py (100%) mode change 100755 => 100644 rename {events => peppy/events}/matchLockEvent.py (100%) mode change 100755 => 100644 rename {events => peppy/events}/matchNoBeatmapEvent.py (100%) mode change 100755 => 100644 rename {events => peppy/events}/matchPlayerLoadEvent.py (100%) mode change 100755 => 100644 rename {events => peppy/events}/matchReadyEvent.py (100%) mode change 100755 => 100644 rename {events => peppy/events}/matchSkipEvent.py (100%) mode change 100755 => 100644 rename {events => peppy/events}/matchStartEvent.py (100%) mode change 100755 => 100644 rename {events => peppy/events}/matchTransferHostEvent.py (100%) mode change 100755 => 100644 rename {events => peppy/events}/partLobbyEvent.py (100%) mode change 100755 => 100644 rename {events => peppy/events}/partMatchEvent.py (100%) mode change 100755 => 100644 rename {events => peppy/events}/requestStatusUpdateEvent.py (100%) mode change 100755 => 100644 rename {events => peppy/events}/sendPrivateMessageEvent.py (100%) mode change 100755 => 100644 rename {events => peppy/events}/sendPublicMessageEvent.py (100%) mode change 100755 => 100644 rename {events => peppy/events}/setAwayMessageEvent.py (100%) mode change 100755 => 100644 rename {events => peppy/events}/spectateFramesEvent.py (100%) mode change 100755 => 100644 rename {events => peppy/events}/startSpectatingEvent.py (100%) mode change 100755 => 100644 rename {events => peppy/events}/stopSpectatingEvent.py (100%) mode change 100755 => 100644 rename {events => peppy/events}/tournamentJoinMatchChannelEvent.py (100%) mode change 100755 => 100644 rename {events => peppy/events}/tournamentLeaveMatchChannelEvent.py (100%) mode change 100755 => 100644 rename {events => peppy/events}/tournamentMatchInfoRequestEvent.py (100%) mode change 100755 => 100644 rename {events => peppy/events}/userPanelRequestEvent.py (100%) mode change 100755 => 100644 rename {events => peppy/events}/userStatsRequestEvent.py (100%) mode change 100755 => 100644 rename {handlers => peppy/handlers}/__init__.py (100%) mode change 100755 => 100644 rename {handlers => peppy/handlers}/apiAerisThing.py (100%) rename {handlers => peppy/handlers}/apiOnlineUsers.py (96%) rename {handlers => peppy/handlers}/apiOnlineUsersHandler.py (100%) mode change 100755 => 100644 rename {handlers => peppy/handlers}/apiServerStatusHandler.py (100%) mode change 100755 => 100644 rename {handlers => peppy/handlers}/api_status.py (100%) rename {handlers => peppy/handlers}/mainHandler.py (100%) rename {helpers => peppy/helpers}/__init__.py (100%) mode change 100755 => 100644 rename {helpers => peppy/helpers}/chatHelper.py (100%) mode change 100755 => 100644 rename {helpers => peppy/helpers}/consoleHelper.py (100%) mode change 100755 => 100644 rename {helpers => peppy/helpers}/geo_helper.py (100%) rename {helpers => peppy/helpers}/packetHelper.py (100%) rename {helpers => peppy/helpers}/realistik_stuff.py (100%) rename {helpers => peppy/helpers}/status_helper.py (100%) rename {helpers => peppy/helpers}/systemHelper.py (100%) mode change 100755 => 100644 rename {helpers => peppy/helpers}/user_helper.py (100%) rename logger.py => peppy/logger.py (100%) rename main.py => peppy/main.py (94%) rename {objects => peppy/objects}/__init__.py (100%) mode change 100755 => 100644 rename {objects => peppy/objects}/banchoConfig.py (100%) mode change 100755 => 100644 rename {objects => peppy/objects}/channel.py (100%) mode change 100755 => 100644 rename {objects => peppy/objects}/fokabot.py (100%) rename {objects => peppy/objects}/glob.py (100%) rename {objects => peppy/objects}/match.py (100%) mode change 100755 => 100644 rename {objects => peppy/objects}/osuToken.py (100%) rename {objects => peppy/objects}/stream.py (100%) mode change 100755 => 100644 rename {pubSubHandlers => peppy/redis_handlers}/__init__.py (100%) mode change 100755 => 100644 rename {pubSubHandlers => peppy/redis_handlers}/banHandler.py (100%) mode change 100755 => 100644 rename {pubSubHandlers => peppy/redis_handlers}/bot_msg_handler.py (100%) rename {pubSubHandlers => peppy/redis_handlers}/disconnectHandler.py (100%) mode change 100755 => 100644 rename {pubSubHandlers => peppy/redis_handlers}/notificationHandler.py (100%) mode change 100755 => 100644 rename {pubSubHandlers => peppy/redis_handlers}/refreshPrivsHandler.py (100%) rename {pubSubHandlers => peppy/redis_handlers}/updateSilenceHandler.py (100%) mode change 100755 => 100644 rename {pubSubHandlers => peppy/redis_handlers}/updateStatsHandler.py (100%) mode change 100755 => 100644 create mode 100644 requirements/dev.txt rename requirements.txt => requirements/main.txt (100%) mode change 100755 => 100644 rename bible.txt => resources/bible.txt (100%) rename ip_db_2.mmdb => resources/geolocation_database.mmdb (100%) diff --git a/collection/channels.py b/peppy/collection/channels.py old mode 100755 new mode 100644 similarity index 100% rename from collection/channels.py rename to peppy/collection/channels.py diff --git a/collection/matches.py b/peppy/collection/matches.py old mode 100755 new mode 100644 similarity index 100% rename from collection/matches.py rename to peppy/collection/matches.py diff --git a/collection/streams.py b/peppy/collection/streams.py old mode 100755 new mode 100644 similarity index 100% rename from collection/streams.py rename to peppy/collection/streams.py diff --git a/collection/tokens.py b/peppy/collection/tokens.py old mode 100755 new mode 100644 similarity index 100% rename from collection/tokens.py rename to peppy/collection/tokens.py diff --git a/common/__init__.py b/peppy/common/__init__.py old mode 100755 new mode 100644 similarity index 100% rename from common/__init__.py rename to peppy/common/__init__.py diff --git a/common/constants/__init__.py b/peppy/common/constants/__init__.py old mode 100755 new mode 100644 similarity index 100% rename from common/constants/__init__.py rename to peppy/common/constants/__init__.py diff --git a/common/constants/actions.py b/peppy/common/constants/actions.py old mode 100755 new mode 100644 similarity index 100% rename from common/constants/actions.py rename to peppy/common/constants/actions.py diff --git a/common/constants/bcolors.py b/peppy/common/constants/bcolors.py old mode 100755 new mode 100644 similarity index 100% rename from common/constants/bcolors.py rename to peppy/common/constants/bcolors.py diff --git a/common/constants/gameModes.py b/peppy/common/constants/gameModes.py old mode 100755 new mode 100644 similarity index 100% rename from common/constants/gameModes.py rename to peppy/common/constants/gameModes.py diff --git a/common/constants/mods.py b/peppy/common/constants/mods.py old mode 100755 new mode 100644 similarity index 100% rename from common/constants/mods.py rename to peppy/common/constants/mods.py diff --git a/common/constants/privileges.py b/peppy/common/constants/privileges.py old mode 100755 new mode 100644 similarity index 100% rename from common/constants/privileges.py rename to peppy/common/constants/privileges.py diff --git a/common/db/__init__.py b/peppy/common/db/__init__.py old mode 100755 new mode 100644 similarity index 100% rename from common/db/__init__.py rename to peppy/common/db/__init__.py diff --git a/common/db/dbConnector.py b/peppy/common/db/dbConnector.py old mode 100755 new mode 100644 similarity index 100% rename from common/db/dbConnector.py rename to peppy/common/db/dbConnector.py diff --git a/common/generalUtils.py b/peppy/common/generalUtils.py old mode 100755 new mode 100644 similarity index 100% rename from common/generalUtils.py rename to peppy/common/generalUtils.py diff --git a/common/redis/__init__.py b/peppy/common/redis/__init__.py old mode 100755 new mode 100644 similarity index 100% rename from common/redis/__init__.py rename to peppy/common/redis/__init__.py diff --git a/common/redis/generalPubSubHandler.py b/peppy/common/redis/generalPubSubHandler.py old mode 100755 new mode 100644 similarity index 100% rename from common/redis/generalPubSubHandler.py rename to peppy/common/redis/generalPubSubHandler.py diff --git a/common/redis/pubSub.py b/peppy/common/redis/pubSub.py old mode 100755 new mode 100644 similarity index 100% rename from common/redis/pubSub.py rename to peppy/common/redis/pubSub.py diff --git a/common/ripple/__init__.py b/peppy/common/ripple/__init__.py old mode 100755 new mode 100644 similarity index 100% rename from common/ripple/__init__.py rename to peppy/common/ripple/__init__.py diff --git a/common/ripple/scoreUtils.py b/peppy/common/ripple/scoreUtils.py old mode 100755 new mode 100644 similarity index 100% rename from common/ripple/scoreUtils.py rename to peppy/common/ripple/scoreUtils.py diff --git a/common/ripple/userUtils.py b/peppy/common/ripple/userUtils.py old mode 100755 new mode 100644 similarity index 100% rename from common/ripple/userUtils.py rename to peppy/common/ripple/userUtils.py diff --git a/common/web/__init__.py b/peppy/common/web/__init__.py old mode 100755 new mode 100644 similarity index 100% rename from common/web/__init__.py rename to peppy/common/web/__init__.py diff --git a/common/web/requestsManager.py b/peppy/common/web/requestsManager.py old mode 100755 new mode 100644 similarity index 100% rename from common/web/requestsManager.py rename to peppy/common/web/requestsManager.py diff --git a/config.py b/peppy/config.py similarity index 100% rename from config.py rename to peppy/config.py diff --git a/constants/__init__.py b/peppy/constants/__init__.py old mode 100755 new mode 100644 similarity index 100% rename from constants/__init__.py rename to peppy/constants/__init__.py diff --git a/constants/clientPackets.py b/peppy/constants/clientPackets.py old mode 100755 new mode 100644 similarity index 100% rename from constants/clientPackets.py rename to peppy/constants/clientPackets.py diff --git a/constants/dataTypes.py b/peppy/constants/dataTypes.py old mode 100755 new mode 100644 similarity index 100% rename from constants/dataTypes.py rename to peppy/constants/dataTypes.py diff --git a/constants/exceptions.py b/peppy/constants/exceptions.py old mode 100755 new mode 100644 similarity index 100% rename from constants/exceptions.py rename to peppy/constants/exceptions.py diff --git a/constants/fokabotCommands.py b/peppy/constants/fokabotCommands.py similarity index 100% rename from constants/fokabotCommands.py rename to peppy/constants/fokabotCommands.py diff --git a/constants/matchModModes.py b/peppy/constants/matchModModes.py old mode 100755 new mode 100644 similarity index 100% rename from constants/matchModModes.py rename to peppy/constants/matchModModes.py diff --git a/constants/matchScoringTypes.py b/peppy/constants/matchScoringTypes.py old mode 100755 new mode 100644 similarity index 100% rename from constants/matchScoringTypes.py rename to peppy/constants/matchScoringTypes.py diff --git a/constants/matchTeamTypes.py b/peppy/constants/matchTeamTypes.py old mode 100755 new mode 100644 similarity index 100% rename from constants/matchTeamTypes.py rename to peppy/constants/matchTeamTypes.py diff --git a/constants/matchTeams.py b/peppy/constants/matchTeams.py old mode 100755 new mode 100644 similarity index 100% rename from constants/matchTeams.py rename to peppy/constants/matchTeams.py diff --git a/constants/packetIDs.py b/peppy/constants/packetIDs.py old mode 100755 new mode 100644 similarity index 100% rename from constants/packetIDs.py rename to peppy/constants/packetIDs.py diff --git a/constants/rosuprivs.py b/peppy/constants/rosuprivs.py similarity index 100% rename from constants/rosuprivs.py rename to peppy/constants/rosuprivs.py diff --git a/constants/serverPackets.py b/peppy/constants/serverPackets.py old mode 100755 new mode 100644 similarity index 100% rename from constants/serverPackets.py rename to peppy/constants/serverPackets.py diff --git a/constants/slotStatuses.py b/peppy/constants/slotStatuses.py old mode 100755 new mode 100644 similarity index 100% rename from constants/slotStatuses.py rename to peppy/constants/slotStatuses.py diff --git a/constants/userRanks.py b/peppy/constants/userRanks.py old mode 100755 new mode 100644 similarity index 100% rename from constants/userRanks.py rename to peppy/constants/userRanks.py diff --git a/events/__init__.py b/peppy/events/__init__.py old mode 100755 new mode 100644 similarity index 100% rename from events/__init__.py rename to peppy/events/__init__.py diff --git a/events/beatmapInfoRequest.py b/peppy/events/beatmapInfoRequest.py similarity index 100% rename from events/beatmapInfoRequest.py rename to peppy/events/beatmapInfoRequest.py diff --git a/events/cantSpectateEvent.py b/peppy/events/cantSpectateEvent.py old mode 100755 new mode 100644 similarity index 100% rename from events/cantSpectateEvent.py rename to peppy/events/cantSpectateEvent.py diff --git a/events/changeActionEvent.py b/peppy/events/changeActionEvent.py old mode 100755 new mode 100644 similarity index 100% rename from events/changeActionEvent.py rename to peppy/events/changeActionEvent.py diff --git a/events/changeMatchModsEvent.py b/peppy/events/changeMatchModsEvent.py old mode 100755 new mode 100644 similarity index 100% rename from events/changeMatchModsEvent.py rename to peppy/events/changeMatchModsEvent.py diff --git a/events/changeMatchPasswordEvent.py b/peppy/events/changeMatchPasswordEvent.py old mode 100755 new mode 100644 similarity index 100% rename from events/changeMatchPasswordEvent.py rename to peppy/events/changeMatchPasswordEvent.py diff --git a/events/changeMatchSettingsEvent.py b/peppy/events/changeMatchSettingsEvent.py old mode 100755 new mode 100644 similarity index 100% rename from events/changeMatchSettingsEvent.py rename to peppy/events/changeMatchSettingsEvent.py diff --git a/events/changeSlotEvent.py b/peppy/events/changeSlotEvent.py old mode 100755 new mode 100644 similarity index 100% rename from events/changeSlotEvent.py rename to peppy/events/changeSlotEvent.py diff --git a/events/channelJoinEvent.py b/peppy/events/channelJoinEvent.py old mode 100755 new mode 100644 similarity index 100% rename from events/channelJoinEvent.py rename to peppy/events/channelJoinEvent.py diff --git a/events/channelPartEvent.py b/peppy/events/channelPartEvent.py old mode 100755 new mode 100644 similarity index 100% rename from events/channelPartEvent.py rename to peppy/events/channelPartEvent.py diff --git a/events/createMatchEvent.py b/peppy/events/createMatchEvent.py old mode 100755 new mode 100644 similarity index 100% rename from events/createMatchEvent.py rename to peppy/events/createMatchEvent.py diff --git a/events/friendAddEvent.py b/peppy/events/friendAddEvent.py old mode 100755 new mode 100644 similarity index 100% rename from events/friendAddEvent.py rename to peppy/events/friendAddEvent.py diff --git a/events/friendRemoveEvent.py b/peppy/events/friendRemoveEvent.py old mode 100755 new mode 100644 similarity index 100% rename from events/friendRemoveEvent.py rename to peppy/events/friendRemoveEvent.py diff --git a/events/joinLobbyEvent.py b/peppy/events/joinLobbyEvent.py old mode 100755 new mode 100644 similarity index 100% rename from events/joinLobbyEvent.py rename to peppy/events/joinLobbyEvent.py diff --git a/events/joinMatchEvent.py b/peppy/events/joinMatchEvent.py old mode 100755 new mode 100644 similarity index 100% rename from events/joinMatchEvent.py rename to peppy/events/joinMatchEvent.py diff --git a/events/loginEvent.py b/peppy/events/loginEvent.py old mode 100755 new mode 100644 similarity index 100% rename from events/loginEvent.py rename to peppy/events/loginEvent.py diff --git a/events/logoutEvent.py b/peppy/events/logoutEvent.py old mode 100755 new mode 100644 similarity index 100% rename from events/logoutEvent.py rename to peppy/events/logoutEvent.py diff --git a/events/matchBeatmapEvent.py b/peppy/events/matchBeatmapEvent.py old mode 100755 new mode 100644 similarity index 100% rename from events/matchBeatmapEvent.py rename to peppy/events/matchBeatmapEvent.py diff --git a/events/matchChangeTeamEvent.py b/peppy/events/matchChangeTeamEvent.py old mode 100755 new mode 100644 similarity index 100% rename from events/matchChangeTeamEvent.py rename to peppy/events/matchChangeTeamEvent.py diff --git a/events/matchCompleteEvent.py b/peppy/events/matchCompleteEvent.py old mode 100755 new mode 100644 similarity index 100% rename from events/matchCompleteEvent.py rename to peppy/events/matchCompleteEvent.py diff --git a/events/matchFailedEvent.py b/peppy/events/matchFailedEvent.py old mode 100755 new mode 100644 similarity index 100% rename from events/matchFailedEvent.py rename to peppy/events/matchFailedEvent.py diff --git a/events/matchFramesEvent.py b/peppy/events/matchFramesEvent.py old mode 100755 new mode 100644 similarity index 100% rename from events/matchFramesEvent.py rename to peppy/events/matchFramesEvent.py diff --git a/events/matchHasBeatmapEvent.py b/peppy/events/matchHasBeatmapEvent.py old mode 100755 new mode 100644 similarity index 100% rename from events/matchHasBeatmapEvent.py rename to peppy/events/matchHasBeatmapEvent.py diff --git a/events/matchInviteEvent.py b/peppy/events/matchInviteEvent.py old mode 100755 new mode 100644 similarity index 100% rename from events/matchInviteEvent.py rename to peppy/events/matchInviteEvent.py diff --git a/events/matchLockEvent.py b/peppy/events/matchLockEvent.py old mode 100755 new mode 100644 similarity index 100% rename from events/matchLockEvent.py rename to peppy/events/matchLockEvent.py diff --git a/events/matchNoBeatmapEvent.py b/peppy/events/matchNoBeatmapEvent.py old mode 100755 new mode 100644 similarity index 100% rename from events/matchNoBeatmapEvent.py rename to peppy/events/matchNoBeatmapEvent.py diff --git a/events/matchPlayerLoadEvent.py b/peppy/events/matchPlayerLoadEvent.py old mode 100755 new mode 100644 similarity index 100% rename from events/matchPlayerLoadEvent.py rename to peppy/events/matchPlayerLoadEvent.py diff --git a/events/matchReadyEvent.py b/peppy/events/matchReadyEvent.py old mode 100755 new mode 100644 similarity index 100% rename from events/matchReadyEvent.py rename to peppy/events/matchReadyEvent.py diff --git a/events/matchSkipEvent.py b/peppy/events/matchSkipEvent.py old mode 100755 new mode 100644 similarity index 100% rename from events/matchSkipEvent.py rename to peppy/events/matchSkipEvent.py diff --git a/events/matchStartEvent.py b/peppy/events/matchStartEvent.py old mode 100755 new mode 100644 similarity index 100% rename from events/matchStartEvent.py rename to peppy/events/matchStartEvent.py diff --git a/events/matchTransferHostEvent.py b/peppy/events/matchTransferHostEvent.py old mode 100755 new mode 100644 similarity index 100% rename from events/matchTransferHostEvent.py rename to peppy/events/matchTransferHostEvent.py diff --git a/events/partLobbyEvent.py b/peppy/events/partLobbyEvent.py old mode 100755 new mode 100644 similarity index 100% rename from events/partLobbyEvent.py rename to peppy/events/partLobbyEvent.py diff --git a/events/partMatchEvent.py b/peppy/events/partMatchEvent.py old mode 100755 new mode 100644 similarity index 100% rename from events/partMatchEvent.py rename to peppy/events/partMatchEvent.py diff --git a/events/requestStatusUpdateEvent.py b/peppy/events/requestStatusUpdateEvent.py old mode 100755 new mode 100644 similarity index 100% rename from events/requestStatusUpdateEvent.py rename to peppy/events/requestStatusUpdateEvent.py diff --git a/events/sendPrivateMessageEvent.py b/peppy/events/sendPrivateMessageEvent.py old mode 100755 new mode 100644 similarity index 100% rename from events/sendPrivateMessageEvent.py rename to peppy/events/sendPrivateMessageEvent.py diff --git a/events/sendPublicMessageEvent.py b/peppy/events/sendPublicMessageEvent.py old mode 100755 new mode 100644 similarity index 100% rename from events/sendPublicMessageEvent.py rename to peppy/events/sendPublicMessageEvent.py diff --git a/events/setAwayMessageEvent.py b/peppy/events/setAwayMessageEvent.py old mode 100755 new mode 100644 similarity index 100% rename from events/setAwayMessageEvent.py rename to peppy/events/setAwayMessageEvent.py diff --git a/events/spectateFramesEvent.py b/peppy/events/spectateFramesEvent.py old mode 100755 new mode 100644 similarity index 100% rename from events/spectateFramesEvent.py rename to peppy/events/spectateFramesEvent.py diff --git a/events/startSpectatingEvent.py b/peppy/events/startSpectatingEvent.py old mode 100755 new mode 100644 similarity index 100% rename from events/startSpectatingEvent.py rename to peppy/events/startSpectatingEvent.py diff --git a/events/stopSpectatingEvent.py b/peppy/events/stopSpectatingEvent.py old mode 100755 new mode 100644 similarity index 100% rename from events/stopSpectatingEvent.py rename to peppy/events/stopSpectatingEvent.py diff --git a/events/tournamentJoinMatchChannelEvent.py b/peppy/events/tournamentJoinMatchChannelEvent.py old mode 100755 new mode 100644 similarity index 100% rename from events/tournamentJoinMatchChannelEvent.py rename to peppy/events/tournamentJoinMatchChannelEvent.py diff --git a/events/tournamentLeaveMatchChannelEvent.py b/peppy/events/tournamentLeaveMatchChannelEvent.py old mode 100755 new mode 100644 similarity index 100% rename from events/tournamentLeaveMatchChannelEvent.py rename to peppy/events/tournamentLeaveMatchChannelEvent.py diff --git a/events/tournamentMatchInfoRequestEvent.py b/peppy/events/tournamentMatchInfoRequestEvent.py old mode 100755 new mode 100644 similarity index 100% rename from events/tournamentMatchInfoRequestEvent.py rename to peppy/events/tournamentMatchInfoRequestEvent.py diff --git a/events/userPanelRequestEvent.py b/peppy/events/userPanelRequestEvent.py old mode 100755 new mode 100644 similarity index 100% rename from events/userPanelRequestEvent.py rename to peppy/events/userPanelRequestEvent.py diff --git a/events/userStatsRequestEvent.py b/peppy/events/userStatsRequestEvent.py old mode 100755 new mode 100644 similarity index 100% rename from events/userStatsRequestEvent.py rename to peppy/events/userStatsRequestEvent.py diff --git a/handlers/__init__.py b/peppy/handlers/__init__.py old mode 100755 new mode 100644 similarity index 100% rename from handlers/__init__.py rename to peppy/handlers/__init__.py diff --git a/handlers/apiAerisThing.py b/peppy/handlers/apiAerisThing.py similarity index 100% rename from handlers/apiAerisThing.py rename to peppy/handlers/apiAerisThing.py diff --git a/handlers/apiOnlineUsers.py b/peppy/handlers/apiOnlineUsers.py similarity index 96% rename from handlers/apiOnlineUsers.py rename to peppy/handlers/apiOnlineUsers.py index e27abb3..6202357 100644 --- a/handlers/apiOnlineUsers.py +++ b/peppy/handlers/apiOnlineUsers.py @@ -1,28 +1,28 @@ -from __future__ import annotations - -import json - -import tornado.gen -import tornado.web - -from common.web import requestsManager -from objects import glob - - -class handler(requestsManager.asyncRequestHandler): - @tornado.web.asynchronous - @tornado.gen.engine - def asyncGet(self): - statusCode = 400 - data = {"message": "unknown error"} - try: - statusCode = 200 - data["message"] = "ok" - data["ids"] = [i.userID for i in glob.tokens.tokens.values()] - finally: - # Add status code to data - data["status"] = statusCode - - # Send response - self.write(json.dumps(data)) - self.set_status(statusCode) +from __future__ import annotations + +import json + +import tornado.gen +import tornado.web + +from common.web import requestsManager +from objects import glob + + +class handler(requestsManager.asyncRequestHandler): + @tornado.web.asynchronous + @tornado.gen.engine + def asyncGet(self): + statusCode = 400 + data = {"message": "unknown error"} + try: + statusCode = 200 + data["message"] = "ok" + data["ids"] = [i.userID for i in glob.tokens.tokens.values()] + finally: + # Add status code to data + data["status"] = statusCode + + # Send response + self.write(json.dumps(data)) + self.set_status(statusCode) diff --git a/handlers/apiOnlineUsersHandler.py b/peppy/handlers/apiOnlineUsersHandler.py old mode 100755 new mode 100644 similarity index 100% rename from handlers/apiOnlineUsersHandler.py rename to peppy/handlers/apiOnlineUsersHandler.py diff --git a/handlers/apiServerStatusHandler.py b/peppy/handlers/apiServerStatusHandler.py old mode 100755 new mode 100644 similarity index 100% rename from handlers/apiServerStatusHandler.py rename to peppy/handlers/apiServerStatusHandler.py diff --git a/handlers/api_status.py b/peppy/handlers/api_status.py similarity index 100% rename from handlers/api_status.py rename to peppy/handlers/api_status.py diff --git a/handlers/mainHandler.py b/peppy/handlers/mainHandler.py similarity index 100% rename from handlers/mainHandler.py rename to peppy/handlers/mainHandler.py diff --git a/helpers/__init__.py b/peppy/helpers/__init__.py old mode 100755 new mode 100644 similarity index 100% rename from helpers/__init__.py rename to peppy/helpers/__init__.py diff --git a/helpers/chatHelper.py b/peppy/helpers/chatHelper.py old mode 100755 new mode 100644 similarity index 100% rename from helpers/chatHelper.py rename to peppy/helpers/chatHelper.py diff --git a/helpers/consoleHelper.py b/peppy/helpers/consoleHelper.py old mode 100755 new mode 100644 similarity index 100% rename from helpers/consoleHelper.py rename to peppy/helpers/consoleHelper.py diff --git a/helpers/geo_helper.py b/peppy/helpers/geo_helper.py similarity index 100% rename from helpers/geo_helper.py rename to peppy/helpers/geo_helper.py diff --git a/helpers/packetHelper.py b/peppy/helpers/packetHelper.py similarity index 100% rename from helpers/packetHelper.py rename to peppy/helpers/packetHelper.py diff --git a/helpers/realistik_stuff.py b/peppy/helpers/realistik_stuff.py similarity index 100% rename from helpers/realistik_stuff.py rename to peppy/helpers/realistik_stuff.py diff --git a/helpers/status_helper.py b/peppy/helpers/status_helper.py similarity index 100% rename from helpers/status_helper.py rename to peppy/helpers/status_helper.py diff --git a/helpers/systemHelper.py b/peppy/helpers/systemHelper.py old mode 100755 new mode 100644 similarity index 100% rename from helpers/systemHelper.py rename to peppy/helpers/systemHelper.py diff --git a/helpers/user_helper.py b/peppy/helpers/user_helper.py similarity index 100% rename from helpers/user_helper.py rename to peppy/helpers/user_helper.py diff --git a/logger.py b/peppy/logger.py similarity index 100% rename from logger.py rename to peppy/logger.py diff --git a/main.py b/peppy/main.py similarity index 94% rename from main.py rename to peppy/main.py index 86918e5..62160c5 100644 --- a/main.py +++ b/peppy/main.py @@ -26,13 +26,13 @@ from objects import banchoConfig from objects import fokabot from objects import glob -from pubSubHandlers import banHandler -from pubSubHandlers import bot_msg_handler -from pubSubHandlers import disconnectHandler -from pubSubHandlers import notificationHandler -from pubSubHandlers import refreshPrivsHandler -from pubSubHandlers import updateSilenceHandler -from pubSubHandlers import updateStatsHandler +from redis_handlers import banHandler +from redis_handlers import bot_msg_handler +from redis_handlers import disconnectHandler +from redis_handlers import notificationHandler +from redis_handlers import refreshPrivsHandler +from redis_handlers import updateSilenceHandler +from redis_handlers import updateStatsHandler def make_app(): @@ -49,7 +49,6 @@ def make_app(): def main(): - """A main function to execute code.""" try: # Server start consoleHelper.printServerStartHeader(True) diff --git a/objects/__init__.py b/peppy/objects/__init__.py old mode 100755 new mode 100644 similarity index 100% rename from objects/__init__.py rename to peppy/objects/__init__.py diff --git a/objects/banchoConfig.py b/peppy/objects/banchoConfig.py old mode 100755 new mode 100644 similarity index 100% rename from objects/banchoConfig.py rename to peppy/objects/banchoConfig.py diff --git a/objects/channel.py b/peppy/objects/channel.py old mode 100755 new mode 100644 similarity index 100% rename from objects/channel.py rename to peppy/objects/channel.py diff --git a/objects/fokabot.py b/peppy/objects/fokabot.py similarity index 100% rename from objects/fokabot.py rename to peppy/objects/fokabot.py diff --git a/objects/glob.py b/peppy/objects/glob.py similarity index 100% rename from objects/glob.py rename to peppy/objects/glob.py diff --git a/objects/match.py b/peppy/objects/match.py old mode 100755 new mode 100644 similarity index 100% rename from objects/match.py rename to peppy/objects/match.py diff --git a/objects/osuToken.py b/peppy/objects/osuToken.py similarity index 100% rename from objects/osuToken.py rename to peppy/objects/osuToken.py diff --git a/objects/stream.py b/peppy/objects/stream.py old mode 100755 new mode 100644 similarity index 100% rename from objects/stream.py rename to peppy/objects/stream.py diff --git a/pubSubHandlers/__init__.py b/peppy/redis_handlers/__init__.py old mode 100755 new mode 100644 similarity index 100% rename from pubSubHandlers/__init__.py rename to peppy/redis_handlers/__init__.py diff --git a/pubSubHandlers/banHandler.py b/peppy/redis_handlers/banHandler.py old mode 100755 new mode 100644 similarity index 100% rename from pubSubHandlers/banHandler.py rename to peppy/redis_handlers/banHandler.py diff --git a/pubSubHandlers/bot_msg_handler.py b/peppy/redis_handlers/bot_msg_handler.py similarity index 100% rename from pubSubHandlers/bot_msg_handler.py rename to peppy/redis_handlers/bot_msg_handler.py diff --git a/pubSubHandlers/disconnectHandler.py b/peppy/redis_handlers/disconnectHandler.py old mode 100755 new mode 100644 similarity index 100% rename from pubSubHandlers/disconnectHandler.py rename to peppy/redis_handlers/disconnectHandler.py diff --git a/pubSubHandlers/notificationHandler.py b/peppy/redis_handlers/notificationHandler.py old mode 100755 new mode 100644 similarity index 100% rename from pubSubHandlers/notificationHandler.py rename to peppy/redis_handlers/notificationHandler.py diff --git a/pubSubHandlers/refreshPrivsHandler.py b/peppy/redis_handlers/refreshPrivsHandler.py similarity index 100% rename from pubSubHandlers/refreshPrivsHandler.py rename to peppy/redis_handlers/refreshPrivsHandler.py diff --git a/pubSubHandlers/updateSilenceHandler.py b/peppy/redis_handlers/updateSilenceHandler.py old mode 100755 new mode 100644 similarity index 100% rename from pubSubHandlers/updateSilenceHandler.py rename to peppy/redis_handlers/updateSilenceHandler.py diff --git a/pubSubHandlers/updateStatsHandler.py b/peppy/redis_handlers/updateStatsHandler.py old mode 100755 new mode 100644 similarity index 100% rename from pubSubHandlers/updateStatsHandler.py rename to peppy/redis_handlers/updateStatsHandler.py diff --git a/requirements/dev.txt b/requirements/dev.txt new file mode 100644 index 0000000..bae22f5 --- /dev/null +++ b/requirements/dev.txt @@ -0,0 +1,2 @@ +-r main.txt +pre-commit diff --git a/requirements.txt b/requirements/main.txt old mode 100755 new mode 100644 similarity index 100% rename from requirements.txt rename to requirements/main.txt diff --git a/bible.txt b/resources/bible.txt similarity index 100% rename from bible.txt rename to resources/bible.txt diff --git a/ip_db_2.mmdb b/resources/geolocation_database.mmdb similarity index 100% rename from ip_db_2.mmdb rename to resources/geolocation_database.mmdb From 1a8833290fc8a019c3416fbd1631c558a30d36c9 Mon Sep 17 00:00:00 2001 From: RealistikDash Date: Sat, 1 Jun 2024 00:58:57 +0100 Subject: [PATCH 05/10] refactor: use env based config --- .gitignore | 2 - peppy/collection/tokens.py | 4 +- peppy/common/db/dbConnector.py | 51 +++++++------------ peppy/common/ripple/userUtils.py | 10 ++-- peppy/common/web/requestsManager.py | 4 +- peppy/config.py | 79 ----------------------------- peppy/constants/fokabotCommands.py | 36 ++++++------- peppy/constants/serverPackets.py | 6 +-- peppy/events/loginEvent.py | 32 ++++++------ peppy/handlers/apiAerisThing.py | 6 +-- peppy/handlers/mainHandler.py | 4 +- peppy/helpers/chatHelper.py | 4 +- peppy/helpers/user_helper.py | 5 -- peppy/main.py | 41 ++++++++------- peppy/objects/channel.py | 4 +- peppy/objects/fokabot.py | 16 +++--- peppy/objects/glob.py | 8 +-- peppy/objects/match.py | 6 +-- peppy/objects/osuToken.py | 8 +-- peppy/settings.py | 40 +++++++++++++++ requirements/main.txt | 1 + 21 files changed, 153 insertions(+), 214 deletions(-) delete mode 100644 peppy/config.py create mode 100644 peppy/settings.py diff --git a/.gitignore b/.gitignore index c4c34d6..6c303cc 100755 --- a/.gitignore +++ b/.gitignore @@ -1,6 +1,5 @@ **/__pycache__ **/build -config.ini filters.txt .data .idea @@ -8,5 +7,4 @@ redistest.py *.c *.so .pyenv -config.json .vscode/ diff --git a/peppy/collection/tokens.py b/peppy/collection/tokens.py index af0c36e..b2df939 100644 --- a/peppy/collection/tokens.py +++ b/peppy/collection/tokens.py @@ -6,8 +6,8 @@ import redis +import settings from common.ripple import userUtils -from config import config from constants import serverPackets from constants.exceptions import periodicLoopException from events import logoutEvent @@ -169,7 +169,7 @@ def usersTimeoutCheckLoop(self) -> None: # Check timeout (fokabot is ignored) if ( value.pingTime < timeoutLimit - and value.userID != config.SRV_BOT_ID + and value.userID != settings.PS_BOT_USER_ID and not value.irc and not value.tournament ): diff --git a/peppy/common/db/dbConnector.py b/peppy/common/db/dbConnector.py index 36ac0d2..d7035f9 100644 --- a/peppy/common/db/dbConnector.py +++ b/peppy/common/db/dbConnector.py @@ -42,35 +42,21 @@ def __del__(self) -> None: class ConnectionPool: - """ - A MySQL workers pool - """ - - __slots__ = ( - "config", - "maxSize", - "pool", - "consecutiveEmptyPool", - ) - def __init__( self, host: str, + port: int, username: str, password: str, database: str, size: int = 128, ) -> None: - """ - Initialize a MySQL connections pool + self.host = host + self.port = port + self.username = username + self.password = password + self.database = database - :param host: MySQL host - :param username: MySQL username - :param password: MySQL password - :param database: MySQL database name - :param size: pool max size - """ - self.config = (host, username, password, database) self.maxSize = size self.pool = queue.Queue(self.maxSize) self.consecutiveEmptyPool = 0 @@ -84,7 +70,15 @@ def newWorker(self, temporary: bool = False) -> Worker: :return: instance of worker class """ db = MySQLdb.connect( - *self.config, autocommit=True, charset="utf8", use_unicode=True + host=self.host, + port=self.port, + user=self.username, + password=self.password, + database=self.database, + + autocommit=True, + charset="utf8", + use_unicode=True, ) conn = Worker(db, temporary) return conn @@ -118,7 +112,7 @@ def getWorker(self) -> Worker: if self.pool.empty(): # The pool is empty. Spawn a new temporary worker log.warning("MySQL connections pool is empty. Using temporary worker.") - worker = self.newWorker(True) + worker = self.newWorker(temporary=True) # Increment saturation self.consecutiveEmptyPool += 1 @@ -172,22 +166,13 @@ class DatabasePool: def __init__( self, host: str, + port: int, username: str, password: str, database: str, initialSize: int, ) -> None: - """ - Initialize a new MySQL database helper with multiple workers. - This class is thread safe. - - :param host: MySQL host - :param username: MySQL username - :param password: MySQL password - :param database: MySQL database name - :param initialSize: initial pool size - """ - self.pool = ConnectionPool(host, username, password, database, initialSize) + self.pool = ConnectionPool(host, port, username, password, database, initialSize) def execute(self, query: str, params: object = ()) -> int: """ diff --git a/peppy/common/ripple/userUtils.py b/peppy/common/ripple/userUtils.py index 7337fe9..309d616 100644 --- a/peppy/common/ripple/userUtils.py +++ b/peppy/common/ripple/userUtils.py @@ -12,13 +12,13 @@ from typing import Optional +import settings from common import generalUtils from common.constants import gameModes, mods from common.constants import privileges from logger import log from common.ripple import scoreUtils from objects import glob -from config import config def getBeatmapTime(beatmapID): @@ -1431,7 +1431,7 @@ def silence(userID, seconds, silenceReason, author=None): """ if author is None: - author = config.SRV_BOT_ID + author = settings.PS_BOT_USER_ID # db qurey silenceEndTime = int(time.time()) + seconds glob.db.execute( @@ -2239,7 +2239,7 @@ def insert_ban_log( """ if from_id is None: - from_id = config.SRV_BOT_ID + from_id = settings.PS_BOT_USER_ID if prefix: detail = "pep.py Autoban: " + detail @@ -2275,7 +2275,7 @@ def restrict_with_log( """ if from_id is None: - from_id = config.SRV_BOT_ID + from_id = settings.PS_BOT_USER_ID glob.db.execute( f"UPDATE users SET privileges = privileges & ~{privileges.USER_PUBLIC}, " @@ -2308,7 +2308,7 @@ def ban_with_log( """ if from_id is None: - from_id = config.SRV_BOT_ID + from_id = settings.PS_BOT_USER_ID glob.db.execute( f"UPDATE users SET privileges = 0, " diff --git a/peppy/common/web/requestsManager.py b/peppy/common/web/requestsManager.py index 71b4524..860fdc5 100644 --- a/peppy/common/web/requestsManager.py +++ b/peppy/common/web/requestsManager.py @@ -6,7 +6,7 @@ import tornado.web from tornado.ioloop import IOLoop -from config import config +import settings from logger import log from objects import glob @@ -58,7 +58,7 @@ def getRequestIP(self) -> Optional[str]: """ # Check if they are connecting through a switcher - if "ppy.sh" in self.request.headers.get("Host", "") or not config.USING_CF: + if "ppy.sh" in self.request.headers.get("Host", "") or not settings.HTTP_USING_CLOUDFLARE: return self.request.headers.get("X-Real-IP") return self.request.headers.get("CF-Connecting-IP") diff --git a/peppy/config.py b/peppy/config.py deleted file mode 100644 index 971dc5b..0000000 --- a/peppy/config.py +++ /dev/null @@ -1,79 +0,0 @@ -from __future__ import annotations - -import os -from dataclasses import dataclass -from json import dump -from json import load -from typing import Any - -from logger import log as logger # TODO: tf. - - -@dataclass -class Config: - PORT: int = 5001 - DB_HOST: str = "localhost" - DB_USERNAME: str = "root" - DB_PASSWORD: str = "lole" - DB_DATABASE: str = "rosu" - DB_WORKERS: int = 4 - REDIS_HOST: str = "localhost" - REDIS_PORT: int = 6379 - REDIS_DB: int = 0 - REDIS_PASSWORD: str = "" - THREADS_COUNT: int = 2 - NEW_RANKED_WEBHOOK: str = "" - USING_CF: bool = True - SRV_NAME: str = "RealistikOsu" - SRV_DOMAIN: str = "ussr.pl" - SRV_BOT_NAME: str = "RealistikBot" - SRV_BOT_ID: int = 999 - SRV_MIN_CLIENT_YEAR: int = 2022 - MAPS_DIRECTORY: str = "/home/realistikosu/ussr/.data/maps/" - - -def read_config_json() -> dict[str, Any]: - with open("config.json") as f: - return load(f) - - -def write_config(config: Config): - with open("config.json", "w") as f: - dump(config.__dict__, f, indent=4) - - -def load_config() -> Config: - """Loads the config from the file, handling config updates. - Note: - Raises `SystemExit` on config update. - """ - - config_dict = {} - - if os.path.exists("config.json"): - config_dict = read_config_json() - - # Compare config json attributes with config class attributes - missing_keys = [key for key in Config.__annotations__ if key not in config_dict] - - # Remove extra fields - for key in tuple( - config_dict, - ): - if key not in Config.__annotations__: - del config_dict[key] - - # Create config regardless, populating it with missing keys and removing - # unnecessary keys. - config = Config(**config_dict) - - if missing_keys: - logger.info(f"Your config has been updated with {len(missing_keys)} new keys.") - logger.debug("Missing keys: " + ", ".join(missing_keys)) - write_config(config) - raise SystemExit(0) - - return config - - -config = load_config() diff --git a/peppy/constants/fokabotCommands.py b/peppy/constants/fokabotCommands.py index f30e997..13c5d5c 100644 --- a/peppy/constants/fokabotCommands.py +++ b/peppy/constants/fokabotCommands.py @@ -18,13 +18,13 @@ from discord_webhook import DiscordEmbed from discord_webhook import DiscordWebhook +import settings from common import generalUtils from common.constants import gameModes from common.constants import mods from common.constants import privileges from common.ripple import userUtils from common.ripple.userUtils import restrict_with_log -from config import config from constants import exceptions from constants import matchModModes from constants import matchScoringTypes @@ -77,7 +77,7 @@ def refresh_bmap(md5: str) -> None: def calc_completion(bmapid, n300, n100, n50, miss): bmap = osupyparser.OsuFile( - f"{config.MAPS_DIRECTORY}{bmapid}.osu", + f"{settings.DATA_BEATMAP_DIRECTORY}/{bmapid}.osu", ).parse_file() total_hits = int(n300 + n100 + n50 + miss) @@ -298,21 +298,21 @@ def editMap(fro: str, chan: str, message: list[str]) -> str: if set_check: # In theory it should work, practically i have no fucking clue. map_name = res["song_name"].split("[")[0].strip() - beatmap_url = f"the beatmap set [https://{config.SRV_DOMAIN}/beatmaps/{token.tillerino[0]} {map_name}]" + beatmap_url = f"the beatmap set [https://{settings.PS_DOMAIN}/beatmaps/{token.tillerino[0]} {map_name}]" else: map_name = res["song_name"] - beatmap_url = f"the beatmap [https://{config.SRV_DOMAIN}/beatmaps/{token.tillerino[0]} {map_name}]" + beatmap_url = f"the beatmap [https://{settings.PS_DOMAIN}/beatmaps/{token.tillerino[0]} {map_name}]" - if config.NEW_RANKED_WEBHOOK: - webhook = DiscordWebhook(url=config.NEW_RANKED_WEBHOOK) + if settings.DISCORD_RANKED_WEBHOOK_URL: + webhook = DiscordWebhook(url=settings.DISCORD_RANKED_WEBHOOK_URL) embed = DiscordEmbed( description=f"{status_readable.title()} by {fro}", color=242424, ) embed.set_author( name=f"{map_name} was just {status_readable}", - url=f"https://{config.SRV_DOMAIN}/beatmaps/{token.tillerino[0]}", - icon_url=f"https://a.{config.SRV_DOMAIN}/{token.userID}", + url=f"https://{settings.PS_DOMAIN}/beatmaps/{token.tillerino[0]}", + icon_url=f"https://a.{settings.PS_DOMAIN}/{token.userID}", ) embed.set_footer(text="via pep.py!") embed.set_image( @@ -324,7 +324,7 @@ def editMap(fro: str, chan: str, message: list[str]) -> str: chat.sendMessage( glob.BOT_NAME, "#announce", - f"[https://{config.SRV_DOMAIN}/u/{token.userID} {fro}] has {status_readable} {beatmap_url}", + f"[https://{settings.PS_DOMAIN}/u/{token.userID} {fro}] has {status_readable} {beatmap_url}", ) return f"Successfully {status_readable} a map." @@ -455,8 +455,8 @@ def kick(fro, chan, message): def fokabotReconnect(fro, chan, message): """Forces the bot to reconnect.""" # Check if the bot is already connected - if glob.tokens.getTokenFromUserID(config.SRV_BOT_ID) is not None: - return f"{glob.BOT_NAME} is already connected to {config.SRV_NAME}!" + if glob.tokens.getTokenFromUserID(settings.PS_BOT_USER_ID) is not None: + return f"{glob.BOT_NAME} is already connected to {settings.PS_NAME}!" # Bot is not connected, connect it fokabot.connect() @@ -676,8 +676,8 @@ def freeze(fro, chan, message): if targetToken is not None: targetToken.enqueue( serverPackets.notification( - f"You have been frozen! The {config.SRV_NAME} staff team has found you " - f"suspicious and would like to request a liveplay. Visit {config.SRV_DOMAIN} for more info.", + f"You have been frozen! The {settings.PS_NAME} staff team has found you " + f"suspicious and would like to request a liveplay. Visit {settings.PS_DOMAIN} for more info.", ), ) @@ -718,7 +718,7 @@ def unfreeze(fro, chan, message): targetToken.enqueue( serverPackets.notification( "Your account has been unfrozen! You have proven your legitemacy. " - f"Thank you and have fun playing on {config.SRV_NAME}!", + f"Thank you and have fun playing on {settings.PS_NAME}!", ), ) @@ -813,7 +813,7 @@ def systemStatus(fro, chan, message): return "\n".join( ( - f"---> {config.SRV_NAME} <---", + f"---> {settings.PS_NAME} <---", " - Realtime Server -", "> Running the RealistikOsu pep.py fork.", f"> Online Users: {data['connectedUsers']}", @@ -1034,8 +1034,8 @@ def tillerinoLast(fro, chan, message): token.tillerino[2] = fc_acc oppaiData = getPPMessage(token.userID, just_data=True) - user_embed = f"[https://{config.SRV_DOMAIN}/u/{token.userID} {fro}]" - map_embed = f"[http://{config.SRV_DOMAIN}/beatmaps/{data['bid']} {data['sn']}]" + user_embed = f"[https://{settings.PS_DOMAIN}/u/{token.userID} {fro}]" + map_embed = f"[http://{settings.PS_DOMAIN}/beatmaps/{data['bid']} {data['sn']}]" response = [ f"{user_embed} | {map_embed} +{generalUtils.readableMods(data['mods'])}", @@ -1356,7 +1356,7 @@ def mpInvite(): "That user is not connected to bancho right now.", ) _match = glob.matches.matches[getMatchIDFromChannel(chan)] - _match.invite(config.SRV_BOT_ID, userID) + _match.invite(settings.PS_BOT_USER_ID, userID) token.enqueue( serverPackets.notification( f"Please accept the invite you've just received from {glob.BOT_NAME} to " diff --git a/peppy/constants/serverPackets.py b/peppy/constants/serverPackets.py index fc417d3..23be4fa 100644 --- a/peppy/constants/serverPackets.py +++ b/peppy/constants/serverPackets.py @@ -1,9 +1,9 @@ """ Contains functions used to write specific server packets to byte streams """ from __future__ import annotations +import settings from common.constants import privileges from common.ripple import userUtils -from config import config from constants import dataTypes from constants import packetIDs from constants import userRanks @@ -30,7 +30,7 @@ def force_update(): def login_banned() -> bytes: return login_reply(-1) + notification( - f"Your account has been banned from {config.SRV_NAME}! " + f"Your account has been banned from {settings.PS_NAME}! " "Please contact a member of staff for more information.", ) @@ -41,7 +41,7 @@ def login_error(): def login_cheats() -> bytes: return login_reply(-1) + notification( - f"Your account has been restricted from {config.SRV_NAME}! " + f"Your account has been restricted from {settings.PS_NAME}! " "Please contact a member of staff for more information.", ) diff --git a/peppy/events/loginEvent.py b/peppy/events/loginEvent.py index aa795f2..7b73603 100644 --- a/peppy/events/loginEvent.py +++ b/peppy/events/loginEvent.py @@ -6,10 +6,10 @@ import traceback from datetime import datetime +import settings from common.constants import privileges from common.ripple import userUtils from common.ripple.userUtils import restrict_with_log -from config import config from constants import exceptions from constants import serverPackets from helpers import chatHelper as chat @@ -24,23 +24,23 @@ UNFREEZE_NOTIF = serverPackets.notification( "Thank you for providing a liveplay! You have proven your legitemacy and " - f"have subsequently been unfrozen. Have fun playing {config.SRV_NAME}!", + f"have subsequently been unfrozen. Have fun playing {settings.PS_NAME}!", ) FREEZE_RES_NOTIF = serverPackets.notification( "Your window for liveplay sumbission has expired! Your account has been " "restricted as per our cheating policy. Please contact staff for more " - f"information on what can be done. This can be done via the {config.SRV_NAME} Discord server.", + f"information on what can be done. This can be done via the {settings.PS_NAME} Discord server.", ) FALLBACK_NOTIF = serverPackets.notification( - f"Fallback clients are not supported by {config.SRV_NAME}. This is due to a combination of missing features " - f"and server security. Please use a modern build of osu! to play {config.SRV_NAME}.", + f"Fallback clients are not supported by {settings.PS_NAME}. This is due to a combination of missing features " + f"and server security. Please use a modern build of osu! to play {settings.PS_NAME}.", ) OLD_CLIENT_NOTIF = serverPackets.notification( - f"You are using an outdated client (minimum release year {config.SRV_MIN_CLIENT_YEAR}). " - f"Please update your client to the latest version to play {config.SRV_NAME}.", + f"You are using an outdated client (minimum release year {settings.PS_MINIMUM_CLIENT_YEAR}). " + f"Please update your client to the latest version to play {settings.PS_NAME}.", ) BOT_ACCOUNT_RESPONSE = serverPackets.notification( - f"You may not log into a bot account using a real client. Please use a bot client to play {config.SRV_NAME}.", + f"You may not log into a bot account using a real client. Please use a bot client to play {settings.PS_NAME}.", ) @@ -95,7 +95,7 @@ def handle(tornadoRequest): # Invalid username log.error(f"Login failed for user {username} (user not found)!") responseData += serverPackets.notification( - f"{config.SRV_NAME}: This user does not exist!", + f"{settings.PS_NAME}: This user does not exist!", ) raise exceptions.loginFailedException() @@ -112,7 +112,7 @@ def handle(tornadoRequest): # Invalid password log.error(f"Login failed for user {username} (invalid password)!") responseData += serverPackets.notification( - f"{config.SRV_NAME}: Invalid password!", + f"{settings.PS_NAME}: Invalid password!", ) raise exceptions.loginFailedException() @@ -194,9 +194,9 @@ def handle(tornadoRequest): if frozen and not passed: responseToken.enqueue( serverPackets.notification( - f"The {config.SRV_NAME} staff team has found you suspicious and would like to request a liveplay. " + f"The {settings.PS_NAME} staff team has found you suspicious and would like to request a liveplay. " f"You have until {readabledate} (UTC) to provide a liveplay to the staff team. This can be done via " - f"the {config.SRV_NAME} Discord server. Failure to provide a valid liveplay will result in your account " + f"the {settings.PS_NAME} Discord server. Failure to provide a valid liveplay will result in your account " "being automatically restricted.", ), ) @@ -226,7 +226,7 @@ def handle(tornadoRequest): serverPackets.notification( f"Your supporter status expires in {expireIn}! Following this, you will lose your supporter privileges " "(such as the further profile customisation options, name changes or profile wipes) and will not " - f"be able to access supporter features. If you wish to keep supporting {config.SRV_NAME} and you " + f"be able to access supporter features. If you wish to keep supporting {settings.PS_NAME} and you " "don't want to lose your donor privileges, you can donate again by clicking on 'Donate' on our website.", ), ) @@ -362,7 +362,7 @@ def handle(tornadoRequest): raise exceptions.loginFailedException # Misc outdated client check - elif int(osuVersion[1:5]) < config.SRV_MIN_CLIENT_YEAR: + elif int(osuVersion[1:5]) < settings.PS_MINIMUM_CLIENT_YEAR: glob.tokens.deleteToken(userID) responseData += OLD_CLIENT_NOTIF raise exceptions.loginFailedException @@ -436,7 +436,7 @@ def handle(tornadoRequest): # Me and relesto are getting one as well lmao. UPDATE: Sky and Aochi gets it too lmao. elif userID in (1000, 1180, 3452, 4812): quote = ( - f"Hello I'm {config.SRV_BOT_NAME}! The server's official bot to assist you, " + f"Hello I'm {settings.PS_BOT_USERNAME}! The server's official bot to assist you, " "if you want to know what I can do just type !help" ) else: @@ -497,7 +497,7 @@ def handle(tornadoRequest): ) responseData += serverPackets.login_reply(-5) # Bancho error responseData += serverPackets.notification( - f"{config.SRV_NAME}: The server has experienced an error while logging you " + f"{settings.PS_NAME}: The server has experienced an error while logging you " "in! Please notify the developers for help.", ) finally: diff --git a/peppy/handlers/apiAerisThing.py b/peppy/handlers/apiAerisThing.py index 04d1125..bc53fa0 100644 --- a/peppy/handlers/apiAerisThing.py +++ b/peppy/handlers/apiAerisThing.py @@ -6,8 +6,8 @@ import tornado.gen import tornado.web +import settings from common.web import requestsManager -from config import config from objects import glob @@ -18,10 +18,10 @@ def asyncGet(self): """Handles the server info endpoint for the Aeris client.""" resp_dict = { "version": 0, - "motd": f"{config.SRV_NAME}\n" + "motd": f"{settings.PS_NAME}\n" + random.choice(glob.banchoConf.config["Quotes"]), "onlineUsers": len(glob.tokens.tokens), "icon": "https://ussr.pl/static/image/newlogo2.png", - "botID": config.SRV_BOT_ID, + "botID": settings.PS_BOT_USER_ID, } self.write(json.dumps(resp_dict)) diff --git a/peppy/handlers/mainHandler.py b/peppy/handlers/mainHandler.py index 71892af..e21aa93 100644 --- a/peppy/handlers/mainHandler.py +++ b/peppy/handlers/mainHandler.py @@ -5,6 +5,7 @@ import tornado.gen import tornado.web +import settings from logger import log from common.web import requestsManager from constants import exceptions @@ -55,7 +56,6 @@ from events import beatmapInfoRequest from helpers import packetHelper from objects import glob -from config import config # Placing this here so we do not have to register this every conn. @@ -180,7 +180,7 @@ def asyncPost(self): # Token not found. Get the user to be reconnected. responseData = serverPackets.server_restart(1) responseData += serverPackets.notification( - f"You don't seem to be logged into {config.SRV_NAME} anymore... " + f"You don't seem to be logged into {settings.PS_NAME} anymore... " "This is common during server restarts, trying to log you back in." ) log.warning("Received unknown token! This is normal during server restarts. Reconnecting them.") diff --git a/peppy/helpers/chatHelper.py b/peppy/helpers/chatHelper.py index d939a16..91d3312 100644 --- a/peppy/helpers/chatHelper.py +++ b/peppy/helpers/chatHelper.py @@ -5,8 +5,8 @@ from typing import TYPE_CHECKING from typing import Union +import settings from common.ripple import userUtils -from config import config from constants import exceptions from constants import serverPackets from events import logoutEvent @@ -348,7 +348,7 @@ def sendMessage(fro="", to="", message="", token=None, toIRC=True): log_message_db(token, recipientToken.userID, message) # Spam protection (ignore the bot) - if token.userID > config.SRV_BOT_ID or not token.admin: + if token.userID > settings.PS_BOT_USER_ID or not token.admin: token.spamProtection() # Some bot message diff --git a/peppy/helpers/user_helper.py b/peppy/helpers/user_helper.py index d2ed29c..3abdc83 100644 --- a/peppy/helpers/user_helper.py +++ b/peppy/helpers/user_helper.py @@ -1,12 +1,7 @@ from __future__ import annotations -from typing import Optional - import bcrypt -from common.constants import privileges -from common.ripple.userUtils import removeFromLeaderboard -from config import config from objects import glob diff --git a/peppy/main.py b/peppy/main.py index 62160c5..1e4ec5a 100644 --- a/peppy/main.py +++ b/peppy/main.py @@ -3,7 +3,7 @@ import os import sys import traceback -from multiprocessing.pool import ThreadPool +from concurrent.futures import ThreadPoolExecutor import redis import tornado.gen @@ -11,6 +11,7 @@ import tornado.ioloop import tornado.web +import settings from common.db import dbConnector from common.redis import pubSub from handlers import api_status @@ -65,19 +66,20 @@ def main(): try: log.info("Connecting to MySQL database... ") glob.db = dbConnector.DatabasePool( - glob.config.DB_HOST, - glob.config.DB_USERNAME, - glob.config.DB_PASSWORD, - glob.config.DB_DATABASE, - glob.config.DB_WORKERS, + host=settings.MYSQL_HOST, + port=settings.MYSQL_PORT, + username=settings.MYSQL_USER, + password=settings.MYSQL_PASSWORD, + database=settings.MYSQL_DATABASE, + initialSize=settings.MYSQL_POOL_SIZE, ) log.info("Connecting to redis... ") glob.redis = redis.Redis( - glob.config.REDIS_HOST, - glob.config.REDIS_PORT, - glob.config.REDIS_DB, - glob.config.REDIS_PASSWORD, + host=settings.REDIS_HOST, + port=settings.REDIS_PORT, + password=settings.REDIS_PASSWORD, + db=settings.REDIS_DB, ) glob.redis.ping() except Exception: @@ -118,15 +120,12 @@ def main(): glob.tokens.deleteBanchoSessions() log.info("Complete!") - # Create threads pool - try: - log.info("Creating threads pool... ") - glob.pool = ThreadPool(glob.config.THREADS_COUNT) - log.info("Complete!") - except ValueError: - log.error( - "Error while creating threads pool. Please check your config.ini and run the server again", - ) + # Create thread pool + log.info("Creating thread pool...") + glob.pool = ThreadPoolExecutor( + max_workers=settings.HTTP_THREAD_COUNT, + ) + log.info("Complete!") # Start fokabot log.info("Connecting RealistikBot...") @@ -181,7 +180,7 @@ def main(): # Server start message and console output log.info( - f"pep.py listening for HTTP(s) clients on 127.0.0.1:{glob.config.PORT}...", + f"pep.py listening for HTTP(s) clients on {settings.HTTP_ADDRESS}:{settings.HTTP_PORT}...", ) # Connect to pubsub channels @@ -206,7 +205,7 @@ def main(): } # Start tornado - glob.application.listen(port=glob.config.PORT, address="127.0.0.1") + glob.application.listen(port=settings.HTTP_PORT, address=settings.HTTP_ADDRESS) tornado.ioloop.IOLoop.instance().start() finally: system.dispose() diff --git a/peppy/objects/channel.py b/peppy/objects/channel.py index dc504b4..67861c5 100644 --- a/peppy/objects/channel.py +++ b/peppy/objects/channel.py @@ -2,7 +2,7 @@ import logging -from config import config +import settings from constants import exceptions from objects import glob @@ -28,7 +28,7 @@ def __init__(self, name, description, publicRead, publicWrite, temp, hidden): self.hidden = hidden # Make Foka join the channel - fokaToken = glob.tokens.getTokenFromUserID(config.SRV_BOT_ID) + fokaToken = glob.tokens.getTokenFromUserID(settings.PS_BOT_USER_ID) if fokaToken is not None: try: fokaToken.joinChannel(self) diff --git a/peppy/objects/fokabot.py b/peppy/objects/fokabot.py index 495c879..30c14ea 100644 --- a/peppy/objects/fokabot.py +++ b/peppy/objects/fokabot.py @@ -5,9 +5,9 @@ import traceback from importlib import reload +import settings from common.constants import actions from common.ripple import userUtils -from config import config from constants import fokabotCommands from constants import serverPackets from logger import log @@ -20,10 +20,10 @@ def connect(): :return: """ - glob.BOT_NAME = userUtils.getUsername(config.SRV_BOT_ID) - token = glob.tokens.addToken(config.SRV_BOT_ID) + glob.BOT_NAME = userUtils.getUsername(settings.PS_BOT_USER_ID) + token = glob.tokens.addToken(settings.PS_BOT_USER_ID) token.actionID = actions.WATCHING - token.actionText = f"over {config.SRV_NAME}!" + token.actionText = f"over {settings.PS_NAME}!" token.pp = 69 token.accuracy = 0.69 token.playcount = 69 @@ -31,8 +31,8 @@ def connect(): token.timeOffset = 0 token.country = 2 # this is retared, fuck it im keeping it as europe, couldnt find the uk as its ordered stupidly token.location = (39.01955903386848, 125.75276158057767) # Pyongyang red square - glob.streams.broadcast("main", serverPackets.user_presence(config.SRV_BOT_ID)) - glob.streams.broadcast("main", serverPackets.user_stats(config.SRV_BOT_ID)) + glob.streams.broadcast("main", serverPackets.user_presence(settings.PS_BOT_USER_ID)) + glob.streams.broadcast("main", serverPackets.user_stats(settings.PS_BOT_USER_ID)) def reload_commands(): @@ -46,7 +46,7 @@ def disconnect(): :return: """ - glob.tokens.deleteToken(glob.tokens.getTokenFromUserID(config.SRV_BOT_ID)) + glob.tokens.deleteToken(glob.tokens.getTokenFromUserID(settings.PS_BOT_USER_ID)) def fokabotResponse(fro, chan, message): @@ -102,7 +102,7 @@ def fokabotResponse(fro, chan, message): f"There was an issue while running '{cmd.trigger}' command. \nTraceback: {tb}", ) resp = [ - f"There was issue while processing your command, please report this to {config.SRV_NAME} developer!", + f"There was issue while processing your command, please report this to {settings.PS_NAME} developer!", ] # Debugging for staff if user.admin: diff --git a/peppy/objects/glob.py b/peppy/objects/glob.py index 4f9226c..0bdbfd0 100644 --- a/peppy/objects/glob.py +++ b/peppy/objects/glob.py @@ -2,24 +2,24 @@ from __future__ import annotations import time -from multiprocessing.pool import ThreadPool +from concurrent.futures import ThreadPoolExecutor from typing import TYPE_CHECKING from redis import Redis +import settings from collection.channels import ChannelList from collection.matches import MatchList from collection.streams import StreamList from collection.tokens import TokenList from common.db.dbConnector import DatabasePool -from config import config from objects.banchoConfig import banchoConfig if TYPE_CHECKING: from helpers.status_helper import StatusManager # Consts. -BOT_NAME = config.SRV_BOT_NAME +BOT_NAME = settings.PS_BOT_USERNAME __version__ = "3.1.0" @@ -34,7 +34,7 @@ matches = MatchList() cached_passwords: dict[str, str] = {} chatFilters = None -pool: ThreadPool +pool: ThreadPoolExecutor busyThreads = 0 debug = False diff --git a/peppy/objects/match.py b/peppy/objects/match.py index 891c2c7..327fa60 100644 --- a/peppy/objects/match.py +++ b/peppy/objects/match.py @@ -7,7 +7,7 @@ from typing import Optional from typing import TYPE_CHECKING -from config import config +import settings from constants import dataTypes from constants import matchModModes from constants import matchScoringTypes @@ -521,7 +521,7 @@ def allPlayersCompleted(self) -> None: chat.sendMessage( glob.BOT_NAME, chanName, - f"Hey! Welcome to the {config.SRV_NAME} multiplayer! If you ever encounter " + f"Hey! Welcome to the {settings.PS_NAME} multiplayer! If you ever encounter " "a map you are unable to download through our direct, you can use the " "!mirror command to get an external download link!", ) @@ -802,7 +802,7 @@ def invite(self, fro: int, to: int): return # BOT IS BUSY!!! - if to == config.SRV_BOT_ID: + if to == settings.PS_BOT_USER_ID: chat.sendMessage( glob.BOT_NAME, froToken.username, diff --git a/peppy/objects/osuToken.py b/peppy/objects/osuToken.py index 62b9ef7..d386c77 100644 --- a/peppy/objects/osuToken.py +++ b/peppy/objects/osuToken.py @@ -6,11 +6,11 @@ from typing import Optional from typing import TYPE_CHECKING +import settings from common.constants import actions from common.constants import gameModes from common.constants import privileges from common.ripple import userUtils -from config import config from constants import exceptions from constants import serverPackets from constants.rosuprivs import ADMIN_PRIVS @@ -165,7 +165,7 @@ def enqueue(self, bytes_: bytes) -> None: """ # Stop queuing stuff to the bot so we dont run out of mem - if self.userID == config.SRV_BOT_ID: + if self.userID == settings.PS_BOT_USER_ID: return with self._bufferLock: @@ -485,7 +485,7 @@ def silence(self, seconds=None, reason="", author: Optional[int] = None): """ if author is None: - author = config.SRV_BOT_ID + author = settings.PS_BOT_USER_ID if seconds is None: # Get silence expire from db if needed @@ -611,7 +611,7 @@ def notify_restricted(self) -> None: chat.sendMessage( glob.BOT_NAME, self.username, - f"Your account has been restricted! Please contact the {config.SRV_NAME} staff through our Discord server for more info!", + f"Your account has been restricted! Please contact the {settings.PS_NAME} staff through our Discord server for more info!", ) def notify_unrestricted(self) -> None: diff --git a/peppy/settings.py b/peppy/settings.py new file mode 100644 index 0000000..d124f7b --- /dev/null +++ b/peppy/settings.py @@ -0,0 +1,40 @@ +from __future__ import annotations + +import os + +from dotenv import load_dotenv + +load_dotenv() + +_BOOLEAN_STRINGS = ("true", "1", "yes") +def _parse_bool(value: str) -> bool: + return value.strip().lower() in _BOOLEAN_STRINGS + + +HTTP_PORT = int(os.environ["HTTP_PORT"]) +HTTP_ADDRESS = os.environ["HTTP_ADDRESS"] +HTTP_THREAD_COUNT = int(os.environ["HTTP_THREAD_COUNT"]) +HTTP_USING_CLOUDFLARE = _parse_bool(os.environ["HTTP_USING_CLOUDFLARE"]) + +MYSQL_HOST = os.environ["MYSQL_HOST"] +MYSQL_PORT = int(os.environ["MYSQL_PORT"]) +MYSQL_USER = os.environ["MYSQL_USER"] +MYSQL_PASSWORD = os.environ["MYSQL_PASSWORD"] +MYSQL_DATABASE = os.environ["MYSQL_DATABASE"] +MYSQL_POOL_SIZE = int(os.environ["MYSQL_POOL_SIZE"]) + +REDIS_HOST = os.environ["REDIS_HOST"] +REDIS_PORT = int(os.environ["REDIS_PORT"]) +REDIS_PASSWORD = os.environ["REDIS_PASSWORD"] +REDIS_DB = int(os.environ["REDIS_DB"]) + +DISCORD_RANKED_WEBHOOK_URL = os.environ["DISCORD_RANKED_WEBHOOK_URL"] + +# TODO: Find a better acronym to call an "osu! private server" than "PS" +PS_NAME = os.environ["PS_NAME"] +PS_DOMAIN = os.environ["PS_DOMAIN"] +PS_BOT_USERNAME = os.environ["PS_BOT_USERNAME"] +PS_BOT_USER_ID = int(os.environ["PS_BOT_USER_ID"]) +PS_MINIMUM_CLIENT_YEAR = int(os.environ["PS_MINIMUM_CLIENT_YEAR"]) + +DATA_BEATMAP_DIRECTORY = os.environ["DATA_BEATMAP_DIRECTORY"] diff --git a/requirements/main.txt b/requirements/main.txt index 949f1d6..a82df0a 100644 --- a/requirements/main.txt +++ b/requirements/main.txt @@ -4,6 +4,7 @@ discord-webhook==0.17.0 mysqlclient==2.0.3 osupyparser psutil==5.8.0 +python-dotenv==1.0.1 redis==2.10.5 requests==2.28.1 tornado==4.4.2 From d2f9b23c731b930fbc11e3c1ea5f56747a5f760d Mon Sep 17 00:00:00 2001 From: RealistikDash Date: Sat, 1 Jun 2024 01:04:34 +0100 Subject: [PATCH 06/10] add: example dotenv --- .env.example | 32 ++++++++++++++++++++++++++++++++ .gitignore | 1 + 2 files changed, 33 insertions(+) create mode 100644 .env.example diff --git a/.env.example b/.env.example new file mode 100644 index 0000000..d252125 --- /dev/null +++ b/.env.example @@ -0,0 +1,32 @@ +# HTTP Configuration +HTTP_PORT=2001 +HTTP_ADDRESS=0.0.0.0 +HTTP_THREAD_COUNT=4 +HTTP_USING_CLOUDFLARE=true + +# MySQL Database Configuration +MYSQL_HOST=localhost +MYSQL_PORT=2002 +MYSQL_USER= +MYSQL_PASSWORD= +MYSQL_DATABASE= +MYSQL_POOL_SIZE=10 + +# Redis Configuration +REDIS_HOST=localhost +REDIS_PORT=6379 +REDIS_PASSWORD= +REDIS_DB=0 + +# Discord Webhook Configuration +DISCORD_RANKED_WEBHOOK_URL= + +# osu! Private Server Configuration (PS) +PS_NAME=RealistikOsu +PS_DOMAIN=ussr.pl +PS_BOT_USERNAME=RealistikBot +PS_BOT_USER_ID=999 +PS_MINIMUM_CLIENT_YEAR=2023 + +# Data Directory Configuration +DATA_BEATMAP_DIRECTORY=/path/to/your/beatmap/directory \ No newline at end of file diff --git a/.gitignore b/.gitignore index 6c303cc..1d5dd66 100755 --- a/.gitignore +++ b/.gitignore @@ -8,3 +8,4 @@ redistest.py *.so .pyenv .vscode/ +.env From f50673051beb7904d22dd53bc7479b458cfd96be Mon Sep 17 00:00:00 2001 From: RealistikDash Date: Sat, 1 Jun 2024 01:19:17 +0100 Subject: [PATCH 07/10] add: more configurability for paths and commands --- .env.example | 6 +++++- peppy/constants/fokabotCommands.py | 7 +++++-- peppy/helpers/geo_helper.py | 4 +++- peppy/settings.py | 11 +++++++++++ 4 files changed, 24 insertions(+), 4 deletions(-) diff --git a/.env.example b/.env.example index d252125..b5c32f9 100644 --- a/.env.example +++ b/.env.example @@ -27,6 +27,10 @@ PS_DOMAIN=ussr.pl PS_BOT_USERNAME=RealistikBot PS_BOT_USER_ID=999 PS_MINIMUM_CLIENT_YEAR=2023 +PS_ENABLE_PY_COMMAND=true +PS_PY_COMMAND_WHITELIST=1000,1180 # Data Directory Configuration -DATA_BEATMAP_DIRECTORY=/path/to/your/beatmap/directory \ No newline at end of file +DATA_BEATMAP_DIRECTORY=/path/to/your/beatmap/directory +DATA_GEOLOCATION_PATH=/path/to/geoloc/db +DATA_BIBLE_PATH=/path/to/bible diff --git a/peppy/constants/fokabotCommands.py b/peppy/constants/fokabotCommands.py index 13c5d5c..19bc51a 100644 --- a/peppy/constants/fokabotCommands.py +++ b/peppy/constants/fokabotCommands.py @@ -1792,7 +1792,7 @@ def bless(fro: str, chan: str, message: str) -> str: return "This user is not online, and may not be blessed." # Acquire bible from file. - with open("bible.txt") as stream: + with open(settings.DATA_BIBLE_PATH) as stream: holy_bible = stream.read() # Split the bible into 2000 char chunks (str writer and reader limit) @@ -1854,8 +1854,11 @@ def troll(fro: str, chan: str, message: str) -> str: def py(fro: str, chan: str, message: str) -> str: """Allows for code execution inside server (DANGEROUS COMMAND)""" + if not settings.PS_ENABLE_PY_COMMAND: + return "This command has been disabled on this server." + user = glob.tokens.getTokenFromUsername(username_safe(fro), safe=True) - if not user.userID in (1000, 1180): + if not user.userID in settings.PS_PY_COMMAND_WHITELIST: return "This command is reserved for head developers only!" if not message[0]: diff --git a/peppy/helpers/geo_helper.py b/peppy/helpers/geo_helper.py index e9f48cc..dede889 100644 --- a/peppy/helpers/geo_helper.py +++ b/peppy/helpers/geo_helper.py @@ -2,7 +2,9 @@ from geoip2 import database -db_reader = database.Reader("ip_db_2.mmdb") +import settings + +db_reader = database.Reader(settings.DATA_GEOLOCATION_PATH) countryCodes = { "IO": 104, diff --git a/peppy/settings.py b/peppy/settings.py index d124f7b..0ff03b7 100644 --- a/peppy/settings.py +++ b/peppy/settings.py @@ -11,6 +11,13 @@ def _parse_bool(value: str) -> bool: return value.strip().lower() in _BOOLEAN_STRINGS +def _parse_int_list(value: str) -> list[int]: + if not value: + return [] + + return [int(i) for i in value.strip().replace(", ", ",").split(",")] + + HTTP_PORT = int(os.environ["HTTP_PORT"]) HTTP_ADDRESS = os.environ["HTTP_ADDRESS"] HTTP_THREAD_COUNT = int(os.environ["HTTP_THREAD_COUNT"]) @@ -36,5 +43,9 @@ def _parse_bool(value: str) -> bool: PS_BOT_USERNAME = os.environ["PS_BOT_USERNAME"] PS_BOT_USER_ID = int(os.environ["PS_BOT_USER_ID"]) PS_MINIMUM_CLIENT_YEAR = int(os.environ["PS_MINIMUM_CLIENT_YEAR"]) +PS_ENABLE_PY_COMMAND = _parse_bool(os.environ["PS_ENABLE_PY_COMMAND"]) +PS_PY_COMMAND_WHITELIST = _parse_int_list(os.environ) DATA_BEATMAP_DIRECTORY = os.environ["DATA_BEATMAP_DIRECTORY"] +DATA_GEOLOCATION_PATH = os.environ["DATA_GEOLOCATION_PATH"] +DATA_BIBLE_PATH = os.environ["DATA_BIBLE_PATH"] From 2bdb47eb379287ee793c9471c673a3ef28674a5a Mon Sep 17 00:00:00 2001 From: RealistikDash Date: Sat, 1 Jun 2024 01:33:00 +0100 Subject: [PATCH 08/10] add: full dockerisation --- .env.example | 3 +++ Dockerfile | 24 ++++++++++++++++++++++++ Makefile | 3 +++ scripts/await_service.sh | 30 ++++++++++++++++++++++++++++++ scripts/bootstrap.sh | 9 +++++++++ scripts/run_app.sh | 7 +++++++ 6 files changed, 76 insertions(+) create mode 100644 Dockerfile create mode 100644 Makefile create mode 100644 scripts/await_service.sh create mode 100644 scripts/bootstrap.sh create mode 100644 scripts/run_app.sh diff --git a/.env.example b/.env.example index b5c32f9..25f0f9e 100644 --- a/.env.example +++ b/.env.example @@ -34,3 +34,6 @@ PS_PY_COMMAND_WHITELIST=1000,1180 DATA_BEATMAP_DIRECTORY=/path/to/your/beatmap/directory DATA_GEOLOCATION_PATH=/path/to/geoloc/db DATA_BIBLE_PATH=/path/to/bible + +# Misc Configuration. +SERVICE_READINESS_TIMEOUT=30 diff --git a/Dockerfile b/Dockerfile new file mode 100644 index 0000000..c92e732 --- /dev/null +++ b/Dockerfile @@ -0,0 +1,24 @@ +FROM python:3.12 + +ENV PYTHONUNBUFFERED=1 + +WORKDIR /app + +# NOTE: These are handled as image resources, and therefore moved into the image. +COPY ./resources/geolocation_database.mmdb /app/resources/geolocation_database.mmdb +COPY ./resources/bible.txt /app/resources/bible.txt + +ENV DATA_GEOLOCATION_PATH=/app/resources/geolocation_database.mmdb +ENV DATA_BIBLE_PATH=/app/resources/bible.txt + +# Requirements +COPY ./requirements/main.txt /app/requirements.txt +RUN python3.12 -m pip install -r /app/requirements.txt + +# Scripts +COPY ./scripts /app/scripts + +# Application. +COPY ./peppy /app/peppy + +ENTRYPOINT [ "/app/scripts/bootstrap.sh" ] diff --git a/Makefile b/Makefile new file mode 100644 index 0000000..0bb4dd4 --- /dev/null +++ b/Makefile @@ -0,0 +1,3 @@ +#!/usr/bin/make +build: + docker build -t peppy:latest . diff --git a/scripts/await_service.sh b/scripts/await_service.sh new file mode 100644 index 0000000..c73a3a3 --- /dev/null +++ b/scripts/await_service.sh @@ -0,0 +1,30 @@ +#!/bin/bash +set -uo pipefail + +await_service() +{ + local start_ts=$(date +%s) + while [ $(date +%s) -lt $((start_ts + $3)) ]; + do + (echo -n > /dev/tcp/$1/$2) > /dev/null + if [[ $? -eq 0 ]]; then + break + fi + sleep 1 + done + local end_ts=$(date +%s) + + if [ $(date +%s) -ge $((start_ts + $3)) ]; then + echo "Timeout occurred while waiting for $1:$2 to become available" + exit 1 + fi + + echo "$1:$2 is available after $((end_ts - start_ts)) seconds" +} + +if [[ $# -ne 3 ]]; then + echo "Usage: $0 " + exit 1 +fi + +await_service $1 $2 $3 diff --git a/scripts/bootstrap.sh b/scripts/bootstrap.sh new file mode 100644 index 0000000..b09a5a1 --- /dev/null +++ b/scripts/bootstrap.sh @@ -0,0 +1,9 @@ +#!/bin/bash +set -euo pipefail + +echo "Waiting for services to become available..." + +./scripts/await_service.sh $MYSQL_HOST $MYSQL_PORT $SERVICE_READINESS_TIMEOUT +./scripts/await_service.sh $REDIS_HOST $REDIS_PORT $SERVICE_READINESS_TIMEOUT + +exec /app/scripts/run_app.sh diff --git a/scripts/run_app.sh b/scripts/run_app.sh new file mode 100644 index 0000000..e81be3a --- /dev/null +++ b/scripts/run_app.sh @@ -0,0 +1,7 @@ +#!/bin/bash +set -euo pipefail + +echo "Starting server..." + +cd /app/peppy/ +python3.12 main.py From 36a1da7022bfba727a48ff3f6ce3d53388cb445c Mon Sep 17 00:00:00 2001 From: RealistikDash Date: Sat, 1 Jun 2024 01:37:25 +0100 Subject: [PATCH 09/10] bump: all requirements versions --- peppy/main.py | 1 + peppy/settings.py | 2 +- requirements/main.txt | 16 ++++++++-------- 3 files changed, 10 insertions(+), 9 deletions(-) diff --git a/peppy/main.py b/peppy/main.py index 1e4ec5a..5b42baa 100644 --- a/peppy/main.py +++ b/peppy/main.py @@ -6,6 +6,7 @@ from concurrent.futures import ThreadPoolExecutor import redis +import redis.exceptions import tornado.gen import tornado.httpserver import tornado.ioloop diff --git a/peppy/settings.py b/peppy/settings.py index 0ff03b7..e80bf8f 100644 --- a/peppy/settings.py +++ b/peppy/settings.py @@ -44,7 +44,7 @@ def _parse_int_list(value: str) -> list[int]: PS_BOT_USER_ID = int(os.environ["PS_BOT_USER_ID"]) PS_MINIMUM_CLIENT_YEAR = int(os.environ["PS_MINIMUM_CLIENT_YEAR"]) PS_ENABLE_PY_COMMAND = _parse_bool(os.environ["PS_ENABLE_PY_COMMAND"]) -PS_PY_COMMAND_WHITELIST = _parse_int_list(os.environ) +PS_PY_COMMAND_WHITELIST = _parse_int_list(os.environ["PS_PY_COMMAND_WHITELIST"]) DATA_BEATMAP_DIRECTORY = os.environ["DATA_BEATMAP_DIRECTORY"] DATA_GEOLOCATION_PATH = os.environ["DATA_GEOLOCATION_PATH"] diff --git a/requirements/main.txt b/requirements/main.txt index a82df0a..d198587 100644 --- a/requirements/main.txt +++ b/requirements/main.txt @@ -1,10 +1,10 @@ -bcrypt==4.0.0 -colorama==0.4.5 -discord-webhook==0.17.0 -mysqlclient==2.0.3 +bcrypt==4.1.3 +colorama==0.4.6 +discord-webhook==1.3.1 +mysqlclient==2.2.4 osupyparser -psutil==5.8.0 +psutil==5.9.8 python-dotenv==1.0.1 -redis==2.10.5 -requests==2.28.1 -tornado==4.4.2 +redis==5.0.4 +requests==2.32.3 +tornado==6.4 From a168e527cdcf12335580e693878e758ff9a50f68 Mon Sep 17 00:00:00 2001 From: "pre-commit-ci[bot]" <66853113+pre-commit-ci[bot]@users.noreply.github.com> Date: Sat, 1 Jun 2024 00:41:05 +0000 Subject: [PATCH 10/10] [pre-commit.ci] auto fixes from pre-commit.com hooks for more information, see https://pre-commit.ci --- peppy/collection/tokens.py | 1 - peppy/common/db/dbConnector.py | 8 ++-- peppy/common/web/requestsManager.py | 10 ++-- peppy/constants/fokabotCommands.py | 5 +- peppy/constants/serverPackets.py | 1 - peppy/handlers/apiAerisThing.py | 3 +- peppy/handlers/apiOnlineUsers.py | 1 - peppy/handlers/apiOnlineUsersHandler.py | 1 - peppy/handlers/apiServerStatusHandler.py | 1 - peppy/handlers/api_status.py | 1 - peppy/handlers/mainHandler.py | 46 +++++++++++------- peppy/helpers/geo_helper.py | 3 +- peppy/helpers/packetHelper.py | 61 +++++++++++++++--------- peppy/helpers/systemHelper.py | 1 - peppy/helpers/user_helper.py | 1 - peppy/main.py | 4 +- peppy/objects/glob.py | 3 +- peppy/settings.py | 4 +- 18 files changed, 86 insertions(+), 69 deletions(-) diff --git a/peppy/collection/tokens.py b/peppy/collection/tokens.py index b2df939..8a5e4b5 100644 --- a/peppy/collection/tokens.py +++ b/peppy/collection/tokens.py @@ -5,7 +5,6 @@ from typing import Optional import redis - import settings from common.ripple import userUtils from constants import serverPackets diff --git a/peppy/common/db/dbConnector.py b/peppy/common/db/dbConnector.py index d7035f9..82e24fa 100644 --- a/peppy/common/db/dbConnector.py +++ b/peppy/common/db/dbConnector.py @@ -6,9 +6,8 @@ from typing import Optional import MySQLdb -from MySQLdb.connections import Connection - from logger import log +from MySQLdb.connections import Connection class Worker: @@ -75,7 +74,6 @@ def newWorker(self, temporary: bool = False) -> Worker: user=self.username, password=self.password, database=self.database, - autocommit=True, charset="utf8", use_unicode=True, @@ -172,7 +170,9 @@ def __init__( database: str, initialSize: int, ) -> None: - self.pool = ConnectionPool(host, port, username, password, database, initialSize) + self.pool = ConnectionPool( + host, port, username, password, database, initialSize, + ) def execute(self, query: str, params: object = ()) -> int: """ diff --git a/peppy/common/web/requestsManager.py b/peppy/common/web/requestsManager.py index 860fdc5..40311f3 100644 --- a/peppy/common/web/requestsManager.py +++ b/peppy/common/web/requestsManager.py @@ -2,13 +2,12 @@ from typing import Optional +import settings import tornado.gen import tornado.web -from tornado.ioloop import IOLoop - -import settings from logger import log from objects import glob +from tornado.ioloop import IOLoop class asyncRequestHandler(tornado.web.RequestHandler): @@ -58,7 +57,10 @@ def getRequestIP(self) -> Optional[str]: """ # Check if they are connecting through a switcher - if "ppy.sh" in self.request.headers.get("Host", "") or not settings.HTTP_USING_CLOUDFLARE: + if ( + "ppy.sh" in self.request.headers.get("Host", "") + or not settings.HTTP_USING_CLOUDFLARE + ): return self.request.headers.get("X-Real-IP") return self.request.headers.get("CF-Connecting-IP") diff --git a/peppy/constants/fokabotCommands.py b/peppy/constants/fokabotCommands.py index 19bc51a..27e3ed4 100644 --- a/peppy/constants/fokabotCommands.py +++ b/peppy/constants/fokabotCommands.py @@ -15,9 +15,6 @@ import osupyparser import requests -from discord_webhook import DiscordEmbed -from discord_webhook import DiscordWebhook - import settings from common import generalUtils from common.constants import gameModes @@ -32,6 +29,8 @@ from constants import matchTeamTypes from constants import serverPackets from constants import slotStatuses +from discord_webhook import DiscordEmbed +from discord_webhook import DiscordWebhook from helpers import chatHelper as chat from helpers import systemHelper from helpers import user_helper diff --git a/peppy/constants/serverPackets.py b/peppy/constants/serverPackets.py index 23be4fa..8cd05d6 100644 --- a/peppy/constants/serverPackets.py +++ b/peppy/constants/serverPackets.py @@ -174,7 +174,6 @@ def user_stats(userID): if performancePoints >= 32767: rankedScore = performancePoints performancePoints = 0 - return packetHelper.buildPacket( packetIDs.server_userStats, diff --git a/peppy/handlers/apiAerisThing.py b/peppy/handlers/apiAerisThing.py index bc53fa0..d7a60f2 100644 --- a/peppy/handlers/apiAerisThing.py +++ b/peppy/handlers/apiAerisThing.py @@ -3,10 +3,9 @@ import json import random +import settings import tornado.gen import tornado.web - -import settings from common.web import requestsManager from objects import glob diff --git a/peppy/handlers/apiOnlineUsers.py b/peppy/handlers/apiOnlineUsers.py index 6202357..951bf82 100644 --- a/peppy/handlers/apiOnlineUsers.py +++ b/peppy/handlers/apiOnlineUsers.py @@ -4,7 +4,6 @@ import tornado.gen import tornado.web - from common.web import requestsManager from objects import glob diff --git a/peppy/handlers/apiOnlineUsersHandler.py b/peppy/handlers/apiOnlineUsersHandler.py index b7a1827..eda5aea 100644 --- a/peppy/handlers/apiOnlineUsersHandler.py +++ b/peppy/handlers/apiOnlineUsersHandler.py @@ -4,7 +4,6 @@ import tornado.gen import tornado.web - from common.web import requestsManager from objects import glob diff --git a/peppy/handlers/apiServerStatusHandler.py b/peppy/handlers/apiServerStatusHandler.py index 1c52333..8325bb9 100644 --- a/peppy/handlers/apiServerStatusHandler.py +++ b/peppy/handlers/apiServerStatusHandler.py @@ -4,7 +4,6 @@ import tornado.gen import tornado.web - from common.web import requestsManager from objects import glob diff --git a/peppy/handlers/api_status.py b/peppy/handlers/api_status.py index 0e268b5..6e2025f 100644 --- a/peppy/handlers/api_status.py +++ b/peppy/handlers/api_status.py @@ -4,7 +4,6 @@ import tornado.gen import tornado.web - from common.web import requestsManager from logger import log from objects import glob diff --git a/peppy/handlers/mainHandler.py b/peppy/handlers/mainHandler.py index e21aa93..97b8521 100644 --- a/peppy/handlers/mainHandler.py +++ b/peppy/handlers/mainHandler.py @@ -1,16 +1,17 @@ +from __future__ import annotations + import datetime import sys import traceback +import settings import tornado.gen import tornado.web - -import settings -from logger import log from common.web import requestsManager from constants import exceptions from constants import packetIDs from constants import serverPackets +from events import beatmapInfoRequest from events import cantSpectateEvent from events import changeActionEvent from events import changeMatchModsEvent @@ -48,13 +49,13 @@ 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 events import beatmapInfoRequest +from events import tournamentMatchInfoRequestEvent +from events import userPanelRequestEvent +from events import userStatsRequestEvent from helpers import packetHelper +from logger import log from objects import glob # Placing this here so we do not have to register this every conn. @@ -129,7 +130,7 @@ def asyncPost(self): # Server's token string and request data responseTokenString = "" - responseData = bytes() + responseData = b'' if requestTokenString is None: # No token, first request. Handle login. @@ -157,21 +158,31 @@ def asyncPost(self): # Get packet ID, data length and data packetID = packetHelper.readPacketID(leftData) dataLength = packetHelper.readPacketLength(leftData) - packetData = requestData[pos:(pos+dataLength+7)] + packetData = requestData[pos : (pos + dataLength + 7)] # Process/ignore packet if packetID != 4: if packetID in eventHandler: - if not userToken.restricted or (userToken.restricted and packetID in packetsRestricted): + if not userToken.restricted or ( + userToken.restricted and packetID in packetsRestricted + ): eventHandler[packetID].handle(userToken, packetData) else: - log.warning("Ignored packet id from {} ({}) (user is restricted)".format(requestTokenString, packetID)) + log.warning( + "Ignored packet id from {} ({}) (user is restricted)".format( + requestTokenString, packetID, + ), + ) else: - log.warning("Unknown packet id from {} ({})".format(requestTokenString, packetID)) + log.warning( + "Unknown packet id from {} ({})".format( + requestTokenString, packetID, + ), + ) # Update pos so we can read the next stacked packet # +7 because we add packet ID bytes, unused byte and data length bytes - pos += dataLength+7 + pos += dataLength + 7 # Token queue built, send it responseTokenString = userToken.token @@ -181,9 +192,11 @@ def asyncPost(self): responseData = serverPackets.server_restart(1) responseData += serverPackets.notification( f"You don't seem to be logged into {settings.PS_NAME} anymore... " - "This is common during server restarts, trying to log you back in." + "This is common during server restarts, trying to log you back in.", + ) + log.warning( + "Received unknown token! This is normal during server restarts. Reconnecting them.", ) - log.warning("Received unknown token! This is normal during server restarts. Reconnecting them.") finally: # Unlock token if userToken is not None: @@ -198,7 +211,6 @@ def asyncPost(self): # Send server's response to client # We don't use token object because we might not have a token (failed login) - self.write(responseData) # Add all the headers AFTER the response has been written @@ -214,5 +226,5 @@ def asyncPost(self): def asyncGet(self): # We are updating this to be full stealth self.write( - """Loading site... """ + """Loading site... """, ) diff --git a/peppy/helpers/geo_helper.py b/peppy/helpers/geo_helper.py index dede889..c82e7fc 100644 --- a/peppy/helpers/geo_helper.py +++ b/peppy/helpers/geo_helper.py @@ -1,8 +1,7 @@ from __future__ import annotations -from geoip2 import database - import settings +from geoip2 import database db_reader = database.Reader(settings.DATA_GEOLOCATION_PATH) diff --git a/peppy/helpers/packetHelper.py b/peppy/helpers/packetHelper.py index d57a9ec..729f059 100644 --- a/peppy/helpers/packetHelper.py +++ b/peppy/helpers/packetHelper.py @@ -1,6 +1,10 @@ +from __future__ import annotations + import struct + from constants import dataTypes + def uleb128Encode(num: int) -> bytearray: """ Encode an int to uleb128 @@ -19,10 +23,11 @@ def uleb128Encode(num: int) -> bytearray: num >>= 7 if num != 0: arr[length] |= 128 - length+=1 + length += 1 return arr + def uleb128Decode(num: bytes) -> tuple[int, int]: """ Decode a uleb128 to int @@ -45,6 +50,7 @@ def uleb128Decode(num: bytes) -> tuple[int, int]: return value, length + def unpackData(data: bytes, dataType: int): """ Unpacks a single section of a packet. @@ -76,6 +82,7 @@ def unpackData(data: bytes, dataType: int): # Unpack return struct.unpack(unpackType, bytes(data))[0] + def packData(__data, dataType: int) -> bytes: """ Packs a single section of a packet. @@ -84,8 +91,8 @@ def packData(__data, dataType: int) -> bytes: :param dataType: data type :return: packed bytes """ - data = bytes() # data to return - pack = True # if True, use pack. False only with strings + data = b'' # data to return + pack = True # if True, use pack. False only with strings packType = "" # Get right pack Type @@ -138,7 +145,8 @@ def packData(__data, dataType: int) -> bytes: return data -def buildPacket(__packet: int, __packetData = None) -> bytes: + +def buildPacket(__packet: int, __packetData=None) -> bytes: """ Builds a packet @@ -150,9 +158,9 @@ def buildPacket(__packet: int, __packetData = None) -> bytes: if __packetData is None: __packetData = [] # Set some variables - packetData = bytes() + packetData = b'' packetLength = 0 - packetBytes = bytes() + packetBytes = b'' # Pack packet data for i in __packetData: @@ -162,12 +170,13 @@ def buildPacket(__packet: int, __packetData = None) -> bytes: packetLength = len(packetData) # Return packet as bytes - packetBytes += struct.pack(" int: """ Read packetID (first two bytes) from a packet @@ -177,6 +186,7 @@ def readPacketID(stream: bytes) -> int: """ return unpackData(stream[0:2], dataTypes.UINT16) + def readPacketLength(stream: bytes) -> int: """ Read packet data length (3:7 bytes) from a packet @@ -187,7 +197,7 @@ def readPacketLength(stream: bytes) -> int: return unpackData(stream[3:7], dataTypes.UINT32) -def readPacketData(stream: bytes, structure = None, hasFirstBytes = True): +def readPacketData(stream: bytes, structure=None, hasFirstBytes=True): """ Read packet data from `stream` according to `structure` :param stream: packet bytes @@ -221,15 +231,20 @@ def readPacketData(stream: bytes, structure = None, hasFirstBytes = True): unpack = False # Read length (uInt16) - length = unpackData(stream[start:start+2], dataTypes.UINT16) + length = unpackData(stream[start : start + 2], dataTypes.UINT16) # Read all int inside list data[i[0]] = [] - for j in range(0,length): - data[i[0]].append(unpackData(stream[start+2+(4*j):start+2+(4*(j+1))], dataTypes.SINT32)) + for j in range(0, length): + data[i[0]].append( + unpackData( + stream[start + 2 + (4 * j) : start + 2 + (4 * (j + 1))], + dataTypes.SINT32, + ), + ) # Update end - end = start+2+(4*length) + end = start + 2 + (4 * length) elif i[1] == dataTypes.STRING: # String, don't unpack unpack = False @@ -238,23 +253,23 @@ def readPacketData(stream: bytes, structure = None, hasFirstBytes = True): if stream[start] == 0: # Empty string data[i[0]] = "" - end = start+1 + end = start + 1 else: # Non empty string # Read length and calculate end - length = uleb128Decode(stream[start+1:]) - end = start+length[0]+length[1]+1 + length = uleb128Decode(stream[start + 1 :]) + end = start + length[0] + length[1] + 1 # Read bytes - data[i[0]] = stream[start+1+length[1]:end].decode() + data[i[0]] = stream[start + 1 + length[1] : end].decode() elif i[1] == dataTypes.BYTE: - end = start+1 + end = start + 1 elif i[1] in (dataTypes.UINT16, dataTypes.SINT16): - end = start+2 + end = start + 2 elif i[1] in (dataTypes.UINT32, dataTypes.SINT32, dataTypes.FFLOAT): - end = start+4 + end = start + 4 elif i[1] in (dataTypes.UINT64, dataTypes.SINT64): - end = start+8 + end = start + 8 # Unpack if needed if unpack: diff --git a/peppy/helpers/systemHelper.py b/peppy/helpers/systemHelper.py index 9dd4352..cd018cc 100644 --- a/peppy/helpers/systemHelper.py +++ b/peppy/helpers/systemHelper.py @@ -8,7 +8,6 @@ import time import psutil - from constants import serverPackets from helpers import consoleHelper from logger import log diff --git a/peppy/helpers/user_helper.py b/peppy/helpers/user_helper.py index 3abdc83..bb812d9 100644 --- a/peppy/helpers/user_helper.py +++ b/peppy/helpers/user_helper.py @@ -1,7 +1,6 @@ from __future__ import annotations import bcrypt - from objects import glob diff --git a/peppy/main.py b/peppy/main.py index 5b42baa..a1e488f 100644 --- a/peppy/main.py +++ b/peppy/main.py @@ -5,14 +5,12 @@ import traceback from concurrent.futures import ThreadPoolExecutor -import redis import redis.exceptions +import settings import tornado.gen import tornado.httpserver import tornado.ioloop import tornado.web - -import settings from common.db import dbConnector from common.redis import pubSub from handlers import api_status diff --git a/peppy/objects/glob.py b/peppy/objects/glob.py index 0bdbfd0..5422262 100644 --- a/peppy/objects/glob.py +++ b/peppy/objects/glob.py @@ -5,8 +5,6 @@ from concurrent.futures import ThreadPoolExecutor from typing import TYPE_CHECKING -from redis import Redis - import settings from collection.channels import ChannelList from collection.matches import MatchList @@ -14,6 +12,7 @@ from collection.tokens import TokenList from common.db.dbConnector import DatabasePool from objects.banchoConfig import banchoConfig +from redis import Redis if TYPE_CHECKING: from helpers.status_helper import StatusManager diff --git a/peppy/settings.py b/peppy/settings.py index e80bf8f..d21769f 100644 --- a/peppy/settings.py +++ b/peppy/settings.py @@ -7,6 +7,8 @@ load_dotenv() _BOOLEAN_STRINGS = ("true", "1", "yes") + + def _parse_bool(value: str) -> bool: return value.strip().lower() in _BOOLEAN_STRINGS @@ -14,7 +16,7 @@ def _parse_bool(value: str) -> bool: def _parse_int_list(value: str) -> list[int]: if not value: return [] - + return [int(i) for i in value.strip().replace(", ", ",").split(",")]