Important: This documentation covers Yarn 1 (Classic).
For Yarn 2+ docs and migration guide, see yarnpkg.com.

Package detail

@jellybrick/dbus-next

JellyBrick2.8kMIT0.10.3TypeScript support: included

The next great DBus library for Node

dbus, dcop, d-bus, rpc, gnome, kde

readme

dbus-next

The next great DBus library for NodeJS.

Documentation

Chat

About

dbus-next is a fully featured high level library for DBus geared primarily towards integration of applications into Linux desktop and mobile environments.

Desktop application developers can use this library for integrating their applications into desktop environments by implementing common DBus standard interfaces or creating custom plugin interfaces.

Desktop users can use this library to create their own scripts and utilities to interact with those interfaces for customization of their desktop environment.

Node Compatibility

As of now, dbus-next targets the latest features of JavaScript. The earliest version supported is 6.3.0. However, the library uses BigInt by default for the long integer types which was introduced in 10.8.0. If you need to support versions earlier than this, set BigInt compatibility mode. This will configure the library to use JSBI as a polyfill for long types.

const dbus = require('dbus-next');
dbus.setBigIntCompat(true);

The Client Interface

You can get a proxy object for a name on the bus with the bus.getProxyObject() function, passing the name and the path. The proxy object contains introspection data about the object including a list of nodes and interfaces. You can get an interface with the object.getInterface() function passing the name of the interface.

The interface object has methods you can call that correspond to the methods in the introspection data. Pass normal JavaScript objects to the parameters of the function and they will automatically be converted into the advertised DBus type. However, you must use the Variant class to represent DBus variants.

Methods will similarly return JavaScript objects converted from the advertised DBus type, with the Variant class used to represent returned variants. If the method returns multiple values, they will be returned within an array.

The interface object is an event emitter that will emit the name of a signal when it is emitted on the bus. Arguments to the callback should correspond to the arguments of the signal.

This is a brief example of using a proxy object with the MPRIS media player interface.

let dbus = require('dbus-next');
let bus = dbus.sessionBus();
let Variant = dbus.Variant;

// getting an object introspects it on the bus and creates the interfaces
let obj = await bus.getProxyObject('org.mpris.MediaPlayer2.vlc', '/org/mpris/MediaPlayer2');

// the interfaces are the primary way of interacting with objects on the bus
let player = obj.getInterface('org.mpris.MediaPlayer2.Player');
let properties = obj.getInterface('org.freedesktop.DBus.Properties');

// call methods on the interface
await player.Play()

// get properties with the properties interface (this returns a variant)
let volumeVariant = await properties.Get('org.mpris.MediaPlayer2.Player', 'Volume');
console.log('current volume: ' + volumeVariant.value);

// set properties with the properties interface using a variant
await properties.Set('org.mpris.MediaPlayer2.Player', 'Volume', new Variant('d', volumeVariant.value + 0.05));

// listen to signals
properties.on('PropertiesChanged', (iface, changed, invalidated) => {
  for (let prop of Object.keys(changed)) {
    console.log(`property changed: ${prop}`);
  }
});

For a complete example, see the MPRIS client example which can be used to control media players on the command line.

The Service Interface

You can use the Interface class to define your interfaces. This interfaces uses the proposed decorators syntax which is not yet part of the ECMAScript standard, but should be included one day. Unfortunately, you'll need a Babel plugin to make this code work for now.

let dbus = require('dbus-next');
let Variant = dbus.Variant;

let {
  Interface, property, method, signal, DBusError,
  ACCESS_READ, ACCESS_WRITE, ACCESS_READWRITE
} = dbus.interface;

let bus = dbus.sessionBus();

class ExampleInterface extends Interface {
  @property({signature: 's', access: ACCESS_READWRITE})
  SimpleProperty = 'foo';

  _MapProperty = {
    'foo': new Variant('s', 'bar'),
    'bat': new Variant('i', 53)
  };

  @property({signature: 'a{sv}'})
  get MapProperty() {
    return this._MapProperty;
  }

