#pragma once #include "session.h" Session::Session(QObject *parent, MainQMLAdaptor* main_gui) : QObject(parent) { _initDBus(); _main_gui = main_gui; // QML -> MainQMLAdaptor::handleConnectButtonClick --onConnectButtonClick--> this::handleConnectButtonClick QObject::connect(_main_gui, SIGNAL(onConnectButtonClick(bool)), this, SLOT(handleConnectButtonClick(bool))); // session::setPin --pinChanged--> MainQMLAdaptor::setPin --pinChanged--> QML QObject::connect(this, SIGNAL(pinChanged(QString)), main_gui, SLOT(setPin(QString))); // session::setURL --urlChanged--> MainQMLAdaptor::setURL --urlChanged--> QML QObject::connect(this, SIGNAL(urlChanged(QString)), main_gui, SLOT(setURL(QString))); // QML -> MainQMLAdaptor::onCloseHandler --onCloseSignal--> session::onCloseHandler QObject::connect(main_gui, SIGNAL(onCloseSignal()), this, SLOT(onCloseHandler())); this->init_vars(); } void Session::statusTimerEvent() { qDebug() << "Status timer event triggered"; this->refresh_status_request_dbus(this->getId()); } void Session::init_vars() { setPin("-----"); setId(-1); setURL(tr("Not available yet")); setStatus("unknown"); _main_gui->setConnectButtonChecked(false); _main_gui->setConnectButtonEnabled(true); _main_gui->setStatusIndicator(false); _minimizedBefore = false; } QString Session::getStatus() { return _status; } QString Session::getURL() { return _url; } int Session::getId() { return _id; } QString Session::getPin() { return _pin; } bool Session::isSessionAliveOrRunning(QString status) { if (status.length() > 0 && (status == "running" || status == "active")) { return true; } else { return false; } } void Session::setStatus(QString status) { _status = status; QString guiString = tr("Unknown state of service"); _main_gui->setStatusIndicator(false); if (status == "running") { /* Session is running but no one is connected yet */ guiString = tr("Remote Support session is ready to be connected to"); _main_gui->setStatusIndicator(true, QColor(255, 255, 0, 127)); } else if (status == "dead") { /* Session died */ guiString = tr("Remote Support session was stopped ungracefully"); // Clear current variables this->init_vars(); _main_gui->setStatusIndicator(true, QColor(255, 0, 0, 127)); emit _main_gui->showWindow(); } else if (status == "stopped") { /* Session is stopped */ guiString = tr("Remote Support session was stopped"); // Clear current variables this->init_vars(); emit _main_gui->showWindow(); } else if (status == "active") { /* Partner is connected */ if (!_minimizedBefore) { qDebug() << "Minimizing window now..."; emit _main_gui->minimizeWindow(); _minimizedBefore = true; } guiString = tr("Your partner is connected to the Remote Support session"); _main_gui->setStatusIndicator(true, QColor(0, 255, 0, 127)); } else if (status == "waiting_start_request_answer") { /* When pressing on start button display following message while waiting */ guiString = tr("Trying to reach session service..."); } _main_gui->setStatus(guiString); emit statusChanged(_status); } void Session::setURL(QString url) { _url = url; emit urlChanged(url); } void Session::setId(int id) { _id = id; emit idChanged(id); } void Session::setPin(QString pin) { _pin = pin; emit pinChanged(pin); } void Session::handleConnectButtonClick(bool checked) { qDebug() << "-----Connect button handler-----\nCurrent session #" << this->getId(); // Stopping even if nothing is running this->stop(this->getId()); if (checked) { // Start the Session again this->start(); } qDebug() << "-----\\Connect button handler-----"; } void Session::_initDBus() { if (!QDBusConnection::sessionBus().isConnected()) { qCritical() << "Cannot connect to the D-Bus session bus."; } // Create DBus object _dbus_rwa = new OrgArcticaProjectRWAInterface("org.ArcticaProject.RWA", "/RWA", QDBusConnection::sessionBus(), this->parent()); qDebug("Initialized DBus object!"); } void Session::start() { qDebug() << "Requesting D-Bus session service to start a new session"; // Make an asynchrous 'start' call (Response will be sent to 'start_dbus_replied') QDBusPendingCall async = _dbus_rwa->asyncCall("start"); QDBusPendingCallWatcher *watcher = new QDBusPendingCallWatcher(async, this); QObject::connect(watcher, SIGNAL(finished(QDBusPendingCallWatcher*)), this, SLOT(start_dbus_replied(QDBusPendingCallWatcher*))); // Disable connect button to reduce spam. // And don't enable it as long there is no status update. // (Or something fails) _main_gui->setConnectButtonEnabled(false); this->setStatus("waiting_start_request_answer"); } void Session::start_dbus_replied(QDBusPendingCallWatcher *call) { QString result = ""; QDBusPendingReply reply = *call; if (reply.isError()) { qCritical("Error: cannot parse 'start' reply from D-Bus service"); qDebug() << "The reply" << reply.error(); // The user should have the oportunity to try again. this->init_vars(); _main_gui->openMessageDialog(tr("Remote Support for your Desktop"), tr("D-Bus response was invalid.\nFunction call: '%1'\nMaybe service isn't listening?").arg("start"), QMessageBox::Icon::Critical); return; } else { result = reply.argumentAt<0>(); } call->deleteLater(); qDebug() << "Raw JSON from starting session is:" << result; QJsonDocument doc = QJsonDocument::fromJson(result.toUtf8()); // Get the QJsonObject QJsonObject jObject = doc.object(); QVariantMap mainMap = jObject.toVariantMap(); // Session ID == PID int sessionid = mainMap["id"].toInt(); this->setId(sessionid); // URL of remote web app frontend QString url = mainMap["url"].toString(); this->setURL(url); // PIN QString pin = mainMap["pin"].toString(); this->setPin(pin); qDebug() << "Got session id:" << sessionid; qDebug() << "Got url:" << url; qDebug() << "Got pin:" << pin; this->getStatus(); emit pinChanged(pin); emit urlChanged(url); emit idChanged(sessionid); statusTimer->start(1000); } void Session::stop(int pid) { if (pid <= 0 ){ qDebug() << "Won't send a request to D-Bus service to stop a session when session ID <= 0"; return; } // Stopping now. qDebug() << "Requesting D-Bus session service to stop session #" << pid; // Make an asynchrous 'stop' call (Response will be sent to 'stop_dbus_replied') QDBusPendingCall async = _dbus_rwa->asyncCall("stop", pid); QDBusPendingCallWatcher *watcher = new QDBusPendingCallWatcher(async, this); QObject::connect(watcher, SIGNAL(finished(QDBusPendingCallWatcher*)), this, SLOT(stop_dbus_replied(QDBusPendingCallWatcher*))); // Clear current variables this->init_vars(); // Disable connect button to reduce spam. // And don't enable it as long there is no status update. // (Or something fails) _main_gui->setConnectButtonEnabled(false); } void Session::stop_dbus_replied(QDBusPendingCallWatcher *call) { QString result = ""; QDBusPendingReply reply = *call; if (reply.isError()) { qCritical("Error: cannot parse 'stop' reply from D-Bus service"); qDebug() << "The reply" << reply.error(); this->init_vars(); _main_gui->openMessageDialog(tr("Remote Support for your Desktop"), tr("D-Bus response was invalid.\nFunction call: '%1'\nMaybe service isn't listening?").arg("stop"), QMessageBox::Icon::Critical); return; } else { result = reply.argumentAt<0>(); } call->deleteLater(); // Get the QJsonObject QJsonDocument doc = QJsonDocument::fromJson(result.toUtf8()); QJsonObject jObject = doc.object(); QVariantMap mainMap = jObject.toVariantMap(); qDebug() << "Refreshed status:" << mainMap["status"].toString(); this->setStatus(mainMap["status"].toString()); // Clear current variables this->init_vars(); } void Session::status(int pid) { // Requesting status now. qDebug() << "Requesting status for session #" << pid; // Make an asynchrous 'status' call (Response will be sent to 'status_dbus_replied') QDBusPendingCall async = _dbus_rwa->asyncCall("status", pid); QDBusPendingCallWatcher *watcher = new QDBusPendingCallWatcher(async, this); QObject::connect(watcher, SIGNAL(finished(QDBusPendingCallWatcher*)), this, SLOT(stop_dbus_replied(QDBusPendingCallWatcher*))); } void Session::refresh_status(int pid) { // Refreshing status qDebug() << "Requesting status refresh for session #" << pid; // Make an asynchrous 'refresh_status' call (Response will be sent to 'status_dbus_replied') QDBusPendingCall async = _dbus_rwa->asyncCall("refresh_status", pid); QDBusPendingCallWatcher *watcher = new QDBusPendingCallWatcher(async, this); QObject::connect(watcher, SIGNAL(finished(QDBusPendingCallWatcher*)), this, SLOT(status_dbus_replied(QDBusPendingCallWatcher*))); } void Session::status_dbus_replied(QDBusPendingCallWatcher *call) { QString result = ""; QDBusPendingReply reply = *call; if (reply.isError()) { qCritical("Error: cannot parse 'status' reply from D-Bus service"); qDebug() << "The reply" << reply.error(); _main_gui->openMessageDialog(tr("Remote Support for your Desktop"), tr("D-Bus response was invalid.\nFunction call: '%1'\nMaybe service isn't listening?").arg("status"), QMessageBox::Icon::Critical); // Includes stopping status-refreshing timer this->init_vars(); return; } else { result = reply.argumentAt<0>(); } call->deleteLater(); // Get the QJsonObject QJsonDocument doc = QJsonDocument::fromJson(result.toUtf8()); QJsonObject jObject = doc.object(); QVariantMap mainMap = jObject.toVariantMap(); qDebug() << "Refreshed status:" << mainMap["status"].toString(); this->setStatus(mainMap["status"].toString()); // Enable (dis)connect button _main_gui->setConnectButtonEnabled(true); if (this->isSessionAliveOrRunning(new_status)) { // Ask status every 1000 millisecond QTimer::singleShot(1000, this, &Session::statusTimerEvent); } } void Session::onCloseHandler() { // To cleanup things here this->stop(this->getId()); }