diff --git a/bemani/backend/danevo/danevo.py b/bemani/backend/danevo/danevo.py index 9f76000..647c82a 100644 --- a/bemani/backend/danevo/danevo.py +++ b/bemani/backend/danevo/danevo.py @@ -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 diff --git a/bemani/backend/dispatch.py b/bemani/backend/dispatch.py index b024d47..7ea0008 100644 --- a/bemani/backend/dispatch.py +++ b/bemani/backend/dispatch.py @@ -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: diff --git a/bemani/common/__init__.py b/bemani/common/__init__.py index f71c8aa..4dba980 100644 --- a/bemani/common/__init__.py +++ b/bemani/common/__init__.py @@ -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", ] diff --git a/bemani/common/decorators.py b/bemani/common/decorators.py new file mode 100644 index 0000000..4655d75 --- /dev/null +++ b/bemani/common/decorators.py @@ -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 diff --git a/bemani/data/config.py b/bemani/data/config.py index e066c08..67f4722 100644 --- a/bemani/data/config.py +++ b/bemani/data/config.py @@ -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)) diff --git a/bemani/utils/api.py b/bemani/utils/api.py index e6ac5a9..6933778 100644 --- a/bemani/utils/api.py +++ b/bemani/utils/api.py @@ -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 diff --git a/bemani/utils/frontend.py b/bemani/utils/frontend.py index 710abf9..b6d4e54 100644 --- a/bemani/utils/frontend.py +++ b/bemani/utils/frontend.py @@ -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() diff --git a/bemani/utils/proxy.py b/bemani/utils/proxy.py index 159c5b3..9892851 100644 --- a/bemani/utils/proxy.py +++ b/bemani/utils/proxy.py @@ -333,6 +333,7 @@ if __name__ == "__main__": }, }, "verbose": args.verbose, + "debug": True, "timeout": args.timeout, "keepalive": args.keepalive, } diff --git a/bemani/utils/services.py b/bemani/utils/services.py index fe0cb6b..2c4ca76 100644 --- a/bemani/utils/services.py +++ b/bemani/utils/services.py @@ -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()