diwic / dbus-rs Goto Github PK
View Code? Open in Web Editor NEWD-Bus binding for the Rust language
License: Other
D-Bus binding for the Rust language
License: Other
This question is somewhat related to the problem of method dispatch on multiple parameters (rather than just the first).
I am planning to have a method, m, which accepts object paths as arguments. The client has identified the appropriate object paths to pass as arguments by examining the result of GetManagedObjects() and identifying the correct object paths by matching on the interface and property values. The arguments as received by the service have been constructed as MessageItem::ObjectPath<some Path>
. So, while the first argument, on which the method has been dispatched, contains the actual object path with associated data, the other object path arguments do not.
It is desirable, from my point of view, to use the Path
argument to obtain the corresponding ObjectPath
from the tree. The reason for this is that I plan to have decorated the ObjectPath with essential data which my method requires for its operation. At this time, it is not possible to lookup an ObjectPath in the tree in order to discover its data.
Is that a fundamental limitation, or could it be removed by means of a get
method on the tree?
Note: It would also be possible to have a look-aside table attached to the tree which mapped Path
s to the appropriate data and to choose not to decorate the ObjectPath at all. But that seems to be working a bit outside the expectations of this library and seems kind of clumsy.
Hi,
I'm the creator of pydbus, DBus bindings for Python. I've stumbled upon the case of bytestrings - ay - which are commonly used to send non-Unicode data over DBus.
Because of the GDBus's API, apps commonly require these strings to be '\0'-terminated. And that's completely unintuitive for high-level languages, and something that requires the user to read API docs.
I'm thinking about solving the problem automatically, and I see two solutions:
Whatever we choose, the solution should be agreed upon by authors of bindings for all languages. That's why I'm here.
Do you have any experience with "ay"-encoded bytestrings?
Relevant discussion: LEW21/pydbus#27
Thank you for the great rust wrapper! I have a question.
I can't find any example on how to parse the input arguments and convert from MessageItem to for example String. Is this not implemented yet? If it is, how can get the incoming arguments as native types, ie, i32, String, etc?
Couldn't find if there were any other venues to ask question, sorry for the issue noise.
I'm working on a screensaver and I'd like to use DBus for communication, so I can have a server that creates a DBus interface and whatnot and wait for requests like to start the screensaver or lock the screen.
Since there are also other things involved the design from the example with the closures seems rather complicated to fit into my design.
What I'm trying to achieve is having a Server
struct that contains the connection/tree/whatever which spawns a thread, and this thread sends the DBus calls being received through a channel, then the loop in main
reads from the channel, does some thing and calls the proper stuff to respond to the request and writes back to another channel, and then the thread spawned by Server
responds back through DBus.
Is this currently possible without hacking it up using the Factory::method
closures? Are there any examples to do this I missed?
Thanks.
I have requests that take a while until they are processed and a response can be given.
AFAIK, you would have to spawn a new process for each request to keep the dbus interface responsive while processing one request, so something like
for n in conn.iter(1000) {
thread::spawn(|| {
match n {
ConnectionItem::MethodCall(mut m) => {
o.handle_message(&mut m);
},
_ => (),
}
});
}
However, n
cannot be sent to another thread:
src/dbus_service.rs:51:4: 51:17 error: the trait `core::marker::Send` is not implemented for the type `alloc::rc::Rc<dbus::objpath::IObjectPath<'_>>` [E0277]
src/dbus_service.rs:51 thread::spawn(|| {
^~~~~~~~~~~~~
note: in expansion of for loop expansion
src/dbus_service.rs:50:3: 59:4 note: expansion site
src/dbus_service.rs:51:4: 51:17 note: `alloc::rc::Rc<dbus::objpath::IObjectPath<'_>>` cannot be sent between threads safely
src/dbus_service.rs:51 thread::spawn(|| {
^~~~~~~~~~~~~
note: in expansion of for loop expansion
src/dbus_service.rs:50:3: 59:4 note: expansion site
src/dbus_service.rs:51:4: 51:17 error: the trait `core::marker::Sync` is not implemented for the type `*mut libc::types::common::c95::c_void` [E0277]
src/dbus_service.rs:51 thread::spawn(|| {
^~~~~~~~~~~~~
note: in expansion of for loop expansion
src/dbus_service.rs:50:3: 59:4 note: expansion site
src/dbus_service.rs:51:4: 51:17 note: `*mut libc::types::common::c95::c_void` cannot be shared between threads safely
src/dbus_service.rs:51 thread::spawn(|| {
^~~~~~~~~~~~~
note: in expansion of for loop expansion
src/dbus_service.rs:50:3: 59:4 note: expansion site
error: aborting due to 2 previous errors
Is there a way to fix this?
Hi (again)
Is it possible to make MethodHandler FnMut? I want to be able to change the state of my program from the method callback but this is not possible if Fn is used for the closure..
Is there any interest in moving rustc serialize support for ItemMessage
into dbus-rs?
Hi!
This is more of a question than a bug as it seems like all the dbus implementations that I have looked at work the same.
Basically, it seems that a service writes some code that determines the introspection information that can be obtained over the dbus via the Introspect method. Also, it writes some code that puts messages on the dbus. These messages are supposed to conform to the signature information that the client can get via the Introspect method. But the dbus libraries, including yours, don't seem to have any mechanism in place for ensuring that this happens correctly, or for detecting errors. Basically, making sure that the actual values match the published signature seems to be entirely up to the programmer.
I am wondering if there is a way of fixing this problem in a library written in a language which is statically checked and has a fairly flexible type system like Rust does.
Hello,
I also commented in the now-closed issue #33, which fixed the bug, but wasn't sure if you'd be notified.
But I was wondering if you could publish a new version to crates with the bugfix. I'd like to publish my secret service library, which depends on the bugfix.
I don't think I can use your github repo as the dependency source for crates.io, but if there's another workaround for now I'd be happy to do it.
Hi, my friend @tasleson did some work to find out the memory usage of using dbus, and saw high memory usage by dbus-rs, worse than when implemented in Python. His code is here:
https://github.com/tasleson/misc-tools/tree/master/dbus_memory/rust
My theory is this is because dbus-rs is not sharing identical strings, such as interface or property names, that sort of thing, which adds up when there are large numbers of each, but this is just a guess at the moment.
Hi, I'm using your library to cut my teeth with Rust.
Namely I'm trying to retrieve metadata of the current song played by VLC:
let c = Connection::get_private(BusType::Session).unwrap();
let p = Props::new(&c, "org.mpris.MediaPlayer2.vlc",
"/org/mpris/MediaPlayer2",
"org.mpris.MediaPlayer2.Player",
10000);
let res : Result<MessageItem, _> = p.get("Metadata");
match res {
dbus::arg::Array(res) => Ok(res),
// ....
};
However I can't use the dbus::arg::XXX
methods as suggested in #39 to retrieve the item(s) from the Props
, I have a casting error like mismatched types (expected enum 'std::result::Result', found struct 'dbus::arg::Array')
. Dumping directly with a println!
shows the correct content:
Ok(Array([DictEntry(Str("mpris:trackid"), Variant(ObjectPath(Path("/org/videolan/vlc/playlist/15")))), DictEntry(Str("xesam:url"), ....)
How do I iterate the std::result::Result
to a dbus::arg::Array
and friends (Variant
, Dict
, etc.)?
Thank you so much for a hint!
Hiya,
We're still stuck on the issues raised by #40. We want the good stuff a tree provides (introspection, object manager, method dispatch) and also be able to add and remove object paths. This is important because we want to have our DBus interface create and remove objects and interfaces at runtime, and it's currently not possible, although we keep coming back to this as a natural way to want to design an API.
One easy thing would be to Add Tree::add_o_path()
to tree/objectpath.rs Tree
. This makes it possible to add an objectpath to the tree from a tree's method (although this requires an unsafe
conversion of &m.tree
to a &mut m.tree
, it's a least possible) (This should not cause issues as long as it's always a different ObjectPath we're adding or removing than the objectpath/interface our method was invoked on)
Thinking longer-term, I'm wondering how hard it would be to make MethodInfo::tree a mutable ref (I tried it, 'a
s blossomed everywhere and I gave up, but you might have more luck) Or, I noticed that the only users of MethodInfo::tree are introspection and managed_objects, that call tree::children()
, which then filters for children within the object path -- could there be a more distributed method of iterating and looking up object paths that would not require the entire &Tree
? If so then an objectpath's method could be called without referencing the tree, and enclosing Tree
in Rc<RefCell>>
would let us close over and modify the tree without unsafe
.
It would be nice if it was easier to use this dbus library in an async fashion.
When sending a struct
in an array
like this
extern crate dbus;
use dbus::{Connection, BusType, MessageItem, Message};
fn main() {
let c = Connection::get_private(BusType::Session).unwrap();
let mut m = Message::new_method_call("org.test.rust",
"/", "org.test.rust",
"Test").unwrap();
let a = MessageItem::from("test".to_string());
let b = MessageItem::from("test".to_string());
let foo = MessageItem::Struct(vec!(a, b));
let bar = foo.clone();
let args = [MessageItem::new_array(vec!(foo, bar)).unwrap()];
println!("{:?}", args);
m.append_items(&args);
c.send(m).unwrap();
}
The signature is set to "r", which, according to the D-Bus documentation, "is reserved for use in bindings and implementations to represent the general concept of a struct, and must not appear in signatures used on D-Bus".
Trying to send such a Message results in
arguments to dbus_message_iter_open_container() were incorrect, assertion "(type == DBUS_TYPE_ARRAY && contained_signature && *contained_signature == DBUS_DICT_ENTRY_BEGIN_CHAR) || (contained_signature == NULL || _dbus_check_is_valid_signature (contained_signature))" failed in file dbus-message.c line 2914.
This could or could not be a bug in the dbus library according to this and this.
Anyways manually setting the signature works around the issue:
extern crate dbus;
use dbus::{Connection, BusType, MessageItem, Message};
use std::borrow::Cow;
fn main() {
let c = Connection::get_private(BusType::Session).unwrap();
let mut m = Message::new_method_call("org.test.rust",
"/", "org.test.rust",
"Test").unwrap();
let a = MessageItem::from("test".to_string());
let b = MessageItem::from("test".to_string());
let foo = MessageItem::Struct(vec!(a, b));
let bar = foo.clone();
let args = [MessageItem::Array(vec!(foo, bar), Cow::Owned("(ss)".to_string()))];
m.append_items(&args);
c.send(m).unwrap();
}
Hey there, sorry if this is a dumb question, but the docs for D-Bus are very technical and there doesn't seem to be much else out there on the web.
If I want to only allow certain clients to use an interface/method, how would I go about doing that through this crate? I saw this question on stackexchange that mentioned a ~/.dbus-keyrings
folder, but wasn't sure how that relates to having different interfaces/methods exposed to clients.
I could do something application side (e.g with tokens/a listing of whitelisted clients), but I wanted to see if there was an easier and more idiomatic way before going down that route.
I get this error when calling GetManagedObjects
from qdbusviewer-qt5. Here's my code for reference.
process 12282: Array or variant type requires that type object_path be written, but string was written.
The overall signature expected here was 'a{oa{sa{sv}}}' and we are on byte 2 of that signature.
D-Bus not built with -rdynamic so unable to print a backtrace
I am trying to use this library to get connection info from NetworkManager using the GetSettings
method. I used D-Feet to try out the function which has a signature of GetSettings() -> (Dict of {String, Dict of {String, Variant} } settings)
, the data returned by D-Feet is below:
{'802-11-wireless': {'mac-address': [228, 179, 24, 77, 64, 139],
'mac-address-blacklist': [],
'mode': 'infrastructure',
'security': '802-11-wireless-security',
'seen-bssids': ['02:1D:AA:80:1B:DA', '02:1D:AA:80:1D:12'],
'ssid': [80,
108,
111,
117,
103,
104,
32,
87,
97,
121,
32,
67,
97,
102,
101]},
'802-11-wireless-security': {'auth-alg': 'open',
'group': [],
'key-mgmt': 'wpa-psk',
'pairwise': [],
'proto': []},
'connection': {'id': 'Plough Way Cafe',
'permissions': [],
'secondaries': [],
'timestamp': 1479304123,
'type': '802-11-wireless',
'uuid': 'ff9b7028-0911-491a-bfe8-53cba76069da'},
'ipv4': {'address-data': [],
'addresses': [],
'dns': [],
'dns-search': [],
'method': 'auto',
'route-data': [],
'routes': []},
'ipv6': {'address-data': [],
'addresses': [],
'dns': [],
'dns-search': [],
'method': 'auto',
'route-data': [],
'routes': []}}
and my code:
extern crate dbus;
fn main() {
let message = dbus::Message::new_method_call("org.freedesktop.NetworkManager",
"/org/freedesktop/NetworkManager/Settings/0",
"org.freedesktop.NetworkManager.Settings.\
Connection",
"GetSettings")
.unwrap();
let response = dbus::Connection::get_private(dbus::BusType::System)
.unwrap()
.send_with_reply_and_block(message, 2000)
.unwrap();
println!("{:?}", response);
let test: dbus::arg::Dict<&str, dbus::arg::Dict<&str, dbus::arg::Variant<()>, _>, _> =
response.get1().unwrap();
println!("{:?}", test);
}
which results in this error:
error[E0277]: the trait bound `(): dbus::arg::Get<'_>` is not satisfied
--> src/main.rs:20:18
|
20 | response.get1().unwrap();
| ^^^^ the trait `dbus::arg::Get<'_>` is not implemented for `()`
|
= note: required because of the requirements on the impl of `dbus::arg::Get<'_>` for `dbus::arg::Variant<()>`
= note: required because of the requirements on the impl of `dbus::arg::Get<'_>` for `dbus::arg::Dict<'_, &str, dbus::arg::Variant<()>, dbus::arg::Iter<'_>>`
= note: required because of the requirements on the impl of `dbus::arg::Get<'_>` for `dbus::arg::Dict<'_, &str, dbus::arg::Dict<'_, &str, dbus::arg::Variant<()>, dbus::arg::Iter<'_>>, dbus::arg::Iter<'_>>`
How can I get the connection info?
I thought the whole point of Variant
is that it can hold different types of data? What am I doing wrong?
If I substitute the Variant
type ()
with &str
it prints out Dict(Iter("Unknown?!", "Unknown?!", "Unknown?!", "Unknown?!", "Unknown?!"), PhantomData)
. What is the Unknown?!
value?
The API for Dict
also states
Creates a new
Dict
from an iterator. The iterator is consumed when appended.
How/should I use this instead?
UPDATE
I have managed to make some progress, perhaps naively?
My code now looks like this:
extern crate dbus;
extern crate network_manager;
#[derive(Default, Debug)]
struct Connection {
path: String,
id: String,
uuid: String,
ssid: String,
interface: String,
security: String,
psk: String, // Only used when creating a new connection
}
fn main() {
let connection = Connection {
path: "/org/freedesktop/NetworkManager/Settings/0".to_string(),
..Default::default()
};
let message = dbus::Message::new_method_call("org.freedesktop.NetworkManager",
connection.path.clone(),
"org.freedesktop.NetworkManager.Settings.\
Connection",
"GetSettings")
.unwrap();
let response = dbus::Connection::get_private(dbus::BusType::System)
.unwrap()
.send_with_reply_and_block(message, 2000)
.unwrap();
let mut outer_array_iter = response.iter_init().recurse(97).unwrap();
loop {
let mut outer_dict_iter = outer_array_iter.recurse(101).unwrap();
outer_dict_iter.next();
let mut inner_array_iter = outer_dict_iter.recurse(97).unwrap();
loop {
let mut inner_dict_iter = inner_array_iter.recurse(101).unwrap();
let key = inner_dict_iter.read::<&str>().unwrap();
match key {
"id" => {
let val: dbus::arg::Variant<&str> = inner_dict_iter.read().unwrap();
println!("id {:?}", val);
}
"uuid" => {
let val: dbus::arg::Variant<&str> = inner_dict_iter.read().unwrap();
println!("uuid {:?}", val);
}
"ssid" => {
let val: dbus::arg::Variant<dbus::arg::Array<i32, _>> = inner_dict_iter.read()
.unwrap();
println!("ssid {:?}", val);
}
"type" => {
let val: dbus::arg::Variant<&str> = inner_dict_iter.read().unwrap();
println!("interface {:?}", val);
}
"security" => {
let val: dbus::arg::Variant<&str> = inner_dict_iter.read().unwrap();
println!("security {:?}", val);
}
_ => (),
}
if !(inner_array_iter.next()) {
break;
}
}
if !(outer_array_iter.next()) {
break;
}
}
println!("{:?}", connection);
}
this prints out:
id Variant("Plough Way Cafe")
uuid Variant("e078808e-626f-4be9-bbb4-5e48b1d626de")
interface Variant("802-11-wireless")
ssid Variant(Array(Iter("u8", "u8", "u8", "u8", "u8", "u8", "u8", "u8"), PhantomData))
security Variant("802-11-wireless-security")
Connection { path: "/org/freedesktop/NetworkManager/Settings/0", id: "", uuid: "", ssid: "", interface: "", security: "", psk: "" }
How can I get the data out of Variant
and into my connection
struct?
Is there a better way to use iterators as this feels v.fragile?
Thanks
...rather than an i32. This is a small breaking change, but I'm keeping it here so I remember it next time I do breaking changes.
It runs just fine on 1.4.0-nightly, but fails on 1.5.0-stable and 1.7.0-nightly.
src/methoddisp.rs:793:88: 797:6 error: `count` does not live long enough
src/methoddisp.rs:793 let _setme = i.add_p_ref(f.property("setme", 0u8).access(Access::ReadWrite).on_set(|_,_,_| {
src/methoddisp.rs:794 let v: i32 = count.get_value().inner().unwrap();
src/methoddisp.rs:795 count.set_value((v + 1).into()).unwrap();
src/methoddisp.rs:796 Ok(vec!())
src/methoddisp.rs:797 }));
src/methoddisp.rs:787:27: 798:2 note: reference must be valid for the block at 787:26...
src/methoddisp.rs:787 fn prop_lifetime_simple() {
src/methoddisp.rs:788 let count;
src/methoddisp.rs:789 let f = Factory::new_fnmut();
src/methoddisp.rs:790 let mut i = f.interface("com.example.dbus.rs");
src/methoddisp.rs:791 count = i.add_p_ref(f.property("changes", 0i32));
src/methoddisp.rs:792
...
src/methoddisp.rs:788:15: 798:2 note: ...but borrowed value is only valid for the block suffix following statement 0 at 788:14
src/methoddisp.rs:788 let count;
src/methoddisp.rs:789 let f = Factory::new_fnmut();
src/methoddisp.rs:790 let mut i = f.interface("com.example.dbus.rs");
src/methoddisp.rs:791 count = i.add_p_ref(f.property("changes", 0i32));
src/methoddisp.rs:792
src/methoddisp.rs:793 let _setme = i.add_p_ref(f.property("setme", 0u8).access(Access::ReadWrite).on_set(|_,_,_| {
I'm writing a GUI front-end to systemd for managing system services and although I am able to get a list of unit files from dbus using this wrapper, I'm not quite sure how to go about sending the information needed to disable and enable services through dbus. The following is what I'm using to get the information I need, and this works perfectly.
let connection = dbus::Connection::get_private(dbus::BusType::System).unwrap();
let message = dbus::Message::new_method_call("org.freedesktop.systemd1",
"/org/freedesktop/systemd1", "org.freedesktop.systemd1.Manager", "ListUnitFiles").
unwrap_or_else(|e| panic!("{}", e));
let reply = connection.send_with_reply_and_block(message, 1000).unwrap();
Now I need to call the EnableUnitFiles() and DisableUnitFiles() methods with information I've gained from the first method, which requires a list of pathnames (I'll only do one at a time) with two booleans, yet I'm not quite sure how to accomplish this.
Object paths supported by a tree may come and go. Tree has an add()
but lacks remove()
. It's easy to add a remove() that just removes it from self.paths, but it looks like we also need to call c.unregister_object_path...but only if after set_registered() has been called. So basically I'm thinking to enable adding/removing object paths at runtime we need to either pass c to add() & remove() and register/unregister within those functions, but then we don't really need set_registered() any more? But then maybe we want to unregister any remaining paths from Drop?
Wanted to get your thoughts on what it would take to properly enable this.
Is there a recommended way to do this?
I think that the get*() methods themselves do not distinguish; they return None if the arg is missing or has the wrong type.
I've come up with an approach that looks something like this:
let message: &Message = m.msg;
let item: MessageItem = try!(message.get1().ok_or_else(MethodErr::no_arg));
let name: &str = try!(message.get1().ok_or_else(|| MethodErr::invalid_arg(&item)));
...
The results I get are nice and distinguish between the two situatons:
[mulhern@dhcp-25-209 stratisd]$ busctl --user call org.storage.stratis1 /org/storage/stratis1 org.storage.stratis1.Manager DestroyPool
Not enough arguments
[mulhern@dhcp-25-209 stratisd]$ busctl --user call org.storage.stratis1 /org/storage/stratis1 org.storage.stratis1.Manager DestroyPool i 2
Invalid argument Int32(2)
[mulhern@dhcp-25-209 stratisd]$ busctl --user call org.storage.stratis1 /org/storage/stratis1 org.storage.stratis1.Manager DestroyPool s name
qs 0 "Ok"
Notice, though, how I have to call get1() twice, one to detect if the argument is there at all, and once to detect if the item has the correct type. Should some one in need of this amount of specificity be doing something different?
There is another approach that just considers the entire message an invalid arg, that yields results something like this, if the message has too few args or if the args are ill-typed:
[mulhern@dhcp-25-209 stratisd]$ busctl --user call org.storage.stratis1 /org/storage/stratis1 org.storage.stratis1.Manager DestroyPool i 2
Invalid argument [Int32(2)]
[mulhern@dhcp-25-209 stratisd]$ busctl --user call org.storage.stratis1 /org/storage/stratis1 org.storage.stratis1.Manager DestroyPool
Invalid argument []
[mulhern@dhcp-25-209 stratisd]$ busctl --user call org.storage.stratis1 /org/storage/stratis1 org.storage.stratis1.Manager DestroyPool s name
qs 0 "Ok"
It is implemented kind of like this:
let message: &Message = m.msg;
let name: &str = try!(message.get1().ok_or_else(|| MethodErr::invalid_arg(&message.get_items())));
...
Thanks for any help you can give.
Hi,
I am working on a Yocto/OE recipe for building RVI SOTA client which is written in the Rust programming language and depends on crate dbus-rs version 0.1.2. I noticed that the crate fails to build for ARM due to mismatched types. In my opinion c_char raw pointers should be cast correctly to make it work for ARM. I have already created a patch for version 0.1.2 as part of the Yocto/OE recipe. In my opinion similar patches have to be applied to the latest versions of files src/lib.rs and src/message.rs.
Best regards, Leon
Hi,
I'm experiencing an artefact where some tools that interrogate the D-Bus service think that the signature of a property is a Variant containing a type X, and others think that it is the bare type X.
Compare the following:
[mulhern@dhcp-25-209 stratisd-client-dbus]$ busctl --user get-property org.storage.stratis1 /org/storage/stratis1 org.storage.stratis1.Manager RedundancyCodes
a(sq) 1 "RAID0" 0
From QT5DbusViewer
Received reply from :1.6899
Arguments: [Variant: [Argument: a(sq) {[Argument: (sq) "RAID0", 0]}]]
From dbus-python
(Pdb) Manager.Properties.RedundancyCodes(self._proxy)
dbus.Array([dbus.Struct((dbus.String('RAID0'), dbus.UInt16(0)), signature=None)], signature=dbus.Signature('(sq)'), variant_level=1)
Note how the bottom 2 think that they're dealing with a variant type, while busctl does not seem to.
Note also that it is not the type within the array that is a variant, but the array itself.
Have you heard of this and do you think it's likely that it is a result of some dbus-rs behavior? I had originally ruled that out, because busctl does not indicate that the result is a variant. But I have also noticed that you have a publicly defined get_as_variant()
method on the Property, and I'm not sure of its purpose or when it might be called.
Please let me know if you have any thoughts,
Thanks!
Don't know how much work this would be, but just wanted to open this issue to indicate it is desired 😄
process 11575: arguments to dbus_message_iter_open_container() were incorrect, assertion "(type == DBUS_TYPE_ARRAY && contained_signature && *contained_signature == DBUS_DICT_ENTRY_BEGIN_CHAR) || (contained_signature == NULL || _dbus_check_is_valid_signature (contained_signature))" failed in file dbus-message.c line 2878. This is normally a bug in some application using the D-Bus library. D-Bus not built with -rdynamic so unable to print a backtrace
Looks like this is in iter_append_array
. The typesig for the failing operation is {sv}
and the a parameter is [DictEntry(Str("BlockDevices"), Variant(Array([Struct([Str("/dev/vdd"), UInt32(0)]), Struct([Str("/dev/vdb"), UInt32(0)]), Struct([Str("/dev/vdc"), UInt32(0)])], "(su)")))]
For reference, the code where I'm building the MessageItem is https://github.com/agrover/froyo/blob/master/src/dbus_api.rs#L38 in case the error lies there.
Two reasons:
-rs
suffix is redundant, since the fact that it's on crates.io already tells us it's Rust.extern crate "dbus-rs" as dbus;
.dbus
is still free on crates.io, so now's a great opportunity to grab the name.
Great library, but I'm having a huge problem with the fact that you cannot create an empty array (see https://github.com/diwic/dbus-rs/blob/master/src/message.rs#L208) which is a huge problem (for example if you want to return a list of some search results that is empty).
I think that this issue could be resolved easily by just passing the type signature as a parameter.
I’m prototyping a program which communicates with Avahi via dbus. Avahi sends signals for newly discovered services, so my code looks like this:
extern crate dbus;
#[derive(Debug)]
struct ServiceBrowserItemNew {
interface: i32,
protocol: i32,
name: String,
item_type: String,
domain: String,
flags: u32,
}
fn service_browser_item_new_msg(m: &dbus::Message) -> Option<ServiceBrowserItemNew> {
let mut iter = m.iter_init();
let interface = iter.get::<i32>().unwrap();
assert!(iter.next());
let protocol = iter.get::<i32>().unwrap();
assert!(iter.next());
let name = iter.get::<&str>().unwrap().to_string();
assert!(iter.next());
let item_type = iter.get::<&str>().unwrap().to_string();
assert!(iter.next());
let domain = iter.get::<&str>().unwrap().to_string();
assert!(iter.next());
let flags = iter.get::<u32>().unwrap();
Some(ServiceBrowserItemNew {
interface: interface,
protocol: protocol,
name: name,
item_type: item_type,
domain: domain,
flags: flags,
})
}
fn focus_msg(ci: &dbus::ConnectionItem) -> Option<ServiceBrowserItemNew> {
let m = if let &dbus::ConnectionItem::Signal(ref s) = ci {
s
} else {
return None;
};
if &*m.interface().unwrap() == "org.freedesktop.Avahi.ServiceBrowser" &&
&*m.member().unwrap() == "ItemNew" {
return service_browser_item_new_msg(m);
}
None
}
fn main() {
let c = dbus::Connection::get_private(dbus::BusType::System).unwrap();
let sbn = dbus::Message::new_method_call("org.freedesktop.Avahi",
"/",
"org.freedesktop.Avahi.Server",
"ServiceBrowserNew").unwrap()
.append1(-1i32) // interface: AVAHI_IF_UNSPEC
.append1(-1i32) // protocol: AVAHI_PROTO_UNSPEC (ipv4+ipv6)
.append1("_googlecast._tcp") // type
.append1("") // TODO: is "" == null?
.append1(0u32); // flags: 0
let r = c.send_with_reply_and_block(sbn, 2000).unwrap();
let path: dbus::Path = r.get1().unwrap();
println!("returned path = {}", path);
c.add_match("interface='org.freedesktop.Avahi'").unwrap();
for i in c.iter(1000) {
if let Some(app) = focus_msg(&i) {
// e.g. ServiceBrowserItemNew { interface: 3, protocol: 0,
// name: "Chromecast", item_type: "_googlecast._tcp", domain: "local", flags: 5 }
println!("got a message: {:?}", app);
} else {
println!("got message which i do not understand");
}
}
}
The signal decoding part seems pretty cumbersome to me. I’m new to Rust, so it’s pretty likely that I’m missing something, hence I figured I’d ask.
In Go, I can imagine a design using reflection and tags (like JSON and XML decoding work):
type ServiceBrowserItemNew struct {
Interface int32 `dbus:"1"`
Protocol int32 `dbus:"2"`
// …
}
func main() {
// …
for {
msg := <-conn.Items()
if msg.Interface == "org.freedesktop.Avahi.ServiceBrowser" && msg.Member == "ItemNew" {
var sbin ServiceBrowserItemNew
if err := msg.Unmarshal(&sbin); err != nil {
log.Fatal(err)
}
// …
}
}
}
Is something similar possible in Rust with this dbus library? Or is iterating through the individual message arguments really the idiomatic way?
Error
currently uses c pointers, which don't implement the Sync
trait.
error-chain requires errors to implement the Sync
trait since version 0.8.0.
See also: rust-lang-deprecated/error-chain#110
Props returns MessageItem, so one can't use dbus::arg::Array and friends, which I thought was recommended over MessageItem these days?
I'm trying to use dbus
as a dependency, but the build process fails with a type mismatch error in the invocation of cstring_wrapper!()
. Am I doing something wrong?
Compiling dbus v0.5.1
Running `rustc --crate-name dbus /home/pi/.cargo/registry/src/github.com-1ecc6299db9ec823/dbus-0.5.1/src/lib.rs --crate-type lib -g -C metadata=c7a44efa2351d871 -C extra-filename=-c7a44efa2351d871 --out-dir /home/pi/elyo/trunk/rust/test/target/debug/deps --emit=dep-info,link -L dependency=/home/pi/elyo/trunk/rust/test/target/debug/deps --extern libc=/home/pi/elyo/trunk/rust/test/target/debug/deps/liblibc-b4eee0616d69ca39.rlib --cap-lints allow -L native=/usr/lib/arm-linux-gnueabihf -l dbus-1`
error[E0308]: mismatched types
--> /home/pi/.cargo/registry/src/github.com-1ecc6299db9ec823/dbus-0.5.1/src/strings.rs:43:25
|
43 | $t::check_valid(s.as_ptr() as *const i8).map(|_| {
| ^^^^^^^^^^^^^^^^^^^^^^^ expected u8, found i8
...
128 | cstring_wrapper!(Signature, dbus_signature_validate_single);
| ------------------------------------------------------------ in this macro invocation
error[E0308]: mismatched types
--> /home/pi/.cargo/registry/src/github.com-1ecc6299db9ec823/dbus-0.5.1/src/strings.rs:43:25
|
43 | $t::check_valid(s.as_ptr() as *const i8).map(|_| {
| ^^^^^^^^^^^^^^^^^^^^^^^ expected u8, found i8
...
140 | cstring_wrapper!(Path, dbus_validate_path);
| ------------------------------------------- in this macro invocation
error[E0308]: mismatched types
--> /home/pi/.cargo/registry/src/github.com-1ecc6299db9ec823/dbus-0.5.1/src/strings.rs:43:25
|
43 | $t::check_valid(s.as_ptr() as *const i8).map(|_| {
| ^^^^^^^^^^^^^^^^^^^^^^^ expected u8, found i8
...
152 | cstring_wrapper!(Member, dbus_validate_member);
| ----------------------------------------------- in this macro invocation
error[E0308]: mismatched types
--> /home/pi/.cargo/registry/src/github.com-1ecc6299db9ec823/dbus-0.5.1/src/strings.rs:43:25
|
43 | $t::check_valid(s.as_ptr() as *const i8).map(|_| {
| ^^^^^^^^^^^^^^^^^^^^^^^ expected u8, found i8
...
159 | cstring_wrapper!(Interface, dbus_validate_interface);
| ----------------------------------------------------- in this macro invocation
error[E0308]: mismatched types
--> /home/pi/.cargo/registry/src/github.com-1ecc6299db9ec823/dbus-0.5.1/src/strings.rs:43:25
|
43 | $t::check_valid(s.as_ptr() as *const i8).map(|_| {
| ^^^^^^^^^^^^^^^^^^^^^^^ expected u8, found i8
...
166 | cstring_wrapper!(BusName, dbus_validate_bus_name);
| -------------------------------------------------- in this macro invocation
error[E0308]: mismatched types
--> /home/pi/.cargo/registry/src/github.com-1ecc6299db9ec823/dbus-0.5.1/src/strings.rs:43:25
|
43 | $t::check_valid(s.as_ptr() as *const i8).map(|_| {
| ^^^^^^^^^^^^^^^^^^^^^^^ expected u8, found i8
...
173 | cstring_wrapper!(ErrorName, dbus_validate_error_name);
| ------------------------------------------------------ in this macro invocation
error: aborting due to 6 previous errors
error: Could not compile `dbus`.
Caused by:
process didn't exit successfully: `rustc --crate-name dbus /home/pi/.cargo/registry/src/github.com-1ecc6299db9ec823/dbus-0.5.1/src/lib.rs --crate-type lib -g -C metadata=c7a44efa2351d871 -C extra-filename=-c7a44efa2351d871 --out-dir /home/pi/elyo/trunk/rust/test/target/debug/deps --emit=dep-info,link -L dependency=/home/pi/elyo/trunk/rust/test/target/debug/deps --extern libc=/home/pi/elyo/trunk/rust/test/target/debug/deps/liblibc-b4eee0616d69ca39.rlib --cap-lints allow -L native=/usr/lib/arm-linux-gnueabihf -l dbus-1` (exit code: 101)
Hi!
Here's a link to my failure: https://travis-ci.org/stratis-storage/stratisd/builds/174912560. Let me know if you aren't able to view it.
The failure is here:
Build failed, waiting for other jobs to finish...
error: failed to run custom build command for `dbus v0.4.1`
process didn't exit successfully: `/home/travis/build/stratis-storage/stratisd/target/debug/build/dbus-5e9bab8f37d6caf2/build-script-build` (exit code: 101)
--- stderr
thread 'main' panicked at 'called `Result::unwrap()` on an `Err` value: "`\"pkg-config\" \"--libs\" \"--cflags\" \"dbus-1\"` did not exit successfully: exit code: 1\n--- stdout\nPackage dbus-1 was not found in the pkg-config search path.\nPerhaps you should add the directory containing `dbus-1.pc\'\nto the PKG_CONFIG_PATH environment variable\nNo package \'dbus-1\' found\n"', ../src/libcore/result.rs:79
The problem is, possibly, a question around Ubuntu which doesn't seem to actually have a package called dbus-1. See: http://packages.ubuntu.com/search?keywords=dbus. Have you heard about install issues on Ubuntu before or could you offer any suggestions?
Thanks and let me know if I can give you more information.
Hi. I've a message of type
published_count: HashMap<String, u64>,
I want to broadcast a signal with above message. How do I do that?
I'm trying to do something like this.
let m3 = dbus::Message::new_signal("/com/tekjar/Test", "com.tekjar.Test", "TotalPublishCount").unwrap();
let m3 = m3.append(total_published_count.into());
connection.send(m3).unwrap();
It would be nice if there was a way to serialize/deserialize directly between structs and DBus arguments/messages.
Given that serde seems to be the future rather than rustc_serialize, that's the proposed framework to use for serializing/deserializing.
Not sure if this is technically the best forum for this discussion, but I figured I'd post my ideas out in the open so that anyone looking at and using this library can help scrutinize them.
First, thanks for writing this library. FFI code is not one of my strong points in Rust, and so it helps to have a lot of that boilerplate out of the way. =) That said, I do have some suggestions for improving it. Your API is almost an exact mapping of some of the functions from the DBus API, which means that it's functional, but not very Rustic. The DBus API's design is largely constrained by C's relative simplicity, but I believe there are a few approaches worth considering to make it easier to use on the Rust side.
The first big change that I've been playing around with (in the sense that I don't yet have a working version) is newtyping Message
into several different types like this:
// private newtype of DBusMessage, where shared functionality would be implemented
struct Message(*mut ffi::DBusMessage);
// public newtypes for specific message types
pub struct MethodCall(Message);
pub struct MethodReturn(Message);
// ...etc.
The advantage of this is that certain methods, such as for constructing return values, would only be available on the message types where it makes sense.
impl Message {
// potential location for methods that are supported by multiple types
}
impl MethodCall {
pub fn new_method_return(&self, ...) -> MethodReturn {
...
}
}
impl MethodReturn {
// notice how new_method_return() is missing
}
Then most of the Message
methods could be implemented as instance methods on the type that supports them.
One other possibility I've been playing around with in my head is to group all of the public Message
types under an enum, e.g.
struct msg(*mut ffi::DBusMessage); // notice the rename
pub enum Message {
MethodCall(msg),
MethodReturn(msg),
// ...etc.
}
Lastly, a minor note is that instead of accepting &str
parameters, it would be nice if these methods accepted anything implementing Str
to eliminate the need to ever call .as_slice()
outside of their implementation.
Maybe if I have some time in the coming weeks I'll try and get a working prototype together, but I just wanted to share my thoughts.
Compiling this crate with a recent Nightly Rust produces the warning in the title. I haven’t looked into it further.
While writing an application making quite a bit of use of dbus i realized nowhere is documented how to use signals. Furthermore it is not documented how a server might implement properties. The rustdoc documentation is not really useful. Both of those are fairly important features of dbus, so documentation should be added.
Hello,
This is more a question than an issue but I wondered if there was / will be any way to work with dbus signal in dbus-rs?
I might be making a mistake in implementation, but I have not been able to get nested dictionaries to work.
Building the dictionary with a nested dictionary:
https://github.com/hwchen/secret-service-rs/blob/master/src/collection.rs#L224
The method call interface:
https://github.com/hwchen/secret-service-rs/blob/master/src/util.rs#L64
The test:
https://github.com/hwchen/secret-service-rs/blob/master/src/item.rs#L272
The error:
---- item::test::should_create_get_and_set_item_attributes stdout ----
thread 'item::test::should_create_get_and_set_item_attributes' panicked at 'assertion failed: unsafe {
ffi::dbus_message_iter_open_container(i, ffi::DBUS_TYPE_VARIANT, atype.as_ptr(), &mut subiter)
} != 0',
/home/hwchen/.cargo/registry/src/github.com-88ac128001ac3a9a/dbus-0.2.1/src/message.rs:154
Please excuse messy code, I have a lot of refactoring to do.
This occurs when I invoke GetManagedObjects
.
I have a property defined for an interface called Pool.
As the properties are being listed a method belonging to the Pool interface is invoked. It extracts the object path, but that object path is the object path that was used to call GetManagedObjects
originally, and it is not an object path for an object that implements the Pool interface. This causes an error in my method as this situation is unexpected.
Obtaining the value of the property on an object path that does implement the Pool interface works fine.
Running dbus-0.4.1.
To get/append arguments to a message, we can currently to it the enum way (MessageItem) or the generics way (msgarg::Arg). But we're missing the trait object way. It would be very helpful, e g, if one could append, say, an Box<Arg + Append>
, but that doesn't work today, because Arg
is not object safe.
Hi!
We have a bunch of properties that are RO by intention (can not be set via the D-Bus interface).
But the value of a RO property may still change. This change could result from side-effects from other procedure calls or any number of reasons.
When this happens, it is still desirable to emit a PropertiesChanged signal which includes the information about the property changed in a reasonably timely manner. We're not sure if we want to just invalidate or actually give the new value.
Are there currently recommended ways to go about doing this, i.e., emitting a PropertiesChanged signal with information for a RO property?
I'm trying to have a d-bus method return a tuple of two values (specifically a width and height) and I for some reason can't get the signature right.
Here's a snippet of the test code I have:
.add_m(
f.method("Resolution", (), |m| {
Ok(vec![m.msg.method_return()
.append2(1u32, 1u32)
])
}).outarg::<(u32, u32), _>("success")
But when trying to test it with a Python repl + pydbus I get the error:
Method 'Resolution' returned type '(uu)', but expected '((uu))' (13)
What, IMHO, needs to be done:
How can I create new dbus::arg::Dict
with the type dbus::arg::Dict<&str, dbus::arg::Dict<&str, dbus::arg::Variant<_>
containing data that looks like this...
{
'802-11-wireless': {'mac-address': [228, 179, 24, 77, 64, 139],
'mac-address-blacklist': [],
'mode': 'infrastructure',
'security': '802-11-wireless-security',
'seen-bssids': ['EC:1F:72:1C:60:36'],
'ssid': [106, 111, 101]},
'802-11-wireless-security': {'auth-alg': 'open',
'group': [],
'key-mgmt': 'wpa-psk',
'pairwise': [],
'proto': []},
'connection': {'id': 'joe',
'permissions': [],
'secondaries': [],
'timestamp': 1484488610,
'type': '802-11-wireless',
'uuid': '347aa082-8846-4e8d-be99-bd527c65eef1'}
}
So far I have this...
fn main() {
let mut settings = std::collections::HashMap::new();
settings.insert("connection",
std::collections::HashMap::<&str, dbus::arg::Variant<_>>::new());
settings.insert("802-11-wireless",
std::collections::HashMap::<&str, dbus::arg::Variant<_>>::new());
settings.insert("802-11-wireless-security",
std::collections::HashMap::<&str, dbus::arg::Variant<_>>::new());
settings.get_mut("connection").unwrap().insert("id", dbus::arg::Variant("resin_io"));
settings.get_mut("connection").unwrap().insert("type", dbus::arg::Variant("802-11-wireless"));
settings.get_mut("802-11-wireless").unwrap().insert("ssid", dbus::arg::Variant(vec![10, 20, 30]));
let test = dbus::arg::Dict::new(settings.iter());
println!("{:?}", settings);
}
which throws some errors...
error[E0308]: mismatched types
--> src/main.rs:18:84
|
18 | settings.get_mut("802-11-wireless").unwrap().insert("ssid", dbus::arg::Variant(vec![10, 20, 30]));
| ^^^^^^^^^^^^^^^^ expected &str, found struct `std::vec::Vec`
|
= note: expected type `&str`
= note: found type `std::vec::Vec<{integer}>`
= help: here are some functions which might fulfill your needs:
- .remove(...)
- .swap_remove(...)
= note: this error originates in a macro outside of the current crate
error[E0277]: the trait bound `std::collections::HashMap<&str, dbus::arg::Variant<&str>>: dbus::arg::Arg` is not satisfied
--> src/main.rs:20:16
|
20 | let test = dbus::arg::Dict::new(settings.iter());
| ^^^^^^^^^^^^^^^^^^^^ the trait `dbus::arg::Arg` is not implemented for `std::collections::HashMap<&str, dbus::arg::Variant<&str>>`
|
= note: required because of the requirements on the impl of `dbus::arg::Arg` for `&std::collections::HashMap<&str, dbus::arg::Variant<&str>>`
= note: required by `dbus::arg::Dict`
error[E0277]: the trait bound `std::collections::HashMap<&str, dbus::arg::Variant<&str>>: dbus::arg::Append` is not satisfied
--> src/main.rs:20:16
|
20 | let test = dbus::arg::Dict::new(settings.iter());
| ^^^^^^^^^^^^^^^^^^^^ the trait `dbus::arg::Append` is not implemented for `std::collections::HashMap<&str, dbus::arg::Variant<&str>>`
|
= note: required because of the requirements on the impl of `dbus::arg::Append` for `&std::collections::HashMap<&str, dbus::arg::Variant<&str>>`
= note: required by `<dbus::arg::Dict<'a, K, V, I>>::new`
error[E0277]: the trait bound `std::collections::HashMap<&str, dbus::arg::Variant<&str>>: dbus::arg::Arg` is not satisfied
--> src/main.rs:20:16
|
20 | let test = dbus::arg::Dict::new(settings.iter());
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ the trait `dbus::arg::Arg` is not implemented for `std::collections::HashMap<&str, dbus::arg::Variant<&str>>`
|
= note: required because of the requirements on the impl of `dbus::arg::Arg` for `&std::collections::HashMap<&str, dbus::arg::Variant<&str>>`
= note: required by `dbus::arg::Dict`
error: aborting due to 4 previous errors
Am I am on right track or completely missing something?
Do you have any plans to enable conversion between structs and dbus types?
Thanks in advance.
I'm not happy with the design of MessageItem::Array, since it is possible to have an array that does not follow the type signature. However, fixing this would be a backwards incompatible change.
I was trying to compile Servo in a CentOS 6.5 environment, which has dbus-1.2.24-7. Linking fails:
/home/djc/src/servo/.cargo/registry/src/github.com-1ecc6299db9ec823/dbus-0.3.3/src/strings.rs:28: error: undefined reference to 'dbus_validate_path'
/home/djc/src/servo/.cargo/registry/src/github.com-1ecc6299db9ec823/dbus-0.3.3/src/strings.rs:19: error: undefined reference to 'dbus_validate_path'
/home/djc/src/servo/.cargo/registry/src/github.com-1ecc6299db9ec823/dbus-0.3.3/src/strings.rs:28: error: undefined reference to 'dbus_validate_member'
/home/djc/src/servo/.cargo/registry/src/github.com-1ecc6299db9ec823/dbus-0.3.3/src/strings.rs:19: error: undefined reference to 'dbus_validate_member'
/home/djc/src/servo/.cargo/registry/src/github.com-1ecc6299db9ec823/dbus-0.3.3/src/strings.rs:28: error: undefined reference to 'dbus_validate_interface'
/home/djc/src/servo/.cargo/registry/src/github.com-1ecc6299db9ec823/dbus-0.3.3/src/strings.rs:19: error: undefined reference to 'dbus_validate_interface'
/home/djc/src/servo/.cargo/registry/src/github.com-1ecc6299db9ec823/dbus-0.3.3/src/strings.rs:28: error: undefined reference to 'dbus_validate_bus_name'
/home/djc/src/servo/.cargo/registry/src/github.com-1ecc6299db9ec823/dbus-0.3.3/src/strings.rs:19: error: undefined reference to 'dbus_validate_bus_name'
What versions of dbus are supported? Would it be viable to support this version of dbus?
hello, is there have some examples for emit signal at server side?
A declarative, efficient, and flexible JavaScript library for building user interfaces.
🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.
TypeScript is a superset of JavaScript that compiles to clean JavaScript output.
An Open Source Machine Learning Framework for Everyone
The Web framework for perfectionists with deadlines.
A PHP framework for web artisans
Bring data to life with SVG, Canvas and HTML. 📊📈🎉
JavaScript (JS) is a lightweight interpreted programming language with first-class functions.
Some thing interesting about web. New door for the world.
A server is a program made to process requests and deliver data to clients.
Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.
Some thing interesting about visualization, use data art
Some thing interesting about game, make everyone happy.
We are working to build community through open source technology. NB: members must have two-factor auth.
Open source projects and samples from Microsoft.
Google ❤️ Open Source for everyone.
Alibaba Open Source for everyone
Data-Driven Documents codes.
China tencent open source team.