DBus Proxy Objects for Lua - v0.10.3
dbus_proxy is a Lua module built on top of lgi to offer a simple API to GLib's GIO GDBusProxy objects. This should make it easier to interact with DBus interfaces.
Creating a proxy object is as easy as doing
p = require("dbus_proxy") proxy = p.Proxy:new( { bus = p.Bus.SYSTEM, -- or p.Bus.SESSION name = "com.example.BusName", interface = "com.example.InterfaceName", path = "/com/example/objectPath" } )
At this point, all the properties, methods and signals of the object are
available in the proxy
table. Be aware that properties, methods and signals
will likely be written in CamelCase
since this it the convention in DBus
(e.g. proxy.SomeProperty
or proxy:SomeMethod()
). Please refer to the
documentation of the object you are proxying for more information.
NOTE
If a property has the same name as a method, as e.g. it happens with
org.freedesktop.systemd1.Unit
in the case of Restart
, an underscore will
be added to it.
For example:
local p = require("dbus_proxy") local proxy = p.Proxy:new( { bus = p.Bus.SESSION, name = "org.freedesktop.systemd1", interface = "org.freedesktop.systemd1.Unit", path = "/org/freedesktop/systemd1/unit/redshift_2eservice" } ) -- https://github.com/systemd/systemd/blob/v246/src/core/job.c#L1623 local job_mode = "replace" ok, err = proxy:Restart(_job_mode) assert(ok, tostring(err)) print(ok) -- e.g. "/org/freedesktop/systemd1/job/123" restart_property = proxy._Restart -- same as: proxy.accessors._Restart.getter(proxy)
The code is released under the Apache License Version 2.0, see the LICENSE file for full information.
For more detailed information, see the documentation in the docs
folder.
Motivation
I have written a few widgets for the Awesome Window Manager that use DBus. The
widgets depend on ldbus_api
-
also written by me - which is a high level API written on top
of ldbus
. ldbus
has
an outstanding bug that may
cause of random crashes. I have been looking into a more actively developed
library to replace ldbus_api
and ldbus
and found lgi
, which offers a much
better way of interacting with DBus using GIO's Proxy objects.
Documentation
The documentation is built using ldoc
. For
convenience, a copy of the generated documentation is available in the docs
folder.
To generate the documentation from source, run
ldoc .
from the root of the repository.
Installation
Luarocks
You can install dbus_proxy with luarocks
by running:
luarocks install dbus_proxy
You may need to use the --local
option if you can't or don't want to install
the module at the system level.
NixOS
If you are on NixOS, you can install this package from nix-stefano-m-overlays.
Testing
To test the code, you need to install the busted framework. Then run
busted .
(node the dot!) from the root of the repository to run the tests.
The tests depend on a number of DBus interfaces being available on the system. It would be nice to not depend on this, but I don't have time to come up with a complete DBus mock (contributions are welcome!).
Contributing
This project is developed in my own spare time, progress will likely be slow as soon as I reach a decent level of satisfaction with it. That said, for feedback, suggestions, bug reports and improvements, please create an issue in GitHub and I'll do my best to respond.
Synchronizing Proxy Objects
As already explained, the Proxy objects expose methods, properties and signals of the corresponding remote DBus objects. When a property in a DBus object changes, the same change is reflected in the proxy. Similarly, when a signal is emitted, the proxy object is notified accordingly.
For all this to work though, the code must run inside GLib's main event loop. This can be achieved in two ways:
- Create a main loop and run it when the application starts:
GLib = require("lgi").GLib -- Set up the application, then do: main_loop = GLib.MainLoop() main_loop:run() -- use main_loop:quit() to stop the main loop.
- Use more fine-grained control by running an iteration at a time from the main context; this is particularly useful when you want to integrate your code with an external main loop:
GLib = require("lgi").GLib -- Set up the code, then do ctx = GLib.MainLoop():get_context() -- Run a single blocking iteration if ctx:iteration(true) == true then print("something changed!") end -- Run a single non-blocking iteration if ctx:iteration() == true then print("something changed here too!") end
NOTE
If you use the Awesome Window Manager, the code will be already running inside a main loop.