Nushell plugin for interacting with D-Bus
0
fork

Configure Feed

Select the types of activity you want to include in your feed.

mostly complete implementation of dbus response to nushell

+96 -21
+24 -18
src/client.rs
··· 1 - use dbus::{blocking::LocalConnection, channel::{Channel, BusType}}; 1 + use dbus::{channel::{Channel, BusType}, Message}; 2 2 use nu_plugin::LabeledError; 3 - use nu_protocol::Spanned; 3 + use nu_protocol::{Spanned, Value}; 4 4 5 5 use crate::config::{DbusClientConfig, DbusBusChoice}; 6 6 7 7 /// Executes D-Bus actions on a connection, handling nushell types 8 8 pub struct DbusClient { 9 9 config: DbusClientConfig, 10 - conn: LocalConnection, 10 + conn: Channel, 11 11 } 12 12 13 13 impl DbusClient { ··· 31 31 })?; 32 32 Ok(DbusClient { 33 33 config, 34 - conn: LocalConnection::from(channel) 34 + conn: channel 35 35 }) 36 36 } 37 37 ··· 42 42 object: &Spanned<String>, 43 43 interface: &Spanned<String>, 44 44 method: &Spanned<String>, 45 - ) -> Result<(), LabeledError> { 46 - // TODO convert & return response 45 + ) -> Result<Value, LabeledError> { 47 46 // 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 + 48 55 // Validate inputs before sending to the dbus lib so we don't panic 49 56 macro_rules! validate_with { 50 57 ($type:ty, $spanned:expr) => (<$type>::new(&$spanned.item).map_err(|msg| { ··· 60 67 let valid_interface = validate_with!(dbus::strings::Interface, interface)?; 61 68 let valid_method = validate_with!(dbus::strings::Member, method)?; 62 69 63 - // Send method call 64 - let proxy = self.conn.with_proxy( 70 + // Construct the method call message 71 + let message = Message::new_method_call( 65 72 valid_dest, 66 73 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)?) 77 83 } 78 84 }
+70
src/convert.rs
··· 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 + }
+2 -3
src/main.rs
··· 3 3 4 4 mod config; 5 5 mod client; 6 + mod convert; 6 7 7 8 use config::*; 8 9 use client::*; ··· 102 103 &call.req(0)?, 103 104 &call.req(1)?, 104 105 &call.req(2)?, 105 - )?; 106 - // TODO handle response 107 - Ok(Value::nothing(call.head)) 106 + ) 108 107 } 109 108 }