File: IObject.h

package info (click to toggle)
sdbus-cpp 2.2.1-1
  • links: PTS, VCS
  • area: main
  • in suites: forky, sid
  • size: 1,556 kB
  • sloc: cpp: 12,626; ansic: 239; xml: 170; makefile: 27
file content (484 lines) | stat: -rw-r--r-- 22,539 bytes parent folder | download | duplicates (2)
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
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
/**
 * (C) 2016 - 2021 KISTLER INSTRUMENTE AG, Winterthur, Switzerland
 * (C) 2016 - 2024 Stanislav Angelovic <stanislav.angelovic@protonmail.com>
 *
 * @file IObject.h
 *
 * Created on: Nov 8, 2016
 * Project: sdbus-c++
 * Description: High-level D-Bus IPC C++ library based on sd-bus
 *
 * This file is part of sdbus-c++.
 *
 * sdbus-c++ is free software; you can redistribute it and/or modify it
 * under the terms of the GNU Lesser General Public License as published by
 * the Free Software Foundation, either version 2.1 of the License, or
 * (at your option) any later version.
 *
 * sdbus-c++ is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
 * GNU Lesser General Public License for more details.
 *
 * You should have received a copy of the GNU Lesser General Public License
 * along with sdbus-c++. If not, see <http://www.gnu.org/licenses/>.
 */

#ifndef SDBUS_CXX_IOBJECT_H_
#define SDBUS_CXX_IOBJECT_H_

#include <sdbus-c++/ConvenienceApiClasses.h>
#include <sdbus-c++/Flags.h>
#include <sdbus-c++/TypeTraits.h>
#include <sdbus-c++/VTableItems.h>

#include <functional>
#include <memory>
#include <string>
#include <vector>

// Forward declarations
namespace sdbus {
    class Signal;
    class IConnection;
    class ObjectPath;
}

namespace sdbus {

    /********************************************//**
     * @class IObject
     *
     * IObject class represents a D-Bus object instance identified by a specific object path.
     * D-Bus object provides its interfaces, methods, signals and properties on a bus
     * identified by a specific bus name.
     *
     * All IObject member methods throw @c sdbus::Error in case of D-Bus or sdbus-c++ error.
     * The IObject class has been designed as thread-aware. However, the operation of
     * creating and sending asynchronous method replies, as well as creating and emitting
     * signals, is thread-safe by design.
     *
     ***********************************************/
    class IObject
    {
    public: // High-level, convenience API
        virtual ~IObject() = default;

        /*!
         * @brief Adds a declaration of methods, properties and signals of the object at a given interface
         *
         * @param[in] vtable Individual instances of VTable item structures stored in a vector
         * @return VTableAdder high-level helper class
         *
         * This method is used to declare attributes for the object under the given interface.
         * Parameter `vtable' represents a vtable definition that may contain method declarations
         * (using MethodVTableItem struct), property declarations (using PropertyVTableItem
         * struct), signal declarations (using SignalVTableItem struct), or global interface
         * flags (using InterfaceFlagsVTableItem struct).
         *
         * An interface can have any number of vtables attached to it.
         *
         * Consult manual pages for the underlying `sd_bus_add_object_vtable` function for more information.
         *
         * The method can be called at any time during object's lifetime.
         *
         * When called like `addVTable(vtable).forInterface(interface)`, then an internal registration
         * slot is created for that vtable and its lifetime is tied to the lifetime of the Object instance.
         * When called like `addVTable(items...).forInterface(interface, sdbus::return_slot)`, then an internal
         * registration slot is created for the vtable and is returned to the caller. Keeping the slot means
         * keep the registration "alive". Destroying the slot means that the vtable is not needed anymore,
         * and the vtable gets removed from the object. This allows for "dynamic" object API where vtables
         * can be added or removed by the user at runtime.
         *
         * The function provides strong exception guarantee. The state of the object remains
         * unmodified in face of an exception.
         *
         * @throws sdbus::Error in case of failure
         */
        [[nodiscard]] VTableAdder addVTable(std::vector<VTableItem> vtable);

