Nushell plugin for interacting with D-Bus
at main 127 lines 4.3 kB view raw
1use nu_plugin::{EngineInterface, EvaluatedCall, SimplePluginCommand}; 2use nu_protocol::{Example, LabeledError, Signature, SyntaxShape, Type, Value}; 3 4use crate::{DbusSignatureUtilExt, client::DbusClient, config::DbusClientConfig}; 5 6pub struct Call; 7 8impl SimplePluginCommand for Call { 9 type Plugin = crate::NuPluginDbus; 10 11 fn name(&self) -> &str { 12 "dbus call" 13 } 14 15 fn signature(&self) -> Signature { 16 Signature::build(self.name()) 17 .dbus_command() 18 .accepts_dbus_client_options() 19 .accepts_timeout() 20 .input_output_type(Type::Nothing, Type::Any) 21 .named( 22 "signature", 23 SyntaxShape::String, 24 "Signature of the arguments to send, in D-Bus format.\n \ 25 If not provided, they will be determined from introspection.\n \ 26 If --no-introspect is specified and this is not provided, they will \ 27 be guessed (poorly)", 28 None, 29 ) 30 .switch( 31 "no-flatten", 32 "Always return a list of all return values", 33 None, 34 ) 35 .switch( 36 "no-introspect", 37 "Don't use introspection to determine the correct argument signature", 38 None, 39 ) 40 .required_named( 41 "dest", 42 SyntaxShape::String, 43 "The name of the connection to send the method to", 44 None, 45 ) 46 .required( 47 "object", 48 SyntaxShape::String, 49 "The path to the object to call the method on", 50 ) 51 .required( 52 "interface", 53 SyntaxShape::String, 54 "The name of the interface the method belongs to", 55 ) 56 .required( 57 "method", 58 SyntaxShape::String, 59 "The name of the method to send", 60 ) 61 .rest( 62 "args", 63 SyntaxShape::Any, 64 "Arguments to send with the method call", 65 ) 66 } 67 68 fn description(&self) -> &str { 69 "Call a method and get its response" 70 } 71 72 fn extra_description(&self) -> &str { 73 "Returns an array if the method call returns more than one value." 74 } 75 76 fn search_terms(&self) -> Vec<&str> { 77 vec!["dbus"] 78 } 79 80 fn examples(&self) -> Vec<Example<'_>> { 81 vec![ 82 Example { 83 example: "dbus call --dest=org.freedesktop.DBus \ 84 /org/freedesktop/DBus org.freedesktop.DBus.Peer Ping", 85 description: "Ping the D-Bus server itself", 86 result: None, 87 }, 88 Example { 89 example: "dbus call --dest=org.freedesktop.Notifications \ 90 /org/freedesktop/Notifications org.freedesktop.Notifications \ 91 Notify \"Floppy disks\" 0 \"media-floppy\" \"Rarely seen\" \ 92 \"But sometimes still used\" [] {} 5000", 93 description: "Show a notification on the desktop for 5 seconds", 94 result: None, 95 }, 96 ] 97 } 98 99 fn run( 100 &self, 101 _plugin: &Self::Plugin, 102 _engine: &EngineInterface, 103 call: &EvaluatedCall, 104 _input: &Value, 105 ) -> Result<Value, LabeledError> { 106 let config = DbusClientConfig::try_from(call)?; 107 let dbus = DbusClient::new(config)?; 108 let values = dbus.call( 109 &call.get_flag("dest")?.unwrap(), 110 &call.req(0)?, 111 &call.req(1)?, 112 &call.req(2)?, 113 call.get_flag("signature")?.as_ref(), 114 &call.positional[3..], 115 )?; 116 117 let flatten = !call.get_flag::<bool>("no-flatten")?.unwrap_or(false); 118 119 // Make the output easier to deal with by returning a list only if there are multiple return 120 // values (not so common) 121 match values.len() { 122 0 if flatten => Ok(Value::nothing(call.head)), 123 1 if flatten => Ok(values.into_iter().nth(0).unwrap()), 124 _ => Ok(Value::list(values, call.head)), 125 } 126 } 127}