artemis/titles/cm/index.py
2024-03-23 00:22:07 +08:00

139 lines
4.6 KiB
Python

import json
import logging
import string
import zlib
from logging.handlers import TimedRotatingFileHandler
from os import path
from typing import List
import coloredlogs
import inflection
import yaml
from core.config import CoreConfig
from core.title import BaseServlet
from core.utils import Utils
from starlette.requests import Request
from starlette.responses import Response
from starlette.routing import Route
from .base import CardMakerBase
from .cm135 import CardMaker135
from .config import CardMakerConfig
from .const import CardMakerConstants
class CardMakerServlet(BaseServlet):
def __init__(self, core_cfg: CoreConfig, cfg_dir: str) -> None:
super().__init__(core_cfg, cfg_dir)
self.game_cfg = CardMakerConfig()
if path.exists(f"{cfg_dir}/{CardMakerConstants.CONFIG_NAME}"):
self.game_cfg.update(
yaml.safe_load(open(f"{cfg_dir}/{CardMakerConstants.CONFIG_NAME}"))
)
self.versions = [
CardMakerBase(core_cfg, self.game_cfg),
CardMaker135(core_cfg, self.game_cfg),
]
self.logger = logging.getLogger("cardmaker")
log_fmt_str = "[%(asctime)s] Card Maker | %(levelname)s | %(message)s"
log_fmt = logging.Formatter(log_fmt_str)
fileHandler = TimedRotatingFileHandler(
"{0}/{1}.log".format(self.core_cfg.server.log_dir, "cardmaker"),
encoding="utf8",
when="d",
backupCount=10,
)
fileHandler.setFormatter(log_fmt)
consoleHandler = logging.StreamHandler()
consoleHandler.setFormatter(log_fmt)
self.logger.addHandler(fileHandler)
self.logger.addHandler(consoleHandler)
self.logger.setLevel(self.game_cfg.server.loglevel)
coloredlogs.install(
level=self.game_cfg.server.loglevel, logger=self.logger, fmt=log_fmt_str
)
@classmethod
def is_game_enabled(
cls, game_code: str, core_cfg: CoreConfig, cfg_dir: str
) -> bool:
game_cfg = CardMakerConfig()
if path.exists(f"{cfg_dir}/{CardMakerConstants.CONFIG_NAME}"):
game_cfg.update(
yaml.safe_load(open(f"{cfg_dir}/{CardMakerConstants.CONFIG_NAME}"))
)
if not game_cfg.server.enable:
return False
return True
def get_routes(self) -> List[Route]:
return [
Route(
"/SDED/{version:int}/{endpoint:str}", self.render_POST, methods=["POST"]
)
]
async def render_POST(self, request: Request) -> bytes:
version: int = request.path_params.get("version")
endpoint: str = request.path_params.get("endpoint")
req_raw = await request.body()
internal_ver = 0
client_ip = Utils.get_ip_addr(request)
if version >= 130 and version < 135: # Card Maker
internal_ver = CardMakerConstants.VER_CARD_MAKER
elif version >= 135 and version < 140: # Card Maker 1.35
internal_ver = CardMakerConstants.VER_CARD_MAKER_135
if all(c in string.hexdigits for c in endpoint) and len(endpoint) == 32:
# If we get a 32 character long hex string, it's a hash and we're
# doing encrypted. The likelyhood of false positives is low but
# technically not 0
self.logger.error("Encryption not supported at this time")
try:
unzip = zlib.decompress(req_raw)
except zlib.error as e:
self.logger.error(
f"Failed to decompress v{version} {endpoint} request -> {e}"
)
return Response(zlib.compress(b'{"stat": "0"}'))
req_data = json.loads(unzip)
self.logger.info(f"v{version} {endpoint} request from {client_ip}")
self.logger.debug(req_data)
func_to_find = "handle_" + inflection.underscore(endpoint) + "_request"
if not hasattr(self.versions[internal_ver], func_to_find):
self.logger.warning(f"Unhandled v{version} request {endpoint}")
return Response(zlib.compress(b'{"returnCode": 1}'))
try:
handler = getattr(self.versions[internal_ver], func_to_find)
resp = await handler(req_data)
except Exception as e:
self.logger.error(f"Error handling v{version} method {endpoint} - {e}")
raise
return Response(zlib.compress(b'{"stat": "0"}'))
if resp is None:
resp = {"returnCode": 1}
self.logger.debug(f"Response {resp}")
return Response(
zlib.compress(json.dumps(resp, ensure_ascii=False).encode("utf-8"))
)