Sample implemention of JSONtoTextParser

This commit is contained in:
Fabian Dill 2021-01-31 11:33:39 +01:00
parent 3d81f0cca7
commit 1da1e4eac6
3 changed files with 57 additions and 40 deletions

View File

@ -43,7 +43,6 @@ def create_named_task(coro, *args, name=None):
return asyncio.create_task(coro, *args, name=name) return asyncio.create_task(coro, *args, name=name)
coloramaparser = HTMLtoColoramaParser()
class Context(): class Context():
@ -101,6 +100,8 @@ class Context():
self.finished_game = False self.finished_game = False
self.slow_mode = False self.slow_mode = False
self.jsontotextparser = JSONtoTextParser(self)
@property @property
def endpoints(self): def endpoints(self):
if self.server: if self.server:
@ -957,8 +958,8 @@ async def process_server_cmd(ctx: Context, cmd: str, args: typing.Optional[dict]
elif cmd == 'Print': elif cmd == 'Print':
logger.info(args["text"]) logger.info(args["text"])
elif cmd == 'PrintHTML': elif cmd == 'PrintJSON':
logger.info(coloramaparser.get_colorama_text(args["text"])) logger.info(ctx.jsontotextparser(args["data"]))
elif cmd == 'HintPointUpdate': elif cmd == 'HintPointUpdate':
ctx.hint_points = args['points'] ctx.hint_points = args['points']
@ -1411,7 +1412,6 @@ async def main():
help="Turn off emitting a webserver for the webbrowser based user interface.") help="Turn off emitting a webserver for the webbrowser based user interface.")
args = parser.parse_args() args = parser.parse_args()
logging.basicConfig(format='%(message)s', level=getattr(logging, args.loglevel.upper(), logging.INFO)) logging.basicConfig(format='%(message)s', level=getattr(logging, args.loglevel.upper(), logging.INFO))
if args.diff_file: if args.diff_file:
import Patch import Patch
logging.info("Patch file was supplied. Creating sfc rom..") logging.info("Patch file was supplied. Creating sfc rom..")

View File

@ -592,8 +592,8 @@ class CommandMeta(type):
commands = attrs["commands"] = {} commands = attrs["commands"] = {}
for base in bases: for base in bases:
commands.update(base.commands) commands.update(base.commands)
commands.update({name[5:].lower(): method for name, method in attrs.items() if commands.update({command_name[5:]: method for command_name, method in attrs.items() if
name.startswith("_cmd_")}) command_name.startswith("_cmd_")})
return super(CommandMeta, cls).__new__(cls, name, bases, attrs) return super(CommandMeta, cls).__new__(cls, name, bases, attrs)

View File

@ -2,7 +2,6 @@ from __future__ import annotations
import asyncio import asyncio
import logging import logging
import typing import typing
from html.parser import HTMLParser
from json import loads, dumps from json import loads, dumps
import websockets import websockets
@ -55,43 +54,61 @@ class Endpoint:
raise NotImplementedError raise NotImplementedError
class HTMLtoColoramaParser(HTMLParser): class HandlerMeta(type):
def get_colorama_text(self, input_text: str) -> str: def __new__(mcs, name, bases, attrs):
self.feed(input_text) handlers = attrs["handlers"] = {}
self.close() trigger: str = "_handle_"
data = self.data for base in bases:
self.reset() handlers.update(base.commands)
return data handlers.update({handler_name[len(trigger):]: method for handler_name, method in attrs.items() if
handler_name.startswith(trigger)})
def handle_data(self, data): orig_init = attrs.get('__init__', None)
self.data += data
def handle_starttag(self, tag, attrs): def __init__(self, *args, **kwargs):
if tag in {"span", "div", "p"}: # turn functions into bound methods
for attr in attrs: self.handlers = {name: method.__get__(self, type(self)) for name, method in
subtag, data = attr handlers.items()}
if subtag == "style": if orig_init:
for subdata in data.split(";"): orig_init(self, *args, **kwargs)
if subdata.startswith("color"):
color = subdata.split(":", 1)[-1].strip()
if color in color_codes:
self.data += color_code(color)
self.colored = tag
def handle_endtag(self, tag): attrs['__init__'] = __init__
if tag == self.colored: return super(HandlerMeta, mcs).__new__(mcs, name, bases, attrs)
self.colored = False
self.data += color_code("reset")
def reset(self):
super(HTMLtoColoramaParser, self).reset()
self.data = ""
self.colored = False
def close(self): class JSONtoTextParser(metaclass=HandlerMeta):
super(HTMLtoColoramaParser, self).close() def __init__(self, ctx: "MultiClient.Context"):
if self.colored: self.ctx = ctx
self.handle_endtag(self.colored)
def __call__(self, input_object: typing.List[dict]) -> str:
return "".join(self.handle_node(section) for section in input_object)
def handle_node(self, node: dict):
type = node.get("type", None)
handler = self.handlers.get(type, self.handlers["text"])
return handler(node)
def _handle_color(self, node: dict):
if node["color"] in color_codes:
return color_code(node["color"]) + self._handle_text(node) + color_code("reset")
else:
logging.warning(f"Unknown color in node {node}")
return self._handle_text(node)
def _handle_text(self, node: dict):
return node.get("text", "")
def _handle_player_id(self, node: dict):
player = node["player"]
node["color"] = 'yellow' if player != self.ctx.slot else 'magenta'
node["text"] = self.ctx.player_names[player]
return self._handle_color(node)
# for other teams, spectators etc.? Only useful if player isn't in the clientside mapping
def _handle_player_name(self, node: dict):
node["color"] = 'yellow'
return self._handle_color(node)
color_codes = {'reset': 0, 'bold': 1, 'underline': 4, 'black': 30, 'red': 31, 'green': 32, 'yellow': 33, 'blue': 34, color_codes = {'reset': 0, 'bold': 1, 'underline': 4, 'black': 30, 'red': 31, 'green': 32, 'yellow': 33, 'blue': 34,
@ -110,4 +127,4 @@ def color(text, *args):
CLIENT_UNKNOWN = 0 CLIENT_UNKNOWN = 0
CLIENT_READY = 10 CLIENT_READY = 10
CLIENT_PLAYING = 20 CLIENT_PLAYING = 20
CLIENT_GOAL = 30 CLIENT_GOAL = 30