Code Monkey home page Code Monkey logo

lua-dbus_proxy's Introduction

Build Status codecov

DBus Proxy Objects for Lua - @VERSION@

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.


lua-dbus_proxy's People

Contributors

frenzox avatar jcrd avatar stefano-m avatar unai-ndz avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar

lua-dbus_proxy's Issues

can't call method declared as a{sv}

This may well just be my lack of understanding of DBus. I'm trying to make a voice call using ModemManager, but not getting very far. I pass it {Number = "+15005550002"} and it reports
an error

/nix/store/q7h8zgwc4zc59351gzjyj8hcik81w1bs-lua-5.3.6/bin/lua: ...ua-5.3.6-env/share/lua/5.3/lgi/override/GLib-Variant.lua:111: bad argument #2 to 'new_variant' (GLib.Variant expected, got string).

I also tried voice():CreateCall({Number = GV("s","+15005550002")}) but that gives me (GLib.Variant expected, got userdata)

What am I doing wrong? All help gratefully received

Here's the full script, though I don't know if you'll need a modem installed to replicate it.

local lgi = require("lgi")
local dbus = require("dbus_proxy")
local GLib = lgi.GLib
local GV = lgi.GLib.VariantType
local modem_manager = (dbus.Proxy):new({bus = dbus.Bus.SYSTEM, name = "org.freedesktop.ModemManager1", interface = "org.freedesktop.DBus.ObjectManager", path = "/org/freedesktop/ModemManager1"})

local function voice()
  return (dbus.Proxy):new({bus = dbus.Bus.SYSTEM, name = "org.freedesktop.ModemManager1", interface = "org.freedesktop.ModemManager1.Modem.Voice", path = next(modem_manager:GetManagedObjects())})
end

voice():CreateCall({Number = "+15005550002"})

PS not a real phone number, it comes from https://www.twilio.com/docs/iam/test-credentials#test-calls

Support for asynchronous method calls

Hi,

I see that currently generated methods are called using the g_dbus_proxy_call_sync function. This is fine for non intensive tasks, but when methods can take longer to return, using the synchronous call can be an issue.

Would it be possible to generate an asynchronous version of the proxy methods as well?

disconnect from signal

Hello,

I use the function :

proxy:connect_signal(callback, "PropertiesChanged", nil)

But sometimes, I would like to remove the function attached to the signal. But I did not find a function suitable for this. Ho can I do that ?

If I try to attach a void function, will it remove the callback one ?

proxy:connect_signal(function () end, "PropertiesChanged", nil)

extend set_property?

In _proxy.lua, the getter's and setter's are not as intuitive as they should be.

get_property returns some sort of Lua'ized version of the result where some of the GVariants are translated to plain Lua.
set_property does nothing like auto conversion to GVariant.

Maybe a minimum solution would be something like:

local function set_property(proxy, name, opts)
  local variant_value
  local vtype = type(opts)
  if vtype == "userdata" and tostring(opts):find("GLib%.Variant$") then
    variant_value = opts
  elseif vtype == "table" and opts.signature and opts.value then
    variant_value = GVariant(opts.signature, opts.value)
  else
    error("Wrong parameter, should be table with { .signature and .value } or GVariant")
  end
  proxy._proxy:set_cached_property(name, variant_value)
end

This may report a correct error and also accepts GVariants if they are passed.
It may also be nice to have a converter for the basic types (number, string) but that's just an idea.

What do you think?

Creating a proxy fails when a remote object has a method and a property with the same name

Happened to me when I asked systemd1 for a unit object

