From 0ab43e800e58240417aec8d9ae56865bc5a60b3c Mon Sep 17 00:00:00 2001 From: 573dev <> Date: Fri, 6 Nov 2020 20:36:42 -0600 Subject: [PATCH] Start using xml templating --- v8_server/eamuse/services/cardmng.py | 127 ++++++++---------- v8_server/eamuse/services/facility.py | 2 +- v8_server/eamuse/services/local.py | 2 +- v8_server/eamuse/services/package.py | 2 +- v8_server/eamuse/services/services.py | 2 +- v8_server/eamuse/utils/xml.py | 45 ------- v8_server/eamuse/xml/__init__.py | 0 .../eamuse/xml/templates/cardmng/authpass.xml | 3 + .../xml/templates/cardmng/bindmodel.xml | 3 + .../xml/templates/cardmng/getdatalist.xml | 3 + .../xml/templates/cardmng/getkeepspan.xml | 3 + .../eamuse/xml/templates/cardmng/getrefid.xml | 3 + .../eamuse/xml/templates/cardmng/inquire.xml | 13 ++ v8_server/eamuse/xml/utils.py | 83 ++++++++++++ 14 files changed, 174 insertions(+), 117 deletions(-) delete mode 100644 v8_server/eamuse/utils/xml.py create mode 100644 v8_server/eamuse/xml/__init__.py create mode 100644 v8_server/eamuse/xml/templates/cardmng/authpass.xml create mode 100644 v8_server/eamuse/xml/templates/cardmng/bindmodel.xml create mode 100644 v8_server/eamuse/xml/templates/cardmng/getdatalist.xml create mode 100644 v8_server/eamuse/xml/templates/cardmng/getkeepspan.xml create mode 100644 v8_server/eamuse/xml/templates/cardmng/getrefid.xml create mode 100644 v8_server/eamuse/xml/templates/cardmng/inquire.xml create mode 100644 v8_server/eamuse/xml/utils.py diff --git a/v8_server/eamuse/services/cardmng.py b/v8_server/eamuse/services/cardmng.py index 1adf3c9..74116d2 100644 --- a/v8_server/eamuse/services/cardmng.py +++ b/v8_server/eamuse/services/cardmng.py @@ -2,10 +2,26 @@ from lxml.builder import E from v8_server import db from v8_server.eamuse.services.services import ServiceRequest -from v8_server.eamuse.utils.xml import get_xml_attrib +from v8_server.eamuse.xml.utils import ( + drop_attributes, + get_xml_attrib, + load_xml_template, +) from v8_server.model.user import Card, Profile, RefID, User, UserAccount +class CardStatus(object): + """ + Possible Card Status Values + """ + + SUCCESS = 0 + NO_PROFILE = 109 + NOT_ALLOWED = 110 + NOT_REGISTERED = 112 + INVALID_PIN = 116 + + class CardMng(object): """ Handle the CardMng (Card Manage) request. @@ -13,13 +29,6 @@ class CardMng(object): This is for supporting eAmuse card interaction. """ - # List of statuses we return to the game for various card related reasons - SUCCESS = 0 - NO_PROFILE = 109 - NOT_ALLOWED = 110 - NOT_REGISTERED = 112 - INVALID_PIN = 116 - # Methods INQUIRE = "inquire" GETREFID = "getrefid" @@ -31,75 +40,59 @@ class CardMng(object): @classmethod def inquire(cls, req: ServiceRequest): """ - Example Request: - - - + Handle a Card Manage Inquire Request - Example Response: - - - + Either the given card id is a brand new user, or a returning user. + + Modifyable XML Text Replacements: + refid: The RefID.refid value for an existing user + newflag: Set to true for a new user, else 0 + binded: Set to true if the user has a profile/account, else 0 + status: See CardMng status consts at the top of this class """ + # Grab the card id cardid = get_xml_attrib(req.xml[0], "cardid") + # Default result for a new unregistered user + args = { + "refid": "", + "newflag": 1, + "binded": 0, + "status": CardStatus.NOT_REGISTERED, + } + # Check if a user with this card id already exists user = User.from_cardid(cardid) - if user is None: - # The user doesn't exist, force system to create a new account - response = E.response( - E.cardmng( - { - "newflag": "1", - "binded": "0", - "status": str(CardMng.NOT_REGISTERED), - } - ) - ) - else: + # We have a returning user + if user is not None: refid = RefID.from_userid(user.userid) bound = UserAccount.from_userid(user.userid) is not None if refid is None: + # TODO: better exception? raise Exception("RefID Should not be None here!") - response = E.response( - E.cardmng( - { - "refid": refid.refid, - "dataid": refid.refid, - "newflag": "0", - "binded": "1" if bound else "0", - "expired": "0", - "exflag": "0", - "useridflag": "1", - "extidflag": "1", - "status": str(CardMng.SUCCESS), - } - ) + args["refid"] = refid.refid + args["newflag"] = 0 + args["binded"] = bound + args["status"] = CardStatus.SUCCESS + + result = load_xml_template("cardmng", "inquire", args) + + # If we have a brand new user, we can remove unnecessary xml attributes from the + # cardmng node + if user is None: + drop_attributes( + result.find("cardmng"), + ["refid", "dataid", "expired", "exflag", "useridflag", "extidflag"], ) - return response + return result @classmethod def getrefid(cls, req: ServiceRequest): - """""" # Grab the card id and pin cardid = get_xml_attrib(req.xml[0], "cardid") pin = get_xml_attrib(req.xml[0], "passwd") @@ -117,7 +110,7 @@ class CardMng(object): # Generate the refid and return it refid = RefID.create_with_userid(user.userid) - return E.response(E.cardmng({"dataid": refid.refid, "refid": refid.refid})) + return load_xml_template("cardmng", "getrefid", {"refid": refid.refid}) @classmethod def authpass(cls, req: ServiceRequest): @@ -134,13 +127,9 @@ class CardMng(object): # Check if the pin is valid for the user user = refid.user - valid = user.pin == pin + status = CardStatus.SUCCESS if user.pin == pin else CardStatus.INVALID_PIN - return E.response( - E.cardmng( - {"status": str(CardMng.SUCCESS if valid else CardMng.INVALID_PIN)} - ) - ) + return load_xml_template("cardmng", "authpass", {"status": status}) @classmethod def bindmodel(cls, req: ServiceRequest): @@ -157,18 +146,20 @@ class CardMng(object): db.session.add(profile) db.session.commit() - return E.response(E.cardmng({"dataid": refid.refid})) + return load_xml_template("cardmng", "bindmodel", {"refid": refid.refid}) @classmethod def getkeepspan(cls): """ Unclear what this method does, return an arbitrary span """ - return E.response(E.cardmng({"keepspan": "30"})) + + keepspan = 30 + return load_xml_template("cardmng", "getkeepspan", {"keepspan": keepspan}) @classmethod def getdatalist(cls): """ Unclear what this method does, return a dummy response """ - return E.response(E.cardmng()) + return load_xml_template("cardmng", "cardmng") diff --git a/v8_server/eamuse/services/facility.py b/v8_server/eamuse/services/facility.py index 38fd146..5e70411 100644 --- a/v8_server/eamuse/services/facility.py +++ b/v8_server/eamuse/services/facility.py @@ -1,6 +1,6 @@ from lxml.builder import E -from v8_server.eamuse.utils.xml import XMLBinTypes as T, e_type +from v8_server.eamuse.xml.utils import XMLBinTypes as T, e_type class Facility(object): diff --git a/v8_server/eamuse/services/local.py b/v8_server/eamuse/services/local.py index cdc08b4..84a49bd 100644 --- a/v8_server/eamuse/services/local.py +++ b/v8_server/eamuse/services/local.py @@ -7,7 +7,7 @@ from lxml.builder import E from v8_server import db from v8_server.eamuse.services.services import ServiceRequest from v8_server.eamuse.utils.crc import calculate_crc8 -from v8_server.eamuse.utils.xml import XMLBinTypes as T, e_type, fill, get_xml_attrib +from v8_server.eamuse.xml.utils import XMLBinTypes as T, e_type, fill, get_xml_attrib from v8_server.model.song import HitChart from v8_server.model.user import User, UserAccount diff --git a/v8_server/eamuse/services/package.py b/v8_server/eamuse/services/package.py index 8740ae1..79ba53c 100644 --- a/v8_server/eamuse/services/package.py +++ b/v8_server/eamuse/services/package.py @@ -1,7 +1,7 @@ from lxml.builder import E from v8_server.eamuse.services.services import ServiceRequest -from v8_server.eamuse.utils.xml import get_xml_attrib +from v8_server.eamuse.xml.utils import get_xml_attrib class Package(object): diff --git a/v8_server/eamuse/services/services.py b/v8_server/eamuse/services/services.py index 5387ee6..c29c189 100644 --- a/v8_server/eamuse/services/services.py +++ b/v8_server/eamuse/services/services.py @@ -18,7 +18,7 @@ from v8_server import LOG_PATH, app from v8_server.eamuse.utils.arc4 import EAmuseARC4 from v8_server.eamuse.utils.eamuse import Model from v8_server.eamuse.utils.lz77 import Lz77 -from v8_server.eamuse.utils.xml import get_xml_attrib, get_xml_tag +from v8_server.eamuse.xml.utils import get_xml_attrib, get_xml_tag # We want a general logger, and a special logger to log requests separately diff --git a/v8_server/eamuse/utils/xml.py b/v8_server/eamuse/utils/xml.py deleted file mode 100644 index c49b64a..0000000 --- a/v8_server/eamuse/utils/xml.py +++ /dev/null @@ -1,45 +0,0 @@ -from datetime import datetime -from typing import Dict, Optional - -from lxml import etree - - -def fill(count: int, value: str = "0") -> str: - return " ".join(value for _ in range(0, count)) - - -class XMLBinTypes(object): - s8 = "s8" - u8 = "u8" - s16 = "s16" - u16 = "u16" - s32 = "s32" - u32 = "u32" - s64 = "s64" - u64 = "u64" - ip4 = "ip4" - time = "time" - str = "str" - - -def e_type(_type, count: Optional[int] = None) -> Dict[str, str]: - result = {"__type": _type} - if count is not None: - result["__count"] = str(count) - return result - - -def get_xml_tag(xml: etree) -> str: - return str(xml.tag) - - -def get_xml_attrib(xml: etree, name: str) -> str: - return str(xml.attrib[name]) if name in xml.attrib else "None" - - -def format_date(timestamp: Optional[int]) -> str: - if timestamp is None: - return "None" - - dt = datetime.fromtimestamp(timestamp) - return dt.strftime("%Y-%m-%d %H:%M:%S") diff --git a/v8_server/eamuse/xml/__init__.py b/v8_server/eamuse/xml/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/v8_server/eamuse/xml/templates/cardmng/authpass.xml b/v8_server/eamuse/xml/templates/cardmng/authpass.xml new file mode 100644 index 0000000..4c6f978 --- /dev/null +++ b/v8_server/eamuse/xml/templates/cardmng/authpass.xml @@ -0,0 +1,3 @@ + + + diff --git a/v8_server/eamuse/xml/templates/cardmng/bindmodel.xml b/v8_server/eamuse/xml/templates/cardmng/bindmodel.xml new file mode 100644 index 0000000..afb3385 --- /dev/null +++ b/v8_server/eamuse/xml/templates/cardmng/bindmodel.xml @@ -0,0 +1,3 @@ + + + diff --git a/v8_server/eamuse/xml/templates/cardmng/getdatalist.xml b/v8_server/eamuse/xml/templates/cardmng/getdatalist.xml new file mode 100644 index 0000000..ecc7764 --- /dev/null +++ b/v8_server/eamuse/xml/templates/cardmng/getdatalist.xml @@ -0,0 +1,3 @@ + + + diff --git a/v8_server/eamuse/xml/templates/cardmng/getkeepspan.xml b/v8_server/eamuse/xml/templates/cardmng/getkeepspan.xml new file mode 100644 index 0000000..070bc82 --- /dev/null +++ b/v8_server/eamuse/xml/templates/cardmng/getkeepspan.xml @@ -0,0 +1,3 @@ + + + diff --git a/v8_server/eamuse/xml/templates/cardmng/getrefid.xml b/v8_server/eamuse/xml/templates/cardmng/getrefid.xml new file mode 100644 index 0000000..4e6ca03 --- /dev/null +++ b/v8_server/eamuse/xml/templates/cardmng/getrefid.xml @@ -0,0 +1,3 @@ + + + diff --git a/v8_server/eamuse/xml/templates/cardmng/inquire.xml b/v8_server/eamuse/xml/templates/cardmng/inquire.xml new file mode 100644 index 0000000..0e442a7 --- /dev/null +++ b/v8_server/eamuse/xml/templates/cardmng/inquire.xml @@ -0,0 +1,13 @@ + + + diff --git a/v8_server/eamuse/xml/utils.py b/v8_server/eamuse/xml/utils.py new file mode 100644 index 0000000..4ab2dd8 --- /dev/null +++ b/v8_server/eamuse/xml/utils.py @@ -0,0 +1,83 @@ +import logging +from datetime import datetime +from pathlib import Path +from typing import Any, Dict, List, Optional + +from lxml import etree + + +logger = logging.getLogger(__name__) + + +def load_xml_template( + service: str, method: str, args: Optional[Dict[str, Any]], / # noqa: W504 +) -> etree: + """ + Given a service and a method, load the appropriate XML template and return it + + Args: + service (str): eAmuse Service Name + method (str): eAmuse Method Name + args (Dict[str, Any]): Used for formatting the xml string + + Returns: + etree: Resulting XML etree + """ + template_path = Path(__file__).parent / "templates" + filepath = template_path / service / f"{method}.xml" + + try: + xml_str = filepath.open().read() + except Exception: + raise + + if args is not None: + xml_str = xml_str.format(**args) + + return etree.fromstring(xml_str.encode("UTF-8")) + + +def drop_attributes(element: etree, attributes: List[str]) -> None: + for attribute in attributes: + element.attrib.pop(attribute) + + +def fill(count: int, value: str = "0") -> str: + return " ".join(value for _ in range(0, count)) + + +class XMLBinTypes(object): + s8 = "s8" + u8 = "u8" + s16 = "s16" + u16 = "u16" + s32 = "s32" + u32 = "u32" + s64 = "s64" + u64 = "u64" + ip4 = "ip4" + time = "time" + str = "str" + + +def e_type(_type, count: Optional[int] = None) -> Dict[str, str]: + result = {"__type": _type} + if count is not None: + result["__count"] = str(count) + return result + + +def get_xml_tag(xml: etree) -> str: + return str(xml.tag) + + +def get_xml_attrib(xml: etree, name: str) -> str: + return str(xml.attrib[name]) if name in xml.attrib else "None" + + +def format_date(timestamp: Optional[int]) -> str: + if timestamp is None: + return "None" + + dt = datetime.fromtimestamp(timestamp) + return dt.strftime("%Y-%m-%d %H:%M:%S")