Asciifarm/asciifarm/common/messages.py

158 lines
4.0 KiB
Python

import re
import unicodedata
import json
class InvalidMessageError(Exception):
errType = "invalidmessage"
description = ""
def __init__(self, description="", errType=None):
self.description = description
if errType is not None:
self.errType = errType
def toMessage(self):
return ErrorMessage(self.errType, self.description)
class InvalidNameError(InvalidMessageError):
errType = "invalidname"
class Message:
@classmethod
def msgType(cls):
return cls.typename
def to_json(self):
raise NotImplementedError
def to_json_bytes(self):
return bytes(json.dumps(self.to_json()), "utf-8")
@classmethod
def from_json(cls, jsonobj):
raise NotImplementedError
class ClientToServerMessage(Message):
def body(self):
raise NotImplementedError
def to_json(self):
return [self.typename, self.body()]
@classmethod
def from_json(cls, jsonlist):
assert len(jsonlist) == 2, InvalidMessageError
typename, body = jsonlist
assert typename == cls.msgType(), InvalidMessageError
return cls(body)
class NameMessage(ClientToServerMessage):
typename = "name"
categories = {"Lu", "Ll", "Lt", "Lm", "Lo", "Nd", "Nl", "No", "Pc"}
def __init__(self, name):
assert isinstance(name, str), InvalidNameError("name must be a string")
assert (len(name) > 0), InvalidNameError("name needs at least one character")
assert (len(bytes(name, "utf-8")) <= 256), InvalidNameError("name may not be longer than 256 utf8 bytes")
if name[0] != "~":
for char in name:
category = unicodedata.category(char)
assert category in self.categories, InvalidNameError("all name caracters must be in these unicode categories: " + "|".join(self.categories) + " (except for tildenames)")
self.name = name
def body(self):
return self.name
class InputMessage(ClientToServerMessage):
typename = "input"
def __init__(self, inp):
self.inp = inp
def body(self):
return self.inp
class ChatMessage(ClientToServerMessage):
typename = "chat"
def __init__(self, text):
assert isinstance(text, str), InvalidMessageError("chat message must be a string")
assert text.isprintable(), InvalidMessageError("chat messages may only contain printable unicode characters")
self.text = text
def body(self):
return self.text
class ServerToClientMessage(Message):
msglen = 0
@classmethod
def from_json(cls, jsonlist):
assert len(jsonlist) == cls.msglen, InvalidMessageError
assert jsonlist[0] == cls.msgType(), InvalidMessageError
return cls(*jsonlist[1:])
class MessageMessage(ServerToClientMessage): # this name feels stupid
""" A message to inform the client. This is meant to be read by the user"""
typename = "message"
msglen = 3
def __init__(self, text, type=""):
self.text = text
self.type = type
def to_json(self):
return [self.typename, self.text, self.type]
class WorldMessage(ServerToClientMessage):
""" A message about the world state """
typename = "world"
msglen = 2
def __init__(self, updates):
assert isinstance(updates, list), InvalidMessageError
self.updates = updates
def to_json(self):
return [self.typename, self.updates]
class ErrorMessage(ServerToClientMessage):
typename = "error"
msglen = 3
def __init__(self, errType, description=""):
self.errType = errType
self.description = description
def to_json(self):
return [self.typename, self.errType, self.description]
messages = {message.msgType(): message for message in [
NameMessage,
InputMessage,
ChatMessage,
WorldMessage,
ErrorMessage,
MessageMessage
]}