2 * Copyright 2017 Samsung Electronics Co., Ltd
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
8 * http://www.apache.org/licenses/LICENSE-2.0
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
23 #include "Optional.hpp"
32 #include <type_traits>
33 #include <unordered_map>
36 #define DBUS_DEBUG( ... ) \
39 DBus::debugPrint( __FILE__, __LINE__, __VA_ARGS__ ); \
43 * @brief Template based, single file, wrapper library around eldbus for DBUS based communication.
45 * Main motivation was missing asynchronous calls in AT-SPI library and difficulties,
46 * when using eldbus from C++.
49 * - takes care of marshalling arguments to and from DBUS calls.
50 * - allows synchronous and asynchronous calls.
51 * - allows synchronous and asynchronous listeners on signals.
52 * - manages all involved objects' lifetimes.
53 * - errors are passed as optional-alike objects, no exceptions are used.
54 * - allows setting additional debug-print function for more details about
57 * DBUS's method signatures (and expected return values) are specified as template argument,
58 * using functor syntax. For example:
60 * auto dbus = DBusClient{ ... };
61 * auto v = dbus.method<std::tuple<int, float>(float, float, std::string)>("foo").call(1.0f, 2.0f, "qwe");
63 * means (synchronous) call on dbus object, which takes three arguments (thus making call signature \b dds)
64 * of types float, float and string (float will be automatically converted to double).
65 * Expected return value is std::tuple<int, float>, which gives signature <B>(id)</B> - std::tuple acts
66 * as struct container. Returned value v will be of type ValueOrError<std::tuple<int, float>>.\n
67 * Slightly different (asynchronous) example:
69 * auto dbus = DBusClient{ ... };
70 * std::function<void(ValueOrError<int, float>)> callback;
71 * dbus.method<ValueOrError<int, float>(float, float, std::string)>("foo").asyncCall(callback, 1.0f, 2.0f, "qwe");
73 * Now the call takes the same arguments and has the same signature. But expected values are different -
74 * now the signature is simply \b id. ValueOrError acts in this case as placeholder for list of values,
75 * which DBUS allows as return data. The call itself is asynchronous - instead of expecting reply
76 * you need to pass a callback, which will be called either with received data and error message.
78 * Library is not thread-safe, the same object shouldn't be called from different threads without
79 * synchronization. There's no guarantee, that callbacks will be executed on the same thread.
86 class DBusInterfaceDescription;
89 * @brief DBus action enumeration
91 * @param METHOD_CALL DBus is about to call a method on some external target
92 * @param SETTER_CALL DBus is about to call a setter method on some external target
93 * @param GETTER_CALL DBus is about to call a getter method on some external target
94 * @param SIGNAL_RECEIVED DBus just received a signal
95 * @param METHOD_RESPONSE DBus server received a method call
96 * @param SETTER_RESPONSE DBus server received a setter call
97 * @param GETTER_RESPONSE DBus server received a getter call
98 * @param SIGNAL_EMIT DBus server is about to emit a signal
100 enum class DBusActionType
113 * @brief Structure containing information about DBus activity, when calling notification callback
115 * @param type type of the action
116 * @param path path of the object, that's involved in action
117 * @param interface interface, on which member was acted upon. Note, that in case of getters and setters
118 * this will be real interface, not org.freedesktop.DBus.Properties
119 * @param member member name, that was involved (either method / setter / getter / signal)
123 const DBusActionType type;
124 const char* const bus = nullptr;
125 const char* const path = nullptr;
126 const char* const interface = nullptr;
127 const char* const member = nullptr;
129 DBusAction( const DBusActionType type,
130 const char* const bus = nullptr,
131 const char* const path = nullptr,
132 const char* const interface = nullptr,
133 const char* const member = nullptr ) : type( type ), bus( bus ), path( path ), interface( interface ), member( member ) {}
137 * @brief Formats debug message and calls debug printer (if any) with it
139 void debugPrint( const char* file, size_t line, const char* format, ... );
142 * @brief Sets debug printer callback, which will be called with debug messages
144 * Callback will be called in various moments of DBus activity. First value passed to callback
145 * is pointer to text, second it's length. Text is ended with 0 (not counted towards it's size),
146 * user can safely printf it.
148 void setDebugPrinter( std::function< void( const char*, size_t ) > );
151 * @brief Sets notification callback about processing of DBus call
153 * Notification callback can be set independently either on client or server.
154 * On client's side callback will be called, when user calls method / getter / setter
155 * or when client has received a signal.
156 * On server's side callback will be called, when sever has received a request to
157 * handle method / getter / setter or when server is going to emit a signal.
158 * Callback should returns as fast as possible.
159 * User can't call setDBusActionNotifier from inside the callback call -
160 * it will cause a deadlock
162 void setDBusActionNotifier( std::function< void( DBusAction ) > callback );
166 void emitNotification( const char* bus, const char* path, const char* interface, const char* member, DBusActionType type );
174 Error( std::string msg ) : message( std::move( msg ) )
176 assert( !message.empty() );
185 * @brief Value representing data, that came from DBUS or error message
187 * Object of this class either helds series of values (of types ARGS...)
188 * or error message. This object will be true in boolean context, if has data
189 * and false, if an error occured.
190 * It's valid to create ValueOrError object with empty argument list or void:
193 * ValueOrError<void> v2;
195 * Both mean the same - ValueOrError containing no real data and being a marker,
196 * wherever operation successed or failed and containing possible error message.
198 template < typename... ARGS >
203 * @brief Empty constructor. Valid only, if all ARGS types are default constructible.
205 ValueOrError() = default;
208 * @brief Value constructor.
210 * This will be initialized as success with passed in values.
212 ValueOrError( ARGS... t ) : value( std::move( t )... ) {}
215 * @brief Alternative Value constructor.
217 * This will be initialized as success with passed in values.
219 ValueOrError( std::tuple< ARGS... > t ) : value( std::move( t ) ) {}
222 * @brief Error constructor. This will be initialized as failure with given error message.
224 ValueOrError( Error e ) : error( std::move( e ) )
226 assert( !error.message.empty() );
230 * @brief bool operator.
232 * Returns true, if operation was successful (getValues member is callable), or false
233 * when operation failed (getError is callable).
235 explicit operator bool() const
237 return error.message.empty();
241 * @brief Returns error message object.
243 * Returns object containing error message associated with the failed operation.
244 * Only callable, if operation actually failed, otherwise will assert.
246 const Error& getError() const
252 * @brief Returns modifiable tuple of held data.
254 * Returns reference to the internal tuple containing held data.
255 * User can modify (or move) data safely.
256 * Only callable, if operation actually successed, otherwise will assert.
258 std::tuple< ARGS... >& getValues()
265 * @brief Returns const tuple of held data.
267 * Returns const reference to the internal tuple containing held data.
268 * Only callable, if operation actually successed, otherwise will assert.
270 const std::tuple< ARGS... >& getValues() const
278 std::tuple< ARGS... > value;
288 ValueOrError() = default;
289 ValueOrError( std::tuple<> t ) {}
290 ValueOrError( Error e ) : error( std::move( e ) )
292 assert( !error.message.empty() );
295 explicit operator bool() const
297 return error.message.empty();
299 const Error& getError() const
303 std::tuple<>& getValues()
306 static std::tuple<> t;
309 std::tuple<> getValues() const
320 class ValueOrError< void >
323 ValueOrError() = default;
324 ValueOrError( Success ) {}
325 ValueOrError( Error e ) : error( std::move( e ) )
327 assert( !error.message.empty() );
330 explicit operator bool() const
332 return error.message.empty();
334 const Error& getError() const
338 std::tuple<>& getValues()
341 static std::tuple<> t;
344 std::tuple<> getValues() const
359 class CallOnDestructionList
362 CallOnDestructionList() = default;
363 CallOnDestructionList( const CallOnDestructionList& ) = delete;
364 CallOnDestructionList( CallOnDestructionList&& ) = default;
366 CallOnDestructionList& operator=( const CallOnDestructionList& ) = delete;
367 CallOnDestructionList& operator=( CallOnDestructionList&& );
369 void add( const std::function< void() >& c );
372 std::vector< std::function< void() > > functions;
375 struct caller_eldbus_connection_unref
377 void operator()( Eldbus_Connection* p ) const
379 eldbus_connection_unref( p );
383 struct caller_eldbus_message_unref
385 void operator()( Eldbus_Message* p ) const
387 eldbus_message_unref( p );
391 struct caller_eldbus_proxy_unref
393 void operator()( Eldbus_Proxy* p ) const
395 eldbus_proxy_unref( p );
402 * @brief Class used to marshall DBUS's variant type
404 * Minimalistic class, that allows user to specify DBUS variant type
405 * as argument or return value. You need to pass real type hidden under variant as
406 * template type \b A. At this point library doesn't allow to expected one of few classes
407 * as return data in variant. So for example user can't specify method call, which on return
408 * expects DBUS variant holding either string or int.
410 template < typename A >
417 class EldbusConnection
419 Eldbus_Connection* ptr = nullptr;
422 EldbusConnection( Eldbus_Connection* c ) : ptr( c )
426 EldbusConnection() = delete;
427 EldbusConnection( const EldbusConnection& ) = delete;
428 EldbusConnection( EldbusConnection&& ) = delete;
431 eldbus_connection_unref( ptr );
435 Eldbus_Connection* get() const
440 //using EldbusConnectionCallbackHandle = std::shared_ptr<Eldbus_Connection>;
441 using EldbusMessageCallbackHandle = std::unique_ptr< Eldbus_Message, detail::caller_eldbus_message_unref >;
442 using EldbusObjectCallbackHandle = std::shared_ptr< Eldbus_Object >;
443 using EldbusProxyHandle = std::shared_ptr< Eldbus_Proxy >;
447 * @brief Namespace for private, internal functions and classes
453 template < typename T, typename = void >
455 template < typename... ARGS >
456 struct signature< std::tuple< ARGS... > >;
457 template < typename A, typename B >
458 struct signature< std::pair< A, B > >;
459 template < typename A >
460 struct signature< std::vector< A > >;
461 template < typename A, size_t N >
462 struct signature< std::array< A, N > >;
463 template < typename A, typename B >
464 struct signature< std::unordered_map< A, B > >;
465 template < typename A, typename B >
466 struct signature< std::map< A, B > >;
468 template < typename T >
469 struct signature< T, typename std::enable_if< std::is_enum< T >::value, void >::type >
472 * @brief Returns name of type marshalled, for informative purposes
474 static std::string name()
479 * @brief Returns DBUS' signature of type marshalled
481 static std::string sig()
483 // TODO: add check for failure in marshalling arguments
487 * @brief Marshals value v as marshalled type into message
489 static void set( Eldbus_Message_Iter* iter, T v )
491 eldbus_message_iter_arguments_append( iter, sig().c_str(), static_cast< int >( v ) );
494 * @brief Marshals value from marshalled type into variable v
496 static bool get( Eldbus_Message_Iter* iter, T& v )
499 auto z = eldbus_message_iter_get_and_next( iter, sig()[0], &q );
500 v = static_cast< T >( q );
507 * @brief Signature class for marshalling uint8 type.
510 struct signature< uint8_t >
513 * @brief Returns name of type marshalled, for informative purposes
515 static std::string name()
520 * @brief Returns DBUS' signature of type marshalled
522 static std::string sig()
527 * @brief Marshals value v as marshalled type into message
529 static void set( Eldbus_Message_Iter* iter, uint8_t v )
531 eldbus_message_iter_arguments_append( iter, sig().c_str(), v );
534 * @brief Marshals value from marshalled type into variable v
536 static bool get( Eldbus_Message_Iter* iter, uint8_t& v )
538 return eldbus_message_iter_get_and_next( iter, sig()[0], &v );
543 * @brief Signature class for marshalling uint16 type.
546 struct signature< uint16_t >
549 * @brief Returns name of type marshalled, for informative purposes
551 static std::string name()
556 * @brief Returns DBUS' signature of type marshalled
558 static std::string sig()
563 * @brief Marshals value v as marshalled type into message
565 static void set( Eldbus_Message_Iter* iter, uint16_t v )
567 eldbus_message_iter_arguments_append( iter, sig().c_str(), v );
570 * @brief Marshals value from marshalled type into variable v
572 static bool get( Eldbus_Message_Iter* iter, uint16_t& v )
574 return eldbus_message_iter_get_and_next( iter, sig()[0], &v );
579 * @brief Signature class for marshalling uint32 type.
582 struct signature< uint32_t >
585 * @brief Returns name of type marshalled, for informative purposes
587 static std::string name()
592 * @brief Returns DBUS' signature of type marshalled
594 static std::string sig()
599 * @brief Marshals value v as marshalled type into message
601 static void set( Eldbus_Message_Iter* iter, uint32_t v )
603 eldbus_message_iter_arguments_append( iter, sig().c_str(), v );
606 * @brief Marshals value from marshalled type into variable v
608 static bool get( Eldbus_Message_Iter* iter, uint32_t& v )
610 return eldbus_message_iter_get_and_next( iter, sig()[0], &v );
615 * @brief Signature class for marshalling uint64 type.
618 struct signature< uint64_t >
621 * @brief Returns name of type marshalled, for informative purposes
623 static std::string name()
628 * @brief Returns DBUS' signature of type marshalled
630 static std::string sig()
635 * @brief Marshals value v as marshalled type into message
637 static void set( Eldbus_Message_Iter* iter, uint64_t v )
639 eldbus_message_iter_arguments_append( iter, sig().c_str(), v );
642 * @brief Marshals value from marshalled type into variable v
644 static bool get( Eldbus_Message_Iter* iter, uint64_t& v )
646 return eldbus_message_iter_get_and_next( iter, sig()[0], &v );
651 * @brief Signature class for marshalling int16 type.
654 struct signature< int16_t >
657 * @brief Returns name of type marshalled, for informative purposes
659 static std::string name()
664 * @brief Returns DBUS' signature of type marshalled
666 static std::string sig()
671 * @brief Marshals value v as marshalled type into message
673 static void set( Eldbus_Message_Iter* iter, int16_t v )
675 eldbus_message_iter_arguments_append( iter, sig().c_str(), v );
678 * @brief Marshals value from marshalled type into variable v
680 static bool get( Eldbus_Message_Iter* iter, int16_t& v )
682 return eldbus_message_iter_get_and_next( iter, sig()[0], &v );
687 * @brief Signature class for marshalling int32 type.
690 struct signature< int32_t >
693 * @brief Returns name of type marshalled, for informative purposes
695 static std::string name()
700 * @brief Returns DBUS' signature of type marshalled
702 static std::string sig()
707 * @brief Marshals value v as marshalled type into message
709 static void set( Eldbus_Message_Iter* iter, int32_t v )
711 eldbus_message_iter_arguments_append( iter, sig().c_str(), v );
714 * @brief Marshals value from marshalled type into variable v
716 static bool get( Eldbus_Message_Iter* iter, int32_t& v )
718 return eldbus_message_iter_get_and_next( iter, sig()[0], &v );
723 * @brief Signature class for marshalling int64 type.
726 struct signature< int64_t >
729 * @brief Returns name of type marshalled, for informative purposes
731 static std::string name()
736 * @brief Returns DBUS' signature of type marshalled
738 static std::string sig()
743 * @brief Marshals value v as marshalled type into message
745 static void set( Eldbus_Message_Iter* iter, int64_t v )
747 eldbus_message_iter_arguments_append( iter, sig().c_str(), v );
750 * @brief Marshals value from marshalled type into variable v
752 static bool get( Eldbus_Message_Iter* iter, int64_t& v )
754 return eldbus_message_iter_get_and_next( iter, sig()[0], &v );
759 * @brief Signature class for marshalling double type.
762 struct signature< double >
765 * @brief Returns name of type marshalled, for informative purposes
767 static std::string name()
772 * @brief Returns DBUS' signature of type marshalled
774 static std::string sig()
779 * @brief Marshals value v as marshalled type into message
781 static void set( Eldbus_Message_Iter* iter, double v )
783 eldbus_message_iter_arguments_append( iter, sig().c_str(), v );
786 * @brief Marshals value from marshalled type into variable v
788 static bool get( Eldbus_Message_Iter* iter, double& v )
790 return eldbus_message_iter_get_and_next( iter, sig()[0], &v );
793 * @brief Marshals value from marshalled type into variable v
795 static bool get( Eldbus_Message_Iter* iter, float& v2 )
798 auto r = eldbus_message_iter_get_and_next( iter, sig()[0], &v );
799 v2 = static_cast< float >( v );
805 * @brief Signature class for marshalling float type.
808 struct signature< float >
811 * @brief Returns name of type marshalled, for informative purposes
813 static std::string name()
818 * @brief Returns DBUS' signature of type marshalled
820 static std::string sig()
825 * @brief Marshals value v as marshalled type into message
827 static void set( Eldbus_Message_Iter* iter, float v )
829 eldbus_message_iter_arguments_append( iter, sig().c_str(), v );
832 * @brief Marshals value from marshalled type into variable v
834 static bool get( Eldbus_Message_Iter* iter, double& v )
836 return eldbus_message_iter_get_and_next( iter, sig()[0], &v );
839 * @brief Marshals value from marshalled type into variable v
841 static bool get( Eldbus_Message_Iter* iter, float& v2 )
844 auto r = eldbus_message_iter_get_and_next( iter, sig()[0], &v );
845 v2 = static_cast< float >( v );
851 * @brief Signature class for marshalling boolean type.
854 struct signature< bool >
857 * @brief Returns name of type marshalled, for informative purposes
859 static std::string name()
864 * @brief Returns DBUS' signature of type marshalled
866 static std::string sig()
871 * @brief Marshals value v as marshalled type into message
873 static void set( Eldbus_Message_Iter* iter, bool v )
875 eldbus_message_iter_arguments_append( iter, sig().c_str(), v ? 1 : 0 );
878 * @brief Marshals value from marshalled type into variable v
880 static bool get( Eldbus_Message_Iter* iter, bool& v )
883 auto z = eldbus_message_iter_get_and_next( iter, sig()[0], &q );
890 * @brief Signature class for marshalling string type.
892 * Both (const) char * and std::string types are accepted as value to send.
893 * Only std::string is accepted as value to receive.
896 struct signature< std::string >
899 * @brief Returns name of type marshalled, for informative purposes
901 static std::string name()
906 * @brief Returns DBUS' signature of type marshalled
908 static std::string sig()
913 * @brief Marshals value v as marshalled type into message
915 static void set( Eldbus_Message_Iter* iter, const std::string& v )
917 eldbus_message_iter_arguments_append( iter, sig().c_str(), v.c_str() );
920 * @brief Marshals value v as marshalled type into message
922 static void set( Eldbus_Message_Iter* iter, const char* v )
924 eldbus_message_iter_arguments_append( iter, sig().c_str(), v );
927 * @brief Marshals value from marshalled type into variable v
929 static bool get( Eldbus_Message_Iter* iter, std::string& v )
932 if( !eldbus_message_iter_get_and_next( iter, 's', &q ) )
934 if( !eldbus_message_iter_get_and_next( iter, 'o', &q ) )
942 struct signature< ObjectPath >
945 * @brief Returns name of type marshalled, for informative purposes
947 static std::string name()
952 * @brief Returns DBUS' signature of type marshalled
954 static std::string sig()
959 * @brief Marshals value v as marshalled type into message
961 static void set( Eldbus_Message_Iter* iter, const std::string& v )
963 eldbus_message_iter_arguments_append( iter, sig().c_str(), v.c_str() );
966 * @brief Marshals value v as marshalled type into message
968 static void set( Eldbus_Message_Iter* iter, const ObjectPath& v )
970 eldbus_message_iter_arguments_append( iter, sig().c_str(), v.value.c_str() );
973 * @brief Marshals value v as marshalled type into message
975 static void set( Eldbus_Message_Iter* iter, const char* v )
977 eldbus_message_iter_arguments_append( iter, sig().c_str(), v );
980 * @brief Marshals value from marshalled type into variable v
982 static bool get( Eldbus_Message_Iter* iter, ObjectPath& v )
985 if( !eldbus_message_iter_get_and_next( iter, 'o', &q ) )
991 * @brief Marshals value from marshalled type into variable v
993 static bool get( Eldbus_Message_Iter* iter, std::string& v )
996 if( !eldbus_message_iter_get_and_next( iter, 'o', &q ) )
1004 * @brief Signature class for marshalling (const) char * type.
1006 * Both (const) char * and std::string types are accepted as value to send.
1007 * You can't use (const) char * variable type to receive value.
1010 struct signature< char* >
1013 * @brief Returns name of type marshalled, for informative purposes
1015 static std::string name()
1020 * @brief Returns DBUS' signature of type marshalled
1022 static std::string sig()
1027 * @brief Marshals value v as marshalled type into message
1029 static void set( Eldbus_Message_Iter* iter, const std::string& v )
1031 eldbus_message_iter_arguments_append( iter, sig().c_str(), v.c_str() );
1034 * @brief Marshals value v as marshalled type into message
1036 static void set( Eldbus_Message_Iter* iter, const char* v )
1038 eldbus_message_iter_arguments_append( iter, sig().c_str(), v );
1043 * @brief Signature class for marshalling (const) char[N] type.
1045 * Both (const) char[N] and std::string types are accepted as value to send.
1046 * You can't use (const) char[N] variable type to receive value.
1048 template < size_t N >
1049 struct signature< char[N] >
1052 * @brief Returns name of type marshalled, for informative purposes
1054 static std::string name()
1059 * @brief Returns DBUS' signature of type marshalled
1061 static std::string sig()
1066 * @brief Marshals value v as marshalled type into message
1068 static void set( Eldbus_Message_Iter* iter, const std::string& v )
1070 eldbus_message_iter_arguments_append( iter, sig().c_str(), v.c_str() );
1073 * @brief Marshals value v as marshalled type into message
1075 static void set( Eldbus_Message_Iter* iter, const char* v )
1077 eldbus_message_iter_arguments_append( iter, sig().c_str(), v );
1081 template < size_t INDEX, typename A, typename... ARGS >
1082 struct signature_tuple_element_type_helper
1084 using type = typename signature_tuple_element_type_helper< INDEX - 1, ARGS... >::type;
1086 template < typename A, typename... ARGS >
1087 struct signature_tuple_element_type_helper< 0, A, ARGS... >
1094 * @brief Helper class to marshall tuples
1096 * This class marshals all elements of the tuple value starting at the index INDEX
1097 * and incrementing. This class recursively calls itself with increasing INDEX value
1098 * until INDEX is equal to SIZE, where recursive calling ends.
1100 template < size_t INDEX, size_t SIZE, typename... ARGS >
1101 struct signature_tuple_helper
1103 using current_type = typename signature_tuple_element_type_helper< INDEX, ARGS... >::type;
1106 * @brief Returns name of type marshalled, for informative purposes
1108 static std::string name()
1110 if( INDEX + 1 >= SIZE )
1111 return signature< current_type >::name();
1112 return signature< current_type >::name() + ", " + signature_tuple_helper< INDEX + 1, SIZE, ARGS... >::name();
1115 * @brief Returns DBUS' signature of type marshalled
1117 static std::string sig()
1119 return signature< current_type >::sig() + signature_tuple_helper< INDEX + 1, SIZE, ARGS... >::sig();
1122 * @brief Marshals value v as marshalled type into message
1124 static void set( Eldbus_Message_Iter* iter, const std::tuple< ARGS... >& args )
1126 signature< current_type >::set( iter, std::get< INDEX >( args ) );
1127 signature_tuple_helper< INDEX + 1, SIZE, ARGS... >::set( iter, args );
1130 * @brief Marshals value from marshalled type into variable v
1132 static bool get( Eldbus_Message_Iter* iter, std::tuple< ARGS... >& args )
1134 return signature< current_type >::get( iter, std::get< INDEX >( args ) ) &&
1135 signature_tuple_helper< INDEX + 1, SIZE, ARGS... >::get( iter, args );
1140 * @brief Helper class to marshall tuples
1142 * This class marks end of the tuple marshalling. Members of this class are called
1143 * when INDEX value is equal to SIZE.
1145 template < size_t SIZE, typename... ARGS >
1146 struct signature_tuple_helper< SIZE, SIZE, ARGS... >
1149 * @brief Returns name of type marshalled, for informative purposes
1151 static std::string name()
1156 * @brief Returns DBUS' signature of type marshalled
1158 static std::string sig()
1163 * @brief Marshals value v as marshalled type into message
1165 static void set( Eldbus_Message_Iter* iter, const std::tuple< ARGS... >& args )
1169 * @brief Marshals value from marshalled type into variable v
1171 static bool get( Eldbus_Message_Iter* iter, std::tuple< ARGS... >& args )
1178 * @brief Signature class for marshalling tuple of values
1180 * This class marshalls tuple of values. This represents
1181 * DBUS struct typle, encoded with character 'r'
1183 template < typename... ARGS >
1184 struct signature< std::tuple< ARGS... > >
1187 * @brief Returns name of type marshalled, for informative purposes
1189 static std::string name()
1191 return "tuple<" + signature_tuple_helper< 0, sizeof...( ARGS ), ARGS... >::name() + ">";
1194 * @brief Returns DBUS' signature of type marshalled
1196 static std::string sig()
1198 return "(" + signature_tuple_helper< 0, sizeof...( ARGS ), ARGS... >::sig() + ")";
1201 * @brief Marshals value v as marshalled type into message
1203 static void set( Eldbus_Message_Iter* iter, const std::tuple< ARGS... >& args )
1205 auto entry = eldbus_message_iter_container_new( iter, 'r', NULL );
1206 signature_tuple_helper< 0, sizeof...( ARGS ), ARGS... >::set( entry, args );
1207 eldbus_message_iter_container_close( iter, entry );
1210 * @brief Marshals value from marshalled type into variable v
1212 static bool get( Eldbus_Message_Iter* iter, std::tuple< ARGS... >& args )
1214 Eldbus_Message_Iter* entry;
1215 if( !eldbus_message_iter_get_and_next( iter, 'r', &entry ) )
1217 auto z = signature_tuple_helper< 0, sizeof...( ARGS ), ARGS... >::get( entry, args );
1222 * @brief Signature class for marshalling ValueOrError template type
1224 * ValueOrError template type is used to marshall list of values passed to
1225 * DBUS (or received from) at the "top" level. For example ss(s) is represented as
1226 * \code{.cpp} ValueOrError<std::string, std::string, std::tuple<std::string>> \endcode
1227 * While (ss(s)) is represented as
1228 * \code{.cpp} std::tuple<std::string, std::string, std::tuple<std::string>> \endcode
1230 * \code{.cpp} ValueOrError<std::tuple<std::string, std::string, std::tuple<std::string>>> \endcode
1232 template < typename... ARGS >
1233 struct signature< ValueOrError< ARGS... > >
1236 * @brief Returns name of type marshalled, for informative purposes
1238 static std::string name()
1240 return "ValueOrError<" + signature_tuple_helper< 0, sizeof...( ARGS ), ARGS... >::name() + ">";
1243 * @brief Returns DBUS' signature of type marshalled
1245 static std::string sig()
1247 return signature_tuple_helper< 0, sizeof...( ARGS ), ARGS... >::sig();
1250 * @brief Marshals value v as marshalled type into message
1252 static void set( Eldbus_Message_Iter* iter, const ValueOrError< ARGS... >& args )
1254 signature_tuple_helper< 0, sizeof...( ARGS ), ARGS... >::set( iter, args.getValues() );
1257 * @brief Marshals value from marshalled type into variable v
1259 static bool get( Eldbus_Message_Iter* iter, ValueOrError< ARGS... >& args )
1261 return signature_tuple_helper< 0, sizeof...( ARGS ), ARGS... >::get( iter, args.getValues() );
1265 * @brief Signature class for marshalling ValueOrError<void> type
1268 struct signature< ValueOrError< void > >
1271 * @brief Returns name of type marshalled, for informative purposes
1273 static std::string name()
1275 return "ValueOrError<void>";
1278 * @brief Returns DBUS' signature of type marshalled
1280 static std::string sig()
1285 * @brief Marshals value v as marshalled type into message
1287 static void set( Eldbus_Message_Iter* iter, const ValueOrError< void >& args )
1291 * @brief Marshals value from marshalled type into variable v
1293 static bool get( Eldbus_Message_Iter* iter, ValueOrError< void >& args )
1299 * @brief Signature class for marshalling ValueOrError<> type
1302 struct signature< ValueOrError<> >
1305 * @brief Returns name of type marshalled, for informative purposes
1307 static std::string name()
1309 return "ValueOrError<>";
1312 * @brief Returns DBUS' signature of type marshalled
1314 static std::string sig()
1319 * @brief Marshals value v as marshalled type into message
1321 static void set( Eldbus_Message_Iter* iter, const ValueOrError<>& args )
1325 * @brief Marshals value from marshalled type into variable v
1327 static bool get( Eldbus_Message_Iter* iter, ValueOrError<>& args )
1333 * @brief Signature class for marshalling pair of types
1335 template < typename A, typename B >
1336 struct signature< std::pair< A, B > >
1339 * @brief Returns name of type marshalled, for informative purposes
1341 static std::string name()
1343 return "pair<" + signature_tuple_helper< 0, 2, A, B >::name() + ">";
1346 * @brief Returns DBUS' signature of type marshalled
1348 static std::string sig()
1350 return "(" + signature_tuple_helper< 0, 2, A, B >::sig() + ")";
1353 * @brief Marshals value v as marshalled type into message
1355 static void set( Eldbus_Message_Iter* iter, const std::pair< A, B >& ab, bool dictionary = false )
1357 auto entry = eldbus_message_iter_container_new( iter, dictionary ? 'e' : 'r', NULL );
1358 signature_tuple_helper< 0, 2, A, B >::set( entry, ab );
1359 eldbus_message_iter_container_close( iter, entry );
1362 * @brief Marshals value from marshalled type into variable v
1364 static bool get( Eldbus_Message_Iter* iter, std::pair< A, B >& ab )
1367 char* t = eldbus_message_iter_signature_get( iter );
1368 if( t && t[0] == '{' )
1372 Eldbus_Message_Iter* entry;
1373 if( !eldbus_message_iter_get_and_next( iter, sg, &entry ) )
1375 std::tuple< A, B > ab_tmp;
1376 auto z = signature_tuple_helper< 0, 2, A, B >::get( entry, ab_tmp );
1379 ab.first = std::move( std::get< 0 >( ab_tmp ) );
1380 ab.second = std::move( std::get< 1 >( ab_tmp ) );
1386 * @brief Signature class for marshalling std::vector template type
1388 * This marshals container's content as DBUS a ascii character type code.
1390 template < typename A >
1391 struct signature< std::vector< A > >
1394 * @brief Returns name of type marshalled, for informative purposes
1396 static std::string name()
1398 return "vector<" + signature< A >::name() + ">";
1401 * @brief Returns DBUS' signature of type marshalled
1403 static std::string sig()
1405 return "a" + signature< A >::sig();
1408 * @brief Marshals value v as marshalled type into message
1410 static void set( Eldbus_Message_Iter* iter, const std::vector< A >& v )
1412 auto lst = eldbus_message_iter_container_new( iter, 'a', signature< A >::sig().c_str() );
1416 signature< A >::set( lst, a );
1418 eldbus_message_iter_container_close( iter, lst );
1421 * @brief Marshals value from marshalled type into variable v
1423 static bool get( Eldbus_Message_Iter* iter, std::vector< A >& v )
1425 Eldbus_Message_Iter* s;
1427 if( !eldbus_message_iter_get_and_next( iter, 'a', &s ) )
1430 while( signature< A >::get( s, a ) )
1431 v.push_back( std::move( a ) );
1438 * @brief Signature class for marshalling std::array template type
1440 * This marshals container's content as DBUS a ascii character type code.
1442 template < typename A, size_t N >
1443 struct signature< std::array< A, N > >
1446 * @brief Returns name of type marshalled, for informative purposes
1448 static std::string name()
1450 return "array<" + signature< A >::name() + ", " + std::to_string( N ) + ">";
1453 * @brief Returns DBUS' signature of type marshalled
1455 static std::string sig()
1457 return "a" + signature< A >::sig();
1460 * @brief Marshals value v as marshalled type into message
1462 static void set( Eldbus_Message_Iter* iter, const std::array< A, N >& v )
1464 auto lst = eldbus_message_iter_container_new( iter, 'a', signature< A >::sig().c_str() );
1468 signature< A >::set( lst, a );
1470 eldbus_message_iter_container_close( iter, lst );
1473 * @brief Marshals value from marshalled type into variable v
1475 static bool get( Eldbus_Message_Iter* iter, std::array< A, N >& v )
1477 Eldbus_Message_Iter* s;
1478 if( !eldbus_message_iter_get_and_next( iter, 'a', &s ) )
1482 if( !signature< A >::get( s, a ) )
1490 * @brief Signature class for marshalling EldbusVariant type
1492 * This marshals variant's content as DBUS v ascii character type code.
1494 template < typename A >
1495 struct signature< EldbusVariant< A > >
1498 * @brief Returns name of type marshalled, for informative purposes
1500 static std::string name()
1502 return "variant<" + signature< A >::name() + ">";
1505 * @brief Returns DBUS' signature of type marshalled
1507 static std::string sig()
1512 * @brief Marshals value v as marshalled type into message
1514 static void set( Eldbus_Message_Iter* iter, const EldbusVariant< A >& v )
1516 set( iter, v.value );
1519 * @brief Marshals value v as marshalled type into message
1521 static void set( Eldbus_Message_Iter* iter, const A& v )
1523 auto var = eldbus_message_iter_container_new( iter, 'v', signature< A >::sig().c_str() );
1524 signature< A >::set( var, v );
1525 eldbus_message_iter_container_close( iter, var );
1528 * @brief Marshals value from marshalled type into variable v
1530 static bool get( Eldbus_Message_Iter* iter, EldbusVariant< A >& v )
1532 Eldbus_Message_Iter* s;
1533 if( !eldbus_message_iter_get_and_next( iter, 'v', &s ) )
1535 return signature< A >::get( s, v.value );
1539 * @brief Signature class for marshalling std::unordered_map template type
1541 * This marshals container's content as DBUS {} ascii character type code.
1542 * Note, that library doesnt check, if the key is basic type, as DBUS
1543 * specification mandates.
1544 * User can always exchange std::unordered_map for std::map and the reverse.
1545 * User can receive such values as std::vector of std::pair<key, value> values.
1546 * Order of such values is unspecified.
1548 template < typename A, typename B >
1549 struct signature< std::unordered_map< A, B > >
1552 * @brief Returns name of type marshalled, for informative purposes
1554 static std::string name()
1556 return "unordered_map<" + signature< A >::name() + ", " + signature< B >::name() + ">";
1559 * @brief Returns DBUS' signature of type marshalled
1561 static std::string sig()
1563 return "a{" + signature_tuple_helper< 0, 2, A, B >::sig() + "}";
1566 * @brief Marshals value v as marshalled type into message
1568 static void set( Eldbus_Message_Iter* iter, const std::unordered_map< A, B >& v )
1570 auto sig = "{" + signature_tuple_helper< 0, 2, A, B >::sig() + "}";
1571 auto lst = eldbus_message_iter_container_new( iter, 'a', sig.c_str() );
1575 signature< std::pair< A, B > >::set( lst, a, true );
1577 eldbus_message_iter_container_close( iter, lst );
1580 * @brief Marshals value from marshalled type into variable v
1582 static bool get( Eldbus_Message_Iter* iter, std::unordered_map< A, B >& v )
1584 Eldbus_Message_Iter* s;
1586 if( !eldbus_message_iter_get_and_next( iter, 'a', &s ) )
1588 std::pair< A, B > a;
1589 while( signature< std::pair< A, B > >::get( s, a ) )
1590 v.insert( std::move( a ) );
1595 * @brief Signature class for marshalling std::unordered_map template type
1597 * This marshals container's content as DBUS {} ascii character type code.
1598 * Note, that library doesnt check, if the key is basic type, as DBUS
1599 * specification mandates.
1600 * User can always exchange std::unordered_map for std::map and the reverse.
1601 * User can receive such values as std::vector of std::pair<key, value> values.
1602 * Order of such values is unspecified.
1604 template < typename A, typename B >
1605 struct signature< std::map< A, B > >
1608 * @brief Returns name of type marshalled, for informative purposes
1610 static std::string name()
1612 return "map<" + signature< A >::name() + ", " + signature< B >::name() + ">";
1615 * @brief Returns DBUS' signature of type marshalled
1617 static std::string sig()
1619 return "a{" + signature_tuple_helper< 0, 2, A, B >::sig() + "}";
1622 * @brief Marshals value v as marshalled type into message
1624 static void set( Eldbus_Message_Iter* iter, const std::map< A, B >& v )
1626 auto sig = "{" + signature_tuple_helper< 0, 2, A, B >::sig() + "}";
1627 auto lst = eldbus_message_iter_container_new( iter, 'a', sig.c_str() );
1631 signature< std::pair< A, B > >::set( lst, a, true );
1633 eldbus_message_iter_container_close( iter, lst );
1636 * @brief Marshals value from marshalled type into variable v
1638 static bool get( Eldbus_Message_Iter* iter, std::map< A, B >& v )
1640 Eldbus_Message_Iter* s;
1641 if( !eldbus_message_iter_get_and_next( iter, 'a', &s ) )
1643 std::pair< A, B > a;
1644 while( signature< std::pair< A, B > >::get( s, a ) )
1645 v.insert( std::move( a ) );
1650 * @brief Signature helper class for marshalling const reference types
1652 template < typename A >
1653 struct signature< const A& >
1656 * @brief Returns name of type marshalled, for informative purposes
1658 static std::string name()
1660 return "const " + signature< A >::name() + "&";
1663 * @brief Returns DBUS' signature of type marshalled
1665 static std::string sig()
1667 return signature< A >::sig();
1670 * @brief Marshals value v as marshalled type into message
1672 static void set( Eldbus_Message_Iter* iter, const A& v )
1674 signature< A >::set( iter, v );
1677 * @brief Marshals value from marshalled type into variable v
1679 static void get( Eldbus_Message_Iter* iter, A& v )
1681 signature< A >::get( iter, v );
1685 * @brief Signature helper class for marshalling reference types
1687 template < typename A >
1688 struct signature< A& >
1691 * @brief Returns name of type marshalled, for informative purposes
1693 static std::string name()
1695 return signature< A >::name() + "&";
1698 * @brief Returns DBUS' signature of type marshalled
1700 static std::string sig()
1702 return signature< A >::sig();
1705 * @brief Marshals value v as marshalled type into message
1707 static void set( Eldbus_Message_Iter* iter, const A& v )
1709 signature< A >::set( iter, v );
1712 * @brief Marshals value from marshalled type into variable v
1714 static void get( Eldbus_Message_Iter* iter, A& v )
1716 signature< A >::get( iter, v );
1720 * @brief Signature helper class for marshalling const types
1722 template < typename A >
1723 struct signature< const A >
1726 * @brief Returns name of type marshalled, for informative purposes
1728 static std::string name()
1730 return "const " + signature< A >::name();
1733 * @brief Returns DBUS' signature of type marshalled
1735 static std::string sig()
1737 return signature< A >::sig();
1740 * @brief Marshals value v as marshalled type into message
1742 static void set( Eldbus_Message_Iter* iter, const A& v )
1744 signature< A >::set( iter, v );
1747 * @brief Marshals value from marshalled type into variable v
1749 static void get( Eldbus_Message_Iter* iter, A& v )
1751 signature< A >::get( iter, v );
1755 // * @brief Signature helper class for marshalling AT-SPI Accessible pointer values
1757 // * In AT-SPI specification those values are mandated to be marshalled as struct (so)
1758 // * where o is object (exactly as string, but with different ascii
1759 // * character code.
1761 // template <> struct signature<std::shared_ptr<AtspiAccessible>> {
1762 // using subtype = std::pair<std::string, std::string>;
1765 // * @brief Returns name of type marshalled, for informative purposes
1767 // static std::string name()
1769 // return "AtspiAccessiblePtr";
1772 // * @brief Returns DBUS' signature of type marshalled
1774 // static std::string sig()
1779 // * @brief Marshals value v as marshalled type into message
1781 // static void set(Eldbus_Message_Iter *iter, const std::shared_ptr<AtspiAccessible> &v)
1783 // const auto prefixPath = "/org/a11y/atspi/accessible/";
1784 // const auto nullPath = "/org/a11y/atspi/null";
1787 // auto bus = atspi_accessible_get_bus_name(v.get(), NULL);
1788 // auto path = atspi_accessible_get_path(v.get(), NULL);
1789 // signature<subtype>::set(iter, { bus, std::string{prefixPath} + path });
1793 // signature<subtype>::set(iter, { {}, std::string{nullPath} });
1797 // * @brief Marshals value from marshalled type into variable v
1799 // static bool get(Eldbus_Message_Iter *iter, std::shared_ptr<AtspiAccessible> &v);
1804 friend class ::DBus::DBusServer;
1805 friend class ::DBus::DBusClient;
1806 friend class ::DBus::DBusInterfaceDescription;
1807 static std::atomic< unsigned int > LastId;
1808 unsigned int id = ++LastId;
1810 template < typename ValueType >
1811 ValueType unpackValues( CallId callId, const Eldbus_Message* msg )
1813 auto iter = eldbus_message_iter_get( msg );
1818 if( !signature< ValueType >::get( iter, r ) )
1820 DBUS_DEBUG( "ValueType is %s", signature< ValueType >::name().c_str() );
1821 r = Error{"call " + std::to_string( callId.id ) + ": failed to unpack values, got signature '" +
1822 eldbus_message_signature_get( msg ) + "', expected '" + signature< ValueType >::sig() + "'"};
1827 r = Error{"call " + std::to_string( callId.id ) + ": failed to get iterator"};
1831 inline void packValues_helper( Eldbus_Message_Iter* iter ) {}
1832 template < typename A, typename... ARGS >
1833 void packValues_helper( Eldbus_Message_Iter* iter, A&& a, ARGS&&... r )
1835 signature< A >::set( iter, std::forward< A >( a ) );
1836 packValues_helper( iter, std::forward< ARGS >( r )... );
1838 template < typename... ARGS >
1839 void packValues( CallId callId, Eldbus_Message* msg, ARGS&&... r )
1841 auto iter = eldbus_message_iter_get( msg );
1842 packValues_helper( iter, std::forward< ARGS >( r )... );
1845 template < typename >
1847 template < typename R, typename... ARGS >
1848 struct ReturnType< R( ARGS... ) >
1852 template < typename R, typename... ARGS >
1853 struct ReturnType< std::function< R( ARGS... ) > >
1861 template < int N, int... S >
1862 struct sequence_gen : sequence_gen< N - 1, N - 1, S... >
1865 template < int... S >
1866 struct sequence_gen< 0, S... >
1868 typedef sequence< S... > type;
1870 template < typename C, typename... ARGS >
1873 const std::function< C >& c;
1874 const std::tuple< ARGS... >& args;
1876 template < int... S >
1877 auto apply_2( sequence< S... > ) const -> decltype( c( std::get< S >( args )... ) )
1879 return c( std::get< S >( args )... );
1881 auto apply_1() const -> decltype( apply_2( typename sequence_gen< sizeof...( ARGS ) >::type() ) )
1883 return apply_2( typename sequence_gen< sizeof...( ARGS ) >::type() );
1886 template < typename C, typename A, typename... ARGS >
1887 struct apply_helper_2
1889 const std::function< C >& c;
1891 const std::tuple< ARGS... >& args;
1893 template < int... S >
1894 auto apply_2( sequence< S... > ) const -> decltype( c( a, std::get< S >( args )... ) )
1896 return c( a, std::get< S >( args )... );
1898 auto apply_1() const -> decltype( apply_2( typename sequence_gen< sizeof...( ARGS ) >::type() ) )
1900 return apply_2( typename sequence_gen< sizeof...( ARGS ) >::type() );
1903 template < typename C, typename... ARGS >
1904 auto apply( const std::function< C >& c, const std::tuple< ARGS... >& args ) -> typename ReturnType< C >::type
1906 apply_helper< C, ARGS... > ah{c, args};
1907 return ah.apply_1();
1909 template < typename C, typename D, typename... ARGS >
1910 auto apply( const std::function< C >& c, const D& d, const std::tuple< ARGS... >& args ) -> typename ReturnType< C >::type
1912 apply_helper_2< C, D, ARGS... > ah{c, d, args};
1913 return ah.apply_1();
1916 struct EldbusProxyBase
1928 constexpr static int ELDBUS_CALL_TIMEOUT = 1000;
1930 struct ConnectionState
1932 std::shared_ptr< DBus::EldbusConnection > connection;
1933 EldbusObjectCallbackHandle object;
1934 EldbusProxyHandle proxy;
1935 EldbusProxyHandle propertiesProxy;
1937 using CallAsyncDataType = std::tuple< CallId, std::function< void( const Eldbus_Message* ) > >;
1939 static void callAsyncCb( void* data, const Eldbus_Message* msg, Eldbus_Pending* pending )
1941 auto d = static_cast< CallAsyncDataType* >( data );
1942 DBUS_DEBUG( "call %d: got reply", std::get< 0 >( *d ).id );
1943 std::get< 1 > ( *d )( msg );
1945 static void pendingFreeCb( void* data, const void* )
1947 auto d = static_cast< CallAsyncDataType* >( data );
1948 DBUS_DEBUG( "call %d: deleting", std::get< 0 >( *d ).id );
1951 template < typename RETTYPE, typename... ARGS >
1952 RETTYPE call( CallId callId, ConnectionState& connectionState, bool property, const std::string& funcName, const ARGS&... args )
1954 auto proxy = property ? connectionState.propertiesProxy : connectionState.proxy;
1957 DBUS_DEBUG( "call %d: not initialized", callId.id );
1958 return Error{"not initialized"};
1961 DBUS_DEBUG( "call %d: calling '%s'", callId.id, funcName.c_str() );
1962 EldbusMessageCallbackHandle msg{eldbus_proxy_method_call_new( proxy.get(), funcName.c_str() )};
1965 DBUS_DEBUG( "call %d: failed", callId.id );
1966 return Error{"failed to create message"};
1969 detail::packValues( callId, msg.get(), args... );
1970 auto replyRawPtr = eldbus_proxy_send_and_block( proxy.get(), msg.release(), ELDBUS_CALL_TIMEOUT );
1971 EldbusMessageCallbackHandle reply{replyRawPtr};
1972 DBUS_DEBUG( "call %d: calling '%s' done", callId.id, funcName.c_str() );
1975 DBUS_DEBUG( "call %d: failed", callId.id );
1976 return Error{"eldbus returned null as reply"};
1978 const char *errname, *errmsg;
1979 if( eldbus_message_error_get( reply.get(), &errname, &errmsg ) )
1981 DBUS_DEBUG( "call %d: %s: %s", callId.id, errname, errmsg );
1982 return Error{std::string( errname ) + ": " + errmsg};
1984 DBUS_DEBUG( "call %d: got reply with signature '%s'", callId.id, eldbus_message_signature_get( reply.get() ) );
1985 return detail::unpackValues< RETTYPE >( callId, reply.get() );
1988 template < typename RETTYPE, typename... ARGS >
1989 void asyncCall( CallId callId, ConnectionState connectionState,
1990 bool property, const std::string& funcName,
1991 std::function< void( RETTYPE ) > callback, const ARGS&... args )
1993 auto proxy = property ? connectionState.propertiesProxy : connectionState.proxy;
1996 DBUS_DEBUG( "call %d: not initialized", callId.id );
1997 callback( Error{"not initialized"} );
2001 EldbusMessageCallbackHandle msg{eldbus_proxy_method_call_new( proxy.get(), funcName.c_str() )};
2004 DBUS_DEBUG( "call %d: failed", callId.id );
2005 callback( Error{"failed to create message"} );
2009 auto cbData = new CallAsyncDataType{callId, [callback, callId, proxy]( const Eldbus_Message* reply ) {
2010 DBUS_DEBUG( "call %d: calling done", callId.id );
2013 DBUS_DEBUG( "call %d: failed", callId.id );
2014 callback( Error{"eldbus returned null as reply"} );
2018 const char *errname, *errmsg;
2019 if( eldbus_message_error_get( reply, &errname, &errmsg ) )
2021 DBUS_DEBUG( "call %d: %s: %s", callId.id, errname, errmsg );
2022 callback( Error{std::string( errname ) + ": " + errmsg} );
2026 DBUS_DEBUG( "call %d: got reply with signature '%s'", callId.id, eldbus_message_signature_get( reply ) );
2027 callback( detail::unpackValues< RETTYPE >( callId, reply ) );
2031 detail::packValues( callId, msg.get(), args... );
2032 auto pending = eldbus_proxy_send( proxy.get(), msg.release(), callAsyncCb, cbData, ELDBUS_CALL_TIMEOUT );
2035 eldbus_pending_free_cb_add( pending, pendingFreeCb, cbData );
2036 DBUS_DEBUG( "call %d: call sent", callId.id );
2040 DBUS_DEBUG( "call %d: failed to send call", callId.id );
2041 callback( Error{"failed to send call"} );
2044 inline void displayDebugCallInfo( CallId callId, const std::string& funcName, const std::string& info, const std::string& interfaceName )
2046 DBUS_DEBUG( "call %d: %s iname = %s fname = %s", callId.id, info.c_str(), interfaceName.c_str(), funcName.c_str() );
2048 inline void displayDebugCallInfoSignal( CallId callId, const std::string& funcName, const std::string& info, const std::string& interfaceName )
2050 DBUS_DEBUG( "call %d: %s signal iname = %s fname = %s", callId.id, info.c_str(), interfaceName.c_str(), funcName.c_str() );
2052 inline void displayDebugCallInfoProperty( CallId callId, const std::string& funcName, std::string info, const std::string& interfaceName,
2053 const std::string& propertyName )
2055 DBUS_DEBUG( "call %d: %s iname = %s pname = %s", callId.id, info.c_str(), interfaceName.c_str(), propertyName.c_str() );
2060 struct char_ptr_deleter
2062 void operator()( char* p )
2067 std::vector< std::unique_ptr< char, char_ptr_deleter > > storage;
2070 const char* add( const char* txt )
2072 auto ptr = strdup( txt );
2073 storage.push_back( std::unique_ptr< char, char_ptr_deleter >( ptr ) );
2074 return storage.back().get();
2076 const char* add( const std::string& txt )
2078 return add( txt.c_str() );
2081 template < typename A, typename... ARGS >
2082 struct EldbusArgGenerator_Helper
2084 static void add( std::vector< Eldbus_Arg_Info >& r, StringStorage& strings )
2087 auto sig = signature< A >::sig();
2088 assert( !sig.empty() );
2089 auto name = "p" + std::to_string( s + 1 );
2090 r.push_back( Eldbus_Arg_Info{strings.add( sig ), strings.add( name )} );
2091 EldbusArgGenerator_Helper< ARGS... >::add( r, strings );
2095 struct EldbusArgGenerator_Helper< void >
2097 static void add( std::vector< Eldbus_Arg_Info >&, StringStorage& )
2102 struct EldbusArgGenerator_Helper< ValueOrError< void >, void >
2104 static void add( std::vector< Eldbus_Arg_Info >&, StringStorage& )
2109 struct EldbusArgGenerator_Helper< ValueOrError<>, void >
2111 static void add( std::vector< Eldbus_Arg_Info >&, StringStorage& )
2115 template < typename... ARGS >
2116 struct EldbusArgGenerator_Helper< std::tuple< ARGS... > >
2118 static void add( std::vector< Eldbus_Arg_Info >& r, StringStorage& strings )
2120 EldbusArgGenerator_Helper< ARGS..., void >::add( r, strings );
2123 template < typename RetType >
2124 struct dbus_interface_return_type_traits
2126 using type = ValueOrError< RetType >;
2128 template < typename... ARGS >
2129 struct dbus_interface_return_type_traits< ValueOrError< ARGS... > >
2131 using type = ValueOrError< ARGS... >;
2133 template < typename T >
2134 struct dbus_interface_traits;
2135 template < typename RetType, typename... ARGS >
2136 struct dbus_interface_traits< RetType( ARGS... ) >
2138 using Ret = typename dbus_interface_return_type_traits< RetType >::type;
2139 using SyncCB = std::function< Ret( ARGS... ) >;
2140 using AsyncCB = std::function< void( std::function< void( Ret ) >, ARGS... ) >;
2141 using VEArgs = ValueOrError< ARGS... >;
2143 template < typename T >
2144 struct EldbusArgGenerator_Args;
2145 template < typename RetType, typename... ARGS >
2146 struct EldbusArgGenerator_Args< RetType( ARGS... ) >
2148 static std::string name()
2150 return signature_tuple_helper< 0, sizeof...( ARGS ), ARGS... >::name();
2152 static std::vector< Eldbus_Arg_Info > get( StringStorage& strings )
2154 std::vector< Eldbus_Arg_Info > tmp;
2155 EldbusArgGenerator_Helper< ARGS..., void >::add( tmp, strings );
2156 tmp.push_back( {nullptr, nullptr} );
2160 template < typename T >
2161 struct EldbusArgGenerator_ReturnType;
2162 template < typename RetType, typename... ARGS >
2163 struct EldbusArgGenerator_ReturnType< RetType( ARGS... ) >
2165 static std::string name()
2167 return signature< RetType >::name();
2169 static std::vector< Eldbus_Arg_Info > get( StringStorage& strings )
2171 std::vector< Eldbus_Arg_Info > tmp;
2172 EldbusArgGenerator_Helper< RetType, void >::add( tmp, strings );
2173 tmp.push_back( {nullptr, nullptr} );
2177 template < typename T >
2178 struct EldbusArgGenerator_ReturnType;
2179 template < typename... ARGS >
2180 struct EldbusArgGenerator_ReturnType< void( ARGS... ) >
2182 static std::string name()
2186 static std::vector< Eldbus_Arg_Info > get( StringStorage& strings )
2188 std::vector< Eldbus_Arg_Info > tmp;
2189 tmp.push_back( {nullptr, nullptr} );
2197 * @brief Enumeration determining, which DBUS session user wants to connect to.
2199 enum class ConnectionType
2206 * @brief Class representing client's end of DBUS connection
2208 * Allows calling (synchronous and asynchronos) methods on selected interface
2209 * Allows (synchronous and asynchronos) setting / getting properties.
2210 * Allows registering signals.
2212 class DBusClient : private detail::EldbusProxyBase
2215 struct ConnectionInfo
2217 std::string interfaceName, busName, pathName;
2218 void emit( const char* member, DBusActionType type )
2220 detail::emitNotification( busName.c_str(), pathName.c_str(), interfaceName.c_str(), member, type );
2226 * @brief Default constructor, creates non-connected object.
2228 DBusClient() = default;
2230 * @brief Connects to dbus choosen by tp, using given arguments
2232 * @param bus_name name of the bus to connect to
2233 * @param path_name object's path
2234 * @param interface_name interface name
2236 DBusClient( std::string busName_, std::string pathName_, std::string interfaceName_,
2237 ConnectionType tp );
2239 * @brief Connects to dbus using connection conn
2241 * @param bus_name name of the bus to connect to
2242 * @param path_name object's path
2243 * @param interface_name interface name
2244 * @param conn connection object from getDBusConnectionByType call
2246 DBusClient( std::string busName_, std::string pathName_, std::string interfaceName_,
2247 const std::shared_ptr< DBus::EldbusConnection >& conn = {} );
2249 * @brief Destructor object.
2251 * All signals added will be disconnected.
2252 * All asynchronous calls will be cancelled, their callback's will be called
2253 * with failure message.
2255 ~DBusClient() = default;
2256 DBusClient( const DBusClient& ) = delete;
2257 DBusClient( DBusClient&& ) = default;
2259 DBusClient& operator=( DBusClient&& ) = default;
2260 DBusClient& operator=( const DBusClient& ) = delete;
2263 * @brief bool operator
2265 * Returns true, if object is connected to DBUS
2267 explicit operator bool() const
2269 return bool( connectionState.proxy );
2273 * @brief Helper class for calling a method
2275 * Template type T defines both arguments sent to the method
2276 * and expected values. Receiving different values will be reported as
2277 * error. For example:
2278 * \code{.cpp} Method<int(float, float)> \endcode
2279 * defines method, which takes two arguments (two floats) and return
2280 * single value of type int.
2282 template < typename T >
2286 using RetType = typename detail::dbus_interface_traits< T >::Ret;
2287 detail::ConnectionState connectionState;
2288 std::string funcName;
2290 std::shared_ptr< ConnectionInfo > connectionInfo;
2294 * @brief Executes synchronous call on DBUS's method
2296 * The function returns ValueOrError<...> object, which
2297 * contains either received values or error message.
2299 * @param args arguments to pass to the method
2301 template < typename... ARGS >
2302 RetType call( const ARGS&... args )
2304 detail::CallId callId;
2305 detail::displayDebugCallInfo( callId, funcName, info, connectionInfo->interfaceName );
2306 return detail::call< RetType >( callId, connectionState, false, funcName, args... );
2310 * @brief Executes asynchronous call on DBUS's method
2312 * The function calls callback with either received values or error message.
2314 * @param callback callback functor, which will be called with return value(s) or error message
2315 * @param args arguments to pass to the method
2317 template < typename... ARGS >
2318 void asyncCall( std::function< void( RetType ) > callback, const ARGS&... args )
2320 detail::CallId callId;
2321 detail::displayDebugCallInfo( callId, funcName, info, connectionInfo->interfaceName );
2322 auto connectionState = this->connectionState;
2323 detail::asyncCall< RetType >( callId, connectionState, false, funcName, std::move( callback ), args... );
2328 * @brief Helper class for calling a property
2330 * Template type T defines type of the value hidden under property.
2331 * Note, that library automatically wraps both sent and received value into
2332 * DBUS's wrapper type.
2334 template < typename T >
2338 using RetType = typename detail::dbus_interface_return_type_traits< T >::type;
2339 using VariantRetType = typename detail::dbus_interface_return_type_traits< EldbusVariant< T > >::type;
2340 detail::ConnectionState connectionState;
2341 std::string propName;
2343 std::shared_ptr< ConnectionInfo > connectionInfo;
2347 * @brief executes synchronous get on property
2349 * The function returns ValueOrError<...> object, which
2350 * contains either received values or error message.
2354 connectionInfo->emit( propName.c_str(), DBusActionType::GETTER_CALL );
2355 detail::CallId callId;
2356 detail::displayDebugCallInfoProperty( callId, "Get", info, connectionInfo->interfaceName, propName );
2357 auto z = detail::call< VariantRetType >( callId, connectionState, true, "Get", connectionInfo->interfaceName, propName );
2359 return z.getError();
2360 return {std::get< 0 >( z.getValues() ).value};
2364 * @brief executes asynchronous get on property
2366 * The function calls callback with either received values or error message.
2368 * @param callback callback functor, which will be called with return value(s) or error message
2370 void asyncGet( std::function< void( RetType ) > callback )
2372 connectionInfo->emit( propName.c_str(), DBusActionType::GETTER_CALL );
2373 detail::CallId callId;
2374 detail::displayDebugCallInfoProperty( callId, "Get", info, connectionInfo->interfaceName, propName );
2375 auto connectionState = this->connectionState;
2376 auto cc = [callback]( VariantRetType reply ) {
2378 callback( std::move( std::get< 0 >( reply.getValues() ).value ) );
2380 callback( reply.getError() );
2382 detail::asyncCall< VariantRetType >( callId, connectionState, true, "Get", std::move( cc ), connectionInfo->interfaceName, propName );
2386 * @brief executes synchronous set on property
2388 * The function returns ValueOrError<void> object, with
2389 * possible error message.
2391 ValueOrError< void > set( const T& r )
2393 connectionInfo->emit( propName.c_str(), DBusActionType::SETTER_CALL );
2394 detail::CallId callId;
2395 detail::displayDebugCallInfoProperty( callId, "Set", info, connectionInfo->interfaceName, propName );
2396 EldbusVariant< T > variantValue{std::move( r )};
2397 return detail::call< ValueOrError< void > >( callId, connectionState, true, "Set", connectionInfo->interfaceName, propName, variantValue );
2401 * @brief executes asynchronous get on property
2403 * The function calls callback with either received values or error message.
2405 * @param callback callback functor, which will be called with return value(s) or error message
2407 void asyncSet( std::function< void( ValueOrError< void > ) > callback, const T& r )
2409 connectionInfo->emit( propName.c_str(), DBusActionType::SETTER_CALL );
2410 detail::CallId callId;
2411 detail::displayDebugCallInfoProperty( callId, "Set", info, connectionInfo->interfaceName, propName );
2412 EldbusVariant< T > variantValue{std::move( r )};
2413 detail::asyncCall< ValueOrError< void > >( callId, connectionState, true, "Set", std::move( callback ), connectionInfo->interfaceName, propName, variantValue );
2418 * @brief Constructs Property<...> object for calling properties
2420 * The function constructs and returns proxy object for calling property.
2422 * @param propName property name to set and / or query
2424 template < typename PropertyType >
2425 Property< PropertyType > property( std::string propName )
2427 return Property< PropertyType >{connectionState, std::move( propName ), info, connectionInfo};
2431 * @brief Constructs Method<...> object for calling methods
2433 * The function constructs and returns proxy object for calling method.
2435 * @param funcName function name to call
2437 template < typename MethodType >
2438 Method< MethodType > method( std::string funcName )
2440 return Method< MethodType >{connectionState, std::move( funcName ), info, connectionInfo};
2444 * @brief Registers notification callback, when property has changed
2446 * The callback will be called with new value, when property's value has changed.
2447 * Note, that template type V must match expected type, otherwise undefined behavior will occur,
2448 * there's no check for this.
2450 template < typename V >
2451 void addPropertyChangedEvent( std::string propertyName, std::function< void( V ) > callback )
2453 detail::CallId callId;
2454 detail::displayDebugCallInfoSignal( callId, propertyName, info, connectionInfo->interfaceName );
2455 DBUS_DEBUG( "call %d: adding property", callId.id );
2456 auto cS = this->connectionState;
2457 auto cI = this->connectionInfo;
2458 auto callbackLambdaPtr = new std::function< void( Eldbus_Proxy_Event_Property_Changed* ) >;
2459 *callbackLambdaPtr = [callId, cS, callback, propertyName, cI]( Eldbus_Proxy_Event_Property_Changed* ev ) {
2460 const char* ifc = eldbus_proxy_interface_get( ev->proxy );
2461 DBUS_DEBUG( "call %d: property changed iname = %s pname = %s (name %s iface %s)",
2462 callId.id, cI->interfaceName.c_str(), propertyName.c_str(), ev->name, ifc );
2464 if( ev->name && ev->name == propertyName && ifc && cI->interfaceName == ifc )
2466 if( !eina_value_get( ev->value, &val ) )
2468 DBUS_DEBUG( "unable to get property's value" );
2471 DBUS_DEBUG( ". %d", val );
2477 auto p = connectionState.proxy.get();
2478 eldbus_proxy_event_callback_add( p, ELDBUS_PROXY_EVENT_PROPERTY_CHANGED,
2479 listenerEventChangedCallback, callbackLambdaPtr );
2480 destructors.add( [=]() {
2481 eldbus_proxy_event_callback_del( p, ELDBUS_PROXY_EVENT_PROPERTY_CHANGED,
2482 listenerEventChangedCallback, callbackLambdaPtr );
2483 delete callbackLambdaPtr;
2487 * @brief Registers callback on the DBUS' signal
2489 * The function registers callback signalName. When signal comes, callback will be called.
2490 * Callback object will exists as long as signal is registered. You can unregister signal
2491 * by destroying DBusClient object.
2493 * @param signalName name of the signal to register
2494 * @param callback callback to call
2496 template < typename SignalType >
2497 void addSignal( std::string signalName, std::function< SignalType > callback )
2499 detail::CallId callId;
2500 detail::displayDebugCallInfoSignal( callId, signalName, info, connectionInfo->interfaceName );
2501 auto cS = this->connectionState;
2502 auto cI = this->connectionInfo;
2503 auto callbackLambda = [callId, cS, callback, signalName, cI]( const Eldbus_Message* msg ) -> void {
2504 const char *errname, *aux;
2505 if( eldbus_message_error_get( msg, &errname, &aux ) )
2507 DBUS_DEBUG( "call %d: Eldbus error: %s %s", callId.id, errname, aux );
2510 cI->emit( signalName.c_str(), DBusActionType::SIGNAL_RECEIVED );
2511 DBUS_DEBUG( "call %d: received signal with signature '%s'", callId.id, eldbus_message_signature_get( msg ) );
2512 using ParamsType = typename detail::dbus_interface_traits< SignalType >::VEArgs;
2513 auto params = detail::unpackValues< ParamsType >( callId, msg );
2516 DBUS_DEBUG( "call %d: failed: %s", callId.id, params.getError().message.c_str() );
2521 detail::apply( callback, params.getValues() );
2525 DBUS_DEBUG( "unhandled exception" );
2529 auto tmp = new std::function< void( const Eldbus_Message* msg ) >{std::move( callbackLambda )};
2530 auto handler = eldbus_proxy_signal_handler_add( connectionState.proxy.get(), signalName.c_str(), listenerCallback, tmp );
2531 destructors.add( [=]() {
2532 eldbus_signal_handler_del( handler );
2539 detail::ConnectionState connectionState;
2540 detail::CallOnDestructionList destructors;
2542 std::shared_ptr< ConnectionInfo > connectionInfo;
2543 void emitNotification( DBusActionType type );
2545 static void listenerCallback( void* data, const Eldbus_Message* msg )
2547 auto p = static_cast< std::function< void( const Eldbus_Message* msg ) >* >( data );
2550 static void listenerEventChangedCallback( void* data, Eldbus_Proxy* proxy EINA_UNUSED, void* event )
2552 auto p = static_cast< std::function< void( Eldbus_Proxy_Event_Property_Changed* ) >* >( data );
2553 ( *p )( static_cast< Eldbus_Proxy_Event_Property_Changed* >( event ) );
2559 * @brief Helper class describing DBUS's server interface
2562 class DBusInterfaceDescription
2564 friend class DBusServer;
2571 std::string memberName;
2572 std::vector< Eldbus_Arg_Info > in, out;
2573 std::function< Eldbus_Message*( const Eldbus_Message* msg ) > callback;
2578 std::string memberName;
2579 std::vector< Eldbus_Arg_Info > args;
2580 unsigned int uniqueId;
2584 detail::CallId setterId, getterId;
2585 std::string memberName, typeSignature;
2586 std::function< ValueOrError< void >( const Eldbus_Message*src, Eldbus_Message_Iter*dst ) > getCallback, setCallback;
2590 friend class ::DBus::DBusServer;
2591 friend class ::DBus::DBusClient;
2592 friend class ::DBus::DBusInterfaceDescription;
2595 SignalId( detail::CallId id ) : id( id ) {}
2598 SignalId() = default;
2603 * @brief Creates empty interface description with given name
2605 * @param interfaceName name of the interface
2607 DBusInterfaceDescription( std::string interfaceName );
2610 * @brief adds new, synchronous method to the interface
2612 * When method memberName is called on DBUS, callback functor will be called
2613 * with values received from DBUS. callback won't be called, if method was
2614 * called with invalid signature. Value returned from functor (or error message)
2615 * will be marshalled back to the caller.
2617 * Template type T defines both arguments sent to the method
2618 * and expected values. Receiving different values will be reported as
2619 * error. For example:
2620 * \code{.cpp} Method<int(float, float)> \endcode
2621 * defines method, which takes two arguments (two floats) and return
2622 * single value of type int.
2624 * @param memberName name of the method
2625 * @param callback functor, which will be called
2627 template < typename T >
2628 void addMethod( const std::string& memberName, typename detail::dbus_interface_traits< T >::SyncCB callback )
2630 detail::CallId callId;
2632 methods.push_back( std::move( mi ) );
2633 auto& z = methods.back();
2634 z.in = detail::EldbusArgGenerator_Args< T >::get( strings );
2635 z.out = detail::EldbusArgGenerator_ReturnType< T >::get( strings );
2636 z.memberName = memberName;
2637 DBUS_DEBUG( "call %d: method %s, in %s, out %s", callId.id, memberName.c_str(),
2638 detail::EldbusArgGenerator_Args< T >::name().c_str(),
2639 detail::EldbusArgGenerator_ReturnType< T >::name().c_str() );
2640 z.callback = construct< T >( callId, callback );
2645 * @brief adds new, asynchronous method to the interface
2647 * When method memberName is called on DBUS, callback functor will be called
2648 * with values received from DBUS. callback won't be called, if method was
2649 * called with invalid signature. callback will called with reply callback functor.
2650 * Reply callback functor must be called with reply value, when it's ready.
2651 * It's safe to ignore calling reply callback, but some resources might be kept
2652 * as long as either reply callback exists or reply timeout hasn't yet been met.
2654 * Template type T defines both arguments sent to the method
2655 * and expected values. Receiving different values will be reported as
2656 * error. For example:
2657 * \code{.cpp} Method<int(float, float)> \endcode
2658 * defines method, which takes two arguments (two floats) and return
2659 * single value of type int.
2661 * @param memberName name of the method
2662 * @param callback functor, which will be called
2664 template < typename T >
2665 void addAsyncMethod( const std::string& memberName, typename detail::dbus_interface_traits< T >::AsyncCB callback );
2668 * @brief adds new, synchronous property to the interface
2670 * When property memberName is called on DBUS, respective callback functor will be called
2671 * with values received from DBUS. callback won't be called, if method was
2672 * called with invalid signature. Value returned from functor (or error message)
2673 * will be marshalled back to the caller.
2675 * Template type T defines type of the value hidden under property.
2676 * Note, that library automatically wraps both sent and received value into
2677 * DBUS's wrapper type.
2679 * @param memberName name of the method
2680 * @param getter functor, which will be called when property is being read
2681 * @param setter functor, which will be called when property is being set
2683 template < typename T >
2684 void addProperty( const std::string& memberName, std::function< ValueOrError< T >() > getter, std::function< ValueOrError< void >( T ) > setter )
2686 properties.push_back( {} );
2687 auto& z = properties.back();
2688 z.memberName = memberName;
2689 z.typeSignature = detail::signature< T >::sig();
2692 detail::CallId getterId;
2693 z.getterId = getterId;
2694 DBUS_DEBUG( "call %d: property %s (get) type %s", getterId.id, memberName.c_str(), detail::signature< T >::name().c_str() );
2695 z.getCallback = [=]( const Eldbus_Message* src, Eldbus_Message_Iter* dst ) -> ValueOrError< void > {
2696 detail::emitNotification( eldbus_message_sender_get( src ),
2697 eldbus_message_path_get( src ), interfaceName.c_str(), memberName.c_str(), DBusActionType::GETTER_RESPONSE );
2700 auto v = detail::apply( getter, std::tuple<>{} );
2703 detail::signature< T >::set( dst, std::get< 0 >( v.getValues() ) );
2704 DBUS_DEBUG( "call %d: success", getterId.id );
2707 DBUS_DEBUG( "call %d: failed: %s", getterId.id, v.getError().message.c_str() );
2708 return v.getError();
2710 catch( std::exception& e )
2712 return Error{std::string( "unhandled exception (" ) + e.what() + ")"};
2716 return Error{"unhandled exception"};
2722 detail::CallId setterId;
2723 z.setterId = setterId;
2724 DBUS_DEBUG( "call %d: property %s (set) type %s", setterId.id, memberName.c_str(), detail::signature< T >::name().c_str() );
2725 z.setCallback = [=]( const Eldbus_Message* src, Eldbus_Message_Iter* src_iter ) -> ValueOrError< void > {
2726 detail::emitNotification( eldbus_message_sender_get( src ),
2727 eldbus_message_path_get( src ), interfaceName.c_str(), memberName.c_str(), DBusActionType::SETTER_RESPONSE );
2728 std::tuple< T > value;
2729 auto src_signature = eldbus_message_iter_signature_get( src_iter );
2730 if( detail::signature< T >::get( src_iter, std::get< 0 >( value ) ) )
2734 auto v = detail::apply( setter, std::move( value ) );
2737 DBUS_DEBUG( "call %d: success", setterId.id );
2740 DBUS_DEBUG( "call %d: failed: %s", setterId.id, v.getError().message.c_str() );
2741 free( src_signature );
2742 return v.getError();
2744 catch( std::exception& e )
2746 return Error{std::string( "unhandled exception (" ) + e.what() + ")"};
2750 return Error{"unhandled exception"};
2753 DBUS_DEBUG( "call %d: failed to unpack values, got signature '%s', expected '%s'", setterId.id,
2754 src_signature, detail::signature< T >::sig().c_str() );
2755 return Error{"call " + std::to_string( setterId.id ) + ": failed to unpack values, got signature '" +
2756 src_signature + "', expected '" + detail::signature< T >::sig() + "'"};
2762 * @brief adds new signal to the interface
2764 * Template types ARGS defines values, which will be emited with the signal
2766 * @param memberName name of the method
2768 template < typename... ARGS >
2769 SignalId addSignal( const std::string& memberName )
2771 detail::CallId callId;
2772 signals.push_back( {} );
2773 auto& z = signals.back();
2774 z.memberName = memberName;
2775 z.args = detail::EldbusArgGenerator_Args< void( ARGS... ) >::get( strings );
2777 DBUS_DEBUG( "call %d: signal %s", callId.id, memberName.c_str() );
2778 return SignalId{callId};
2783 std::vector< MethodInfo > methods;
2784 std::vector< PropertyInfo > properties;
2785 std::vector< SignalInfo > signals;
2786 std::string interfaceName;
2787 detail::StringStorage strings;
2789 template < typename T >
2790 std::function< Eldbus_Message*( const Eldbus_Message* msg ) > construct( detail::CallId callId,
2791 typename detail::dbus_interface_traits< T >::SyncCB callback )
2793 using VEArgs = typename detail::dbus_interface_traits< T >::VEArgs;
2794 return [=]( const Eldbus_Message* msg ) -> Eldbus_Message* {
2795 DBUS_DEBUG( "call %d: entering", callId.id );
2796 detail::emitNotification( eldbus_message_sender_get( msg ),
2797 eldbus_message_path_get( msg ), interfaceName.c_str(), eldbus_message_member_get( msg ), DBusActionType::METHOD_RESPONSE );
2798 Eldbus_Message* ret = nullptr;
2799 auto args = detail::unpackValues< VEArgs >( callId, msg );
2804 auto v = detail::apply( callback, std::move( args.getValues() ) );
2807 DBUS_DEBUG( "call %d: success", callId.id );
2808 ret = eldbus_message_method_return_new( msg );
2809 packValues( callId, ret, v );
2813 DBUS_DEBUG( "call %d: failed: %s", callId.id, v.getError().message.c_str() );
2814 ret = eldbus_message_error_new( msg, "org.freedesktop.DBus.Error.Failed", v.getError().message.c_str() );
2817 catch( std::exception& e )
2819 auto txt = std::string( "unhandled exception (" ) + e.what() + ")";
2820 DBUS_DEBUG( "call %d: failed: %s", callId.id, txt.c_str() );
2821 ret = eldbus_message_error_new( msg, "org.freedesktop.DBus.Error.Failed", txt.c_str() );
2825 DBUS_DEBUG( "call %d: failed: %s", callId.id, "unhandled exception" );
2826 ret = eldbus_message_error_new( msg, "org.freedesktop.DBus.Error.Failed", "unhandled exception" );
2831 std::ostringstream err;
2832 err << "expected signature '" << detail::signature< VEArgs >::sig() << "', got '" << eldbus_message_signature_get( msg ) << "'";
2833 auto str = err.str();
2834 DBUS_DEBUG( "call %d: failed: %s", callId.id, str.c_str() );
2835 ret = eldbus_message_error_new( msg, "org.freedesktop.DBus.Error.InvalidArgs", str.c_str() );
2844 * @brief Class representing server's end of DBUS connection
2846 * Allows listening (synchronously and asynchronosly) on methods on selected interface
2847 * Allows listening (synchronously and asynchronosly) on setting / getting properties.
2848 * Allows emiting signals.
2850 class DBusServer : private detail::EldbusProxyBase
2854 * @brief Constructs non-connected dbus server.
2856 DBusServer() = default;
2859 * @brief Constructs dbus server on either system or user dbus connection.
2862 DBusServer( ConnectionType tp );
2864 * @brief Constructs dbus server on connection from getDBusConnectionByType
2867 DBusServer( const std::shared_ptr< DBus::EldbusConnection >& conn );
2871 * Destructor will properly destroy everything. Destructor will cancel
2874 ~DBusServer() = default;
2876 DBusServer( const DBusServer& ) = delete;
2877 DBusServer( DBusServer&& ) = default;
2879 DBusServer& operator=( DBusServer&& ) = default;
2880 DBusServer& operator=( const DBusServer& ) = delete;
2883 * @brief Registers interface on given path name
2885 * @param pathName path object to register interface on.
2889 void addInterface( const std::string& pathName, DBusInterfaceDescription& dscr, bool fallback = false );
2892 * @brief Gets bus name of the current connection (must be connected)
2894 std::string getBusName() const;
2897 * @brief Returns connection object for this dbus server object
2899 * @return connection object
2901 std::shared_ptr< DBus::EldbusConnection > getConnection();
2904 * @brief Emits signal
2906 * You must pass identifier of the signal, got as result of calling DBusInterfaceDescription::addSignal.
2907 * Types of the arguments must match EXACTLY types used to call addSignal.
2909 * @param signal identifier of the signal
2910 * @param args values to emit
2912 template < typename... ARGS >
2913 void emit( DBusInterfaceDescription::SignalId signal, const ARGS&... args )
2915 auto it = signalData.find( signal.id.id );
2916 if( it != signalData.end() )
2918 auto msg = eldbus_service_signal_new( it->second.first, it->second.second );
2919 detail::packValues( signal.id, msg, args... );
2920 eldbus_service_signal_send( it->second.first, msg );
2924 DBUS_DEBUG( "signal %d not found", signal.id.id );
2929 * @brief Emits signal
2931 * Emits signal based only on data passed to the function
2933 * @param signal identifier of the signal
2934 * @param args values to emit
2936 template < typename... ARGS >
2937 void emit2( const std::string& path, const std::string& interfaceName,
2938 const std::string& signalName, const ARGS&... args )
2940 auto msg = eldbus_message_signal_new( path.c_str(), interfaceName.c_str(), signalName.c_str() );
2942 detail::packValues( id, msg, args... );
2943 eldbus_connection_send( connection->get(), msg, nullptr, nullptr, -1 );
2946 * @brief Returns current object path, when handling call to property / method
2948 * User can call this function from inside callback used to handle property / method calls.
2949 * It will retrieve object's path used in the call. Note, that in asynchronous handling
2950 * of those calls user need to retrieve and store the current object / current connection
2951 * as the value will change at the moment user's callback handling will exit. For example:
2953 * DBusInterfaceDescription interface{"name"};
2954 * auto handler_later = [](std::function<void(void)> done_cb) {
2955 * // process something later on
2956 * DBusServer::getCurrentObjectPath(); // this will return empty string
2958 * interface.addAsyncMethod<void()>("m", [=](std::function<void(void)> done_cb) {
2959 * DBusServer::getCurrentObjectPath(); // this will current object's path
2961 * // do some processing later on and call done_cb, when it's done
2962 * register_to_call_sometime_later_on(std::move(done_cb));
2966 static std::string getCurrentObjectPath();
2969 * @brief Returns current connection object, when handling call to property / method
2971 * User can call this function from inside callback used to handle property / method calls.
2972 * It will retrieve object's path used in the call. Note, that in asynchronous handling
2973 * of those calls user need to retrieve and store the current object / current connection
2974 * as the value will change at the moment user's callback handling will exit. For example:
2976 * DBusInterfaceDescription interface{"name"};
2977 * auto handler_later = [](std::function<void(void)> done_cb) {
2978 * // process something later on
2979 * DBusServer::getCurrentObjectPath(); // this will return empty string
2981 * interface.addAsyncMethod<void()>("m", [=](std::function<void(void)> done_cb) {
2982 * DBusServer::getCurrentObjectPath(); // this will current object's path
2984 * // do some processing later on and call done_cb, when it's done
2985 * register_to_call_sometime_later_on(std::move(done_cb));
2989 static std::shared_ptr< DBus::EldbusConnection > getCurrentConnection();
2993 std::shared_ptr< DBus::EldbusConnection > connection;
2994 detail::CallOnDestructionList destructors;
2995 std::unordered_map< unsigned int, std::pair< const Eldbus_Service_Interface*, unsigned int > > signalData;
2999 template < typename T >
3000 void DBusInterfaceDescription::addAsyncMethod( const std::string& memberName, typename detail::dbus_interface_traits< T >::AsyncCB callback )
3002 detail::CallId callId;
3004 methods.push_back( std::move( mi ) );
3005 auto& z = methods.back();
3006 z.in = detail::EldbusArgGenerator_Args< T >::get( strings );
3007 z.out = detail::EldbusArgGenerator_ReturnType< T >::get( strings );
3008 z.memberName = memberName;
3009 DBUS_DEBUG( "call %d: method %s, in %s, out %s", callId.id, memberName.c_str(),
3010 detail::EldbusArgGenerator_Args< T >::name().c_str(),
3011 detail::EldbusArgGenerator_ReturnType< T >::name().c_str() );
3012 using VEArgs = typename detail::dbus_interface_traits< T >::VEArgs;
3013 z.callback = [=]( const Eldbus_Message* msg ) -> Eldbus_Message* {
3014 detail::emitNotification( eldbus_message_sender_get( msg ),
3015 eldbus_message_path_get( msg ), interfaceName.c_str(), memberName.c_str(), DBusActionType::METHOD_RESPONSE );
3018 bool replyRunning = true;
3019 Eldbus_Message* reply = nullptr;
3020 EldbusMessageCallbackHandle message;
3022 auto callState = std::make_shared< CallState >();
3023 callState->message.reset( eldbus_message_ref( const_cast< Eldbus_Message* >( msg ) ) );
3024 auto connection = DBusServer::getCurrentConnection();
3025 auto retCallback = [=]( typename detail::dbus_interface_traits< T >::Ret v ) {
3028 callState->reply = eldbus_message_method_return_new( callState->message.get() );
3029 packValues( callId, callState->reply, v );
3033 DBUS_DEBUG( "call %d: failed: %s", callId.id, v.getError().message.c_str() );
3034 callState->reply = eldbus_message_error_new( callState->message.get(), "org.freedesktop.DBus.Error.Failed", v.getError().message.c_str() );
3036 if( !callState->replyRunning )
3038 eldbus_connection_send( connection->get(), callState->reply, NULL, NULL, -1 );
3041 Eldbus_Message* ret = nullptr;
3042 auto args = detail::unpackValues< VEArgs >( callId, msg );
3045 auto error = [&]( const std::string& txt ) {
3046 if( !callState->reply )
3048 DBUS_DEBUG( "call %d: failed: %s", callId.id, txt.c_str() );
3049 callState->reply = eldbus_message_error_new( callState->message.get(), "org.freedesktop.DBus.Error.Failed", txt.c_str() );
3054 detail::apply( callback, std::move( retCallback ), std::move( args.getValues() ) );
3056 catch( std::exception& e )
3058 error( std::string( "unhandled exception (" ) + e.what() + ")" );
3062 error( "unhandled exception" );
3065 callState->replyRunning = false;
3066 ret = callState->reply;
3070 std::ostringstream err;
3071 err << "expected signature '" << detail::signature< VEArgs >::sig() << "', got '" << eldbus_message_signature_get( msg ) << "'";
3072 auto str = err.str();
3073 ret = eldbus_message_error_new( msg, "org.freedesktop.DBus.Error.InvalidArgs", str.c_str() );
3082 std::shared_ptr< EldbusConnection > getDBusConnectionByType( ConnectionType tp );
3083 std::shared_ptr< EldbusConnection > getDBusConnectionByName( const std::string& name );
3084 std::string getConnectionName( const std::shared_ptr< EldbusConnection >& );
3091 template < size_t INDEX, typename... ARGS >
3092 inline auto get( DBus::ValueOrError< ARGS... >& v ) -> decltype( std::get< INDEX >( v.getValues() ) ) &
3094 return std::get< INDEX >( v.getValues() );
3096 template < size_t INDEX, typename... ARGS >
3097 inline auto get( const DBus::ValueOrError< ARGS... >& v ) -> decltype( std::get< INDEX >( v.getValues() ) )
3099 return std::get< INDEX >( v.getValues() );