feat: speed up unmarshall performance (#71)
This commit is contained in:
@@ -16,8 +16,15 @@ bluez_rssi_message = (
|
|||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
|
stream = io.BytesIO(bytes.fromhex(bluez_rssi_message))
|
||||||
|
|
||||||
|
unmarshaller = Unmarshaller(stream)
|
||||||
|
|
||||||
|
|
||||||
def unmarhsall_bluez_rssi_message():
|
def unmarhsall_bluez_rssi_message():
|
||||||
Unmarshaller(io.BytesIO(bytes.fromhex(bluez_rssi_message))).unmarshall()
|
stream.seek(0)
|
||||||
|
unmarshaller.reset()
|
||||||
|
unmarshaller.unmarshall()
|
||||||
|
|
||||||
|
|
||||||
count = 1000000
|
count = 1000000
|
||||||
|
|||||||
@@ -35,8 +35,15 @@ bluez_properties_message = (
|
|||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
|
stream = io.BytesIO(bluez_properties_message)
|
||||||
|
|
||||||
|
unmarshaller = Unmarshaller(stream)
|
||||||
|
|
||||||
|
|
||||||
def unmarhsall_bluez_rssi_message():
|
def unmarhsall_bluez_rssi_message():
|
||||||
Unmarshaller(io.BytesIO(bluez_properties_message)).unmarshall()
|
stream.seek(0)
|
||||||
|
unmarshaller.reset()
|
||||||
|
unmarshaller.unmarshall()
|
||||||
|
|
||||||
|
|
||||||
count = 1000000
|
count = 1000000
|
||||||
|
|||||||
@@ -8,25 +8,30 @@ from ..signature import SignatureType
|
|||||||
cdef unsigned int UINT32_SIZE
|
cdef unsigned int UINT32_SIZE
|
||||||
cdef unsigned int HEADER_ARRAY_OF_STRUCT_SIGNATURE_POSITION
|
cdef unsigned int HEADER_ARRAY_OF_STRUCT_SIGNATURE_POSITION
|
||||||
cdef unsigned int HEADER_SIGNATURE_SIZE
|
cdef unsigned int HEADER_SIGNATURE_SIZE
|
||||||
|
cdef unsigned int LITTLE_ENDIAN
|
||||||
|
cdef unsigned int BIG_ENDIAN
|
||||||
|
cdef str UINT32_CAST
|
||||||
|
cdef object UINT32_SIGNATURE
|
||||||
|
|
||||||
cdef class Unmarshaller:
|
cdef class Unmarshaller:
|
||||||
|
|
||||||
cdef object unix_fds
|
cdef object _unix_fds
|
||||||
cdef bytearray buf
|
cdef bytearray _buf
|
||||||
cdef object view
|
cdef object _view
|
||||||
cdef unsigned int pos
|
cdef unsigned int _pos
|
||||||
cdef object stream
|
cdef object _stream
|
||||||
cdef object sock
|
cdef object _sock
|
||||||
cdef object _message
|
cdef object _message
|
||||||
cdef object readers
|
cdef object _readers
|
||||||
cdef unsigned int body_len
|
cdef unsigned int _body_len
|
||||||
cdef unsigned int serial
|
cdef unsigned int _serial
|
||||||
cdef unsigned int header_len
|
cdef unsigned int _header_len
|
||||||
cdef object message_type
|
cdef unsigned int _message_type
|
||||||
cdef object flag
|
cdef unsigned int _flag
|
||||||
cdef unsigned int msg_len
|
cdef unsigned int _msg_len
|
||||||
cdef object _uint32_unpack
|
cdef object _uint32_unpack
|
||||||
|
|
||||||
|
cpdef reset(self)
|
||||||
|
|
||||||
@cython.locals(
|
@cython.locals(
|
||||||
start_len=cython.ulong,
|
start_len=cython.ulong,
|
||||||
@@ -56,6 +61,7 @@ cdef class Unmarshaller:
|
|||||||
@cython.locals(
|
@cython.locals(
|
||||||
endian=cython.uint,
|
endian=cython.uint,
|
||||||
protocol_version=cython.uint,
|
protocol_version=cython.uint,
|
||||||
|
can_cast=cython.bint
|
||||||
)
|
)
|
||||||
cpdef _read_header(self)
|
cpdef _read_header(self)
|
||||||
|
|
||||||
|
|||||||
@@ -65,8 +65,8 @@ def cast_parser_factory(ctype: str, size: int) -> READER_TYPE:
|
|||||||
"""Build a parser that casts the bytes to the given ctype."""
|
"""Build a parser that casts the bytes to the given ctype."""
|
||||||
|
|
||||||
def _cast_parser(self: "Unmarshaller", signature: SignatureType) -> Any:
|
def _cast_parser(self: "Unmarshaller", signature: SignatureType) -> Any:
|
||||||
self.pos += size + (-self.pos & (size - 1)) # align
|
self._pos += size + (-self._pos & (size - 1)) # align
|
||||||
return self.view[self.pos - size : self.pos].cast(ctype)[0]
|
return self._view[self._pos - size : self._pos].cast(ctype)[0]
|
||||||
|
|
||||||
return _cast_parser
|
return _cast_parser
|
||||||
|
|
||||||
@@ -75,8 +75,8 @@ def unpack_parser_factory(unpack_from: Callable, size: int) -> READER_TYPE:
|
|||||||
"""Build a parser that unpacks the bytes using the given unpack_from function."""
|
"""Build a parser that unpacks the bytes using the given unpack_from function."""
|
||||||
|
|
||||||
def _unpack_from_parser(self: "Unmarshaller", signature: SignatureType) -> Any:
|
def _unpack_from_parser(self: "Unmarshaller", signature: SignatureType) -> Any:
|
||||||
self.pos += size + (-self.pos & (size - 1)) # align
|
self._pos += size + (-self._pos & (size - 1)) # align
|
||||||
return unpack_from(self.view, self.pos - size)[0]
|
return unpack_from(self._view, self._pos - size)[0]
|
||||||
|
|
||||||
return _unpack_from_parser
|
return _unpack_from_parser
|
||||||
|
|
||||||
@@ -129,41 +129,59 @@ class MarshallerStreamEndError(Exception):
|
|||||||
class Unmarshaller:
|
class Unmarshaller:
|
||||||
|
|
||||||
__slots__ = (
|
__slots__ = (
|
||||||
"unix_fds",
|
"_unix_fds",
|
||||||
"buf",
|
"_buf",
|
||||||
"view",
|
"_view",
|
||||||
"pos",
|
"_pos",
|
||||||
"stream",
|
"_stream",
|
||||||
"sock",
|
"_sock",
|
||||||
"_message",
|
"_message",
|
||||||
"readers",
|
"_readers",
|
||||||
"body_len",
|
"_body_len",
|
||||||
"serial",
|
"_serial",
|
||||||
"header_len",
|
"_header_len",
|
||||||
"message_type",
|
"_message_type",
|
||||||
"flag",
|
"_flag",
|
||||||
"msg_len",
|
"_msg_len",
|
||||||
"_uint32_unpack",
|
"_uint32_unpack",
|
||||||
)
|
)
|
||||||
|
|
||||||
def __init__(self, stream: io.BufferedRWPair, sock=None):
|
def __init__(self, stream: io.BufferedRWPair, sock=None):
|
||||||
self.unix_fds: List[int] = []
|
self._unix_fds: List[int] = []
|
||||||
self.buf = bytearray() # Actual buffer
|
self._buf = bytearray() # Actual buffer
|
||||||
self.view = None # Memory view of the buffer
|
self._view = None # Memory view of the buffer
|
||||||
self.pos = 0
|
self._stream = stream
|
||||||
self.stream = stream
|
self._sock = sock
|
||||||
self.sock = sock
|
|
||||||
self._message: Message | None = None
|
self._message: Message | None = None
|
||||||
self.readers: Dict[str, READER_TYPE] = {}
|
self._readers: Dict[str, READER_TYPE] = {}
|
||||||
self.body_len = 0
|
self._pos = 0
|
||||||
self.serial = 0
|
self._body_len = 0
|
||||||
self.header_len = 0
|
self._serial = 0
|
||||||
self.message_type: MessageType | None = None
|
self._header_len = 0
|
||||||
self.flag: MessageFlag | None = None
|
self._message_type = 0
|
||||||
self.msg_len = 0
|
self._flag = 0
|
||||||
|
self._msg_len = 0
|
||||||
# Only set if we cannot cast
|
# Only set if we cannot cast
|
||||||
self._uint32_unpack: Callable | None = None
|
self._uint32_unpack: Callable | None = None
|
||||||
|
|
||||||
|
def reset(self) -> None:
|
||||||
|
"""Reset the unmarshaller to its initial state.
|
||||||
|
|
||||||
|
Call this before processing a new message.
|
||||||
|
"""
|
||||||
|
self._unix_fds: List[int] = []
|
||||||
|
self._view = None
|
||||||
|
self._buf.clear()
|
||||||
|
self._message = None
|
||||||
|
self._pos = 0
|
||||||
|
self._body_len = 0
|
||||||
|
self._serial = 0
|
||||||
|
self._header_len = 0
|
||||||
|
self._message_type = 0
|
||||||
|
self._flag = 0
|
||||||
|
self._msg_len = 0
|
||||||
|
self._uint32_unpack = None
|
||||||
|
|
||||||
@property
|
@property
|
||||||
def message(self) -> Message:
|
def message(self) -> Message:
|
||||||
"""Return the message that has been unmarshalled."""
|
"""Return the message that has been unmarshalled."""
|
||||||
@@ -175,7 +193,7 @@ class Unmarshaller:
|
|||||||
unix_fd_list = array.array("i")
|
unix_fd_list = array.array("i")
|
||||||
|
|
||||||
try:
|
try:
|
||||||
msg, ancdata, *_ = self.sock.recvmsg(
|
msg, ancdata, *_ = self._sock.recvmsg(
|
||||||
length, socket.CMSG_LEN(MAX_UNIX_FDS * unix_fd_list.itemsize)
|
length, socket.CMSG_LEN(MAX_UNIX_FDS * unix_fd_list.itemsize)
|
||||||
)
|
)
|
||||||
except BlockingIOError:
|
except BlockingIOError:
|
||||||
@@ -187,7 +205,7 @@ class Unmarshaller:
|
|||||||
unix_fd_list.frombytes(
|
unix_fd_list.frombytes(
|
||||||
data[: len(data) - (len(data) % unix_fd_list.itemsize)]
|
data[: len(data) - (len(data) % unix_fd_list.itemsize)]
|
||||||
)
|
)
|
||||||
self.unix_fds.extend(list(unix_fd_list))
|
self._unix_fds.extend(list(unix_fd_list))
|
||||||
|
|
||||||
return msg
|
return msg
|
||||||
|
|
||||||
@@ -204,127 +222,130 @@ class Unmarshaller:
|
|||||||
:returns:
|
:returns:
|
||||||
None
|
None
|
||||||
"""
|
"""
|
||||||
start_len = len(self.buf)
|
start_len = len(self._buf)
|
||||||
missing_bytes = pos - (start_len - self.pos)
|
missing_bytes = pos - (start_len - self._pos)
|
||||||
if self.sock is None:
|
if self._sock is None:
|
||||||
data = self.stream.read(missing_bytes)
|
data = self._stream.read(missing_bytes)
|
||||||
else:
|
else:
|
||||||
data = self.read_sock(missing_bytes)
|
data = self.read_sock(missing_bytes)
|
||||||
if data == b"":
|
if data == b"":
|
||||||
raise EOFError()
|
raise EOFError()
|
||||||
if data is None:
|
if data is None:
|
||||||
raise MarshallerStreamEndError()
|
raise MarshallerStreamEndError()
|
||||||
self.buf.extend(data)
|
self._buf.extend(data)
|
||||||
if len(data) + start_len != pos:
|
if len(data) + start_len != pos:
|
||||||
raise MarshallerStreamEndError()
|
raise MarshallerStreamEndError()
|
||||||
|
|
||||||
def read_uint32_cast(self, signature: SignatureType) -> Any:
|
def read_uint32_cast(self, signature: SignatureType) -> Any:
|
||||||
self.pos += UINT32_SIZE + (-self.pos & (UINT32_SIZE - 1)) # align
|
self._pos += UINT32_SIZE + (-self._pos & (UINT32_SIZE - 1)) # align
|
||||||
return self.view[self.pos - UINT32_SIZE : self.pos].cast(UINT32_CAST)[0]
|
return self._view[self._pos - UINT32_SIZE : self._pos].cast(UINT32_CAST)[0]
|
||||||
|
|
||||||
def read_boolean(self, type_=None) -> bool:
|
def read_boolean(self, type_=None) -> bool:
|
||||||
return bool(self.readers[UINT32_SIGNATURE.token](self, UINT32_SIGNATURE))
|
return bool(self._readers[UINT32_SIGNATURE.token](self, UINT32_SIGNATURE))
|
||||||
|
|
||||||
def read_string_cast(self, type_=None) -> str:
|
def read_string_cast(self, type_=None) -> str:
|
||||||
"""Read a string using cast."""
|
"""Read a string using cast."""
|
||||||
self.pos += UINT32_SIZE + (-self.pos & (UINT32_SIZE - 1)) # align
|
self._pos += UINT32_SIZE + (-self._pos & (UINT32_SIZE - 1)) # align
|
||||||
str_start = self.pos
|
str_start = self._pos
|
||||||
# read terminating '\0' byte as well (str_length + 1)
|
# read terminating '\0' byte as well (str_length + 1)
|
||||||
start_pos = self.pos - UINT32_SIZE
|
start_pos = self._pos - UINT32_SIZE
|
||||||
self.pos += self.view[start_pos : self.pos].cast(UINT32_CAST)[0] + 1
|
self._pos += self._view[start_pos : self._pos].cast(UINT32_CAST)[0] + 1
|
||||||
return self.buf[str_start : self.pos - 1].decode()
|
return self._buf[str_start : self._pos - 1].decode()
|
||||||
|
|
||||||
def read_string_unpack(self, type_=None) -> str:
|
def read_string_unpack(self, type_=None) -> str:
|
||||||
"""Read a string using unpack."""
|
"""Read a string using unpack."""
|
||||||
self.pos += UINT32_SIZE + (-self.pos & (UINT32_SIZE - 1)) # align
|
self._pos += UINT32_SIZE + (-self._pos & (UINT32_SIZE - 1)) # align
|
||||||
str_start = self.pos
|
str_start = self._pos
|
||||||
# read terminating '\0' byte as well (str_length + 1)
|
# read terminating '\0' byte as well (str_length + 1)
|
||||||
self.pos += self._uint32_unpack(self.view, str_start - UINT32_SIZE)[0] + 1
|
self._pos += self._uint32_unpack(self._view, str_start - UINT32_SIZE)[0] + 1
|
||||||
return self.buf[str_start : self.pos - 1].decode()
|
return self._buf[str_start : self._pos - 1].decode()
|
||||||
|
|
||||||
def read_signature(self, type_=None) -> str:
|
def read_signature(self, type_=None) -> str:
|
||||||
signature_len = self.view[self.pos] # byte
|
signature_len = self._view[self._pos] # byte
|
||||||
o = self.pos + 1
|
o = self._pos + 1
|
||||||
# read terminating '\0' byte as well (str_length + 1)
|
# read terminating '\0' byte as well (str_length + 1)
|
||||||
self.pos = o + signature_len + 1
|
self._pos = o + signature_len + 1
|
||||||
return self.buf[o : o + signature_len].decode()
|
return self._buf[o : o + signature_len].decode()
|
||||||
|
|
||||||
def read_variant(self, type_=None) -> Variant:
|
def read_variant(self, type_=None) -> Variant:
|
||||||
tree = SignatureTree._get(self.read_signature())
|
tree = SignatureTree._get(self.read_signature())
|
||||||
# verify in Variant is only useful on construction not unmarshalling
|
# verify in Variant is only useful on construction not unmarshalling
|
||||||
return Variant(
|
return Variant(
|
||||||
tree, self.readers[tree.types[0].token](self, tree.types[0]), verify=False
|
tree, self._readers[tree.types[0].token](self, tree.types[0]), verify=False
|
||||||
)
|
)
|
||||||
|
|
||||||
def read_struct(self, type_=None) -> List[Any]:
|
def read_struct(self, type_=None) -> List[Any]:
|
||||||
self.pos += -self.pos & 7 # align 8
|
self._pos += -self._pos & 7 # align 8
|
||||||
readers = self.readers
|
readers = self._readers
|
||||||
return [
|
return [
|
||||||
readers[child_type.token](self, child_type) for child_type in type_.children
|
readers[child_type.token](self, child_type) for child_type in type_.children
|
||||||
]
|
]
|
||||||
|
|
||||||
def read_dict_entry(self, type_: SignatureType) -> Dict[Any, Any]:
|
def read_dict_entry(self, type_: SignatureType) -> Dict[Any, Any]:
|
||||||
self.pos += -self.pos & 7 # align 8
|
self._pos += -self._pos & 7 # align 8
|
||||||
return self.readers[type_.children[0].token](
|
return self._readers[type_.children[0].token](
|
||||||
self, type_.children[0]
|
self, type_.children[0]
|
||||||
), self.readers[type_.children[1].token](self, type_.children[1])
|
), self._readers[type_.children[1].token](self, type_.children[1])
|
||||||
|
|
||||||
def read_array(self, type_: SignatureType) -> List[Any]:
|
def read_array(self, type_: SignatureType) -> List[Any]:
|
||||||
self.pos += -self.pos & 3 # align 4 for the array
|
self._pos += -self._pos & 3 # align 4 for the array
|
||||||
self.pos += (
|
self._pos += (
|
||||||
-self.pos & (UINT32_SIZE - 1)
|
-self._pos & (UINT32_SIZE - 1)
|
||||||
) + UINT32_SIZE # align for the uint32
|
) + UINT32_SIZE # align for the uint32
|
||||||
if self._uint32_unpack:
|
if self._uint32_unpack:
|
||||||
array_length = self._uint32_unpack(self.view, self.pos - UINT32_SIZE)[0]
|
array_length = self._uint32_unpack(self._view, self._pos - UINT32_SIZE)[0]
|
||||||
else:
|
else:
|
||||||
array_length = self.view[self.pos - UINT32_SIZE : self.pos].cast(
|
array_length = self._view[self._pos - UINT32_SIZE : self._pos].cast(
|
||||||
UINT32_CAST
|
UINT32_CAST
|
||||||
)[0]
|
)[0]
|
||||||
|
|
||||||
child_type = type_.children[0]
|
child_type = type_.children[0]
|
||||||
if child_type.token in "xtd{(":
|
token = child_type.token
|
||||||
|
|
||||||
|
if token in "xtd{(":
|
||||||
# the first alignment is not included in the array size
|
# the first alignment is not included in the array size
|
||||||
self.pos += -self.pos & 7 # align 8
|
self._pos += -self._pos & 7 # align 8
|
||||||
|
|
||||||
if child_type.token == "y":
|
if token == "y":
|
||||||
self.pos += array_length
|
self._pos += array_length
|
||||||
return self.buf[self.pos - array_length : self.pos]
|
return self._buf[self._pos - array_length : self._pos]
|
||||||
|
|
||||||
beginning_pos = self.pos
|
beginning_pos = self._pos
|
||||||
readers = self.readers
|
readers = self._readers
|
||||||
|
|
||||||
if child_type.token == "{":
|
if token == "{":
|
||||||
result_dict = {}
|
result_dict = {}
|
||||||
while self.pos - beginning_pos < array_length:
|
child_0 = child_type.children[0]
|
||||||
self.pos += -self.pos & 7 # align 8
|
reader_0 = readers[child_0.token]
|
||||||
key = readers[child_type.children[0].token](
|
child_1 = child_type.children[1]
|
||||||
self, child_type.children[0]
|
reader_1 = readers[child_1.token]
|
||||||
)
|
while self._pos - beginning_pos < array_length:
|
||||||
result_dict[key] = readers[child_type.children[1].token](
|
self._pos += -self._pos & 7 # align 8
|
||||||
self, child_type.children[1]
|
key = reader_0(self, child_0)
|
||||||
)
|
result_dict[key] = reader_1(self, child_1)
|
||||||
return result_dict
|
return result_dict
|
||||||
|
|
||||||
result_list = []
|
result_list = []
|
||||||
while self.pos - beginning_pos < array_length:
|
reader = readers[child_type.token]
|
||||||
result_list.append(readers[child_type.token](self, child_type))
|
while self._pos - beginning_pos < array_length:
|
||||||
|
result_list.append(reader(self, child_type))
|
||||||
return result_list
|
return result_list
|
||||||
|
|
||||||
def header_fields(self, header_length) -> Dict[str, Any]:
|
def header_fields(self, header_length) -> Dict[str, Any]:
|
||||||
"""Header fields are always a(yv)."""
|
"""Header fields are always a(yv)."""
|
||||||
beginning_pos = self.pos
|
beginning_pos = self._pos
|
||||||
headers = {}
|
headers = {}
|
||||||
while self.pos - beginning_pos < header_length:
|
while self._pos - beginning_pos < header_length:
|
||||||
# Now read the y (byte) of struct (yv)
|
# Now read the y (byte) of struct (yv)
|
||||||
self.pos += (-self.pos & 7) + 1 # align 8 + 1 for 'y' byte
|
self._pos += (-self._pos & 7) + 1 # align 8 + 1 for 'y' byte
|
||||||
field_0 = self.view[self.pos - 1]
|
field_0 = self._view[self._pos - 1]
|
||||||
|
|
||||||
# Now read the v (variant) of struct (yv)
|
# Now read the v (variant) of struct (yv)
|
||||||
signature_len = self.view[self.pos] # byte
|
signature_len = self._view[self._pos] # byte
|
||||||
o = self.pos + 1
|
o = self._pos + 1
|
||||||
self.pos += signature_len + 2 # one for the byte, one for the '\0'
|
self._pos += signature_len + 2 # one for the byte, one for the '\0'
|
||||||
tree = SignatureTree._get(self.buf[o : o + signature_len].decode())
|
tree = SignatureTree._get(self._buf[o : o + signature_len].decode())
|
||||||
headers[HEADER_NAME_MAP[field_0]] = self.readers[tree.types[0].token](
|
headers[HEADER_NAME_MAP[field_0]] = self._readers[tree.types[0].token](
|
||||||
self, tree.types[0]
|
self, tree.types[0]
|
||||||
)
|
)
|
||||||
return headers
|
return headers
|
||||||
@@ -334,10 +355,10 @@ class Unmarshaller:
|
|||||||
# Signature is of the header is
|
# Signature is of the header is
|
||||||
# BYTE, BYTE, BYTE, BYTE, UINT32, UINT32, ARRAY of STRUCT of (BYTE,VARIANT)
|
# BYTE, BYTE, BYTE, BYTE, UINT32, UINT32, ARRAY of STRUCT of (BYTE,VARIANT)
|
||||||
self.read_to_pos(HEADER_SIGNATURE_SIZE)
|
self.read_to_pos(HEADER_SIGNATURE_SIZE)
|
||||||
buffer = self.buf
|
buffer = self._buf
|
||||||
endian = buffer[0]
|
endian = buffer[0]
|
||||||
self.message_type = MESSAGE_TYPE_MAP[buffer[1]]
|
self._message_type = buffer[1]
|
||||||
self.flag = MESSAGE_FLAG_MAP[buffer[2]]
|
self._flag = buffer[2]
|
||||||
protocol_version = buffer[3]
|
protocol_version = buffer[3]
|
||||||
|
|
||||||
if endian != LITTLE_ENDIAN and endian != BIG_ENDIAN:
|
if endian != LITTLE_ENDIAN and endian != BIG_ENDIAN:
|
||||||
@@ -349,44 +370,44 @@ class Unmarshaller:
|
|||||||
f"got unknown protocol version: {protocol_version}"
|
f"got unknown protocol version: {protocol_version}"
|
||||||
)
|
)
|
||||||
|
|
||||||
self.body_len, self.serial, self.header_len = UNPACK_LENGTHS[
|
self._body_len, self._serial, self._header_len = UNPACK_LENGTHS[
|
||||||
endian
|
endian
|
||||||
].unpack_from(buffer, 4)
|
].unpack_from(buffer, 4)
|
||||||
self.msg_len = (
|
self._msg_len = (
|
||||||
self.header_len + (-self.header_len & 7) + self.body_len
|
self._header_len + (-self._header_len & 7) + self._body_len
|
||||||
) # align 8
|
) # align 8
|
||||||
can_cast = bool(
|
can_cast = bool(
|
||||||
(IS_LITTLE_ENDIAN and endian == LITTLE_ENDIAN)
|
(IS_LITTLE_ENDIAN and endian == LITTLE_ENDIAN)
|
||||||
or (IS_BIG_ENDIAN and endian == BIG_ENDIAN)
|
or (IS_BIG_ENDIAN and endian == BIG_ENDIAN)
|
||||||
)
|
)
|
||||||
self.readers = self._readers_by_type[(endian, can_cast)]
|
self._readers = self._readers_by_type[(endian, can_cast)]
|
||||||
if not can_cast:
|
if not can_cast:
|
||||||
self._uint32_unpack = UINT32_UNPACK_BY_ENDIAN[endian]
|
self._uint32_unpack = UINT32_UNPACK_BY_ENDIAN[endian]
|
||||||
|
|
||||||
def _read_body(self):
|
def _read_body(self):
|
||||||
"""Read the body of the message."""
|
"""Read the body of the message."""
|
||||||
self.read_to_pos(HEADER_SIGNATURE_SIZE + self.msg_len)
|
self.read_to_pos(HEADER_SIGNATURE_SIZE + self._msg_len)
|
||||||
self.view = memoryview(self.buf)
|
self._view = memoryview(self._buf)
|
||||||
self.pos = HEADER_ARRAY_OF_STRUCT_SIGNATURE_POSITION
|
self._pos = HEADER_ARRAY_OF_STRUCT_SIGNATURE_POSITION
|
||||||
header_fields = self.header_fields(self.header_len)
|
header_fields = self.header_fields(self._header_len)
|
||||||
self.pos += -self.pos & 7 # align 8
|
self._pos += -self._pos & 7 # align 8
|
||||||
tree = SignatureTree._get(header_fields.get(HeaderField.SIGNATURE.name, ""))
|
tree = SignatureTree._get(header_fields.get(HeaderField.SIGNATURE.name, ""))
|
||||||
self._message = Message(
|
self._message = Message(
|
||||||
destination=header_fields.get(HEADER_DESTINATION),
|
destination=header_fields.get(HEADER_DESTINATION),
|
||||||
path=header_fields.get(HEADER_PATH),
|
path=header_fields.get(HEADER_PATH),
|
||||||
interface=header_fields.get(HEADER_INTERFACE),
|
interface=header_fields.get(HEADER_INTERFACE),
|
||||||
member=header_fields.get(HEADER_MEMBER),
|
member=header_fields.get(HEADER_MEMBER),
|
||||||
message_type=self.message_type,
|
message_type=MESSAGE_TYPE_MAP[self._message_type],
|
||||||
flags=self.flag,
|
flags=MESSAGE_FLAG_MAP[self._flag],
|
||||||
error_name=header_fields.get(HEADER_ERROR_NAME),
|
error_name=header_fields.get(HEADER_ERROR_NAME),
|
||||||
reply_serial=header_fields.get(HEADER_REPLY_SERIAL),
|
reply_serial=header_fields.get(HEADER_REPLY_SERIAL),
|
||||||
sender=header_fields.get(HEADER_SENDER),
|
sender=header_fields.get(HEADER_SENDER),
|
||||||
unix_fds=self.unix_fds,
|
unix_fds=self._unix_fds,
|
||||||
signature=tree.signature,
|
signature=tree,
|
||||||
body=[self.readers[t.token](self, t) for t in tree.types]
|
body=[self._readers[t.token](self, t) for t in tree.types]
|
||||||
if self.body_len
|
if self._body_len
|
||||||
else [],
|
else [],
|
||||||
serial=self.serial,
|
serial=self._serial,
|
||||||
# The D-Bus implementation already validates the message,
|
# The D-Bus implementation already validates the message,
|
||||||
# so we don't need to do it again.
|
# so we don't need to do it again.
|
||||||
validate=False,
|
validate=False,
|
||||||
@@ -400,7 +421,7 @@ class Unmarshaller:
|
|||||||
to be resumed when more data comes in over the wire.
|
to be resumed when more data comes in over the wire.
|
||||||
"""
|
"""
|
||||||
try:
|
try:
|
||||||
if not self.msg_len:
|
if not self._msg_len:
|
||||||
self._read_header()
|
self._read_header()
|
||||||
self._read_body()
|
self._read_body()
|
||||||
except MarshallerStreamEndError:
|
except MarshallerStreamEndError:
|
||||||
|
|||||||
@@ -2,6 +2,7 @@ import array
|
|||||||
import asyncio
|
import asyncio
|
||||||
import logging
|
import logging
|
||||||
import socket
|
import socket
|
||||||
|
import traceback
|
||||||
from collections import deque
|
from collections import deque
|
||||||
from copy import copy
|
from copy import copy
|
||||||
from typing import Any, Optional
|
from typing import Any, Optional
|
||||||
@@ -419,11 +420,17 @@ class MessageBus(BaseMessageBus):
|
|||||||
return handler
|
return handler
|
||||||
|
|
||||||
def _message_reader(self) -> None:
|
def _message_reader(self) -> None:
|
||||||
|
unmarshaller = self._unmarshaller
|
||||||
try:
|
try:
|
||||||
while True:
|
while True:
|
||||||
if self._unmarshaller.unmarshall():
|
if unmarshaller.unmarshall():
|
||||||
self._on_message(self._unmarshaller.message)
|
try:
|
||||||
self._unmarshaller = self._create_unmarshaller()
|
self._process_message(unmarshaller.message)
|
||||||
|
except Exception as e:
|
||||||
|
logging.error(
|
||||||
|
f"got unexpected error processing a message: {e}.\n{traceback.format_exc()}"
|
||||||
|
)
|
||||||
|
unmarshaller.reset()
|
||||||
else:
|
else:
|
||||||
break
|
break
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
|
|||||||
@@ -1,4 +1,6 @@
|
|||||||
import io
|
import io
|
||||||
|
import logging
|
||||||
|
import traceback
|
||||||
from typing import Callable, Optional
|
from typing import Callable, Optional
|
||||||
|
|
||||||
from .. import introspection as intr
|
from .. import introspection as intr
|
||||||
@@ -173,6 +175,14 @@ class MessageBus(BaseMessageBus):
|
|||||||
else:
|
else:
|
||||||
self._auth = auth
|
self._auth = auth
|
||||||
|
|
||||||
|
def _on_message(self, msg: Message) -> None:
|
||||||
|
try:
|
||||||
|
self._process_message(msg)
|
||||||
|
except Exception as e:
|
||||||
|
logging.error(
|
||||||
|
f"got unexpected error processing a message: {e}.\n{traceback.format_exc()}"
|
||||||
|
)
|
||||||
|
|
||||||
def connect(
|
def connect(
|
||||||
self, connect_notify: Callable[["MessageBus", Optional[Exception]], None] = None
|
self, connect_notify: Callable[["MessageBus", Optional[Exception]], None] = None
|
||||||
):
|
):
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
from typing import Any, List
|
from typing import Any, List, Union
|
||||||
|
|
||||||
from ._private.constants import LITTLE_ENDIAN, PROTOCOL_VERSION, HeaderField
|
from ._private.constants import LITTLE_ENDIAN, PROTOCOL_VERSION, HeaderField
|
||||||
from ._private.marshaller import Marshaller
|
from ._private.marshaller import Marshaller
|
||||||
@@ -105,11 +105,11 @@ class Message:
|
|||||||
reply_serial: int = None,
|
reply_serial: int = None,
|
||||||
sender: str = None,
|
sender: str = None,
|
||||||
unix_fds: List[int] = [],
|
unix_fds: List[int] = [],
|
||||||
signature: str = "",
|
signature: Union[str, SignatureTree] = "",
|
||||||
body: List[Any] = [],
|
body: List[Any] = [],
|
||||||
serial: int = 0,
|
serial: int = 0,
|
||||||
validate: bool = True,
|
validate: bool = True,
|
||||||
):
|
) -> None:
|
||||||
self.destination = destination
|
self.destination = destination
|
||||||
self.path = path
|
self.path = path
|
||||||
self.interface = interface
|
self.interface = interface
|
||||||
@@ -124,14 +124,12 @@ class Message:
|
|||||||
self.reply_serial = reply_serial
|
self.reply_serial = reply_serial
|
||||||
self.sender = sender
|
self.sender = sender
|
||||||
self.unix_fds = unix_fds
|
self.unix_fds = unix_fds
|
||||||
self.signature = (
|
if type(signature) is SignatureTree:
|
||||||
signature.signature if type(signature) is SignatureTree else signature
|
self.signature = signature.signature
|
||||||
)
|
self.signature_tree = signature
|
||||||
self.signature_tree = (
|
else:
|
||||||
signature
|
self.signature = signature
|
||||||
if type(signature) is SignatureTree
|
self.signature_tree = SignatureTree._get(signature)
|
||||||
else SignatureTree._get(signature)
|
|
||||||
)
|
|
||||||
self.body = body
|
self.body = body
|
||||||
self.serial = serial
|
self.serial = serial
|
||||||
|
|
||||||
|
|||||||
@@ -690,14 +690,6 @@ class BaseMessageBus:
|
|||||||
ErrorType.INTERNAL_ERROR, "invalid message type for method call", msg
|
ErrorType.INTERNAL_ERROR, "invalid message type for method call", msg
|
||||||
)
|
)
|
||||||
|
|
||||||
def _on_message(self, msg: Message) -> None:
|
|
||||||
try:
|
|
||||||
self._process_message(msg)
|
|
||||||
except Exception as e:
|
|
||||||
logging.error(
|
|
||||||
f"got unexpected error processing a message: {e}.\n{traceback.format_exc()}"
|
|
||||||
)
|
|
||||||
|
|
||||||
def _send_reply(self, msg: Message):
|
def _send_reply(self, msg: Message):
|
||||||
bus = self
|
bus = self
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user