Kstars

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

KDE's Doxygen guidelines are available online.