  set MapProperty(value) {
    this._MapProperty = value;

    Interface.emitPropertiesChanged(this, {
      MapProperty: value
    });
  }

  @method({inSignature: 's', outSignature: 's'})
  Echo(what) {
    return what;
  }

  @method({inSignature: 'ss', outSignature: 'vv'})
  ReturnsMultiple(what, what2) {
    return [
      new Variant('s', what),
      new Variant('s', what2)
    ];
  }

  @method({inSignature: '', outSignature: ''})
  ThrowsError() {
    // the error is returned to the client
    throw new DBusError('org.test.iface.Error', 'something went wrong');
  }

  @method({inSignature: '', outSignature: '', noReply: true})
  NoReply() {
    // by setting noReply to true, dbus-next will NOT send a return reply through dbus 
    // after the method is called.
  }

  @signal({signature: 's'})
  HelloWorld(value) {
    return value;
  }

  @signal({signature: 'ss'})
  SignalMultiple(x) {
    return [
      'hello',
      'world'
    ];
  }
}

let example = new ExampleInterface('org.test.iface');

setTimeout(() => {
  // emit the HelloWorld signal by calling the method with the parameters to
  // send to the listeners
  example.HelloWorld('hello');
}, 500);

async function main() {
  // make a request for the name on the bus
  await bus.requestName('org.test.name');
  // export the interface on the path
  bus.export('/org/test/path', example);
}

main().catch((err) => {
  console.log('Error: ' + err);
});

Interfaces extend the Interface class. Declare service methods, properties, and signals with the decorators provided from the library. You can optionally request a name on the bus with bus.requestName() so clients have a well-known name to connect to. Then call bus.export() with the path and interface to expose this interface on the bus.

Methods are called when a DBus client calls that method on the server. Properties can be gotten and set with the org.freedesktop.DBus.Properties interface and are included in the introspection xml.

To emit a signal, just call the method marked with the signal decorator and the signal will be emitted with the returned value.

If you have an interface xml description, which can be gotten from the org.freedesktop.DBus.Introspect method on an exported interface, you can generate dbus-next JavaScript classes from the xml file with the bin/generate-interfaces.js utility.

The Low-Level Interface

The low-level interface can be used to interact with messages directly. Create new messages with the Message class to be sent on the bus as method calls, signals, method returns, or errors. Method calls can be called with the call() method of the MessageBus to await a reply and send() can be use for messages that don't expect a reply.

let dbus = require('dbus-next');
let Message = dbus.Message;

let bus = dbus.sessionBus();

// send a method call to list the names on the bus
let methodCall = new Message({
  destination: 'org.freedesktop.DBus',
  path: '/org/freedesktop/DBus',
  interface: 'org.freedesktop.DBus',
  member: 'ListNames'
});

let reply = await bus.call(methodCall);
console.log('names on the bus: ', reply.body[0]);

// add a custom handler for a particular method
bus.addMethodHandler((msg) => {
  if (msg.path === '/org/test/path' &&
      msg.interface === 'org.test.interface'
      && msg.member === 'SomeMethod') {
    // handle the method by sending a reply
    let someMethodReply = Message.newMethodReturn(msg, 's', ['hello']);
    bus.send(someMethodReply);
    return true;
  }
});

// listen to any messages that are sent to the bus
bus.on('message', (msg) => {
  console.log('got a message: ', msg);
});

For a complete example of how to use the low-level interface to send messages, see the dbus-next-send.js script in the bin directory.

The Type System

Values that are sent or received over the message bus always have an associated signature that specifies the types of those values. For the high-level client and service, these signatures are specified in XML data which is advertised in a standard DBus interface. The high-level client dynamically creates classes based on this introspection data with methods and signals with arguments based on the type signature. The high-level service does the inverse by introspecting the class to create the introspection XML data which is advertised on the bus for clients.

Each code in the signature is mapped to a JavaScript type as shown in the table below.

