@@ -21,15 +21,7 @@ ServiceClient::ServiceClient( QString name, QString type, const QoSWrapper &qos
2121 babel_fish_ = BabelFishDispenser::getBabelFish ();
2222}
2323
24- ServiceClient::~ServiceClient ()
25- {
26- stop_ = true ;
27- for ( auto &thread : waiting_threads_ ) {
28- if ( thread.joinable () )
29- thread.join ();
30- }
31- waiting_threads_.clear ();
32- }
24+ ServiceClient::~ServiceClient () = default ;
3325
3426void ServiceClient::onRos2Initialized ()
3527{
@@ -49,23 +41,43 @@ void ServiceClient::onRos2Initialized()
4941 connect_timer_.start ();
5042}
5143
52- void ServiceClient::onRos2Shutdown ()
53- {
54- stop_ = true ;
55- for ( auto &thread : waiting_threads_ ) {
56- if ( thread.joinable () )
57- thread.join ();
58- }
59- client_.reset ();
60- }
44+ void ServiceClient::onRos2Shutdown () { client_.reset (); }
6145
6246void ServiceClient::checkServiceReady ()
6347{
64- if ( !isServiceReady () )
48+ if ( !isServiceReady () ) {
49+ int timeouted = 0 ;
50+ for ( size_t i = 0 ; i < waiting_service_calls_.size (); ++i, ++timeouted ) {
51+ if ( clock::now () - waiting_service_calls_[i].start <
52+ std::chrono::milliseconds ( connection_timeout_ ) )
53+ break ;
54+ QML_ROS2_PLUGIN_DEBUG (
55+ " Request for service '%s' timeouted while waiting for it to become ready." ,
56+ name_.toStdString ().c_str () );
57+ invokeCallback ( waiting_service_calls_[i].callback , QVariant ( false ) );
58+ pending_requests_--;
59+ }
60+ if ( timeouted > 0 ) {
61+ waiting_service_calls_.erase ( waiting_service_calls_.begin (),
62+ waiting_service_calls_.begin () + timeouted );
63+ emit pendingRequestsChanged ();
64+ }
6565 return ;
66+ }
6667 connect_timer_.stop ();
6768 disconnect ( &connect_timer_, &QTimer::timeout, this , &ServiceClient::checkServiceReady );
6869 emit serviceReadyChanged ();
70+
71+ if ( waiting_service_calls_.empty () )
72+ return ;
73+
74+ blockSignals ( true );
75+ for ( const auto &call : waiting_service_calls_ ) {
76+ pending_requests_--;
77+ sendRequestAsync ( call.request , call.callback );
78+ }
79+ blockSignals ( false );
80+ emit pendingRequestsChanged ();
6981}
7082
7183bool ServiceClient::isServiceReady () const
@@ -87,32 +99,15 @@ void ServiceClient::setConnectionTimeout( int timeout )
8799 emit connectionTimeoutChanged ();
88100}
89101
102+ int ServiceClient::pendingRequests () const { return pending_requests_; }
103+
90104void ServiceClient::sendRequestAsync ( const QVariantMap &req, const QJSValue &callback )
91105{
92- using clock = std::chrono::steady_clock ;
106+ pending_requests_++ ;
93107 if ( client_ == nullptr || !client_->service_is_ready () ) {
94108 QML_ROS2_PLUGIN_DEBUG ( " Service '%s' not ready, waiting up to %d ms." ,
95109 name_.toStdString ().c_str (), connection_timeout_ );
96- waiting_threads_.emplace_back ( [this , req, callback] {
97- auto now = clock::now ();
98- while ( !isServiceReady () ) {
99- if ( stop_ || clock::now () - now > std::chrono::milliseconds ( connection_timeout_ ) ) {
100- QML_ROS2_PLUGIN_DEBUG ( " Service '%s' timeouted or client was destroyed while waiting for "
101- " it to become ready." ,
102- name_.toStdString ().c_str () );
103- QMetaObject::invokeMethod ( this , " invokeCallback" , Qt::AutoConnection,
104- Q_ARG ( QJSValue, callback ),
105- Q_ARG ( QVariant, QVariant ( false ) ) );
106- return ;
107- }
108- std::this_thread::sleep_for ( std::chrono::milliseconds ( 5 ) );
109- }
110- QML_ROS2_PLUGIN_DEBUG (
111- " Service '%s' is ready after waiting %ld ms. Sending goal." , name_.toStdString ().c_str (),
112- std::chrono::duration_cast<std::chrono::milliseconds>( clock::now () - now ).count () );
113- QMetaObject::invokeMethod ( this , " sendRequestAsync" , Qt::AutoConnection,
114- Q_ARG ( QVariantMap, req ), Q_ARG ( QJSValue, callback ) );
115- } );
110+ waiting_service_calls_.push_back ( { req, callback, clock::now () } );
116111 return ;
117112 }
118113 QML_ROS2_PLUGIN_DEBUG ( " Service '%s' is ready. Sending request." , name_.toStdString ().c_str () );
@@ -123,10 +118,13 @@ void ServiceClient::sendRequestAsync( const QVariantMap &req, const QJSValue &ca
123118 client_->async_send_request ( message, [callback,
124119 this ]( BabelFishServiceClient::SharedFuture response ) {
125120 QML_ROS2_PLUGIN_DEBUG ( " Received response from service %s." , name_.toStdString ().c_str () );
121+ pending_requests_--;
122+ emit pendingRequestsChanged ();
126123 QMetaObject::invokeMethod ( this , " invokeCallback" , Qt::AutoConnection,
127124 Q_ARG ( QJSValue, callback ),
128125 Q_ARG ( QVariant, msgToMap ( response.get () ) ) );
129126 } );
127+ emit pendingRequestsChanged ();
130128 return ;
131129 } catch ( BabelFishException &ex ) {
132130 QML_ROS2_PLUGIN_ERROR ( " Failed to call service: %s" , ex.what () );
@@ -135,6 +133,7 @@ void ServiceClient::sendRequestAsync( const QVariantMap &req, const QJSValue &ca
135133 } catch ( ... ) {
136134 QML_ROS2_PLUGIN_ERROR ( " Failed to call service: Unknown error." );
137135 }
136+ pending_requests_--;
138137 QMetaObject::invokeMethod ( this , " invokeCallback" , Qt::AutoConnection,
139138 Q_ARG ( QJSValue, callback ), Q_ARG ( QVariant, QVariant ( false ) ) );
140139}
0 commit comments