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.
*/
@ -620,8 +632,9 @@ QMetaObject::Connection SyncthingConnection::requestLog(std::function<void (cons
* - Loading the certificate is only possible if the connection object is configured
* to connect to the locally running Syncthing instance. Otherwise this method will
* 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
m_expectedSslErrors.clear();
@ -629,31 +642,33 @@ void SyncthingConnection::loadSelfSignedCertificate()
// not required when not using secure connection
const QUrl syncthingUrl(m_syncthingUrl);
if(!syncthingUrl.scheme().endsWith(QChar('s'))) {
return;
return false;
}
// only possible if the Syncthing instance is running on the local machine
if(!isLocal(syncthingUrl)) {
return;
return false;
}
// find cert
const QString certPath = !m_configDir.isEmpty() ? (m_configDir + QStringLiteral("/https-cert.pem")) : SyncthingConfig::locateHttpsCertificate();
if(certPath.isEmpty()) {
emit error(tr("Unable to locate certificate used by Syncthing GUI."), SyncthingErrorCategory::OverallConnection);
return;
return false;
}
// add exception
const QList<QSslCertificate> cert = QSslCertificate::fromPath(certPath);
if(cert.isEmpty()) {
const QList<QSslCertificate> certs = QSslCertificate::fromPath(certPath);
if(certs.isEmpty()) {
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 << QSslError(QSslError::UnableToGetLocalIssuerCertificate, cert.at(0));
m_expectedSslErrors << QSslError(QSslError::UnableToVerifyFirstCertificate, cert.at(0));
m_expectedSslErrors << QSslError(QSslError::SelfSignedCertificate, cert.at(0));
m_expectedSslErrors << QSslError(QSslError::HostNameMismatch, cert.at(0));
m_expectedSslErrors << QSslError(QSslError::UnableToGetLocalIssuerCertificate, cert)
<< QSslError(QSslError::UnableToVerifyFirstCertificate, cert)
<< QSslError(QSslError::SelfSignedCertificate, cert)
<< QSslError(QSslError::HostNameMismatch, cert);
return true;
}
/*!
@ -661,26 +676,46 @@ void SyncthingConnection::loadSelfSignedCertificate()
* \remarks
* - 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.
* \returns Returns whether at least one property requiring a reconnect to take effect has changed.
* \sa reconnect()
*/
void SyncthingConnection::applySettings(SyncthingConnectionSettings &connectionSettings)
bool SyncthingConnection::applySettings(SyncthingConnectionSettings &connectionSettings)
{
setSyncthingUrl(connectionSettings.syncthingUrl);
setApiKey(connectionSettings.apiKey);
if(connectionSettings.authEnabled) {
setCredentials(connectionSettings.userName, connectionSettings.password);
} else {
setCredentials(QString(), QString());
bool reconnectRequired = false;
if(syncthingUrl() != connectionSettings.syncthingUrl) {
setSyncthingUrl(connectionSettings.syncthingUrl);
reconnectRequired = true;
}
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);
setDevStatsPollInterval(connectionSettings.devStatsPollInterval);
setAutoReconnectInterval(connectionSettings.reconnectInterval);
if(connectionSettings.expectedSslErrors.isEmpty()) {
loadSelfSignedCertificate();
connectionSettings.expectedSslErrors = expectedSslErrors();
} else {
m_expectedSslErrors = connectionSettings.expectedSslErrors;
}
return reconnectRequired;
}
/*!

View File

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

View File

@ -61,7 +61,7 @@ TrayIcon::TrayIcon(QObject *parent) :
// setup notifications
m_disconnectedNotification.setMessage(tr("Disconnected from Syncthing"));
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")}));
connect(&m_syncthingNotification, &DBusNotification::actionInvoked, this, &TrayIcon::handleSyncthingNotificationAction);
#endif

View File

@ -375,7 +375,7 @@ void TrayWidget::applySettings()
instance->m_connectionsMenu->actions().at(0)->setChecked(true);
}
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
#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)
{
Q_UNUSED(type)
@ -128,20 +148,8 @@ bool WebPage::handleNavigationRequest(const QUrl &currentUrl, const QUrl &target
return true;
}
// only allow navigation on the same page
if(currentUrl.scheme() == targetUrl.scheme()
&& currentUrl.host() == targetUrl.host()
&& 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;
}
if(isSamePage(currentUrl, targetUrl)) {
return true;
}
// otherwise open URL in external browser
QDesktopServices::openUrl(targetUrl);

View File

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

View File

@ -54,7 +54,9 @@ QtGui::WebViewDialog::~WebViewDialog()
void QtGui::WebViewDialog::applySettings(const Data::SyncthingConnectionSettings &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);
}