UNPKG

@quadratclown/dbus-next

Version:
161 lines (146 loc) 4.79 kB
const { Message } = require('../message-type'); const Interface = require('./interface').Interface; const assertObjectPathValid = require('../validators').assertObjectPathValid; class ServiceObject { constructor (path, bus) { assertObjectPathValid(path); this.path = path; this.bus = bus; this.interfaces = {}; this._handlers = {}; } addInterface (iface) { if (!(iface instanceof Interface)) { throw new Error(`object.addInterface takes an Interface as the first argument (got ${iface})`); } if (this.interfaces[iface.$name]) { throw new Error(`an interface with name '${iface.$name}' is already exported on this object`); } this.interfaces[iface.$name] = iface; const that = this; const propertiesChangedHandler = function (changedProperties, invalidatedProperties) { const body = [ iface.$name, changedProperties, invalidatedProperties ]; that.bus.send(Message.newSignal(that.path, 'org.freedesktop.DBus.Properties', 'PropertiesChanged', 'sa{sv}as', body)); }; const signalHandler = function (options, result) { // TODO lots of repeated code with the method handler here const { signature, signatureTree, name } = options; if (result === undefined) { result = []; } else if (signatureTree.length === 1) { result = [result]; } else if (!Array.isArray(result)) { throw new Error(`signal ${iface.$name}.${name} expected to return multiple arguments in an array (signature: '${signature}')`); } if (signatureTree.length !== result.length) { throw new Error(`signal ${iface.$name}.${name} returned the wrong number of arguments (got ${result.length} expected ${signatureTree.length}) for signature '${signature}'`); } that.bus.send(Message.newSignal(that.path, iface.$name, name, signature, result)); }; this._handlers[iface.$name] = { propertiesChanged: propertiesChangedHandler, signal: signalHandler }; iface.$emitter.on('signal', signalHandler); iface.$emitter.on('properties-changed', propertiesChangedHandler); } removeInterface (iface) { if (!(iface instanceof Interface)) { throw new Error(`object.removeInterface takes an Interface as the first argument (got ${iface})`); } if (!this.interfaces[iface.$name]) { throw new Error(`Interface ${iface.$name} not exported on this object`); } const handlers = this._handlers[iface.$name]; iface.$emitter.removeListener('signal', handlers.signal); iface.$emitter.removeListener('properties-changed', handlers.propertiesChanged); delete this._handlers[iface.$name]; delete this.interfaces[iface.$name]; } introspect () { const interfaces = ServiceObject.defaultInterfaces(); for (const i of Object.keys(this.interfaces)) { const iface = this.interfaces[i]; interfaces.push(iface.$introspect()); } return interfaces; } static defaultInterfaces () { return [ { $: { name: 'org.freedesktop.DBus.Introspectable' }, method: [ { $: { name: 'Introspect' }, arg: [ { $: { name: 'data', direction: 'out', type: 's' } } ] } ] }, { $: { name: 'org.freedesktop.DBus.Peer' }, method: [ { $: { name: 'GetMachineId' }, arg: [ { $: { direction: 'out', name: 'machine_uuid', type: 's' } } ] }, { $: { name: 'Ping' } } ] }, { $: { name: 'org.freedesktop.DBus.Properties' }, method: [ { $: { name: 'Get' }, arg: [ { $: { direction: 'in', type: 's' } }, { $: { direction: 'in', type: 's' } }, { $: { direction: 'out', type: 'v' } } ] }, { $: { name: 'Set' }, arg: [ { $: { direction: 'in', type: 's' } }, { $: { direction: 'in', type: 's' } }, { $: { direction: 'in', type: 'v' } } ] }, { $: { name: 'GetAll' }, arg: [ { $: { direction: 'in', type: 's' } }, { $: { direction: 'out', type: 'a{sv}' } } ] } ], signal: [ { $: { name: 'PropertiesChanged' }, arg: [ { $: { type: 's' } }, { $: { type: 'a{sv}' } }, { $: { type: 'as' } } ] } ] } ]; } } module.exports = ServiceObject;