Merge remote-tracking branch 'origin/develop' into fork_develop

This commit is contained in:
Dniel97 2023-07-15 22:47:05 +02:00
commit 389784ce82
Signed by untrusted user: Dniel97
GPG Key ID: 6180B3C768FB2E08
5 changed files with 254 additions and 151 deletions

View File

@ -27,9 +27,9 @@ class Data:
if self.config.database.sha2_password: if self.config.database.sha2_password:
passwd = sha256(self.config.database.password.encode()).digest() passwd = sha256(self.config.database.password.encode()).digest()
self.__url = f"{self.config.database.protocol}://{self.config.database.username}:{passwd.hex()}@{self.config.database.host}/{self.config.database.name}?charset=utf8mb4" self.__url = f"{self.config.database.protocol}://{self.config.database.username}:{passwd.hex()}@{self.config.database.host}:{self.config.database.port}/{self.config.database.name}?charset=utf8mb4"
else: else:
self.__url = f"{self.config.database.protocol}://{self.config.database.username}:{self.config.database.password}@{self.config.database.host}/{self.config.database.name}?charset=utf8mb4" self.__url = f"{self.config.database.protocol}://{self.config.database.username}:{self.config.database.password}@{self.config.database.host}:{self.config.database.port}/{self.config.database.name}?charset=utf8mb4"
if Data.engine is None: if Data.engine is None:
Data.engine = create_engine(self.__url, pool_recycle=3600) Data.engine = create_engine(self.__url, pool_recycle=3600)
@ -94,7 +94,7 @@ class Data:
game_mod.database(self.config) game_mod.database(self.config)
metadata.create_all(self.__engine.connect()) metadata.create_all(self.__engine.connect())
self.base.set_schema_ver( self.base.touch_schema_ver(
game_mod.current_schema_version, game_mod.game_codes[0] game_mod.current_schema_version, game_mod.game_codes[0]
) )

View File

@ -102,6 +102,18 @@ class BaseData:
return None return None
return row["version"] return row["version"]
def touch_schema_ver(self, ver: int, game: str = "CORE") -> Optional[int]:
sql = insert(schema_ver).values(game=game, version=ver)
conflict = sql.on_duplicate_key_update(version=schema_ver.c.version)
result = self.execute(conflict)
if result is None:
self.logger.error(
f"Failed to update schema version for game {game} (v{ver})"
)
return None
return result.lastrowid
def set_schema_ver(self, ver: int, game: str = "CORE") -> Optional[int]: def set_schema_ver(self, ver: int, game: str = "CORE") -> Optional[int]:
sql = insert(schema_ver).values(game=game, version=ver) sql = insert(schema_ver).values(game=game, version=ver)

View File

