diff options
Diffstat (limited to 'python/service.py')
| -rw-r--r-- | python/service.py | 187 | 
1 files changed, 187 insertions, 0 deletions
diff --git a/python/service.py b/python/service.py new file mode 100644 index 00000000..fc044af0 --- /dev/null +++ b/python/service.py @@ -0,0 +1,187 @@ +from decorators import * + +import dbus_bindings  + +class Name: +    """A base class for exporting your own Named Services across the Bus + +    Just inherit from Name, providing the name of your service +    (e.g. org.designfu.SampleService). +    """ +    def __init__(self, named_service, bus=None): +        self._named_service = named_service +                              +        if bus == None: +            # Get the default bus +            self._bus = Bus() +        else: +            self._bus = bus + +        dbus_bindings.bus_request_name(self._bus.get_connection(), named_service) + +    def get_bus(self): +        """Get the Bus this Service is on""" +        return self._bus + +    def get_name(self): +        """Get the name of this service""" +        return self._named_service + +def _dispatch_dbus_method_call(target_methods, self, argument_list, message): +    """Calls method_to_call using argument_list, but handles +    exceptions, etc, and generates a reply to the DBus Message message +    """ +    try: +        target_method = None +         +        dbus_interface = message.get_interface() +        if dbus_interface == None: +            if target_methods: +                target_method = target_methods[0] +        else: +            for dbus_method in target_methods: +                if dbus_method._dbus_interface == dbus_interface: +                    target_method = dbus_method +                    break +         +        if target_method: +            retval = target_method(self, *argument_list) +        else: +            if not dbus_interface: +                raise UnknownMethodException('%s is not a valid method'%(message.get_member())) +            else: +                raise UnknownMethodException('%s is not a valid method of interface %s'%(message.get_member(), dbus_interface)) +    except Exception, e: +        if e.__module__ == '__main__': +            # FIXME: is it right to use .__name__ here? +            error_name = e.__class__.__name__ +        else: +            error_name = e.__module__ + '.' + str(e.__class__.__name__) +            error_contents = str(e) +            reply = dbus_bindings.Error(message, error_name, error_contents) +    else: +        reply = dbus_bindings.MethodReturn(message) +        if retval != None: +            iter = reply.get_iter(append=True) +            iter.append(retval) +	     +    return reply + +class ObjectType(type): +    def __init__(cls, name, bases, dct): + +        #generate out vtable +        method_vtable = getattr(cls, '_dbus_method_vtable', {}) +        reflection_data = getattr(cls, '_dbus_reflection_data', "") + +        reflection_interface_method_hash = {} +        reflection_interface_signal_hash = {} + +        for func in dct.values(): +            if getattr(func, '_dbus_is_method', False): +                if method_vtable.has_key(func.__name__): +                    method_vtable[func.__name__].append(func) +                else: +	            method_vtable[func.__name__] = [func] +                 +                #generate a hash of interfaces so we can group +                #methods in the xml data +                if reflection_interface_method_hash.has_key(func._dbus_interface): +                    reflection_interface_method_hash[func._dbus_interface].append(func) +                else: +                    reflection_interface_method_hash[func._dbus_interface] = [func] + +            elif getattr(func, '_dbus_is_signal', False): +                if reflection_interface_signal_hash.has_key(func._dbus_interface): +                    reflection_interface_signal_hash[func._dbus_interface].append(func) +                else: +                    reflection_interface_signal_hash[func._dbus_interface] = [func] + +	for interface in reflection_interface_method_hash.keys(): +            reflection_data = reflection_data + '  <interface name="%s">\n'%(interface) +            for func in reflection_interface_method_hash[interface]: +                reflection_data = reflection_data + cls._reflect_on_method(func) + +            if reflection_interface_signal_hash.has_key(interface): +                for func in reflection_interface_signal_hash[interface]: +                    reflection_data = reflection_data + cls._reflect_on_signal(func) + +                del reflection_interface_signal_hash[interface] +                 +            reflection_data = reflection_data + '  </interface>\n' + +	for interface in reflection_interface_signal_hash.keys(): +            reflection_data = reflection_data + '  <interface name="%s">\n'%(interface) +             +            for func in reflection_interface_signal_hash[interface]: +                reflection_data = reflection_data + cls._reflect_on_signal(func) + +            reflection_data = reflection_data + '  </interface>\n' + +        cls._dbus_reflection_data = reflection_data   +	cls._dbus_method_vtable = method_vtable +         +        super(ObjectType, cls).__init__(name, bases, dct) + +    #reflections on methods and signals may look like similar code but may in fact +    #diverge in the future so keep them seperate +    def _reflect_on_method(cls, func): +        reflection_data = '    <method name="%s">\n'%(func.__name__) +        for arg in func._dbus_args: +            reflection_data = reflection_data + '      <arg name="%s" type="v" />\n'%(arg) + +            #reclaim some memory +            func._dbus_args = None +            reflection_data = reflection_data + '    </method>\n' + +        return reflection_data   +              +    def _reflect_on_signal(cls, func): +        reflection_data = '    <signal name="%s">\n'%(func.__name__) +        for arg in func._dbus_args: +            reflection_data = reflection_data + '      <arg name="%s" type="v" />\n'%(arg) +            #reclaim some memory +            func._dbus_args = None +            reflection_data = reflection_data + '    </signal>\n' + +        return reflection_data + +class Object: +    """A base class for exporting your own Objects across the Bus. + +    Just inherit from Object and provide a list of methods to share +    across the Bus. These will appear as member functions of your +    ServiceObject. +    """ +    __metaclass__ = ObjectType +     +    def __init__(self, object_path, name): +        self._object_path = object_path +        self._name = name  +        self._bus = name.get_bus() +             +        self._connection = self._bus.get_connection() + +        self._connection.register_object_path(object_path, self._unregister_cb, self._message_cb) + +    def _unregister_cb(self, connection): +        print ("Unregister") + +    def _message_cb(self, connection, message): +        target_method_name = message.get_member() +        target_methods = self._dbus_method_vtable[target_method_name] +        args = message.get_args_list() +         +        reply = _dispatch_dbus_method_call(target_methods, self, args, message) + +        self._connection.send(reply) + +    @method('org.freedesktop.DBus.Introspectable') +    def Introspect(self): +        reflection_data = '<!DOCTYPE node PUBLIC "-//freedesktop//DTD D-BUS Object Introspection 1.0//EN" "http://www.freedesktop.org/standards/dbus/1.0/introspect.dtd">\n' +        reflection_data = reflection_data + '<node name="%s">\n'%(self._object_path) +        reflection_data = reflection_data + self._dbus_reflection_data +        reflection_data = reflection_data + '</node>\n' + +        return reflection_data +  | 
