玉兔远程控制 0.1.0-bate5
载入中...
搜索中...
未找到
Manager.cpp
1// Author: Kang Lin <kl222@126.com>
2
3#include <QPluginLoader>
4#include <QKeyEvent>
5#include <QtPlugin>
6#include <QFile>
7#include <QApplication>
8#include <QSettings>
9#include <QLoggingCategory>
10#include <QMessageBox>
11#include <QCheckBox>
12
13#include "RabbitCommonDir.h"
14#include "RabbitCommonTools.h"
15#include "ParameterPluginUI.h"
16#include "ParameterRecordUI.h"
17#if defined(HAVE_QTERMWIDGET)
18 #include "ParameterTerminalUI.h"
19 #include "OperateTerminal.h"
20#endif
21#ifdef HAVE_LIBSSH
22 #include "ChannelSSH.h"
23#endif
24
25#if HAVE_QTKEYCHAIN
26 #include "keychain.h"
27#endif
28
29#include "Channel.h"
30#include "Manager.h"
31
32static Q_LOGGING_CATEGORY(log, "Manager")
33
34CManager::CManager(QObject *parent, QString szFile) : QObject(parent)
35 , m_FileVersion(1) //TODO: update version it if update data
36 , m_pHook(nullptr)
37{
38 bool check = false;
39 //#if defined (_DEBUG) || !defined(BUILD_SHARED_LIBS)
40 // Q_INIT_RESOURCE(translations_Plugin);
41 //#endif
42
43 m_Translator = RabbitCommon::CTools::Instance()->InstallTranslator(
44 "Plugin", RabbitCommon::CTools::TranslationType::Library);
45
47 m_szSettingsFile = szFile;
48 m_pParameter = new CParameterPlugin();
49 if(m_pParameter) {
50 LoadSettings(m_szSettingsFile);
51
52 bool bReboot = true;
53 QString szSnap;
54 QString szFlatpak;
55#if defined(Q_OS_ANDROID)
56 bReboot = false;
57#endif
58#if QT_VERSION > QT_VERSION_CHECK(6, 0, 0) && defined(Q_OS_WIN)
59 szSnap = qEnvironmentVariable("SNAP");
60 szFlatpak = qEnvironmentVariable("FLATPAK_ID");
61#else
62 szSnap = QString::fromLocal8Bit(qgetenv("SNAP"));
63 szFlatpak = QString::fromLocal8Bit(qgetenv("FLATPAK_ID"));
64#endif
65 if(!szSnap.isEmpty() || !szFlatpak.isEmpty())
66 bReboot = false;
67 if(bReboot && !RabbitCommon::CTools::Instance()->HasAdministratorPrivilege()
68 && m_pParameter->GetPromptAdministratorPrivilege())
69 {
70 int nRet = 0;
71 QString szMsg;
72 szMsg = tr("The programe is not administrator privilege.\n"
73 "Some features are limited.\n");
74#if defined(Q_OS_WIN)
75 szMsg += tr("Eg: Can not disable system shortcuts(eg: Ctrl+Alt+del).") + "\n";
76#else
77 szMsg += tr("Eg: Can not use the wake on LAN feature.") + "\n";
78#endif
79 szMsg += tr("Restart program by administrator?");
80 QMessageBox msg(QMessageBox::Warning, tr("Warning"), szMsg,
81 QMessageBox::Yes | QMessageBox::No);
82 msg.setCheckBox(new QCheckBox(tr("Always shown"), &msg));
83 msg.checkBox()->setCheckable(true);
84 msg.checkBox()->setChecked(
85 m_pParameter->GetPromptAdministratorPrivilege());
86 nRet = msg.exec();
87
88 m_pParameter->SetPromptAdministratorPrivilege(
89 msg.checkBox()->isChecked());
90 SaveSettings(m_szSettingsFile);
91
92 if(QMessageBox::Yes == nRet) {
93 RabbitCommon::CTools::Instance()->StartWithAdministratorPrivilege(true);
94 return;
95 }
96 }
97
98 check = connect(m_pParameter, SIGNAL(sigNativeWindowRecieveKeyboard()),
99 this, SLOT(slotNativeWindowRecieveKeyboard()));
100 Q_ASSERT(check);
101 m_pHook = CHook::GetHook(m_pParameter, this);
102 if(m_pHook)
103 m_pHook->RegisterKeyboard();
104 } else {
105 qCritical(log) << "new CParameterPlugin() fail";
106 Q_ASSERT(m_pParameter);
107 }
108
109 LoadPlugins();
110}
111
112CManager::~CManager()
113{
114 qDebug(log) << "CManager::~CManager()";
115
116 qApp->removeEventFilter(this);
117
118 if(m_pHook) {
119 m_pHook->UnRegisterKeyboard();
120 m_pHook->deleteLater();
121 m_pHook = nullptr;
122 }
123
124 if(m_pParameter) {
125 m_pParameter->deleteLater();
126 m_pParameter = nullptr;
127 }
128
129 if(m_Translator)
130 RabbitCommon::CTools::Instance()->RemoveTranslator(m_Translator);
131
133
134 //#if defined (_DEBUG) || !defined(BUILD_SHARED_LIBS)
135 // Q_CLEANUP_RESOURCE(translations_Plugin);
136 //#endif
137}
138
139int CManager::LoadPlugins()
140{
141 int nRet = 0;
142 foreach (QObject *plugin, QPluginLoader::staticInstances())
143 {
144 CPlugin* p = qobject_cast<CPlugin*>(plugin);
145 if(p)
146 {
147 if(m_Plugins.find(p->Id()) == m_Plugins.end())
148 {
149 qInfo(log) << "Success: Load plugin" << p->Name();
150 AppendPlugin(p);
151 }
152 else
153 qWarning(log) << "The plugin" << p->Name() << " is exist.";
154 }
155 }
156
157 QString szPath = RabbitCommon::CDir::Instance()->GetDirPlugins();
158
159 QStringList filters;
160 if(filters.isEmpty())
161 {
162#if defined (Q_OS_WINDOWS) || defined(Q_OS_WIN)
163 filters << "*Plugin*.dll";
164#elif defined(Q_OS_MACOS) || defined(Q_OS_MAC)
165 filters << "*Plugin*.dylib";
166#else
167 filters << "*Plugin*.so";
168#endif
169 }
170 nRet = FindPlugins(szPath, filters);
171 if(!m_szDetails.isEmpty())
172 m_szDetails = "## " + tr("Plugins") + "\n" + m_szDetails;
173
174 qDebug(log) << ("Client details:\n" + Details()).toStdString().c_str();
175 return nRet;
176}
177
178int CManager::FindPlugins(QDir dir, QStringList filters)
179{
180 QString fileName;
181
182 QString szCurrentPath = QDir::currentPath();
183 QStringList files = dir.entryList(filters, QDir::Files | QDir::NoDotAndDotDot);
184 if(!files.isEmpty())
185 {
186 //This method is invalid
187 //QCoreApplication::addLibraryPath(QDir::cleanPath(dir.absolutePath()));
188
189 QDir::setCurrent(QDir::cleanPath(dir.absolutePath()));
190
191 // This method is valid
192 //#if defined(Q_OS_WINDOWS)
193 // QString szPath = QString::fromLocal8Bit(qgetenv("PATH"));
194 // szPath += ";";
195 // szPath += QDir::cleanPath(dir.absolutePath());
196 // qputenv("PATH", szPath.toLatin1());
197 //#endif
198 }
199
200 foreach (fileName, files) {
201 QString szPlugins = dir.absoluteFilePath(fileName);
202 QPluginLoader loader(szPlugins);
203 QObject *plugin = loader.instance();
204 if (plugin) {
205 CPlugin* p = qobject_cast<CPlugin*>(plugin);
206 if(p)
207 {
208 if(m_Plugins.find(p->Id()) == m_Plugins.end())
209 {
210 qInfo(log) << "Success: Load plugin"
211 << p->Name() << "from" << szPlugins;
212 AppendPlugin(p);
213 }
214 else
215 qWarning(log) << "The plugin [" << p->Name() << "] is exist.";
216 }
217 } else {
218 QString szMsg;
219 szMsg = "Error: Load plugin fail from " + szPlugins;
220 if(!loader.errorString().isEmpty())
221 szMsg += "; Error: " + loader.errorString();
222 qCritical(log) << szMsg.toStdString().c_str();
223 }
224 }
225
226 foreach (fileName, dir.entryList(QDir::Dirs | QDir::NoDotAndDotDot)) {
227 QDir pluginDir = dir;
228 if(pluginDir.cd(fileName))
229 FindPlugins(pluginDir, filters);
230 }
231
232 QDir::setCurrent(szCurrentPath);
233
234 return 0;
235}
236
237int CManager::AppendPlugin(CPlugin *p)
238{
239 if(!p) return -1;
240 m_Plugins.insert(p->Id(), p);
241 //p->InitTranslator();
242 int val = 0;
243 bool bRet = QMetaObject::invokeMethod(
244 p,
245 "InitTranslator",
246 Qt::DirectConnection,
247 Q_RETURN_ARG(int, val));
248 if(!bRet || val)
249 {
250 qCritical(log) << "The plugin" << p->Name()
251 << "initial translator fail" << bRet << val;
252 }
253
254 m_szDetails += "### " + p->DisplayName() + "\n"
255 + tr("Version:") + " " + p->Version() + " \n"
256 + p->Description() + "\n";
257 if(!p->Details().isEmpty())
258 m_szDetails += p->Details() + "\n";
259
260 return 0;
261}
262
265{
266 COperate* pOperate = nullptr;
267 auto it = m_Plugins.find(id);
268 if(m_Plugins.end() != it)
269 {
270 bool bRet = 0;
271 qDebug(log) << "CreateOperate id:" << id;
272 auto plugin = it.value();
273 if(plugin) {
274 //p = plugin->CreateOperate(id);
275 bRet = QMetaObject::invokeMethod(
276 plugin,
277 "CreateOperate",
278 Qt::DirectConnection,
279 Q_RETURN_ARG(COperate*, pOperate),
280 Q_ARG(QString, id),
281 Q_ARG(CParameterPlugin*, m_pParameter));
282 if(!bRet) {
283 qCritical(log) << "Create COperate fail.";
284 return nullptr;
285 }
286 }
287 }
288 return pOperate;
289}
291
293{
294 qDebug(log) << Q_FUNC_INFO;
295 if(!p) return 0;
296
297 CPlugin* pPlugin = nullptr;
298 //pPlugin->GetPlugin();
299 bool bRet = QMetaObject::invokeMethod(
300 p,
301 "GetPlugin",
302 Qt::DirectConnection,
303 Q_RETURN_ARG(CPlugin*, pPlugin));
304
305 if(bRet && pPlugin) {
306 int nRet = 0;
307 //pPlugin->DeleteOperate(p);
308 bRet = QMetaObject::invokeMethod(
309 pPlugin,
310 "DeleteOperate",
311 Qt::DirectConnection,
312 Q_RETURN_ARG(int, nRet),
313 Q_ARG(COperate*, p));
314 if(!bRet) {
315 nRet = -1;
316 qCritical(log) << "Call pPlugin->DeleteOperate(p) fail";
317 }
318 return nRet;
319 }
320
321 qCritical(log) << "Get CManager fail.";
322 return -1;
323}
324
325COperate* CManager::LoadOperate(const QString &szFile)
326{
327 COperate* pOperate = nullptr;
328 if(szFile.isEmpty()) return nullptr;
329 qDebug(log) << "Load operate configure file:"<< szFile;
330 QSettings set(szFile, QSettings::IniFormat);
331 m_FileVersion = set.value("Manage/FileVersion", m_FileVersion).toInt();
332 QString id = set.value("Plugin/ID").toString();
333 QString protocol = set.value("Plugin/Protocol").toString();
334 QString name = set.value("Plugin/Name").toString();
335 qDebug(log) << "LoadOperate protocol:" << protocol
336 << "name:" << name << "id:" << id;
337 pOperate = CreateOperate(id);
338 if(pOperate) {
339 int nRet = false;
340 //bRet = pOperate->Load(szFile);
341 bool bRet = QMetaObject::invokeMethod(
342 pOperate,
343 "Load",
344 Qt::DirectConnection,
345 Q_RETURN_ARG(int, nRet),
346 Q_ARG(QString, szFile));
347 if(!bRet) {
348 qCritical(log) << "Call pOperate->Load(szFile) fail.";
349 return nullptr;
350 }
351 if(nRet) {
352 qCritical(log) << "Load parameter fail" << nRet;
353 DeleteOperate(pOperate);
354 return nullptr;
355 }
356 pOperate->SetSettingsFile(szFile);
357 }
358 else
359 qCritical(log) << "Don't create Operate:" << name << protocol << id << szFile;
360
361 return pOperate;
362}
363
365{
366 if(!pOperate) return -1;
367
368 QString szFile = pOperate->GetSettingsFile();
369 if(szFile.isEmpty())
370 szFile = RabbitCommon::CDir::Instance()->GetDirUserData()
371 + QDir::separator()
372 + pOperate->Id()
373 + ".rrc";
374
375 QSettings set(szFile, QSettings::IniFormat);
376
377 CPlugin* pPlugin = nullptr; //pOperate->GetPlugin;
378 bool bRet = QMetaObject::invokeMethod(
379 pOperate,
380 "GetPlugin",
381 Qt::DirectConnection,
382 Q_RETURN_ARG(CPlugin*, pPlugin));
383 if(!bRet || !pPlugin)
384 {
385 qCritical(log) << "Get plugin client fail";
386 }
387 Q_ASSERT(pPlugin);
388
389 set.setValue("Manage/FileVersion", m_FileVersion);
390 set.setValue("Plugin/ID", pPlugin->Id());
391 set.setValue("Plugin/Protocol", pPlugin->Protocol());
392 set.setValue("Plugin/Name", pPlugin->Name());
393 int nRet = 0;
394 //nRet = pOperate->Save(szFile);
395 bRet = QMetaObject::invokeMethod(
396 pOperate,
397 "Save",
398 Qt::DirectConnection,
399 Q_RETURN_ARG(int, nRet),
400 Q_ARG(QString, szFile));
401 if(!bRet) {
402 qCritical(log) << "Call pOperate->Save(szFile) fail.";
403 return -1;
404 }
405 if(nRet) {
406 qCritical(log) << "Save parameter fail" << nRet;
407 return -2;
408 }
409 return 0;
410}
411
412int CManager::LoadSettings(const QString szFile)
413{
414 if(!m_pParameter) {
415 qCritical(log) << "The m_pParameter is nullptr";
416 Q_ASSERT_X(m_pParameter, "CManager", "The m_pParameter is nullptr");
417 return -1;
418 }
419
420 QString s = szFile;
421 if(s.isEmpty())
422 s = m_szSettingsFile;
423 return m_pParameter->Load(s);
424}
425
426int CManager::SaveSettings(const QString szFile)
427{
428 if(!m_pParameter) {
429 qCritical(log) << "The m_pParameter is nullptr";
430 Q_ASSERT_X(m_pParameter, "CManager", "The m_pParameter is nullptr");
431 return -1;
432 }
433
434 QString s = szFile;
435 if(s.isEmpty())
436 s = m_szSettingsFile;
437 return m_pParameter->Save(s);
438}
439
440QList<QWidget*> CManager::GetSettingsWidgets(QWidget* parent)
441{
442 QList<QWidget*> lstWidget;
443
444 CParameterPluginUI* pClient = new CParameterPluginUI(parent);
445 if(pClient) {
446 pClient->SetParameter(m_pParameter);
447 lstWidget.push_back(pClient);
448 }
449#if defined(HAVE_QTERMWIDGET)
450 CParameterTerminalUI* pTermina = new CParameterTerminalUI(parent);
451 if(pTermina) {
452 pTermina->SetParameter(&m_pParameter->m_Terminal);
453 pTermina->setWindowTitle(tr("Terminal"));
454 lstWidget.push_back(pTermina);
455 }
456#endif
457 CParameterRecordUI* pRecord = new CParameterRecordUI(parent);
458 if(pRecord) {
459 pRecord->SetParameter(&m_pParameter->m_Record);
460 lstWidget.push_back(pRecord);
461 }
462
463 return lstWidget;
464}
465
467{
468 int nRet = 0;
469 QMap<QString, CPlugin*>::iterator it;
470 for(it = m_Plugins.begin(); it != m_Plugins.end(); it++)
471 {
472 nRet = handle->onProcess(it.key(), it.value());
473 if(nRet)
474 return nRet;
475 }
476 return nRet;
477}
478
479#if HAS_CPP_11
480int CManager::EnumPlugins(std::function<int(const QString &, CPlugin *)> cb)
481{
482 int nRet = 0;
483 QMap<QString, CPlugin*>::iterator it;
484 for(it = m_Plugins.begin(); it != m_Plugins.end(); it++)
485 {
486 nRet = cb(it.key(), it.value());
487 if(nRet)
488 return nRet;
489 }
490 return nRet;
491}
492#endif
493
494const QString CManager::Details() const
495{
496 QString szDetail;
497#if HAVE_QTERMWIDGET
498 szDetail += COperateTerminal::Details();
499#endif
500#ifdef HAVE_LIBSSH
501 CChannelSSH channel(nullptr, nullptr);
502 szDetail += channel.GetDetails();
503#endif
504#if HAVE_QTKEYCHAIN
505 szDetail += "- QtKeyChain\n" +
506 QString(" - ") + tr("Version:")
507 + " 0x" + QString::number(QTKEYCHAIN_VERSION, 16) + "\n";
508#endif
509
510 if(!szDetail.isEmpty()) {
511 szDetail = "## " + tr("Dependency libraries:") + "\n" + szDetail;
512 }
513 szDetail += m_szDetails;
514 return szDetail;
515}
516
517void CManager::slotNativeWindowRecieveKeyboard()
518{
519 Q_ASSERT(m_pParameter);
520 if(m_pParameter->GetNativeWindowReceiveKeyboard()) {
521 if(m_pHook) {
522 m_pHook->UnRegisterKeyboard();
523 m_pHook->deleteLater();
524 m_pHook = nullptr;
525 }
526 } else {
527 if(m_pHook) return;
528 m_pHook = CHook::GetHook(m_pParameter, this);
529 if(m_pHook)
530 m_pHook->RegisterKeyboard();
531 }
532}
static int RemoveTranslation()
Remove translation
Definition Channel.cpp:138
static int InitTranslation()
Initial translation
Definition Channel.cpp:130
处理连接者。用于客户端得到连接者信号
Definition Manager.h:145
virtual int onProcess(const QString &id, CPlugin *pPlugin)=0
Process plugins
管理插件
Definition Manager.h:45
virtual QList< QWidget * > GetSettingsWidgets(QWidget *parent)
得到设置参数窗口
Definition Manager.cpp:440
virtual int EnumPlugins(Handle *handle)
Enum plugins
Definition Manager.cpp:466
virtual COperate * CreateOperate(const QString &id)
新建 COperate 指针,所有者是调用者。 当不在使用时,调用者必调用 DeteleOperate() 须释放指针。 调用者必须连接信号 COperate::sigFinished 。 释放指针 (...
Definition Manager.cpp:264
virtual COperate * LoadOperate(const QString &szFile)
从文件中新建 COperate 指针,所有者是调用者。 当不再使用时,调用者必须负责调用 DeleteOperate() 删除此指针。 调用者必须连接信号 COperate::sigFinished 。...
Definition Manager.cpp:325
virtual int DeleteOperate(COperate *p)
Delete COperate
Definition Manager.cpp:292
virtual int SaveOperate(COperate *pOperate)
保存连接参数到文件
Definition Manager.cpp:364
virtual int SaveSettings(const QString szFile=QString())
保存客户端参数到文件
Definition Manager.cpp:426
virtual int LoadSettings(const QString szFile=QString())
从文件中加载客户端参数
Definition Manager.cpp:412
操作接口。
Definition Operate.h:51
virtual const QString Id()
Identity
Definition Operate.cpp:33
virtual int SetParameter(CParameter *pParameter) override
[override functions]
插件的全局参数。
virtual int SetParameter(CParameter *pParameter) override
[override functions]
virtual int Save(QString szFile=QString(), bool bForce=true)
Save to file
Definition Parameter.cpp:47
virtual int Load(QString szFile=QString())
Load from file
Definition Parameter.cpp:35
插件接口
Definition Plugin.h:15
virtual const QString Version() const =0
Version
virtual const QString Details() const
显示更多细节。 例如: 在关于对话框或日志中显示。 包括插件的依赖库的版本信息和描述
Definition Plugin.cpp:78
virtual const QString Id()
标识。默认: Type() + ":" + Protocol() + ":" + Name()
Definition Plugin.cpp:68
virtual const QString Name() const =0
插件名,这个名一定要与工程名(${PROJECT_NAME})相同。 翻译文件(${PROJECT_NAME}_*.ts))名与其相关。
virtual const QString DisplayName() const
在界面上显示的名称
Definition Plugin.cpp:73
virtual const QString Protocol() const =0
协议
virtual const QString Description() const =0
描述