        /*!
         * @brief Adds a declaration of methods, properties and signals of the object at a given interface
         *
         * @param[in] items Individual instances of VTable item structures
         * @return VTableAdder high-level helper class
         *
         * This method is used to declare attributes for the object under the given interface.
         * Parameter pack contains vtable definition that may contain method declarations
         * (using MethodVTableItem struct), property declarations (using PropertyVTableItem
         * struct), signal declarations (using SignalVTableItem struct), or global interface
         * flags (using InterfaceFlagsVTableItem struct).
         *
         * An interface can have any number of vtables attached to it.
         *
         * Consult manual pages for the underlying `sd_bus_add_object_vtable` function for more information.
         *
         * The method can be called at any time during object's lifetime.
         *
         * When called like `addVTable(items...).forInterface(interface)`, then an internal registration
         * slot is created for that vtable and its lifetime is tied to the lifetime of the Object instance.
         * When called like `addVTable(items...).forInterface(interface, sdbus::return_slot)`, then an internal
         * registration slot is created for the vtable and is returned to the caller. Keeping the slot means
         * keep the registration "alive". Destroying the slot means that the vtable is not needed anymore,
         * and the vtable gets removed from the object. This allows for "dynamic" object API where vtables
         * can be added or removed by the user at runtime.
         *
         * The function provides strong exception guarantee. The state of the object remains
         * unmodified in face of an exception.
         *
         * @throws sdbus::Error in case of failure
         */
        template < typename... VTableItems
                 , typename = std::enable_if_t<(is_one_of_variants_types<VTableItem, std::decay_t<VTableItems>> && ...)> >
        [[nodiscard]] VTableAdder addVTable(VTableItems&&... items);

        /*!
         * @brief Emits signal on D-Bus
         *
         * @param[in] signalName Name of the signal
         * @return A helper object for convenient emission of signals
         *
         * This is a high-level, convenience way of emitting D-Bus signals that abstracts
         * from the D-Bus message concept. Signal arguments are automatically serialized
         * in a message and D-Bus signatures automatically deduced from the provided native arguments.
         *
         * Example of use:
         * @code
         * int arg1 = ...;
         * double arg2 = ...;
         * SignalName fooSignal{"fooSignal"};
         * object_.emitSignal(fooSignal).onInterface("com.kistler.foo").withArguments(arg1, arg2);
         * @endcode
         *
         * @throws sdbus::Error in case of failure
         */
        [[nodiscard]] SignalEmitter emitSignal(const SignalName& signalName);

        /*!
         * @copydoc IObject::emitSignal(const SignalName&)
         */
        [[nodiscard]] SignalEmitter emitSignal(const std::string& signalName);

        /*!
         * @copydoc IObject::emitSignal(const SignalName&)
         */
        [[nodiscard]] SignalEmitter emitSignal(const char* signalName);

        /*!
         * @brief Emits PropertyChanged signal for specified properties under a given interface of this object path
         *
         * @param[in] interfaceName Name of an interface that properties belong to
         * @param[in] propNames Names of properties that will be included in the PropertiesChanged signal
         *
         * @throws sdbus::Error in case of failure
         */
        virtual void emitPropertiesChangedSignal(const InterfaceName& interfaceName, const std::vector<PropertyName>& propNames) = 0;

        /*!
         * @copydoc IObject::emitPropertiesChangedSignal(const InterfaceName&,const std::vector<PropertyName>&)
         */
        virtual void emitPropertiesChangedSignal(const char* interfaceName, const std::vector<PropertyName>& propNames) = 0;

