feat: speed up run time constructed method handlers (#275)
This commit is contained in:
parent
7ede6bb438
commit
9f54fc3194
@ -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
|
||||
)
|
||||
|
||||
@ -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:
|
||||
|
||||
@ -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,
|
||||
)
|
||||
|
||||
@ -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(
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user