Improve systemd integration

* Allow using systemd unit status to better handle
  reconnect attempts to local instance
* Misc adjustments
This commit is contained in:
Martchus 2016-12-27 16:16:12 +01:00
parent 1c2c77b4ec
commit 3cadd8cbcb
9 changed files with 94 additions and 45 deletions

View File

@ -61,6 +61,8 @@ SyncthingService::SyncthingService(QObject *parent) :
connect(s_manager, &OrgFreedesktopSystemd1ManagerInterface::UnitNew, this, &SyncthingService::handleUnitAdded); connect(s_manager, &OrgFreedesktopSystemd1ManagerInterface::UnitNew, this, &SyncthingService::handleUnitAdded);
connect(s_manager, &OrgFreedesktopSystemd1ManagerInterface::UnitRemoved, this, &SyncthingService::handleUnitRemoved); connect(s_manager, &OrgFreedesktopSystemd1ManagerInterface::UnitRemoved, this, &SyncthingService::handleUnitRemoved);
m_serviceWatcher = new QDBusServiceWatcher(s_manager->service(), s_manager->connection()); m_serviceWatcher = new QDBusServiceWatcher(s_manager->service(), s_manager->connection());
connect(m_serviceWatcher, &QDBusServiceWatcher::serviceRegistered, this, &SyncthingService::handleServiceRegisteredChanged);
connect(m_serviceWatcher, &QDBusServiceWatcher::serviceUnregistered, this, &SyncthingService::handleServiceRegisteredChanged);
} }
void SyncthingService::setUnitName(const QString &unitName) void SyncthingService::setUnitName(const QString &unitName)
@ -91,18 +93,18 @@ bool SyncthingService::isUnitAvailable() const
void SyncthingService::setRunning(bool running) void SyncthingService::setRunning(bool running)
{ {
if(running) { if(running) {
registerErrorHandler(s_manager->StartUnit(m_unitName, QStringLiteral("replace")), QT_TR_NOOP_UTF8("starting unit")); registerErrorHandler(s_manager->StartUnit(m_unitName, QStringLiteral("replace")), QT_TR_NOOP_UTF8("start unit"));
} else { } else {
registerErrorHandler(s_manager->StopUnit(m_unitName, QStringLiteral("replace")), QT_TR_NOOP_UTF8("stopping unit")); registerErrorHandler(s_manager->StopUnit(m_unitName, QStringLiteral("replace")), QT_TR_NOOP_UTF8("stop unit"));
} }
} }
void SyncthingService::setEnabled(bool enabled) void SyncthingService::setEnabled(bool enabled)
{ {
if(enabled) { if(enabled) {
registerErrorHandler(s_manager->EnableUnitFiles(QStringList(m_unitName), false, true), QT_TR_NOOP_UTF8("enabling unit")); registerErrorHandler(s_manager->EnableUnitFiles(QStringList(m_unitName), false, true), QT_TR_NOOP_UTF8("enable unit"));
} else { } else {
registerErrorHandler(s_manager->DisableUnitFiles(QStringList(m_unitName), false), QT_TR_NOOP_UTF8("disabling unit")); registerErrorHandler(s_manager->DisableUnitFiles(QStringList(m_unitName), false), QT_TR_NOOP_UTF8("disable unit"));
} }
} }
@ -164,6 +166,13 @@ void SyncthingService::handleError(const char *context, QDBusPendingCallWatcher
} }
} }
void SyncthingService::handleServiceRegisteredChanged(const QString &service)
{
if(service == s_manager->service()) {
emit systemdAvailableChanged(s_manager->isValid());
}
}
bool SyncthingService::handlePropertyChanged(QString &variable, void (SyncthingService::*signal)(const QString &), const QString &propertyName, const QVariantMap &changedProperties, const QStringList &invalidatedProperties) bool SyncthingService::handlePropertyChanged(QString &variable, void (SyncthingService::*signal)(const QString &), const QString &propertyName, const QVariantMap &changedProperties, const QStringList &invalidatedProperties)
{ {
const QVariant valueVariant(changedProperties[propertyName]); const QVariant valueVariant(changedProperties[propertyName]);

View File

@ -81,6 +81,7 @@ private Q_SLOTS:
void handleUnitGet(QDBusPendingCallWatcher *watcher); void handleUnitGet(QDBusPendingCallWatcher *watcher);
void handlePropertiesChanged(const QString &interface, const QVariantMap &changedProperties, const QStringList &invalidatedProperties); void handlePropertiesChanged(const QString &interface, const QVariantMap &changedProperties, const QStringList &invalidatedProperties);
void handleError(const char *error, QDBusPendingCallWatcher *watcher); void handleError(const char *error, QDBusPendingCallWatcher *watcher);
void handleServiceRegisteredChanged(const QString &service);
void setUnit(const QDBusObjectPath &objectPath); void setUnit(const QDBusObjectPath &objectPath);
void setProperties(const QString &activeState, const QString &subState, const QString &unitFileState, const QString &description); void setProperties(const QString &activeState, const QString &subState, const QString &unitFileState, const QString &description);

View File

@ -38,7 +38,7 @@ void handleSystemdServiceError(const QString &context, const QString &name, cons
QMessageBox msgBox; QMessageBox msgBox;
msgBox.setIcon(QMessageBox::Critical); msgBox.setIcon(QMessageBox::Critical);
msgBox.setText(QCoreApplication::translate("main", "Unable to ") + context); msgBox.setText(QCoreApplication::translate("main", "Unable to ") + context);
msgBox.setInformativeText(name % QStringLiteral(": ") % message); msgBox.setInformativeText(name % QStringLiteral(":\n") % message);
msgBox.exec(); msgBox.exec();
} }
#endif #endif

View File

@ -100,6 +100,7 @@ void restore()
auto &systemd = v.systemd; auto &systemd = v.systemd;
systemd.syncthingUnit = settings.value(QStringLiteral("syncthingUnit"), systemd.syncthingUnit).toString(); systemd.syncthingUnit = settings.value(QStringLiteral("syncthingUnit"), systemd.syncthingUnit).toString();
systemd.showButton = settings.value(QStringLiteral("showButton"), systemd.showButton).toBool(); systemd.showButton = settings.value(QStringLiteral("showButton"), systemd.showButton).toBool();
systemd.considerForReconnect = settings.value(QStringLiteral("considerForReconnect"), systemd.considerForReconnect).toBool();
#endif #endif
settings.endGroup(); settings.endGroup();
@ -167,6 +168,7 @@ void save()
const auto &systemd = v.systemd; const auto &systemd = v.systemd;
settings.setValue(QStringLiteral("syncthingUnit"), systemd.syncthingUnit); settings.setValue(QStringLiteral("syncthingUnit"), systemd.syncthingUnit);
settings.setValue(QStringLiteral("showButton"), systemd.showButton); settings.setValue(QStringLiteral("showButton"), systemd.showButton);
settings.setValue(QStringLiteral("considerForReconnect"), systemd.considerForReconnect);
#endif #endif
settings.endGroup(); settings.endGroup();

View File

@ -66,7 +66,8 @@ struct Launcher
struct Systemd struct Systemd
{ {
QString syncthingUnit = QStringLiteral("syncthing.service"); QString syncthingUnit = QStringLiteral("syncthing.service");
bool showButton = true; bool showButton = false;
bool considerForReconnect = false;
}; };
#endif #endif

View File

@ -596,6 +596,7 @@ bool SystemdOptionPage::apply()
auto &settings = values().systemd; auto &settings = values().systemd;
settings.syncthingUnit = ui()->syncthingUnitLineEdit->text(); settings.syncthingUnit = ui()->syncthingUnitLineEdit->text();
settings.showButton = ui()->showButtonCheckBox->isChecked(); settings.showButton = ui()->showButtonCheckBox->isChecked();
settings.considerForReconnect = ui()->considerForReconnectCheckBox->isChecked();
} }
return true; return true;
} }
@ -606,6 +607,7 @@ void SystemdOptionPage::reset()
const auto &settings = values().systemd; const auto &settings = values().systemd;
ui()->syncthingUnitLineEdit->setText(settings.syncthingUnit); ui()->syncthingUnitLineEdit->setText(settings.syncthingUnit);
ui()->showButtonCheckBox->setChecked(settings.showButton); ui()->showButtonCheckBox->setChecked(settings.showButton);
ui()->considerForReconnectCheckBox->setChecked(settings.considerForReconnect);
handleDescriptionChanged(m_service.description()); handleDescriptionChanged(m_service.description());
handleStatusChanged(m_service.activeState(), m_service.subState()); handleStatusChanged(m_service.activeState(), m_service.subState());
handleEnabledChanged(m_service.unitFileState()); handleEnabledChanged(m_service.unitFileState());
@ -614,7 +616,7 @@ void SystemdOptionPage::reset()
void SystemdOptionPage::handleDescriptionChanged(const QString &description) void SystemdOptionPage::handleDescriptionChanged(const QString &description)
{ {
ui()->descriptionValueLabel->setText(description.isEmpty() ? QCoreApplication::translate("QtGui::SystemdOptionPage", "specified unit is unknown") : description); ui()->descriptionValueLabel->setText(description.isEmpty() ? QCoreApplication::translate("QtGui::SystemdOptionPage", "specified unit is either inactive or doesn't exist") : description);
} }
void setIndicatorColor(QWidget *indicator, const QColor &color) void setIndicatorColor(QWidget *indicator, const QColor &color)
@ -642,7 +644,7 @@ void SystemdOptionPage::handleStatusChanged(const QString &activeState, const QS
? Colors::green(values().appearance.brightTextColors) ? Colors::green(values().appearance.brightTextColors)
: Colors::red(values().appearance.brightTextColors)) : Colors::red(values().appearance.brightTextColors))
); );
ui()->startPushButton->setVisible(!status.isEmpty() && !isRunning); ui()->startPushButton->setVisible(!isRunning);
ui()->stopPushButton->setVisible(!status.isEmpty() && isRunning); ui()->stopPushButton->setVisible(!status.isEmpty() && isRunning);
} }
@ -653,7 +655,7 @@ void SystemdOptionPage::handleEnabledChanged(const QString &unitFileState)
setIndicatorColor(ui()->enabledIndicator, isEnabled setIndicatorColor(ui()->enabledIndicator, isEnabled
? Colors::green(values().appearance.brightTextColors) ? Colors::green(values().appearance.brightTextColors)
: Colors::gray(values().appearance.brightTextColors)); : Colors::gray(values().appearance.brightTextColors));
ui()->enablePushButton->setVisible(!unitFileState.isEmpty() && !isEnabled); ui()->enablePushButton->setVisible(!isEnabled);
ui()->disablePushButton->setVisible(!unitFileState.isEmpty() && isEnabled); ui()->disablePushButton->setVisible(!unitFileState.isEmpty() && isEnabled);
} }
#endif #endif

