Skip to content

Commit 9d8aff2

Browse files
committed
mostly complete implementation of dbus response to nushell
1 parent d8becee commit 9d8aff2

3 files changed

Lines changed: 96 additions & 21 deletions

File tree

src/client.rs

Lines changed: 24 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -1,13 +1,13 @@
1-
use dbus::{blocking::LocalConnection, channel::{Channel, BusType}};
1+
use dbus::{channel::{Channel, BusType}, Message};
22
use nu_plugin::LabeledError;
3-
use nu_protocol::Spanned;
3+
use nu_protocol::{Spanned, Value};
44

55
use crate::config::{DbusClientConfig, DbusBusChoice};
66

77
/// Executes D-Bus actions on a connection, handling nushell types
88
pub struct DbusClient {
99
config: DbusClientConfig,
10-
conn: LocalConnection,
10+
conn: Channel,
1111
}
1212

1313
impl DbusClient {
@@ -31,7 +31,7 @@ impl DbusClient {
3131
})?;
3232
Ok(DbusClient {
3333
config,
34-
conn: LocalConnection::from(channel)
34+
conn: channel
3535
})
3636
}
3737

@@ -42,9 +42,16 @@ impl DbusClient {
4242
object: &Spanned<String>,
4343
interface: &Spanned<String>,
4444
method: &Spanned<String>,
45-
) -> Result<(), LabeledError> {
46-
// TODO convert & return response
45+
) -> Result<Value, LabeledError> {
4746
// TODO accept arguments
47+
macro_rules! error {
48+
($label:expr) => (LabeledError {
49+
label: $label,
50+
msg: "while calling a D-Bus method".into(),
51+
span: Some(self.config.span)
52+
})
53+
}
54+
4855
// Validate inputs before sending to the dbus lib so we don't panic
4956
macro_rules! validate_with {
5057
($type:ty, $spanned:expr) => (<$type>::new(&$spanned.item).map_err(|msg| {
@@ -60,19 +67,18 @@ impl DbusClient {
6067
let valid_interface = validate_with!(dbus::strings::Interface, interface)?;
6168
let valid_method = validate_with!(dbus::strings::Member, method)?;
6269

63-
// Send method call
64-
let proxy = self.conn.with_proxy(
70+
// Construct the method call message
71+
let message = Message::new_method_call(
6572
valid_dest,
6673
valid_object,
67-
self.config.timeout.item
68-
);
69-
let () = proxy.method_call(valid_interface, valid_method, ()).map_err(|err| {
70-
LabeledError {
71-
label: err.to_string(),
72-
msg: "while calling a D-Bus method".into(),
73-
span: Some(self.config.span),
74-
}
75-
})?;
76-
Ok(())
74+
valid_interface,
75+
valid_method,
76+
).map_err(|err| error!(err))?;
77+
78+
// Send it on the channel and get the response
79+
let resp = self.conn.send_with_reply_and_block(message, self.config.timeout.item)
80+
.map_err(|err| error!(err.to_string()))?;
81+
82+
Ok(crate::convert::from_message(&resp)?)
7783
}
7884
}

src/convert.rs

Lines changed: 70 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,70 @@
1+
use dbus::{Message, arg::{ArgType, RefArg}};
2+
use nu_plugin::LabeledError;
3+
use nu_protocol::{Value, Span, Record};
4+
5+
pub fn from_message(message: &Message) -> Result<Value, LabeledError> {
6+
let mut out = vec![];
7+
for refarg in message.iter_init() {
8+
if let Some(o) = from_refarg(&refarg) {
9+
out.push(o);
10+
}
11+
}
12+
Ok(Value::list(out, Span::unknown()))
13+
}
14+
15+
pub fn from_refarg(refarg: &dyn RefArg) -> Option<Value> {
16+
Some(match refarg.arg_type() {
17+
ArgType::Array => {
18+
if refarg.signature().starts_with("a{") {
19+
// This is a dictionary
20+
let mut record = Record::new();
21+
for entry in refarg.as_iter().unwrap() {
22+
let mut entry_iter = entry.as_iter().unwrap();
23+
let key = entry_iter.next().unwrap();
24+
let val = entry_iter.next().unwrap();
25+
if let Some(key) = key.as_str() {
26+
record.insert(key, from_refarg(val)?);
27+
}
28+
}
29+
Value::record(record, Span::unknown())
30+
} else if &*refarg.signature() == "ay" {
31+
// Byte array - better to return as binary
32+
let bytes = dbus::arg::cast::<Vec<u8>>(&refarg.box_clone()).unwrap().to_owned();
33+
Value::binary(bytes, Span::unknown())
34+
} else {
35+
// It's an array
36+
Value::list(
37+
refarg.as_iter().unwrap().map(from_refarg).flatten().collect(),
38+
Span::unknown())
39+
}
40+
},
41+
ArgType::Variant => {
42+
let inner = refarg.as_iter().unwrap().nth(0).unwrap();
43+
return from_refarg(inner);
44+
},
45+
ArgType::Boolean =>
46+
Value::bool(refarg.as_i64().unwrap() != 0, Span::unknown()),
47+
48+
// Strings
49+
ArgType::String | ArgType::ObjectPath | ArgType::Signature =>
50+
Value::string(refarg.as_str().unwrap(), Span::unknown()),
51+
// Ints
52+
ArgType::Byte | ArgType::Int16 | ArgType::UInt16 | ArgType::Int32 |
53+
ArgType::UInt32 | ArgType::Int64 | ArgType::UnixFd =>
54+
Value::int(refarg.as_i64().unwrap(), Span::unknown()),
55+
// Floats
56+
ArgType::Double =>
57+
Value::float(refarg.as_f64().unwrap(), Span::unknown()),
58+
59+
ArgType::Struct =>
60+
Value::list(
61+
refarg.as_iter().unwrap().map(from_refarg).flatten().collect(),
62+
Span::unknown()),
63+
64+
ArgType::DictEntry => todo!(),
65+
ArgType::UInt64 => todo!(), // nushell only supports up to i64
66+
67+
// End of iterator
68+
ArgType::Invalid => return None,
69+
})
70+
}

src/main.rs

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@ use nu_protocol::{PluginSignature, Value, SyntaxShape, PluginExample};
33

44
mod config;
55
mod client;
6+
mod convert;
67

78
use config::*;
89
use client::*;
@@ -102,8 +103,6 @@ impl NuPluginDbus {
102103
&call.req(0)?,
103104
&call.req(1)?,
104105
&call.req(2)?,
105-
)?;
106-
// TODO handle response
107-
Ok(Value::nothing(call.head))
106+
)
108107
}
109108
}

0 commit comments

Comments
 (0)