3
2
forked from Dniel97/artemis
artemis/titles/mai2/index.py

262 lines
10 KiB
Python
Raw Normal View History

from twisted.web.http import Request
2023-05-13 02:05:05 +00:00
from twisted.web.server import NOT_DONE_YET
import json
import inflection
import yaml
import string
import logging, coloredlogs
import zlib
from logging.handlers import TimedRotatingFileHandler
from os import path, mkdir
from typing import Tuple
from core.config import CoreConfig
2023-04-10 16:58:19 +00:00
from core.utils import Utils
from titles.mai2.config import Mai2Config
from titles.mai2.const import Mai2Constants
from titles.mai2.base import Mai2Base
2023-05-01 02:19:31 +00:00
from titles.mai2.finale import Mai2Finale
from titles.mai2.dx import Mai2DX
from titles.mai2.dxplus import Mai2DXPlus
from titles.mai2.splash import Mai2Splash
from titles.mai2.splashplus import Mai2SplashPlus
from titles.mai2.universe import Mai2Universe
from titles.mai2.universeplus import Mai2UniversePlus
2023-04-10 16:58:19 +00:00
from titles.mai2.festival import Mai2Festival
2023-03-09 16:38:58 +00:00
class Mai2Servlet:
def __init__(self, core_cfg: CoreConfig, cfg_dir: str) -> None:
self.core_cfg = core_cfg
self.game_cfg = Mai2Config()
if path.exists(f"{cfg_dir}/{Mai2Constants.CONFIG_NAME}"):
2023-03-09 16:38:58 +00:00
self.game_cfg.update(
yaml.safe_load(open(f"{cfg_dir}/{Mai2Constants.CONFIG_NAME}"))
)
self.versions = [
2023-05-01 02:19:31 +00:00
Mai2Base,
None,
None,
None,
None,
None,
None,
None,
None,
None,
None,
None,
2023-05-06 23:04:10 +00:00
Mai2Finale,
Mai2DX,
Mai2DXPlus,
Mai2Splash,
Mai2SplashPlus,
Mai2Universe,
Mai2UniversePlus,
Mai2Festival,
2023-05-01 02:19:31 +00:00
]
self.logger = logging.getLogger("mai2")
2023-05-03 07:25:29 +00:00
if not hasattr(self.logger, "initted"):
log_fmt_str = "[%(asctime)s] Mai2 | %(levelname)s | %(message)s"
log_fmt = logging.Formatter(log_fmt_str)
fileHandler = TimedRotatingFileHandler(
"{0}/{1}.log".format(self.core_cfg.server.log_dir, "mai2"),
encoding="utf8",
when="d",
backupCount=10,
)
2023-05-03 07:25:29 +00:00
fileHandler.setFormatter(log_fmt)
2023-03-09 16:38:58 +00:00
2023-05-03 07:25:29 +00:00
consoleHandler = logging.StreamHandler()
consoleHandler.setFormatter(log_fmt)
2023-05-03 07:25:29 +00:00
self.logger.addHandler(fileHandler)
self.logger.addHandler(consoleHandler)
2023-03-09 16:38:58 +00:00
2023-05-03 07:25:29 +00:00
self.logger.setLevel(self.game_cfg.server.loglevel)
coloredlogs.install(
level=self.game_cfg.server.loglevel, logger=self.logger, fmt=log_fmt_str
)
self.logger.initted = True
@classmethod
2023-03-09 16:38:58 +00:00
def get_allnet_info(
cls, game_code: str, core_cfg: CoreConfig, cfg_dir: str
) -> Tuple[bool, str, str]:
game_cfg = Mai2Config()
if path.exists(f"{cfg_dir}/{Mai2Constants.CONFIG_NAME}"):
2023-03-09 16:38:58 +00:00
game_cfg.update(
yaml.safe_load(open(f"{cfg_dir}/{Mai2Constants.CONFIG_NAME}"))
)
if not game_cfg.server.enable:
return (False, "", "")
2023-03-09 16:38:58 +00:00
if core_cfg.server.is_develop:
2023-03-09 16:38:58 +00:00
return (
True,
f"http://{core_cfg.title.hostname}:{core_cfg.title.port}/{game_code}/$v/",
2023-05-09 07:53:31 +00:00
f"{core_cfg.title.hostname}",
2023-03-09 16:38:58 +00:00
)
return (
True,
f"http://{core_cfg.title.hostname}/{game_code}/$v/",
2023-05-03 07:25:29 +00:00
f"{core_cfg.title.hostname}",
2023-03-09 16:38:58 +00:00
)
def setup(self):
if self.game_cfg.uploads.photos and self.game_cfg.uploads.photos_dir and not path.exists(self.game_cfg.uploads.photos_dir):
try:
mkdir(self.game_cfg.uploads.photos_dir)
2023-07-16 20:58:34 +00:00
except Exception:
self.logger.error(f"Failed to make photo upload directory at {self.game_cfg.uploads.photos_dir}")
if self.game_cfg.uploads.movies and self.game_cfg.uploads.movies_dir and not path.exists(self.game_cfg.uploads.movies_dir):
try:
mkdir(self.game_cfg.uploads.movies_dir)
2023-07-16 20:58:34 +00:00
except Exception:
self.logger.error(f"Failed to make movie upload directory at {self.game_cfg.uploads.movies_dir}")
def render_POST(self, request: Request, version: int, url_path: str) -> bytes:
if url_path.lower() == "ping":
return zlib.compress(b'{"returnCode": "1"}')
2023-06-25 22:43:00 +00:00
2023-06-25 23:10:34 +00:00
elif url_path.startswith("api/movie/"):
2023-06-25 22:43:00 +00:00
self.logger.info(f"Movie data: {url_path} - {request.content.getvalue()}")
return b""
req_raw = request.content.getvalue()
url = request.uri.decode()
url_split = url_path.split("/")
internal_ver = 0
endpoint = url_split[len(url_split) - 1]
2023-04-10 16:58:19 +00:00
client_ip = Utils.get_ip_addr(request)
2023-05-06 23:04:10 +00:00
if request.uri.startswith(b"/SDEZ"):
2023-05-03 07:25:29 +00:00
if version < 105: # 1.0
internal_ver = Mai2Constants.VER_MAIMAI_DX
elif version >= 105 and version < 110: # Plus
internal_ver = Mai2Constants.VER_MAIMAI_DX_PLUS
elif version >= 110 and version < 115: # Splash
internal_ver = Mai2Constants.VER_MAIMAI_DX_SPLASH
elif version >= 115 and version < 120: # Splash Plus
internal_ver = Mai2Constants.VER_MAIMAI_DX_SPLASH_PLUS
elif version >= 120 and version < 125: # Universe
internal_ver = Mai2Constants.VER_MAIMAI_DX_UNIVERSE
elif version >= 125 and version < 130: # Universe Plus
internal_ver = Mai2Constants.VER_MAIMAI_DX_UNIVERSE_PLUS
elif version >= 130: # Festival
internal_ver = Mai2Constants.VER_MAIMAI_DX_FESTIVAL
2023-05-03 07:25:29 +00:00
else:
if version < 110: # 1.0
internal_ver = Mai2Constants.VER_MAIMAI
elif version >= 110 and version < 120: # Plus
internal_ver = Mai2Constants.VER_MAIMAI_PLUS
elif version >= 120 and version < 130: # Green
internal_ver = Mai2Constants.VER_MAIMAI_GREEN
2023-05-05 00:12:31 +00:00
elif version >= 130 and version < 140: # Green Plus
2023-05-03 07:25:29 +00:00
internal_ver = Mai2Constants.VER_MAIMAI_GREEN_PLUS
elif version >= 140 and version < 150: # Orange
internal_ver = Mai2Constants.VER_MAIMAI_ORANGE
2023-05-05 00:12:31 +00:00
elif version >= 150 and version < 160: # Orange Plus
2023-05-03 07:25:29 +00:00
internal_ver = Mai2Constants.VER_MAIMAI_ORANGE_PLUS
elif version >= 160 and version < 170: # Pink
internal_ver = Mai2Constants.VER_MAIMAI_PINK
2023-05-05 00:12:31 +00:00
elif version >= 170 and version < 180: # Pink Plus
2023-05-03 07:25:29 +00:00
internal_ver = Mai2Constants.VER_MAIMAI_PINK_PLUS
elif version >= 180 and version < 185: # Murasaki
internal_ver = Mai2Constants.VER_MAIMAI_MURASAKI
2023-05-05 00:12:31 +00:00
elif version >= 185 and version < 190: # Murasaki Plus
2023-05-03 07:25:29 +00:00
internal_ver = Mai2Constants.VER_MAIMAI_MURASAKI_PLUS
elif version >= 190 and version < 195: # Milk
internal_ver = Mai2Constants.VER_MAIMAI_MILK
2023-05-05 00:12:31 +00:00
elif version >= 195 and version < 197: # Milk Plus
2023-05-03 07:25:29 +00:00
internal_ver = Mai2Constants.VER_MAIMAI_MILK_PLUS
elif version >= 197: # Finale
internal_ver = Mai2Constants.VER_MAIMAI_FINALE
if all(c in string.hexdigits for c in endpoint) and len(endpoint) == 32:
2023-03-09 16:38:58 +00:00
# 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")
2023-03-09 16:38:58 +00:00
try:
unzip = zlib.decompress(req_raw)
2023-03-09 16:38:58 +00:00
except zlib.error as e:
2023-03-09 16:38:58 +00:00
self.logger.error(
f"Failed to decompress v{version} {endpoint} request -> {e}"
)
return zlib.compress(b'{"stat": "0"}')
2023-03-09 16:38:58 +00:00
req_data = json.loads(unzip)
2023-03-09 16:38:58 +00:00
self.logger.info(f"v{version} {endpoint} request from {client_ip}")
2023-04-10 16:58:19 +00:00
self.logger.debug(req_data)
func_to_find = "handle_" + inflection.underscore(endpoint) + "_request"
2023-05-06 23:04:10 +00:00
handler_cls = self.versions[internal_ver](self.core_cfg, self.game_cfg)
2023-04-10 16:58:19 +00:00
if not hasattr(handler_cls, func_to_find):
self.logger.warning(f"Unhandled v{version} request {endpoint}")
2023-04-10 16:58:19 +00:00
resp = {"returnCode": 1}
2023-04-10 16:58:19 +00:00
else:
try:
handler = getattr(handler_cls, func_to_find)
resp = handler(req_data)
2023-04-10 16:58:19 +00:00
except Exception as e:
self.logger.error(f"Error handling v{version} method {endpoint} - {e}")
return zlib.compress(b'{"stat": "0"}')
2023-03-09 16:38:58 +00:00
if resp == None:
2023-03-09 16:38:58 +00:00
resp = {"returnCode": 1}
2023-04-10 16:58:19 +00:00
self.logger.debug(f"Response {resp}")
2023-03-09 16:38:58 +00:00
return zlib.compress(json.dumps(resp, ensure_ascii=False).encode("utf-8"))
2023-05-06 23:04:10 +00:00
def render_GET(self, request: Request, version: int, url_path: str) -> bytes:
2023-05-10 06:31:30 +00:00
self.logger.info(f"v{version} GET {url_path}")
url_split = url_path.split("/")
2023-06-25 23:10:34 +00:00
if (url_split[0] == "api" and url_split[1] == "movie") or url_split[0] == "movie":
if url_split[2] == "moviestart":
2023-06-25 22:43:00 +00:00
return json.dumps({"moviestart":{"status":"OK"}}).encode()
2023-05-10 06:31:30 +00:00
if url_split[0] == "old":
if url_split[1] == "ping":
self.logger.info(f"v{version} old server ping")
return zlib.compress(b"ok")
elif url_split[1].startswith("userdata"):
self.logger.info(f"v{version} old server userdata inquire")
return zlib.compress(b"{}")
elif url_split[1].startswith("friend"):
self.logger.info(f"v{version} old server friend inquire")
return zlib.compress(b"{}")
elif url_split[0] == "usbdl":
if url_split[1] == "CONNECTIONTEST":
self.logger.info(f"v{version} usbdl server test")
return zlib.compress(b"ok")
elif url_split[0] == "deliver":
2023-05-13 02:05:05 +00:00
file = url_split[len(url_split) - 1]
self.logger.info(f"v{version} {file} deliver inquire")
if not self.game_cfg.deliver.enable or not path.exists(f"{self.game_cfg.deliver.content_folder}/{file}"):
2023-05-10 06:31:30 +00:00
return zlib.compress(b"")
2023-05-06 23:04:10 +00:00
else:
2023-05-10 06:31:30 +00:00
return zlib.compress(b"{}")