= cockpit.js: DBus ClientCockpit allows access to DBus services via this API.[[cockpit-dbus-types]]== DBus TypesDBus values are represented as javascript values and objects as follows:`+BYTE 'y'+`::Javascript number.`+BOOLEAN 'b'+`::Javascript boolean.`+INT16 'n'+`::Javascript number.`+UINT16 'q'+`::Javascript number.`+INT32 'i'+`::Javascript number.`+UINT32 'u'+`::Javascript number.`+INT64 'x'+`::Javascript number.`+UINT64 't'+`::Javascript number.`+DOUBLE 'd'+`::Javascript number.`+STRING 's'+`::Javascript string.`+OBJECT_PATH 'o'+`::Javascript string.`+SIGNATURE 'g'+`::Javascript string.`+ARRAY of BYTE 'ay'+`::A string containing base64 encoded data.`+ARRAY of DICT_ENTRY with STRING keys 'a{s?}'+`::A javascript plain object with the keys as property names.`+ARRAY of DICT_ENTRY with other keys 'a{??}'+`::A javascript plain object each key JSON encoded into a string propertyname.`+ARRAY of other+`::A javascript array.`+VARIANT+`::A javascript plain object with the `+"t"+` property set to a DBus typestring, and the `+"v"+` property set to a value.`+HANDLE 'h'+`::A javascript object that describes a cockpit channel which representsthe passed file descriptor. The `+payload+` is always set to`+stream+`. Pass it toxref:cockpit-channels.adoc#cockpit-channels-channel[cockpit.channel()] to create thechannel and start reading or writing on it. Handles can only bereceived, not sent from within cockpit.[[cockpit-dbus-dbus]]== cockpit.dbus()....client = cockpit.dbus(name, [options])....Create a DBus client for the given bus `+name+` (eg: service name). Usethe following functions to make DBus method calls, watch for events,etc. The optional `+options+` argument is a javascript plain object, andmay include:`+"bus"+`::The DBus bus to connect to. Specifying `+"session"+` will connect tothe DBus user session bus, `+"user"+` will connect to the user bus (onsome systems this is identical to the session bus), `+"system"+` willconnect to the DBus system bus, and `+"none"+` to the non-standard busspecified with the `+address+` option. This defaults to "system" ifnot present.`+"address"+`::The bus address to connect to in case `+bus+` is `+"none"+`.`+"superuser"+`::Set to `+"require"+` to talk to this service as root. The DBus servicewill see the DBus method calls and accesses as coming from root,rather than the logged in user. This is useful for talking to servicesthat do not correctly usehttps://www.freedesktop.org/software/polkit[polkit] to authorizeadministrative users. If the currently logged in user is not permittedto become root (eg: via `+pkexec+`) then the `+client+` willimmediately be link:#cockpit-dbus-onclose[closed] with a`+"access-denied"+` problem code.+Set to `+"try"+` to try to talk as root, but if that fails, fall backto unprivileged.`+"track"+`::It is valid for a DBus service to exit, and be restarted in such a waythat clients continue to talk to it across the restart. Some servicesare not written with this in mind. If the `+"track"+` option is set to`+true+` then the channel will close when the service exits and/ordisconnects from the DBus bus.If the `+name+` argument is null, and no options other than `+"bus"+`are specified, then a shared DBus `+client+` is created. When using sucha client with a DBus bus, a `+"name"+` option must be specified onvarious other methods in order to specify which client to talk to.[[cockpit-dbus-wait]]== client.wait()....promise = client.wait([callback])....Returns a `+promise+` that is ready when the client is ready, or failsif the client closes. If a `+callback+` is specified, it is attached tothe promise.[[cockpit-dbus-close]]== client.close()....client.close([problem])....Close the DBus client. If `+problem+` is specified it should be axref:cockpit-error.adoc#cockpit-problems[problem code] string.[[cockpit-dbus-onclose]]== client.onclose....client.addEventListener("close", options => { ... })....An event triggered when the DBus client closes. This can happen eitherbecause link:#cockpit-dbus-close[client.close()] function was called, orthe DBus service went away, or some other problem or disconnection.The `+options+` will contain various close information, including a`+"problem"+` field which will be set if the channel was closed becauseof a problem.[[cockpit-dbus-onowned]]== client.onowner....client.addEventListener("owner", (event, owner) => { ... })....An event triggered when the owner of the DBus name changes. The ownervalue will be the id of the name owner on the bus or null if the name isunowned. The absence of an owner should not be treated as adisconnection. However this makes it possible to take some action basedon the actual status of the service, for example disconnecting a pendingsignal handler.[[cockpit-dbus-options]]== client.optionsSet to the options used when creating the client. Will not change forthe life of the client.[[cockpit-dbus-unique-name]]== client.unique_nameThe unique DBus name of the client. Initially null, and becomes validonce the the client is ready.[[cockpit-dbus-proxy]]== client.proxy()....proxy = client.proxy([interface, path], [options])....Create proxy javascript object for a DBus `+interface+`. At thespecified DBus object `+path+`. The proxy will have properties, methodsand signals from to the DBus interface, and allows for naturalinteraction. If no `+interface+` is specified then the DBus bus name ofthe client is used. If no `+path+` is specified, then the DBus name ofthe client is converted to a path.If creating lots of proxies for a given `+interface+` it is moreefficient to use the link:#cockpit-dbus-proxies[`+client.proxies()+`]function.The proxy is loaded when thelink:#cockpit-dbus-proxy-valid[`+proxy.valid+`] field is `+true+`, andit is set to `+false+` if the underlying `+interface+` and/or `+path+`don't or no longer exist, or the `+client+` has closed. You can wait forproxy to become valid by passing a callback to itslink:#cockpit-dbus-proxy-wait[`+proxy.wait()+`] function. Thelink:#cockpit-dbus-proxy-onchanged[`+proxy.onchanged+`] event will alsofire when the proxy becomes valid or invalid. DBus properties andmethods on the proxy are not defined until the proxy becomes valid.....value = proxy.Prop1proxy.WritableProp = value....All DBus properties on the `+interface+` that start with an upper caseletter (as is convention) will be automatically defined on this proxy,and will update their values as the DBus property values change. Inaddition the link:#cockpit-dbus-proxy-onchanged[`+proxy.onchanged+`]event will fire every time the properties change.If you assign a value to a writable property on the proxy, the proxywill try to set that property on the DBus `+interface+` at `+path+`. Theactual proxy property value will not update until the DBus service hasnotified the proxy of the change. If setting a property fails a warningwill be logged. In order to have more reliable setting of properties, ortrack when they have been set, or if setting fails, use thelink:#cockpit-dbus-call[`+client.call()+`] directly. It should be notedthat DBus service implementations may also be inconsistent in theirbehavior when setting a property fails.You can access the raw property data using thelink:#cockpit-dbus-proxy-data[`+proxy.data+`] field, including data forproperties that do not start with an upper case letter.....proxy.Method(arg1, arg2).then((retval1, retval2) => {...}).catch(ex => {...});....All DBus methods on the `+interface+` that start with an upper caseletter (as is convention) will be automatically defined on this proxy.These methods are called with arguments as normal javascript arguments.Ahttps://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Promise[Promise]that will complete successfully when the method returns, or fail if anerror occurs. The return values from the DBus method will be passed tothe `+then+` handler function directly.Methods that do not start with an upper case letter can be invoked byusing the usual link:#cockpit-dbus-proxy-call[`+proxy.call()+`]directly.....proxy.addEventListener("signal", (event, arg1, arg2) => {...});....All DBus signals on the `+interface+` that start with an upper caseletter (as is convention) will be automatically emit events on thisproxy. These events will contain the signal arguments after the standard`+event+` argument.Signals that do not start with an upper case letter can be subscribed toby using link:#cockpit-dbus-proxy-signal[`+proxy.onsignal+`] directly.Usually a proxy asks the `+client+` to watch and notify it of changes tothe relevant object or path. You can pass an `+options+` argument withthe `+watch+` field set to `+false+` to prevent this.[[cockpit-dbus-proxy-client]]== proxy.clientSet to the DBus client of the proxy. Will not change for the life of theproxy.[[cockpit-dbus-proxy-path]]== proxy.pathSet to the DBus object path of the proxy. Will not change for the lifeof the proxy.[[cockpit-dbus-proxy-iface]]== proxy.ifaceSet to the DBus interface name of the proxy. Will not change for thelife of the proxy.[[cockpit-dbus-proxy-valid]]== proxy.validSet to `+true+` when the proxy's DBus interface is present at its DBuspath, and all information for the proxy has loaded. Is set to `+false+`while loading, and after the proxy no longer refers a DBus interface andpath. Also set to `+false+` if the `+client+` closes.Use the by link:#cockpit-dbus-proxy-wait[`+proxy.wait()+`] function towait for a proxy to load. Thelink:#cockpit-dbus-proxy-onchanged[`+proxy.onchanged+`] event will alsobe emitted when the proxy becomes valid or invalid. DBus properties andmethods on the proxy are not defined until the proxy becomes valid.[[cockpit-dbus-proxy-data]]== proxy.dataA plain javascript object containing all the raw property data that thisproxy has loaded. This will be updated automatically as the proxy isnotified of property changes from the DBus service. Thelink:#cockpit-dbus-proxy-onchanged[`+proxy.onchanged+`] event will beemitted when it changes.[[cockpit-dbus-proxy-call]]== proxy.call()....invocation = proxy.call(method, args, [options])....Make a DBus method call on this proxy.For DBus methods that start with an upper case letter, is usually moreconvenient link:#cockpit-dbus-proxy[to call the method directly on theproxy]. However if methods that do not follow the usual DBus convention,or specify additional options, or the caller cannot be sure that themethod actually exists, you can use this method.This function also works on proxies that have are still loading and havenot become valid yet.The `+method+` should be a DBus method name, and the `+args+` should bean array of arguments to pass to the method. The `+options+` arelink:#cockpit-dbus-call[described elsewhere].The returned value is identical to the one returned fromlink:#cockpit-dbus-call[client.call()]. It is ahttps://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Promise[Promise]that will complete successfully when the method returns, or fail if anerror occurs.[[cockpit-dbus-proxy-wait]]== proxy.wait()....promise = proxy.wait()proxy.wait(() => {...});....Wait for a proxy to finish loading. This function returns a promise. Ifa callback function is passed as an argument then that function will beinvoked when the proxy is ready. If this method is called after a proxyhas already loaded, then the promise will be resolved immediately, andany callback will be invoked immediately. Use the promise or`+proxy.valid+` to determine whether the proxy is valid.[[cockpit-dbus-proxy-onchanged]]== proxy.onchanged....proxy.addEventListener("changed", (event, data) => {...});....This event is emitted when the proxy's properties change.The `+data+` has the following form, and will only include propertiesthat have changed:....{"Prop1": "value","Prop2": 5}....[[cockpit-dbus-proxy-signal]]== proxy.onsignal....proxy.addEventListener("signal", (event, name, args) => {...});....This event is emitted when the proxy's emits an event.For most events, that have names which start with an upper case letter,you can just link:#cockpit-dbus-proxy[connect to that event as a signaldirectly]. However if you wish to be notified when any signal isemitted, or for signals that do not follow the usual DBus convention,you can connect to this event.The `+name+` is the DBus signal name, and the `+args+` is an array ofarguments that were emitted with the signal.[[cockpit-dbus-proxies]]== client.proxies()....proxies = client.proxies([interface], [path_namespace], [options])....Create link:#cockpit-dbus-proxy[proxy javascript objects] for a DBusinterfaces. The proxies will have properties, methods and signals fromthe DBus `+interface+`, and allow for natural interaction. If no`+interface+` is specified then the DBus bus name of the client is used.If no `+path_namespace+` is provided then `+"/"+` will be used.Proxies will be automatically created for instances of the `+interface+`available at the DBus service. The optional `+path_namespace+` argumentcan be used to restrict the proxies for instances that have DBus pathswhich have the namespace path prefix.....proxy1 = proxies["/dbus/path1"];proxy2 = proxies["/dbus/path2"];for (proxy in proxies) {...}....The returned `+proxies+` object will is used as a dictionary, and willhave values containing proxies for DBus interface instances, with thekeys being the DBus paths of those instances. It is possible toenumerate over the returned `+proxies+`.Proxies will be automatically added and removed from the `+proxies+`object as they appear and disappear in the service. Thelink:#cockpit-dbus-proxies-onadded[`+proxies.onadded+`] andlink:#cockpit-dbus-proxies-onremoved[`+proxies.onremoved+`] events willbe emitted. DBus services may not support notifications of pathsdisappearing.Use the `+proxies.wait()+` function to be notified when the initial setof proxies has been populated.Usually a proxies ask the `+client+` to watch and be notified of changesto the relevant object or path. You can pass an `+options+` argumentwith the `+watch+` field set to `+false+` to prevent this.[[cockpit-dbus-proxies-wait]]== proxies.wait()....promise = proxies.wait()proxies.wait(() => {...});....Wait for a `+proxies+` object to populate its initial set of proxies.This function returns a promise. If a callback function is passed as anargument then that function will be invoked when the proxies are ready.If this method is called after the proxies have populated, then thepromise will be resolved immediately, and any callback will be invokedimmediately.[[cockpit-dbus-proxies-client]]== proxies.clientSet to the DBus client of the proxies. Will not change.[[cockpit-dbus-proxies-iface]]== proxies.ifaceSet to the DBus interface name of the proxies. Will not change.[[cockpit-dbus-proxies-path_namespace]]== proxies.path_namespaceSet to the DBus path namespace used which the proxies must have as aDBus path prefix. Will not change.[[cockpit-dbus-proxies-onadded]]== proxies.onadded....proxies.addEventListener("added", (event, proxy) => {...})....This event is emitted when a proxy is added to the `+proxies+` object.The proxy will already have loaded.[[cockpit-dbus-proxies-onchanged]]== proxies.onchanged....proxies.addEventListener("changed", (event, proxy) => {...})....This event is emitted when one of the proxy in the `+proxies+` objectchanges its properties.[[cockpit-dbus-proxies-onremoved]]== proxies.onremoved....proxies.addEventListener("removed", (event, proxy) => {...})....This event is emitted when a proxy is removed to the `+proxies+` object.[[cockpit-dbus-call]]== client.call()....invocation = client.call(path, interface, method, args, [options])....Make a DBus method call.The `+path+` is the DBus object path to make the call on, `+interface+`is the DBus interface for the method and `+method+` is the name of themethod to call. The `+args+` is an array of arguments to pass to themethod, each of which must be appropriate for the expectedlink:#cockpit-dbus[DBus type] of that argument. The `+args+` may be`+null+` if no arguments are to be sent.The returned value is ahttps://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Promise[Promise]that will complete successfully when the method returns, or fail if anerror occurs.If `+options+` is specified it should be a plain javascript object,which may contain the following properties:`+flags+`::A string containing DBus message flags. The character `+"i"+`indicates to the dbus service that interactive authentication isallowed. If the entire `+flags+` field is missing, then `+"i"+` is setby default.`+type+`::A valid DBus type signature to use when calling the method. In theabsence of this, the DBus service will be introspected (and the resultcached) to ask what the method type signature is.`+timeout+`::The timeout of the call in milliseconds. The call will fail with the`+"timeout"+` problem code. If "timeout" is not given, the call willnever time out.[[cockpit-dbus-then]]== invocation.then()....invocation.then((args, options) => { ... })....This is a standardhttps://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Promise[Promise]method. It sets up a handler to be called when the DBus method callfinishes successfully.The `+args+` argument is an array of return values from the DBus method.Each of them will be converted to an appropriatelink:#cockpit-dbus[javascript type].The `+options+` argument may contain additional information about thereply. If the `+type+` option was specified when performing the methodcall, then the `+options+` in the reply here will also contain a`+type+` field containing the DBus type signature of the output. If the`+flags+` option was specified when performing the call then the`+options+` in the reply here will contain message flags. Possible outmessage flags are:`+>+`::A big endian message.`+<+`::A little endian message.[[cockpit-dbus-catch]]== invocation.catch()....invocation.catch(exception => { ... })....This is a standardhttps://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Promise[Promise]method. It sets up a handler to be called when the DBus method callfails.The `+exception+` object passed to the handler can have the followingproperties:`+problem+`::A xref:cockpit-error.adoc#cockpit-problems[problem code] string when a problem occurredstarting or communicating with the DBus service. This is `+null+` inthe cases where an actual DBus error was occurred.`+name+`::The DBus error name. This will be `+null+` in cases where the failurewas not due to a DBus error.`+message+`::A DBus error message. This will be `+null+` in cases where the failurewas not due to a DBus error.[[cockpit-dbus-subscribe]]== client.subscribe()....subscription = client.subscribe(match, (path, interface, signal, args) => { ... })....Subscribe to signals. The `+match+` argument is a javascript plainobject which defines what signals to subscribe to. Each property in the`+match+` argument restricts signals subscribed to. If a property is notpresent then it is treated as a wildcard, matching anything. If an emptyobject is specified as `+match+` then all signals will be subscribed to.The `+match+` argument may contain the following properties:`+interface+`::A DBus interface to match.`+path+`::A DBus object path to match. May not be used together with the`+path_namespace+` property. It should be a valid DBus object path,that is, it should have no trailing slash.`+path_namespace+`::A DBus object path prefix to match. Any paths in the hierarchy belowthis top path will match. May not be used together with the `+path+`property.`+member+`::The DBus signal name to match.`+arg0+`::Matches the first argument of a DBus message, which must be a string.The handler passed as the second argument will be invoked when thesignal is received. A `+subscription+` is returned which can be used toremove the subscription by calling its `+subscription.remove()+` method.It is not a problem to subscribe to the same signals more than once,with identical or slightly different `+match+` arguments.[[cockpit-dbus-remove]]== subscription.remove()....subscription.remove()....Unsubscribe from the DBus signal subscription.[[cockpit-dbus-watch]]== client.watch()....watch = client.watch(path)watch = client.watch({ "path_namespace": path_namespace, "interface": interface })....Watch for property and interface changes on the given DBus object`+path+` DBus `+path_namespace+`. If `+interface+` is specified onlyproperties on that DBus interface will be watched.The link:#cockpit-dbus-proxy[`+client.proxy()+`] andlink:#cockpit-dbus-proxies[`+client.proxies()+`] functions and theobjects they return are high level wrappers around `+client.watch()+`.The property and interface changes will be available in raw form on thelink:#cockpit-dbus-onnotify[`+client.onnotify+`] event.Property and interface changes that are caused by a method call orsignal will show up before that method call reply is received, or signalevent is triggered. It should be possible to rely on this guarantee,unless the DBus service in question behaves incorrectly. Internallythese watches work well with code that implements thehttps://dbus.freedesktop.org/doc/dbus-specification.html#standard-interfaces-objectmanager[ObjectManager]portion of the DBus specification. If no ObjectManager implementation isavailable, the watch falls back to using DBushttps://dbus.freedesktop.org/doc/dbus-specification.html#standard-interfaces-introspectable[Introspection]along with the usualhttps://dbus.freedesktop.org/doc/dbus-specification.html#standard-interfaces-properties[PropertiesChanged]signal. If the DBus service implements none of these, or implements themin an inconsistent manner, then this function will provide inconsistentor unexpected results.The parameter is either a DBus `+path+` or a plain javascript objectwith zero or more of the following fields. If an empty javascript objectis used as an argument, then all paths, interfaces and properties willbe watched.`+interface+`::Watch properties on this DBus interface.`+path+`::Watch interfaces and properties at this DBus path. May not be usedtogether with the `+path_namespace+` property.`+path_namespace+`::Watch interfaces and properties under this DBus path. It should be avalid DBus object path, that is, it should have no trailing slash. Ifan ObjectManager implementation is available at this interface, thenit is used. May not be used together with the `+path+` property.The returned value is ahttps://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Promise[Promise]that will complete successfully when the watch has populated its initialset of properties and interfaces, and these have been notified vialink:#cockpit-dbus-onnotify[`+client.onnotify+`].A watch can be removed by calling thelink:#cockpit-dbus-watch-remove[`+watch.remove()+`] method on thereturned value. If identical watches are added more than once, then theymust also be removed the same number of times before the removal takeseffect.[[cockpit-dbus-watch-then]]== watch.then()....watch.then(() => { ... })....This is a standardhttps://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Promise[Promise]method. It sets up a handler to be called when the watch has populatedits initial properties and interfaces.[[cockpit-dbus-watch-catch]]== watch.catch()....watch.catch(ex => { ... })....This is a standardhttps://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Promise[Promise]method. It sets up a handler to be called if the watch fails to populateits initial properties and interfaces. Note that a watch will only failif the DBus client closes or is somehow disconnected. It does not failin the case of missing interfaces or properties.[[cockpit-dbus-watch-remove]]== watch.remove()....watch.remove()....Remove the watch. This may not have any immediate effect if otherwatches are in place. In particular, if identical watches are added morethan once, then they must also be removed the same number of timesbefore the removal takes effect.[[cockpit-dbus-onnotify]]== client.onnotify....client.addEventListener("notify", data => { ... })....An event triggered when link:#cockpit-dbus-watch[watched] properties orinterfaces change.The link:#cockpit-dbus-proxy[`+client.proxy()+`] andlink:#cockpit-dbus-proxies[`+client.proxies()+`] functions and theobjects they return are high level wrappers around the `+data+` providedby this event.The `+data+` has the following form:....{"/path1": {"org.Interface1": {"Prop1": "value","Prop2": 5},"org.Interface2": null}}....Multiple paths may be present, each of which may have multipleinterfaces, each of which may have multiple properties. The first time agiven path and interface is emitted from this signal, it will have allits properties and interfaces. Thereafter only changes are noted. If aninterface is set to `+null+`, then that interface has disappeared.[[cockpit-dbus-notify]]== client.notify()....client.notify(data)....Emits a synthetic link:#cockpit-dbus-onnotify[`+notify+`] event. The`+data+` argument should follow the same layout as described for the`+notify+` event.[[cockpit-dbus-onmeta]]== client.onmeta....client.onmeta = (ev, data) => { ... }....An event triggered when the meta data aboutlink:#cockpit-dbus-watch[watched] interfaces is loaded.The link:#cockpit-dbus-proxy[`+client.proxy()+`] andlink:#cockpit-dbus-proxies[`+client.proxies()+`] functions and theobjects they return are high level wrappers around the `+data+` providedby this event.The `+data+` has the following form:....{"org.Interface": {"methods": {"Method1": {"in": [ "s", "v" ],"out": [ "i" ]},"Method2": { }},"signals": {"Signal": {"in": [ "b", "s" ]}},"properties": {"Prop1": {"flags": "rw","type": "s"},"Prop2": {"flags": "r","type": "b"}}}}....Multiple interfaces may be present, each of which may have methods andproperties. This is emitted before the firstlink:#cockpit-dbus-proxy[`+client.onnotify+`] event for the relevantinterface.[[cockpit-dbus-variant]]== cockpit.variant()....variant = cockpit.variant(type, value)....A DBus variant is represented as a plain javascript object with a`+"t"+` property represesting the full DBus type of the variant, and a`+"v"+` property containing the variant value.This is a helper function for creating such a variant object.