feat: speed up to processing bluez passive data (#221)
This commit is contained in:
parent
71e6fdfc97
commit
8e7432d31b
@ -27,6 +27,8 @@ cdef object LITTLE_ENDIAN
|
|||||||
cdef object PROTOCOL_VERSION
|
cdef object PROTOCOL_VERSION
|
||||||
|
|
||||||
cdef object MESSAGE_FLAG
|
cdef object MESSAGE_FLAG
|
||||||
|
cdef object MESSAGE_FLAG_NONE
|
||||||
|
cdef object MESSAGE_TYPE_METHOD_CALL
|
||||||
|
|
||||||
cdef get_signature_tree
|
cdef get_signature_tree
|
||||||
|
|
||||||
|
|||||||
@ -30,6 +30,9 @@ HEADER_UNIX_FDS = HeaderField.UNIX_FDS.value
|
|||||||
|
|
||||||
MESSAGE_FLAG = MessageFlag
|
MESSAGE_FLAG = MessageFlag
|
||||||
|
|
||||||
|
MESSAGE_FLAG_NONE = MessageFlag.NONE
|
||||||
|
MESSAGE_TYPE_METHOD_CALL = MessageType.METHOD_CALL
|
||||||
|
|
||||||
|
|
||||||
class Message:
|
class Message:
|
||||||
"""A class for sending and receiving messages through the
|
"""A class for sending and receiving messages through the
|
||||||
@ -101,8 +104,8 @@ class Message:
|
|||||||
path: Optional[str] = None,
|
path: Optional[str] = None,
|
||||||
interface: Optional[str] = None,
|
interface: Optional[str] = None,
|
||||||
member: Optional[str] = None,
|
member: Optional[str] = None,
|
||||||
message_type: MessageType = MessageType.METHOD_CALL,
|
message_type: MessageType = MESSAGE_TYPE_METHOD_CALL,
|
||||||
flags: Union[MessageFlag, int] = MessageFlag.NONE,
|
flags: Union[MessageFlag, int] = MESSAGE_FLAG_NONE,
|
||||||
error_name: Optional[Union[str, ErrorType]] = None,
|
error_name: Optional[Union[str, ErrorType]] = None,
|
||||||
reply_serial: int = 0,
|
reply_serial: int = 0,
|
||||||
sender: Optional[str] = None,
|
sender: Optional[str] = None,
|
||||||
@ -153,6 +156,22 @@ class Message:
|
|||||||
if not getattr(self, field):
|
if not getattr(self, field):
|
||||||
raise InvalidMessageError(f"missing required field: {field}")
|
raise InvalidMessageError(f"missing required field: {field}")
|
||||||
|
|
||||||
|
def __repr__(self) -> str:
|
||||||
|
"""Return a string representation of this message."""
|
||||||
|
return (
|
||||||
|
f"<Message {self.message_type.name} "
|
||||||
|
f"serial={self.serial} "
|
||||||
|
f"reply_serial={self.reply_serial} "
|
||||||
|
f"sender={self.sender} "
|
||||||
|
f"destination={self.destination} "
|
||||||
|
f"path={self.path} "
|
||||||
|
f"interface={self.interface} "
|
||||||
|
f"member={self.member} "
|
||||||
|
f"error_name={self.error_name} "
|
||||||
|
f"signature={self.signature} "
|
||||||
|
f"body={self.body}>"
|
||||||
|
)
|
||||||
|
|
||||||
@staticmethod
|
@staticmethod
|
||||||
def new_error(
|
def new_error(
|
||||||
msg: "Message", error_name: Union[str, ErrorType], error_text: str
|
msg: "Message", error_name: Union[str, ErrorType], error_text: str
|
||||||
|
|||||||
@ -10,12 +10,14 @@ cdef object MessageFlag
|
|||||||
|
|
||||||
cdef object MESSAGE_TYPE_CALL
|
cdef object MESSAGE_TYPE_CALL
|
||||||
cdef object MESSAGE_TYPE_SIGNAL
|
cdef object MESSAGE_TYPE_SIGNAL
|
||||||
cdef object NO_REPLY_EXPECTED_VALUE
|
cdef object NO_REPLY_EXPECTED
|
||||||
|
cdef object BLOCK_UNEXPECTED_REPLY
|
||||||
cdef object assert_object_path_valid
|
cdef object assert_object_path_valid
|
||||||
cdef object assert_bus_name_valid
|
cdef object assert_bus_name_valid
|
||||||
|
|
||||||
cdef _expects_reply(Message msg)
|
cdef _expects_reply(Message msg)
|
||||||
|
|
||||||
|
|
||||||
cdef class SendReply:
|
cdef class SendReply:
|
||||||
|
|
||||||
cdef object _bus
|
cdef object _bus
|
||||||
@ -28,12 +30,12 @@ cdef class BaseMessageBus:
|
|||||||
cdef public object _user_disconnect
|
cdef public object _user_disconnect
|
||||||
cdef public object _method_return_handlers
|
cdef public object _method_return_handlers
|
||||||
cdef public object _serial
|
cdef public object _serial
|
||||||
cdef public object _path_exports
|
cdef public cython.dict _path_exports
|
||||||
cdef public cython.list _user_message_handlers
|
cdef public cython.list _user_message_handlers
|
||||||
cdef public object _name_owners
|
cdef public cython.dict _name_owners
|
||||||
cdef public object _bus_address
|
cdef public object _bus_address
|
||||||
cdef public object _name_owner_match_rule
|
cdef public object _name_owner_match_rule
|
||||||
cdef public object _match_rules
|
cdef public cython.dict _match_rules
|
||||||
cdef public object _high_level_client_initialized
|
cdef public object _high_level_client_initialized
|
||||||
cdef public object _ProxyObject
|
cdef public object _ProxyObject
|
||||||
cdef public object _machine_id
|
cdef public object _machine_id
|
||||||
@ -45,7 +47,9 @@ cdef class BaseMessageBus:
|
|||||||
cpdef _process_message(self, Message msg)
|
cpdef _process_message(self, Message msg)
|
||||||
|
|
||||||
@cython.locals(
|
@cython.locals(
|
||||||
|
methods=cython.list,
|
||||||
method=_Method,
|
method=_Method,
|
||||||
interface=ServiceInterface
|
interface=ServiceInterface,
|
||||||
|
interfaces=cython.list,
|
||||||
)
|
)
|
||||||
cdef _find_message_handler(self, Message msg)
|
cdef _find_message_handler(self, Message msg)
|
||||||
|
|||||||
@ -27,13 +27,34 @@ from .validators import assert_bus_name_valid, assert_object_path_valid
|
|||||||
|
|
||||||
MESSAGE_TYPE_CALL = MessageType.METHOD_CALL
|
MESSAGE_TYPE_CALL = MessageType.METHOD_CALL
|
||||||
MESSAGE_TYPE_SIGNAL = MessageType.SIGNAL
|
MESSAGE_TYPE_SIGNAL = MessageType.SIGNAL
|
||||||
NO_REPLY_EXPECTED_VALUE = MessageFlag.NO_REPLY_EXPECTED.value
|
NO_REPLY_EXPECTED = MessageFlag.NO_REPLY_EXPECTED
|
||||||
|
_LOGGER = logging.getLogger(__name__)
|
||||||
|
|
||||||
|
|
||||||
_Message = Message
|
_Message = Message
|
||||||
|
|
||||||
|
|
||||||
def _expects_reply(msg: _Message) -> bool:
|
def _expects_reply(msg: _Message) -> bool:
|
||||||
return not (msg.flags.value & NO_REPLY_EXPECTED_VALUE)
|
"""Whether a message expects a reply."""
|
||||||
|
return not (msg.flags & NO_REPLY_EXPECTED)
|
||||||
|
|
||||||
|
|
||||||
|
def _block_unexpected_reply(reply: _Message) -> None:
|
||||||
|
"""Block a reply if it's not expected.
|
||||||
|
|
||||||
|
Previously we silently ignored replies that were not expected, but this
|
||||||
|
lead to implementation errors that were hard to debug. Now we log a
|
||||||
|
debug message instead.
|
||||||
|
"""
|
||||||
|
_LOGGER.debug(
|
||||||
|
"Blocked attempt to send a reply from handler "
|
||||||
|
"that received a message with flag "
|
||||||
|
"MessageFlag.NO_REPLY_EXPECTED: %s",
|
||||||
|
reply,
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
|
BLOCK_UNEXPECTED_REPLY = _block_unexpected_reply
|
||||||
|
|
||||||
|
|
||||||
class SendReply:
|
class SendReply:
|
||||||
@ -50,8 +71,7 @@ class SendReply:
|
|||||||
return self
|
return self
|
||||||
|
|
||||||
def __call__(self, reply: Message) -> None:
|
def __call__(self, reply: Message) -> None:
|
||||||
if _expects_reply(self._msg):
|
self._bus.send(reply)
|
||||||
self._bus.send(reply)
|
|
||||||
|
|
||||||
def _exit(
|
def _exit(
|
||||||
self,
|
self,
|
||||||
@ -855,9 +875,19 @@ class BaseMessageBus:
|
|||||||
if msg.message_type is MESSAGE_TYPE_CALL:
|
if msg.message_type is MESSAGE_TYPE_CALL:
|
||||||
if not handled:
|
if not handled:
|
||||||
handler = self._find_message_handler(msg)
|
handler = self._find_message_handler(msg)
|
||||||
|
if not _expects_reply(msg):
|
||||||
|
if handler:
|
||||||
|
handler(msg, BLOCK_UNEXPECTED_REPLY)
|
||||||
|
else:
|
||||||
|
_LOGGER.error(
|
||||||
|
'"%s.%s" with signature "%s" could not be found',
|
||||||
|
msg.interface,
|
||||||
|
msg.member,
|
||||||
|
msg.signature,
|
||||||
|
)
|
||||||
|
return
|
||||||
|
|
||||||
send_reply = SendReply(self, msg)
|
send_reply = SendReply(self, msg)
|
||||||
|
|
||||||
with send_reply:
|
with send_reply:
|
||||||
if handler:
|
if handler:
|
||||||
handler(msg, send_reply)
|
handler(msg, send_reply)
|
||||||
@ -892,8 +922,11 @@ class BaseMessageBus:
|
|||||||
def _callback_method_handler(
|
def _callback_method_handler(
|
||||||
msg: Message, send_reply: Callable[[Message], None]
|
msg: Message, send_reply: Callable[[Message], None]
|
||||||
) -> None:
|
) -> None:
|
||||||
|
result = method_fn(interface, *msg_body_to_args(msg))
|
||||||
|
if not _expects_reply(msg):
|
||||||
|
return
|
||||||
body, fds = fn_result_to_body(
|
body, fds = fn_result_to_body(
|
||||||
method_fn(interface, *msg_body_to_args(msg)),
|
result,
|
||||||
signature_tree=out_signature_tree,
|
signature_tree=out_signature_tree,
|
||||||
replace_fds=negotiate_unix_fd,
|
replace_fds=negotiate_unix_fd,
|
||||||
)
|
)
|
||||||
@ -911,8 +944,8 @@ class BaseMessageBus:
|
|||||||
return _callback_method_handler
|
return _callback_method_handler
|
||||||
|
|
||||||
def _find_message_handler(
|
def _find_message_handler(
|
||||||
self, msg
|
self, msg: _Message
|
||||||
) -> Optional[Callable[[Message, Callable], None]]:
|
) -> Optional[Callable[[Message, Callable[[Message], None]], None]]:
|
||||||
if (
|
if (
|
||||||
msg.interface == "org.freedesktop.DBus.Introspectable"
|
msg.interface == "org.freedesktop.DBus.Introspectable"
|
||||||
and msg.member == "Introspect"
|
and msg.member == "Introspect"
|
||||||
@ -937,8 +970,12 @@ class BaseMessageBus:
|
|||||||
|
|
||||||
msg_path = msg.path
|
msg_path = msg.path
|
||||||
if msg_path:
|
if msg_path:
|
||||||
for interface in self._path_exports.get(msg_path, []):
|
interfaces = self._path_exports.get(msg_path)
|
||||||
for method in ServiceInterface._get_methods(interface):
|
if not interfaces:
|
||||||
|
return None
|
||||||
|
for interface in interfaces:
|
||||||
|
methods = ServiceInterface._get_methods(interface)
|
||||||
|
for method in methods:
|
||||||
if method.disabled:
|
if method.disabled:
|
||||||
continue
|
continue
|
||||||
|
|
||||||
|
|||||||
@ -2,17 +2,19 @@
|
|||||||
|
|
||||||
import cython
|
import cython
|
||||||
|
|
||||||
|
from .signature cimport SignatureTree
|
||||||
|
|
||||||
|
|
||||||
cdef class _Method:
|
cdef class _Method:
|
||||||
|
|
||||||
cdef public object name
|
cdef public str name
|
||||||
cdef public object fn
|
cdef public object fn
|
||||||
cdef public object disabled
|
cdef public object disabled
|
||||||
cdef public object introspection
|
cdef public object introspection
|
||||||
cdef public object in_signature
|
cdef public str in_signature
|
||||||
cdef public object out_signature
|
cdef public str out_signature
|
||||||
cdef public object in_signature_tree
|
cdef public SignatureTree in_signature_tree
|
||||||
cdef public object out_signature_tree
|
cdef public SignatureTree out_signature_tree
|
||||||
|
|
||||||
cdef class ServiceInterface:
|
cdef class ServiceInterface:
|
||||||
|
|
||||||
|
|||||||
@ -36,7 +36,7 @@ if TYPE_CHECKING:
|
|||||||
|
|
||||||
|
|
||||||
class _Method:
|
class _Method:
|
||||||
def __init__(self, fn, name, disabled=False):
|
def __init__(self, fn, name: str, disabled=False):
|
||||||
in_signature = ""
|
in_signature = ""
|
||||||
out_signature = ""
|
out_signature = ""
|
||||||
|
|
||||||
|
|||||||
@ -602,5 +602,6 @@ def test_unmarshall_bluez_passive_message():
|
|||||||
unmarshaller = Unmarshaller(stream)
|
unmarshaller = Unmarshaller(stream)
|
||||||
unmarshaller.unmarshall()
|
unmarshaller.unmarshall()
|
||||||
message = unmarshaller.message
|
message = unmarshaller.message
|
||||||
|
assert "/org/bluez/hci0/dev_58_D3_49_E6_02_6E" in str(message)
|
||||||
unpacked = unpack_variants(message.body)
|
unpacked = unpack_variants(message.body)
|
||||||
assert unpacked == ["/org/bluez/hci0/dev_58_D3_49_E6_02_6E"]
|
assert unpacked == ["/org/bluez/hci0/dev_58_D3_49_E6_02_6E"]
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user