import dbus_bindings from exceptions import MissingReplyHandlerException, MissingErrorHandlerException class DeferedMethod: """A DeferedMethod This is returned instead of ProxyMethod when we are defering DBus calls while waiting for introspection data to be returned This class can be used for debugging purposes """ def __call__(self, *args, **keywords): return None class ProxyMethod: """A proxy Method. Typically a member of a ProxyObject. Calls to the method produce messages that travel over the Bus and are routed to a specific named Service. """ def __init__(self, connection, named_service, object_path, dbus_interface, method_name): self._connection = connection self._named_service = named_service self._object_path = object_path self._method_name = method_name self._dbus_interface = dbus_interface def __call__(self, *args, **keywords): dbus_interface = self._dbus_interface if keywords.has_key('dbus_interface'): dbus_interface = keywords['dbus_interface'] timeout = -1 if keywords.has_key('timeout'): timeout = keywords['timeout'] reply_handler = None if keywords.has_key('reply_handler'): reply_handler = keywords['reply_handler'] error_handler = None if keywords.has_key('error_handler'): error_handler = keywords['error_handler'] if not(reply_handler and error_handler): if reply_handler: raise MissingErrorHandlerException() elif error_handler: raise MissingReplyHandlerException() message = dbus_bindings.MethodCall(self._object_path, dbus_interface, self._method_name) message.set_destination(self._named_service) # Add the arguments to the function iter = message.get_iter(True) for arg in args: iter.append(arg) if reply_handler: result = self._connection.send_with_reply_handlers(message, timeout, reply_handler, error_handler) args_tuple = result else: reply_message = self._connection.send_with_reply_and_block(message, timeout) args_tuple = reply_message.get_args_list() if len(args_tuple) == 0: return elif len(args_tuple) == 1: return args_tuple[0] else: return args_tuple class ProxyObject: """A proxy to the remote Object. A ProxyObject is provided by the Bus. ProxyObjects have member functions, and can be called like normal Python objects. """ ProxyMethodClass = ProxyMethod DeferedMethodClass = DeferedMethod INTROSPECT_STATE_DONT_INTROSPECT = 0 INTROSPECT_STATE_INTROSPECT_IN_PROGRESS = 1 INTROSPECT_STATE_INTROSPECT_DONE = 2 #TODO: default introspect to False right now because it is not done yet # make sure to default to True later def __init__(self, bus, named_service, object_path, introspect=False): self._bus = bus self._named_service = named_service self._object_path = object_path #PendingCall object for Introspect call self._pending_introspect = None #queue of async calls waiting on the Introspect to return self._pending_introspect_queue = [] if not introspect: self._introspect_state = self.INTROSPECT_STATE_DONT_INTROSPECT else: self._introspect_state = self.INTROSPECT_STATE_INTROSPECT_IN_PROGRESS (result, self._pending_introspect) = self._Introspect() def connect_to_signal(self, signal_name, handler_function, dbus_interface=None, **keywords): self._bus.add_signal_receiver(handler_function, signal_name=signal_name, dbus_interface=dbus_interface, named_service=self._named_service, path=self._object_path, **keywords) def _Introspect(self): message = dbus_bindings.MethodCall(self._object_path, 'org.freedesktop.DBus.Introspectable', 'Introspect') message.set_destination(self._named_service) result = self._bus.get_connection().send_with_reply_handlers(message, -1, self._introspect_reply_handler, self._introspect_error_handler) return result def _introspect_reply_handler(self, data): self._introspect_state = self.INTROSPECT_STATE_INTROSPECT_DONE for call in self._pending_introspect_queue: (member, iface, args, keywords) = call call_object = self.ProxyMethodClass(self._bus.get_connection(), self._named_service, self._object_path, iface, member) call_object(args, keywords) def _introspect_error_handler(self, error): self._introspect_state = self.INTROSPECT_STATE_DONT_INTROSPECT def __getattr__(self, member, **keywords): if member == '__call__': return object.__call__ elif member.startswith('__') and member.endswith('__'): raise AttributeError(member) else: iface = None if keywords.has_key('dbus_interface'): iface = keywords['dbus_interface'] if self._introspect_state == self.INTROSPECT_STATE_INTROSPECT_IN_PROGRESS: reply_handler = None if keywords.has_key('reply_handler'): reply_handler = keywords['reply_handler'] error_handler = None if keywords.has_key('error_handler'): error_handler = keywords['error_handler'] if not reply_handler: self._pending_introspect.block() else: call = (memeber, iface, args, keywords) self._pending_introspect_queue.append(call) ret = self.DeferedMethodClass() return ret ret = self.ProxyMethodClass(self._bus.get_connection(), self._named_service, self._object_path, iface, member) return ret def __repr__(self): return ''%( self._bus, self._named_service, self._object_path , id(self)) __str__ = __repr__