feat: speed up run time constructed method handlers (#275)

This commit is contained in:
J. Nick Koston 2023-12-03 20:28:04 -10:00 committed by GitHub
parent 7ede6bb438
commit 9f54fc3194
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
4 changed files with 119 additions and 72 deletions

View File

@ -57,3 +57,11 @@ cdef class BaseMessageBus:
cpdef _call(self, Message msg, object callback)
cpdef next_serial(self)
cpdef void _callback_method_handler(
self,
ServiceInterface interface,
_Method method,
Message msg,
object send_reply
)

View File

@ -865,67 +865,64 @@ class BaseMessageBus:
return_handler(msg, None)
del self._method_return_handlers[msg.reply_serial]
def _callback_method_handler(
self,
interface: ServiceInterface,
method: _Method,
msg: Message,
send_reply: Callable[[Message], None],
) -> None:
"""This is the callback that will be called when a method call is."""
args = ServiceInterface._c_msg_body_to_args(msg) if msg.unix_fds else msg.body
result = method.fn(interface, *args)
if send_reply is BLOCK_UNEXPECTED_REPLY or _expects_reply(msg) is False:
return
body, fds = ServiceInterface._c_fn_result_to_body(
result,
signature_tree=method.out_signature_tree,
replace_fds=self._negotiate_unix_fd,
)
send_reply(
Message(
message_type=MessageType.METHOD_RETURN,
reply_serial=msg.serial,
destination=msg.sender,
signature=method.out_signature,
body=body,
unix_fds=fds,
)
)
def _make_method_handler(
self, interface: ServiceInterface, method: _Method
) -> Callable[[Message, Callable[[Message], None]], None]:
method_fn = method.fn
out_signature_tree = method.out_signature_tree
negotiate_unix_fd = self._negotiate_unix_fd
out_signature = method.out_signature
message_type_method_return = MessageType.METHOD_RETURN
msg_body_to_args = ServiceInterface._msg_body_to_args
fn_result_to_body = ServiceInterface._fn_result_to_body
def _callback_method_handler(
msg: Message, send_reply: Callable[[Message], None]
) -> None:
"""This is the callback that will be called when a method call is."""
args = msg_body_to_args(msg) if msg.unix_fds else msg.body
result = method_fn(interface, *args)
if send_reply is BLOCK_UNEXPECTED_REPLY or _expects_reply(msg) is False:
return
body, fds = fn_result_to_body(
result,
signature_tree=out_signature_tree,
replace_fds=negotiate_unix_fd,
)
send_reply(
Message(
message_type=message_type_method_return,
reply_serial=msg.serial,
destination=msg.sender,
signature=out_signature,
body=body,
unix_fds=fds,
)
)
return _callback_method_handler
return partial(self._callback_method_handler, interface, method)
def _find_message_handler(
self, msg: _Message
) -> Optional[Callable[[Message, Callable[[Message], None]], None]]:
if (
msg.interface == "org.freedesktop.DBus.Introspectable"
and msg.member == "Introspect"
and msg.signature == ""
):
return self._default_introspect_handler
if msg.interface.startswith("org.freedesktop.DBus."):
if (
msg.interface == "org.freedesktop.DBus.Introspectable"
and msg.member == "Introspect"
and msg.signature == ""
):
return self._default_introspect_handler
if msg.interface == "org.freedesktop.DBus.Properties":
return self._default_properties_handler
if msg.interface == "org.freedesktop.DBus.Properties":
return self._default_properties_handler
if msg.interface == "org.freedesktop.DBus.Peer":
if msg.member == "Ping" and msg.signature == "":
return self._default_ping_handler
elif msg.member == "GetMachineId" and msg.signature == "":
return self._default_get_machine_id_handler
if msg.interface == "org.freedesktop.DBus.Peer":
if msg.member == "Ping" and msg.signature == "":
return self._default_ping_handler
elif msg.member == "GetMachineId" and msg.signature == "":
return self._default_get_machine_id_handler
if (
msg.interface == "org.freedesktop.DBus.ObjectManager"
and msg.member == "GetManagedObjects"
):
return self._default_get_managed_objects_handler
if (
msg.interface == "org.freedesktop.DBus.ObjectManager"
and msg.member == "GetManagedObjects"
):
return self._default_get_managed_objects_handler
msg_path = msg.path
if msg_path:

View File

@ -2,6 +2,7 @@
import cython
from .message cimport Message
from .signature cimport SignatureTree
@ -16,6 +17,14 @@ cdef class _Method:
cdef public SignatureTree in_signature_tree
cdef public SignatureTree out_signature_tree
cdef tuple _real_fn_result_to_body(
object result,
SignatureTree signature_tree,
bint replace_fds
)
cdef class ServiceInterface:
cdef public str name
@ -30,3 +39,13 @@ cdef class ServiceInterface:
@staticmethod
cdef object _c_get_handler(ServiceInterface interface, _Method method, object bus)
@staticmethod
cdef list _c_msg_body_to_args(Message msg)
@staticmethod
cdef tuple _c_fn_result_to_body(
object result,
SignatureTree signature_tree,
bint replace_fds,
)

View File

@ -326,6 +326,35 @@ def dbus_property(
return decorator
def _real_fn_result_to_body(
result: Optional[Any],
signature_tree: SignatureTree,
replace_fds: bool,
) -> Tuple[List[Any], List[int]]:
out_len = len(signature_tree.types)
if result is None:
final_result = []
else:
if out_len == 1:
final_result = [result]
else:
result_type = type(result)
if result_type is not list and result_type is not tuple:
raise SignatureBodyMismatchError(
"Expected signal to return a list or tuple of arguments"
)
final_result = result
if out_len != len(final_result):
raise SignatureBodyMismatchError(
f"Signature and function return mismatch, expected {len(signature_tree.types)} arguments but got {len(result)}"
)
if not replace_fds:
return final_result, []
return replace_fds_with_idx(signature_tree, final_result)
class ServiceInterface:
"""An abstract class that can be extended by the user to define DBus services.
@ -505,6 +534,11 @@ class ServiceInterface:
@staticmethod
def _msg_body_to_args(msg: Message) -> List[Any]:
return ServiceInterface._c_msg_body_to_args(msg)
@staticmethod
def _c_msg_body_to_args(msg: Message) -> List[Any]:
# https://github.com/cython/cython/issues/3327
if not signature_contains_type(msg.signature_tree, msg.body, "h"):
return msg.body
@ -520,31 +554,20 @@ class ServiceInterface:
result: Optional[Any],
signature_tree: SignatureTree,
replace_fds: bool = True,
) -> Tuple[List[Any], List[int]]:
return _real_fn_result_to_body(result, signature_tree, replace_fds)
@staticmethod
def _c_fn_result_to_body(
result: Optional[Any],
signature_tree: SignatureTree,
replace_fds: bool,
) -> Tuple[List[Any], List[int]]:
"""The high level interfaces may return single values which may be
wrapped in a list to be a message body. Also they may return fds
directly for type 'h' which need to be put into an external list."""
out_len = len(signature_tree.types)
if result is None:
result = []
else:
if out_len == 1:
result = [result]
else:
result_type = type(result)
if result_type is not list and result_type is not tuple:
raise SignatureBodyMismatchError(
"Expected signal to return a list or tuple of arguments"
)
if out_len != len(result):
raise SignatureBodyMismatchError(
f"Signature and function return mismatch, expected {len(signature_tree.types)} arguments but got {len(result)}"
)
if not replace_fds:
return result, []
return replace_fds_with_idx(signature_tree, result)
# https://github.com/cython/cython/issues/3327
return _real_fn_result_to_body(result, signature_tree, replace_fds)
@staticmethod
def _handle_signal(