@ -4,6 +4,7 @@ from logging.handlers import TimedRotatingFileHandler
from twisted.web import resource from twisted.web import resource
from twisted.web.http import Request from twisted.web.http import Request
from datetime import datetime from datetime import datetime
from Crypto.Cipher import Blowfish
import pytz import pytz
from core import CoreConfig from core import CoreConfig
@ -56,18 +57,22 @@ class MuchaServlet:
self.logger.error( self.logger.error(
f"Error processing mucha request {request.content.getvalue()}" f"Error processing mucha request {request.content.getvalue()}"
) )
return b"" return b"RESULTS=000"
req = MuchaAuthRequest(req_dict) req = MuchaAuthRequest(req_dict)
self.logger.info(f"Boardauth request from {client_ip} for {req.gameVer}")
self.logger.debug(f"Mucha request {vars(req)}") self.logger.debug(f"Mucha request {vars(req)}")
self.logger.info(f"Boardauth request from {client_ip} for {req.gameVer}")
if req.gameCd not in self.mucha_registry: if req.gameCd not in self.mucha_registry:
self.logger.warn(f"Unknown gameCd {req.gameCd}") self.logger.warn(f"Unknown gameCd {req.gameCd}")
return b"" return b"RESULTS=000"
# TODO: Decrypt S/N # TODO: Decrypt S/N
#cipher = Blowfish.new(req.sendDate.encode(), Blowfish.MODE_ECB)
#sn_decrypt = cipher.decrypt(bytes.fromhex(req.serialNum))
#self.logger.debug(f"Decrypt SN to {sn_decrypt.hex()}")
resp = MuchaAuthResponse( resp = MuchaAuthResponse(
f"{self.config.mucha.hostname}{':' + str(self.config.allnet.port) if self.config.server.is_develop else ''}" f"{self.config.mucha.hostname}{':' + str(self.config.allnet.port) if self.config.server.is_develop else ''}"
) )
@ -84,22 +89,37 @@ class MuchaServlet:
self.logger.error( self.logger.error(
f"Error processing mucha request {request.content.getvalue()}" f"Error processing mucha request {request.content.getvalue()}"
) )
return b"" return b"RESULTS=000"
req = MuchaUpdateRequest(req_dict) req = MuchaUpdateRequest(req_dict)
self.logger.info(f"Updatecheck request from {client_ip} for {req.gameVer}")
self.logger.debug(f"Mucha request {vars(req)}") self.logger.debug(f"Mucha request {vars(req)}")
self.logger.info(f"Updatecheck request from {client_ip} for {req.gameVer}")
if req.gameCd not in self.mucha_registry: if req.gameCd not in self.mucha_registry:
self.logger.warn(f"Unknown gameCd {req.gameCd}") self.logger.warn(f"Unknown gameCd {req.gameCd}")
return b"" return b"RESULTS=000"
resp = MuchaUpdateResponseStub(req.gameVer) resp = MuchaUpdateResponse(req.gameVer, f"{self.config.mucha.hostname}{':' + str(self.config.allnet.port) if self.config.server.is_develop else ''}")
self.logger.debug(f"Mucha response {vars(resp)}") self.logger.debug(f"Mucha response {vars(resp)}")
return self.mucha_postprocess(vars(resp)) return self.mucha_postprocess(vars(resp))
def handle_dlstate(self, request: Request, _: Dict) -> bytes:
req_dict = self.mucha_preprocess(request.content.getvalue())
client_ip = Utils.get_ip_addr(request)
if req_dict is None:
self.logger.error(
f"Error processing mucha request {request.content.getvalue()}"
)
return b""
req = MuchaDownloadStateRequest(req_dict)
self.logger.info(f"DownloadState request from {client_ip} for {req.gameCd} -> {req.updateVer}")
self.logger.debug(f"request {vars(req)}")
return b"RESULTS=001"
def mucha_preprocess(self, data: bytes) -> Optional[Dict]: def mucha_preprocess(self, data: bytes) -> Optional[Dict]:
try: try:
ret: Dict[str, Any] = {} ret: Dict[str, Any] = {}
@ -202,22 +222,57 @@ class MuchaUpdateRequest:
class MuchaUpdateResponse: class MuchaUpdateResponse:
def __init__(self, game_ver: str, mucha_url: str) -> None: def __init__(self, game_ver: str, mucha_url: str) -> None:
self.RESULTS = "001" self.RESULTS = "001"
self.EXE_VER = game_ver
self.UPDATE_VER_1 = game_ver self.UPDATE_VER_1 = game_ver
self.UPDATE_URL_1 = f"https://{mucha_url}/updUrl1/" self.UPDATE_URL_1 = f"http://{mucha_url}/updUrl1/"
self.UPDATE_SIZE_1 = "0" self.UPDATE_SIZE_1 = "20"
self.UPDATE_CRC_1 = "0000000000000000"
self.CHECK_URL_1 = f"https://{mucha_url}/checkUrl/" self.CHECK_CRC_1 = "0000000000000000"
self.EXE_VER_1 = game_ver self.CHECK_URL_1 = f"http://{mucha_url}/checkUrl/"
self.CHECK_SIZE_1 = "20"
self.INFO_SIZE_1 = "0" self.INFO_SIZE_1 = "0"
self.COM_SIZE_1 = "0" self.COM_SIZE_1 = "0"
self.COM_TIME_1 = "0" self.COM_TIME_1 = "0"
self.LAN_INFO_SIZE_1 = "0" self.LAN_INFO_SIZE_1 = "0"
self.USER_ID = "" self.USER_ID = ""
self.PASSWORD = "" self.PASSWORD = ""
"""
RESULTS
EXE_VER
UPDATE_VER_%d
UPDATE_URL_%d
UPDATE_SIZE_%d
CHECK_CRC_%d
CHECK_URL_%d
CHECK_SIZE_%d
INFO_SIZE_1
COM_SIZE_1
COM_TIME_1
LAN_INFO_SIZE_1
USER_ID
PASSWORD
"""
class MuchaUpdateResponseStub: class MuchaUpdateResponseStub:
def __init__(self, game_ver: str) -> None: def __init__(self, game_ver: str) -> None:
self.RESULTS = "001" self.RESULTS = "001"
self.UPDATE_VER_1 = game_ver self.UPDATE_VER_1 = game_ver
class MuchaDownloadStateRequest:
def __init__(self, request: Dict) -> None:
self.gameCd = request.get("gameCd", "")
self.updateVer = request.get("updateVer", "")
self.serialNum = request.get("serialNum", "")
self.fileSize = request.get("fileSize", "")
self.compFileSize = request.get("compFileSize", "")
self.boardId = request.get("boardId", "")
self.placeId = request.get("placeId", "")
self.storeRouterIp = request.get("storeRouterIp", "")