        /*!
         * @brief Emits PropertyChanged signal for all properties on a given interface of this object path
         *
         * @param[in] interfaceName Name of an interface
         *
         * @throws sdbus::Error in case of failure
         */
        virtual void emitPropertiesChangedSignal(const InterfaceName& interfaceName) = 0;

        /*!
         * @copydoc IObject::emitPropertiesChangedSignal(const InterfaceName&)
         */
        virtual void emitPropertiesChangedSignal(const char* interfaceName) = 0;

        /*!
         * @brief Emits InterfacesAdded signal on this object path
         *
         * This emits an InterfacesAdded signal on this object path, by iterating all registered
         * interfaces on the path. All properties are queried and included in the signal.
         * This call is equivalent to emitInterfacesAddedSignal() with an explicit list of
         * registered interfaces. However, unlike emitInterfacesAddedSignal(interfaces), this
         * call can figure out the list of supported interfaces itself. Furthermore, it properly
         * adds the builtin org.freedesktop.DBus.* interfaces.
         *
         * @throws sdbus::Error in case of failure
         */
        virtual void emitInterfacesAddedSignal() = 0;

        /*!
         * @brief Emits InterfacesAdded signal on this object path
         *
         * This emits an InterfacesAdded signal on this object path with explicitly provided list
         * of registered interfaces. Since v2.0, sdbus-c++ supports dynamically addable/removable
         * object interfaces and their vtables, so this method now makes more sense.
         *
         * @throws sdbus::Error in case of failure
         */
        virtual void emitInterfacesAddedSignal(const std::vector<InterfaceName>& interfaces) = 0;

        /*!
         * @brief Emits InterfacesRemoved signal on this object path
         *
         * This is like sd_bus_emit_object_added(), but emits an InterfacesRemoved signal on this
         * object path. This only includes any registered interfaces but skips the properties.
         * This function shall be called (just) before destroying the object.
         *
         * @throws sdbus::Error in case of failure
         */
        virtual void emitInterfacesRemovedSignal() = 0;

        /*!
         * @brief Emits InterfacesRemoved signal on this object path
         *
         * This emits an InterfacesRemoved signal on the given path with explicitly provided list
         * of registered interfaces. Since v2.0, sdbus-c++ supports dynamically addable/removable
         * object interfaces and their vtables, so this method now makes more sense.
         *
         * @throws sdbus::Error in case of failure
         */
        virtual void emitInterfacesRemovedSignal(const std::vector<InterfaceName>& interfaces) = 0;

        /*!
         * @brief Adds an ObjectManager interface at the path of this D-Bus object
         *
         * Creates an ObjectManager interface at the specified object path on
         * the connection. This is a convenient way to interrogate a connection
         * to see what objects it has.
         *
         * This call creates a so-called floating registration. This means that
         * the ObjectManager interface stays there for the lifetime of the object.
         *
         * @throws sdbus::Error in case of failure
         */
        virtual void addObjectManager() = 0;

        /*!
         * @brief Adds an ObjectManager interface at the path of this D-Bus object
         *
         * @return Slot handle owning the registration
         *
         * Creates an ObjectManager interface at the specified object path on
         * the connection. This is a convenient way to interrogate a connection
         * to see what objects it has.
         *
         * The lifetime of the ObjectManager interface is bound to the lifetime
         * of the returned slot instance.
         *
         * @throws sdbus::Error in case of failure
         */
        [[nodiscard]] virtual Slot addObjectManager(return_slot_t) = 0;

        /*!
         * @brief Provides D-Bus connection used by the object
         *
         * @return Reference to the D-Bus connection
         */
        [[nodiscard]] virtual sdbus::IConnection& getConnection() const = 0;

        /*!
         * @brief Returns object path of the underlying DBus object
         */
        [[nodiscard]] virtual const ObjectPath& getObjectPath() const = 0;