$ gdbus introspect --system --dest org.freedesktop.systemd1 --object-path /org/freedesktop/systemd1/unit/avahi_2ddaemon_2eservice /org/freedesktop/systemd1/unit/avahi_2ddaemon_2eservice | grep -e "Restart"
      readonly s Restart = 'no';            <--- property
      readonly t RestartUSec = 100000;
      readonly (aiai) RestartPreventExitStatus = ([], []);
      readonly (aiai) RestartForceExitStatus = ([], []);
      readonly u NRestarts = 0;
      readonly i RestartKillSignal = 15;
      Restart(in  s mode,          <--- method
      TryRestart(in  s mode,
      ReloadOrRestart(in  s mode,
      ReloadOrTryRestart(in  s mode,

This example fails with Property 'Restart' is not writable right in the proxy constructor.

I patched this for myself by namespacing properties with prop_, but can't PR that due to obvious compatibility issues

fails to install on lua 5.4-1, fedora 36

x inxi -S
System:
  Host: pennyroyal Kernel: 5.19.15-201.fc36.x86_64 arch: x86_64 bits: 64
    Desktop: awesome v: 4.3 Distro: Fedora release 36 (Thirty Six)

x luarocks install --local dbus_proxy 
Installing https://luarocks.org/dbus_proxy-0.10.3-2.src.rock
Missing dependencies for dbus_proxy 0.10.3-2:
   lgi >= 0.9.0, < 1 (not installed)

dbus_proxy 0.10.3-2 depends on lua >= 5.1 (5.4-1 provided by VM)
dbus_proxy 0.10.3-2 depends on lgi >= 0.9.0, < 1 (not installed)
Installing https://luarocks.org/lgi-0.9.2-1.src.rock

lgi 0.9.2-1 depends on lua >= 5.1 (5.4-1 provided by VM)
make -C lgi
make[1]: Entering directory '/tmp/luarocks_lgi-0.9.2-1-lhkOk5/lgi/lgi'
pkg-config --exists 'gobject-introspection-1.0 >= 0.10.8' --print-errors
touch .depcheck
gcc -fPIC  -O2 -fPIC -I/usr/include -I/usr/include/gobject-introspection-1.0 -I/usr/include/glib-2.0 -I/usr/lib64/glib-2.0/include -I/usr/include/sysprof-4 -pthread  -Wall -Wextra -O2 -g -c -o buffer.o buffer.c
gcc -fPIC  -O2 -fPIC -I/usr/include -I/usr/include/gobject-introspection-1.0 -I/usr/include/glib-2.0 -I/usr/lib64/glib-2.0/include -I/usr/include/sysprof-4 -pthread  -Wall -Wextra -O2 -g -c -o callable.o callable.c
callable.c: In function ‘closure_callback’:
callable.c:1237:13: error: too few arguments to function ‘lua_resume’
 1237 |       res = lua_resume (L, NULL, npos);
      |             ^~~~~~~~~~
In file included from lgi.h:11,
                 from callable.c:12:
/usr/include/lua.h:300:15: note: declared here
  300 | LUA_API int  (lua_resume)     (lua_State *L, lua_State *from, int narg,
      |               ^~~~~~~~~~
make[1]: *** [Makefile:63: callable.o] Error 1
make[1]: Leaving directory '/tmp/luarocks_lgi-0.9.2-1-lhkOk5/lgi/lgi'
make: *** [Makefile:16: all] Error 2

Error: Failed installing dependency: https://luarocks.org/lgi-0.9.2-1.src.rock - Build error: Failed building.

Installation via Luarocks fails with " Error: Couldn't extract archive: unrecognized filename extension"

Installing lua-dbus_proxy via the luarocks cli results in an error:

 % luarocks install --local dbus_proxy 
Installing https://luarocks.org/dbus_proxy-0.10.3-2.src.rock

Error: Couldn't extract archive /tmp/luarocks_dbus_proxy-0.10.3-2-6sTEvt/lua-dbus_proxy: unrecognized filename extension

It only happens for the two 0.10.3 versions, and only when installing from luarocks.org with luarocks install. Manually installing with luarocks make rockspec/dbus_proxy-0.10.3-2.rockspec works fine, so it seems the packages on luarocks.org are broken.

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.