Kstars

clientmanager.cpp
1/*
2 SPDX-FileCopyrightText: 2012 Jasem Mutlaq <mutlaqja@ikarustech.com>
3
4 SPDX-License-Identifier: GPL-2.0-or-later
5*/
6
7#include "clientmanager.h"
8
9#include "deviceinfo.h"
10#include "drivermanager.h"
11#include "guimanager.h"
12#include "indilistener.h"
13#include "Options.h"
14#include "servermanager.h"
15
16#include <indi_debug.h>
17#include <QTimer>
18
19ClientManager::ClientManager()
20{
21 connect(this, &ClientManager::newINDIProperty, this, &ClientManager::processNewProperty, Qt::UniqueConnection);
22 connect(this, &ClientManager::removeBLOBManager, this, &ClientManager::processRemoveBLOBManager, Qt::UniqueConnection);
23}
24
25bool ClientManager::isDriverManaged(const QSharedPointer<DriverInfo> &driver)
26{
27 return std::any_of(m_ManagedDrivers.begin(), m_ManagedDrivers.end(), [driver](const auto & oneDriver)
28 {
29 return driver == oneDriver;
30 });
31}
32
33void ClientManager::newDevice(INDI::BaseDevice dp)
34{
35 //setBLOBMode(B_ALSO, dp->getDeviceName());
36 // JM 2018.09.27: ClientManager will no longer handle BLOB, just messages.
37 // We relay the BLOB handling to BLOB Manager to better manage concurrent connections with large data
38 setBLOBMode(B_NEVER, dp.getDeviceName());
39
40 if (QString(dp.getDeviceName()).isEmpty())
41 {
42 qCWarning(KSTARS_INDI) << "Received invalid device with empty name! Ignoring the device...";
43 return;
44 }
45
46 qCDebug(KSTARS_INDI) << "Received new device" << dp.getDeviceName();
47
48 // First iteration find unique matches
49 for (auto &oneDriverInfo : m_ManagedDrivers)
50 {
51 if (oneDriverInfo->getUniqueLabel() == QString(dp.getDeviceName()))
52 {
53 oneDriverInfo->setUniqueLabel(dp.getDeviceName());
54 DeviceInfo *devInfo = new DeviceInfo(oneDriverInfo, dp);
55 oneDriverInfo->addDevice(devInfo);
56 qCDebug(KSTARS_INDI) << "Driver" << oneDriverInfo->getName() << "is adding device" << dp.getDeviceName() <<
57 "(exact match by label)";
58 emit newINDIDevice(devInfo);
59 return;
60 }
61 }
62
63 // Next use getName() exact match
64 for (auto &oneDriverInfo : m_ManagedDrivers)
65 {
66 if (oneDriverInfo->getName() == QString(dp.getDeviceName()))
67 {
68 oneDriverInfo->setUniqueLabel(dp.getDeviceName());
69 DeviceInfo *devInfo = new DeviceInfo(oneDriverInfo, dp);
70 oneDriverInfo->addDevice(devInfo);
71 qCDebug(KSTARS_INDI) << "Driver" << oneDriverInfo->getName() << "is adding device" << dp.getDeviceName() <<
72 "(exact match by name)";
73 emit newINDIDevice(devInfo);
74 return;
75 }
76 }
77
78 // Next use getName() startsWith() match
79 for (auto &oneDriverInfo : m_ManagedDrivers)
80 {
81 if (QString(dp.getDeviceName()).startsWith(oneDriverInfo->getName()))
82 {
83 oneDriverInfo->setUniqueLabel(dp.getDeviceName());
84 DeviceInfo *devInfo = new DeviceInfo(oneDriverInfo, dp);
85 oneDriverInfo->addDevice(devInfo);
86 qCDebug(KSTARS_INDI) << "Driver" << oneDriverInfo->getName() << "is adding device" << dp.getDeviceName() <<
87 "(startsWith match)";
88 emit newINDIDevice(devInfo);
89 return;
90 }
91 }
92
93 // Finally find partial matches
94 for (auto &oneDriverInfo : m_ManagedDrivers)
95 {
96 auto dvName = oneDriverInfo->getName().split(' ').first();
97 if (dvName.isEmpty())
98 dvName = oneDriverInfo->getName();
99 if (/*dv->getUniqueLabel() == dp->getDeviceName() ||*/
100 QString(dp.getDeviceName()).startsWith(dvName, Qt::CaseInsensitive) ||
101 ((oneDriverInfo->getDriverSource() == HOST_SOURCE || oneDriverInfo->getDriverSource() == GENERATED_SOURCE)))
102 {
103 oneDriverInfo->setUniqueLabel(dp.getDeviceName());
104 DeviceInfo *devInfo = new DeviceInfo(oneDriverInfo, dp);
105 qCDebug(KSTARS_INDI) << "Driver" << oneDriverInfo->getName() << "is adding device" << dp.getDeviceName() <<
106 "(heuristic match)";
107 oneDriverInfo->addDevice(devInfo);
108 emit newINDIDevice(devInfo);
109 return;
110 }
111 }
112}
113
114void ClientManager::newProperty(INDI::Property property)
115{
116 // Do not emit the signal if the server is disconnected or disconnecting (deadlock between signals)
117 if (!isServerConnected())
118 {
119 IDLog("Received new property %s for disconnected device %s, discarding\n", property.getName(), property.getDeviceName());
120 return;
121 }
122
123 //IDLog("Received new property %s for device %s\n", prop->getName(), prop->getgetDeviceName());
124 emit newINDIProperty(property);
125}
126
127void ClientManager::updateProperty(INDI::Property property)
128{
129 emit updateINDIProperty(property);
130}
131
132void ClientManager::removeProperty(INDI::Property prop)
133{
134 const QString name = prop.getName();
135 const QString device = prop.getDeviceName();
136 emit removeINDIProperty(prop);
137
138 // If BLOB property is removed, remove its corresponding property if one exists.
139 if (blobManagers.empty() == false && prop.getType() == INDI_BLOB && prop.getPermission() != IP_WO)
140 emit removeBLOBManager(device, name);
141}
142
143void ClientManager::processRemoveBLOBManager(const QString &device, const QString &property)
144{
145 auto manager = std::find_if(blobManagers.begin(), blobManagers.end(), [device, property](auto & oneManager)
146 {
147 const auto bProperty = oneManager->property("property").toString();
148 const auto bDevice = oneManager->property("device").toString();
149 return (device == bDevice && property == bProperty);
150 });
151
152 if (manager != blobManagers.end())
153 {
154 (*manager)->disconnectServer();
155 (*manager)->deleteLater();
156 blobManagers.removeOne(*manager);
157 }
158}
159
160void ClientManager::processNewProperty(INDI::Property prop)
161{
162 // Only handle RW and RO BLOB properties
163 if (prop.getType() == INDI_BLOB && prop.getPermission() != IP_WO)
164 {
165 BlobManager *bm = new BlobManager(this, getHost(), getPort(), prop.getDeviceName(), prop.getName());
166 connect(bm, &BlobManager::propertyUpdated, this, &ClientManager::updateINDIProperty);
167 connect(bm, &BlobManager::connected, this, [prop, this]()
168 {
169 if (prop && prop.getRegistered())
170 emit newBLOBManager(prop.getDeviceName(), prop);
171 });
172 blobManagers.append(bm);
173 }
174}
175
177{
178 disconnectServer();
179 for (auto &oneManager : blobManagers)
180 oneManager->disconnectServer();
181}
182
183void ClientManager::removeDevice(INDI::BaseDevice dp)
184{
185 QString deviceName = dp.getDeviceName();
186
187 QMutableListIterator<BlobManager*> it(blobManagers);
188 while (it.hasNext())
189 {
190 auto &oneManager = it.next();
191 if (oneManager->property("device").toString() == deviceName)
192 {
193 oneManager->disconnect();
194 it.remove();
195 }
196 }
197
198 for (auto &driverInfo : m_ManagedDrivers)
199 {
200 for (auto &deviceInfo : driverInfo->getDevices())
201 {
202 if (deviceInfo->getDeviceName() == deviceName)
203 {
204 qCDebug(KSTARS_INDI) << "Removing device" << deviceName;
205
206 emit removeINDIDevice(deviceName);
207
208 driverInfo->removeDevice(deviceInfo);
209
210 if (driverInfo->isEmpty())
211 {
212 driverInfo->setClientState(false);
213 m_ManagedDrivers.removeOne(driverInfo);
214 }
215
216 return;
217 }
218 }
219 }
220}
221
222void ClientManager::newMessage(INDI::BaseDevice dp, int messageID)
223{
224 emit newINDIMessage(dp, messageID);
225}
226
227void ClientManager::newUniversalMessage(std::string message)
228{
229 emit newINDIUniversalMessage(QString::fromStdString(message));
230}
231
232
234{
235 qCDebug(KSTARS_INDI) << "Adding managed driver" << driver->getName();
236
237 m_ManagedDrivers.append(driver);
238
239 driver->setClientManager(this);
240
241 sManager = driver->getServerManager();
242}
243
245{
246 if (m_ManagedDrivers.empty())
247 {
248 qCDebug(KSTARS_INDI) << "removeManagedDriver: no managed drivers!";
249 return;
250 }
251
252 qCDebug(KSTARS_INDI) << "Removing managed driver" << driver->getName();
253
254 driver->setClientState(false);
255
256 for (auto &di : driver->getDevices())
257 {
258 qCDebug(KSTARS_INDI) << "Managed driver" << driver->getName() << "has device" << di->getDeviceName() <<
259 "that will be removed";
260
261 // #1 Remove from GUI Manager
262 GUIManager::Instance()->removeDevice(di->getDeviceName());
263
264 // #2 Remove from INDI Listener
265 INDIListener::Instance()->removeDevice(di->getDeviceName());
266
267 // #3 Remove device from Driver Info
268 driver->removeDevice(di);
269 }
270 m_ManagedDrivers.removeOne(driver);
271}
272
273void ClientManager::serverConnected()
274{
275 qCDebug(KSTARS_INDI) << "INDI server connected.";
276
277 for (auto &oneDriverInfo : m_ManagedDrivers)
278 {
279 oneDriverInfo->setClientState(true);
280 if (sManager)
281 oneDriverInfo->setHostParameters(sManager->getHost(), sManager->getPort());
282 }
283
284 m_PendingConnection = false;
285 m_ConnectionRetries = MAX_RETRIES;
286
287 emit started();
288}
289
290void ClientManager::serverDisconnected(int exitCode)
291{
292 if (m_PendingConnection)
293 qCDebug(KSTARS_INDI) << "INDI server connection refused.";
294 else
295 qCDebug(KSTARS_INDI) << "INDI server disconnected. Exit code:" << exitCode;
296
297 for (auto &oneDriverInfo : m_ManagedDrivers)
298 {
299 oneDriverInfo->setClientState(false);
300 oneDriverInfo->reset();
301 }
302
303 if (m_PendingConnection)
304 {
305 // Should we retry again?
306 if (m_ConnectionRetries-- > 0)
307 {
308 // Connect again in 1 second.
309 QTimer::singleShot(1000, this, [this]()
310 {
311 qCDebug(KSTARS_INDI) << "Retrying connection again...";
312 if (connectServer() == false)
313 serverDisconnected(0);
314 else
315 m_PendingConnection = false;
316 });
317 }
318 // Nope cannot connect to server.
319 else
320 {
321 m_PendingConnection = false;
322 m_ConnectionRetries = MAX_RETRIES;
323 emit failed(i18n("Failed to connect to INDI server %1:%2", getHost(), getPort()));
324 }
325 }
326 // Did server disconnect abnormally?
327 else if (exitCode < 0)
328 emit terminated(i18n("Connection to INDI host at %1 on port %2 lost. Server disconnected: %3", getHost(), getPort(),
329 exitCode));
330}
331
332const QList<QSharedPointer<DriverInfo>> &ClientManager::getManagedDrivers() const
333{
334 return m_ManagedDrivers;
335}
336
337void ClientManager::establishConnection()
338{
339 qCDebug(KSTARS_INDI)
340 << "INDI: Connecting to local INDI server on port " << getPort() << " ...";
341
342 m_PendingConnection = true;
343 m_ConnectionRetries = 2;
344
345 if (connectServer() == false)
346 serverDisconnected(0);
347 else
348 m_PendingConnection = false;
349}
350
351const QSharedPointer<DriverInfo> &ClientManager::findDriverInfoByName(const QString &name)
352{
353 auto pos = std::find_if(m_ManagedDrivers.begin(), m_ManagedDrivers.end(), [name](QSharedPointer<DriverInfo> oneDriverInfo)
354 {
355 return oneDriverInfo->getName() == name;
356 });
357
358 return *pos;
359}
360
361const QSharedPointer<DriverInfo> &ClientManager::findDriverInfoByLabel(const QString &label)
362{
363 auto pos = std::find_if(m_ManagedDrivers.begin(), m_ManagedDrivers.end(), [label](QSharedPointer<DriverInfo> oneDriverInfo)
364 {
365 return oneDriverInfo->getLabel() == label;
366 });
367
368 return *pos;
369}
370
371void ClientManager::setBLOBEnabled(bool enabled, const QString &device, const QString &property)
372{
373 for(auto &bm : blobManagers)
374 {
375 if (bm->property("device") == device && (property.isEmpty() || bm->property("property") == property))
376 {
377 bm->setEnabled(enabled);
378 return;
379 }
380 }
381}
382
383bool ClientManager::isBLOBEnabled(const QString &device, const QString &property)
384{
385 for(auto &bm : blobManagers)
386 {
387 if (bm->property("device") == device && bm->property("property") == property)
388 return bm->property("enabled").toBool();
389 }
390
391 return false;
392}
BlobManager manages connection to INDI server to handle a specific BLOB.
Definition blobmanager.h:34
void disconnectAll()
disconnectAll Disconnect from server and disconnect all BLOB Managers.
void removeManagedDriver(const QSharedPointer< DriverInfo > &driver)
removeManagedDriver Remove managed driver from pool of drivers managed by this client manager.
void appendManagedDriver(const QSharedPointer< DriverInfo > &driver)
appendManagedDriver Add driver to pool of managed drivers by this client manager.
DeviceInfo is simple class to hold DriverInfo and INDI::BaseDevice associated with a particular devic...
Definition deviceinfo.h:21
QString i18n(const char *text, const TYPE &arg...)
QString name(GameStandardAction id)
void append(QList< T > &&value)
iterator begin()
bool empty() const const
iterator end()
bool removeOne(const AT &t)
QMetaObject::Connection connect(const QObject *sender, PointerToMemberFunction signal, Functor functor)
QVariant property(const char *name) const const
QString fromStdString(const std::string &str)
bool isEmpty() const const
bool startsWith(QChar c, Qt::CaseSensitivity cs) const const
CaseInsensitive
UniqueConnection
This file is part of the KDE documentation.
Documentation copyright © 1996-2024 The KDE developers.
Generated on Fri Jul 26 2024 11:59:52 by doxygen 1.11.0 written by Dimitri van Heesch, © 1997-2006

KDE's Doxygen guidelines are available online.