        /*!
         * @brief Provides access to the currently processed D-Bus message
         *
         * This method provides access to the currently processed incoming D-Bus message.
         * "Currently processed" means that the registered callback handler(s) for that message
         * are being invoked. This method is meant to be called from within a callback handler
         * (e.g. from a D-Bus signal handler, or async method reply handler, etc.). In such a case it is
         * guaranteed to return a valid D-Bus message instance for which the handler is called.
         * If called from other contexts/threads, it may return a valid or invalid message, depending
         * on whether a message was processed or not at the time of the call.
         *
         * @return Currently processed D-Bus message
         */
        [[nodiscard]] virtual Message getCurrentlyProcessedMessage() const = 0;

        /*!
         * @brief Unregisters object's API and removes object from the bus
         *
         * This method unregisters the object, its interfaces, methods, signals and properties
         * from the bus. Unregistration is done automatically also in object's destructor. This
         * method makes sense if, in the process of object removal, we need to make sure that
         * callbacks are unregistered explicitly before the final destruction of the object instance.
         *
         * @throws sdbus::Error in case of failure
         */
        virtual void unregister() = 0;

    public: // Lower-level, message-based API
        /*!
         * @brief Adds a declaration of methods, properties and signals of the object at a given interface
         *
         * @param[in] interfaceName Name of an interface the the vtable is registered for
         * @param[in] items Individual instances of VTable item structures
         *
         * This method is used to declare attributes for the object under the given interface.
         * Parameter `items' represents a vtable definition that may contain method declarations
         * (using MethodVTableItem struct), property declarations (using PropertyVTableItem
         * struct), signal declarations (using SignalVTableItem struct), or global interface
         * flags (using InterfaceFlagsVTableItem struct).
         *
         * An interface can have any number of vtables attached to it.
         *
         * Consult manual pages for the underlying `sd_bus_add_object_vtable` function for more information.
         *
         * The method can be called at any time during object's lifetime. For each vtable an internal
         * registration slot is created and its lifetime is tied to the lifetime of the Object instance.
         *
         * The function provides strong exception guarantee. The state of the object remains
         * unmodified in face of an exception.
         *
         * @throws sdbus::Error in case of failure
         */
        template < typename... VTableItems
                 , typename = std::enable_if_t<(is_one_of_variants_types<VTableItem, std::decay_t<VTableItems>> && ...)> >
        void addVTable(InterfaceName interfaceName, VTableItems&&... items);

        /*!
         * @brief Adds a declaration of methods, properties and signals of the object at a given interface
         *
         * @param[in] interfaceName Name of an interface the the vtable is registered for
         * @param[in] vtable A list of individual descriptions in the form of VTable item instances
         *
         * This method is used to declare attributes for the object under the given interface.
         * The `vtable' parameter may contain method declarations (using MethodVTableItem struct),
         * property declarations (using PropertyVTableItem struct), signal declarations (using
         * SignalVTableItem struct), or global interface flags (using InterfaceFlagsVTableItem struct).
         *
         * An interface can have any number of vtables attached to it.
         *
         * Consult manual pages for the underlying `sd_bus_add_object_vtable` function for more information.
         *
         * The method can be called at any time during object's lifetime. For each vtable an internal
         * registration slot is created and its lifetime is tied to the lifetime of the Object instance.
         *
         * The function provides strong exception guarantee. The state of the object remains
         * unmodified in face of an exception.
         *
         * @throws sdbus::Error in case of failure
         */
        virtual void addVTable(InterfaceName interfaceName, std::vector<VTableItem> vtable) = 0;