View File

@ -15,7 +15,23 @@
</font> </font>
</property> </property>
<property name="text"> <property name="text">
<string>Show start/stop button on tray for local instance when specified unit available</string> <string>Show start/stop button on tray for local instance when systemd is available</string>
</property>
</widget>
</item>
<item>
<widget class="QCheckBox" name="considerForReconnectCheckBox">
<property name="text">
<string>Consider systemd unit status for reconnect attempts to local instance
• Don't reconnect when unit not active/running
• Try to reconnect when unit becomes active/running</string>
</property>
</widget>
</item>
<item>
<widget class="Line" name="line">
<property name="orientation">
<enum>Qt::Horizontal</enum>
</property> </property>
</widget> </widget>
</item> </item>
@ -50,20 +66,7 @@
<item row="0" column="1"> <item row="0" column="1">
<widget class="Widgets::ClearLineEdit" name="syncthingUnitLineEdit"/> <widget class="Widgets::ClearLineEdit" name="syncthingUnitLineEdit"/>
</item> </item>
<item row="1" column="1"> <item row="1" column="0">
<widget class="Line" name="line1">
<property name="sizePolicy">
<sizepolicy hsizetype="MinimumExpanding" vsizetype="Fixed">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="orientation">
<enum>Qt::Horizontal</enum>
</property>
</widget>
</item>
<item row="2" column="0">
<widget class="QLabel" name="descriptionLabel"> <widget class="QLabel" name="descriptionLabel">
<property name="sizePolicy"> <property name="sizePolicy">
<sizepolicy hsizetype="Preferred" vsizetype="Expanding"> <sizepolicy hsizetype="Preferred" vsizetype="Expanding">
@ -76,7 +79,7 @@
</property> </property>
</widget> </widget>
</item> </item>
<item row="2" column="1"> <item row="1" column="1">
<layout class="QHBoxLayout" name="descriptionHorizontalLayout"> <layout class="QHBoxLayout" name="descriptionHorizontalLayout">
<item> <item>
<widget class="QLabel" name="descriptionValueLabel"> <widget class="QLabel" name="descriptionValueLabel">
@ -99,7 +102,7 @@
</item> </item>
</layout> </layout>
</item> </item>
<item row="3" column="0"> <item row="2" column="0">
<widget class="QLabel" name="statusLabel"> <widget class="QLabel" name="statusLabel">
<property name="sizePolicy"> <property name="sizePolicy">
<sizepolicy hsizetype="Preferred" vsizetype="Expanding"> <sizepolicy hsizetype="Preferred" vsizetype="Expanding">
@ -112,7 +115,7 @@
</property> </property>
</widget> </widget>
</item> </item>
<item row="3" column="1"> <item row="2" column="1">
<layout class="QHBoxLayout" name="statusHorizontalLayout"> <layout class="QHBoxLayout" name="statusHorizontalLayout">
<item> <item>
<widget class="QWidget" name="statusIndicator" native="true"> <widget class="QWidget" name="statusIndicator" native="true">
@ -176,7 +179,7 @@
</item> </item>
</layout> </layout>
</item> </item>
<item row="4" column="0"> <item row="3" column="0">
<widget class="QLabel" name="unitFileStateLabel"> <widget class="QLabel" name="unitFileStateLabel">
<property name="sizePolicy"> <property name="sizePolicy">
<sizepolicy hsizetype="Preferred" vsizetype="Expanding"> <sizepolicy hsizetype="Preferred" vsizetype="Expanding">
@ -189,7 +192,7 @@
</property> </property>
</widget> </widget>
</item> </item>
<item row="4" column="1"> <item row="3" column="1">
<layout class="QHBoxLayout" name="unitFileStateHorizontalLayout"> <layout class="QHBoxLayout" name="unitFileStateHorizontalLayout">
<item> <item>
<widget class="QWidget" name="enabledIndicator" native="true"> <widget class="QWidget" name="enabledIndicator" native="true">

