summaryrefslogtreecommitdiff
path: root/examples/dbus-service.js
blob: b4af5c1af29ada63ad729477d2d2aae8a949b4fd (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
// SPDX-License-Identifier: MIT OR LGPL-2.0-or-later
// SPDX-FileCopyrightText: 2020 Andy Holmes <andrew.g.r.holmes@gmail.com>

import GLib from 'gi://GLib';
import Gio from 'gi://Gio';

/*
 * An XML DBus Interface
 */
const ifaceXml = `
<node>
  <interface name="org.gnome.gjs.Test">
    <method name="SimpleMethod"/>
    <method name="ComplexMethod">
      <arg type="s" direction="in" name="input"/>
      <arg type="u" direction="out" name="length"/>
    </method>
    <signal name="TestSignal">
      <arg name="type" type="s"/>
      <arg name="value" type="b"/>
    </signal>
    <property name="ReadOnlyProperty" type="s" access="read"/>
    <property name="ReadWriteProperty" type="b" access="readwrite"/>
  </interface>
</node>`;


// An example of the service-side implementation of the above interface.
class Service {
    constructor() {
        this.dbus = Gio.DBusExportedObject.wrapJSObject(ifaceXml, this);
    }

    // Properties
    get ReadOnlyProperty() {
        return 'a string';
    }

    get ReadWriteProperty() {
        if (this._readWriteProperty === undefined)
            return false;

        return this._readWriteProperty;
    }

    set ReadWriteProperty(value) {
        if (this.ReadWriteProperty !== value) {
            this._readWriteProperty = value;

            // Emitting property changes over DBus
            this.dbus.emit_property_changed(
                'ReadWriteProperty',
                new GLib.Variant('b', value)
            );
        }
    }

    // Methods
    SimpleMethod() {
        print('SimpleMethod() invoked');
    }

    ComplexMethod(input) {
        print(`ComplexMethod() invoked with "${input}"`);

        return input.length;
    }

    // Signals
    emitTestSignal() {
        this.dbus.emit_signal(
            'TestSignal',
            new GLib.Variant('(sb)', ['string', false])
        );
    }
}


// Once you've created an instance of your service, you will want to own a name
// on the bus so clients can connect to it.
let serviceObj = new Service();
let serviceSignalId = 0;


function onBusAcquired(connection, _name) {
    // At this point you have acquired a connection to the bus, and you should
    // export your interfaces now.
    serviceObj.dbus.export(connection, '/org/gnome/gjs/Test');
}

function onNameAcquired(_connection, _name) {
    // Clients will typically start connecting and using your interface now.

    // Emit the TestSignal every few seconds
    serviceSignalId = GLib.timeout_add_seconds(GLib.PRIORITY_DEFAULT, 3, () => {
        serviceObj.emitTestSignal();

        return GLib.SOURCE_CONTINUE;
    });
}

function onNameLost(_connection, _name) {
    // Clients will know not to call methods on your interface now. Usually this
    // callback will only be invoked if you try to own a name on DBus that
    // already has an owner.

    // Stop emitting the test signal
    if (serviceSignalId > 0) {
        GLib.Source.remove(serviceSignalId);
        serviceSignalId = 0;
    }
}

let ownerId = Gio.bus_own_name(
    Gio.BusType.SESSION,
    'org.gnome.gjs.Test',
    Gio.BusNameOwnerFlags.NONE,
    onBusAcquired,
    onNameAcquired,
    onNameLost
);


// Start an event loop
let loop = GLib.MainLoop.new(null, false);
loop.run();

// Unowning names works just like disconnecting, but note that `onNameLost()`
// will not be invoked in this case.
Gio.bus_unown_name(ownerId);

if (serviceSignalId > 0) {
    GLib.Source.remove(serviceSignalId);
    serviceSignalId = 0;
}