Introspection
Network Manager
Create a Service
GObject Introspection
A dbus service is usable by other applications. It listens for input from another process, and responds with output.
When you create a service, you need to make a couple decisions about when you want to start your service, and when you want to terminate it...
Start: Startup, login, first-use, on-demand?
End: Each time? logout? Shutdown?
In other words, is this a single-use service, or a forever-running daemon?
Happily, the actual code differences are trivial. Dbus itself can launch a service that's not running yet. (Indeed, a lot of startup and login depends on that!)
Example Dbus Service in Python3
Here's an example of a self-contained daemon written in Python 3 (source). It's introspectable and executable from dbus-send or d-feet. When called, it simply returns a "Hello, World!" string.
It can be started by either dbus or another process (like Upstart or a script). Since it runs in an endless loop awaiting input, it will run until logout. It can also be manually terminated by uncommenting the
Gtk.main_quit()
command.#!/usr/bin/env/python3 # This file is /home/me/test-dbus.py # Remember to make it executable if you want dbus to launch it # It works with both Python2 and Python3 from gi.repository import Gtk import dbus import dbus.service from dbus.mainloop.glib import DBusGMainLoop class MyDBUSService(dbus.service.Object): def __init__(self): bus_name = dbus.service.BusName('org.me.test', bus=dbus.SessionBus()) dbus.service.Object.__init__(self, bus_name, '/org/me/test') @dbus.service.method('org.me.test') def hello(self): #Gtk.main_quit() # Terminate after running. Daemons don't use this. return "Hello,World!" DBusGMainLoop(set_as_default=True) myservice = MyDBUSService() Gtk.main()
Daemon that runs all the time
Just run the script at startup (or login). Or send a dbus-send message to the service, and dbus will start it. It will be terminated as part of shutdown (or logout). While it's running, it's introspectable and visible from d-feet.
Dbus-initiated start
Add a .service file. This file simply tells dbus how to start the service.
Here's an example service file:
# Service file: /usr/share/dbus-1/services/test.service [D-BUS Service] Name=org.me.test Exec="/home/me/test-dbus.py"
Dbus should automatically pick up the new service without need for any restart. Let's test if dbus discovered the service:
$ dbus-send --session --print-reply \ --dest="org.freedesktop.DBus" \ /org/freedesktop/DBus \ org.freedesktop.DBus.ListActivatableNames \ | grep test string "org.me.test"
The new service does not show up in d-feet until after it is run the first time, since before there is nothing to probe or introspect. But it does exist, and is findable and usable by other dbus-aware applications.
Let's try the new service:
$ dbus-send --session --print-reply \ --dest="org.me.test" /org/me/test org.me.test.hello method return sender=:1.239 -> dest=:1.236 reply_serial=2 string "Hello,World!" $ dbus-send --session --print-reply \ --dest="org.me.test" /org/me/test org.me.test.Frank Error org.freedesktop.DBus.Error.UnknownMethod: Traceback (most recent call last): File "/usr/lib/python3/dist-packages/dbus/service.py", line 654, in _message_cb (candidate_method, parent_method) = _method_lookup(self, method_name, interface_name) File "/usr/lib/python3/dist-packages/dbus/service.py", line 246, in _method_lookup raise UnknownMethodException('%s is not a valid method of interface %s' % (method_name, dbus_interface)) dbus.exceptions.UnknownMethodException: org.freedesktop.DBus.Error.UnknownMethod: Unknown method: Frank is not a valid method of interface org.me.test
It worked! Dbus launches the script, waits for the service to come up, then asks the service for the appropriate method.Upon execution of the method, the waiting loop terminates, and the script finishes and shuts down.
As a test, you can see that 'hello' is indeed a valid method and returns a valid response, while the invalid method 'Frank' causes a not-found error.
Dbus-initiated stop
Dbus doesn't stop scripts or processes. But a script can stop itself.
In order to wait for input, python-dbus uses a
Gtk.main()
loop. In this case, simply uncomment the line Gtk.main_quit()
. When the method is called,the main()
loop gets terminated, and the script continues to the next loop or end.If you use on-demand starting and stopping, be aware that the service will exist, but will be visible in d-feet or introspectable only for the few seconds it's actually running.
Obsolete: Before python included introspection, you needed to include an interface definition. But you don't need this anymore - introspection seems to have replaced it. Avoid confusion - some old tutorials out there still include it.
<?xml version="1.0" encoding="UTF-8"?> <!-- /usr/share/dbus-1/interfaces/org.me.test.xml --> <node name="/org/me/test"> <interface name="org.me.test"> <annotation name="org.freedesktop.DBus.GLib.CSymbol" value="server"/> <method name="EchoString"> <arg type="s" name="original" direction="in" /> <arg type="s" name="echo" direction="out" /> </method> <!-- Add more methods/signals if you want --> </interface> </node>
No comments:
Post a Comment