File: IProxy.h

package info (click to toggle)
sdbus-cpp 0.8.3-4
  • links: PTS, VCS
  • area: main
  • in suites: bullseye
  • size: 1,184 kB
  • sloc: cpp: 9,207; xml: 160; ansic: 115; makefile: 22
file content (427 lines) | stat: -rw-r--r-- 18,056 bytes parent folder | download | duplicates (3)
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
/**
 * (C) 2016 - 2017 KISTLER INSTRUMENTE AG, Winterthur, Switzerland
 * (C) 2016 - 2019 Stanislav Angelovic <angelovic.s@gmail.com>
 *
 * @file IProxy.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_IPROXY_H_
#define SDBUS_CXX_IPROXY_H_

#include <sdbus-c++/ConvenienceApiClasses.h>
#include <string>
#include <memory>
#include <functional>
#include <chrono>

// Forward declarations
namespace sdbus {
    class MethodCall;
    class MethodReply;
    class IConnection;
    class PendingAsyncCall;
    namespace internal {
        class Proxy;
    }
}

namespace sdbus {

    /********************************************//**
     * @class IProxy
     *
     * IProxy class represents a proxy object, which is a convenient local object created
     * to represent a remote D-Bus object in another process.
     * The proxy enables calling methods on remote objects, receiving signals from remote
     * objects, and getting/setting properties of remote objects.
     *
     * All IProxy member methods throw @c sdbus::Error in case of D-Bus or sdbus-c++ error.
     * The IProxy class has been designed as thread-aware. However, the operation of
     * creating and sending method calls (both synchronously and asynchronously) is
     * thread-safe by design.
     *
     ***********************************************/
    class IProxy
    {
    public:
        virtual ~IProxy() = default;

        /*!
         * @brief Creates a method call message
         *
         * @param[in] interfaceName Name of an interface that provides a given method
         * @param[in] methodName Name of the method
         * @return A method call message
         *
         * Serialize method arguments into the returned message and invoke the method by passing
         * the message with serialized arguments to the @c callMethod function.
         * Alternatively, use higher-level API @c callMethod(const std::string& methodName) defined below.
         *
         * @throws sdbus::Error in case of failure
         */
        virtual MethodCall createMethodCall(const std::string& interfaceName, const std::string& methodName) = 0;

        /*!
         * @brief Calls method on the proxied D-Bus object
         *
         * @param[in] message Message representing a method call
         * @param[in] timeout Timeout for dbus call in microseconds
         * @return A method reply message
         *
         * Normally, the call is blocking, i.e. it waits for the remote method to finish with either
         * a return value or an error.
         *
         * If the method call argument is set to not expect reply, the call will not wait for the remote
         * method to finish, i.e. the call will be non-blocking, and the function will return an empty,
         * invalid MethodReply object (representing void).
         *
         * Note: To avoid messing with messages, use higher-level API defined below.
         *
         * @throws sdbus::Error in case of failure
         */
        virtual MethodReply callMethod(const MethodCall& message, uint64_t timeout = 0) = 0;

        /*!
         * @copydoc IProxy::callMethod(const MethodCall&,uint64_t)
         */
        template <typename _Rep, typename _Period>
        MethodReply callMethod(const MethodCall& message, const std::chrono::duration<_Rep, _Period>& timeout);

        /*!
         * @brief Calls method on the proxied D-Bus object asynchronously
         *
         * @param[in] message Message representing an async method call
         * @param[in] asyncReplyCallback Handler for the async reply
         * @param[in] timeout Timeout for dbus call in microseconds
         * @return Cookie for the the pending asynchronous call
         *
         * The call is non-blocking. It doesn't wait for the reply. Once the reply arrives,
         * the provided async reply handler will get invoked from the context of the connection
         * I/O event loop thread.
         *
         * Note: To avoid messing with messages, use higher-level API defined below.
         *
         * @throws sdbus::Error in case of failure
         */
        virtual PendingAsyncCall callMethod(const MethodCall& message, async_reply_handler asyncReplyCallback, uint64_t timeout = 0) = 0;

        /*!
         * @copydoc IProxy::callMethod(const MethodCall&,async_reply_handler,uint64_t)
         */
        template <typename _Rep, typename _Period>
        PendingAsyncCall callMethod(const MethodCall& message, async_reply_handler asyncReplyCallback, const std::chrono::duration<_Rep, _Period>& timeout);

        /*!
         * @brief Registers a handler for the desired signal emitted by the proxied D-Bus object
         *
         * @param[in] interfaceName Name of an interface that the signal belongs to
         * @param[in] signalName Name of the signal
         * @param[in] signalHandler Callback that implements the body of the signal handler
         *
         * @throws sdbus::Error in case of failure
         */
        virtual void registerSignalHandler( const std::string& interfaceName
                                          , const std::string& signalName
                                          , signal_handler signalHandler ) = 0;

        /*!
         * @brief Finishes the registration of signal handlers
         *
         * The method physically subscribes to the desired signals.
         * Must be called only once, after all signals have been registered already.
         *
         * @throws sdbus::Error in case of failure
         */
        virtual void finishRegistration() = 0;

        /*!
         * @brief Unregisters proxy's signal handlers and stops receving replies to pending async calls
         *
         * Unregistration is done automatically also in proxy's destructor. This method makes
         * sense if, in the process of proxy removal, we need to make sure that callbacks
         * are unregistered explicitly before the final destruction of the proxy instance.
         *
         * @throws sdbus::Error in case of failure
         */
        virtual void unregister() = 0;

        /*!
         * @brief Calls method on the proxied D-Bus object
         *
         * @param[in] methodName Name of the method
         * @return A helper object for convenient invocation of the method
         *
         * This is a high-level, convenience way of calling D-Bus methods that abstracts
         * from the D-Bus message concept. Method arguments/return value are automatically (de)serialized
         * in a message and D-Bus signatures automatically deduced from the provided native arguments
         * and return values.
         *
         * Example of use:
         * @code
         * int result, a = ..., b = ...;
         * object_.callMethod("multiply").onInterface(INTERFACE_NAME).withArguments(a, b).storeResultsTo(result);
         * @endcode
         *
         * @throws sdbus::Error in case of failure
         */
        [[nodiscard]] MethodInvoker callMethod(const std::string& methodName);

        /*!
         * @brief Calls method on the proxied D-Bus object asynchronously
         *
         * @param[in] methodName Name of the method
         * @return A helper object for convenient asynchronous invocation of the method
         *
         * This is a high-level, convenience way of calling D-Bus methods that abstracts
         * from the D-Bus message concept. Method arguments/return value are automatically (de)serialized
         * in a message and D-Bus signatures automatically deduced from the provided native arguments
         * and return values.
         *
         * Example of use:
         * @code
         * int a = ..., b = ...;
         * object_.callMethodAsync("multiply").onInterface(INTERFACE_NAME).withArguments(a, b).uponReplyInvoke([](int result)
         * {
         *     std::cout << "Got result of multiplying " << a << " and " << b << ": " << result << std::endl;
         * });
         * @endcode
         *
         * @throws sdbus::Error in case of failure
         */
        [[nodiscard]] AsyncMethodInvoker callMethodAsync(const std::string& methodName);

        /*!
         * @brief Registers signal handler for a given signal of the proxied D-Bus object
         *
         * @param[in] signalName Name of the signal
         * @return A helper object for convenient registration of the signal handler
         *
         * This is a high-level, convenience way of registering to 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 parameters
         * of the provided native signal callback.
         *
         * Example of use:
         * @code
         * object_.uponSignal("fooSignal").onInterface("com.kistler.foo").call([this](int arg1, double arg2){ this->onFooSignal(arg1, arg2); });
         * @endcode
         *
         * @throws sdbus::Error in case of failure
         */
        [[nodiscard]] SignalSubscriber uponSignal(const std::string& signalName);

        /*!
         * @brief Gets value of a property of the proxied D-Bus object
         *
         * @param[in] propertyName Name of the property
         * @return A helper object for convenient getting of property value
         *
         * This is a high-level, convenience way of reading D-Bus property values that abstracts
         * from the D-Bus message concept. sdbus::Variant is returned which shall then be converted
         * to the real property type (implicit conversion is supported).
         *
         * Example of use:
         * @code
         * int state = object.getProperty("state").onInterface("com.kistler.foo");
         * @endcode
         *
         * @throws sdbus::Error in case of failure
         */
        [[nodiscard]] PropertyGetter getProperty(const std::string& propertyName);

        /*!
         * @brief Sets value of a property of the proxied D-Bus object
         *
         * @param[in] propertyName Name of the property
         * @return A helper object for convenient setting of property value
         *
         * This is a high-level, convenience way of writing D-Bus property values that abstracts
         * from the D-Bus message concept.
         *
         * Example of use:
         * @code
         * int state = ...;
         * object_.setProperty("state").onInterface("com.kistler.foo").toValue(state);
         * @endcode
         *
         * @throws sdbus::Error in case of failure
         */
        [[nodiscard]] PropertySetter setProperty(const std::string& propertyName);

        /*!
         * @brief Returns object path of the underlying DBus object
         */
        virtual const std::string& getObjectPath() const = 0;
    };

    /********************************************//**
     * @class PendingAsyncCall
     *
     * PendingAsyncCall represents a simple handle type to cancel the delivery
     * of the asynchronous D-Bus call result to the application.
     *
     * The handle is lifetime-independent from the originating Proxy object.
     * It's safe to call its methods even after the Proxy has gone.
     *
     ***********************************************/
    class PendingAsyncCall
    {
    public:
        /*!
         * @brief Cancels the delivery of the pending asynchronous call result
         *
         * This function effectively removes the callback handler registered to the
         * async D-Bus method call result delivery. Does nothing if the call was
         * completed already, or if the originating Proxy object has gone meanwhile.
         */
        void cancel();

        /*!
         * @brief Answers whether the asynchronous call is still pending
         *
         * @return True if the call is pending, false if the call has been fully completed
         *
         * Pending call in this context means a call whose results have not arrived, or
         * have arrived and are currently being processed by the callback handler.
         */
        bool isPending() const;

    private:
        friend internal::Proxy;
        PendingAsyncCall(std::weak_ptr<void> callData);

    private:
        std::weak_ptr<void> callData_;
    };

    // Out-of-line member definitions

    template <typename _Rep, typename _Period>
    inline MethodReply IProxy::callMethod(const MethodCall& message, const std::chrono::duration<_Rep, _Period>& timeout)
    {
        auto microsecs = std::chrono::duration_cast<std::chrono::microseconds>(timeout);
        return callMethod(message, microsecs.count());
    }

    template <typename _Rep, typename _Period>
    inline PendingAsyncCall IProxy::callMethod(const MethodCall& message, async_reply_handler asyncReplyCallback, const std::chrono::duration<_Rep, _Period>& timeout)
    {
        auto microsecs = std::chrono::duration_cast<std::chrono::microseconds>(timeout);
        return callMethod(message, std::move(asyncReplyCallback), microsecs.count());
    }

    inline MethodInvoker IProxy::callMethod(const std::string& methodName)
    {
        return MethodInvoker(*this, methodName);
    }

    inline AsyncMethodInvoker IProxy::callMethodAsync(const std::string& methodName)
    {
        return AsyncMethodInvoker(*this, methodName);
    }

    inline SignalSubscriber IProxy::uponSignal(const std::string& signalName)
    {
        return SignalSubscriber(*this, signalName);
    }

    inline PropertyGetter IProxy::getProperty(const std::string& propertyName)
    {
        return PropertyGetter(*this, propertyName);
    }

    inline PropertySetter IProxy::setProperty(const std::string& propertyName)
    {
        return PropertySetter(*this, propertyName);
    }

    /*!
     * @brief Creates a proxy object for a specific remote D-Bus object
     *
     * @param[in] connection D-Bus connection to be used by the proxy object
     * @param[in] destination Bus name that provides the remote D-Bus object
     * @param[in] objectPath Path of the remote D-Bus object
     * @return Pointer to the proxy object instance
     *
     * The provided connection will be used by the proxy to issue calls against the object,
     * and signals, if any, will be subscribed to on this connection. The caller still
     * remains the owner of the connection (the proxy just keeps a reference to it), and
     * should make sure that an I/O event loop is running on that connection, so the proxy
     * may receive incoming signals and asynchronous method replies.
     *
     * Code example:
     * @code
     * auto proxy = sdbus::createProxy(connection, "com.kistler.foo", "/com/kistler/foo");
     * @endcode
     */
    [[nodiscard]] std::unique_ptr<sdbus::IProxy> createProxy( sdbus::IConnection& connection
                                                            , std::string destination
                                                            , std::string objectPath );

    /*!
     * @brief Creates a proxy object for a specific remote D-Bus object
     *
     * @param[in] connection D-Bus connection to be used by the proxy object
     * @param[in] destination Bus name that provides the remote D-Bus object
     * @param[in] objectPath Path of the remote D-Bus object
     * @return Pointer to the object proxy instance
     *
     * The provided connection will be used by the proxy to issue calls against the object,
     * and signals, if any, will be subscribed to on this connection. The Object proxy becomes
     * an exclusive owner of this connection, and will automatically start a procesing loop
     * upon that connection in a separate internal thread. Handlers for incoming signals and
     * asynchronous method replies will be executed in the context of that thread.
     *
     * Code example:
     * @code
     * auto proxy = sdbus::createProxy(std::move(connection), "com.kistler.foo", "/com/kistler/foo");
     * @endcode
     */
    [[nodiscard]] std::unique_ptr<sdbus::IProxy> createProxy( std::unique_ptr<sdbus::IConnection>&& connection
                                                            , std::string destination
                                                            , std::string objectPath );

    /*!
     * @brief Creates a proxy object for a specific remote D-Bus object
     *
     * @param[in] destination Bus name that provides the remote D-Bus object
     * @param[in] objectPath Path of the remote D-Bus object
     * @return Pointer to the object proxy instance
     *
     * No D-Bus connection is provided here, so the object proxy will create and manage
     * his own connection, and will automatically start a procesing loop upon that connection
     * in a separate internal thread. Handlers for incoming signals and asynchronous
     * method replies will be executed in the context of that thread.
     *
     * Code example:
     * @code
     * auto proxy = sdbus::createProxy("com.kistler.foo", "/com/kistler/foo");
     * @endcode
     */
    [[nodiscard]] std::unique_ptr<sdbus::IProxy> createProxy( std::string destination
                                                            , std::string objectPath );

}

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

#endif /* SDBUS_CXX_IPROXY_H_ */