76 lines
2.5 KiB
Python
76 lines
2.5 KiB
Python
import base64
|
|
import re
|
|
from io import BytesIO
|
|
from amqp.model.model import AMQResponse
|
|
from amqp.model.snowflake_id import SnowflakeId
|
|
from amqp.router.serializer import parse_map_string, map_as_string
|
|
|
|
|
|
class AMQResponseFactory:
|
|
MAGIC_BYTE_HTTP_REQUEST = "A"
|
|
|
|
@staticmethod
|
|
def create_async_response_message(_id: SnowflakeId) -> AMQResponse:
|
|
return AMQResponse(
|
|
str(_id), 200, "application/text", "OK".encode("utf-8"), "", "", {}
|
|
)
|
|
|
|
@staticmethod
|
|
def serialize(response: AMQResponse) -> bytes:
|
|
id_bytes = response.id.encode('utf-8')
|
|
prolog = (
|
|
f"|r={response.response_code}|c={response.content_type}|e={response.error}|f={response.error_cause}|t={{{map_as_string(response.trace_info)}}}|b="
|
|
).encode('utf-8')
|
|
header_length = 1 + len(id_bytes) + len(prolog)
|
|
prolog_len = header_length.to_bytes(2, byteorder='big')
|
|
msg_length = 2 + header_length + len(response.response)
|
|
with BytesIO(bytearray(msg_length)) as baos:
|
|
baos.write(prolog_len)
|
|
baos.write(AMQResponseFactory.MAGIC_BYTE_HTTP_REQUEST.encode('utf-8'))
|
|
baos.write(id_bytes)
|
|
baos.write(prolog)
|
|
baos.write(base64.b64encode(response.response))
|
|
return baos.getvalue()
|
|
|
|
@staticmethod
|
|
def from_bytes(input_bytes: bytes) -> AMQResponse:
|
|
prolog_len = (input_bytes[0] << 8) + input_bytes[1]
|
|
metadata = input_bytes[2:prolog_len + 2].decode()
|
|
|
|
pattern = re.compile(
|
|
f"{AMQResponseFactory.MAGIC_BYTE_HTTP_REQUEST}"
|
|
r"([0-9A-Fa-f]+)\|"
|
|
r"r=([^|]*)\|"
|
|
r"c=([^|]*)\|"
|
|
r"e=([^|]*)\|"
|
|
r"f=([^|]*)\|"
|
|
r"t=(\{[^}]*\})\|"
|
|
r"b="
|
|
)
|
|
match = pattern.match(metadata)
|
|
if not match:
|
|
raise ValueError(
|
|
f"AMQResponse format does not match expected format. "
|
|
f"Input string [{metadata}] does not match pattern: {pattern.pattern}"
|
|
)
|
|
|
|
id_str = match.group(1)
|
|
response_code = int(match.group(2))
|
|
content_type = match.group(3)
|
|
error = match.group(4)
|
|
error_cause = match.group(5)
|
|
trace_info_str = match.group(6)
|
|
body_b64 = input_bytes[prolog_len + 2:]
|
|
|
|
trace_info = parse_map_string(trace_info_str)
|
|
|
|
return AMQResponse(
|
|
id_str,
|
|
response_code,
|
|
content_type,
|
|
base64.b64decode(body_b64),
|
|
error,
|
|
error_cause,
|
|
trace_info,
|
|
)
|