Source code for evennia.server.portal.wire_formats.evennia_v1
"""
Evennia V1 wire format (v1.evennia.com).
This is Evennia's legacy WebSocket wire format. All messages are UTF-8
JSON text frames in the form:
["cmdname", [args], {kwargs}]
Text output is HTML-converted from ANSI before sending. This format
is used by Evennia's built-in webclient and is the default when no
WebSocket subprotocol is negotiated.
"""
import html
import json
from evennia.utils.ansi import parse_ansi
from evennia.utils.text2html import parse_html
from .base import _RE_SCREENREADER_REGEX, WireFormat
[docs]
class EvenniaV1Format(WireFormat):
"""
Evennia's legacy wire format: JSON arrays over TEXT frames.
Wire format:
All frames are TEXT (UTF-8 JSON).
Structure: ["cmdname", [args], {kwargs}]
Text handling:
Outgoing text is converted from ANSI to HTML via parse_html().
OOB:
All commands are effectively OOB — the cmdname field can be
any string, not just "text".
"""
name = "v1.evennia.com"
supports_oob = True
[docs]
def decode_incoming(self, payload, is_binary, protocol_flags=None):
"""
Decode incoming JSON array message.
Args:
payload (bytes): UTF-8 encoded JSON: ["cmdname", [args], {kwargs}]
is_binary (bool): Should be False for this format.
protocol_flags (dict, optional): Not used by this format.
Returns:
dict or None: kwargs for data_in(), e.g. {"text": [["look"], {}]}
"""
try:
cmdarray = json.loads(str(payload, "utf-8"))
except (json.JSONDecodeError, UnicodeDecodeError):
return None
if isinstance(cmdarray, (list, tuple)) and len(cmdarray) >= 3:
return {cmdarray[0]: [cmdarray[1], cmdarray[2]]}
return None
[docs]
def encode_text(self, *args, protocol_flags=None, **kwargs):
"""
Encode text output as HTML-converted JSON.
Converts ANSI color codes to HTML spans, applies screenreader
and raw text options.
Returns:
tuple or None: (json_bytes, False) where False means TEXT frame.
"""
if args:
args = list(args)
text = args[0]
if text is None:
return None
else:
return None
flags = protocol_flags or {}
options = kwargs.pop("options", {})
raw = options.get("raw", flags.get("RAW", False))
client_raw = options.get("client_raw", False)
nocolor = options.get("nocolor", flags.get("NOCOLOR", False))
screenreader = options.get("screenreader", flags.get("SCREENREADER", False))
prompt = options.get("send_prompt", False)
if screenreader:
text = parse_ansi(text, strip_ansi=True, xterm256=False, mxp=False)
text = _RE_SCREENREADER_REGEX.sub("", text)
cmd = "prompt" if prompt else "text"
if raw:
if client_raw:
args[0] = text
else:
args[0] = html.escape(text)
else:
args[0] = parse_html(text, strip_ansi=nocolor)
return (json.dumps([cmd, args, kwargs]).encode("utf-8"), False)
[docs]
def encode_prompt(self, *args, protocol_flags=None, **kwargs):
"""
Encode a prompt as HTML-converted JSON with send_prompt flag.
Returns:
tuple or None: (json_bytes, False) for TEXT frame.
"""
options = kwargs.get("options", {})
options["send_prompt"] = True
kwargs["options"] = options
return self.encode_text(*args, protocol_flags=protocol_flags, **kwargs)
[docs]
def encode_default(self, cmdname, *args, protocol_flags=None, **kwargs):
"""
Encode any OOB command as a JSON array.
Skips the "options" command (legacy behavior).
Returns:
tuple or None: (json_bytes, False) for TEXT frame, or None
if cmdname is "options".
"""
if cmdname == "options":
return None
return (json.dumps([cmdname, args, kwargs]).encode("utf-8"), False)