44
55#include < QJsonArray>
66
7- AdapterClient::AdapterClient (AdapterProcess* pProcess, QObject* parent) : QObject(parent), _pProcess(pProcess)
7+ AdapterClient::AdapterClient (AdapterProcess* pProcess, QObject* parent, int handshakeTimeoutMs)
8+ : QObject(parent), _pProcess(pProcess), _handshakeTimeoutMs(handshakeTimeoutMs)
89{
910 Q_ASSERT (pProcess);
1011 _pProcess->setParent (this );
@@ -16,6 +17,7 @@ AdapterClient::AdapterClient(AdapterProcess* pProcess, QObject* parent) : QObjec
1617 connect (_pProcess, &AdapterProcess::errorReceived, this , &AdapterClient::onErrorReceived);
1718 connect (_pProcess, &AdapterProcess::processError, this , &AdapterClient::onProcessError);
1819 connect (_pProcess, &AdapterProcess::processFinished, this , &AdapterClient::onProcessFinished);
20+ connect (_pProcess, &AdapterProcess::notificationReceived, this , &AdapterClient::onNotificationReceived);
1921}
2022
2123AdapterClient::~AdapterClient () = default ;
@@ -35,7 +37,7 @@ void AdapterClient::prepareAdapter(const QString& adapterPath)
3537
3638 qCInfo (scopeComm) << " AdapterClient: process started, sending initialize" ;
3739 _state = State::INITIALIZING;
38- _handshakeTimer.start (cHandshakeTimeoutMs );
40+ _handshakeTimer.start (_handshakeTimeoutMs );
3941 _pProcess->sendRequest (" adapter.initialize" , QJsonObject ());
4042}
4143
@@ -50,7 +52,7 @@ void AdapterClient::provideConfig(QJsonObject config, QStringList registerExpres
5052 _pendingExpressions = registerExpressions;
5153 _pendingConfig = config;
5254 _state = State::CONFIGURING;
53- _handshakeTimer.start (cHandshakeTimeoutMs );
55+ _handshakeTimer.start (_handshakeTimeoutMs );
5456 QJsonObject params;
5557 params[" config" ] = _pendingConfig;
5658 _pProcess->sendRequest (" adapter.configure" , params);
@@ -91,12 +93,13 @@ void AdapterClient::stopSession()
9193 {
9294 _state = State::STOPPING;
9395 _pProcess->sendRequest (" adapter.shutdown" , QJsonObject ());
96+ _handshakeTimer.start (_handshakeTimeoutMs);
9497 }
9598 else
9699 {
100+ _state = State::STOPPING;
97101 _pProcess->stop ();
98- _state = State::IDLE;
99- emit sessionStopped ();
102+ /* sessionStopped is emitted from onProcessFinished once the process exits */
100103 }
101104}
102105
@@ -111,8 +114,10 @@ void AdapterClient::onResponseReceived(int id, const QString& method, const QJso
111114 {
112115 qCWarning (scopeComm) << " AdapterClient: unexpected non-object result for" << method;
113116 _handshakeTimer.stop ();
117+ /* Set IDLE before stop() so onProcessFinished's IDLE guard suppresses any
118+ duplicate sessionError emission when the process exits asynchronously. */
114119 _state = State::IDLE;
115- QTimer::singleShot ( 0 , this , [ this ]() { _pProcess->stop (); } );
120+ _pProcess->stop ();
116121 emit sessionError (QString (" Unexpected non-object result for %1" ).arg (method));
117122 }
118123}
@@ -125,8 +130,10 @@ void AdapterClient::onErrorReceived(int id, const QString& method, const QJsonOb
125130 qCWarning (scopeComm) << " AdapterClient: error for" << method << " :" << errorMsg;
126131
127132 State previousState = _state;
133+ /* Set IDLE before stop() so onProcessFinished's IDLE guard suppresses any
134+ duplicate sessionError emission when the process exits asynchronously. */
128135 _state = State::IDLE;
129- QTimer::singleShot ( 0 , this , [ this ]() { _pProcess->stop (); } );
136+ _pProcess->stop ();
130137
131138 if (previousState != State::STOPPING)
132139 {
@@ -137,14 +144,22 @@ void AdapterClient::onErrorReceived(int id, const QString& method, const QJsonOb
137144void AdapterClient::onProcessError (const QString& message)
138145{
139146 _handshakeTimer.stop ();
140- _state = State::IDLE;
141- emit sessionError (message);
147+ if (_state != State::STOPPING)
148+ {
149+ _state = State::IDLE;
150+ emit sessionError (message);
151+ }
142152}
143153
144154void AdapterClient::onProcessFinished ()
145155{
146156 _handshakeTimer.stop ();
147- if (_state != State::IDLE)
157+ if (_state == State::STOPPING)
158+ {
159+ _state = State::IDLE;
160+ emit sessionStopped ();
161+ }
162+ else if (_state != State::IDLE)
148163 {
149164 _state = State::IDLE;
150165 emit sessionError (" Adapter process exited unexpectedly" );
@@ -154,9 +169,35 @@ void AdapterClient::onProcessFinished()
154169void AdapterClient::onHandshakeTimeout ()
155170{
156171 qCWarning (scopeComm) << " AdapterClient: handshake timed out in state" << static_cast <int >(_state);
172+ bool wasStopping = (_state == State::STOPPING);
157173 _state = State::IDLE;
158- QTimer::singleShot (0 , this , [this ]() { _pProcess->stop (); });
159- emit sessionError (" Adapter handshake timed out" );
174+ _pProcess->stop ();
175+ if (wasStopping)
176+ {
177+ emit sessionStopped ();
178+ }
179+ else
180+ {
181+ emit sessionError (" Adapter handshake timed out" );
182+ }
183+ }
184+
185+ void AdapterClient::onNotificationReceived (QString method, QJsonValue params)
186+ {
187+ if (method != QStringLiteral (" adapter.diagnostic" ))
188+ {
189+ return ;
190+ }
191+
192+ if (!params.isObject ())
193+ {
194+ qCWarning (scopeComm) << " AdapterClient: adapter.diagnostic params is not an object" ;
195+ return ;
196+ }
197+
198+ QJsonObject obj = params.toObject ();
199+ emit diagnosticReceived (obj.value (QStringLiteral (" level" )).toString (),
200+ obj.value (QStringLiteral (" message" )).toString ());
160201}
161202
162203void AdapterClient::handleLifecycleResponse (const QString& method, const QJsonObject& result)
@@ -215,8 +256,7 @@ void AdapterClient::handleLifecycleResponse(const QString& method, const QJsonOb
215256 {
216257 qCInfo (scopeComm) << " AdapterClient: shutdown acknowledged" ;
217258 _pProcess->stop ();
218- _state = State::IDLE;
219- emit sessionStopped ();
259+ /* sessionStopped is emitted from onProcessFinished once the process exits */
220260 }
221261 else
222262 {
0 commit comments