HelperLauncher.cpp 5.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182
  1. //
  2. // Created by Tobias Hieta on 28/08/15.
  3. //
  4. #include "HelperLauncher.h"
  5. #include "QsLog.h"
  6. #include "settings/SettingsComponent.h"
  7. #include "settings/SettingsSection.h"
  8. #include "utils/Utils.h"
  9. #include "Names.h"
  10. #include <QTimer>
  11. /////////////////////////////////////////////////////////////////////////////////////////
  12. HelperLauncher::HelperLauncher(QObject* parent) : QObject(parent)
  13. {
  14. start();
  15. }
  16. /////////////////////////////////////////////////////////////////////////////////////////
  17. void HelperLauncher::start()
  18. {
  19. m_jsonClient = new LocalJsonClient("pmpHelper");
  20. connect(m_jsonClient, &QLocalSocket::connected, this, &HelperLauncher::didConnect);
  21. connect(m_jsonClient, static_cast<void (QLocalSocket::*)(QLocalSocket::LocalSocketError)>(&QLocalSocket::error), this, &HelperLauncher::socketError);
  22. connect(m_jsonClient, &LocalJsonClient::messageReceived, this, &HelperLauncher::gotMessage);
  23. connect(m_jsonClient, &QLocalSocket::disconnected, this, &HelperLauncher::socketDisconnect);
  24. #ifdef Q_OS_MAC
  25. m_launchd = new HelperLaunchd(this);
  26. #endif
  27. m_helperProcess = new QProcess(this);
  28. connect(SettingsComponent::Get().getSection(SETTINGS_SECTION_WEBCLIENT), &SettingsSection::valuesUpdated, [=](const QVariantMap& values)
  29. {
  30. if (values.contains("clientID"))
  31. updateClientId();
  32. });
  33. }
  34. /////////////////////////////////////////////////////////////////////////////////////////
  35. bool HelperLauncher::connectToHelper()
  36. {
  37. if (m_jsonClient->state() == QLocalSocket::ConnectedState ||
  38. m_jsonClient->state() == QLocalSocket::ConnectingState)
  39. return true;
  40. QLOG_DEBUG() << "Connecting to helper";
  41. m_jsonClient->connectToServer();
  42. return true;
  43. }
  44. /////////////////////////////////////////////////////////////////////////////////////////
  45. bool HelperLauncher::killHelper()
  46. {
  47. QVariantMap msg;
  48. msg.insert("command", "quit");
  49. m_jsonClient->sendMessage(msg);
  50. if (m_jsonClient->waitForBytesWritten(1000))
  51. {
  52. QLOG_DEBUG() << "Waiting for helper to die";
  53. if (!m_jsonClient->waitForDisconnected(3000))
  54. {
  55. QLOG_ERROR() << "Helper refused to disconnect. Didn't it get the PM?";
  56. return false;
  57. }
  58. QLOG_DEBUG() << "Helper gone";
  59. return true;
  60. }
  61. return false;
  62. }
  63. /////////////////////////////////////////////////////////////////////////////////////////
  64. void HelperLauncher::gotMessage(const QVariantMap& message)
  65. {
  66. if (message.value("version").toString() != Version::GetVersionString() ||
  67. message.value("path").toString() != HelperPath())
  68. {
  69. QLOG_WARN() << "Running helper does not match our current version. Killing it and starting a new one.";
  70. killHelper();
  71. }
  72. else
  73. {
  74. QLOG_DEBUG() << "Helper is running version:" << message.value("version").toString();
  75. }
  76. }
  77. /////////////////////////////////////////////////////////////////////////////////////////
  78. void HelperLauncher::socketError(QLocalSocket::LocalSocketError error)
  79. {
  80. QLOG_DEBUG() << "Failed to connect to helper:" << m_jsonClient->errorString();
  81. if (error == QLocalSocket::ConnectionRefusedError ||
  82. error == QLocalSocket::ServerNotFoundError)
  83. launch();
  84. }
  85. /////////////////////////////////////////////////////////////////////////////////////////
  86. void HelperLauncher::socketDisconnect()
  87. {
  88. QLOG_DEBUG() << "Disconnected from helper, trying to relaunch";
  89. connectToHelper();
  90. }
  91. /////////////////////////////////////////////////////////////////////////////////////////
  92. void HelperLauncher::updateClientId()
  93. {
  94. // update clientId if we have it
  95. if (!SettingsComponent::Get().value(SETTINGS_SECTION_WEBCLIENT, "clientID").toString().isEmpty())
  96. {
  97. QVariantMap msg;
  98. msg.insert("command", "info");
  99. QVariantMap arg;
  100. arg.insert("clientId", SettingsComponent::Get().value(SETTINGS_SECTION_WEBCLIENT, "clientID").toString());
  101. QString userId = Utils::CurrentUserId();
  102. if (!userId.isEmpty())
  103. arg.insert("userId", userId);
  104. msg.insert("argument", arg);
  105. m_jsonClient->sendMessage(msg);
  106. }
  107. };
  108. /////////////////////////////////////////////////////////////////////////////////////////
  109. void HelperLauncher::didConnect()
  110. {
  111. QLOG_DEBUG() << "Connected to helper";
  112. updateClientId();
  113. }
  114. /////////////////////////////////////////////////////////////////////////////////////////
  115. void HelperLauncher::launch()
  116. {
  117. QLOG_DEBUG() << "Launching helper:" << HelperPath();
  118. #ifdef Q_OS_MAC
  119. m_launchd->start();
  120. #else
  121. if (!m_helperProcess->startDetached(HelperPath(), QStringList()))
  122. {
  123. QLOG_ERROR() << "Failed to open helper: " + m_helperProcess->errorString();
  124. throw FatalException("Failed to launch helper: " + m_helperProcess->errorString());
  125. }
  126. #endif
  127. QTimer::singleShot(1000, this, &HelperLauncher::connectToHelper);
  128. }
  129. /////////////////////////////////////////////////////////////////////////////////////////
  130. QString HelperLauncher::HelperPath()
  131. {
  132. QString programName = Names::HelperName();
  133. #ifdef Q_OS_WIN
  134. programName += ".exe";
  135. #endif
  136. QString helperPath = SettingsComponent::Get().value(SETTINGS_SECTION_PATH, "helperprogram").toString();
  137. // fallback to the resource dir
  138. if (helperPath.isEmpty() || !QFile().exists(helperPath))
  139. helperPath = Paths::resourceDir(programName);
  140. if (!QFile().exists(helperPath))
  141. throw FatalException("Can't find helper program");
  142. return helperPath;
  143. }
  144. /////////////////////////////////////////////////////////////////////////////////////////
  145. void HelperLauncher::stop()
  146. {
  147. // this method needs to disconnect all signals from the helper as well, so it doesn't start up again.
  148. m_jsonClient->disconnect();
  149. killHelper();
  150. }