Only reconnect when relevant settings changed

This commit is contained in:
Martchus 2017-01-01 19:19:16 +01:00
parent d66bedf988
commit 7755e97c5f
7 changed files with 92 additions and 44 deletions

View File

@ -138,6 +138,18 @@ void SyncthingConnection::connect()
} }
} }
/*!
* \brief Applies the specified configuration and tries to reconnect via reconnect() if properties requiring reconnect
* to take effect have changed.
* \remarks The expected SSL errors of the specified configuration are updated accordingly.
*/
void SyncthingConnection::connect(SyncthingConnectionSettings &connectionSettings)
{
if(applySettings(connectionSettings)) {
reconnect();
}
}
/*! /*!
* \brief Disconnects. Does nothing if not connected. * \brief Disconnects. Does nothing if not connected.
*/ */
@ -620,8 +632,9 @@ QMetaObject::Connection SyncthingConnection::requestLog(std::function<void (cons
* - Loading the certificate is only possible if the connection object is configured * - Loading the certificate is only possible if the connection object is configured
* to connect to the locally running Syncthing instance. Otherwise this method will * to connect to the locally running Syncthing instance. Otherwise this method will
* only do the cleanup of previous certificates but not emit any errors. * only do the cleanup of previous certificates but not emit any errors.
* \returns Returns whether a certificate could be loaded.
*/ */
void SyncthingConnection::loadSelfSignedCertificate() bool SyncthingConnection::loadSelfSignedCertificate()
{ {
// ensure current exceptions for self-signed certificates are cleared // ensure current exceptions for self-signed certificates are cleared
m_expectedSslErrors.clear(); m_expectedSslErrors.clear();
@ -629,31 +642,33 @@ void SyncthingConnection::loadSelfSignedCertificate()
// not required when not using secure connection // not required when not using secure connection
const QUrl syncthingUrl(m_syncthingUrl); const QUrl syncthingUrl(m_syncthingUrl);
if(!syncthingUrl.scheme().endsWith(QChar('s'))) { if(!syncthingUrl.scheme().endsWith(QChar('s'))) {
return; return false;
} }
// only possible if the Syncthing instance is running on the local machine // only possible if the Syncthing instance is running on the local machine
if(!isLocal(syncthingUrl)) { if(!isLocal(syncthingUrl)) {
return; return false;
} }
// find cert // find cert
const QString certPath = !m_configDir.isEmpty() ? (m_configDir + QStringLiteral("/https-cert.pem")) : SyncthingConfig::locateHttpsCertificate(); const QString certPath = !m_configDir.isEmpty() ? (m_configDir + QStringLiteral("/https-cert.pem")) : SyncthingConfig::locateHttpsCertificate();
if(certPath.isEmpty()) { if(certPath.isEmpty()) {
emit error(tr("Unable to locate certificate used by Syncthing GUI."), SyncthingErrorCategory::OverallConnection); emit error(tr("Unable to locate certificate used by Syncthing GUI."), SyncthingErrorCategory::OverallConnection);
return; return false;
} }
// add exception // add exception
const QList<QSslCertificate> cert = QSslCertificate::fromPath(certPath); const QList<QSslCertificate> certs = QSslCertificate::fromPath(certPath);
if(cert.isEmpty()) { if(certs.isEmpty()) {
emit error(tr("Unable to load certificate used by Syncthing GUI."), SyncthingErrorCategory::OverallConnection); emit error(tr("Unable to load certificate used by Syncthing GUI."), SyncthingErrorCategory::OverallConnection);
return; return false;
} }
const QSslCertificate &cert = certs.at(0);
m_expectedSslErrors.reserve(4); m_expectedSslErrors.reserve(4);
m_expectedSslErrors << QSslError(QSslError::UnableToGetLocalIssuerCertificate, cert.at(0)); m_expectedSslErrors << QSslError(QSslError::UnableToGetLocalIssuerCertificate, cert)
m_expectedSslErrors << QSslError(QSslError::UnableToVerifyFirstCertificate, cert.at(0)); << QSslError(QSslError::UnableToVerifyFirstCertificate, cert)
m_expectedSslErrors << QSslError(QSslError::SelfSignedCertificate, cert.at(0)); << QSslError(QSslError::SelfSignedCertificate, cert)
m_expectedSslErrors << QSslError(QSslError::HostNameMismatch, cert.at(0)); << QSslError(QSslError::HostNameMismatch, cert);
return true;
} }
/*! /*!
@ -661,26 +676,46 @@ void SyncthingConnection::loadSelfSignedCertificate()
* \remarks * \remarks
* - The expected SSL errors of the specified configuration are updated accordingly. * - The expected SSL errors of the specified configuration are updated accordingly.
* - The configuration is not used instantly. It will be used on the next reconnect. * - The configuration is not used instantly. It will be used on the next reconnect.
* \returns Returns whether at least one property requiring a reconnect to take effect has changed.
* \sa reconnect() * \sa reconnect()
*/ */
void SyncthingConnection::applySettings(SyncthingConnectionSettings &connectionSettings) bool SyncthingConnection::applySettings(SyncthingConnectionSettings &connectionSettings)
{ {
setSyncthingUrl(connectionSettings.syncthingUrl); bool reconnectRequired = false;
setApiKey(connectionSettings.apiKey); if(syncthingUrl() != connectionSettings.syncthingUrl) {
if(connectionSettings.authEnabled) { setSyncthingUrl(connectionSettings.syncthingUrl);
setCredentials(connectionSettings.userName, connectionSettings.password); reconnectRequired = true;
} else {
setCredentials(QString(), QString());
} }
if(apiKey() != connectionSettings.apiKey) {
setApiKey(connectionSettings.apiKey);
reconnectRequired = true;
}
if((connectionSettings.authEnabled && (user() != connectionSettings.userName || password() != connectionSettings.password))
|| (!connectionSettings.authEnabled && (!user().isEmpty() || !password().isEmpty()))) {
if(connectionSettings.authEnabled) {
setCredentials(connectionSettings.userName, connectionSettings.password);
} else {
setCredentials(QString(), QString());
}
reconnectRequired = true;
}
if(connectionSettings.expectedSslErrors.isEmpty()) {
const bool previouslyHadExpectedSslErrors = !expectedSslErrors().isEmpty();
const bool ok = loadSelfSignedCertificate();
connectionSettings.expectedSslErrors = expectedSslErrors();
if(ok || (previouslyHadExpectedSslErrors && !ok)) {
reconnectRequired = true;
}
} else if(expectedSslErrors() != connectionSettings.expectedSslErrors) {
m_expectedSslErrors = connectionSettings.expectedSslErrors;
reconnectRequired = true;
}
setTrafficPollInterval(connectionSettings.trafficPollInterval); setTrafficPollInterval(connectionSettings.trafficPollInterval);
setDevStatsPollInterval(connectionSettings.devStatsPollInterval); setDevStatsPollInterval(connectionSettings.devStatsPollInterval);
setAutoReconnectInterval(connectionSettings.reconnectInterval); setAutoReconnectInterval(connectionSettings.reconnectInterval);
if(connectionSettings.expectedSslErrors.isEmpty()) {
loadSelfSignedCertificate(); return reconnectRequired;
connectionSettings.expectedSslErrors = expectedSslErrors();
} else {
m_expectedSslErrors = connectionSettings.expectedSslErrors;
}
} }
/*! /*!

View File

@ -111,9 +111,10 @@ public:
const std::vector<SyncthingDir *> &completedDirs() const; const std::vector<SyncthingDir *> &completedDirs() const;
public Q_SLOTS: public Q_SLOTS:
void loadSelfSignedCertificate(); bool loadSelfSignedCertificate();
void applySettings(SyncthingConnectionSettings &connectionSettings); bool applySettings(SyncthingConnectionSettings &connectionSettings);
void connect(); void connect();
void connect(SyncthingConnectionSettings &connectionSettings);
void disconnect(); void disconnect();
void reconnect(); void reconnect();
void reconnect(SyncthingConnectionSettings &connectionSettings); void reconnect(SyncthingConnectionSettings &connectionSettings);

View File

@ -61,7 +61,7 @@ TrayIcon::TrayIcon(QObject *parent) :
// setup notifications // setup notifications
m_disconnectedNotification.setMessage(tr("Disconnected from Syncthing")); m_disconnectedNotification.setMessage(tr("Disconnected from Syncthing"));
m_disconnectedNotification.setActions(QStringList(tr("Try to reconnect"))); m_disconnectedNotification.setActions(QStringList(tr("Try to reconnect")));
connect(&m_disconnectedNotification, &DBusNotification::actionInvoked, &(m_trayMenu.widget()->connection()), &SyncthingConnection::connect); connect(&m_disconnectedNotification, &DBusNotification::actionInvoked, &(m_trayMenu.widget()->connection()), static_cast<void(SyncthingConnection::*)(void)>(&SyncthingConnection::connect));
m_syncthingNotification.setActions(QStringList({QStringLiteral("show"), tr("Show"), QStringLiteral("dismiss"), tr("Dismiss")})); m_syncthingNotification.setActions(QStringList({QStringLiteral("show"), tr("Show"), QStringLiteral("dismiss"), tr("Dismiss")}));
connect(&m_syncthingNotification, &DBusNotification::actionInvoked, this, &TrayIcon::handleSyncthingNotificationAction); connect(&m_syncthingNotification, &DBusNotification::actionInvoked, this, &TrayIcon::handleSyncthingNotificationAction);
#endif #endif

View File

@ -375,7 +375,7 @@ void TrayWidget::applySettings()
instance->m_connectionsMenu->actions().at(0)->setChecked(true); instance->m_connectionsMenu->actions().at(0)->setChecked(true);
} }
instance->m_ui->connectionsPushButton->setText(instance->m_selectedConnection->label); instance->m_ui->connectionsPushButton->setText(instance->m_selectedConnection->label);
instance->m_connection.reconnect(*instance->m_selectedConnection); instance->m_connection.connect(*instance->m_selectedConnection);
// web view // web view
#ifndef SYNCTHINGTRAY_NO_WEBVIEW #ifndef SYNCTHINGTRAY_NO_WEBVIEW

View File

@ -57,6 +57,26 @@ WebPage::WebPage(WebViewDialog *dlg, WEB_VIEW_PROVIDER *view) :
} }
} }
bool WebPage::isSamePage(const QUrl &url1, const QUrl &url2)
{
if(url1.scheme() == url2.scheme()
&& url1.host() == url2.host()
&& url1.port() == url2.port()) {
QString path1 = url1.path();
while(path1.endsWith(QChar('/'))) {
path1.resize(path1.size() - 1);
}
QString path2 = url2.path();
while(path2.endsWith(QChar('/'))) {
path2.resize(path2.size() - 1);
}
if(path1 == path2) {
return true;
}
}
return false;
}
WEB_PAGE_PROVIDER *WebPage::createWindow(WEB_PAGE_PROVIDER::WebWindowType type) WEB_PAGE_PROVIDER *WebPage::createWindow(WEB_PAGE_PROVIDER::WebWindowType type)
{ {
Q_UNUSED(type) Q_UNUSED(type)
@ -128,20 +148,8 @@ bool WebPage::handleNavigationRequest(const QUrl &currentUrl, const QUrl &target
return true; return true;
} }
// only allow navigation on the same page // only allow navigation on the same page
if(currentUrl.scheme() == targetUrl.scheme() if(isSamePage(currentUrl, targetUrl)) {
&& currentUrl.host() == targetUrl.host() return true;
&& currentUrl.port() == targetUrl.port()) {
QString currentPath = currentUrl.path();
while(currentPath.endsWith(QChar('/'))) {
currentPath.resize(currentPath.size() - 1);
}
QString targetPath = targetUrl.path();
while(targetPath.endsWith(QChar('/'))) {
targetPath.resize(targetPath.size() - 1);
}
if(currentPath == targetPath) {
return true;
}
} }
// otherwise open URL in external browser // otherwise open URL in external browser
QDesktopServices::openUrl(targetUrl); QDesktopServices::openUrl(targetUrl);

View File

@ -26,6 +26,8 @@ class WebPage : public WEB_PAGE_PROVIDER
public: public:
WebPage(WebViewDialog *dlg = nullptr, WEB_VIEW_PROVIDER *view = nullptr); WebPage(WebViewDialog *dlg = nullptr, WEB_VIEW_PROVIDER *view = nullptr);
static bool isSamePage(const QUrl &url1, const QUrl &url2);
protected: protected:
WEB_PAGE_PROVIDER *createWindow(WebWindowType type); WEB_PAGE_PROVIDER *createWindow(WebWindowType type);
#ifdef SYNCTHINGTRAY_USE_WEBENGINE #ifdef SYNCTHINGTRAY_USE_WEBENGINE
@ -45,7 +47,7 @@ private slots:
#endif #endif
private: private:
bool handleNavigationRequest(const QUrl &currentUrl, const QUrl &url); static bool handleNavigationRequest(const QUrl &currentUrl, const QUrl &url);
WebViewDialog *m_dlg; WebViewDialog *m_dlg;
WEB_VIEW_PROVIDER *m_view; WEB_VIEW_PROVIDER *m_view;

View File

@ -54,7 +54,9 @@ QtGui::WebViewDialog::~WebViewDialog()
void QtGui::WebViewDialog::applySettings(const Data::SyncthingConnectionSettings &connectionSettings) void QtGui::WebViewDialog::applySettings(const Data::SyncthingConnectionSettings &connectionSettings)
{ {
m_settings = connectionSettings; m_settings = connectionSettings;
m_view->setUrl(connectionSettings.syncthingUrl); if(!WebPage::isSamePage(m_view->url(), connectionSettings.syncthingUrl)) {
m_view->setUrl(connectionSettings.syncthingUrl);
}
m_view->setZoomFactor(Settings::values().webView.zoomFactor); m_view->setZoomFactor(Settings::values().webView.zoomFactor);
} }