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
isDriverManaged(DriverInfo * di)18 bool ClientManager::isDriverManaged(DriverInfo *di)
19 {
20 foreach (DriverInfo *dv, managedDrivers)
21 {
22 if (dv == di)
23 return true;
24 }
25
26 return false;
27 }
28
newDevice(INDI::BaseDevice * dp)29 void ClientManager::newDevice(INDI::BaseDevice *dp)
30 {
31 //setBLOBMode(B_ALSO, dp->getDeviceName());
32 // JM 2018.09.27: ClientManager will no longer handle BLOB, just messages.
33 // We relay the BLOB handling to BLOB Manager to better manage concurrent connections with large data
34 setBLOBMode(B_NEVER, dp->getDeviceName());
35
36 DriverInfo *deviceDriver = nullptr;
37
38 if (QString(dp->getDeviceName()).isEmpty())
39 {
40 qCWarning(KSTARS_INDI) << "Received invalid device with empty name! Ignoring the device...";
41 return;
42 }
43
44 qCDebug(KSTARS_INDI) << "Received new device" << dp->getDeviceName();
45
46 // First iteration find unique matches
47 for (auto &oneDriverInfo : managedDrivers)
48 {
49 if (oneDriverInfo->getUniqueLabel() == QString(dp->getDeviceName()))
50 {
51 deviceDriver = oneDriverInfo;
52 break;
53 }
54 }
55
56 // Second iteration find partial matches
57 if (deviceDriver == nullptr)
58 {
59 for (auto &oneDriverInfo : managedDrivers)
60 {
61 QString dvName = oneDriverInfo->getName();
62 dvName = oneDriverInfo->getName().split(' ').first();
63 if (dvName.isEmpty())
64 dvName = oneDriverInfo->getName();
65 if (/*dv->getUniqueLabel() == dp->getDeviceName() ||*/
66 QString(dp->getDeviceName()).startsWith(dvName, Qt::CaseInsensitive) ||
67 ((oneDriverInfo->getDriverSource() == HOST_SOURCE || oneDriverInfo->getDriverSource() == GENERATED_SOURCE)))
68 {
69 deviceDriver = oneDriverInfo;
70 break;
71 }
72 }
73 }
74
75 if (deviceDriver == nullptr)
76 return;
77
78 deviceDriver->setUniqueLabel(dp->getDeviceName());
79
80 DeviceInfo *devInfo = new DeviceInfo(deviceDriver, dp);
81 deviceDriver->addDevice(devInfo);
82 emit newINDIDevice(devInfo);
83 }
84
newProperty(INDI::Property * pprop)85 void ClientManager::newProperty(INDI::Property *pprop)
86 {
87 INDI::Property prop(*pprop);
88
89 // Do not emit the signal if the server is disconnected or disconnecting (deadlock between signals)
90 if (!isServerConnected())
91 {
92 IDLog("Received new property %s for disconnected device %s, discarding\n", prop.getName(), prop.getDeviceName());
93 return;
94 }
95
96 //IDLog("Received new property %s for device %s\n", prop->getName(), prop->getgetDeviceName());
97 emit newINDIProperty(prop);
98
99 // Only handle RW and RO BLOB properties
100 if (prop.getType() == INDI_BLOB && prop.getPermission() != IP_WO)
101 {
102 QPointer<BlobManager> bm = new BlobManager(getHost(), getPort(), prop.getBaseDevice()->getDeviceName(), prop.getName());
103 connect(bm.data(), &BlobManager::newINDIBLOB, this, &ClientManager::newINDIBLOB);
104 connect(bm.data(), &BlobManager::connected, this, [prop, this]()
105 {
106 if (prop && prop.getRegistered())
107 emit newBLOBManager(prop->getBaseDevice()->getDeviceName(), prop);
108 });
109 blobManagers.append(bm);
110 }
111 }
112
removeProperty(INDI::Property * prop)113 void ClientManager::removeProperty(INDI::Property *prop)
114 {
115 const QString name = prop->getName();
116 const QString device = prop->getDeviceName();
117 emit removeINDIProperty(device, name);
118
119 // If BLOB property is removed, remove its corresponding property if one exists.
120 if (blobManagers.empty() == false && prop->getType() == INDI_BLOB && prop->getPermission() != IP_WO)
121 {
122 for (QPointer<BlobManager> bm : blobManagers)
123 {
124 const QString bProperty = bm.data()->property("property").toString();
125 const QString bDevice = bm.data()->property("device").toString();
126 if (bDevice == device && bProperty == name)
127 {
128 blobManagers.removeOne(bm);
129 bm.data()->disconnectServer();
130 bm->deleteLater();
131 break;
132 }
133 }
134 }
135 }
136
disconnectAll()137 void ClientManager::disconnectAll()
138 {
139 disconnectServer();
140 for (auto &oneManager : blobManagers)
141 oneManager->disconnectServer();
142 }
143
removeDevice(INDI::BaseDevice * dp)144 void ClientManager::removeDevice(INDI::BaseDevice *dp)
145 {
146 QString deviceName = dp->getDeviceName();
147
148 QMutableListIterator<QPointer<BlobManager>> it(blobManagers);
149 while (it.hasNext())
150 {
151 QPointer<BlobManager> &oneManager = it.next();
152 if (oneManager->property("device").toString() == deviceName)
153 {
154 oneManager->disconnect();
155 it.remove();
156 }
157 }
158
159 for (auto driverInfo : managedDrivers)
160 {
161 for (auto deviceInfo : driverInfo->getDevices())
162 {
163 if (deviceInfo->getDeviceName() == deviceName)
164 {
165 qCDebug(KSTARS_INDI) << "Removing device" << deviceName;
166
167 emit removeINDIDevice(deviceName);
168
169 driverInfo->removeDevice(deviceInfo);
170
171 if (driverInfo->isEmpty())
172 {
173 managedDrivers.removeOne(driverInfo);
174 if (driverInfo->getDriverSource() == GENERATED_SOURCE)
175 driverInfo->deleteLater();
176 }
177
178 return;
179 }
180 }
181 }
182 }
183
newBLOB(IBLOB * bp)184 void ClientManager::newBLOB(IBLOB *bp)
185 {
186 emit newINDIBLOB(bp);
187 }
188
newSwitch(ISwitchVectorProperty * svp)189 void ClientManager::newSwitch(ISwitchVectorProperty *svp)
190 {
191 emit newINDISwitch(svp);
192 }
193
newNumber(INumberVectorProperty * nvp)194 void ClientManager::newNumber(INumberVectorProperty *nvp)
195 {
196 emit newINDINumber(nvp);
197 }
198
newText(ITextVectorProperty * tvp)199 void ClientManager::newText(ITextVectorProperty *tvp)
200 {
201 emit newINDIText(tvp);
202 }
203
newLight(ILightVectorProperty * lvp)204 void ClientManager::newLight(ILightVectorProperty *lvp)
205 {
206 emit newINDILight(lvp);
207 }
208
newMessage(INDI::BaseDevice * dp,int messageID)209 void ClientManager::newMessage(INDI::BaseDevice *dp, int messageID)
210 {
211 emit newINDIMessage(dp, messageID);
212 }
213
214 #if INDI_VERSION_MAJOR >= 1 && INDI_VERSION_MINOR >= 5
newUniversalMessage(std::string message)215 void ClientManager::newUniversalMessage(std::string message)
216 {
217 emit newINDIUniversalMessage(QString::fromStdString(message));
218 }
219 #endif
220
appendManagedDriver(DriverInfo * dv)221 void ClientManager::appendManagedDriver(DriverInfo *dv)
222 {
223 qCDebug(KSTARS_INDI) << "Adding managed driver" << dv->getName();
224
225 managedDrivers.append(dv);
226
227 dv->setClientManager(this);
228
229 sManager = dv->getServerManager();
230 }
231
removeManagedDriver(DriverInfo * dv)232 void ClientManager::removeManagedDriver(DriverInfo *dv)
233 {
234 qCDebug(KSTARS_INDI) << "Removing managed driver" << dv->getName();
235
236 dv->setClientState(false);
237 managedDrivers.removeOne(dv);
238
239 for (auto di : dv->getDevices())
240 {
241 // #1 Remove from GUI Manager
242 GUIManager::Instance()->removeDevice(di->getDeviceName());
243
244 // #2 Remove from INDI Listener
245 INDIListener::Instance()->removeDevice(di->getDeviceName());
246
247 // #3 Remove device from Driver Info
248 dv->removeDevice(di);
249 }
250
251 if (dv->getDriverSource() == GENERATED_SOURCE)
252 dv->deleteLater();
253 }
254
serverConnected()255 void ClientManager::serverConnected()
256 {
257 qCDebug(KSTARS_INDI) << "INDI server connected.";
258
259 for (auto &oneDriverInfo : managedDrivers)
260 {
261 oneDriverInfo->setClientState(true);
262 if (sManager)
263 oneDriverInfo->setHostParameters(sManager->getHost(), sManager->getPort());
264 }
265 }
266
serverDisconnected(int exit_code)267 void ClientManager::serverDisconnected(int exit_code)
268 {
269 qCDebug(KSTARS_INDI) << "INDI server disconnected. Exit code:" << exit_code;
270
271 for (auto &oneDriverInfo : managedDrivers)
272 {
273 oneDriverInfo->setClientState(false);
274 oneDriverInfo->reset();
275 }
276
277 if (exit_code < 0)
278 emit connectionFailure(this);
279 }
getManagedDrivers() const280 QList<DriverInfo *> ClientManager::getManagedDrivers() const
281 {
282 return managedDrivers;
283 }
284
findDriverInfoByName(const QString & name)285 DriverInfo *ClientManager::findDriverInfoByName(const QString &name)
286 {
287 auto pos = std::find_if(managedDrivers.begin(), managedDrivers.end(), [name](DriverInfo * oneDriverInfo)
288 {
289 return oneDriverInfo->getName() == name;
290 });
291
292 if (pos != managedDrivers.end())
293 return *pos;
294 else
295 return nullptr;
296 }
297
findDriverInfoByLabel(const QString & label)298 DriverInfo *ClientManager::findDriverInfoByLabel(const QString &label)
299 {
300 auto pos = std::find_if(managedDrivers.begin(), managedDrivers.end(), [label](DriverInfo * oneDriverInfo)
301 {
302 return oneDriverInfo->getLabel() == label;
303 });
304
305 if (pos != managedDrivers.end())
306 return *pos;
307 else
308 return nullptr;
309 }
310
setBLOBEnabled(bool enabled,const QString & device,const QString & property)311 void ClientManager::setBLOBEnabled(bool enabled, const QString &device, const QString &property)
312 {
313 for(QPointer<BlobManager> bm : blobManagers)
314 {
315 if (bm->property("device") == device && (property.isEmpty() || bm->property("property") == property))
316 {
317 bm->setEnabled(enabled);
318 return;
319 }
320 }
321 }
322
isBLOBEnabled(const QString & device,const QString & property)323 bool ClientManager::isBLOBEnabled(const QString &device, const QString &property)
324 {
325 for(QPointer<BlobManager> bm : blobManagers)
326 {
327 if (bm->property("device") == device && bm->property("property") == property)
328 return bm->property("enabled").toBool();
329 }
330
331 return false;
332 }
333