View File

@ -113,6 +113,13 @@ class HttpDispatcher(resource.Resource):
action="handle_updatecheck", action="handle_updatecheck",
conditions=dict(method=["POST"]), conditions=dict(method=["POST"]),
) )
self.map_post.connect(
"mucha_dlstate",
"/mucha/downloadstate.do",
controller="mucha",
action="handle_dlstate",
conditions=dict(method=["POST"]),
)
self.map_get.connect( self.map_get.connect(
"title_get", "title_get",

View File

@ -11,6 +11,7 @@ from titles.cxb.config import CxbConfig
from titles.cxb.const import CxbConstants from titles.cxb.const import CxbConstants
from titles.cxb.database import CxbData from titles.cxb.database import CxbData
from threading import Thread
class CxbBase: class CxbBase:
def __init__(self, cfg: CoreConfig, game_cfg: CxbConfig) -> None: def __init__(self, cfg: CoreConfig, game_cfg: CxbConfig) -> None:
@ -54,6 +55,151 @@ class CxbBase:
self.logger.warn(f"User {data['login']['authid']} does not have a profile") self.logger.warn(f"User {data['login']['authid']} does not have a profile")
return {} return {}
def task_generateCoupon(index, data1):
# Coupons
for i in range(500, 510):
index.append(str(i))
couponid = int(i) - 500
dataValue = [
{
"couponId": str(couponid),
"couponNum": "1",
"couponLog": [],
}
]
data1.append(
b64encode(
bytes(json.dumps(dataValue[0], separators=(",", ":")), "utf-8")
).decode("utf-8")
)
def task_generateShopListTitle(index, data1):
# ShopList_Title
for i in range(200000, 201451):
index.append(str(i))
shopid = int(i) - 200000
dataValue = [
{
"shopId": shopid,
"shopState": "2",
"isDisable": "t",
"isDeleted": "f",
"isSpecialFlag": "f",
}
]
data1.append(
b64encode(
bytes(json.dumps(dataValue[0], separators=(",", ":")), "utf-8")
).decode("utf-8")
)
def task_generateShopListIcon(index, data1):
# ShopList_Icon
for i in range(202000, 202264):
index.append(str(i))
shopid = int(i) - 200000
dataValue = [
{
"shopId": shopid,
"shopState": "2",
"isDisable": "t",
"isDeleted": "f",
"isSpecialFlag": "f",
}
]
data1.append(
b64encode(
bytes(json.dumps(dataValue[0], separators=(",", ":")), "utf-8")
).decode("utf-8")
)
def task_generateStories(index, data1):
# Stories
for i in range(900000, 900003):
index.append(str(i))
storyid = int(i) - 900000
dataValue = [
{
"storyId": storyid,
"unlockState1": ["t"] * 10,
"unlockState2": ["t"] * 10,
"unlockState3": ["t"] * 10,
"unlockState4": ["t"] * 10,
"unlockState5": ["t"] * 10,
"unlockState6": ["t"] * 10,
"unlockState7": ["t"] * 10,
"unlockState8": ["t"] * 10,
"unlockState9": ["t"] * 10,
"unlockState10": ["t"] * 10,
"unlockState11": ["t"] * 10,
"unlockState12": ["t"] * 10,
"unlockState13": ["t"] * 10,
"unlockState14": ["t"] * 10,
"unlockState15": ["t"] * 10,
"unlockState16": ["t"] * 10,
}
]
data1.append(
b64encode(
bytes(json.dumps(dataValue[0], separators=(",", ":")), "utf-8")
).decode("utf-8")
)
def task_generateScoreData(song, index, data1):
song_data = song["data"]
songCode = []
songCode.append(
{
"mcode": song_data["mcode"],
"musicState": song_data["musicState"],
"playCount": song_data["playCount"],
"totalScore": song_data["totalScore"],
"highScore": song_data["highScore"],
"everHighScore": song_data["everHighScore"]
if "everHighScore" in song_data
else ["0", "0", "0", "0", "0"],
"clearRate": song_data["clearRate"],
"rankPoint": song_data["rankPoint"],
"normalCR": song_data["normalCR"]
if "normalCR" in song_data
else ["0", "0", "0", "0", "0"],
"survivalCR": song_data["survivalCR"]
if "survivalCR" in song_data
else ["0", "0", "0", "0", "0"],
"ultimateCR": song_data["ultimateCR"]
if "ultimateCR" in song_data
else ["0", "0", "0", "0", "0"],
"nohopeCR": song_data["nohopeCR"]
if "nohopeCR" in song_data
else ["0", "0", "0", "0", "0"],
"combo": song_data["combo"],
"coupleUserId": song_data["coupleUserId"],
"difficulty": song_data["difficulty"],
"isFullCombo": song_data["isFullCombo"],
"clearGaugeType": song_data["clearGaugeType"],
"fieldType": song_data["fieldType"],
"gameType": song_data["gameType"],
"grade": song_data["grade"],
"unlockState": song_data["unlockState"],
"extraState": song_data["extraState"],
}
)
index.append(song_data["index"])
data1.append(
b64encode(
bytes(json.dumps(songCode[0], separators=(",", ":")), "utf-8")
).decode("utf-8")
)
def task_generateIndexData(versionindex):
try:
v_profile = self.data.profile.get_profile_index(0, uid, self.version)
v_profile_data = v_profile["data"]
versionindex.append(int(v_profile_data["appVersion"]))
except:
versionindex.append("10400")
def handle_action_loadrange_request(self, data: Dict) -> Dict: def handle_action_loadrange_request(self, data: Dict) -> Dict:
range_start = data["loadrange"]["range"][0] range_start = data["loadrange"]["range"][0]
range_end = data["loadrange"]["range"][1] range_end = data["loadrange"]["range"][1]
@ -107,146 +253,29 @@ class CxbBase:
900000 = Stories 900000 = Stories
""" """
# Coupons # Async threads to generate the response
for i in range(500, 510): thread_Coupon = Thread(target=CxbBase.task_generateCoupon(index, data1))
index.append(str(i)) thread_ShopListTitle = Thread(target=CxbBase.task_generateShopListTitle(index, data1))
couponid = int(i) - 500 thread_ShopListIcon = Thread(target=CxbBase.task_generateShopListIcon(index, data1))
dataValue = [ thread_Stories = Thread(target=CxbBase.task_generateStories(index, data1))
{
"couponId": str(couponid),
"couponNum": "1",
"couponLog": [],
}
]
data1.append(
b64encode(
bytes(json.dumps(dataValue[0], separators=(",", ":")), "utf-8")
).decode("utf-8")
)
# ShopList_Title thread_Coupon.start()
for i in range(200000, 201451): thread_ShopListTitle.start()
index.append(str(i)) thread_ShopListIcon.start()
shopid = int(i) - 200000 thread_Stories.start()
dataValue = [
{
"shopId": shopid,
"shopState": "2",
"isDisable": "t",
"isDeleted": "f",
"isSpecialFlag": "f",
}
]
data1.append(
b64encode(
bytes(json.dumps(dataValue[0], separators=(",", ":")), "utf-8")
).decode("utf-8")
)
# ShopList_Icon thread_Coupon.join()
for i in range(202000, 202264): thread_ShopListTitle.join()
index.append(str(i)) thread_ShopListIcon.join()
shopid = int(i) - 200000 thread_Stories.join()
dataValue = [
{
"shopId": shopid,
"shopState": "2",
"isDisable": "t",
"isDeleted": "f",
"isSpecialFlag": "f",
}
]
data1.append(
b64encode(
bytes(json.dumps(dataValue[0], separators=(",", ":")), "utf-8")
).decode("utf-8")
)
# Stories
for i in range(900000, 900003):
index.append(str(i))
storyid = int(i) - 900000
dataValue = [
{
"storyId": storyid,
"unlockState1": ["t"] * 10,
"unlockState2": ["t"] * 10,
"unlockState3": ["t"] * 10,
"unlockState4": ["t"] * 10,
"unlockState5": ["t"] * 10,
"unlockState6": ["t"] * 10,
"unlockState7": ["t"] * 10,
"unlockState8": ["t"] * 10,
"unlockState9": ["t"] * 10,
"unlockState10": ["t"] * 10,
"unlockState11": ["t"] * 10,
"unlockState12": ["t"] * 10,
"unlockState13": ["t"] * 10,
"unlockState14": ["t"] * 10,
"unlockState15": ["t"] * 10,
"unlockState16": ["t"] * 10,
}
]
data1.append(
b64encode(
bytes(json.dumps(dataValue[0], separators=(",", ":")), "utf-8")
).decode("utf-8")
)
for song in songs: for song in songs:
song_data = song["data"] thread_ScoreData = Thread(target=CxbBase.task_generateScoreData(song, index, data1))
songCode = [] thread_ScoreData.start()
songCode.append(
{
"mcode": song_data["mcode"],
"musicState": song_data["musicState"],
"playCount": song_data["playCount"],
"totalScore": song_data["totalScore"],
"highScore": song_data["highScore"],
"everHighScore": song_data["everHighScore"]
if "everHighScore" in song_data
else ["0", "0", "0", "0", "0"],
"clearRate": song_data["clearRate"],
"rankPoint": song_data["rankPoint"],
"normalCR": song_data["normalCR"]
if "normalCR" in song_data
else ["0", "0", "0", "0", "0"],
"survivalCR": song_data["survivalCR"]
if "survivalCR" in song_data
else ["0", "0", "0", "0", "0"],
"ultimateCR": song_data["ultimateCR"]
if "ultimateCR" in song_data
else ["0", "0", "0", "0", "0"],
"nohopeCR": song_data["nohopeCR"]
if "nohopeCR" in song_data
else ["0", "0", "0", "0", "0"],
"combo": song_data["combo"],
"coupleUserId": song_data["coupleUserId"],
"difficulty": song_data["difficulty"],
"isFullCombo": song_data["isFullCombo"],
"clearGaugeType": song_data["clearGaugeType"],
"fieldType": song_data["fieldType"],
"gameType": song_data["gameType"],
"grade": song_data["grade"],
"unlockState": song_data["unlockState"],
"extraState": song_data["extraState"],
}
)
index.append(song_data["index"])
data1.append(
b64encode(
bytes(json.dumps(songCode[0], separators=(",", ":")), "utf-8")
).decode("utf-8")
)
for v in index: for v in index:
try: thread_IndexData = Thread(target=CxbBase.task_generateIndexData(versionindex))
v_profile = self.data.profile.get_profile_index(0, uid, self.version) thread_IndexData.start()
v_profile_data = v_profile["data"]
versionindex.append(int(v_profile_data["appVersion"]))
except:
versionindex.append("10400")
return {"index": index, "data": data1, "version": versionindex} return {"index": index, "data": data1, "version": versionindex}
@ -544,4 +573,4 @@ class CxbBase:
def handle_action_stampreq_request(self, data: Dict) -> Dict: def handle_action_stampreq_request(self, data: Dict) -> Dict:
self.logger.info(data) self.logger.info(data)
return {"stampreq": ""} return {"stampreq": ""}