View File

@ -146,7 +146,8 @@ TrayWidget::TrayWidget(TrayMenu *parent) :
#ifdef LIB_SYNCTHING_CONNECTOR_SUPPORT_SYSTEMD #ifdef LIB_SYNCTHING_CONNECTOR_SUPPORT_SYSTEMD
const SyncthingService &service = syncthingService(); const SyncthingService &service = syncthingService();
connect(m_ui->startStopPushButton, &QPushButton::clicked, &service, &SyncthingService::toggleRunning); connect(m_ui->startStopPushButton, &QPushButton::clicked, &service, &SyncthingService::toggleRunning);
connect(&service, &SyncthingService::stateChanged, this, &TrayWidget::updateStartStopButton); connect(&service, &SyncthingService::systemdAvailableChanged, this, &TrayWidget::handleSystemdStatusChanged);
connect(&service, &SyncthingService::stateChanged, this, &TrayWidget::handleSystemdStatusChanged);
#endif #endif
} }
@ -385,7 +386,7 @@ void TrayWidget::applySettings()
// systemd // systemd
#ifdef LIB_SYNCTHING_CONNECTOR_SUPPORT_SYSTEMD #ifdef LIB_SYNCTHING_CONNECTOR_SUPPORT_SYSTEMD
instance->updateStartStopButton(); instance->handleSystemdStatusChanged();
#endif #endif
// update visual appearance // update visual appearance
@ -493,25 +494,54 @@ void TrayWidget::updateTraffic()
} }
#ifdef LIB_SYNCTHING_CONNECTOR_SUPPORT_SYSTEMD #ifdef LIB_SYNCTHING_CONNECTOR_SUPPORT_SYSTEMD
void TrayWidget::updateStartStopButton() void TrayWidget::handleSystemdStatusChanged()
{ {
const SyncthingService &service = syncthingService(); const SyncthingService &service = syncthingService();
const Settings::Systemd &settings = Settings::values().systemd; const Settings::Systemd &settings = Settings::values().systemd;
const bool serviceRelevant = service.isSystemdAvailable() && isLocal(QUrl(m_connection.syncthingUrl()));
if(settings.showButton && service.isUnitAvailable() && m_selectedConnection && isLocal(QUrl(m_selectedConnection->syncthingUrl))) { if(serviceRelevant) {
m_ui->startStopPushButton->setVisible(true); const bool isRunning = service.isRunning();
if(service.isRunning()) { if(settings.showButton) {
m_ui->startStopPushButton->setText(tr("Stop")); m_ui->startStopPushButton->setVisible(true);
m_ui->startStopPushButton->setToolTip(QStringLiteral("systemctl --user stop ") + service.unitName()); if(isRunning) {
m_ui->startStopPushButton->setIcon(QIcon::fromTheme(QStringLiteral("process-stop"), QIcon(QStringLiteral(":/icons/hicolor/scalable/actions/process-stop.svg")))); m_ui->startStopPushButton->setText(tr("Stop"));
} else { m_ui->startStopPushButton->setToolTip(QStringLiteral("systemctl --user stop ") + service.unitName());
m_ui->startStopPushButton->setText(tr("Start")); m_ui->startStopPushButton->setIcon(QIcon::fromTheme(QStringLiteral("process-stop"), QIcon(QStringLiteral(":/icons/hicolor/scalable/actions/process-stop.svg"))));
m_ui->startStopPushButton->setToolTip(QStringLiteral("systemctl --user start ") + service.unitName()); } else {
m_ui->startStopPushButton->setIcon(QIcon::fromTheme(QStringLiteral("system-run"), QIcon(QStringLiteral(":/icons/hicolor/scalable/apps/system-run.svg")))); m_ui->startStopPushButton->setText(tr("Start"));
m_ui->startStopPushButton->setToolTip(QStringLiteral("systemctl --user start ") + service.unitName());
m_ui->startStopPushButton->setIcon(QIcon::fromTheme(QStringLiteral("system-run"), QIcon(QStringLiteral(":/icons/hicolor/scalable/apps/system-run.svg"))));
}
} }
} else { if(settings.considerForReconnect) {
if(isRunning && m_selectedConnection) {
// auto-reconnect might have been disabled when unit was inactive before, so re-enable it according current connection settings
m_connection.setAutoReconnectInterval(m_selectedConnection->reconnectInterval);
// and reconnect in 5 seconds (Syncthing needs a few seconds till the API becomes available)
QTimer::singleShot(5000, Qt::VeryCoarseTimer, this, &TrayWidget::connectIfServiceRunning);
} else {
// disable auto-reconnect if unit isn't running
m_connection.setAutoReconnectInterval(0);
}
}
}
if(!settings.showButton || !serviceRelevant) {
m_ui->startStopPushButton->setVisible(false); m_ui->startStopPushButton->setVisible(false);
} }
if((!settings.considerForReconnect || !serviceRelevant) && m_selectedConnection) {
m_connection.setAutoReconnectInterval(m_selectedConnection->reconnectInterval);
}
}
void TrayWidget::connectIfServiceRunning()
{
if(Settings::values().systemd.considerForReconnect
&& isLocal(QUrl(m_connection.syncthingUrl()))
&& syncthingService().isRunning()) {
m_connection.connect();
}
} }
#endif #endif
@ -538,7 +568,7 @@ void TrayWidget::handleConnectionSelected(QAction *connectionAction)
m_ui->connectionsPushButton->setText(m_selectedConnection->label); m_ui->connectionsPushButton->setText(m_selectedConnection->label);
m_connection.reconnect(*m_selectedConnection); m_connection.reconnect(*m_selectedConnection);
#ifdef LIB_SYNCTHING_CONNECTOR_SUPPORT_SYSTEMD #ifdef LIB_SYNCTHING_CONNECTOR_SUPPORT_SYSTEMD
updateStartStopButton(); handleSystemdStatusChanged();
#endif #endif
#ifndef SYNCTHINGTRAY_NO_WEBVIEW #ifndef SYNCTHINGTRAY_NO_WEBVIEW
if(m_webViewDlg) { if(m_webViewDlg) {

View File

@ -72,7 +72,8 @@ private slots:
void changeStatus(); void changeStatus();
void updateTraffic(); void updateTraffic();
#ifdef LIB_SYNCTHING_CONNECTOR_SUPPORT_SYSTEMD #ifdef LIB_SYNCTHING_CONNECTOR_SUPPORT_SYSTEMD
void updateStartStopButton(); void handleSystemdStatusChanged();
void connectIfServiceRunning();
#endif #endif
#ifndef SYNCTHINGTRAY_NO_WEBVIEW #ifndef SYNCTHINGTRAY_NO_WEBVIEW
void handleWebViewDeleted(); void handleWebViewDeleted();