        /*!
         * @brief Adds a declaration of methods, properties and signals of the object at a given interface
         *
         * @param[in] interfaceName Name of an interface the the vtable is registered for
         * @param[in] vtable A list of individual descriptions in the form of VTable item instances
         *
         * This method is used to declare attributes for the object under the given interface.
         * The `vtable' parameter may contain method declarations (using MethodVTableItem struct),
         * property declarations (using PropertyVTableItem struct), signal declarations (using
         * SignalVTableItem struct), or global interface flags (using InterfaceFlagsVTableItem struct).
         *
         * An interface can have any number of vtables attached to it.
         *
         * Consult manual pages for the underlying `sd_bus_add_object_vtable` function for more information.
         *
         * The method can be called at any time during object's lifetime. For each vtable an internal
         * registration slot is created and is returned to the caller. The returned slot should be destroyed
         * when the vtable is not needed anymore. This allows for "dynamic" object API where vtables
         * can be added or removed by the user at runtime.
         *
         * The function provides strong exception guarantee. The state of the object remains
         * unmodified in face of an exception.
         *
         * @throws sdbus::Error in case of failure
         */
        [[nodiscard]] virtual Slot addVTable(InterfaceName interfaceName, std::vector<VTableItem> vtable, return_slot_t) = 0;

        /*!
         * @brief Creates a signal message
         *
         * @param[in] interfaceName Name of an interface that the signal belongs under
         * @param[in] signalName Name of the signal
         * @return A signal message
         *
         * Serialize signal arguments into the returned message and emit the signal by passing
         * the message with serialized arguments to the @c emitSignal function.
         * Alternatively, use higher-level API @c emitSignal(const std::string& signalName) defined below.
         *
         * @throws sdbus::Error in case of failure
         */
        [[nodiscard]] virtual Signal createSignal(const InterfaceName& interfaceName, const SignalName& signalName) const = 0;

        /*!
         * @brief Emits signal for this object path
         *
         * @param[in] message Signal message to be sent out
         *
         * Note: To avoid messing with messages, use higher-level API defined below.
         *
         * @throws sdbus::Error in case of failure
         */
        virtual void emitSignal(const sdbus::Signal& message) = 0;

    protected: // Internal API for efficiency reasons used by high-level API helper classes
        friend SignalEmitter;

        [[nodiscard]] virtual Signal createSignal(const char* interfaceName, const char* signalName) const = 0;
    };

    // Out-of-line member definitions

    inline SignalEmitter IObject::emitSignal(const SignalName& signalName)
    {
        return SignalEmitter(*this, signalName);
    }

    inline SignalEmitter IObject::emitSignal(const std::string& signalName)
    {
        return SignalEmitter(*this, signalName.c_str());
    }

    inline SignalEmitter IObject::emitSignal(const char* signalName)
    {
        return SignalEmitter(*this, signalName);
    }

    template <typename... VTableItems, typename>
    void IObject::addVTable(InterfaceName interfaceName, VTableItems&&... items)
    {
        addVTable(std::move(interfaceName), {std::forward<VTableItems>(items)...});
    }

    template <typename... VTableItems, typename>
    VTableAdder IObject::addVTable(VTableItems&&... items)
    {
        return addVTable(std::vector<VTableItem>{std::forward<VTableItems>(items)...});
    }

    inline VTableAdder IObject::addVTable(std::vector<VTableItem> vtable)
    {
        return VTableAdder(*this, std::move(vtable));
    }

    /*!
     * @brief Creates instance representing a D-Bus object
     *
     * @param[in] connection D-Bus connection to be used by the object
     * @param[in] objectPath Path of the D-Bus object
     * @return Pointer to the object representation instance
     *
     * The provided connection will be used by the object to export methods,
     * issue signals and provide properties.
     *
     * Creating a D-Bus object instance is (thread-)safe even upon the connection
     * which is already running its I/O event loop.
     *
     * Code example:
     * @code
     * auto proxy = sdbus::createObject(connection, "/com/kistler/foo");
     * @endcode
     */
    [[nodiscard]] std::unique_ptr<sdbus::IObject> createObject(sdbus::IConnection& connection, ObjectPath objectPath);

}

#include <sdbus-c++/ConvenienceApiClasses.inl>
#include <sdbus-c++/VTableItems.inl>

#endif /* SDBUS_CXX_IOBJECT_H_ */