Name Code JS Type Notes
BYTE y number
BOOLEAN b boolean
INT16 n number
UINT16 q number
INT32 i number
UINT32 u number
INT64 x BigInt Use dbus.setBigIntCompat(true) to use JSBI
UINT64 t BigInt Use dbus.setBigIntCompat(true) to use JSBI
DOUBLE d number
STRING s string
OBJECT_PATH o string Must be a valid object path
SIGNATURE g string Must be a valid signature
UNIX_FD h number Must be a valid unix file descriptor. e.g. from fs.open()
ARRAY a Array Must be followed by a complete type which specifies the child type
STRUCT ( Array Types in the JS Array must match the types between the parens
VARIANT v Variant This class is provided by the library.
DICT_ENTRY { Object Must be included in an array type to be an object.

Unix file descriptors are only supported on abstract or domain (path) sockets. This is the default for both system and session bus. When sending a file descriptor it must be kept open until the message is delivered. When receiving a file descriptor the application is responsible for closing it.

The types a, (, v, and { are container types that hold other values. Examples of container types and JavaScript examples are in the table below.

Signature Example Notes
(su) [ 'foo', 5 ] Each element in the array must match the corresponding type of the struct member.
as [ 'foo', 'bar' ] The child type comes immediately after the a. The array can have any number of elements, but they all must match the child type.
a{su} { 'foo': 5 } An "array of dict entries" is represented by an Object. The type after { is the key type and the type before the } is the value type.
ay Buffer.from([0x62, 0x75, 0x66]) Special case: an array of bytes is represented by a Node Buffer.
v new Variant('s', 'hello') Signature must be a single type. Value may be a container type.
(asv) [ ['foo'], new Variant('s', 'bar') ] Containers may be nested.

For more information on the DBus type system, see the specification.

Negotiating Unix File Descriptors

To support negotiating Unix file descriptors (DBus type h), set negotiateUnixFd to true in the message bus constructor options. The value of any type h in messages sent or received should be the file descriptor itself. You are responsible for closing any file descriptor sent or received by the bus.

Contributing

Contributions are welcome. Development happens on Github.

Similar Projects

dbus-next is a fork of dbus-native library. While this library is great, it has many bugs which I don't think can be fixed without completely redesigning the user API. Another library exists node-dbus which is similar, but also not provide enough features to create full-featured DBus services.

You can use this code under an MIT license (see LICENSE).

© 2012, Andrey Sidorov

© 2018, Tony Crisci

changelog

Changelog

v0.10.2

This is a hotfix release for a bug in the system message bus.

  • Add default parameters object to system message bus constructor (#90)
  • Add missing flags to TypeScript definitions (#91)
  • Add parameters object to system bus TypeScript definitions (#92)

v0.10.1

This release includes bugfixes and new features.

  • Support negotiating Unix FDs (#67, #89)
  • Add noReply to MethodOptions interface in Type Definitions (#70)
  • Fix compatibility with buffer@4 (#71)
  • Init signals on ProxyObject creation (#86)

v0.9.2

This release includes two bugfixes.

  • service: Fix duplicate paths in xml introspection (#62)
  • client: Fix a bug where signal handlers were run multiple times (#64)

v0.9.1

This release includes some bug fixes, new features, and a semi-breaking change.

  • (semi-breaking) Make type ay a buffer. This is different from previous behavior, but it is in line with the documentation from the beginning of the project. (#57)
  • service: Add support for no reply methods (#50)
  • fix syntax for tcp addresses (#51)
  • Add typescript bindings for bus events (#58)
  • bug: property getter executed when using configureMembers (#60)
  • Improve code generators (#52)
  • Avoid JSBI code paths when BigInt compatibility mode is not on (this should help a bit in webpack environments) (f1e2b4a)

v0.8.2

This release includes some bug fixes.

  • Include the TypeScript typings file in the package (#44)
  • Add some fixes for TypeScript types (#45, #46, #47)
  • Support unmarshalling messages in big endian (#36, #48)

v0.8.1

This release contains bugfixes and new features.

  • Update repository url to dbusjs org.
  • Fix memory leak for high level client signal match rules. (#39, #40)
  • Init proxy objects from xml string to avoid extra introspection. (4518825)
  • Add configureMembers to service interface as an alternative to decorators. (#32)
  • Allow async methods in the service interface. (#33)
  • Add TypeScript typings. (#28, #34)
  • Bugfix: correctly unmarshal unix socket 'h' type. (#35)
  • Support DBus monitor clients. (#41, #42)

v0.7.1

This release contains breaking changes, bugfixes, and features.

  • Fix bus name validator for ProxyObject (#27)
  • Move all constants to enum classes (breaking)
  • Remove the Name class (breaking) (#22)
  • Remove the NameExistsError (breaking)
  • Enable TCP support (#26)
  • Use nornagons put fork

v0.6.1

This release contains new major features.

  • Redesign, expose, and add tests for the low-level api (#20)
  • Add reply info to DBusError for the client (#21)
  • Add the dbus-next-send.js script to demonstrate the low-level api.

For more information on the low-level api, see the documentation for the new classes and members.

  • Message class - Represents a DBus message for sending or receiving messages on the bus.
  • MessageBus#call() - Send a method call message on the bus and wait for a reply.
  • MessageBus#send() - Send a message on the bus.
  • MessageBus#newSerial() - Get a serial for sending the message.
  • MessageBus#addMethodHandler() - Add a custom method handler for messages.
  • MessageBus#removeMethodHandler() - Remove a method handler.

The MessageBus has gained the following events:

  • connect - Emitted after the bus has connected.
  • message - Emitted when a message is received on the bus.

v0.5.1

This release contains some import bugfixes, features, and breaking changes. The service interface has been upgraded to "somewhat stable".

  • Use an ES2015 class for the MessageBus.
  • Make the low level interface private for now. (breaking, ref #20).
  • Document the public api and make everything not documented private (breaking, #10).
  • Remove tcp message bus support (breaking).
  • Forward connection errors to the MessageBus.
  • Make interfaces member of the ProxyObject a map from interface names to ProxyInterfaces (breaking).
  • ProxyObject#getInterface now throws an error if the interface is not found (breaking).

v0.4.2

This release contains some important bugfixes and features.

  • Gracefully handle user errors in services by returning the error to the client. (#11)
  • Remove the old high-level interfaces. (#15)
  • Implement org.freedesktop.DBus.Peer for clients. (#16)
  • Cache name owners and discriminate signals on owner (fixes a lot of mpris-service test errors).
  • Clean up a lot of dead code.

v0.4.1

This release contains breaking changes to how interfaces are exported on the bus with the public api. See the README and example service for the current way to export interfaces.

  • Add continuous integration
  • Give DBusError to clients when services throw errors (#11)
  • get dbus session bus address from the filesystem when DBUS_SESSION_BUS_ADDRESS is not set in the environment (addresses #14)
  • Add constants for name request flags
  • remove bus.export() and bus.unexport() (breaking)
  • Add bus.requestName() to the public api which now returns a promise which resolves to a Name object which is now also part of the public api.
  • Add name.release() to remove a name from the bus

v0.3.2

  • Add bus name validators
  • bugfix: allow "-" in bus names
  • bugfix: Use Long.js internally to fix issues with sending and receiving negative numbers

v0.3.1

Export dbus interface and member validators.

v0.2.1

This version introduces changes for compatibility with node version 6.3.0 and adds the generate-interfaces.js utility.

v0.2.0

This version contains breaking changes and new features.

  • BigInt compatibility mode (breaking) (#7)
  • Bump Node engine requirement to 8.2.1 (#7, #6)
  • Make emitting of PropertiesChange a static method on Interface (breaking)
  • Add name option to members to change the name from the JavaScript name (#9)
  • Add disabled option to members to disable members at runtime (#9)
  • Add tests for introspection xml generation

v0.1.0

  • Remove optimist dependency
  • Allow throwing DBusError in getter and setter for interfaces
  • Use BigInt for 'x' and 't' types