Unify debug utility command line a bit, add debug mode decorator for backend.

This commit is contained in:
Jennifer Taylor
2026-08-13 00:44:55 +00:00
parent 7101afefa1
commit af1704d986
9 changed files with 50 additions and 5 deletions

View File

@@ -4,7 +4,7 @@ from typing import Any, Dict, Final, List
from bemani.backend.ess import EventLogHandler
from bemani.backend.danevo.base import DanceEvolutionBase
from bemani.common import VersionConstants, Profile, CardCipher, Time
from bemani.common import VersionConstants, Profile, CardCipher, Time, debugonly
from bemani.protocol import Node
@@ -167,6 +167,7 @@ class DanceEvolution(
return root
@debugonly
def handle_playerdata_usergamedata_recvscores_request(self, request: Node) -> Node:
# NOTE: This is an entirely made up endpoint. The game does not call it. This exists
# entirely to allow for client integration tests (trafficgen) to verify score saving

View File

@@ -20,7 +20,7 @@ class Dispatch:
class and then returning a response.
"""
def __init__(self, config: Config, data: Data, verbose: bool) -> None:
def __init__(self, config: Config, data: Data) -> None:
"""
Initialize the Dispatch object.
@@ -29,7 +29,8 @@ class Dispatch:
data - A Data singleton for DB access.
verbose - Whether we get chatty to stdout or not.
"""
self.__verbose = verbose
self.__verbose = config.verbose
self.__debug = config.debug
self.__data = data
self.__config = config
@@ -144,6 +145,9 @@ class Dispatch:
# First, try to handle with specific service/method function
try:
handler = getattr(game, f"handle_{request.name}_{method}_request")
if not self.__debug and getattr(handler, "__debug_only__", False):
# This is a debug-only endpoint, and we're in production mode.
handler = None
except AttributeError:
handler = None
if handler is not None:
@@ -153,6 +157,9 @@ class Dispatch:
# Now, try to pass it off to a generic service handler
try:
handler = getattr(game, f"handle_{request.name}_requests")
if not self.__debug and getattr(handler, "__debug_only__", False):
# This is a debug-only endpoint, and we're in production mode.
handler = None
except AttributeError:
handler = None
if handler is not None:

View File

@@ -10,6 +10,7 @@ from bemani.common.constants import (
RegionConstants,
)
from bemani.common.card import CardCipher, CardCipherException
from bemani.common.decorators import debugonly
from bemani.common.id import ID
from bemani.common.aes import AESCipher
from bemani.common.time import Time
@@ -39,4 +40,5 @@ __all__ = [
"PEFile",
"InvalidOffsetException",
"cache",
"debugonly",
]

View File

@@ -0,0 +1,14 @@
from typing import TypeVar
T = TypeVar('T')
def debugonly(func: T) -> T:
"""
A decorator that can be added to any handler function in a game backend
which will make it not possible to call in production mode, which is
when running this through uWSGI or another WSGI application.
"""
setattr(func, "__debug_only__", True)
return func

View File

@@ -244,3 +244,11 @@ class Config(dict):
def event_log_duration(self) -> Optional[int]:
duration = self.get("event_log_duration")
return int(duration) if duration else None
@property
def verbose(self) -> bool:
return bool(self.get("verbose", False))
@property
def debug(self) -> bool:
return bool(self.get("debug", False))

View File

@@ -40,6 +40,7 @@ def main() -> None:
action="store_true",
help="Force the database into read-only mode.",
)
parser.add_argument("-v", "--verbose", help="Display verbose API info.", action="store_true")
args = parser.parse_args()
# Set up app
@@ -47,6 +48,10 @@ def main() -> None:
if args.read_only:
config["database"]["read_only"] = True
# Force full verbose output when running as a debug app.
config["verbose"] = args.verbose
config["debug"] = True
if args.profile:
from werkzeug.middleware.profiler import ProfilerMiddleware

View File

@@ -87,6 +87,7 @@ def main() -> None:
action="store_true",
help="Force the database into read-only mode.",
)
parser.add_argument("-v", "--verbose", help="Display verbose client info.", action="store_true")
args = parser.parse_args()
# Set up app
@@ -94,6 +95,10 @@ def main() -> None:
if args.read_only:
config["database"]["read_only"] = True
# Force full verbose output when running as a debug app.
config["verbose"] = args.verbose
config["debug"] = True
# Register all blueprints
register_blueprints()

View File

@@ -333,6 +333,7 @@ if __name__ == "__main__":
},
},
"verbose": args.verbose,
"debug": True,
"timeout": args.timeout,
"keepalive": args.keepalive,
}

View File

@@ -58,7 +58,7 @@ def receive_request(path: str) -> Response:
dataprovider = Data(requestconfig)
try:
dispatch = Dispatch(requestconfig, dataprovider, config["verbose"])
dispatch = Dispatch(requestconfig, dataprovider)
resp = dispatch.handle(req)
if resp is None:
@@ -149,6 +149,7 @@ if __name__ == "__main__":
action="store_true",
help="Force the database into read-only mode.",
)
parser.add_argument("-q", "--quiet", help="Do not display verbose packet info.", action="store_true")
args = parser.parse_args()
# Set up global configuration, overriding config port for convenience in debugging.
@@ -158,7 +159,8 @@ if __name__ == "__main__":
config["database"]["read_only"] = True
# Force full verbose output when running as a debug app.
config["verbose"] = True
config["verbose"] = not args.quiet
config["debug"] = True
# Register game handlers
register_games()