From 08b57088b069de6a9aa513f14d9cba330c35e789 Mon Sep 17 00:00:00 2001 From: drmext <71258889+drmext@users.noreply.github.com> Date: Sat, 23 Sep 2023 09:25:52 +0000 Subject: [PATCH] URL Slash 0 (Off) and 0.0.0.0 --- README.md | 8 +-- modules/__init__.py | 64 ++++++++++++++++++++++++ modules/ddr/playerdata.py | 6 +-- modules/ddr/playerdata_2.py | 6 +-- modules/iidx/iidx30gamesystem.py | 2 +- modules/iidx/iidx30pc.py | 5 +- pyeamu.py | 83 +++++++++++++++++++++++--------- 7 files changed, 139 insertions(+), 35 deletions(-) diff --git a/README.md b/README.md index 978fd94..8ca2af9 100644 --- a/README.md +++ b/README.md @@ -4,15 +4,15 @@ e-amusement server using [FastAPI](https://github.com/tiangolo/fastapi) and [Tin for experimental local testing and playing -**don't host it publicly as-is** +**don't host it publicly as-is. security and privacy features aren't implemented. tinydb can't handle many users.** ## Instructions -1. Install [python](https://www.python.org/ftp/python/3.11.4/python-3.11.4-amd64.exe) with "Add python.exe to PATH" checked +1. Install [python](https://www.python.org/ftp/python/3.11.5/python-3.11.5-amd64.exe) with "Add python.exe to PATH" checked 1. Run [start.bat (Windows)](start.bat) or [start.sh (Linux)](start.sh) -1. Edit prop/ea3-config.xml services *url* and url_slash *1* +1. Set services *url* in tools or prop/ea3-config.xml ## Playable Games @@ -39,7 +39,7 @@ for experimental local testing and playing ## Troubleshooting -- **URL Slash 1 (On)** must be enabled in tools or ea3-config +- Set **URL Slash 1 (On)** in tools or ea3-config [if a supported game breaks without it](modules/__init__.py#L44) - GITADORA requires `mdb_*.xml` copied to the server folder diff --git a/modules/__init__.py b/modules/__init__.py index 0553b9e..d0dbeab 100644 --- a/modules/__init__.py +++ b/modules/__init__.py @@ -2,6 +2,9 @@ from importlib import util from os import path from glob import glob +from fastapi import APIRouter, Request +from typing import Optional + routers = [] for module_path in [ f @@ -15,3 +18,64 @@ for module_path in [ router = getattr(module, "router", None) if router is not None: routers.append(router) + + if path.basename(module_path) != "api.py": + for obj in dir(module): + globals()[obj] = module.__dict__[obj] + +router = APIRouter(tags=["slashless_forwarder"]) + + +@router.post("/core_fwdr") +async def forward_core( + request: Request, + f: Optional[str] = None, + module: Optional[str] = None, + method: Optional[str] = None, +): + if f != None: + module, method = f.split(".") + + find_response = globals()[f"{module}_{method}"] + + return await find_response(request) + + +@router.post("/fwdr") +async def forward_game( + request: Request, + model: Optional[str] = None, + f: Optional[str] = None, + module: Optional[str] = None, + method: Optional[str] = None, +): + if f != None: + module, method = f.split(".") + + game_code = model.split(":")[0] + + # TODO: check for more edge cases + try: + if game_code == "MDX" and module == "eventlog" or module == "eventlog_2": + find_response = globals()[f"ddr_{module}_{method}"] + elif game_code == "REC": + find_response = globals()[f"drs_{module}_{method}"] + elif game_code == "KFC" and module == "eventlog": + find_response = globals()[f"sdvx_{module}_{method}"] + elif game_code == "M32": + if module == "lobby": + find_response = globals()[f"gitadora_{module}_{method}"] + else: + gd_module = module.split("_") + find_response = globals()[f"gitadora_{gd_module[-1]}_{method}"] + return await find_response(gd_module[0], request) + else: + find_response = globals()[f"{module}_{method}".lower()] + except KeyError: + print("Try URL Slash 1 (On) if this game is supported.") + return Response(status_code=404) + + return await find_response(request) + + +routers.append(router) diff --git a/modules/ddr/playerdata.py b/modules/ddr/playerdata.py index 94668e8..083f577 100644 --- a/modules/ddr/playerdata.py +++ b/modules/ddr/playerdata.py @@ -35,7 +35,7 @@ def get_common(ddr_id, game_version, idx): @router.post("/{gameinfo}/playerdata/usergamedata_advanced") -async def usergamedata_advanced(request: Request): +async def playerdata_usergamedata_advanced(request: Request): request_info = await core_process_request(request) game_version = request_info["game_version"] is_omni = True if request_info["rev"] == "O" else False @@ -541,7 +541,7 @@ async def usergamedata_advanced(request: Request): @router.post("/{gameinfo}/playerdata/usergamedata_recv") -async def usergamedata_recv(request: Request): +async def playerdata_usergamedata_recv(request: Request): request_info = await core_process_request(request) game_version = request_info["game_version"] @@ -651,7 +651,7 @@ async def usergamedata_recv(request: Request): @router.post("/{gameinfo}/playerdata/usergamedata_send") -async def usergamedata_send(request: Request): +async def playerdata_usergamedata_send(request: Request): request_info = await core_process_request(request) game_version = request_info["game_version"] diff --git a/modules/ddr/playerdata_2.py b/modules/ddr/playerdata_2.py index 383cd82..dfcb2a5 100644 --- a/modules/ddr/playerdata_2.py +++ b/modules/ddr/playerdata_2.py @@ -35,7 +35,7 @@ def get_common(ddr_id, game_version, idx): @router.post("/{gameinfo}/playerdata_2/usergamedata_advanced") -async def usergamedata_advanced(request: Request): +async def playerdata_2_usergamedata_advanced(request: Request): request_info = await core_process_request(request) game_version = request_info["game_version"] is_omni = True if request_info["rev"] == "O" else False @@ -578,7 +578,7 @@ async def usergamedata_advanced(request: Request): @router.post("/{gameinfo}/playerdata_2/usergamedata_recv") -async def usergamedata_recv(request: Request): +async def playerdata_2_usergamedata_recv(request: Request): request_info = await core_process_request(request) game_version = request_info["game_version"] @@ -688,7 +688,7 @@ async def usergamedata_recv(request: Request): @router.post("/{gameinfo}/playerdata_2/usergamedata_send") -async def usergamedata_send(request: Request): +async def playerdata_2_usergamedata_send(request: Request): request_info = await core_process_request(request) game_version = request_info["game_version"] diff --git a/modules/iidx/iidx30gamesystem.py b/modules/iidx/iidx30gamesystem.py index 1077fa5..190b81a 100644 --- a/modules/iidx/iidx30gamesystem.py +++ b/modules/iidx/iidx30gamesystem.py @@ -17,7 +17,7 @@ async def iidx30gamesystem_systeminfo(request: Request): unlock = () # force unlock LM exclusives to complete unlock all songs server side # this makes LM exclusive folder disappear, so just use hex edits - # unlock = (28073, 28008, 29095, 29094, 29027, 30077, 30076, 30098) + # unlock = (28073, 28008, 29095, 29094, 29027, 30077, 30076, 30098, 30106, 30107, 30028, 30064, 30027) current_time = round(time()) diff --git a/modules/iidx/iidx30pc.py b/modules/iidx/iidx30pc.py index 1ce7aac..c3f6c90 100644 --- a/modules/iidx/iidx30pc.py +++ b/modules/iidx/iidx30pc.py @@ -274,7 +274,7 @@ async def iidx30pc_get(request: Request): tour_id=i, progress=50, # set to 49 to see WT folders, 50 is completed/hidden ) - for i in range(13) + for i in range(16) ], ), E.lightning_setting( @@ -433,6 +433,8 @@ async def iidx30pc_get(request: Request): E.valkyrie_linkage(music_list_1=-1, music_list_2=-1, music_list_3=-1), E.bemani_song_battle(music_list=-1), E.bemani_mixup(music_list=-1), + E.ccj_linkage(music_list=-1), + E.triple_tribe(music_list=-1), E.achievements( E.trophy(profile.get("achievements_trophy", [])[:10], __type="s64"), pack=profile.get("achievements_pack_id", 0), @@ -787,6 +789,7 @@ async def iidx30pc_common(request: Request): # E.fps_fix(), # E.save_unsync_log(), E.tourism_booster(), + E.ameto_event(), expire=600, ) ) diff --git a/pyeamu.py b/pyeamu.py index 515f583..3ca308b 100644 --- a/pyeamu.py +++ b/pyeamu.py @@ -1,9 +1,10 @@ -from urllib.parse import urlunparse, urlencode +from urllib.parse import urlparse, urlunparse, urlencode import uvicorn import ujson as json from os import name, path +from typing import Optional from fastapi import FastAPI, Request, Response from fastapi.middleware.cors import CORSMiddleware @@ -16,16 +17,24 @@ import utils.card as conv from core_common import core_process_request, core_prepare_response, E +import socket + def urlpathjoin(parts, sep="/"): return sep + sep.join([x.lstrip(sep) for x in parts]) -server_address = f"{config.ip}:{config.port}" -server_services_url = urlunparse( - ("http", server_address, config.services_prefix, None, None, None) -) -keepalive_address = "127.0.0.1" +loopback = "127.0.0.1" + +server_addresses = [] +for host in ("localhost", config.ip, socket.gethostname()): + server_addresses.append(f"{host}:{config.port}") + +server_services_urls = [] +for server_address in server_addresses: + server_services_urls.append( + urlunparse(("http", server_address, config.services_prefix, None, None, None)) + ) settings = {} for s in ( @@ -85,23 +94,36 @@ if __name__ == "__main__": ) print() print("\033[1mGame Config\033[0m:") - print(f"\033[92m{server_services_url}\033[0m") - print('\033[92m1\033[0m') + for server_services_url in server_services_urls: + print(f"\033[92m{server_services_url}\033[0m") + print("") + # print('\033[92m0\033[0m') + # print('\033[92m1\033[0m') print() if webui: print("\033[1mWeb Interface\033[0m:") - print(f"http://{server_address}/webui/") + for server_address in server_addresses: + print(f"http://{server_address}/webui/") print() print("\033[1mSource Repository\033[0m:") print("https://github.com/drmext/MonkeyBusiness") print() - uvicorn.run("pyeamu:app", host=config.ip, port=config.port, reload=True) + uvicorn.run("pyeamu:app", host="0.0.0.0", port=config.port, reload=True) +@app.post(urlpathjoin([config.services_prefix])) @app.post(urlpathjoin([config.services_prefix, "/{gameinfo}/services/get"])) -async def services_get(request: Request): +async def services_get( + request: Request, + model: Optional[str] = None, + f: Optional[str] = None, + module: Optional[str] = None, + method: Optional[str] = None, +): request_info = await core_process_request(request) + request_address = f"{urlparse(str(request.url)).netloc}:{config.port}" + services = {} for service in modules.routers: @@ -114,24 +136,42 @@ async def services_get(request: Request): if model_whitelist and request_info["model"] not in model_whitelist: continue + if ( + service.tags + and service.tags[0].startswith("api_") + or service.tags[0] == "slashless_forwarder" + ): + continue + k = (service.tags[0] if service.tags else service.prefix).strip("/") - if k not in services: - services[k] = urlunparse( - ("http", server_address, service.prefix, None, None, None) - ) + if f == "services.get" or module == "services" and method == "get": + if service.prefix == "/core": + non_slash_prefix = "/core_fwdr" + else: + non_slash_prefix = "/fwdr" + if k not in services: + services[k] = urlunparse( + ("http", request_address, non_slash_prefix, None, None, None) + ) + # url_slash + else: + if k not in services: + services[k] = urlunparse( + ("http", request_address, service.prefix, None, None, None) + ) keepalive_params = { - "pa": keepalive_address, - "ia": keepalive_address, - "ga": keepalive_address, - "ma": keepalive_address, + "pa": loopback, + "ia": loopback, + "ga": loopback, + "ma": loopback, "t1": 2, "t2": 10, } services["keepalive"] = urlunparse( ( "http", - keepalive_address, + loopback, "/keepalive", None, urlencode(keepalive_params), @@ -139,9 +179,6 @@ async def services_get(request: Request): ) ) services["ntp"] = urlunparse(("ntp", "pool.ntp.org", "/", None, None, None)) - services["services"] = urlunparse( - ("http", server_address, "/core", None, None, None) - ) response = E.response( E.services(